This commit is contained in:
Nick Peng
2018-06-30 00:28:45 +08:00
parent a1906787b1
commit 1a5a0ae2a2
5 changed files with 356 additions and 53 deletions

View File

@@ -72,11 +72,13 @@ void config_address_destroy(void)
int config_address(char *value)
{
struct dns_address *address = NULL;
struct dns_address *oldaddress;
char ip[MAX_IP_LEN];
char domain_key[DNS_MAX_CONF_CNAME_LEN];
char *begin = NULL;
char *end = NULL;
int len = 0;
int port;
struct sockaddr_storage addr;
socklen_t addr_len = sizeof(addr);
char type = '4';
@@ -101,9 +103,12 @@ int config_address(char *value)
len = end - begin;
memcpy(address->domain, begin, len);
address->domain[len] = 0;
strncpy(ip, end + 1, MAX_IP_LEN);
reverse_string(domain_key + 1, address->domain, len);
if (parse_ip(end + 1, ip, &port) != 0) {
goto errout;
}
if (getaddr_by_host(ip, (struct sockaddr *)&addr, &addr_len) != 0) {
goto errout;
}
@@ -135,7 +140,10 @@ int config_address(char *value)
domain_key[0] = type;
len++;
art_insert(&dns_conf_address, (unsigned char *)domain_key, len, address);
oldaddress = art_insert(&dns_conf_address, (unsigned char *)domain_key, len, address);
if (oldaddress) {
free(oldaddress);
}
return 0;
errout:
@@ -277,4 +285,4 @@ errout:
fclose(fp);
}
return -1;
}
}

251
src/dns.c
View File

