diff --git a/configure.ac b/configure.ac index c3647e3..36c3a79 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.67]) -AC_INIT([ChinaDNS], [1.3.2], [clowwindy42@gmail.com]) +AC_INIT([ChinaDNS], [1.3.3], [clowwindy42@gmail.com]) AC_CONFIG_SRCDIR([src/chinadns.c]) AC_CONFIG_HEADERS([config.h]) diff --git a/openwrt/Makefile b/openwrt/Makefile index 3b107a8..c612de8 100644 --- a/openwrt/Makefile +++ b/openwrt/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ChinaDNS -PKG_VERSION:=1.3.2 +PKG_VERSION:=1.3.3 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_URL:=https://github.com/clowwindy/ChinaDNS/releases/download/$(PKG_VERSION) diff --git a/src/chinadns.c b/src/chinadns.c index 6716554..93deb83 100644 --- a/src/chinadns.c +++ b/src/chinadns.c @@ -97,6 +97,12 @@ static char *ip_list_file = NULL; static ip_list_t ip_list; static int parse_ip_list(); +static char *ipwhite_list_file = NULL; +static ip_list_t ipwhite_list; +static int parse_ipwhite_list(); +static void append_ipwhite_list(struct in_addr addr); +static void writeback_ipwhite_list(); + static char *chnroute_file = NULL; static net_list_t chnroute_list; static int parse_chnroute(); @@ -168,6 +174,12 @@ static void gcov_handler(int signum) #define DLOG(s...) #endif +static void term_handler(int signum) +{ + writeback_ipwhite_list(); + exit(1); +} + int main(int argc, char **argv) { fd_set readset, errorset; int max_fd; @@ -175,6 +187,8 @@ int main(int argc, char **argv) { #ifdef DEBUG signal(SIGTERM, gcov_handler); #endif + signal(SIGTERM, term_handler); + signal(SIGINT, term_handler); memset(&id_addr_queue, 0, sizeof(id_addr_queue)); if (0 != parse_args(argc, argv)) @@ -183,6 +197,8 @@ int main(int argc, char **argv) { memset(&delay_queue, 0, sizeof(delay_queue)); if (0 != parse_ip_list()) return EXIT_FAILURE; + if (0 != parse_ipwhite_list()) + return EXIT_FAILURE; if (0 != parse_chnroute()) return EXIT_FAILURE; if (0 != resolve_dns_servers()) @@ -241,7 +257,7 @@ static int setnonblock(int sock) { static int parse_args(int argc, char **argv) { int ch; - while ((ch = getopt(argc, argv, "hb:p:s:l:c:y:dmvV")) != -1) { + while ((ch = getopt(argc, argv, "w:hb:p:s:l:c:y:dmvV")) != -1) { switch (ch) { case 'h': usage(); @@ -261,6 +277,9 @@ static int parse_args(int argc, char **argv) { case 'l': ip_list_file = strdup(optarg); break; + case 'w': + ipwhite_list_file = strdup(optarg); + break; case 'y': empty_result_delay = atof(optarg); break; @@ -431,6 +450,80 @@ static int parse_ip_list() { return 0; } +static int parse_ipwhite_list() { + FILE *fp; + char line_buf[32]; + char *line = NULL; + size_t len = sizeof(line_buf); + ssize_t read; + ipwhite_list.entries = 0; + int i = 0; + + if (ipwhite_list_file == NULL) + return 0; + + fp = fopen(ipwhite_list_file, "rb"); + if (fp == NULL) { + ERR("fopen"); + VERR("Can't open ip white list: %s\n", ipwhite_list_file); + return -1; + } + while ((line = fgets(line_buf, len, fp))) { + ipwhite_list.entries++; + } + + ipwhite_list.ips = calloc(ipwhite_list.entries, sizeof(struct in_addr)); + if (0 != fseek(fp, 0, SEEK_SET)) { + VERR("fseek"); + return -1; + } + while ((line = fgets(line_buf, len, fp))) { + char *sp_pos; + sp_pos = strchr(line, '\r'); + if (sp_pos) *sp_pos = 0; + sp_pos = strchr(line, '\n'); + if (sp_pos) *sp_pos = 0; + inet_aton(line, &ipwhite_list.ips[i]); + i++; + } + + qsort(ipwhite_list.ips, ipwhite_list.entries, sizeof(struct in_addr), cmp_in_addr); + fclose(fp); + return 0; +} + +static void append_ipwhite_list(struct in_addr addr) +{ + printf("append ip to white list: %s\n", inet_ntoa(addr)); + struct in_addr* ips = ipwhite_list.ips; + ipwhite_list.ips = calloc(ipwhite_list.entries+1, sizeof(struct in_addr)); + memcpy(ipwhite_list.ips, ips, sizeof(struct in_addr)*(ipwhite_list.entries)); + ipwhite_list.ips[ipwhite_list.entries] = addr; + ipwhite_list.entries ++; + qsort(ipwhite_list.ips, ipwhite_list.entries, sizeof(struct in_addr), cmp_in_addr); + free(ips); +} + +static void writeback_ipwhite_list() +{ + int i; + if (ipwhite_list_file == NULL) + return; + + FILE *fp = fopen(ipwhite_list_file, "w"); + if (fp == NULL) { + ERR("fopen"); + VERR("Can't open ip white list: %s\n", ip_list_file); + return; + } + for(i = 0; i < ipwhite_list.entries; i++) + { + fprintf(fp,"%s\n",inet_ntoa(ipwhite_list.ips[i])); + } + fclose(fp); + printf("writeback ipwhite list:%d\n",ipwhite_list.entries); +} + 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; @@ -791,6 +884,11 @@ static int should_filter_query(ns_msg msg, struct in_addr dns_addr) { return 1; } } + r = bsearch(rd, ipwhite_list.ips, ipwhite_list.entries, sizeof(struct in_addr), + cmp_in_addr); + if (r) { + return 0; + } if (test_ip_in_list(*(struct in_addr *)rd, &chnroute_list)) { // result is chn if (dns_is_foreign) { @@ -804,6 +902,8 @@ static int should_filter_query(ns_msg msg, struct in_addr dns_addr) { if (dns_is_chn) { // filter DNS result from chn dns if result is outside chn return 1; + }else{ + append_ipwhite_list(*(struct in_addr *)rd); } } } else if (type == ns_t_aaaa || type == ns_t_ptr) { @@ -898,6 +998,7 @@ usage: chinadns [-h] [-l IPLIST_FILE] [-b BIND_ADDR] [-p BIND_PORT]\n\ Forward DNS requests.\n\ \n\ -l IPLIST_FILE path to ip blacklist file\n\ + -w IPWHITELIST_FILE path to ip whitelist file\n\ -c CHNROUTE_FILE path to china route file\n\ if not specified, CHNRoute will be turned\n\ -d off enable bi-directional CHNRoute filter\n\