1075 lines
26 KiB
C
1075 lines
26 KiB
C
|
/* ==========================================================================
|
||
|
* dns.h - Recursive, Reentrant DNS Resolver.
|
||
|
* --------------------------------------------------------------------------
|
||
|
* Copyright (c) 2009, 2010 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 <stddef.h> /* size_t offsetof() */
|
||
|
#include <stdio.h> /* FILE */
|
||
|
|
||
|
#include <string.h> /* strlen(3) */
|
||
|
|
||
|
#include <time.h> /* time_t */
|
||
|
|
||
|
#if _WIN32
|
||
|
#include <winsock2.h>
|
||
|
#include <ws2tcpip.h>
|
||
|
#else
|
||
|
#include <sys/types.h> /* socklen_t */
|
||
|
#include <sys/socket.h> /* struct socket */
|
||
|
|
||
|
#include <poll.h> /* POLLIN POLLOUT */
|
||
|
|
||
|
#include <netinet/in.h> /* struct in_addr struct in6_addr */
|
||
|
|
||
|
#include <netdb.h> /* struct addrinfo */
|
||
|
#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 0x20110117
|
||
|
#define DNS_V_ABI 0x20100709
|
||
|
#define DNS_V_API 0x20100709
|
||
|
|
||
|
|
||
|
const char *dns_vendor(void);
|
||
|
|
||
|
int dns_v_rel(void);
|
||
|
int dns_v_abi(void);
|
||
|
int dns_v_api(void);
|
||
|
|
||
|
|
||
|
/*
|
||
|
* E R R O R S
|
||
|
*
|
||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
|
||
|
enum dns_errno {
|
||
|
DNS_ENOBUFS = -(('d' << 24) | ('n' << 16) | ('s' << 8) | 64),
|
||
|
DNS_EILLEGAL,
|
||
|
DNS_EORDER,
|
||
|
DNS_ESECTION,
|
||
|
DNS_EUNKNOWN,
|
||
|
}; /* dns_errno */
|
||
|
|
||
|
const char *dns_strerror(int);
|
||
|
|
||
|
extern int dns_debug;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* 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_SSHFP = 44,
|
||
|
DNS_T_SPF = 99,
|
||
|
|
||
|
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,
|
||
|
}; /* 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" */
|
||
|
|
||
|
const char *dns_strsection(enum dns_section, void *, size_t);
|
||
|
#define dns_strsection3(a, b, c) \
|
||
|
dns_strsection((a), (b), (c))
|
||
|
#define dns_strsection1(a) dns_strsection((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1)
|
||
|
#define dns_strsection(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strsection, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
|
||
|
|
||
|
enum dns_section dns_isection(const char *);
|
||
|
|
||
|
const char *dns_strclass(enum dns_class, void *, size_t);
|
||
|
#define dns_strclass3(a, b, c) dns_strclass((a), (b), (c))
|
||
|
#define dns_strclass1(a) dns_strclass((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1)
|
||
|
#define dns_strclass(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strclass, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
|
||
|
|
||
|
enum dns_class dns_iclass(const char *);
|
||
|
|
||
|
const char *dns_strtype(enum dns_type, void *, size_t);
|
||
|
#define dns_strtype3(a, b, c) dns_strtype((a), (b), (c))
|
||
|
#define dns_strtype1(a) dns_strtype((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1)
|
||
|
#define dns_strtype(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strtype, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
|
||
|
|
||
|
enum dns_type dns_itype(const char *);
|
||
|
|
||
|
const char *dns_stropcode(enum dns_opcode);
|
||
|
|
||
|
enum dns_opcode dns_iopcode(const char *);
|
||
|
|
||
|
const char *dns_strrcode(enum dns_rcode);
|
||
|
|
||
|
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;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* C R Y P T O I N T E R F A C E S
|
||
|
*
|
||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
|
||
|
extern unsigned (*dns_random)(void);
|
||
|
|
||
|
|
||
|
/*
|
||
|
* P A C K E T I N T E R F A C E
|
||
|
*
|
||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
|
||
|
struct dns_header {
|
||
|
unsigned qid:16;
|
||
|
|
||
|
#if BYTE_ORDER == 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_s_memo {
|
||
|
unsigned short base, end;
|
||
|
} qd, an, ns, ar;
|
||
|
|
||
|
struct { struct dns_packet *cqe_next, *cqe_prev; } cqe;
|
||
|
|
||
|
size_t size, end;
|
||
|
|
||
|
int:16; /* tcp padding */
|
||
|
|
||
|
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 maximum desired payload */
|
||
|
#define dns_p_new(n) (dns_p_init((struct dns_packet *)&(union { unsigned char b[dns_p_calcsize((n))]; struct dns_packet p; }){ { 0 } }, dns_p_calcsize((n))))
|
||
|
|
||
|
/** takes size of entire packet structure as allocated */
|
||
|
struct dns_packet *dns_p_init(struct dns_packet *, size_t);
|
||
|
|
||
|
/** takes size of maximum desired payload */
|
||
|
struct dns_packet *dns_p_make(size_t, int *);
|
||
|
|
||
|
int dns_p_grow(struct dns_packet **);
|
||
|
|
||
|
struct dns_packet *dns_p_copy(struct dns_packet *, const struct dns_packet *);
|
||
|
|
||
|
#define dns_p_opcode(P) (dns_header(P)->opcode)
|
||
|
|
||
|
#define dns_p_rcode(P) (dns_header(P)->rcode)
|
||
|
|
||
|
unsigned dns_p_count(struct dns_packet *, enum dns_section);
|
||
|
|
||
|
int dns_p_push(struct dns_packet *, enum dns_section, const void *, size_t, enum dns_type, enum dns_class, unsigned, const void *);
|
||
|
|
||
|
void dns_p_dictadd(struct dns_packet *, unsigned short);
|
||
|
|
||
|
struct dns_packet *dns_p_merge(struct dns_packet *, enum dns_section, struct dns_packet *, enum dns_section, int *);
|
||
|
|
||
|
void dns_p_dump(struct dns_packet *, FILE *);
|
||
|
|
||
|
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 */
|
||
|
|
||
|
#define dns_d_new3(a, b, f) dns_d_init(&(char[DNS_D_MAXNAME + 1]){ 0 }, DNS_D_MAXNAME + 1, (a), (b), (f))
|
||
|
#define dns_d_new2(a, f) dns_d_new3((a), strlen((a)), (f))
|
||
|
#define dns_d_new1(a) dns_d_new3((a), strlen((a)), DNS_D_ANCHOR)
|
||
|
#define dns_d_new(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_d_new, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__)
|
||
|
|
||
|
char *dns_d_init(void *, size_t, const void *, size_t, int);
|
||
|
|
||
|
size_t dns_d_anchor(void *, size_t, const void *, size_t);
|
||
|
|
||
|
size_t dns_d_cleave(void *, size_t, const void *, size_t);
|
||
|
|
||
|
size_t dns_d_comp(void *, size_t, const void *, size_t, struct dns_packet *, int *);
|
||
|
|
||
|
size_t dns_d_expand(void *, size_t, unsigned short, struct dns_packet *, int *);
|
||
|
|
||
|
unsigned short dns_d_skip(unsigned short, struct dns_packet *);
|
||
|
|
||
|
int dns_d_push(struct dns_packet *, const void *, size_t);
|
||
|
|
||
|
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 */
|
||
|
|
||
|
|
||
|
int dns_rr_copy(struct dns_packet *, struct dns_rr *, struct dns_packet *);
|
||
|
|
||
|
int dns_rr_parse(struct dns_rr *, unsigned short, struct dns_packet *);
|
||
|
|
||
|
unsigned short dns_rr_skip(unsigned short, struct dns_packet *);
|
||
|
|
||
|
int dns_rr_cmp(struct dns_rr *, struct dns_packet *, struct dns_rr *, struct dns_packet *);
|
||
|
|
||
|
size_t dns_rr_print(void *, size_t, struct dns_rr *, struct dns_packet *, int *);
|
||
|
|
||
|
|
||
|
#define dns_rr_i_new(P, ...) dns_rr_i_init(&(struct dns_rr_i){ 0, __VA_ARGS__ }, (P))
|
||
|
|
||
|
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)();
|
||
|
unsigned args[2];
|
||
|
|
||
|
struct {
|
||
|
unsigned short next;
|
||
|
unsigned short count;
|
||
|
|
||
|
unsigned exec;
|
||
|
unsigned regs[2];
|
||
|
} state, saved;
|
||
|
}; /* struct dns_rr_i */
|
||
|
|
||
|
int dns_rr_i_packet(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *);
|
||
|
|
||
|
int dns_rr_i_order(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *);
|
||
|
|
||
|
int dns_rr_i_shuffle(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *);
|
||
|
|
||
|
struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *, struct dns_packet *);
|
||
|
|
||
|
#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)
|
||
|
|
||
|
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__) = *dns_rr_i_new((P), __VA_ARGS__); dns_rr_grep((rr), 1, &DNS_PP_XPASTE(i, __LINE__), (P), &(int){ 0 }); )
|
||
|
|
||
|
#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 */
|
||
|
|
||
|
int dns_a_parse(struct dns_a *, struct dns_rr *, struct dns_packet *);
|
||
|
|
||
|
int dns_a_push(struct dns_packet *, struct dns_a *);
|
||
|
|
||
|
int dns_a_cmp(const struct dns_a *, const struct dns_a *);
|
||
|
|
||
|
size_t dns_a_print(void *, size_t, 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 */
|
||
|
|
||
|
int dns_aaaa_parse(struct dns_aaaa *, struct dns_rr *, struct dns_packet *);
|
||
|
|
||
|
int dns_aaaa_push(struct dns_packet *, struct dns_aaaa *);
|
||
|
|
||
|
int dns_aaaa_cmp(const struct dns_aaaa *, const struct dns_aaaa *);
|
||
|
|
||
|
size_t dns_aaaa_print(void *, size_t, 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 */
|
||
|
|
||
|
int dns_mx_parse(struct dns_mx *, struct dns_rr *, struct dns_packet *);
|
||
|
|
||
|
int dns_mx_push(struct dns_packet *, struct dns_mx *);
|
||
|
|
||
|
int dns_mx_cmp(const struct dns_mx *, const struct dns_mx *);
|
||
|
|
||
|
size_t dns_mx_print(void *, size_t, struct dns_mx *);
|
||
|
|
||
|
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 */
|
||
|
|
||
|
int dns_ns_parse(struct dns_ns *, struct dns_rr *, struct dns_packet *);
|
||
|
|
||
|
int dns_ns_push(struct dns_packet *, struct dns_ns *);
|
||
|
|
||
|
int dns_ns_cmp(const struct dns_ns *, const struct dns_ns *);
|
||
|
|
||
|
size_t dns_ns_print(void *, size_t, struct dns_ns *);
|
||
|
|
||
|
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 */
|
||
|
|
||
|
int dns_cname_parse(struct dns_cname *, struct dns_rr *, struct dns_packet *);
|
||
|
|
||
|
int dns_cname_push(struct dns_packet *, struct dns_cname *);
|
||
|
|
||
|
int dns_cname_cmp(const struct dns_cname *, const struct dns_cname *);
|
||
|
|
||
|
size_t dns_cname_print(void *, size_t, struct dns_cname *);
|
||
|
|
||
|
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 */
|
||
|
|
||
|
int dns_soa_parse(struct dns_soa *, struct dns_rr *, struct dns_packet *);
|
||
|
|
||
|
int dns_soa_push(struct dns_packet *, struct dns_soa *);
|
||
|
|
||
|
int dns_soa_cmp(const struct dns_soa *, const struct dns_soa *);
|
||
|
|
||
|
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 */
|
||
|
|
||
|
int dns_ptr_parse(struct dns_ptr *, struct dns_rr *, struct dns_packet *);
|
||
|
|
||
|
int dns_ptr_push(struct dns_packet *, struct dns_ptr *);
|
||
|
|
||
|
int dns_ptr_cmp(const struct dns_ptr *, const struct dns_ptr *);
|
||
|
|
||
|
size_t dns_ptr_print(void *, size_t, struct dns_ptr *);
|
||
|
|
||
|
size_t dns_ptr_cname(void *, size_t, struct dns_ptr *);
|
||
|
|
||
|
|
||
|
/*
|
||
|
* 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 */
|
||
|
|
||
|
int dns_srv_parse(struct dns_srv *, struct dns_rr *, struct dns_packet *);
|
||
|
|
||
|
int dns_srv_push(struct dns_packet *, struct dns_srv *);
|
||
|
|
||
|
int dns_srv_cmp(const struct dns_srv *, const struct dns_srv *);
|
||
|
|
||
|
size_t dns_srv_print(void *, size_t, struct dns_srv *);
|
||
|
|
||
|
size_t dns_srv_cname(void *, size_t, struct dns_srv *);
|
||
|
|
||
|
|
||
|
/*
|
||
|
* 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 */
|
||
|
|
||
|
int dns_sshfp_parse(struct dns_sshfp *, struct dns_rr *, struct dns_packet *);
|
||
|
|
||
|
int dns_sshfp_push(struct dns_packet *, struct dns_sshfp *);
|
||
|
|
||
|
int dns_sshfp_cmp(const struct dns_sshfp *, const struct dns_sshfp *);
|
||
|
|
||
|
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 */
|
||
|
|
||
|
struct dns_txt *dns_txt_init(struct dns_txt *, size_t);
|
||
|
|
||
|
int dns_txt_parse(struct dns_txt *, struct dns_rr *, struct dns_packet *);
|
||
|
|
||
|
int dns_txt_push(struct dns_packet *, struct dns_txt *);
|
||
|
|
||
|
int dns_txt_cmp(const struct dns_txt *, const struct dns_txt *);
|
||
|
|
||
|
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_sshfp sshfp;
|
||
|
struct dns_txt txt, spf, rdata;
|
||
|
}; /* union dns_any */
|
||
|
|
||
|
#define DNS_ANY_INIT(any) { .rdata = { .size = sizeof *(any) } }
|
||
|
|
||
|
union dns_any *dns_any_init(union dns_any *, size_t);
|
||
|
|
||
|
int dns_any_parse(union dns_any *, struct dns_rr *, struct dns_packet *);
|
||
|
|
||
|
int dns_any_push(struct dns_packet *, union dns_any *, enum dns_type);
|
||
|
|
||
|
int dns_any_cmp(const union dns_any *, enum dns_type, const union dns_any *, enum dns_type);
|
||
|
|
||
|
size_t dns_any_print(void *, size_t, union dns_any *, enum dns_type);
|
||
|
|
||
|
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;
|
||
|
|
||
|
struct dns_hosts *dns_hosts_open(int *);
|
||
|
|
||
|
void dns_hosts_close(struct dns_hosts *);
|
||
|
|
||
|
unsigned dns_hosts_acquire(struct dns_hosts *);
|
||
|
|
||
|
unsigned dns_hosts_release(struct dns_hosts *);
|
||
|
|
||
|
struct dns_hosts *dns_hosts_mortal(struct dns_hosts *);
|
||
|
|
||
|
struct dns_hosts *dns_hosts_local(int *);
|
||
|
|
||
|
int dns_hosts_loadfile(struct dns_hosts *, FILE *);
|
||
|
|
||
|
int dns_hosts_loadpath(struct dns_hosts *, const char *);
|
||
|
|
||
|
int dns_hosts_dump(struct dns_hosts *, FILE *);
|
||
|
|
||
|
int dns_hosts_insert(struct dns_hosts *, int, const void *, const void *, _Bool);
|
||
|
|
||
|
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[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_DISABLE,
|
||
|
} tcp;
|
||
|
} options;
|
||
|
|
||
|
struct sockaddr_storage iface;
|
||
|
|
||
|
struct { /* PRIVATE */
|
||
|
dns_atomic_t refcount;
|
||
|
} _;
|
||
|
}; /* struct dns_resolv_conf */
|
||
|
|
||
|
struct dns_resolv_conf *dns_resconf_open(int *);
|
||
|
|
||
|
void dns_resconf_close(struct dns_resolv_conf *);
|
||
|
|
||
|
unsigned dns_resconf_acquire(struct dns_resolv_conf *);
|
||
|
|
||
|
unsigned dns_resconf_release(struct dns_resolv_conf *);
|
||
|
|
||
|
struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *);
|
||
|
|
||
|
struct dns_resolv_conf *dns_resconf_local(int *);
|
||
|
|
||
|
struct dns_resolv_conf *dns_resconf_root(int *);
|
||
|
|
||
|
int dns_resconf_loadfile(struct dns_resolv_conf *, FILE *);
|
||
|
|
||
|
int dns_resconf_loadpath(struct dns_resolv_conf *, const char *);
|
||
|
|
||
|
int dns_resconf_dump(struct dns_resolv_conf *, FILE *);
|
||
|
|
||
|
int dns_resconf_setiface(struct dns_resolv_conf *, const char *, unsigned short);
|
||
|
|
||
|
typedef unsigned long dns_resconf_i_t;
|
||
|
|
||
|
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;
|
||
|
|
||
|
struct dns_hints *dns_hints_open(struct dns_resolv_conf *, int *);
|
||
|
|
||
|
void dns_hints_close(struct dns_hints *);
|
||
|
|
||
|
unsigned dns_hints_acquire(struct dns_hints *);
|
||
|
|
||
|
unsigned dns_hints_release(struct dns_hints *);
|
||
|
|
||
|
struct dns_hints *dns_hints_mortal(struct dns_hints *);
|
||
|
|
||
|
int dns_hints_insert(struct dns_hints *, const char *, const struct sockaddr *, unsigned);
|
||
|
|
||
|
unsigned dns_hints_insert_resconf(struct dns_hints *, const char *, const struct dns_resolv_conf *, int *);
|
||
|
|
||
|
struct dns_hints *dns_hints_local(struct dns_resolv_conf *, int *);
|
||
|
|
||
|
struct dns_hints *dns_hints_root(struct dns_resolv_conf *, int *);
|
||
|
|
||
|
|
||
|
struct dns_hints_i {
|
||
|
const char *zone;
|
||
|
|
||
|
struct {
|
||
|
unsigned next;
|
||
|
unsigned seed;
|
||
|
} state;
|
||
|
}; /* struct dns_hints_i */
|
||
|
|
||
|
#define dns_hints_i_new(...) (&(struct dns_hints_i){ __VA_ARGS__ })
|
||
|
|
||
|
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_atomic_t (*acquire)(struct dns_cache *);
|
||
|
dns_atomic_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 dns_cache */
|
||
|
|
||
|
|
||
|
struct dns_cache *dns_cache_init(struct dns_cache *);
|
||
|
|
||
|
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
|
||
|
#define DNS_OPTS_INITIALIZER { DNS_OPTS_INITIALIZER_ }
|
||
|
#define DNS_OPTS_INIT(...) { DNS_OPTS_INITIALIZER_, __VA_ARGS__ }
|
||
|
|
||
|
#define dns_opts(...) (&(struct dns_options)DNS_OPTS_INIT(__VA_ARGS__))
|
||
|
|
||
|
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;
|
||
|
}; /* 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;
|
||
|
|
||
|
struct dns_socket *dns_so_open(const struct sockaddr *, int, const struct dns_options *, int *error);
|
||
|
|
||
|
void dns_so_close(struct dns_socket *);
|
||
|
|
||
|
void dns_so_reset(struct dns_socket *);
|
||
|
|
||
|
unsigned short dns_so_mkqid(struct dns_socket *so);
|
||
|
|
||
|
struct dns_packet *dns_so_query(struct dns_socket *, struct dns_packet *, struct sockaddr *, int *);
|
||
|
|
||
|
int dns_so_submit(struct dns_socket *, struct dns_packet *, struct sockaddr *);
|
||
|
|
||
|
int dns_so_check(struct dns_socket *);
|
||
|
|
||
|
struct dns_packet *dns_so_fetch(struct dns_socket *, int *);
|
||
|
|
||
|
time_t dns_so_elapsed(struct dns_socket *);
|
||
|
|
||
|
void dns_so_clear(struct dns_socket *);
|
||
|
|
||
|
int dns_so_events(struct dns_socket *);
|
||
|
|
||
|
int dns_so_pollfd(struct dns_socket *);
|
||
|
|
||
|
int dns_so_poll(struct dns_socket *, int);
|
||
|
|
||
|
const struct dns_stat *dns_so_stat(struct dns_socket *);
|
||
|
|
||
|
|
||
|
/*
|
||
|
* R E S O L V E R I N T E R F A C E
|
||
|
*
|
||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
|
||
|
struct dns_resolver;
|
||
|
|
||
|
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 *);
|
||
|
|
||
|
struct dns_resolver *dns_res_stub(const struct dns_options *, int *);
|
||
|
|
||
|
void dns_res_reset(struct dns_resolver *);
|
||
|
|
||
|
void dns_res_close(struct dns_resolver *);
|
||
|
|
||
|
unsigned dns_res_acquire(struct dns_resolver *);
|
||
|
|
||
|
unsigned dns_res_release(struct dns_resolver *);
|
||
|
|
||
|
struct dns_resolver *dns_res_mortal(struct dns_resolver *);
|
||
|
|
||
|
int dns_res_submit(struct dns_resolver *, const char *, enum dns_type, enum dns_class);
|
||
|
|
||
|
int dns_res_check(struct dns_resolver *);
|
||
|
|
||
|
struct dns_packet *dns_res_fetch(struct dns_resolver *, int *);
|
||
|
|
||
|
time_t dns_res_elapsed(struct dns_resolver *);
|
||
|
|
||
|
void dns_res_clear(struct dns_resolver *);
|
||
|
|
||
|
int dns_res_events(struct dns_resolver *);
|
||
|
|
||
|
int dns_res_pollfd(struct dns_resolver *);
|
||
|
|
||
|
int dns_res_poll(struct dns_resolver *, int);
|
||
|
|
||
|
struct dns_packet *dns_res_query(struct dns_resolver *, const char *, enum dns_type, enum dns_class, int, int *);
|
||
|
|
||
|
const struct dns_stat *dns_res_stat(struct dns_resolver *);
|
||
|
|
||
|
|
||
|
/*
|
||
|
* A D D R I N F O I N T E R F A C E
|
||
|
*
|
||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
|
||
|
struct dns_addrinfo;
|
||
|
|
||
|
struct dns_addrinfo *dns_ai_open(const char *, const char *, enum dns_type, const struct addrinfo *, struct dns_resolver *, int *);
|
||
|
|
||
|
void dns_ai_close(struct dns_addrinfo *);
|
||
|
|
||
|
int dns_ai_nextent(struct addrinfo **, struct dns_addrinfo *);
|
||
|
|
||
|
size_t dns_ai_print(void *, size_t, struct addrinfo *, struct dns_addrinfo *);
|
||
|
|
||
|
time_t dns_ai_elapsed(struct dns_addrinfo *);
|
||
|
|
||
|
void dns_ai_clear(struct dns_addrinfo *);
|
||
|
|
||
|
int dns_ai_events(struct dns_addrinfo *);
|
||
|
|
||
|
int dns_ai_pollfd(struct dns_addrinfo *);
|
||
|
|
||
|
int dns_ai_poll(struct dns_addrinfo *, int);
|
||
|
|
||
|
const struct dns_stat *dns_ai_stat(struct dns_addrinfo *);
|
||
|
|
||
|
void *dns_sa_addr(int af, void *sa);
|
||
|
unsigned short *dns_sa_port(int af, void *sa);
|
||
|
#if _WIN32
|
||
|
const char *dns_inet_ntop(int af, const void *src, void *dst, unsigned long lim);
|
||
|
#else
|
||
|
#define dns_inet_pton(...) inet_pton(__VA_ARGS__)
|
||
|
#define dns_inet_ntop(...) inet_ntop(__VA_ARGS__)
|
||
|
#endif
|
||
|
#define dns_sa_family(sa) (((struct sockaddr *)(sa))->sa_family)
|
||
|
/*
|
||
|
* U T I L I T Y I N T E R F A C E S
|
||
|
*
|
||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
|
||
|
size_t dns_strlcpy(char *, const char *, size_t);
|
||
|
|
||
|
size_t dns_strlcat(char *, const char *, size_t);
|
||
|
|
||
|
|
||
|
/*
|
||
|
* M A C R O M A G I C S
|
||
|
*
|
||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
|
||
|
#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 */
|