@@ -412,6 +412,95 @@ int dns_get_RAW(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, void *
return 0;
}
int dns_add_OPT(struct dns_packet *packet, dns_rr_type type, unsigned short opt_code, unsigned short opt_len, struct dns_opt *opt)
{
// TODO
int maxlen = 0;
int len = 0;
struct dns_data_context data_context;
int total_len = sizeof(*opt) + opt->length;
int ttl = 0;
/*
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
0: | OPTION-CODE |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2: | OPTION-LENGTH |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
4: | |
/ OPTION-DATA /
/ /
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
*/
unsigned char *data = _dns_add_rrs_start(packet, &maxlen);
if (data == NULL) {
return -1;
}
if (total_len > maxlen) {
return -1;
}
data_context.data = data;
data_context.ptr = data;
data_context.maxsize = maxlen;
ttl = (opt_code << 16) | opt_len;
/* add rr head */
len = _dns_add_rr_head(&data_context, "", type, DNS_C_IN, ttl, total_len);
if (len < 0) {
return -1;
}
/* add rr data */
memcpy(data_context.ptr, opt, total_len);
data_context.ptr += total_len;
len = data_context.ptr - data_context.data;
return dns_rr_add_end(packet, type, DNS_T_OPT, len);
}
int dns_get_OPT(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len, struct dns_opt *opt, int *opt_maxlen)
{
// TODO
int qtype = 0;
int qclass = 0;
int rr_len = 0;
int ret = 0;
struct dns_data_context data_context;
char domain[DNS_MAX_CNAME_LEN];
int maxsize = DNS_MAX_CNAME_LEN;
int ttl = 0;
unsigned char *data = rrs->data;
data_context.data = data;
data_context.ptr = data;
data_context.maxsize = rrs->len;
/* get rr head */
ret = _dns_get_rr_head(&data_context, domain, maxsize, &qtype, &qclass, &ttl, &rr_len);
if (ret < 0) {
return -1;
}
if (qtype != rrs->type || rr_len > *opt_len) {
return -1;
}
/* get rr data */
*opt_code = ttl >> 16;
*opt_len = ttl & 0xFFFF;
memcpy(opt, data_context.ptr, rr_len);
data_context.ptr += rr_len;
*opt_maxlen = rr_len;
return 0;
}
int dns_add_CNAME(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, char *cname)
{
int rr_len = strnlen(cname, DNS_MAX_CNAME_LEN) + 1;
@@ -546,6 +635,47 @@ int dns_get_SOA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, struct
return 0;
}
int dns_add_OPT_ECS(struct dns_packet *packet, dns_rr_type type, struct dns_opt_ecs *ecs)
{
// TODO
unsigned char opt_data[DNS_MAX_OPT_LEN];
struct dns_opt *opt = (struct dns_opt *)opt_data;
int len = 0;
opt->code = DNS_OPT_T_ECS;
opt->length = sizeof(*ecs);
memcpy(opt->data, ecs, sizeof(*ecs));
/* ecs size 4 + bit of address*/
len = sizeof(*opt) + 4;
len += (ecs->source_prefix / 8);
len += (ecs->source_prefix % 8 > 0) ? 1 : 0;
return dns_add_OPT(packet, type, DNS_OPT_T_ECS, len, opt);
}
int dns_get_OPT_ECS(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len, struct dns_opt_ecs *ecs)
{
// TODO
unsigned char opt_data[DNS_MAX_OPT_LEN];
struct dns_opt *opt = (struct dns_opt *)opt_data;
int len = sizeof(opt_data);
if (dns_get_OPT(rrs, opt_code, opt_len, opt, &len) != 0) {
return -1;
}
if (opt->code != DNS_OPT_T_ECS) {
return -1;
}
memcpy(ecs, opt->data, opt->length);
return 0;
}
/*
* Format:
* |DNS_NAME\0(string)|qtype(short)|qclass(short)|
@@ -1074,6 +1204,108 @@ int _dns_encode_SOA(struct dns_context *context, struct dns_rrs *rrs)
return 0;
}
static int _dns_decode_opt_ecs(struct dns_context *context, struct dns_opt_ecs *ecs)
{
// TODO
int len = 0;
if (_dns_left_len(context) < 4) {
return -1;
}
ecs->family = dns_read_short(&context->ptr);
ecs->source_prefix = dns_read_char(&context->ptr);
ecs->scope_prefix = dns_read_char(&context->ptr);
len = (ecs->source_prefix / 8);
len += (ecs->source_prefix % 8 > 0) ? 1 : 0;
if (_dns_left_len(context) < len) {
return -1;
}
memcpy(ecs->addr, context->ptr, len);
context->ptr += len;
return 0;
}
int _dns_encode_OPT(struct dns_context *context, struct dns_rrs *rrs)
{
// TODO
return 0;
}
static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsigned int ttl, int rr_len)
{
unsigned short opt_code;
unsigned short opt_len;
unsigned short ercode = (ttl >> 16) & 0xFFFF;
unsigned short ever = (ttl) & 0xFFFF;
unsigned char *start = context->ptr;
struct dns_packet *packet = context->packet;
int ret = 0;
/*
Field Name Field Type Description
------------------------------------------------------
NAME domain name empty (root domain)
TYPE u_int16_t OPT
CLASS u_int16_t sender's UDP payload size
TTL u_int32_t extended RCODE and flags
RDLEN u_int16_t describes RDATA
RDATA octet stream {attribute,value} pairs
+0 (MSB) +1 (LSB)
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
0: | OPTION-CODE |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2: | OPTION-LENGTH |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
4: | |
/ OPTION-DATA /
/ /
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
TTL
+0 (MSB) +1 (LSB)
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
0: | EXTENDED-RCODE | VERSION |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2: | Z |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
*/
if (ercode != 0) {
tlog(TLOG_ERROR, "extend rcode invalid.");
return -1;
}
ever = ever;
while (context->ptr - start < rr_len) {
opt_code = dns_read_short(&context->ptr);
opt_len = dns_read_short(&context->ptr);
switch (opt_code) {
case DNS_OPT_T_ECS: {
struct dns_opt_ecs ecs;
ret = _dns_decode_opt_ecs(context, &ecs);
if (ret != 0 ) {
tlog(TLOG_ERROR, "decode ecs failed.");
return -1;
}
ret = dns_add_OPT_ECS(packet, type, &ecs);
} break;
default:
context->ptr += opt_len;
tlog(TLOG_DEBUG, "DNS opt type = %d not supported", opt_code);
break;
}
}
return 0;
}
static int _dns_decode_qd(struct dns_context *context)
{
struct dns_packet *packet = context->packet;
@@ -1200,6 +1432,19 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
return -1;
}
} break;
case DNS_T_OPT: {
unsigned char *opt_start = context->ptr;
ret = _dns_decode_opt(context, type, ttl, rr_len);
if (ret < 0) {
tlog(TLOG_ERROR, "decode opt failed, %s", domain);
return -1;
}
if (context->ptr - opt_start != rr_len) {
tlog(TLOG_ERROR, "opt length mitchmatch, %s\n", domain);
return -1;
}
} break;
default:
context->ptr += rr_len;
tlog(TLOG_DEBUG, "DNS type = %d not supported", qtype);
@@ -1263,6 +1508,12 @@ static int _dns_encode_an(struct dns_context *context, struct dns_rrs *rrs)
return -1;
}
break;
case DNS_T_OPT:
ret = _dns_encode_OPT(context, rrs);
if (ret < 0) {
return -1;
}
break;
default:
break;
}

View File

@@ -9,6 +9,7 @@
#define DNS_RR_A_LEN 4
#define DNS_RR_AAAA_LEN 16
#define DNS_MAX_CNAME_LEN 256
#define DNS_MAX_OPT_LEN 256
#define DNS_IN_PACKSIZE (512 * 4)
#define DNS_PACKSIZE (512 * 8)
@@ -44,6 +45,11 @@ typedef enum dns_type {
DNS_T_ALL = 255
} dns_type_t;
typedef enum dns_opt_code {
DNS_OPT_T_ECS = 8,
DNS_OPT_T_ALL = 255
} dns_opt_code_t;
typedef enum dns_opcode {
DNS_OP_QUERY = 0,
DNS_OP_IQUERY = 1,
@@ -128,7 +134,24 @@ struct dns_soa {
unsigned int expire;
unsigned int minimum;
} __attribute__((packed));
;
#define DNS_OPT_ECS_FAMILY_IPV4 1
#define DNS_OPT_ECS_FAMILY_IPV6 2
/* OPT ECS */
struct dns_opt_ecs {
unsigned short family;
unsigned char source_prefix;
unsigned char scope_prefix;
unsigned char addr[DNS_RR_AAAA_LEN];
};
/* OPT */
struct dns_opt {
unsigned short code;
unsigned short length;
unsigned char data[0];
} __attribute__((packed));
struct dns_rrs *dns_get_rrs_next(struct dns_packet *packet, struct dns_rrs *rrs);
struct dns_rrs *dns_get_rrs_start(struct dns_packet *packet, dns_rr_type type, int *count);
@@ -156,6 +179,12 @@ int dns_get_AAAA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsig
int dns_add_SOA(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, struct dns_soa *soa);
int dns_get_SOA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, struct dns_soa *soa);
int dns_add_OPT(struct dns_packet *packet, dns_rr_type type, unsigned short opt_code, unsigned short opt_len, struct dns_opt *opt);
int dns_get_OPT(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len, struct dns_opt *opt, int *opt_maxlen);
int dns_add_OPT_ECS(struct dns_packet *packet, dns_rr_type type, struct dns_opt_ecs *ecs);
int dns_get_OPT_ECS(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len, struct dns_opt_ecs *ecs);
/*
* Packet operation
*/

View File

