 src/dnsmasq.h | 17 ++++++++++--
 src/forward.c |  9 ++++++-
 src/option.c  | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/rfc1035.c | 41 +++++++++++++++++++++++++++-
 4 files changed, 146 insertions(+), 8 deletions(-)

diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 68e6287..464f487 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -553,6 +553,7 @@ struct server {
   unsigned int queries, failed_queries;
 #ifdef HAVE_LOOP
   u32 uid;
+  int trust;
 #endif
   struct server *next; 
 };
@@ -990,6 +991,16 @@ struct dhcp_relay {
   struct dhcp_relay *current, *next;
 };
 
+ struct net_mask_t {
+   struct in_addr net;
+   in_addr_t mask;
+ };
+ 
+ struct net_list_t {
+   int entries;
+   struct net_mask_t *nets;
+ };
+ 
 extern struct daemon {
   /* datastuctures representing the command-line and 
      config file arguments. All set (including defaults)
@@ -1023,6 +1034,7 @@ extern struct daemon {
   char *lease_change_command;
   struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
   struct bogus_addr *bogus_addr, *ignore_addr;
+  struct net_list_t *chnroutes_list;
   struct server *servers;
   struct ipsets *ipsets;
   int log_fac; /* log facility */
@@ -1216,7 +1228,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
 		      time_t now, int ad_reqd, int do_bit, int have_pseudoheader);
 int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, 
 			     struct bogus_addr *baddr, time_t now);
-int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
+int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr, const struct net_list_t *netlist);
 int check_for_local_domain(char *name, time_t now);
 unsigned int questions_crc(struct dns_header *header, size_t plen, char *name);
 size_t resize_packet(struct dns_header *header, size_t plen, 
@@ -1315,8 +1327,9 @@ void set_option_bool(unsigned int opt);
 void reset_option_bool(unsigned int opt);
 struct hostsfile *expand_filelist(struct hostsfile *list);
 char *parse_server(char *arg, union mysockaddr *addr, 
-		   union mysockaddr *source_addr, char *interface, int *flags);
+		   union mysockaddr *source_addr, char *interface, int *flags, int *trust);
 int option_read_dynfile(char *file, int flags);
+int cmp_net_mask(const void *a, const void *b);
 
 /* forward.c */
 void reply_query(int fd, int family, time_t now);
diff --git a/src/forward.c b/src/forward.c
index fde554d..4daa324 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -819,9 +819,16 @@ void reply_query(int fd, int family, time_t now)
   daemon->log_source_addr = &forward->source;
   
   if (daemon->ignore_addr && RCODE(header) == NOERROR &&
-      check_for_ignored_address(header, n, daemon->ignore_addr))
+      check_for_ignored_address(header, n, daemon->ignore_addr, NULL))
     return;
 
+   //my_syslog(LOG_INFO, _("dns server=%s, trust type=%d"), inet_ntoa(serveraddr.in.sin_addr), server->trust);
+   if ((server->trust==0||server->trust==1) && daemon->chnroutes_list && RCODE(header) == NOERROR) {
+       int c = check_for_ignored_address(header, n, NULL, daemon->chnroutes_list);
+       if (server->trust==0 && c==0) return;/* untrust dns sever, and got not in chnroutes address*/
+       if (server->trust==1 && c==1) return;/* trust dns sever, and got in chnroutes address*/
+   }
+ 
   /* Note: if we send extra options in the EDNS0 header, we can't recreate
      the query from the reply. */
   if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) &&
diff --git a/src/option.c b/src/option.c
index 1f698da..0671f6f 100644
--- a/src/option.c
+++ b/src/option.c
@@ -157,6 +157,7 @@ struct myoption {
 #define LOPT_DHCPTTL       348
 #define LOPT_TFTP_MTU      349
 #define LOPT_REPLY_DELAY   350
+#define LOPT_CHNROUTES_FILE 999
 #define LOPT_RAPID_COMMIT  351
 #define LOPT_DUMPFILE      352
 #define LOPT_DUMPMASK      353
@@ -202,6 +203,7 @@ static const struct myoption opts[] =
     { "bogus-priv", 0, 0, 'b' },
     { "bogus-nxdomain", 1, 0, 'B' },
     { "ignore-address", 1, 0, LOPT_IGNORE_ADDR },
+    { "chnroutes-file", 1, 0, LOPT_CHNROUTES_FILE },
     { "selfmx", 0, 0, 'e' },
     { "filterwin2k", 0, 0, 'f' },
     { "pid-file", 2, 0, 'x' },
@@ -512,6 +514,7 @@ static struct {
   { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks."), NULL },
   { LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops."), NULL },
   { LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL }, 
+  { LOPT_CHNROUTES_FILE, ARG_ONE, "<path>", gettext_noop("Trust dns server not containing ipaddr, untrust dns server containing ipaddr."), NULL }, 
   { LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL }, 
   { LOPT_REPLY_DELAY, ARG_ONE, "<integer>", gettext_noop("Delay DHCP replies for at least number of seconds."), NULL },
   { LOPT_RAPID_COMMIT, OPT_RAPID_COMMIT, NULL, gettext_noop("Enables DHCPv4 Rapid Commit option."), NULL },
@@ -778,14 +781,15 @@ static char *parse_mysockaddr(char *arg, union mysockaddr *addr)
   return NULL;
 }
 
-char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags)
+char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags, int *trust)
 {
   int source_port = 0, serv_port = NAMESERVER_PORT;
-  char *portno, *source;
+  char *portno, *source, *trust_type;
   char *interface_opt = NULL;
   int scope_index = 0;
   char *scope_id;
   
+  *trust = -1;/* init trust type to unknown */
   if (!arg || strlen(arg) == 0)
     {
       *flags |= SERV_NO_ADDR;
@@ -797,6 +801,10 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
       (portno = split_chr(source, '#')) &&
       !atoi_check16(portno, &source_port))
     return _("bad port");
+	
+    if ((trust_type = split_chr(arg, ',')) && /* is there a server#port,trust. */
+       !atoi_check16(trust_type, trust))
+     return _("bad trust type");
   
   if ((portno = split_chr(arg, '#')) && /* is there a port no. */
       !atoi_check16(portno, &serv_port))
@@ -1640,6 +1648,63 @@ static void server_list_free(struct server *list)
     }
 }
 
