/* ========================================================================== * dns.h - Recursive, Reentrant DNS Resolver. * -------------------------------------------------------------------------- * Copyright (c) 2009, 2010, 2012-2015 William Ahern * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, subject to the * following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * ========================================================================== */ #ifndef DNS_H #define DNS_H #include /* size_t offsetof() */ #include /* uint64_t */ #include /* FILE */ #include /* strlen(3) */ #include /* struct timespec time_t */ #if _WIN32 #include #include #else #include /* BYTE_ORDER BIG_ENDIAN _BIG_ENDIAN */ #include /* socklen_t */ #include /* struct socket */ #include /* POLLIN POLLOUT */ #include /* struct in_addr struct in6_addr */ #include /* struct addrinfo */ #endif /* * V I S I B I L I T Y * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef DNS_PUBLIC #define DNS_PUBLIC #endif /* * V E R S I O N * * Vendor: Entity for which versions numbers are relevant. (If forking * change DNS_VENDOR to avoid confusion.) * * Three versions: * * REL Official "release"--bug fixes, new features, etc. * ABI Changes to existing object sizes or parameter types * API Changes that might effect application source. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define DNS_VENDOR "william@25thandClement.com" #define DNS_V_REL 0x20160809 #define DNS_V_ABI 0x20160608 #define DNS_V_API 0x20160809 DNS_PUBLIC const char *dns_vendor(void); DNS_PUBLIC int dns_v_rel(void); DNS_PUBLIC int dns_v_abi(void); DNS_PUBLIC int dns_v_api(void); /* * E R R O R S * * Errors and exceptions are always returned through an int. This should * hopefully make integration easier in the majority of circumstances, and * also cut down on useless compiler warnings. * * System and library errors are returned together. POSIX guarantees that * all system errors are positive integers. Library errors are always * negative integers in the range DNS_EBASE to DNS_ELAST, with the high bits * set to the three magic ASCII characters "dns". * * dns_strerror() returns static English string descriptions of all known * errors, and punts the remainder to strerror(3). * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define DNS_EBASE -(('d' << 24) | ('n' << 16) | ('s' << 8) | 64) #define dns_error_t int /* for documentation only */ enum dns_errno { DNS_ENOBUFS = DNS_EBASE, DNS_EILLEGAL, DNS_EORDER, DNS_ESECTION, DNS_EUNKNOWN, DNS_EADDRESS, DNS_ENOQUERY, DNS_ENOANSWER, DNS_EFETCHED, DNS_ESERVICE, /* EAI_SERVICE */ DNS_ENONAME, /* EAI_NONAME */ DNS_EFAIL, /* EAI_FAIL */ DNS_ECONNFIN, DNS_EVERIFY, DNS_ELAST, }; /* dns_errno */ DNS_PUBLIC const char *dns_strerror(dns_error_t); DNS_PUBLIC int *dns_debug_p(void); #define dns_debug (*dns_debug_p()) /* was extern int dns_debug before 20160523 API */ /* * C O M P I L E R A N N O T A T I O N S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if defined __clang__ #define DNS_PRAGMA_PUSH _Pragma("clang diagnostic push") #define DNS_PRAGMA_QUIET _Pragma("clang diagnostic ignored \"-Winitializer-overrides\"") #define DNS_PRAGMA_POP _Pragma("clang diagnostic pop") #elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 #define DNS_PRAGMA_PUSH _Pragma("GCC diagnostic push") #define DNS_PRAGMA_QUIET _Pragma("GCC diagnostic ignored \"-Woverride-init\"") #define DNS_PRAGMA_POP _Pragma("GCC diagnostic pop") #else #define DNS_PRAGMA_PUSH #define DNS_PRAGMA_QUIET #define DNS_PRAGMA_POP #endif #if defined __GNUC__ #define DNS_PRAGMA_EXTENSION __extension__ #else #define DNS_PRAGMA_EXTENSION #endif /* * E V E N T S I N T E R F A C E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if defined(POLLIN) #define DNS_POLLIN POLLIN #else #define DNS_POLLIN 1 #endif #if defined(POLLOUT) #define DNS_POLLOUT POLLOUT #else #define DNS_POLLOUT 2 #endif /* * See Application Interface below for configuring libevent bitmasks instead * of poll(2) bitmasks. */ #define DNS_EVREAD 2 #define DNS_EVWRITE 4 #define DNS_POLL2EV(set) \ (((set) & DNS_POLLIN)? DNS_EVREAD : 0) | (((set) & DNS_POLLOUT)? DNS_EVWRITE : 0) #define DNS_EV2POLL(set) \ (((set) & DNS_EVREAD)? DNS_POLLIN : 0) | (((set) & DNS_EVWRITE)? DNS_POLLOUT : 0) /* * E N U M E R A T I O N I N T E R F A C E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ enum dns_section { DNS_S_QD = 0x01, #define DNS_S_QUESTION DNS_S_QD DNS_S_AN = 0x02, #define DNS_S_ANSWER DNS_S_AN DNS_S_NS = 0x04, #define DNS_S_AUTHORITY DNS_S_NS DNS_S_AR = 0x08, #define DNS_S_ADDITIONAL DNS_S_AR DNS_S_ALL = 0x0f }; /* enum dns_section */ enum dns_class { DNS_C_IN = 1, DNS_C_ANY = 255 }; /* enum dns_class */ enum dns_type { DNS_T_A = 1, DNS_T_NS = 2, DNS_T_CNAME = 5, DNS_T_SOA = 6, DNS_T_PTR = 12, DNS_T_MX = 15, DNS_T_TXT = 16, DNS_T_AAAA = 28, DNS_T_SRV = 33, DNS_T_OPT = 41, DNS_T_SSHFP = 44, DNS_T_SPF = 99, DNS_T_AXFR = 252, DNS_T_ALL = 255 }; /* enum dns_type */ enum dns_opcode { DNS_OP_QUERY = 0, DNS_OP_IQUERY = 1, DNS_OP_STATUS = 2, DNS_OP_NOTIFY = 4, DNS_OP_UPDATE = 5, }; /* dns_opcode */ enum dns_rcode { DNS_RC_NOERROR = 0, DNS_RC_FORMERR = 1, DNS_RC_SERVFAIL = 2, DNS_RC_NXDOMAIN = 3, DNS_RC_NOTIMP = 4, DNS_RC_REFUSED = 5, DNS_RC_YXDOMAIN = 6, DNS_RC_YXRRSET = 7, DNS_RC_NXRRSET = 8, DNS_RC_NOTAUTH = 9, DNS_RC_NOTZONE = 10, /* EDNS(0) extended RCODEs */ DNS_RC_BADVERS = 16, }; /* dns_rcode */ /* * NOTE: These string functions need a small buffer in case the literal * integer value needs to be printed and returned. UNLESS this buffer is * SPECIFIED, the returned string has ONLY BLOCK SCOPE. */ #define DNS_STRMAXLEN 47 /* "QUESTION|ANSWER|AUTHORITY|ADDITIONAL" */ DNS_PUBLIC const char *dns_strsection(enum dns_section, char *); DNS_PUBLIC enum dns_section dns_isection(const char *); DNS_PUBLIC const char *dns_strclass(enum dns_class, char *); DNS_PUBLIC enum dns_class dns_iclass(const char *); DNS_PUBLIC const char *dns_strtype(enum dns_type, char *); DNS_PUBLIC enum dns_type dns_itype(const char *); DNS_PUBLIC const char *dns_stropcode(enum dns_opcode); DNS_PUBLIC enum dns_opcode dns_iopcode(const char *); DNS_PUBLIC const char *dns_strrcode(enum dns_rcode); DNS_PUBLIC enum dns_rcode dns_ircode(const char *); /* * A T O M I C I N T E R F A C E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ typedef unsigned long dns_atomic_t; typedef unsigned long dns_refcount_t; /* must be same value type as dns_atomic_t */ /* * C R Y P T O I N T E R F A C E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ typedef unsigned dns_random_f(void); DNS_PUBLIC dns_random_f **dns_random_p(void); #define dns_random (*dns_random_p()) /* was extern unsigned (*dns_random)(void) before 20160523 API */ /* * P A C K E T I N T E R F A C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_header { unsigned qid:16; #if (defined BYTE_ORDER && BYTE_ORDER == BIG_ENDIAN) || (defined __sun && defined _BIG_ENDIAN) unsigned qr:1; unsigned opcode:4; unsigned aa:1; unsigned tc:1; unsigned rd:1; unsigned ra:1; unsigned unused:3; unsigned rcode:4; #else unsigned rd:1; unsigned tc:1; unsigned aa:1; unsigned opcode:4; unsigned qr:1; unsigned rcode:4; unsigned unused:3; unsigned ra:1; #endif unsigned qdcount:16; unsigned ancount:16; unsigned nscount:16; unsigned arcount:16; }; /* struct dns_header */ #define dns_header(p) (&(p)->header) #ifndef DNS_P_QBUFSIZ #define DNS_P_QBUFSIZ dns_p_calcsize(256 + 4) #endif #ifndef DNS_P_DICTSIZE #define DNS_P_DICTSIZE 16 #endif struct dns_packet { unsigned short dict[DNS_P_DICTSIZE]; struct dns_p_memo { struct dns_s_memo { unsigned short base, end; } qd, an, ns, ar; struct { unsigned short p; unsigned short maxudp; unsigned ttl; } opt; } memo; struct { struct dns_packet *cqe_next, *cqe_prev; } cqe; size_t size, end; int:16; /* tcp padding */ DNS_PRAGMA_EXTENSION union { struct dns_header header; unsigned char data[1]; }; }; /* struct dns_packet */ #define dns_p_calcsize(n) (offsetof(struct dns_packet, data) + DNS_PP_MAX(12, (n))) #define dns_p_sizeof(P) dns_p_calcsize((P)->end) /** takes size of entire packet structure as allocated */ DNS_PUBLIC struct dns_packet *dns_p_init(struct dns_packet *, size_t); /** takes size of maximum desired payload */ DNS_PUBLIC struct dns_packet *dns_p_make(size_t, int *); DNS_PUBLIC int dns_p_grow(struct dns_packet **); DNS_PUBLIC struct dns_packet *dns_p_copy(struct dns_packet *, const struct dns_packet *); #define dns_p_opcode(P) (dns_header(P)->opcode) DNS_PUBLIC enum dns_rcode dns_p_rcode(struct dns_packet *); DNS_PUBLIC unsigned dns_p_count(struct dns_packet *, enum dns_section); DNS_PUBLIC int dns_p_push(struct dns_packet *, enum dns_section, const void *, size_t, enum dns_type, enum dns_class, unsigned, const void *); DNS_PUBLIC void dns_p_dictadd(struct dns_packet *, unsigned short); DNS_PUBLIC struct dns_packet *dns_p_merge(struct dns_packet *, enum dns_section, struct dns_packet *, enum dns_section, int *); DNS_PUBLIC void dns_p_dump(struct dns_packet *, FILE *); DNS_PUBLIC int dns_p_study(struct dns_packet *); /* * D O M A I N N A M E I N T E R F A C E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define DNS_D_MAXLABEL 63 /* + 1 '\0' */ #define DNS_D_MAXNAME 255 /* + 1 '\0' */ #define DNS_D_ANCHOR 1 /* anchor domain w/ root "." */ #define DNS_D_CLEAVE 2 /* cleave sub-domain */ #define DNS_D_TRIM 4 /* remove superfluous dots */ DNS_PUBLIC char *dns_d_init(void *, size_t, const void *, size_t, int); DNS_PUBLIC size_t dns_d_anchor(void *, size_t, const void *, size_t); DNS_PUBLIC size_t dns_d_cleave(void *, size_t, const void *, size_t); DNS_PUBLIC size_t dns_d_comp(void *, size_t, const void *, size_t, struct dns_packet *, int *); DNS_PUBLIC size_t dns_d_expand(void *, size_t, unsigned short, struct dns_packet *, int *); DNS_PUBLIC unsigned short dns_d_skip(unsigned short, struct dns_packet *); DNS_PUBLIC int dns_d_push(struct dns_packet *, const void *, size_t); DNS_PUBLIC size_t dns_d_cname(void *, size_t, const void *, size_t, struct dns_packet *, int *error); /* * R E S O U R C E R E C O R D I N T E R F A C E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_rr { enum dns_section section; struct { unsigned short p; unsigned short len; } dn; enum dns_type type; enum dns_class class; unsigned ttl; struct { unsigned short p; unsigned short len; } rd; }; /* struct dns_rr */ DNS_PUBLIC int dns_rr_copy(struct dns_packet *, struct dns_rr *, struct dns_packet *); DNS_PUBLIC int dns_rr_parse(struct dns_rr *, unsigned short, struct dns_packet *); DNS_PUBLIC unsigned short dns_rr_skip(unsigned short, struct dns_packet *); DNS_PUBLIC int dns_rr_cmp(struct dns_rr *, struct dns_packet *, struct dns_rr *, struct dns_packet *); DNS_PUBLIC size_t dns_rr_print(void *, size_t, struct dns_rr *, struct dns_packet *, int *); struct dns_rr_i { enum dns_section section; const void *name; enum dns_type type; enum dns_class class; const void *data; int follow; int (*sort)(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *); unsigned args[2]; struct { unsigned short next; unsigned short count; unsigned exec; unsigned regs[2]; } state, saved; }; /* struct dns_rr_i */ DNS_PUBLIC int dns_rr_i_packet(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *); DNS_PUBLIC int dns_rr_i_order(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *); DNS_PUBLIC int dns_rr_i_shuffle(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *); DNS_PUBLIC void dns_rr_i_init(struct dns_rr_i *); #define dns_rr_i_save(i) ((i)->saved = (i)->state) #define dns_rr_i_rewind(i) ((i)->state = (i)->saved) #define dns_rr_i_count(i) ((i)->state.count) DNS_PUBLIC unsigned dns_rr_grep(struct dns_rr *, unsigned, struct dns_rr_i *, struct dns_packet *, int *); #define dns_rr_foreach_(rr, P, ...) \ for (struct dns_rr_i DNS_PP_XPASTE(i, __LINE__) = { __VA_ARGS__ }; dns_rr_grep((rr), 1, &DNS_PP_XPASTE(i, __LINE__), (P), NULL); ) #define dns_rr_foreach(...) dns_rr_foreach_(__VA_ARGS__) /* * A R E S O U R C E R E C O R D */ struct dns_a { struct in_addr addr; }; /* struct dns_a */ DNS_PUBLIC int dns_a_parse(struct dns_a *, struct dns_rr *, struct dns_packet *); DNS_PUBLIC int dns_a_push(struct dns_packet *, struct dns_a *); DNS_PUBLIC int dns_a_cmp(const struct dns_a *, const struct dns_a *); DNS_PUBLIC size_t dns_a_print(void *, size_t, struct dns_a *); DNS_PUBLIC size_t dns_a_arpa(void *, size_t, const struct dns_a *); /* * AAAA R E S O U R C E R E C O R D */ struct dns_aaaa { struct in6_addr addr; }; /* struct dns_aaaa */ DNS_PUBLIC int dns_aaaa_parse(struct dns_aaaa *, struct dns_rr *, struct dns_packet *); DNS_PUBLIC int dns_aaaa_push(struct dns_packet *, struct dns_aaaa *); DNS_PUBLIC int dns_aaaa_cmp(const struct dns_aaaa *, const struct dns_aaaa *); DNS_PUBLIC size_t dns_aaaa_print(void *, size_t, struct dns_aaaa *); DNS_PUBLIC size_t dns_aaaa_arpa(void *, size_t, const struct dns_aaaa *); /* * MX R E S O U R C E R E C O R D */ struct dns_mx { unsigned short preference; char host[DNS_D_MAXNAME + 1]; }; /* struct dns_mx */ DNS_PUBLIC int dns_mx_parse(struct dns_mx *, struct dns_rr *, struct dns_packet *); DNS_PUBLIC int dns_mx_push(struct dns_packet *, struct dns_mx *); DNS_PUBLIC int dns_mx_cmp(const struct dns_mx *, const struct dns_mx *); DNS_PUBLIC size_t dns_mx_print(void *, size_t, struct dns_mx *); DNS_PUBLIC size_t dns_mx_cname(void *, size_t, struct dns_mx *); /* * NS R E S O U R C E R E C O R D */ struct dns_ns { char host[DNS_D_MAXNAME + 1]; }; /* struct dns_ns */ DNS_PUBLIC int dns_ns_parse(struct dns_ns *, struct dns_rr *, struct dns_packet *); DNS_PUBLIC int dns_ns_push(struct dns_packet *, struct dns_ns *); DNS_PUBLIC int dns_ns_cmp(const struct dns_ns *, const struct dns_ns *); DNS_PUBLIC size_t dns_ns_print(void *, size_t, struct dns_ns *); DNS_PUBLIC size_t dns_ns_cname(void *, size_t, struct dns_ns *); /* * CNAME R E S O U R C E R E C O R D */ struct dns_cname { char host[DNS_D_MAXNAME + 1]; }; /* struct dns_cname */ DNS_PUBLIC int dns_cname_parse(struct dns_cname *, struct dns_rr *, struct dns_packet *); DNS_PUBLIC int dns_cname_push(struct dns_packet *, struct dns_cname *); DNS_PUBLIC int dns_cname_cmp(const struct dns_cname *, const struct dns_cname *); DNS_PUBLIC size_t dns_cname_print(void *, size_t, struct dns_cname *); DNS_PUBLIC size_t dns_cname_cname(void *, size_t, struct dns_cname *); /* * SOA R E S O U R C E R E C O R D */ struct dns_soa { char mname[DNS_D_MAXNAME + 1]; char rname[DNS_D_MAXNAME + 1]; unsigned serial, refresh, retry, expire, minimum; }; /* struct dns_soa */ DNS_PUBLIC int dns_soa_parse(struct dns_soa *, struct dns_rr *, struct dns_packet *); DNS_PUBLIC int dns_soa_push(struct dns_packet *, struct dns_soa *); DNS_PUBLIC int dns_soa_cmp(const struct dns_soa *, const struct dns_soa *); DNS_PUBLIC size_t dns_soa_print(void *, size_t, struct dns_soa *); /* * PTR R E S O U R C E R E C O R D */ struct dns_ptr { char host[DNS_D_MAXNAME + 1]; }; /* struct dns_ptr */ DNS_PUBLIC int dns_ptr_parse(struct dns_ptr *, struct dns_rr *, struct dns_packet *); DNS_PUBLIC int dns_ptr_push(struct dns_packet *, struct dns_ptr *); DNS_PUBLIC int dns_ptr_cmp(const struct dns_ptr *, const struct dns_ptr *); DNS_PUBLIC size_t dns_ptr_print(void *, size_t, struct dns_ptr *); DNS_PUBLIC size_t dns_ptr_cname(void *, size_t, struct dns_ptr *); DNS_PUBLIC size_t dns_ptr_qname(void *, size_t, int, void *); /* * SRV R E S O U R C E R E C O R D */ struct dns_srv { unsigned short priority; unsigned short weight; unsigned short port; char target[DNS_D_MAXNAME + 1]; }; /* struct dns_srv */ DNS_PUBLIC int dns_srv_parse(struct dns_srv *, struct dns_rr *, struct dns_packet *); DNS_PUBLIC int dns_srv_push(struct dns_packet *, struct dns_srv *); DNS_PUBLIC int dns_srv_cmp(const struct dns_srv *, const struct dns_srv *); DNS_PUBLIC size_t dns_srv_print(void *, size_t, struct dns_srv *); DNS_PUBLIC size_t dns_srv_cname(void *, size_t, struct dns_srv *); /* * OPT R E S O U R C E R E C O R D */ #ifndef DNS_OPT_MINDATA #define DNS_OPT_MINDATA 256 #endif #define DNS_OPT_DNSSEC 0x8000 struct dns_opt { enum dns_rcode rcode; unsigned char version; unsigned short flags; union { unsigned short maxsize; /* deprecated as confusing */ unsigned short maxudp; /* maximum UDP payload size */ }; size_t size, len; unsigned char data[DNS_OPT_MINDATA]; }; /* struct dns_opt */ #define DNS_OPT_INIT(opt) { .size = sizeof (*opt) - offsetof(struct dns_opt, data) } DNS_PUBLIC struct dns_opt *dns_opt_init(struct dns_opt *, size_t); DNS_PUBLIC int dns_opt_parse(struct dns_opt *, struct dns_rr *, struct dns_packet *); DNS_PUBLIC int dns_opt_push(struct dns_packet *, struct dns_opt *); DNS_PUBLIC int dns_opt_cmp(const struct dns_opt *, const struct dns_opt *); DNS_PUBLIC size_t dns_opt_print(void *, size_t, struct dns_opt *); DNS_PUBLIC unsigned int dns_opt_ttl(const struct dns_opt *); DNS_PUBLIC unsigned short dns_opt_class(const struct dns_opt *); DNS_PUBLIC dns_error_t dns_opt_data_push(struct dns_opt *, unsigned char, unsigned short, const void *); /* * SSHFP R E S O U R C E R E C O R D */ struct dns_sshfp { enum dns_sshfp_key { DNS_SSHFP_RSA = 1, DNS_SSHFP_DSA = 2, } algo; enum dns_sshfp_digest { DNS_SSHFP_SHA1 = 1, } type; union { unsigned char sha1[20]; } digest; }; /* struct dns_sshfp */ DNS_PUBLIC int dns_sshfp_parse(struct dns_sshfp *, struct dns_rr *, struct dns_packet *); DNS_PUBLIC int dns_sshfp_push(struct dns_packet *, struct dns_sshfp *); DNS_PUBLIC int dns_sshfp_cmp(const struct dns_sshfp *, const struct dns_sshfp *); DNS_PUBLIC size_t dns_sshfp_print(void *, size_t, struct dns_sshfp *); /* * TXT R E S O U R C E R E C O R D */ #ifndef DNS_TXT_MINDATA #define DNS_TXT_MINDATA 1024 #endif struct dns_txt { size_t size, len; unsigned char data[DNS_TXT_MINDATA]; }; /* struct dns_txt */ DNS_PUBLIC struct dns_txt *dns_txt_init(struct dns_txt *, size_t); DNS_PUBLIC int dns_txt_parse(struct dns_txt *, struct dns_rr *, struct dns_packet *); DNS_PUBLIC int dns_txt_push(struct dns_packet *, struct dns_txt *); DNS_PUBLIC int dns_txt_cmp(const struct dns_txt *, const struct dns_txt *); DNS_PUBLIC size_t dns_txt_print(void *, size_t, struct dns_txt *); /* * ANY R E S O U R C E R E C O R D */ union dns_any { struct dns_a a; struct dns_aaaa aaaa; struct dns_mx mx; struct dns_ns ns; struct dns_cname cname; struct dns_soa soa; struct dns_ptr ptr; struct dns_srv srv; struct dns_opt opt; struct dns_sshfp sshfp; struct dns_txt txt, spf, rdata; }; /* union dns_any */ #define DNS_ANY_INIT(any) { .rdata = { .size = sizeof *(any) - offsetof(struct dns_txt, data) } } DNS_PUBLIC union dns_any *dns_any_init(union dns_any *, size_t); DNS_PUBLIC int dns_any_parse(union dns_any *, struct dns_rr *, struct dns_packet *); DNS_PUBLIC int dns_any_push(struct dns_packet *, union dns_any *, enum dns_type); DNS_PUBLIC int dns_any_cmp(const union dns_any *, enum dns_type, const union dns_any *, enum dns_type); DNS_PUBLIC size_t dns_any_print(void *, size_t, union dns_any *, enum dns_type); DNS_PUBLIC size_t dns_any_cname(void *, size_t, union dns_any *, enum dns_type); /* * H O S T S I N T E R F A C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_hosts; DNS_PUBLIC struct dns_hosts *dns_hosts_open(int *); DNS_PUBLIC void dns_hosts_close(struct dns_hosts *); DNS_PUBLIC dns_refcount_t dns_hosts_acquire(struct dns_hosts *); DNS_PUBLIC dns_refcount_t dns_hosts_release(struct dns_hosts *); DNS_PUBLIC struct dns_hosts *dns_hosts_mortal(struct dns_hosts *); DNS_PUBLIC struct dns_hosts *dns_hosts_local(int *); DNS_PUBLIC int dns_hosts_loadfile(struct dns_hosts *, FILE *); DNS_PUBLIC int dns_hosts_loadpath(struct dns_hosts *, const char *); DNS_PUBLIC int dns_hosts_dump(struct dns_hosts *, FILE *); DNS_PUBLIC int dns_hosts_insert(struct dns_hosts *, int, const void *, const void *, _Bool); DNS_PUBLIC struct dns_packet *dns_hosts_query(struct dns_hosts *, struct dns_packet *, int *); /* * R E S O L V . C O N F I N T E R F A C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_resolv_conf { struct sockaddr_storage nameserver[3]; char search[4][DNS_D_MAXNAME + 1]; /* (f)ile, (b)ind, (c)ache */ char lookup[4 * (1 + (4 * 2))]; /* getaddrinfo family by preference order ("inet4", "inet6") */ int family[3]; struct { _Bool edns0; unsigned ndots; unsigned timeout; unsigned attempts; _Bool rotate; _Bool recurse; _Bool smart; enum { DNS_RESCONF_TCP_ENABLE, DNS_RESCONF_TCP_ONLY, DNS_RESCONF_TCP_SOCKS, DNS_RESCONF_TCP_DISABLE, } tcp; } options; struct sockaddr_storage iface; struct { /* PRIVATE */ dns_atomic_t refcount; } _; }; /* struct dns_resolv_conf */ DNS_PUBLIC struct dns_resolv_conf *dns_resconf_open(int *); DNS_PUBLIC void dns_resconf_close(struct dns_resolv_conf *); DNS_PUBLIC dns_refcount_t dns_resconf_acquire(struct dns_resolv_conf *); DNS_PUBLIC dns_refcount_t dns_resconf_release(struct dns_resolv_conf *); DNS_PUBLIC struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *); DNS_PUBLIC struct dns_resolv_conf *dns_resconf_local(int *); DNS_PUBLIC struct dns_resolv_conf *dns_resconf_root(int *); DNS_PUBLIC int dns_resconf_pton(struct sockaddr_storage *, const char *); DNS_PUBLIC int dns_resconf_loadfile(struct dns_resolv_conf *, FILE *); DNS_PUBLIC int dns_resconf_loadpath(struct dns_resolv_conf *, const char *); DNS_PUBLIC int dns_nssconf_loadfile(struct dns_resolv_conf *, FILE *); DNS_PUBLIC int dns_nssconf_loadpath(struct dns_resolv_conf *, const char *); DNS_PUBLIC int dns_resconf_dump(struct dns_resolv_conf *, FILE *); DNS_PUBLIC int dns_nssconf_dump(struct dns_resolv_conf *, FILE *); DNS_PUBLIC int dns_resconf_setiface(struct dns_resolv_conf *, const char *, unsigned short); typedef unsigned long dns_resconf_i_t; DNS_PUBLIC size_t dns_resconf_search(void *, size_t, const void *, size_t, struct dns_resolv_conf *, dns_resconf_i_t *); /* * H I N T S E R V E R I N T E R F A C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_hints; DNS_PUBLIC struct dns_hints *dns_hints_open(struct dns_resolv_conf *, int *); DNS_PUBLIC void dns_hints_close(struct dns_hints *); DNS_PUBLIC dns_refcount_t dns_hints_acquire(struct dns_hints *); DNS_PUBLIC dns_refcount_t dns_hints_release(struct dns_hints *); DNS_PUBLIC struct dns_hints *dns_hints_mortal(struct dns_hints *); DNS_PUBLIC int dns_hints_insert(struct dns_hints *, const char *, const struct sockaddr *, unsigned); DNS_PUBLIC unsigned dns_hints_insert_resconf(struct dns_hints *, const char *, const struct dns_resolv_conf *, int *); DNS_PUBLIC struct dns_hints *dns_hints_local(struct dns_resolv_conf *, int *); DNS_PUBLIC struct dns_hints *dns_hints_root(struct dns_resolv_conf *, int *); DNS_PUBLIC struct dns_packet *dns_hints_query(struct dns_hints *, struct dns_packet *, int *); DNS_PUBLIC int dns_hints_dump(struct dns_hints *, FILE *); struct dns_hints_i { const char *zone; struct { unsigned next; unsigned seed; } state; }; /* struct dns_hints_i */ DNS_PUBLIC unsigned dns_hints_grep(struct sockaddr **, socklen_t *, unsigned, struct dns_hints_i *, struct dns_hints *); /* * C A C H E I N T E R F A C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_cache { void *state; dns_refcount_t (*acquire)(struct dns_cache *); dns_refcount_t (*release)(struct dns_cache *); struct dns_packet *(*query)(struct dns_packet *, struct dns_cache *, int *); int (*submit)(struct dns_packet *, struct dns_cache *); int (*check)(struct dns_cache *); struct dns_packet *(*fetch)(struct dns_cache *, int *); int (*pollfd)(struct dns_cache *); short (*events)(struct dns_cache *); void (*clear)(struct dns_cache *); union { long i; void *p; } arg[3]; struct { /* PRIVATE */ dns_atomic_t refcount; } _; }; /* struct dns_cache */ DNS_PUBLIC struct dns_cache *dns_cache_init(struct dns_cache *); DNS_PUBLIC void dns_cache_close(struct dns_cache *); /* * A P P L I C A T I O N I N T E R F A C E * * Options to change the behavior of the API. Applies across all the * different components. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define DNS_OPTS_INITIALIZER_ { 0, 0 }, 0, 0 #define DNS_OPTS_INITIALIZER { DNS_OPTS_INITIALIZER_ } struct dns_options { /* * If the callback closes *fd, it must set it to -1. Otherwise, the * descriptor is queued and lazily closed at object destruction or * by an explicit call to _clear(). This allows safe use of * kqueue(2), epoll(2), et al -style persistent events. */ struct { void *arg; int (*cb)(int *fd, void *arg); } closefd; /* bitmask for _events() routines */ enum dns_events { DNS_SYSPOLL, DNS_LIBEVENT, } events; /* Use this SOCKS server. */ const struct sockaddr_storage *socks_host; /* Credentials for the SOCKS server (optional). */ const char *socks_user; const char *socks_password; }; /* struct dns_options */ /* * S T A T S I N T E R F A C E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_stat { size_t queries; struct { struct { size_t count, bytes; } sent, rcvd; } udp, tcp; }; /* struct dns_stat */ /* * S O C K E T I N T E R F A C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_socket; DNS_PUBLIC struct dns_socket *dns_so_open(const struct sockaddr *, int, const struct dns_options *, int *error); DNS_PUBLIC void dns_so_close(struct dns_socket *); DNS_PUBLIC void dns_so_reset(struct dns_socket *); DNS_PUBLIC unsigned short dns_so_mkqid(struct dns_socket *so); DNS_PUBLIC struct dns_packet *dns_so_query(struct dns_socket *, struct dns_packet *, struct sockaddr *, int *); DNS_PUBLIC int dns_so_submit(struct dns_socket *, struct dns_packet *, struct sockaddr *); DNS_PUBLIC int dns_so_check(struct dns_socket *); DNS_PUBLIC struct dns_packet *dns_so_fetch(struct dns_socket *, int *); DNS_PUBLIC time_t dns_so_elapsed(struct dns_socket *); DNS_PUBLIC void dns_so_clear(struct dns_socket *); DNS_PUBLIC int dns_so_events(struct dns_socket *); DNS_PUBLIC int dns_so_pollfd(struct dns_socket *); DNS_PUBLIC int dns_so_poll(struct dns_socket *, int); DNS_PUBLIC const struct dns_stat *dns_so_stat(struct dns_socket *); DNS_PUBLIC struct dns_trace *dns_so_trace(struct dns_socket *); DNS_PUBLIC void dns_so_settrace(struct dns_socket *, struct dns_trace *); /* * R E S O L V E R I N T E R F A C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_resolver; DNS_PUBLIC struct dns_resolver *dns_res_open(struct dns_resolv_conf *, struct dns_hosts *hosts, struct dns_hints *, struct dns_cache *, const struct dns_options *, int *); DNS_PUBLIC struct dns_resolver *dns_res_stub(const struct dns_options *, int *); DNS_PUBLIC void dns_res_reset(struct dns_resolver *); DNS_PUBLIC void dns_res_close(struct dns_resolver *); DNS_PUBLIC dns_refcount_t dns_res_acquire(struct dns_resolver *); DNS_PUBLIC dns_refcount_t dns_res_release(struct dns_resolver *); DNS_PUBLIC struct dns_resolver *dns_res_mortal(struct dns_resolver *); DNS_PUBLIC int dns_res_submit(struct dns_resolver *, const char *, enum dns_type, enum dns_class); DNS_PUBLIC int dns_res_submit2(struct dns_resolver *, const char *, size_t, enum dns_type, enum dns_class); DNS_PUBLIC int dns_res_check(struct dns_resolver *); DNS_PUBLIC struct dns_packet *dns_res_fetch(struct dns_resolver *, int *); DNS_PUBLIC time_t dns_res_elapsed(struct dns_resolver *); DNS_PUBLIC void dns_res_clear(struct dns_resolver *); DNS_PUBLIC int dns_res_events(struct dns_resolver *); DNS_PUBLIC int dns_res_pollfd(struct dns_resolver *); DNS_PUBLIC time_t dns_res_timeout(struct dns_resolver *); DNS_PUBLIC int dns_res_poll(struct dns_resolver *, int); DNS_PUBLIC struct dns_packet *dns_res_query(struct dns_resolver *, const char *, enum dns_type, enum dns_class, int, int *); DNS_PUBLIC const struct dns_stat *dns_res_stat(struct dns_resolver *); DNS_PUBLIC void dns_res_sethints(struct dns_resolver *, struct dns_hints *); DNS_PUBLIC struct dns_trace *dns_res_trace(struct dns_resolver *); DNS_PUBLIC void dns_res_settrace(struct dns_resolver *, struct dns_trace *); /* * A D D R I N F O I N T E R F A C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_addrinfo; DNS_PUBLIC struct dns_addrinfo *dns_ai_open(const char *, const char *, enum dns_type, const struct addrinfo *, struct dns_resolver *, int *); DNS_PUBLIC void dns_ai_close(struct dns_addrinfo *); DNS_PUBLIC int dns_ai_nextent(struct addrinfo **, struct dns_addrinfo *); DNS_PUBLIC size_t dns_ai_print(void *, size_t, struct addrinfo *, struct dns_addrinfo *); DNS_PUBLIC time_t dns_ai_elapsed(struct dns_addrinfo *); DNS_PUBLIC void dns_ai_clear(struct dns_addrinfo *); DNS_PUBLIC int dns_ai_events(struct dns_addrinfo *); DNS_PUBLIC int dns_ai_pollfd(struct dns_addrinfo *); DNS_PUBLIC time_t dns_ai_timeout(struct dns_addrinfo *); DNS_PUBLIC int dns_ai_poll(struct dns_addrinfo *, int); DNS_PUBLIC const struct dns_stat *dns_ai_stat(struct dns_addrinfo *); DNS_PUBLIC struct dns_trace *dns_ai_trace(struct dns_addrinfo *); DNS_PUBLIC void dns_ai_settrace(struct dns_addrinfo *, struct dns_trace *); /* * Q U E R Y T R A C I N G I N T E R F A C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define DNS_TRACE_ID_C(n) UINT64_C(n) typedef uint64_t dns_trace_id_t; #define DNS_TRACE_ABI 0x20160803 struct dns_trace_event { enum { DNS_TE_RES_SUBMIT = 1, DNS_TE_RES_FETCH = 99, DNS_TE_SO_SUBMIT = 100, DNS_TE_SO_VERIFY, DNS_TE_SO_FETCH = 199, DNS_TE_SYS_CONNECT = 200, DNS_TE_SYS_SEND, DNS_TE_SYS_RECV, } type; size_t size; dns_trace_id_t id; struct timespec ts; int abi; union { struct { char qname[DNS_D_MAXNAME + 1]; enum dns_type qtype; enum dns_class qclass; int error; } res_submit; struct { int error; } res_fetch; struct { struct sockaddr_storage haddr; char hname[DNS_D_MAXNAME + 1]; int error; } so_submit; struct { int error; } so_verify; struct { int error; } so_fetch; struct { struct sockaddr_storage src, dst; int socktype; dns_error_t error; } sys_connect, sys_send, sys_recv; }; unsigned char data[]; }; static inline size_t dns_te_datasize(const struct dns_trace_event *te) { size_t n = offsetof(struct dns_trace_event, data); return (n <= te->size)? te->size - n : 0; } struct dns_trace; DNS_PUBLIC int dns_trace_abi(void); DNS_PUBLIC struct dns_trace *dns_trace_open(FILE *, dns_error_t *); DNS_PUBLIC void dns_trace_close(struct dns_trace *); DNS_PUBLIC dns_refcount_t dns_trace_acquire(struct dns_trace *); DNS_PUBLIC dns_refcount_t dns_trace_release(struct dns_trace *); DNS_PUBLIC dns_trace_id_t dns_trace_id(struct dns_trace *); DNS_PUBLIC dns_trace_id_t dns_trace_setid(struct dns_trace *, dns_trace_id_t); DNS_PUBLIC struct dns_trace_event *dns_trace_get(struct dns_trace *, struct dns_trace_event **, dns_error_t *); DNS_PUBLIC struct dns_trace_event *dns_trace_tag(struct dns_trace *, struct dns_trace_event *); DNS_PUBLIC dns_error_t dns_trace_put(struct dns_trace *, const struct dns_trace_event *, const void *, size_t); DNS_PUBLIC dns_error_t dns_trace_dump(struct dns_trace *, FILE *); DNS_PUBLIC struct dns_trace_event *dns_trace_fget(struct dns_trace_event **, FILE *, dns_error_t *); DNS_PUBLIC dns_error_t dns_trace_fput(const struct dns_trace_event *, const void *, size_t, FILE *); /* * U T I L I T Y I N T E R F A C E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ DNS_PUBLIC size_t dns_strlcpy(char *, const char *, size_t); DNS_PUBLIC size_t dns_strlcat(char *, const char *, size_t); /* * M A C R O M A G I C S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define DNS_PP_MIN(a, b) (((a) < (b))? (a) : (b)) #define DNS_PP_MAX(a, b) (((a) > (b))? (a) : (b)) #define DNS_PP_NARG_(a, b, c, d, e, f, g, h, i, j, k, N,...) N #define DNS_PP_NARG(...) DNS_PP_NARG_(__VA_ARGS__, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) #define DNS_PP_CALL(F, ...) F(__VA_ARGS__) #define DNS_PP_PASTE(x, y) x##y #define DNS_PP_XPASTE(x, y) DNS_PP_PASTE(x, y) #define DNS_PP_STRINGIFY_(s) #s #define DNS_PP_STRINGIFY(s) DNS_PP_STRINGIFY_(s) #define DNS_PP_D1 0 #define DNS_PP_D2 1 #define DNS_PP_D3 2 #define DNS_PP_D4 3 #define DNS_PP_D5 4 #define DNS_PP_D6 5 #define DNS_PP_D7 6 #define DNS_PP_D8 7 #define DNS_PP_D9 8 #define DNS_PP_D10 9 #define DNS_PP_D11 10 #define DNS_PP_DEC(N) DNS_PP_XPASTE(DNS_PP_D, N) #endif /* DNS_H */