@@ -49,6 +49,7 @@
#include <unistd.h>
#define DNS_MAX_EVENTS 256
#define DNS_SERVER_TMOUT_TTL (3 * 60)
/* dns server data */
struct dns_server {
@@ -268,11 +269,25 @@ int _dns_server_request_complete(struct dns_request *request)
if (request->qtype == DNS_T_A) {
tlog(TLOG_INFO, "result: %s, rcode: %d, %d.%d.%d.%d\n", request->domain, request->rcode, request->ipv4_addr[0], request->ipv4_addr[1],
request->ipv4_addr[2], request->ipv4_addr[3]);
if (request->has_ipv4) {
if (request->has_ping_result == 0 && request->ttl_v4 > DNS_SERVER_TMOUT_TTL) {
request->ttl_v4 = DNS_SERVER_TMOUT_TTL;
}
}
dns_cache_insert(request->domain, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN);
} else if (request->qtype == DNS_T_AAAA) {
tlog(TLOG_INFO, "result :%s, rcode: %d, %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", request->domain, request->rcode,
request->ipv6_addr[0], request->ipv6_addr[1], request->ipv6_addr[2], request->ipv6_addr[3], request->ipv6_addr[4], request->ipv6_addr[5],
request->ipv6_addr[6], request->ipv6_addr[7], request->ipv6_addr[8], request->ipv6_addr[9], request->ipv6_addr[10], request->ipv6_addr[11],
request->ipv6_addr[12], request->ipv6_addr[13], request->ipv6_addr[14], request->ipv6_addr[15]);
if (request->has_ipv6) {
if (request->has_ping_result == 0 && request->ttl_v6 > DNS_SERVER_TMOUT_TTL) {
request->ttl_v6 = DNS_SERVER_TMOUT_TTL;
}
dns_cache_insert(request->domain, request->ttl_v6, DNS_T_AAAA, request->ipv6_addr, DNS_RR_AAAA_LEN);
}
}
_dns_reply(request);
@@ -333,7 +348,6 @@ void _dns_server_ping_result(struct ping_host_struct *ping_host, const char *hos
{
struct dns_request *request = userptr;
int may_complete = 0;
int addr_type = 0;
if (request == NULL) {
return;
@@ -355,7 +369,6 @@ void _dns_server_ping_result(struct ping_host_struct *ping_host, const char *hos
request->ping_ttl_v4 = rtt;
request->has_ipv4 = 1;
memcpy(request->ipv4_addr, &addr_in->sin_addr.s_addr, 4);
addr_type = 4;
}
} break;
case AF_INET6: {
@@ -366,14 +379,12 @@ void _dns_server_ping_result(struct ping_host_struct *ping_host, const char *hos
request->ping_ttl_v4 = rtt;
request->has_ipv4 = 1;
memcpy(request->ipv4_addr, addr_in6->sin6_addr.s6_addr + 12, 4);
addr_type = 4;
}
} else {
if (request->ping_ttl_v6 > rtt) {
request->ping_ttl_v6 = rtt;
request->has_ipv6 = 1;
memcpy(request->ipv6_addr, addr_in6->sin6_addr.s6_addr, 16);
addr_type = 6;
}
}
} break;
@@ -396,11 +407,6 @@ void _dns_server_ping_result(struct ping_host_struct *ping_host, const char *hos
if (may_complete) {
_dns_server_request_complete(request);
_dns_server_request_remove(request);
if (addr_type == 4) {
dns_cache_insert(request->domain, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN);
} else if (addr_type == 6) {
dns_cache_insert(request->domain, request->ttl_v6, DNS_T_AAAA, request->ipv6_addr, DNS_RR_AAAA_LEN);
}
}
}
@@ -508,6 +514,10 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
memcpy(request->ipv4_addr, addr, DNS_RR_A_LEN);
request->ttl_v4 = ttl;
request->has_ipv4 = 1;
} else {
if (ttl < request->ttl_v4) {
request->ttl_v4 = ttl;
}
}
if (_dns_ip_address_check_add(request, addr, DNS_T_A) != 0) {
_dns_server_request_release(request);
@@ -539,6 +549,10 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
memcpy(request->ipv6_addr, addr, DNS_RR_AAAA_LEN);
request->ttl_v6 = ttl;
request->has_ipv6 = 1;
} else {
if (ttl < request->ttl_v6) {
request->ttl_v6 = ttl;
}
}
if (_dns_ip_address_check_add(request, addr, DNS_T_AAAA) != 0) {
@@ -546,7 +560,7 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
break;
}
sprintf(name, "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
sprintf(ip, "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
if (_dns_server_ping(request, ip) != 0) {
@@ -702,7 +716,7 @@ static struct dns_address *_dns_server_get_address_by_domain(char *domain, int q
domain_key[0] = type;
domain_len++;
return art_substring(&dns_conf_address, (unsigned char *)domain_key, domain_len);;
return art_substring(&dns_conf_address, (unsigned char *)domain_key, domain_len);
}
static int _dns_server_process_address(struct dns_request *request, struct dns_packet *packet)
@@ -745,7 +759,7 @@ errout:
static int _dns_server_process_cache(struct dns_request *request, struct dns_packet *packet)
{
struct dns_cache *dns_cache = NULL;
dns_cache = dns_cache_get(request->domain, request->qtype);
if (dns_cache == NULL) {
goto errout;

View File

@@ -170,9 +170,9 @@ static art_node** find_child(art_node *n, unsigned char c) {
case NODE4:
p.p1 = (art_node4*)n;
for (i=0 ; i < n->num_children; i++) {
/* this cast works around a bug in gcc 5.1 when unrolling loops
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
*/
/* this cast works around a bug in gcc 5.1 when unrolling loops
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
*/
if (((unsigned char*)p.p1->keys)[i] == c)
return &p.p1->children[i];
}
@@ -421,8 +421,8 @@ static void add_child48(art_node48 *n, art_node **ref, unsigned char c, void *ch
n->n.num_children++;
} else {
art_node256 *new_node = (art_node256*)alloc_node(NODE256);
int i;
for (i=0;i<256;i++) {
int i;
for (i=0;i<256;i++) {
if (n->keys[i]) {
new_node->children[i] = n->children[n->keys[i] - 1];
}
@@ -461,8 +461,8 @@ static void add_child16(art_node16 *n, art_node **ref, unsigned char c, void *ch
#else
// Compare the key to all 16 stored keys
unsigned bitfield = 0;
int i;
for (i = 0; i < 16; ++i) {
int i;
for (i = 0; i < 16; ++i) {
if (c < n->keys[i])
bitfield |= (1 << i);
}
@@ -489,9 +489,9 @@ static void add_child16(art_node16 *n, art_node **ref, unsigned char c, void *ch
} else {
art_node48 *new_node = (art_node48*)alloc_node(NODE48);
int i;
int i;
// Copy the child pointers and populate the key map
// Copy the child pointers and populate the key map
memcpy(new_node->children, n->children,
sizeof(void*)*n->n.num_children);
for (i=0;i<n->n.num_children;i++) {
@@ -688,8 +688,8 @@ static void remove_child256(art_node256 *n, art_node **ref, unsigned char c) {
copy_header((art_node*)new_node, (art_node*)n);
int pos = 0;
int i;
for (i=0;i<256;i++) {
int i;
for (i=0;i<256;i++) {
if (n->children[i]) {
new_node->children[pos] = n->children[i];
new_node->keys[i] = pos + 1;
@@ -712,8 +712,8 @@ static void remove_child48(art_node48 *n, art_node **ref, unsigned char c) {
copy_header((art_node*)new_node, (art_node*)n);
int child = 0;
int i;
for (i=0;i<256;i++) {
int i;
for (i=0;i<256;i++) {
pos = n->keys[i];
if (pos) {
new_node->keys[child] = i;
@@ -858,8 +858,8 @@ static int recursive_iter(art_node *n, art_callback cb, void *data) {
}
int idx, res;
int i;
switch (n->type) {
int i;
switch (n->type) {
case NODE4:
for (i=0; i < n->num_children; i++) {
res = recursive_iter(((art_node4*)n)->children[i], cb, data);
@@ -941,12 +941,6 @@ int art_iter_prefix(art_tree *t, const unsigned char *key, int key_len, art_call
art_node *n = t->root;
int prefix_len, depth = 0;
while (n) {
if (IS_LEAF(n)) {
n = (art_node*)LEAF_RAW(n);
art_leaf *l = (art_leaf*)n;
printf("LEAF: %s\n", l->key);
}
// Might be a leaf
if (IS_LEAF(n)) {
n = (art_node*)LEAF_RAW(n);
@@ -998,7 +992,7 @@ int art_iter_prefix(art_tree *t, const unsigned char *key, int key_len, art_call
static int str_prefix_matches(const art_leaf *n, const unsigned char *str, int str_len) {
// Fail if the key length is too short
if (n->key_len > (uint32_t)str_len) return 1;
if (n->key_len > (uint32_t)str_len) return 1;
// Compare the keys
return memcmp(str, n->key, n->key_len);
@@ -1008,33 +1002,40 @@ void *art_substring(const art_tree *t, const unsigned char *str, int str_len)
{
art_node **child;
art_node *n = t->root;
art_leaf *found = NULL;
art_node *m;
art_leaf *found = NULL;
int prefix_len, depth = 0;
int prefix_len, depth = 0;
while (n) {
// Might be a leaf
if (IS_LEAF(n)) {
n = (art_node*)LEAF_RAW(n);
// Check if the expanded path matches
if (!str_prefix_matches((art_leaf*)n, str, str_len)) {
found = (art_leaf*)n;
found = (art_leaf*)n;
}
break;
}
break;
}
// Check if current is leaf
child = find_child(n, 0);
m = (child) ? *child : NULL;
if (m && IS_LEAF(m)) {
m = (art_node*)LEAF_RAW(m);
// Check if the expanded path matches
if (!str_prefix_matches((art_leaf*)m, str, str_len)) {
found = (art_leaf*)m;
}
}
// Bail if the prefix does not match
if (n->partial_len) {
prefix_len = check_prefix(n, str, str_len, depth);
if (prefix_len != min(MAX_PREFIX_LEN, n->partial_len))
break;
depth = depth + n->partial_len;
break;
depth = depth + n->partial_len;
}
art_leaf *l = maximum(n);
if (!str_prefix_matches(l, str, str_len)) {
found = l;
}
// Recursively search
child = find_child(n, str[depth]);
n = (child) ? *child : NULL;
@@ -1042,8 +1043,8 @@ void *art_substring(const art_tree *t, const unsigned char *str, int str_len)
}
if (found == NULL) {
return NULL;
}
return NULL;
}
return found->value;
}
}