+ int cmp_net_mask(const void *a, const void *b) {
+   struct net_mask_t *neta = (struct net_mask_t *)a;
+   struct net_mask_t *netb = (struct 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_chnroutes(const char *filename, struct net_list_t *chnroutes_list) {
+   FILE *fp;
+   char line_buf[32];
+   char *line;
+   size_t len = sizeof(line_buf);
+   chnroutes_list->entries = 0;
+   int i = 0;
+ 
+   fp = fopen(filename, "rb");
+   if (fp == NULL) {
+     return -1;
+   }
+   while ((line = fgets(line_buf, len, fp))) {
+     chnroutes_list->entries++;
+   }
+ 
+   chnroutes_list->nets = calloc(chnroutes_list->entries, sizeof(struct net_mask_t));
+   if (0 != fseek(fp, 0, SEEK_SET)) {
+     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;
+     sp_pos = strchr(line, '/');
+     if (sp_pos) {
+       *sp_pos = 0;
+       chnroutes_list->nets[i].mask = (1 << (32 - atoi(sp_pos + 1))) - 1;
+     } else {
+       chnroutes_list->nets[i].mask = UINT32_MAX;
+     }
+     if (0 == inet_aton(line, &chnroutes_list->nets[i].net)) {
+       return (i+1);
+     }
+     i++;
+   }
+ 
+   qsort(chnroutes_list->nets, chnroutes_list->entries, sizeof(struct net_mask_t),
+         cmp_net_mask);
+ 
+   fclose(fp);
+   return 0;
+ }
+ 
 static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only)
 {      
   int i;
@@ -2499,6 +2564,20 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
 	break;	
       }
       
+    case LOPT_CHNROUTES_FILE: /* --chnroutes-file */
+   {
+		struct net_list_t *crlist = opt_malloc(sizeof(struct net_list_t));
+		int r = parse_chnroutes(opt_string_alloc(arg), crlist);
+		if (r < 0)
+			ret_err(_("chnroutes file open fail."));
+		if (r > 0) {
+			my_syslog(LOG_ERR, _("chnroutes file has wrong entry, line: %d"), r);
+			ret_err(_("chnroutes file has wrong entry."));
+		}
+		daemon->chnroutes_list = crlist;
+
+		break;
+   }
     case 'a':  /* --listen-address */
     case LOPT_AUTHPEER: /* --auth-peer */
       do {
@@ -2613,7 +2692,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
 	  newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
 	else
 	  {
-	    char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
+	    char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags, &newlist->trust);
 	    if (err)
 	      {
 	        server_list_free(newlist);
@@ -2663,7 +2742,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
 	else
 	  ret_err(gen_err);
  
-	string = parse_server(comma, &serv->addr, &serv->source_addr, serv->interface, &serv->flags);
+	string = parse_server(comma, &serv->addr, &serv->source_addr, serv->interface, &serv->flags, &serv->trust);
 	
 	if (string)
 	  ret_err(string);
diff --git a/src/rfc1035.c b/src/rfc1035.c
index fefe63d..c67586a 100644
--- a/src/rfc1035.c
+++ b/src/rfc1035.c
@@ -1116,7 +1116,37 @@ int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
   return 0;
 }
 
-int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr)
+ static int test_ip_in_list(struct in_addr ip, const struct net_list_t *netlist) {
+   // binary search
+   int l = 0, r = netlist->entries - 1;
+   int m, cmp;
+   if (netlist->entries == 0)
+     return 0;
+   struct 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;
+     }
+   }
+   if ((ntohl(netlist->nets[l].net.s_addr) ^ ntohl(ip.s_addr)) &
+       (UINT32_MAX ^ netlist->nets[l].mask)) {
+     return 0;
+   }
+   return 1;
+ }
+ 
+ int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr, const struct net_list_t *netlist)
 {
   unsigned char *p;
   int i, qtype, qclass, rdlen;
@@ -1141,9 +1171,18 @@ int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bog
 	  if (!CHECK_LEN(header, p, qlen, INADDRSZ))
 	    return 0;
 	  
+	  if (baddr!=NULL)    
 	  for (baddrp = baddr; baddrp; baddrp = baddrp->next)
 	    if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
 	      return 1;
+ 
+ 	  if (netlist!=NULL) {
+ 		  struct in_addr addr;
+ 		  memcpy(&addr, p, INADDRSZ);
+ 		  int c = test_ip_in_list(addr, netlist);
+ 		  //my_syslog(LOG_INFO, _("resolved ip = %s, %s chnroutes"), inet_ntoa(addr), (c?"in":"not in"));
+ 		  if (c) return 1;
+ 	  }
 	}
       
       if (!ADD_RDLEN(header, p, qlen, rdlen))
