Add ECS and bugfix

This commit is contained in:
Nick Peng
2018-12-21 22:11:22 +08:00
parent d3b67c3ed4
commit 7aa32069ef
9 changed files with 149 additions and 9 deletions

View File

@@ -44,6 +44,11 @@ cache-size 512
# dualstack-preference [yes|no]
# dualstack-preference yes
# edns client subnet
# edns-client-subnet-ipv4 [ip/subnet]
# edns-client-subnet-ipv6 [ip/subnet]
# edns-client-subnet-ipv4 192.168.1.1/24
# ttl for all resource record
# rr-ttl: ttl for all record
# rr-ttl-min: minimum ttl for resource record

View File

@@ -656,7 +656,7 @@ int dns_get_OPT_payload_size(struct dns_packet *packet)
return packet->payloadsize;
}
int dns_add_OPT_ECS(struct dns_packet *packet, dns_rr_type type, struct dns_opt_ecs *ecs)
int dns_add_OPT_ECS(struct dns_packet *packet, struct dns_opt_ecs *ecs)
{
unsigned char opt_data[DNS_MAX_OPT_LEN];
struct dns_opt *opt = (struct dns_opt *)opt_data;
@@ -1425,7 +1425,7 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign
return -1;
}
ret = dns_add_OPT_ECS(packet, type, &ecs);
ret = dns_add_OPT_ECS(packet, &ecs);
} break;
default:
context->ptr += opt_len;

View File

