/* ** Copyright 1998 - 2011 Double Precision, Inc. ** See COPYING for distribution information. */ #ifndef rfc1035_h #define rfc1035_h #if HAVE_CONFIG_H #include "rfc1035/config.h" #endif #include "random128/random128.h" #include "md5/md5.h" #include #include #include #if HAVE_NETINET_IN_H #include #endif #ifdef __cplusplus extern "C" { #endif #if RFC1035_IPV6 typedef struct in6_addr RFC1035_ADDR; typedef struct sockaddr_in6 RFC1035_SOCKADDR; typedef struct sockaddr_storage RFC1035_NETADDR; #define RFC1035_ADDRANY in6addr_any #else typedef struct in_addr RFC1035_ADDR; typedef struct sockaddr_in RFC1035_SOCKADDR; typedef struct sockaddr RFC1035_NETADDR; extern struct in_addr rfc1035_addr_any; #define RFC1035_ADDRANY rfc1035_addr_any #endif #define RFC1035_TYPE_A 1 #define RFC1035_TYPE_NS 2 #define RFC1035_TYPE_MD 3 #define RFC1035_TYPE_MF 4 #define RFC1035_TYPE_CNAME 5 #define RFC1035_TYPE_SOA 6 #define RFC1035_TYPE_MB 7 #define RFC1035_TYPE_MG 8 #define RFC1035_TYPE_MR 9 #define RFC1035_TYPE_NULL 10 #define RFC1035_TYPE_WKS 11 #define RFC1035_TYPE_PTR 12 #define RFC1035_TYPE_HINFO 13 #define RFC1035_TYPE_MINFO 14 #define RFC1035_TYPE_MX 15 #define RFC1035_TYPE_TXT 16 #define RFC1035_TYPE_AAAA 28 /* RFC 1886. Even if we don't have IPv6 */ #define RFC1035_TYPE_OPT 41 #define RFC1035_TYPE_RRSIG 46 #define RFC1035_TYPE_AXFR 252 #define RFC1035_TYPE_MAILB 253 #define RFC1035_TYPE_MAILA 254 #define RFC1035_TYPE_ANY 255 void rfc1035_type_itostr(int, void (*)(const char *, void *), void *); int rfc1035_type_strtoi(const char *); #define RFC1035_CLASS_IN 1 #define RFC1035_CLASS_CSNET 2 #define RFC1035_CLASS_CHAOS 3 #define RFC1035_CLASS_HESIOD 4 #define RFC1035_CLASS_ANY 255 const char *rfc1035_class_itostr(int); int rfc1035_class_strtoi(const char *); #define RFC1035_OPCODE_QUERY 0 #define RFC1035_OPCODE_IQUERY 1 #define RFC1035_OPCODE_STATUS 2 const char *rfc1035_opcode_itostr(int); int rfc1035_opcode_strtoi(const char *); #define RFC1035_RCODE_NOERROR 0 #define RFC1035_RCODE_FORMAT 1 #define RFC1035_RCODE_SERVFAIL 2 #define RFC1035_RCODE_NXDOMAIN 3 #define RFC1035_RCODE_UNIMPLEMENTED 4 #define RFC1035_RCODE_REFUSED 5 const char *rfc1035_rcode_itostr(int); int rfc1035_rcode_strtoi(const char *); struct rfc1035_query { const char *name; unsigned qtype, qclass; } ; struct rfc1035_reply; /* Defined below */ struct rfc1035_rr; /* Defined below */ /* ** The init family of functions perform various initializations. Calling them ** is optional, as librfc1035.a will use defaults if not specified. */ #define RFC1035_MAXNS 10 #define RFC1035_DEFAULT_INITIAL_TIMEOUT 5 #define RFC1035_DEFAULT_MAXIMUM_BACKOFF 3 /* Resolver state */ struct rfc1035_res { RFC1035_ADDR nameservers[RFC1035_MAXNS]; int rfc1035_nnameservers; char *rfc1035_defaultdomain; int norecursive; /* Do not set the recursive flag, for specialized apps */ int dnssec_payload_size; /* Enable dnssec requests */ unsigned rfc1035_good_ns; unsigned rfc1035_timeout_initial; /* Initial timeout */ unsigned rfc1035_timeout_backoff; /* Maximum exponential backoff */ random128binbuf randseed; MD5_DIGEST randbuf; unsigned randptr; } ; extern struct rfc1035_res rfc1035_default_resolver; void rfc1035_init_timeout(struct rfc1035_res *, unsigned, unsigned); /* ** Specify timeout in seconds, ** and maximum exponential backoff. */ void rfc1035_init_ns(struct rfc1035_res *, const RFC1035_ADDR *, unsigned); /* Specify nameservers to query (max 10) */ void rfc1035_init_norecursive(struct rfc1035_res *, int); /* Set the no-recursive flag, if you don't want the NS to do recursive queries on your behalf */ void rfc1035_init_dnssec_enable(struct rfc1035_res *, int); /* Enable/disable dnssec/edns0 */ void rfc1035_init_edns_payload(struct rfc1035_res *, int); /* Set edns0 payload size */ void rfc1035_init_resolv(struct rfc1035_res *); /* Read /etc/resolv.conf for nameservers */ void rfc1035_destroy_resolv(struct rfc1035_res *); /* Destroy the resolver object */ /* ** Most people will only need to call rfc1035_resolve or ** rfc1035_resolve_cname. The return value from _resolve functions ** should be interpreted as follows: ** NULL - internal failure (treat it as a soft DNS error) ** ptr->rcode = RFC1035_RCODE_NOERROR - success ** ptr->rcode = RFC1035_RCODE_NXDOMAIN - hard DNS error ** ptr->rcode = RFC1035_RCODE_TEMPFAIL - soft DNS error ** ptr->rcode = any other value - log abnormal result, ** handle as soft DNS error */ struct rfc1035_reply *rfc1035_resolve( struct rfc1035_res *, /* Pointer to a resolver structure */ int, /* Opcode, see above. */ const char *, /* Query name */ unsigned, /* Query type, see above. */ unsigned); /* Query class, see above. */ /* ** Multiple queries. Most servers don't support this. */ struct rfc1035_reply *rfc1035_resolve_multiple( struct rfc1035_res *, /* Pointer to a resolver structure */ int, /* opcode */ const struct rfc1035_query *, /* Array of queries */ unsigned); /* Array size */ /* ** rfc1035_resolve_cname is like _resolve, but starts with the default ** servers, and automatically reissues the query if the received response ** is a CNAME. If successful, it returns an INDEX into the allrrs array ** containing the first answer. To get the next answers, call ** rfc1035_replysearch_all with return value+1. If not succesfull, -1 ** is returned. ** ** Note - if the returned index points to a CNAME, this is because a CNAME ** pointed to another CNAME -- it's BAD! ** ** It takes a POINTER to the 'id' counter, which is incremented if a ** second query needs to be issued. ** ** If takes a POINTER to the rfc1035_reply structure, which will be either ** null on exit, or point to the reply received. The pointer MAY be not null ** even if the return value is -1. ** ** Suggested logic: ** Return value >= 0, succesfull query. ** Return value <= -1, ptr is not null, and rcode = RFC1035_RCODE_NXDOMAIN, ** hard DNS error. ** Return value <= -1, ptr is not null, and rcode = RFC1035_RCODE_TEMPFAIL, ** soft DNS error. ** Other situations: log the abnormal result, handle as soft DNS error. */ #define RFC1035_ERR_CNAME_RECURSIVE -2 /* Specific error code for a recursive CNAME record - prohibited */ int rfc1035_resolve_cname( struct rfc1035_res *, /* Pointer to a resolver structure */ char *, /* RFC1035_MAXNAMESIZE buffer with ** the name to query */ unsigned, /* Query type */ unsigned, /* Query class */ struct rfc1035_reply **, /* Ptr set to reply received */ int); /* Extended flags: */ #define RFC1035_X_RANDOMIZE 1 /* Randomize query results */ /* ** rfc1035_resolve_cname_multiple is a version of rfc1035_resolve_cname ** that accepts an array of qtypes, and issues a query for each qtype. ** ** qtypes points to a 0-terminated list of RRs. */ int rfc1035_resolve_cname_multiple(struct rfc1035_res *res, char *namebuf, /* RFC1035_MAXNAMESIZE buffer with ** the name to query */ unsigned char *qtypes, unsigned qclass, struct rfc1035_reply **ptr, int x_flags); /* ** Always call replyfree when done. */ void rfc1035_replyfree(struct rfc1035_reply *); /* ** !!!ALL!!! the const char * pointers in rfc1035_reply are NOT ** standard C strings, but DNS-compressed strings. Call ** replyhostname to translate those to C strings. */ const char *rfc1035_replyhostname( const struct rfc1035_reply *, /* The reply */ const char *, /* The const char ptr */ char *); /* Buffer where to put hostname. All strings are ** guaranteed to fit into RFC1035_MAXNAMESIZE+1 byte ** buffer. ** replyhostname returns this pointer. */ /* Some value added code, look up A and PTR records. */ int rfc1035_a(struct rfc1035_res *, const char *, /* Host name */ RFC1035_ADDR **, /* We allocate array of IP addresses */ unsigned *); /* We return # of IP addresses here */ int rfc1035_ptr(struct rfc1035_res *, const RFC1035_ADDR *, /* Query PTR for this address */ char *); /* Result - RFC1035_MAXNAMESIZE+1 buf */ int rfc1035_ptr_x(struct rfc1035_res *res, const RFC1035_ADDR *addr, void (*cb_func)(const char *, void *), void *cb_arg); /* Invoke a callback function instead ** (multiple callbacks possible) */ /* ---------------------- */ /* Replyuncompress is a lower-level function taking a pointer to ** the const char *. When it returns, the const char * is advanced ** past the end of the compressed string in the DNS data. ** replyuncompress returns its third argument, or NULL if there was ** an error. */ const char *rfc1035_replyuncompress(const char **, const struct rfc1035_reply *, char *); #define RFC1035_MAXNAMESIZE 255 /* ** Compare two hostnames. Return 0 if they match, non-zero if they ** don't. */ int rfc1035_hostnamecmp(const char *, const char *); /* ** After we receive a reply, search for the answer there. Returns ** an index in the respective section, or -1 if not found. ** If we find a CNAME, we return a pointer to it instead, so make ** sure to check for that! */ int rfc1035_replysearch_an( const struct rfc1035_res *, /* The resolver */ const struct rfc1035_reply *, /* The reply */ const char *, /* Hostname to search */ unsigned, /* Type */ unsigned, /* Class */ int); /* Starting position, 1st time use 0 */ int rfc1035_replysearch_ns( const struct rfc1035_res *, /* The resolver */ const struct rfc1035_reply *, /* The reply */ const char *, /* Hostname to search */ unsigned, /* Type */ unsigned, /* Class */ int); /* Starting position, 1st time use 0 */ int rfc1035_replysearch_all( const struct rfc1035_res *, /* The resolver */ const struct rfc1035_reply *, /* The reply */ const char *, /* Hostname to search */ unsigned, /* Type */ unsigned, /* Class */ int); /* Starting position, 1st time use 0 */ /* ** Low level functions follow. */ /* ** rfc1035_mkquery() constructs a query to be sent. The query is ** composed by REPEATEDLY running the caller-provided function, ** which will be called REPEATEDLY to build the query, part by part. */ int rfc1035_mkquery(struct rfc1035_res *, /* resolver structure */ unsigned, /* opcode */ #define RFC1035_RESOLVE_RECURSIVE 1 /* Ask nameserver to do the recursion */ const struct rfc1035_query *, /* questions */ unsigned, /* Number of questions */ void (*)(const char *, unsigned, void *), /* Function - called repetitively ** to build the query */ void *); /* Third arg to function */ /**************************************************************************/ /* Low level input/output functions. Most people won't need to use these */ /**************************************************************************/ int rfc1035_open_udp(int *af); /* Create a UDP socket */ int rfc1035_send_udp(int, /* File descriptor from rfc1035_open */ const struct sockaddr *, int, /* Send to this name server */ const char *, /* The query */ unsigned); /* Query length */ /* ** Returns 0, or non-zero if failed. */ int rfc1035_wait_reply(int, /* File descriptor from rfc1035_open */ unsigned); /* Number of seconds to wait, use 0 for default */ /* Returns 0 when reply is waiting, non-0 if timeout expired */ int rfc1035_wait_query(int, /* File descriptor from rfc1035_open */ unsigned); /* Number of seconds to wait, use 0 for default */ /* Like reply, but we select for writing */ char *rfc1035_query_udp(struct rfc1035_res *, int, /* file descriptor */ const struct sockaddr *, int, /* Attempt number */ const char *, /* query */ unsigned, /* query length */ int *, /* # of bytes received */ unsigned); /* # of seconds to wait for response */ /* ** Jumbo function: sends the indicated query via UDP, waits for ** a validated reply. Returns pointer to dynamically allocated ** memory with the reply. Returns NULL if there was an error. ** errno will be set to EAGAIN if the response timed out ** (if the UDP stack returns an error, we fake an EAGAIN). ** After getting EAGAIN, attempt number should be incremented, ** and we should try again. ** Fake ETIMEDOUT is returned if no more attempts are possible. */ int rfc1035_open_tcp(struct rfc1035_res *, const RFC1035_ADDR *); /* ** Create a TCP socket for this attempt #, ** returns negative for a failure, and sets ** errno. */ /* ** Attempt to transmit the indicated query on this TCP socket. ** Return 0 for successfull transmission. */ int rfc1035_send_tcp(int, /* file descriptor */ const char *, /* query */ unsigned); /* query length */ /* ** Attempt to receive a reply on this TCP socket. ** Returns pointer to dynamically malloced memory, or null if error. */ char *rfc1035_recv_tcp(struct rfc1035_res *, int, /* file descriptor */ int *, /* * initialized to contain msg length */ unsigned); /* # of seconds to wait for a response */ char *rfc1035_query_tcp(struct rfc1035_res *, int, /* file descriptor */ const char *, /* query */ unsigned, /* query length */ int *, /* * initialized to contain msg length */ unsigned); /* # of seconds to wait for response */ /*************************************************/ /* Parse a raw response into a useful structure. */ /*************************************************/ struct rfc1035_rr { const char *rrname; /* NOT a null term str, a ptr into the raw resp */ unsigned rrtype, rrclass; RFC1035_UINT32 ttl; unsigned rdlength; const char *rdata; /* Raw data, parsed record follows: */ union { struct { const char *hinfo_str; const char *os_str; } hinfo; struct in_addr inaddr; /* A */ #if RFC1035_IPV6 struct in6_addr in6addr; /* AAAA */ #endif const char *domainname; /* CNAME, MB, MD, MF, MG, MR, NS, PTR */ struct { const char *rmailbx_label; const char *emailbx_label; } minfo; struct { unsigned preference; const char *mx_label; } mx; struct { const char *mname_label; const char *rname_label; RFC1035_UINT32 serial; RFC1035_UINT32 refresh; RFC1035_UINT32 retry; RFC1035_UINT32 expire; RFC1035_UINT32 minimum; } soa; struct { RFC1035_UINT16 type_covered; unsigned char algorithm; unsigned char labels; RFC1035_UINT16 original_ttl; RFC1035_UINT32 signature_expiration; RFC1035_UINT32 signature_inception; RFC1035_UINT16 key_tag; const char *signer_name; const char *signature; RFC1035_UINT16 signature_len; } rrsig; /* As are just represented by rdata/rdlength */ /* TXTs are parsed directly from rdata/rdlength */ /* WKS are parsed directly */ } rr; } ; struct rfc1035_reply { struct rfc1035_reply *next; /* AXFRs have a linked list here */ const char *reply; /* The raw reply, for convenience's sake */ unsigned replylen; /* The length of the reply */ char *mallocedbuf; /* If not NULL, dynamically allocated ** memory that holds the reply. */ RFC1035_NETADDR server_addr; /* Replying server */ unsigned char qr; unsigned char opcode; unsigned char aa; unsigned char tc; unsigned char rd; unsigned char ra; unsigned char ad; unsigned char cd; unsigned char rcode; unsigned qdcount; unsigned ancount; unsigned nscount; unsigned arcount; struct rfc1035_query *qdptr; /* sizeof qdcount */ struct rfc1035_rr *anptr; struct rfc1035_rr *nsptr; struct rfc1035_rr *arptr; struct rfc1035_rr **allrrs; /* Pointers to all RR records, ** add ancount+nscount+arcount for ** the size of the array */ } ; struct rfc1035_reply *rfc1035_replyparse(const char *, unsigned); void rfc1035_rr_rand_an(struct rfc1035_reply *rr); void rfc1035_rr_rand_ns(struct rfc1035_reply *rr); void rfc1035_rr_rand_ar(struct rfc1035_reply *rr); void rfc1035_rr_rand(struct rfc1035_reply *rr); void rfc1035_dump(struct rfc1035_reply *, FILE *); const char *rfc1035_fmttime(unsigned long, char *); #define RFC1035_MAXTIMEBUFSIZE 40 char *rfc1035_dumprrdata(struct rfc1035_reply *, struct rfc1035_rr *); int rfc1035_rr_gettxt(struct rfc1035_rr *, int, char buf[256]); /* ** I ignore any possible bugs in the resolver functions, and roll my own, ** for IPv4. */ void rfc1035_ntoa_ipv4(const struct in_addr *in, char *buf); int rfc1035_aton_ipv4(const char *p, struct in_addr *in4); #if RFC1035_IPV6 void rfc1035_ipv6to4(struct in_addr *, const struct in6_addr *); void rfc1035_ipv4to6(struct in6_addr *, const struct in_addr *); #endif /* ** Extract network address from a socket address. */ int rfc1035_sockaddrip(const RFC1035_NETADDR *, /* Socket address buffer */ int, /* Length of address */ RFC1035_ADDR *); /* Address saved here */ int rfc1035_sockaddrport(const RFC1035_NETADDR *, /* Socket address buffer */ int, /* Length of address */ int *); /* Port saved here */ #if RFC1035_IPV6 #define RFC1035_NTOABUFSIZE INET6_ADDRSTRLEN #else #define RFC1035_NTOABUFSIZE 16 #endif void rfc1035_ntoa(const RFC1035_ADDR *, char *); int rfc1035_aton(const char *, RFC1035_ADDR *); /* ** New function that compares two addresses -- handles both IPv4 and IPv6: */ int rfc1035_same_ip(const void *, int, const void *, int); int rfc1035_bindsource(int sockfd, /* Socket fd */ const struct sockaddr *addr, /* Buffer to socket address */ int addrlen); /* Size of socket address */ /* ** First try to create an IPv6 socket, then, if we fail, an IPv4 socket. */ int rfc1035_mksocket(int sock_type, /* socket type to create */ int sock_protocol, /* socket protocol to create */ int *af); /* If succeed, address family created */ /* ** Take the destination address, and create a socket address structure ** suitable for connecting to this address. */ int rfc1035_mkaddress(int af, /* AF_INET or AF_INET6 */ /* buf is initiailized to the sender's ip address. */ RFC1035_NETADDR *buf, /* Buffer for the created address */ const RFC1035_ADDR *addr, /* Network address */ int port, /* Network port (network byte order) */ const struct sockaddr **ptr, /* Will point to buf */ int *len); /* Will be size of socket address */ /* ** A convenient interface to the SIOCGIFCONF ioctl. */ struct rfc1035_ifconf { struct rfc1035_ifconf *next; char *ifname; RFC1035_ADDR ifaddr; }; struct rfc1035_ifconf *rfc1035_ifconf(int *errflag); void rfc1035_ifconf_free(struct rfc1035_ifconf *ifconf_list); /* ** Outstanding UDP queries. */ /* common query buffer */ struct querybuf { char qbuf[512]; unsigned qbuflen; } ; struct rfc1035_udp_query_response; /* How many queries, and the queries */ struct rfc1035_udp_query_responses { int n_queries; struct rfc1035_udp_query_response *queries; }; /* Each query, and response already receives so far, if any. */ struct rfc1035_udp_query_response { const char *query; unsigned querylen; char *response; unsigned resplen; }; /* ** Allocate a new rfc1035_udp_query_responses. ** Copies each query into the rfc1035_udp_query_response, each response is ** initialized to null. */ struct rfc1035_udp_query_responses * rfc1035_udp_query_response_alloc(const char **queries, const unsigned *querylens, int n_queries); struct rfc1035_udp_query_responses * rfc1035_udp_query_response_alloc_bis(struct querybuf *queries, int n_queries); /* ** Send all queries via UDPs, wait for responses. ** ** Returns non-0 if all queries are received, 0 if not. EAGAIN indicates ** a timeout, and this can be called again with the same ** rfc1035_udp_query_responses object; this resends all queries for which ** no response was received, and this will wait for the remaining responses. */ int rfc1035_udp_query_multi(struct rfc1035_res *res, /* Socket: */ int fd, /* Where to send it to */ const struct sockaddr *sin, int sin_len, /* The queries */ struct rfc1035_udp_query_responses *qr, /* How long to wait for responses, in seconds. */ unsigned w); /* ** Deallocate rfc1035_udp_query_responses. Each non-NULL response pointer ** gets free()d. */ void rfc1035_udp_query_response_free(struct rfc1035_udp_query_responses *); #ifdef __cplusplus } #endif #endif