├── 0000-Add-feature-to-support-chnroutes.patch └── README.md /0000-Add-feature-to-support-chnroutes.patch: -------------------------------------------------------------------------------- 1 | src/dnsmasq.h | 17 ++++++++++-- 2 | src/forward.c | 9 ++++++- 3 | src/option.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 4 | src/rfc1035.c | 41 +++++++++++++++++++++++++++- 5 | 4 files changed, 146 insertions(+), 8 deletions(-) 6 | 7 | diff --git a/src/dnsmasq.h b/src/dnsmasq.h 8 | index 68e6287..464f487 100644 9 | --- a/src/dnsmasq.h 10 | +++ b/src/dnsmasq.h 11 | @@ -553,6 +553,7 @@ struct server { 12 | unsigned int queries, failed_queries; 13 | #ifdef HAVE_LOOP 14 | u32 uid; 15 | + int trust; 16 | #endif 17 | struct server *next; 18 | }; 19 | @@ -990,6 +991,16 @@ struct dhcp_relay { 20 | struct dhcp_relay *current, *next; 21 | }; 22 | 23 | + struct net_mask_t { 24 | + struct in_addr net; 25 | + in_addr_t mask; 26 | + }; 27 | + 28 | + struct net_list_t { 29 | + int entries; 30 | + struct net_mask_t *nets; 31 | + }; 32 | + 33 | extern struct daemon { 34 | /* datastuctures representing the command-line and 35 | config file arguments. All set (including defaults) 36 | @@ -1023,6 +1034,7 @@ extern struct daemon { 37 | char *lease_change_command; 38 | struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces; 39 | struct bogus_addr *bogus_addr, *ignore_addr; 40 | + struct net_list_t *chnroutes_list; 41 | struct server *servers; 42 | struct ipsets *ipsets; 43 | int log_fac; /* log facility */ 44 | @@ -1216,7 +1228,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, 45 | time_t now, int ad_reqd, int do_bit, int have_pseudoheader); 46 | int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, 47 | struct bogus_addr *baddr, time_t now); 48 | -int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr); 49 | +int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr, const struct net_list_t *netlist); 50 | int check_for_local_domain(char *name, time_t now); 51 | unsigned int questions_crc(struct dns_header *header, size_t plen, char *name); 52 | size_t resize_packet(struct dns_header *header, size_t plen, 53 | @@ -1315,8 +1327,9 @@ void set_option_bool(unsigned int opt); 54 | void reset_option_bool(unsigned int opt); 55 | struct hostsfile *expand_filelist(struct hostsfile *list); 56 | char *parse_server(char *arg, union mysockaddr *addr, 57 | - union mysockaddr *source_addr, char *interface, int *flags); 58 | + union mysockaddr *source_addr, char *interface, int *flags, int *trust); 59 | int option_read_dynfile(char *file, int flags); 60 | +int cmp_net_mask(const void *a, const void *b); 61 | 62 | /* forward.c */ 63 | void reply_query(int fd, int family, time_t now); 64 | diff --git a/src/forward.c b/src/forward.c 65 | index fde554d..4daa324 100644 66 | --- a/src/forward.c 67 | +++ b/src/forward.c 68 | @@ -819,9 +819,16 @@ void reply_query(int fd, int family, time_t now) 69 | daemon->log_source_addr = &forward->source; 70 | 71 | if (daemon->ignore_addr && RCODE(header) == NOERROR && 72 | - check_for_ignored_address(header, n, daemon->ignore_addr)) 73 | + check_for_ignored_address(header, n, daemon->ignore_addr, NULL)) 74 | return; 75 | 76 | + //my_syslog(LOG_INFO, _("dns server=%s, trust type=%d"), inet_ntoa(serveraddr.in.sin_addr), server->trust); 77 | + if ((server->trust==0||server->trust==1) && daemon->chnroutes_list && RCODE(header) == NOERROR) { 78 | + int c = check_for_ignored_address(header, n, NULL, daemon->chnroutes_list); 79 | + if (server->trust==0 && c==0) return;/* untrust dns sever, and got not in chnroutes address*/ 80 | + if (server->trust==1 && c==1) return;/* trust dns sever, and got in chnroutes address*/ 81 | + } 82 | + 83 | /* Note: if we send extra options in the EDNS0 header, we can't recreate 84 | the query from the reply. */ 85 | if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) && 86 | diff --git a/src/option.c b/src/option.c 87 | index 1f698da..0671f6f 100644 88 | --- a/src/option.c 89 | +++ b/src/option.c 90 | @@ -157,6 +157,7 @@ struct myoption { 91 | #define LOPT_DHCPTTL 348 92 | #define LOPT_TFTP_MTU 349 93 | #define LOPT_REPLY_DELAY 350 94 | +#define LOPT_CHNROUTES_FILE 999 95 | #define LOPT_RAPID_COMMIT 351 96 | #define LOPT_DUMPFILE 352 97 | #define LOPT_DUMPMASK 353 98 | @@ -202,6 +203,7 @@ static const struct myoption opts[] = 99 | { "bogus-priv", 0, 0, 'b' }, 100 | { "bogus-nxdomain", 1, 0, 'B' }, 101 | { "ignore-address", 1, 0, LOPT_IGNORE_ADDR }, 102 | + { "chnroutes-file", 1, 0, LOPT_CHNROUTES_FILE }, 103 | { "selfmx", 0, 0, 'e' }, 104 | { "filterwin2k", 0, 0, 'f' }, 105 | { "pid-file", 2, 0, 'x' }, 106 | @@ -512,6 +514,7 @@ static struct { 107 | { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks."), NULL }, 108 | { LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops."), NULL }, 109 | { LOPT_IGNORE_ADDR, ARG_DUP, "", gettext_noop("Ignore DNS responses containing ipaddr."), NULL }, 110 | + { LOPT_CHNROUTES_FILE, ARG_ONE, "", gettext_noop("Trust dns server not containing ipaddr, untrust dns server containing ipaddr."), NULL }, 111 | { LOPT_DHCPTTL, ARG_ONE, "", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL }, 112 | { LOPT_REPLY_DELAY, ARG_ONE, "", gettext_noop("Delay DHCP replies for at least number of seconds."), NULL }, 113 | { LOPT_RAPID_COMMIT, OPT_RAPID_COMMIT, NULL, gettext_noop("Enables DHCPv4 Rapid Commit option."), NULL }, 114 | @@ -778,14 +781,15 @@ static char *parse_mysockaddr(char *arg, union mysockaddr *addr) 115 | return NULL; 116 | } 117 | 118 | -char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags) 119 | +char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags, int *trust) 120 | { 121 | int source_port = 0, serv_port = NAMESERVER_PORT; 122 | - char *portno, *source; 123 | + char *portno, *source, *trust_type; 124 | char *interface_opt = NULL; 125 | int scope_index = 0; 126 | char *scope_id; 127 | 128 | + *trust = -1;/* init trust type to unknown */ 129 | if (!arg || strlen(arg) == 0) 130 | { 131 | *flags |= SERV_NO_ADDR; 132 | @@ -797,6 +801,10 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a 133 | (portno = split_chr(source, '#')) && 134 | !atoi_check16(portno, &source_port)) 135 | return _("bad port"); 136 | + 137 | + if ((trust_type = split_chr(arg, ',')) && /* is there a server#port,trust. */ 138 | + !atoi_check16(trust_type, trust)) 139 | + return _("bad trust type"); 140 | 141 | if ((portno = split_chr(arg, '#')) && /* is there a port no. */ 142 | !atoi_check16(portno, &serv_port)) 143 | @@ -1640,6 +1648,63 @@ static void server_list_free(struct server *list) 144 | } 145 | } 146 | 147 | + int cmp_net_mask(const void *a, const void *b) { 148 | + struct net_mask_t *neta = (struct net_mask_t *)a; 149 | + struct net_mask_t *netb = (struct net_mask_t *)b; 150 | + if (neta->net.s_addr == netb->net.s_addr) 151 | + return 0; 152 | + // TODO: pre ntohl 153 | + if (ntohl(neta->net.s_addr) > ntohl(netb->net.s_addr)) 154 | + return 1; 155 | + return -1; 156 | + } 157 | + 158 | + static int parse_chnroutes(const char *filename, struct net_list_t *chnroutes_list) { 159 | + FILE *fp; 160 | + char line_buf[32]; 161 | + char *line; 162 | + size_t len = sizeof(line_buf); 163 | + chnroutes_list->entries = 0; 164 | + int i = 0; 165 | + 166 | + fp = fopen(filename, "rb"); 167 | + if (fp == NULL) { 168 | + return -1; 169 | + } 170 | + while ((line = fgets(line_buf, len, fp))) { 171 | + chnroutes_list->entries++; 172 | + } 173 | + 174 | + chnroutes_list->nets = calloc(chnroutes_list->entries, sizeof(struct net_mask_t)); 175 | + if (0 != fseek(fp, 0, SEEK_SET)) { 176 | + return -1; 177 | + } 178 | + while ((line = fgets(line_buf, len, fp))) { 179 | + char *sp_pos; 180 | + sp_pos = strchr(line, '\r'); 181 | + if (sp_pos) *sp_pos = 0; 182 | + sp_pos = strchr(line, '\n'); 183 | + if (sp_pos) *sp_pos = 0; 184 | + sp_pos = strchr(line, '/'); 185 | + if (sp_pos) { 186 | + *sp_pos = 0; 187 | + chnroutes_list->nets[i].mask = (1 << (32 - atoi(sp_pos + 1))) - 1; 188 | + } else { 189 | + chnroutes_list->nets[i].mask = UINT32_MAX; 190 | + } 191 | + if (0 == inet_aton(line, &chnroutes_list->nets[i].net)) { 192 | + return (i+1); 193 | + } 194 | + i++; 195 | + } 196 | + 197 | + qsort(chnroutes_list->nets, chnroutes_list->entries, sizeof(struct net_mask_t), 198 | + cmp_net_mask); 199 | + 200 | + fclose(fp); 201 | + return 0; 202 | + } 203 | + 204 | static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only) 205 | { 206 | int i; 207 | @@ -2499,6 +2564,20 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma 208 | break; 209 | } 210 | 211 | + case LOPT_CHNROUTES_FILE: /* --chnroutes-file */ 212 | + { 213 | + struct net_list_t *crlist = opt_malloc(sizeof(struct net_list_t)); 214 | + int r = parse_chnroutes(opt_string_alloc(arg), crlist); 215 | + if (r < 0) 216 | + ret_err(_("chnroutes file open fail.")); 217 | + if (r > 0) { 218 | + my_syslog(LOG_ERR, _("chnroutes file has wrong entry, line: %d"), r); 219 | + ret_err(_("chnroutes file has wrong entry.")); 220 | + } 221 | + daemon->chnroutes_list = crlist; 222 | + 223 | + break; 224 | + } 225 | case 'a': /* --listen-address */ 226 | case LOPT_AUTHPEER: /* --auth-peer */ 227 | do { 228 | @@ -2613,7 +2692,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma 229 | newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */ 230 | else 231 | { 232 | - char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags); 233 | + char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags, &newlist->trust); 234 | if (err) 235 | { 236 | server_list_free(newlist); 237 | @@ -2663,7 +2742,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma 238 | else 239 | ret_err(gen_err); 240 | 241 | - string = parse_server(comma, &serv->addr, &serv->source_addr, serv->interface, &serv->flags); 242 | + string = parse_server(comma, &serv->addr, &serv->source_addr, serv->interface, &serv->flags, &serv->trust); 243 | 244 | if (string) 245 | ret_err(string); 246 | diff --git a/src/rfc1035.c b/src/rfc1035.c 247 | index fefe63d..c67586a 100644 248 | --- a/src/rfc1035.c 249 | +++ b/src/rfc1035.c 250 | @@ -1116,7 +1116,37 @@ int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, 251 | return 0; 252 | } 253 | 254 | -int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr) 255 | + static int test_ip_in_list(struct in_addr ip, const struct net_list_t *netlist) { 256 | + // binary search 257 | + int l = 0, r = netlist->entries - 1; 258 | + int m, cmp; 259 | + if (netlist->entries == 0) 260 | + return 0; 261 | + struct net_mask_t ip_net; 262 | + ip_net.net = ip; 263 | + while (l != r) { 264 | + m = (l + r) / 2; 265 | + cmp = cmp_net_mask(&ip_net, &netlist->nets[m]); 266 | + if (cmp == -1) { 267 | + if (r != m) 268 | + r = m; 269 | + else 270 | + break; 271 | + } else { 272 | + if (l != m) 273 | + l = m; 274 | + else 275 | + break; 276 | + } 277 | + } 278 | + if ((ntohl(netlist->nets[l].net.s_addr) ^ ntohl(ip.s_addr)) & 279 | + (UINT32_MAX ^ netlist->nets[l].mask)) { 280 | + return 0; 281 | + } 282 | + return 1; 283 | + } 284 | + 285 | + int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr, const struct net_list_t *netlist) 286 | { 287 | unsigned char *p; 288 | int i, qtype, qclass, rdlen; 289 | @@ -1141,9 +1171,18 @@ int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bog 290 | if (!CHECK_LEN(header, p, qlen, INADDRSZ)) 291 | return 0; 292 | 293 | + if (baddr!=NULL) 294 | for (baddrp = baddr; baddrp; baddrp = baddrp->next) 295 | if (memcmp(&baddrp->addr, p, INADDRSZ) == 0) 296 | return 1; 297 | + 298 | + if (netlist!=NULL) { 299 | + struct in_addr addr; 300 | + memcpy(&addr, p, INADDRSZ); 301 | + int c = test_ip_in_list(addr, netlist); 302 | + //my_syslog(LOG_INFO, _("resolved ip = %s, %s chnroutes"), inet_ntoa(addr), (c?"in":"not in")); 303 | + if (c) return 1; 304 | + } 305 | } 306 | 307 | if (!ADD_RDLEN(header, p, qlen, rdlen)) 308 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Add dnsmasq for support chnroute file. 2 | === 3 | 4 | 编译/Compile 5 | --- 6 | 7 | ```bash 8 | cd openwrt 9 | cd package/network/services/dnsmasq/patches 10 | wget https://raw.githubusercontent.com/muziling/dnsmasq-chnroute/master/0000-Add-feature-to-support-chnroutes.patch --no-check-certificate 11 | cd ../../../../../ 12 | 13 | make package/network/services/dnsmasq/clean 14 | make package/network/services/dnsmasq/compile V=s 15 | ``` 16 | 17 | 使用/How to use 18 | --- 19 | 20 | ```Dnsmasq config file example: 21 | no-resolv 22 | all-servers 23 | server=114.114.114.114,0 24 | server=8.8.8.8,1 25 | chnroutes-file=/root/chnroute.txt 26 | 27 | server with ",0" is polluted dns, only accept ip in chnroute. 28 | server with ",1" is clean dns, only accept ip not in chnroute. 29 | ``` 30 | --------------------------------------------------------------------------------