diff --git a/Makefile b/Makefile index cb96dc2..5ec2887 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ChinaDNS PKG_VERSION:=1.3.2 -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://github.com/aa65535/openwrt-chinadns/releases/download/v$(PKG_VERSION) diff --git a/README.md b/README.md index fd1ed49..b7fdf17 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ChinaDNS for OpenWrt --- 本项目是 [ChinaDNS][1] 在 OpenWrt 上的移植 - 当前版本: 1.3.2-1 + 当前版本: 1.3.2-3 [预编译 IPK 下载][2] 编译 diff --git a/patches/0001-shorten-timeout.patch b/patches/0001-shorten-timeout.patch index c567b18..044c7c5 100644 --- a/patches/0001-shorten-timeout.patch +++ b/patches/0001-shorten-timeout.patch @@ -1,27 +1,17 @@ -From 404c424fa8dbc34a4273b5ad54b15091efa5d4b4 Mon Sep 17 00:00:00 2001 +From aae68815b58e9dadb2627c3dd268cf81ed53d41d Mon Sep 17 00:00:00 2001 From: Jian Chang -Date: Sat, 7 Nov 2015 10:07:14 +0800 -Subject: [PATCH 1/2] shorten timeout +Date: Thu, 12 Nov 2015 14:30:22 +0800 +Subject: [PATCH 1/3] shorten timeout --- - src/chinadns.c | 11 ++++------- - 1 file changed, 4 insertions(+), 7 deletions(-) + src/chinadns.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chinadns.c b/src/chinadns.c -index 6716554..930e6de 100644 +index 6716554..cab6bdd 100644 --- a/src/chinadns.c +++ b/src/chinadns.c -@@ -159,8 +159,7 @@ static void usage(void); - #ifdef DEBUG - #define DLOG(s...) LOG(s) - void __gcov_flush(void); --static void gcov_handler(int signum) --{ -+static void gcov_handler(int signum) { - __gcov_flush(); - exit(1); - } -@@ -199,8 +198,8 @@ int main(int argc, char **argv) { +@@ -199,8 +199,8 @@ int main(int argc, char **argv) { FD_SET(remote_sock, &readset); FD_SET(remote_sock, &errorset); struct timeval timeout = { @@ -32,21 +22,6 @@ index 6716554..930e6de 100644 }; if (-1 == select(max_fd, &readset, NULL, &errorset, &timeout)) { ERR("select"); -@@ -628,7 +627,7 @@ static void dns_handle_local() { - dns_server_addrs[i].addrlen)) - ERR("sendto"); - } -- for (i = has_chn_dns; i < dns_servers_len; i++) { -+ for (i = has_chn_dns; i < dns_servers_len; i++) { - if (-1 == sendto(remote_sock, compression_buf, len + 1, 0, - dns_server_addrs[i].addr, - dns_server_addrs[i].addrlen)) -@@ -914,5 +913,3 @@ Forward DNS requests.\n\ - \n\ - Online help: \n"); - } -- -- -- 2.6.2.windows.1 diff --git a/patches/0002-Use-to-define-trusted-DNS.patch b/patches/0002-Use-to-define-trusted-DNS.patch deleted file mode 100644 index 872324c..0000000 --- a/patches/0002-Use-to-define-trusted-DNS.patch +++ /dev/null @@ -1,268 +0,0 @@ -From 47c4bbc98be61a1e7738274f3adf0a403b3489a0 Mon Sep 17 00:00:00 2001 -From: Jian Chang -Date: Sun, 8 Nov 2015 16:14:32 +0800 -Subject: [PATCH 2/2] Use # to define trusted DNS - ---- - src/chinadns.c | 140 ++++++++++++++++++++++++++++++++++++--------------------- - 1 file changed, 90 insertions(+), 50 deletions(-) - -diff --git a/src/chinadns.c b/src/chinadns.c -index 930e6de..0955729 100644 ---- a/src/chinadns.c -+++ b/src/chinadns.c -@@ -82,6 +82,10 @@ static int dns_servers_len; - static int has_chn_dns; - static id_addr_t *dns_server_addrs; - -+static int has_trusted_dns = 0; -+static net_list_t trusted_dns_server_list; -+static id_addr_t *trusted_dns_server_addrs; -+ - static int parse_args(int argc, char **argv); - - static int setnonblock(int sock); -@@ -294,6 +298,27 @@ static int parse_args(int argc, char **argv) { - return 0; - } - -+static int cmp_in_addr(const void *a, const void *b) { -+ struct in_addr *ina = (struct in_addr *)a; -+ struct in_addr *inb = (struct in_addr *)b; -+ if (ina->s_addr == inb->s_addr) -+ return 0; -+ if (ina->s_addr > inb->s_addr) -+ return 1; -+ return -1; -+} -+ -+static int cmp_net_mask(const void *a, const void *b) { -+ net_mask_t *neta = (net_mask_t *)a; -+ net_mask_t *netb = (net_mask_t *)b; -+ if (neta->net.s_addr == netb->net.s_addr) -+ return 0; -+ // TODO: pre ntohl -+ if (ntohl(neta->net.s_addr) > ntohl(netb->net.s_addr)) -+ return 1; -+ return -1; -+} -+ - static int resolve_dns_servers() { - struct addrinfo hints; - struct addrinfo *addr_ip; -@@ -303,18 +328,25 @@ static int resolve_dns_servers() { - char *pch = strchr(dns_servers, ','); - has_chn_dns = 0; - int has_foreign_dns = 0; -+ trusted_dns_server_list.entries = 0; - dns_servers_len = 1; -- if (compression) { -- if (!chnroute_file) { -- VERR("Chnroutes are necessary when using DNS compression pointer mutation\n"); -- return -1; -- } -- } - while (pch != NULL) { - dns_servers_len++; - pch = strchr(pch + 1, ','); - } -+ char *rch = strchr(dns_servers, '#'); -+ while (rch != NULL) { -+ dns_servers_len--; -+ trusted_dns_server_list.entries++; -+ rch = strchr(rch + 1, '#'); -+ } - dns_server_addrs = calloc(dns_servers_len, sizeof(id_addr_t)); -+ if (trusted_dns_server_list.entries) { -+ trusted_dns_server_addrs = calloc(trusted_dns_server_list.entries, -+ sizeof(id_addr_t)); -+ trusted_dns_server_list.nets = calloc(trusted_dns_server_list.entries, -+ sizeof(net_mask_t)); -+ } - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; -@@ -324,17 +356,32 @@ static int resolve_dns_servers() { - char *port; - memset(global_buf, 0, BUF_SIZE); - strncpy(global_buf, token, BUF_SIZE - 1); -- port = (strrchr(global_buf, ':')); -- if (port) { -+ -+ if ((port = (strrchr(global_buf, '#')))) { -+ *port = '\0'; -+ port++; -+ if ((r = getaddrinfo(global_buf, port, &hints, &addr_ip))) { -+ VERR("%s:%s\n", gai_strerror(r), token); -+ return -1; -+ } -+ trusted_dns_server_addrs[has_trusted_dns].addr = addr_ip->ai_addr; -+ trusted_dns_server_addrs[has_trusted_dns].addrlen = addr_ip->ai_addrlen; -+ trusted_dns_server_list.nets[has_trusted_dns].mask = 0; -+ inet_aton(global_buf, &trusted_dns_server_list.nets[has_trusted_dns].net); -+ has_trusted_dns++; -+ token = strtok(0, ","); -+ continue; -+ } else if ((port = (strrchr(global_buf, ':')))) { - *port = '\0'; - port++; - } else { - port = "53"; - } -- if (0 != (r = getaddrinfo(global_buf, port, &hints, &addr_ip))) { -+ if ((r = getaddrinfo(global_buf, port, &hints, &addr_ip))) { - VERR("%s:%s\n", gai_strerror(r), token); - return -1; - } -+ token = strtok(0, ","); - if (compression) { - if (test_ip_in_list(((struct sockaddr_in *)addr_ip->ai_addr)->sin_addr, - &chnroute_list)) { -@@ -346,12 +393,10 @@ static int resolve_dns_servers() { - dns_server_addrs[dns_servers_len - has_foreign_dns].addr = addr_ip->ai_addr; - dns_server_addrs[dns_servers_len - has_foreign_dns].addrlen = addr_ip->ai_addrlen; - } -- token = strtok(0, ","); - } else { - dns_server_addrs[i].addr = addr_ip->ai_addr; - dns_server_addrs[i].addrlen = addr_ip->ai_addrlen; - i++; -- token = strtok(0, ","); - if (chnroute_file) { - if (test_ip_in_list(((struct sockaddr_in *)addr_ip->ai_addr)->sin_addr, - &chnroute_list)) { -@@ -362,8 +407,15 @@ static int resolve_dns_servers() { - } - } - } -+ if ((compression || has_trusted_dns) && !chnroute_file) { -+ VERR("Chnroutes are necessary when using DNS compression pointer mutation\ -+ or specifies trusted DNS\n"); -+ return -1; -+ } -+ qsort(trusted_dns_server_list.nets, trusted_dns_server_list.entries, -+ sizeof(net_mask_t), cmp_net_mask); - if (chnroute_file) { -- if (!(has_chn_dns && has_foreign_dns)) { -+ if (!(has_chn_dns && has_foreign_dns || has_trusted_dns)) { - if (compression) { - VERR("You should have at least one Chinese DNS and one foreign DNS when " - "using DNS compression pointer mutation\n"); -@@ -378,16 +430,6 @@ static int resolve_dns_servers() { - return 0; - } - --static int cmp_in_addr(const void *a, const void *b) { -- struct in_addr *ina = (struct in_addr *)a; -- struct in_addr *inb = (struct in_addr *)b; -- if (ina->s_addr == inb->s_addr) -- return 0; -- if (ina->s_addr > inb->s_addr) -- return 1; -- return -1; --} -- - static int parse_ip_list() { - FILE *fp; - char line_buf[32]; -@@ -430,17 +472,6 @@ static int parse_ip_list() { - return 0; - } - --static int cmp_net_mask(const void *a, const void *b) { -- net_mask_t *neta = (net_mask_t *)a; -- net_mask_t *netb = (net_mask_t *)b; -- if (neta->net.s_addr == netb->net.s_addr) -- return 0; -- // TODO: pre ntohl -- if (ntohl(neta->net.s_addr) > ntohl(netb->net.s_addr)) -- return 1; -- return -1; --} -- - static int parse_chnroute() { - FILE *fp; - char line_buf[32]; -@@ -567,7 +598,6 @@ static void dns_handle_local() { - uint16_t query_id; - ssize_t len; - int i; -- int sended = 0; - const char *question_hostname; - ns_msg msg; - len = recvfrom(local_sock, global_buf, BUF_SIZE, 0, src_addr, &src_addrlen); -@@ -602,7 +632,7 @@ static void dns_handle_local() { - id_addr.addr = src_addr; - id_addr.addrlen = src_addrlen; - queue_add(id_addr); -- if (compression) { -+ if (compression || has_trusted_dns) { - if (len > 16) { - size_t off = 12; - int ended = 0; -@@ -617,27 +647,34 @@ static void dns_handle_local() { - off += 1 + global_buf[off]; - } - if (ended) { -- memcpy(compression_buf, global_buf, off-1); -- memcpy(compression_buf + off + 1, global_buf + off, len - off); -- compression_buf[off-1] = '\xc0'; -- compression_buf[off] = '\x04'; - for (i = 0; i < has_chn_dns; i++) { - if (-1 == sendto(remote_sock, global_buf, len, 0, - dns_server_addrs[i].addr, - dns_server_addrs[i].addrlen)) - ERR("sendto"); - } -- for (i = has_chn_dns; i < dns_servers_len; i++) { -- if (-1 == sendto(remote_sock, compression_buf, len + 1, 0, -- dns_server_addrs[i].addr, -- dns_server_addrs[i].addrlen)) -- ERR("sendto"); -- sended = 1; -+ if (has_trusted_dns) { -+ for (i = 0; i < has_trusted_dns; i++) { -+ if (-1 == sendto(remote_sock, global_buf, len, 0, -+ trusted_dns_server_addrs[i].addr, -+ trusted_dns_server_addrs[i].addrlen)) -+ ERR("sendto"); -+ } -+ } else { -+ memcpy(compression_buf, global_buf, off-1); -+ memcpy(compression_buf + off + 1, global_buf + off, len - off); -+ compression_buf[off-1] = '\xc0'; -+ compression_buf[off] = '\x04'; -+ for (i = has_chn_dns; i < dns_servers_len; i++) { -+ if (-1 == sendto(remote_sock, compression_buf, len + 1, 0, -+ dns_server_addrs[i].addr, -+ dns_server_addrs[i].addrlen)) -+ ERR("sendto"); -+ } - } - } - } -- } -- if (!sended) { -+ } else { - for (i = 0; i < dns_servers_len; i++) { - if (-1 == sendto(remote_sock, global_buf, len, 0, - dns_server_addrs[i].addr, -@@ -755,9 +792,12 @@ static int should_filter_query(ns_msg msg, struct in_addr dns_addr) { - // TODO cache result for each dns server - int dns_is_chn = 0; - int dns_is_foreign = 0; -- if (chnroute_file && (dns_servers_len > 1)) { -- dns_is_chn = test_ip_in_list(dns_addr, &chnroute_list); -- dns_is_foreign = !dns_is_chn; -+ if (chnroute_file && ((dns_servers_len > 1) || has_trusted_dns)) { -+ dns_is_foreign = test_ip_in_list(dns_addr, &trusted_dns_server_list); -+ if (!dns_is_foreign) { -+ dns_is_chn = test_ip_in_list(dns_addr, &chnroute_list); -+ dns_is_foreign = !dns_is_chn; -+ } - } - rrmax = ns_msg_count(msg, ns_s_an); - if (rrmax == 0) { --- -2.6.2.windows.1 - diff --git a/patches/0002-refine-chnroute-list.patch b/patches/0002-refine-chnroute-list.patch new file mode 100644 index 0000000..a04b3a2 --- /dev/null +++ b/patches/0002-refine-chnroute-list.patch @@ -0,0 +1,106 @@ +From fa526047e2018240943430d46dc2382285cab014 Mon Sep 17 00:00:00 2001 +From: Jian Chang +Date: Thu, 12 Nov 2015 14:41:50 +0800 +Subject: [PATCH 2/3] refine chnroute list + +--- + src/chinadns.c | 53 ++++++++++++++++++++++++++++------------------------- + 1 file changed, 28 insertions(+), 25 deletions(-) + +diff --git a/src/chinadns.c b/src/chinadns.c +index cab6bdd..7a43eb4 100644 +--- a/src/chinadns.c ++++ b/src/chinadns.c +@@ -97,6 +97,7 @@ static char *ip_list_file = NULL; + static ip_list_t ip_list; + static int parse_ip_list(); + ++#define NETMASK_MIN 0 + static char *chnroute_file = NULL; + static net_list_t chnroute_list; + static int parse_chnroute(); +@@ -436,7 +437,6 @@ static int cmp_net_mask(const void *a, const void *b) { + net_mask_t *netb = (net_mask_t *)b; + if (neta->net.s_addr == netb->net.s_addr) + return 0; +- // TODO: pre ntohl + if (ntohl(neta->net.s_addr) > ntohl(netb->net.s_addr)) + return 1; + return -1; +@@ -451,6 +451,7 @@ static int parse_chnroute() { + char net[32]; + chnroute_list.entries = 0; + int i = 0; ++ int cidr; + + if (chnroute_file == NULL) { + VERR("CHNROUTE_FILE not specified, CHNRoute is disabled\n"); +@@ -481,9 +482,14 @@ static int parse_chnroute() { + sp_pos = strchr(line, '/'); + if (sp_pos) { + *sp_pos = 0; +- chnroute_list.nets[i].mask = (1 << (32 - atoi(sp_pos + 1))) - 1; ++ cidr = atoi(sp_pos + 1); ++ if (cidr > 0) { ++ chnroute_list.nets[i].mask = (1 << (32 - cidr)) - 1; ++ } else { ++ chnroute_list.nets[i].mask = UINT32_MAX; ++ } + } else { +- chnroute_list.nets[i].mask = UINT32_MAX; ++ chnroute_list.nets[i].mask = NETMASK_MIN; + } + if (0 == inet_aton(line, &chnroute_list.nets[i].net)) { + VERR("invalid addr %s in %s:%d\n", line, chnroute_file, i + 1); +@@ -507,29 +513,26 @@ static int test_ip_in_list(struct in_addr ip, const net_list_t *netlist) { + return 0; + net_mask_t ip_net; + ip_net.net = ip; +- while (l != r) { +- m = (l + r) / 2; +- cmp = cmp_net_mask(&ip_net, &netlist->nets[m]); +- if (cmp == -1) { +- if (r != m) +- r = m; +- else +- break; +- } else { +- if (l != m) +- l = m; +- else +- break; +- } ++ while (l <= r) { ++ m = (l + r) >> 1; ++ cmp = cmp_net_mask(&netlist->nets[m], &ip_net); ++ if (cmp < 0) ++ l = m + 1; ++ else if (cmp > 0) ++ r = m - 1; ++ else ++ return 1; ++#ifdef DEBUG + DLOG("l=%d, r=%d\n", l, r); +- DLOG("%s, %d\n", inet_ntoa(netlist->nets[m].net), +- netlist->nets[m].mask); +- } +- DLOG("result: %x\n", +- (ntohl(netlist->nets[l].net.s_addr) ^ ntohl(ip.s_addr))); +- DLOG("mask: %x\n", (UINT32_MAX - netlist->nets[l].mask)); +- if ((ntohl(netlist->nets[l].net.s_addr) ^ ntohl(ip.s_addr)) & +- (UINT32_MAX ^ netlist->nets[l].mask)) { ++ DLOG("%s, %d\n", inet_ntoa(netlist->nets[m].net), netlist->nets[m].mask); ++#endif ++ } ++#ifdef DEBUG ++ DLOG("nets: %x <-> %x\n", ntohl(netlist->nets[l - 1].net.s_addr, ntohl(ip.s_addr)); ++ DLOG("mask: %x\n", netlist->nets[l - 1].mask); ++#endif ++ if (0 == l || (ntohl(ip.s_addr) > (ntohl(netlist->nets[l - 1].net.s_addr) ++ | netlist->nets[l - 1].mask))) { + return 0; + } + return 1; +-- +2.6.2.windows.1 + diff --git a/patches/0003-Use-to-define-trusted-DNS.patch b/patches/0003-Use-to-define-trusted-DNS.patch new file mode 100644 index 0000000..7756f8a --- /dev/null +++ b/patches/0003-Use-to-define-trusted-DNS.patch @@ -0,0 +1,412 @@ +From 3c5acec544c989ec62ddba943164c73b0e977b84 Mon Sep 17 00:00:00 2001 +From: Jian Chang +Date: Fri, 13 Nov 2015 18:50:49 +0800 +Subject: [PATCH 3/3] Use # to define trusted DNS + +--- + src/chinadns.c | 242 +++++++++++++++++++++++++++++++++------------------------ + 1 file changed, 141 insertions(+), 101 deletions(-) + +diff --git a/src/chinadns.c b/src/chinadns.c +index 7a43eb4..df1dcb7 100644 +--- a/src/chinadns.c ++++ b/src/chinadns.c +@@ -75,12 +75,18 @@ static int verbose = 0; + static int compression = 0; + static int bidirectional = 0; + ++#define CHN_DNS 0 ++#define FOREIGN_DNS 1 ++#define TRUSTED_DNS 2 + static const char *default_dns_servers = + "114.114.114.114,223.5.5.5,8.8.8.8,8.8.4.4,208.67.222.222:443,208.67.222.222:5353"; + static char *dns_servers = NULL; + static int dns_servers_len; +-static int has_chn_dns; + static id_addr_t *dns_server_addrs; ++static int test_dns_server_type(struct sockaddr *addr); ++ ++static int has_trusted_dns; ++static ip_list_t trusted_dns_list; + + static int parse_args(int argc, char **argv); + +@@ -108,7 +114,7 @@ static void dns_handle_local(); + static void dns_handle_remote(); + + static const char *hostname_from_question(ns_msg msg); +-static int should_filter_query(ns_msg msg, struct in_addr dns_addr); ++static int should_filter_query(ns_msg msg, struct sockaddr *dns_addr); + + static void queue_add(id_addr_t id_addr); + static id_addr_t *queue_lookup(uint16_t id); +@@ -180,8 +186,6 @@ int main(int argc, char **argv) { + memset(&id_addr_queue, 0, sizeof(id_addr_queue)); + if (0 != parse_args(argc, argv)) + return EXIT_FAILURE; +- if (!compression) +- memset(&delay_queue, 0, sizeof(delay_queue)); + if (0 != parse_ip_list()) + return EXIT_FAILURE; + if (0 != parse_chnroute()) +@@ -190,6 +194,8 @@ int main(int argc, char **argv) { + return EXIT_FAILURE; + if (0 != dns_init_sockets()) + return EXIT_FAILURE; ++ if (!compression) ++ memset(&delay_queue, 0, sizeof(delay_queue)); + + max_fd = MAX(local_sock, remote_sock) + 1; + while (1) { +@@ -296,27 +302,42 @@ static int parse_args(int argc, char **argv) { + return 0; + } + ++static int cmp_in_addr(const void *a, const void *b) { ++ struct in_addr *ina = (struct in_addr *)a; ++ struct in_addr *inb = (struct in_addr *)b; ++ if (ina->s_addr == inb->s_addr) ++ return 0; ++ if (ntohl(ina->s_addr) > ntohl(inb->s_addr)) ++ return 1; ++ return -1; ++} ++ + static int resolve_dns_servers() { + struct addrinfo hints; + struct addrinfo *addr_ip; + char* token; + int r; + int i = 0; +- char *pch = strchr(dns_servers, ','); +- has_chn_dns = 0; ++ has_trusted_dns = 0; ++ int has_chn_dns = 0; + int has_foreign_dns = 0; ++ trusted_dns_list.entries = 0; + dns_servers_len = 1; +- if (compression) { +- if (!chnroute_file) { +- VERR("Chnroutes are necessary when using DNS compression pointer mutation\n"); +- return -1; +- } +- } ++ ++ char *pch = strchr(dns_servers, ','); + while (pch != NULL) { + dns_servers_len++; + pch = strchr(pch + 1, ','); + } ++ char *tch = strchr(dns_servers, '#'); ++ while (tch != NULL) { ++ trusted_dns_list.entries++; ++ tch = strchr(tch + 1, '#'); ++ } + dns_server_addrs = calloc(dns_servers_len, sizeof(id_addr_t)); ++ if (trusted_dns_list.entries) { ++ trusted_dns_list.ips = calloc(trusted_dns_list.entries, sizeof(struct in_addr)); ++ } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; +@@ -324,10 +345,14 @@ static int resolve_dns_servers() { + token = strtok(dns_servers, ","); + while (token) { + char *port; ++ int is_trusted_dns = 0; + memset(global_buf, 0, BUF_SIZE); + strncpy(global_buf, token, BUF_SIZE - 1); +- port = (strrchr(global_buf, ':')); +- if (port) { ++ if ((port = (strrchr(global_buf, '#')))) { ++ *port = '\0'; ++ port++; ++ is_trusted_dns = 1; ++ } else if ((port = (strrchr(global_buf, ':')))) { + *port = '\0'; + port++; + } else { +@@ -337,57 +362,72 @@ static int resolve_dns_servers() { + VERR("%s:%s\n", gai_strerror(r), token); + return -1; + } +- if (compression) { +- if (test_ip_in_list(((struct sockaddr_in *)addr_ip->ai_addr)->sin_addr, +- &chnroute_list)) { +- dns_server_addrs[has_chn_dns].addr = addr_ip->ai_addr; +- dns_server_addrs[has_chn_dns].addrlen = addr_ip->ai_addrlen; +- has_chn_dns++; +- } else { +- has_foreign_dns++; +- dns_server_addrs[dns_servers_len - has_foreign_dns].addr = addr_ip->ai_addr; +- dns_server_addrs[dns_servers_len - has_foreign_dns].addrlen = addr_ip->ai_addrlen; +- } +- token = strtok(0, ","); +- } else { +- dns_server_addrs[i].addr = addr_ip->ai_addr; +- dns_server_addrs[i].addrlen = addr_ip->ai_addrlen; +- i++; +- token = strtok(0, ","); +- if (chnroute_file) { +- if (test_ip_in_list(((struct sockaddr_in *)addr_ip->ai_addr)->sin_addr, +- &chnroute_list)) { +- has_chn_dns = 1; +- } else { +- has_foreign_dns = 1; +- } +- } ++ dns_server_addrs[i].addr = addr_ip->ai_addr; ++ dns_server_addrs[i++].addrlen = addr_ip->ai_addrlen; ++ if (is_trusted_dns) { ++ inet_aton(global_buf, &trusted_dns_list.ips[has_trusted_dns++]); ++ } ++ token = strtok(0, ","); ++ } ++ ++ qsort(trusted_dns_list.ips, trusted_dns_list.entries, sizeof(struct in_addr), ++ cmp_in_addr); ++ ++ for (i = 0; i < dns_servers_len; i++) { ++ switch(test_dns_server_type(dns_server_addrs[i].addr)) { ++ case CHN_DNS: ++ has_chn_dns = 1; ++ break; ++ case FOREIGN_DNS: ++ has_foreign_dns = 1; ++ break; ++ case TRUSTED_DNS: ++ compression = 0; ++ break; + } + } + if (chnroute_file) { +- if (!(has_chn_dns && has_foreign_dns)) { ++ if (has_chn_dns) { + if (compression) { +- VERR("You should have at least one Chinese DNS and one foreign DNS when " +- "using DNS compression pointer mutation\n"); ++ if (!has_foreign_dns) { ++ VERR("You should have at least one Chinese DNS and one foreign DNS " ++ "when using DNS compression pointer mutation\n"); ++ return -1; ++ } ++ } else if (!has_foreign_dns && !has_trusted_dns) { ++ VERR("You should have at least one Chinese DNS and one trusted DNS or " ++ "foreign DNS when chnroutes is enabled\n"); + return -1; +- } else { +- VERR("You should have at least one Chinese DNS and one foreign DNS when " +- "chnroutes is enabled\n"); +- return 0; + } + } ++ } else { ++ if (compression) { ++ VERR("Chnroutes is necessary when using DNS compression pointer mutation\n"); ++ return -1; ++ } ++ if (has_trusted_dns) { ++ VERR("Chnroutes is necessary when specify the trusted DNS\n"); ++ return -1; ++ } + } + return 0; + } + +-static int cmp_in_addr(const void *a, const void *b) { +- struct in_addr *ina = (struct in_addr *)a; +- struct in_addr *inb = (struct in_addr *)b; +- if (ina->s_addr == inb->s_addr) +- return 0; +- if (ina->s_addr > inb->s_addr) +- return 1; +- return -1; ++static int test_dns_server_type(struct sockaddr *addr) { ++ void *r; ++ r = bsearch(&(((struct sockaddr_in *)addr)->sin_addr), ++ trusted_dns_list.ips, trusted_dns_list.entries, ++ sizeof(struct in_addr), cmp_in_addr); ++ if (r) { ++ return TRUSTED_DNS; ++ } else { ++ if (test_ip_in_list(((struct sockaddr_in *)addr)->sin_addr, ++ &chnroute_list)) { ++ return CHN_DNS; ++ } else { ++ return FOREIGN_DNS; ++ } ++ } + } + + static int parse_ip_list() { +@@ -565,13 +605,21 @@ static int dns_init_sockets() { + return 0; + } + ++static int send_request(id_addr_t id_addr, char *buf, ssize_t len) { ++ if (verbose) ++ printf(" %s:%d", inet_ntoa(((struct sockaddr_in *)id_addr.addr)->sin_addr), ++ htons(((struct sockaddr_in *)id_addr.addr)->sin_port)); ++ if (-1 == sendto(remote_sock, buf, len, 0, id_addr.addr, id_addr.addrlen)) ++ ERR("sendto"); ++} ++ + static void dns_handle_local() { + struct sockaddr *src_addr = malloc(sizeof(struct sockaddr)); + socklen_t src_addrlen = sizeof(struct sockaddr); + uint16_t query_id; + ssize_t len; + int i; +- int sended = 0; ++ int ended = 0; + const char *question_hostname; + ns_msg msg; + len = recvfrom(local_sock, global_buf, BUF_SIZE, 0, src_addr, &src_addrlen); +@@ -585,7 +633,7 @@ static void dns_handle_local() { + // TODO generate id for each request to avoid conflicts + query_id = ns_msg_id(msg); + question_hostname = hostname_from_question(msg); +- LOG("request %s\n", question_hostname); ++ LOG("request %s from", question_hostname); + + // assign a new id + uint16_t new_id; +@@ -602,53 +650,45 @@ static void dns_handle_local() { + id_addr_t id_addr; + id_addr.id = new_id; + id_addr.old_id = query_id; +- + id_addr.addr = src_addr; + id_addr.addrlen = src_addrlen; + queue_add(id_addr); +- if (compression) { +- if (len > 16) { +- size_t off = 12; +- int ended = 0; +- while (off < len - 4) { +- if (global_buf[off] & 0xc0) +- break; +- if (global_buf[off] == 0) { +- ended = 1; +- off ++; +- break; +- } +- off += 1 + global_buf[off]; +- } +- if (ended) { +- memcpy(compression_buf, global_buf, off-1); +- memcpy(compression_buf + off + 1, global_buf + off, len - off); +- compression_buf[off-1] = '\xc0'; +- compression_buf[off] = '\x04'; +- for (i = 0; i < has_chn_dns; i++) { +- if (-1 == sendto(remote_sock, global_buf, len, 0, +- dns_server_addrs[i].addr, +- dns_server_addrs[i].addrlen)) +- ERR("sendto"); +- } +- for (i = has_chn_dns; i < dns_servers_len; i++) { +- if (-1 == sendto(remote_sock, compression_buf, len + 1, 0, +- dns_server_addrs[i].addr, +- dns_server_addrs[i].addrlen)) +- ERR("sendto"); +- sended = 1; +- } ++ ++ if (compression && len > 16) { ++ size_t off = 12; ++ while (off < len - 4) { ++ if (global_buf[off] & 0xc0) ++ break; ++ if (global_buf[off] == 0) { ++ ended = 1; ++ off ++; ++ break; + } ++ off += 1 + global_buf[off]; ++ } ++ if (ended) { ++ memcpy(compression_buf, global_buf, off-1); ++ memcpy(compression_buf + off + 1, global_buf + off, len - off); ++ compression_buf[off-1] = '\xc0'; ++ compression_buf[off] = '\x04'; + } + } +- if (!sended) { +- for (i = 0; i < dns_servers_len; i++) { +- if (-1 == sendto(remote_sock, global_buf, len, 0, +- dns_server_addrs[i].addr, +- dns_server_addrs[i].addrlen)) +- ERR("sendto"); ++ for (i = 0; i < dns_servers_len; i++) { ++ switch(test_dns_server_type(dns_server_addrs[i].addr)) { ++ case CHN_DNS: ++ case TRUSTED_DNS: ++ send_request(dns_server_addrs[i], global_buf, len); ++ break; ++ case FOREIGN_DNS: ++ if (ended) ++ send_request(dns_server_addrs[i], compression_buf, len + 1); ++ else if (!has_trusted_dns) ++ send_request(dns_server_addrs[i], global_buf, len); ++ break; + } + } ++ if (verbose) ++ printf("\n"); + } + else + ERR("recvfrom"); +@@ -682,7 +722,7 @@ static void dns_handle_remote() { + id_addr->addr->sa_family = AF_INET; + uint16_t ns_old_id = htons(id_addr->old_id); + memcpy(global_buf, &ns_old_id, 2); +- r = should_filter_query(msg, ((struct sockaddr_in *)src_addr)->sin_addr); ++ r = should_filter_query(msg, src_addr); + if (r == 0) { + if (verbose) + printf("pass\n"); +@@ -752,7 +792,7 @@ static const char *hostname_from_question(ns_msg msg) { + return NULL; + } + +-static int should_filter_query(ns_msg msg, struct in_addr dns_addr) { ++static int should_filter_query(ns_msg msg, struct sockaddr *dns_addr) { + ns_rr rr; + int rrnum, rrmax; + void *r; +@@ -760,12 +800,12 @@ static int should_filter_query(ns_msg msg, struct in_addr dns_addr) { + int dns_is_chn = 0; + int dns_is_foreign = 0; + if (chnroute_file && (dns_servers_len > 1)) { +- dns_is_chn = test_ip_in_list(dns_addr, &chnroute_list); ++ dns_is_chn = (CHN_DNS == test_dns_server_type(dns_addr)); + dns_is_foreign = !dns_is_chn; + } + rrmax = ns_msg_count(msg, ns_s_an); + if (rrmax == 0) { +- if (compression) { ++ if (compression || has_trusted_dns) { + // Wait for foreign dns + if (dns_is_chn) { + return 1; +@@ -787,7 +827,7 @@ static int should_filter_query(ns_msg msg, struct in_addr dns_addr) { + if (type == ns_t_a) { + if (verbose) + printf("%s, ", inet_ntoa(*(struct in_addr *)rd)); +- if (!compression) { ++ if (!compression && !has_trusted_dns) { + r = bsearch(rd, ip_list.ips, ip_list.entries, sizeof(struct in_addr), + cmp_in_addr); + if (r) { +@@ -815,7 +855,7 @@ static int should_filter_query(ns_msg msg, struct in_addr dns_addr) { + } + } + if (rrmax == 1) { +- if (compression) { ++ if (compression || has_trusted_dns) { + return 0; + } else { + return -1; +-- +2.6.2.windows.1 +