@@ -10,10 +10,13 @@
#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_IN_PACKSIZE (512 * 2)
#define DNS_PACKSIZE (512 * 8)
#define DNS_DEFAULT_PACKET_SIZE 512
#define DNS_ADDR_FAMILY_IP 1
#define DNS_ADDR_FAMILY_IPV6 2
typedef enum dns_qr {
DNS_QR_QUERY = 0,
DNS_QR_ANSWER = 1,
@@ -188,7 +191,7 @@ int dns_get_SOA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, struct
int dns_set_OPT_payload_size(struct dns_packet *packet, int payload_size);
int dns_get_OPT_payload_size(struct dns_packet *packet);
int dns_add_OPT_ECS(struct dns_packet *packet, dns_rr_type type, struct dns_opt_ecs *ecs);
int dns_add_OPT_ECS(struct dns_packet *packet, 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

@@ -50,6 +50,17 @@
#define DNS_HOSTNAME_LEN 128
#define DNS_TCP_BUFFER (16 * 1024)
struct dns_client_ecs {
int enable;
unsigned int family;
unsigned int bitlen;
union {
unsigned char ipv4_addr[DNS_RR_A_LEN];
unsigned char ipv6_addr[DNS_RR_AAAA_LEN];
unsigned char addr[0];
};
};
/* dns client */
struct dns_client {
pthread_t tid;
@@ -65,6 +76,10 @@ struct dns_client {
struct list_head dns_request_list;
atomic_t dns_server_num;
/* ECS */
struct dns_client_ecs ecs_ipv4;
struct dns_client_ecs ecs_ipv6;
/* query doman hash table, key: sid + domain */
pthread_mutex_t domain_map_lock;
DECLARE_HASHTABLE(domain_map, 6);
@@ -1548,6 +1563,26 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
return 0;
}
static int _dns_client_dns_add_ecs(struct dns_packet *packet, int qtype)
{
if (qtype == DNS_T_A && client.ecs_ipv4.enable) {
struct dns_opt_ecs ecs;
ecs.family = DNS_ADDR_FAMILY_IP;
ecs.source_prefix = client.ecs_ipv4.bitlen;
ecs.scope_prefix = 0;
memcpy(ecs.addr, client.ecs_ipv4.ipv4_addr, DNS_RR_A_LEN);
return dns_add_OPT_ECS(packet, &ecs);
} else if (qtype == DNS_T_AAAA && client.ecs_ipv6.enable) {
struct dns_opt_ecs ecs;
ecs.family = DNS_ADDR_FAMILY_IPV6;
ecs.source_prefix = client.ecs_ipv6.bitlen;
ecs.scope_prefix = 0;
memcpy(ecs.addr, client.ecs_ipv6.ipv6_addr, DNS_RR_AAAA_LEN);
return dns_add_OPT_ECS(packet, &ecs);
}
return 0;
}
static int _dns_client_send_query(struct dns_query_struct *query, char *doamin)
{
unsigned char packet_buff[DNS_PACKSIZE];
@@ -1571,7 +1606,13 @@ static int _dns_client_send_query(struct dns_query_struct *query, char *doamin)
/* add question */
dns_add_domain(packet, doamin, query->qtype, DNS_C_IN);
dns_set_OPT_payload_size(packet, 1024);
dns_set_OPT_payload_size(packet, DNS_IN_PACKSIZE);
if (_dns_client_dns_add_ecs(packet, query->qtype) != 0) {
tlog(TLOG_ERROR, "add ecs failed.");
return -1;
}
/* encode packet */
encode_len = dns_encode(inpacket, DNS_IN_PACKSIZE, packet);
if (encode_len <= 0) {
@@ -1642,6 +1683,12 @@ errout:
return -1;
}
int dns_client_set_ecs(char *ip, int subnet)
{
return 0;
}
int dns_client_init()
{
pthread_attr_t attr;

View File

@@ -21,6 +21,8 @@ typedef enum dns_result_type {
int dns_client_init(void);
int dns_client_set_ecs(char *ip, int subnet);
/* query result notify function */
typedef int (*dns_client_callback)(char *domain, dns_result_type rtype, unsigned int result_flag, struct dns_packet *packet, unsigned char *inpacket, int inpacket_len, void *user_ptr);

View File

@@ -44,6 +44,9 @@ int dns_conf_rr_ttl_min;
int dns_conf_rr_ttl_max;
int dns_conf_force_AAAA_SOA;
struct dns_edns_client_subnet dns_conf_ipv4_ecs;
struct dns_edns_client_subnet dns_conf_ipv6_ecs;
int config_server(int argc, char *argv[], dns_server_type_t type, int default_port)
{
int index = dns_conf_server_num;
@@ -477,14 +480,61 @@ int config_iplist_rule(char *subnet, enum address_rule rule)
int config_blacklist_ip(void *data, int argc, char *argv[])
{
if (argc <= 1) {
return -1;
}
return config_iplist_rule(argv[1], ADDRESS_RULE_BLACKLIST);
}
int conf_bogus_nxdomain(void *data, int argc, char *argv[])
{
if (argc <= 1) {
return -1;
}
return config_iplist_rule(argv[1], ADDRESS_RULE_BOGUS);
}
int conf_edns_client_subnet(void *data, int argc, char *argv[])
{
char *slash = NULL;
char *value = NULL;
int subnet = 0;
struct dns_edns_client_subnet *ecs = data;
struct sockaddr_storage addr;
socklen_t addr_len = sizeof(addr);
if (argc <= 1 || data == NULL) {
return -1;
}
value = argv[1];
slash = strstr(value, "/");
if (slash) {
*slash = 0;
slash++;
subnet = atoi(slash);
if (subnet < 0 || subnet > 128) {
return -1;
}
}
if (getaddr_by_host(value, (struct sockaddr *)&addr, &addr_len) != 0) {
goto errout;
}
strncpy(ecs->ip, value, DNS_MAX_IPLEN);
ecs->subnet = subnet;
ecs->enable = 1;
return 0;
errout:
return -1;
}
int config_log_level(void *data, int argc, char *argv[])
{
/* read log level and set */
@@ -533,6 +583,8 @@ struct config_item config_item[] = {
CONF_YESNO("force-AAAA-SOA", &dns_conf_force_AAAA_SOA),
CONF_CUSTOM("blacklist-ip", config_blacklist_ip, NULL),
CONF_CUSTOM("bogus-nxdomain", conf_bogus_nxdomain, NULL),
CONF_CUSTOM("edns-client-subnet-ipv4", conf_edns_client_subnet, &dns_conf_ipv6_ecs),
CONF_CUSTOM("edns-client-subnet-ipv6", conf_edns_client_subnet, &dns_conf_ipv6_ecs),
CONF_CUSTOM("conf-file", config_addtional_file, NULL),
CONF_END(),
};

View File

@@ -77,6 +77,12 @@ struct dns_ip_address_rule {
unsigned int bogus : 1;
};
struct dns_edns_client_subnet {
int enable;
char ip[DNS_MAX_IPLEN];
int subnet;
};
extern char dns_conf_server_ip[DNS_MAX_IPLEN];
extern char dns_conf_server_tcp_ip[DNS_MAX_IPLEN];
extern int dns_conf_tcp_idle_time;
@@ -107,6 +113,9 @@ extern int dns_conf_rr_ttl_min;
extern int dns_conf_rr_ttl_max;
extern int dns_conf_force_AAAA_SOA;
extern struct dns_edns_client_subnet dns_conf_ipv4_ecs;
extern struct dns_edns_client_subnet dns_conf_ipv6_ecs;
void dns_server_load_exit(void);
int dns_server_load_conf(const char *file);

View File

@@ -567,7 +567,8 @@ void _dns_server_request_release(struct dns_request *request)
int refcnt = atomic_dec_return(&request->refcnt);
if (refcnt) {
if (refcnt < 0) {
tlog(TLOG_ERROR, "BUG: refcnt is %d, domain %s", refcnt, request->domain);
tlog(TLOG_ERROR, "BUG: refcnt is %d, domain %s, qtype =%d", refcnt, request->domain,
request->qtype);
abort();
}
return;
@@ -707,10 +708,10 @@ int _dns_ip_address_check_add(struct dns_request *request, unsigned char *addr,
}
}
request->ip_map_num++;
pthread_mutex_unlock(&request->ip_map_lock);
addr_map = malloc(sizeof(*addr_map));
if (addr_map == NULL) {
pthread_mutex_unlock(&request->ip_map_lock);
tlog(TLOG_ERROR, "malloc failed");
return -1;
}
@@ -718,6 +719,7 @@ int _dns_ip_address_check_add(struct dns_request *request, unsigned char *addr,
addr_map->addr_type = addr_type;
memcpy(addr_map->addr, addr, addr_len);
hash_add(request->ip_map, &addr_map->node, key);
pthread_mutex_unlock(&request->ip_map_lock);
return 0;
}
@@ -1302,12 +1304,12 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
_dns_server_request_get(request);
request->send_tick = get_tick_count();
dns_client_query(request->domain, qtype, dns_server_resolve_callback, request);
request->request_wait++;
dns_client_query(request->domain, qtype, dns_server_resolve_callback, request);
if (qtype == DNS_T_AAAA && dns_conf_dualstack_preference) {
_dns_server_request_get(request);
dns_client_query(request->domain, DNS_T_A, dns_server_resolve_callback, request);
request->request_wait++;
dns_client_query(request->domain, DNS_T_A, dns_server_resolve_callback, request);
}
return 0;
@@ -1361,6 +1363,7 @@ static int _dns_server_prefetch_request(char *domain, dns_type_t qtype)
_dns_server_request_get(request);
request->send_tick = get_tick_count();
request->request_wait++;
dns_client_query(request->domain, qtype, dns_server_resolve_callback, request);
return 0;

View File

@@ -134,6 +134,20 @@ int smartdns_add_servers(void)
return 0;
}
int smartdns_set_ecs_ip(void)
{
int ret = 0;
if (dns_conf_ipv4_ecs.enable) {
ret |= dns_client_set_ecs(dns_conf_ipv4_ecs.ip, dns_conf_ipv4_ecs.subnet);
}
if (dns_conf_ipv6_ecs.enable) {
ret |= dns_client_set_ecs(dns_conf_ipv6_ecs.ip, dns_conf_ipv6_ecs.subnet);
}
return ret;
}
int create_pid_file(const char *pid_file)
{
int fd;
@@ -251,6 +265,11 @@ int smartdns_init(void)
goto errout;
}
ret = smartdns_set_ecs_ip();
if (ret != 0 ) {
tlog(TLOG_WARN, "set ecs ip address failed.");
}
return 0;
errout: