#ifndef DNSCRYPT_H #define DNSCRYPT_H #include "compat.h" #include "tree.h" #include "debug.h" #include #include #include #include #include #include #if SODIUM_LIBRARY_VERSION_MAJOR < 7 # define sodium_allocarray(C, S) calloc(C, S) # define sodium_malloc(S) malloc(S) # define sodium_free(P) free(P) #endif #define DNS_QUERY_TIMEOUT 10 #define DNS_MAX_PACKET_SIZE_UDP_RECV (65536U - 20U - 8U) #define DNS_MAX_PACKET_SIZE_UDP_SEND 512U #if DNS_MAX_PACKET_SIZE_UDP_RECV > DNS_MAX_PACKET_SIZE_UDP_SEND # define DNS_MAX_PACKET_SIZE_UDP DNS_MAX_PACKET_SIZE_UDP_RECV #else # define DNS_MAX_PACKET_SIZE_UDP DNS_MAX_PACKET_SIZE_UDP_SEND #endif #ifndef DNS_DEFAULT_STANDARD_DNS_PORT # define DNS_DEFAULT_STANDARD_DNS_PORT "53" #endif #ifndef DNS_DEFAULT_LOCAL_PORT # define DNS_DEFAULT_LOCAL_PORT DNS_DEFAULT_STANDARD_DNS_PORT #endif #ifndef DNS_DEFAULT_RESOLVER_PORT # define DNS_DEFAULT_RESOLVER_PORT "443" #endif #define DNS_HEADER_SIZE 12U #define DNS_FLAGS_TC 2U #define DNS_FLAGS_QR 128U #define DNS_FLAGS2_RA 128U #define DNS_CLASS_IN 1U #define DNS_TYPE_TXT 16U #define DNS_TYPE_OPT 41U #define DNS_OFFSET_QUESTION DNS_HEADER_SIZE #define DNS_OFFSET_FLAGS 2U #define DNS_OFFSET_FLAGS2 3U #define DNS_OFFSET_QDCOUNT 4U #define DNS_OFFSET_ANCOUNT 6U #define DNS_OFFSET_NSCOUNT 8U #define DNS_OFFSET_ARCOUNT 10U #define DNS_OFFSET_EDNS_TYPE 0U #define DNS_OFFSET_EDNS_PAYLOAD_SIZE 2U #define DNS_DEFAULT_EDNS_PAYLOAD_SIZE 1252U #define DNSCRYPT_MAGIC_HEADER_LEN 8U #define DNSCRYPT_MAGIC_RESPONSE "r6fnvWj8" #ifndef DNSCRYPT_MAX_PADDING # define DNSCRYPT_MAX_PADDING 256U #endif #ifndef DNSCRYPT_BLOCK_SIZE # define DNSCRYPT_BLOCK_SIZE 64U #endif #ifndef DNSCRYPT_MIN_PAD_LEN # define DNSCRYPT_MIN_PAD_LEN 8U #endif #define crypto_box_HALF_NONCEBYTES (crypto_box_NONCEBYTES / 2U) #include "edns.h" #include "udp_request.h" #include "tcp_request.h" #include "rfc1035.h" #include "logger.h" #include "safe_rw.h" #include "cert.h" #define DNSCRYPT_QUERY_HEADER_SIZE \ (DNSCRYPT_MAGIC_HEADER_LEN + crypto_box_PUBLICKEYBYTES + crypto_box_HALF_NONCEBYTES + crypto_box_MACBYTES) #define DNSCRYPT_RESPONSE_HEADER_SIZE \ (DNSCRYPT_MAGIC_HEADER_LEN + crypto_box_NONCEBYTES + crypto_box_MACBYTES) #define DNSCRYPT_REPLY_HEADER_SIZE \ (DNSCRYPT_MAGIC_HEADER_LEN + crypto_box_HALF_NONCEBYTES * 2 + crypto_box_MACBYTES) #define XSALSA20_CERT(cert) (cert->es_version[0] == 0 && \ cert->es_version[1] == 1) #define XCHACHA20_CERT(cert) (cert->es_version[0] == 0 && \ cert->es_version[1] == 2) typedef struct KeyPair_ { uint8_t crypt_publickey[crypto_box_PUBLICKEYBYTES]; uint8_t crypt_secretkey[crypto_box_SECRETKEYBYTES]; } KeyPair; typedef struct cert_ { uint8_t magic_query[DNSCRYPT_MAGIC_HEADER_LEN]; uint8_t es_version[2]; KeyPair *keypair; } dnsccert; struct context { struct sockaddr_storage local_sockaddr; struct sockaddr_storage resolver_sockaddr; struct sockaddr_storage outgoing_sockaddr; ev_socklen_t local_sockaddr_len; ev_socklen_t resolver_sockaddr_len; ev_socklen_t outgoing_sockaddr_len; const char *ext_address; const char *resolver_address; const char *listen_address; const char *outgoing_address; struct evconnlistener *tcp_conn_listener; struct event *tcp_accept_timer; struct event *udp_listener_event; struct event *udp_resolver_event; evutil_socket_t udp_listener_handle; evutil_socket_t udp_resolver_handle; TCPRequestQueue tcp_request_queue; UDPRequestQueue udp_request_queue; struct event_base *event_loop; unsigned int connections; size_t edns_payload_size; /* Domain name shared buffer. */ char namebuff[MAXDNAME]; /* Process stuff. */ bool daemonize; bool allow_not_dnscrypted; char *pidfile; char *user; uid_t user_id; gid_t user_group; char *user_dir; char *logfile; char *provider_name; char *provider_publickey_file; char *provider_secretkey_file; char *provider_cert_file; struct SignedCert *signed_certs; size_t signed_certs_count; dnsccert *certs; size_t certs_count; uint8_t provider_publickey[crypto_sign_ed25519_PUBLICKEYBYTES]; uint8_t provider_secretkey[crypto_sign_ed25519_SECRETKEYBYTES]; char *crypt_secretkey_file; KeyPair *keypairs; size_t keypairs_count; uint64_t nonce_ts_last; unsigned char hash_key[crypto_shorthash_KEYBYTES]; /* blocking */ struct Blocking_ *blocking; }; const dnsccert * find_cert(const struct context *c, const unsigned char magic_query[DNSCRYPT_MAGIC_HEADER_LEN], const size_t dns_query_len); int dnscrypt_cmp_client_nonce(const uint8_t client_nonce[crypto_box_HALF_NONCEBYTES], const uint8_t *const buf, const size_t len); void dnscrypt_memzero(void *const pnt, const size_t size); uint64_t dnscrypt_hrtime(void); void dnscrypt_key_to_fingerprint(char fingerprint[80U], const uint8_t *const key); int dnscrypt_fingerprint_to_key(const char *const fingerprint, uint8_t key[crypto_box_PUBLICKEYBYTES]); // vim-like binary display static inline void print_binary_string(uint8_t *s, size_t count) { for (size_t i = 1; i <= count; i++) { uint8_t x = *((uint8_t *)s + i - 1); if (x >= (uint8_t)'0' && x <= (uint8_t)'9') { printf("%d", x); } else if (x >= (uint8_t)'a' && x <= (uint8_t)'z') { printf("%c", x); } else if (x >= (uint8_t)'A' && x <= (uint8_t)'Z') { printf("%c", x); } else { printf("\\%03d", x); } if (i % 16 == 0) { printf("\n"); } } printf("\n"); } // binary in hex static inline void print_binary_string_hex(uint8_t *s, size_t count) { for (size_t i = 1; i <= count; i++) { if ((i - 1) % 16 == 0) { printf("%04zx: ", (i - 1)); } uint8_t x = *((uint8_t *)s + i - 1); printf("%02x ", x); if (i % 16 == 0) { printf("\n"); } } printf("\n"); } struct dnscrypt_query_header { uint8_t magic_query[DNSCRYPT_MAGIC_HEADER_LEN]; uint8_t publickey[crypto_box_PUBLICKEYBYTES]; uint8_t nonce[crypto_box_HALF_NONCEBYTES]; uint8_t mac[crypto_box_MACBYTES]; }; int dnscrypt_server_uncurve(struct context *c, const dnsccert *cert, uint8_t client_nonce[crypto_box_HALF_NONCEBYTES], uint8_t nmkey[crypto_box_BEFORENMBYTES], uint8_t *const buf, size_t * const lenp); int dnscrypt_server_curve(struct context *c, const dnsccert *cert, uint8_t client_nonce[crypto_box_HALF_NONCEBYTES], uint8_t nmkey[crypto_box_BEFORENMBYTES], uint8_t *const buf, size_t * const lenp, const size_t max_len); /** * Given a DNS request,iterate over the question sections. * If a TXT request for provider name is made, adds the certs as TXT records * and return 0. dns_query_len is updated to reflect the size of the DNS packet. * return non-zero in case of failure. * */ int dnscrypt_self_serve_cert_file(struct context *c, struct dns_header *header, size_t *dns_query_len, size_t max_len); #endif