diff options
Diffstat (limited to '')
-rw-r--r-- | contrib/librdns/dns_private.h | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/contrib/librdns/dns_private.h b/contrib/librdns/dns_private.h new file mode 100644 index 0000000..c240deb --- /dev/null +++ b/contrib/librdns/dns_private.h @@ -0,0 +1,338 @@ +/* Copyright (c) 2014, Vsevolod Stakhov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DNS_PRIVATE_H_ +#define DNS_PRIVATE_H_ + +#include "config.h" +#include "uthash.h" +#include "utlist.h" +#include "khash.h" +#include "rdns.h" +#include "upstream.h" +#include "ref.h" + +static const int dns_port = 53; +static const int default_io_cnt = 8; +static const int default_tcp_io_cnt = 1; + +#define UDP_PACKET_SIZE (4096) + +#define DNS_COMPRESSION_BITS 0xC0 + +#define DNS_D_MAXLABEL 63 /* + 1 '\0' */ +#define DNS_D_MAXNAME 255 /* + 1 '\0' */ + +#define RESOLV_CONF "/etc/resolv.conf" + +struct dns_header { + unsigned int qid :16; + +#if BYTE_ORDER == BIG_ENDIAN + unsigned int qr:1; + unsigned int opcode:4; + unsigned int aa:1; + unsigned int tc:1; + unsigned int rd:1; + + unsigned int ra:1; + unsigned int cd : 1; + unsigned int ad : 1; + unsigned int z : 1; + unsigned int rcode:4; +#else + unsigned int rd :1; + unsigned int tc :1; + unsigned int aa :1; + unsigned int opcode :4; + unsigned int qr :1; + + unsigned int rcode :4; + unsigned int z : 1; + unsigned int ad : 1; + unsigned int cd : 1; + unsigned int ra :1; +#endif + + unsigned int qdcount :16; + unsigned int ancount :16; + unsigned int nscount :16; + unsigned int arcount :16; +}; + +/** + * Represents DNS server + */ +struct rdns_server { + char *name; + unsigned int port; + unsigned int io_cnt; + unsigned int tcp_io_cnt; + + struct rdns_io_channel **io_channels; + struct rdns_io_channel **tcp_io_channels; + void *ups_elt; + upstream_entry_t up; +}; + +enum rdns_request_state { + RDNS_REQUEST_NEW = 0, + RDNS_REQUEST_REGISTERED = 1, + RDNS_REQUEST_WAIT_SEND, + RDNS_REQUEST_WAIT_REPLY, + RDNS_REQUEST_REPLIED, + RDNS_REQUEST_FAKE, + RDNS_REQUEST_ERROR, + RDNS_REQUEST_TCP, +}; + +struct rdns_request { + struct rdns_resolver *resolver; + struct rdns_async_context *async; + struct rdns_io_channel *io; + struct rdns_reply *reply; + enum rdns_request_type type; + + double timeout; + unsigned int retransmits; + + int id; + struct rdns_request_name *requested_names; + unsigned int qcount; + enum rdns_request_state state; + + uint8_t *packet; + off_t pos; + unsigned int packet_len; + + dns_callback_type func; + void *arg; + + void *async_event; + +#if defined(TWEETNACL) || defined(USE_RSPAMD_CRYPTOBOX) + void *curve_plugin_data; +#endif + + ref_entry_t ref; +}; + + +enum rdns_io_channel_flags { + RDNS_CHANNEL_CONNECTED = 1u << 0u, + RDNS_CHANNEL_ACTIVE = 1u << 1u, + RDNS_CHANNEL_TCP = 1u << 2u, + RDNS_CHANNEL_TCP_CONNECTING = 1u << 3u, +}; + +#define IS_CHANNEL_CONNECTED(ioc) (((ioc)->flags & RDNS_CHANNEL_CONNECTED) != 0) +#define IS_CHANNEL_ACTIVE(ioc) (((ioc)->flags & RDNS_CHANNEL_ACTIVE) != 0) +#define IS_CHANNEL_TCP(ioc) (((ioc)->flags & RDNS_CHANNEL_TCP) != 0) + +/** + * Used to chain output DNS requests for a TCP connection + */ +struct rdns_tcp_output_chain { + uint16_t next_write_size; /* Network byte order! */ + uint16_t cur_write; /* Cur bytes written including `next_write_size` */ + unsigned char *write_buf; + struct rdns_tcp_output_chain *prev, *next; +}; + +/** + * Specific stuff for a TCP IO chain + */ +struct rdns_tcp_channel { + uint16_t next_read_size; /* Network byte order on read, then host byte order */ + uint16_t cur_read; /* Cur bytes read including `next_read_size` */ + unsigned char *cur_read_buf; + unsigned read_buf_allocated; + + /* Chained set of the planned writes */ + struct rdns_tcp_output_chain *output_chain; + unsigned cur_output_chains; + + void *async_read; /** async read event */ + void *async_write; /** async write event */ +}; + +KHASH_DECLARE(rdns_requests_hash, int, struct rdns_request *); +#define RDNS_IO_CHANNEL_TAG UINT64_C(0xe190a5ba12f094c8) +/** + * IO channel for a specific DNS server + */ +struct rdns_io_channel { + uint64_t struct_magic; /**< tag for this structure */ + struct rdns_server *srv; + struct rdns_resolver *resolver; + struct sockaddr *saddr; + socklen_t slen; + int sock; /**< persistent socket */ + int flags; /**< see enum rdns_io_channel_flags */ + void *async_io; /** async opaque ptr */ + khash_t(rdns_requests_hash) *requests; + /* + * For DNS replies parsing we use per-channel structure + * which is used for two purposes: + * 1) We read the next DNS header + * 2) We find the corresponding request (if any) + * 3) We read the remaining packet (associated with a request or dangling) + * This structure is filled on each read-readiness for an IO channel + */ + struct rdns_tcp_channel *tcp; + uint64_t uses; + ref_entry_t ref; +}; + +struct rdns_fake_reply_idx { + enum rdns_request_type type; + unsigned len; + char request[0]; +}; + +struct rdns_fake_reply { + enum dns_rcode rcode; + struct rdns_reply_entry *result; + UT_hash_handle hh; + struct rdns_fake_reply_idx key; +}; + + +struct rdns_resolver { + struct rdns_server *servers; + struct rdns_async_context *async; /** async callbacks */ + void *periodic; /** periodic event for resolver */ + struct rdns_upstream_context *ups; + struct rdns_plugin *curve_plugin; + struct rdns_fake_reply *fake_elts; + +#ifdef __GNUC__ + __attribute__((format(printf, 4, 0))) +#endif + rdns_log_function logger; + void *log_data; + enum rdns_log_level log_level; + + uint64_t max_ioc_uses; + void *refresh_ioc_periodic; + + bool async_binded; + bool initialized; + bool enable_dnssec; + int flags; + ref_entry_t ref; +}; + +struct dns_query; + +/* Internal DNS structs */ + +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_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_class { + DNS_C_IN = 1, + + DNS_C_ANY = 255 +}; +/* enum dns_class */ + +struct dns_query { + char *qname; + unsigned int qtype :16; + unsigned int qclass :16; +}; + +enum dns_type { + DNS_T_A = RDNS_REQUEST_A, + DNS_T_NS = RDNS_REQUEST_NS, + DNS_T_CNAME = 5, + DNS_T_SOA = RDNS_REQUEST_SOA, + DNS_T_PTR = RDNS_REQUEST_PTR, + DNS_T_MX = RDNS_REQUEST_MX, + DNS_T_TXT = RDNS_REQUEST_TXT, + DNS_T_AAAA = RDNS_REQUEST_AAAA, + DNS_T_SRV = RDNS_REQUEST_SRV, + DNS_T_OPT = 41, + DNS_T_SSHFP = 44, + DNS_T_TLSA = RDNS_REQUEST_TLSA, + DNS_T_SPF = RDNS_REQUEST_SPF, + DNS_T_ALL = RDNS_REQUEST_ANY +}; +/* enum dns_type */ + +static const char dns_rcodes[][32] = { + [RDNS_RC_NOERROR] = "no error", + [RDNS_RC_FORMERR] = "query format error", + [RDNS_RC_SERVFAIL] = "server fail", + [RDNS_RC_NXDOMAIN] = "no records with this name", + [RDNS_RC_NOTIMP] = "not implemented", + [RDNS_RC_REFUSED] = "query refused", + [RDNS_RC_YXDOMAIN] = "YXDOMAIN", + [RDNS_RC_YXRRSET] = "YXRRSET", + [RDNS_RC_NXRRSET] = "NXRRSET", + [RDNS_RC_NOTAUTH] = "not authorized", + [RDNS_RC_NOTZONE] = "no such zone", + [RDNS_RC_TIMEOUT] = "query timed out", + [RDNS_RC_NETERR] = "network error", + [RDNS_RC_NOREC] = "requested record is not found" +}; + +static const char dns_types[][16] = { + [RDNS_REQUEST_A] = "A request", + [RDNS_REQUEST_NS] = "NS request", + [RDNS_REQUEST_PTR] = "PTR request", + [RDNS_REQUEST_MX] = "MX request", + [RDNS_REQUEST_TXT] = "TXT request", + [RDNS_REQUEST_SRV] = "SRV request", + [RDNS_REQUEST_SPF] = "SPF request", + [RDNS_REQUEST_AAAA] = "AAAA request", + [RDNS_REQUEST_TLSA] = "TLSA request", + [RDNS_REQUEST_ANY] = "ANY request" +}; + + +#endif /* DNS_PRIVATE_H_ */ |