[Dnsmasq-discuss] [PATCH 2/4] change option parsing accordingly

weichen302 at icloud.com weichen302 at icloud.com
Sun Feb 8 10:11:20 GMT 2015


--server, --local, --address, and --rebind-domain-ok options are stored into
daemon->dh_special_domains; --ipset is stored into daemon->dh_ipsets.

Upstream servers are still in daemon->servers, however, only one copy is stored
if multiple --server share the same server.

--address no long store addr in daemon->servers, instead, the address is with
the label of lowest level of a domain name.


---
 src/option.c |  416 +++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 266 insertions(+), 150 deletions(-)

diff --git a/src/option.c b/src/option.c
index e4b4865..02a3b43 100644
--- a/src/option.c
+++ b/src/option.c
@@ -1980,7 +1980,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
 				  serv = opt_malloc(sizeof(struct server));
 				  memset(serv, 0, sizeof(struct server));
 				  serv->domain = d;
-				  serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
+				  serv->flags =  SERV_HAS_DOMAIN | SERV_NO_ADDR;
 				  serv->next = daemon->servers;
 				  daemon->servers = serv;
 				}
@@ -2217,99 +2217,202 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
 	arg = comma;
       } while (arg);
       break;
-      
-    case 'S':            /*  --server */
-    case LOPT_LOCAL:     /*  --local */
-    case 'A':            /*  --address */
-    case LOPT_NO_REBIND: /*  --rebind-domain-ok */
+
+    case 'S':                       /*  --server */
+    case LOPT_LOCAL:                /*  --local */
+    case 'A':                       /*  --address */
+    case LOPT_NO_REBIND:            /*  --rebind-domain-ok */
       {
-	struct server *serv, *newlist = NULL;
-	
-	unhide_metas(arg);
-	
-	if (arg && (*arg == '/' || option == LOPT_NO_REBIND))
-	  {
-	    int rebind = !(*arg == '/');
-	    char *end = NULL;
-	    if (!rebind)
-	      arg++;
-	    while (rebind || (end = split_chr(arg, '/')))
-	      {
-		char *domain = NULL;
-		/* elide leading dots - they are implied in the search algorithm */
-		while (*arg == '.') arg++;
-		/* # matches everything and becomes a zero length domain string */
-		if (strcmp(arg, "#") == 0)
-		  domain = "";
-		else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
-		  option = '?';
-		serv = opt_malloc(sizeof(struct server));
-		memset(serv, 0, sizeof(struct server));
-		serv->next = newlist;
-		newlist = serv;
-		serv->domain = domain;
-		serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
-		arg = end;
-		if (rebind)
-		  break;
-	      }
-	    if (!newlist)
-	      ret_err(gen_err);
-	  }
-	else
-	  {
-	    newlist = opt_malloc(sizeof(struct server));
-	    memset(newlist, 0, sizeof(struct server));
+        unhide_metas (arg);
+
+        char *start_addr, *s;
+        char *err;
+        struct server newserv;
+        struct dict_node *np = NULL;
+        struct special_domain *obj;
+
+        memset (&newserv, 0, sizeof (struct server));
 #ifdef HAVE_LOOP
-	    newlist->uid = rand32();
+        newserv.uid = rand32 ();
 #endif
-	  }
-	
-	if (servers_only && option == 'S')
-	  newlist->flags |= SERV_FROM_FILE;
-	
-	if (option == 'A')
-	  {
-	    newlist->flags |= SERV_LITERAL_ADDRESS;
-	    if (!(newlist->flags & SERV_TYPE))
-	      ret_err(gen_err);
-	  }
-	else if (option == LOPT_NO_REBIND)
-	  newlist->flags |= SERV_NO_REBIND;
-	
-	if (!arg || !*arg)
-	  {
-	    if (!(newlist->flags & SERV_NO_REBIND))
-	      newlist->flags |= SERV_NO_ADDR; /* no server */
-	    if (newlist->flags & SERV_LITERAL_ADDRESS)
-	      ret_err(gen_err);
-	  }
-
-	else if (strcmp(arg, "#") == 0)
-	  {
-	    newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
-	    if (newlist->flags & SERV_LITERAL_ADDRESS)
-	      ret_err(gen_err);
-	  }
-	else
-	  {
-	    char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
-	    if (err)
-	      ret_err(err);
-	  }
-	
-	serv = newlist;
-	while (serv->next)
-	  {
-	    serv->next->flags = serv->flags;
-	    serv->next->addr = serv->addr;
-	    serv->next->source_addr = serv->source_addr;
-	    strcpy(serv->next->interface, serv->interface);
-	    serv = serv->next;
-	  }
-	serv->next = daemon->servers;
-	daemon->servers = newlist;
-	break;
+        if (arg == NULL)
+          break;
+
+        if (daemon->dh_special_domains == NULL)
+          daemon->dh_special_domains = new_dictnode (NULL, 0);
+
+        // scan the address part first
+        // --xxxx=/example.org/ample.com/temple.net/address-of-server
+        //                                          ^
+        start_addr = NULL;
+        if (strchr (arg, '/') == NULL)
+          {
+            // --xxxx=example.org (only availabe for --rebind-domain-ok)
+            if (option == LOPT_NO_REBIND)
+              newserv.flags |= SERV_NO_REBIND;
+            else if (option == 'S')
+              {
+                // --server=8.8.8.8
+                start_addr = arg;
+              }
+
+          }
+        else
+          {
+            for (s = arg; *s != '\0'; s++)
+              {
+                if (*s == '/')
+                  start_addr = s;
+              }
+            start_addr++;
+          }
+
+        /* --xxxx=/example.org/# , here "#" means use standard server */
+        if (start_addr != NULL)
+          {
+            if (*start_addr == '#')
+              {
+                newserv.flags |= SERV_USE_RESOLV;
+
+              }
+            else if (*start_addr == '\0')
+            /* --xxxx=/example.org/here-is-empty */
+              {
+                if (!(newserv.flags & SERV_NO_REBIND))
+                  newserv.flags |= SERV_NO_ADDR;        /* no server */
+
+                if (option == 'S')
+                  {
+                    ret_err ("--server must specify server address");
+                  }
+
+                if (option == 'A')
+                  {
+                    ret_err ("--address must specify address");
+                  }
+
+              }
+            else
+              {
+                /* --xxxx=/example.org/8.8.8.8#53 at source-ip|interface#port
+                 * --xxxx=8.8.8.8 */
+                err =
+                  parse_server (start_addr, &newserv.addr, &newserv.source_addr,
+                                newserv.interface, &newserv.flags);
+                if (err)
+                  ret_err (err);
+
+              }
+
+          }
+        // --server
+        if (servers_only && option == 'S')
+          newserv.flags |= SERV_FROM_FILE;
+
+        // --rebind-domain-ok
+        if (option == LOPT_NO_REBIND)
+          newserv.flags |= SERV_NO_REBIND;
+
+        // --address will be handled inside the domain dict_node
+
+
+        // the arg pattern can be
+        // --xxxx=example.org (only availabe for --rebind-domain-ok) or
+        // --xxxx=/example.org/ or
+        // --xxxx=/example.org/ample.com/temple.net/
+        if (*arg == '/' || option == LOPT_NO_REBIND)
+          {
+            int rebind = !(*arg == '/');
+            char *end = NULL;
+            if (!rebind)
+              arg++;
+            while (rebind || (end = split_chr (arg, '/')))
+              {
+                char *domain = NULL;
+                /* elide leading dots - they are implied in the search algorithm */
+                while (*arg == '.')
+                  arg++;
+
+                // wrong config option --xxxx=/./1.2.3.4
+                if (strlen (arg) == 0)
+                  continue;
+
+                // --address=/#/1.2.3.4
+                // use label in the root node to mark #(match all domains)
+                if (strcmp (arg, "#") == 0)
+                  {
+                    np = daemon->dh_special_domains;
+                    free(np->label);
+                    np->label = strdup("#");
+                  }
+                else if (!(domain = canonicalise_opt (arg)))
+                  {
+                    option = '?';
+                  }
+                else
+                  {
+                    np = add_or_lookup_domain(daemon->dh_special_domains, domain);
+                  }
+
+                // domain unrecognizable
+                if (np == NULL)
+                    continue;
+
+                if (np->obj == NULL)
+                  {
+                    obj = opt_malloc (sizeof (struct special_domain));
+                    memset (obj, 0, sizeof (struct special_domain));
+                    obj->domain_flags = 0;
+                  }
+                else
+                  {
+                    obj = (struct special_domain *) np->obj;
+                  }
+
+                obj->domain_flags = newserv.flags;
+                if (option == 'A')
+                  {
+                    obj->server = NULL;
+                    obj->domain_flags |= SERV_LITERAL_ADDRESS;
+                    memcpy (&obj->addr, &newserv.addr, sizeof (union mysockaddr));
+                  }
+                else if (option == 'S')
+                  {
+                    // pointer to one of servers in daemon->servers link list,
+                    // no memory is leaked if obj->server been overwritten
+                    newserv.flags |= SERV_HAS_DOMAIN;
+                    obj->server = lookup_or_install_new_server (&newserv);
+                    obj->server->domain = NULL;
+                    obj->domain_flags |= SERV_HAS_DOMAIN;
+                  }
+
+                if (option == LOPT_NO_REBIND)
+                  {
+                    // the rebind flag here instead of the one in struct server
+                    // will be used by forward
+                    obj->domain_flags |= SERV_NO_REBIND;
+                  }
+
+                if (option == LOPT_LOCAL)
+                  {
+                    obj->domain_flags |= SERV_NO_ADDR;
+                  }
+
+                //newserv.flags |= domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
+                np->obj = (void *) obj;
+
+                arg = end;
+                if (rebind)
+                  break;
+              }
+          }
+        // --server=8.8.8.8
+        else if ((strchr (arg, '/') == NULL && option == 'S'))
+          {
+            lookup_or_install_new_server (&newserv);
+          }
+
+        break;
       }
 
     case LOPT_REV_SERV: /* --rev-server */
@@ -2352,65 +2455,78 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
       break;
 #else
       {
-	 struct ipsets ipsets_head;
-	 struct ipsets *ipsets = &ipsets_head;
-	 int size;
-	 char *end;
-	 char **sets, **sets_pos;
-	 memset(ipsets, 0, sizeof(struct ipsets));
-	 unhide_metas(arg);
-	 if (arg && *arg == '/') 
-	   {
-	     arg++;
-	     while ((end = split_chr(arg, '/'))) 
-	       {
-		 char *domain = NULL;
-		 /* elide leading dots - they are implied in the search algorithm */
-		 while (*arg == '.')
-		   arg++;
-		 /* # matches everything and becomes a zero length domain string */
-		 if (strcmp(arg, "#") == 0 || !*arg)
-		   domain = "";
-		 else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg)))
-		   option = '?';
-		 ipsets->next = opt_malloc(sizeof(struct ipsets));
-		 ipsets = ipsets->next;
-		 memset(ipsets, 0, sizeof(struct ipsets));
-		 ipsets->domain = domain;
-		 arg = end;
-	       }
-	   } 
-	 else 
-	   {
-	     ipsets->next = opt_malloc(sizeof(struct ipsets));
-	     ipsets = ipsets->next;
-	     memset(ipsets, 0, sizeof(struct ipsets));
-	     ipsets->domain = "";
-	   }
-	 if (!arg || !*arg)
-	   {
-	     option = '?';
-	     break;
-	   }
-	 size = 2;
-	 for (end = arg; *end; ++end) 
-	   if (*end == ',')
-	       ++size;
-     
-	 sets = sets_pos = opt_malloc(sizeof(char *) * size);
-	 
-	 do {
-	   end = split(arg);
-	   *sets_pos++ = opt_string_alloc(arg);
-	   arg = end;
-	 } while (end);
-	 *sets_pos = 0;
-	 for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next)
-	   ipsets->next->sets = sets;
-	 ipsets->next = daemon->ipsets;
-	 daemon->ipsets = ipsets_head.next;
-	 
-	 break;
+        int size;
+        char *end;
+        char **sets, **sets_pos;
+        int sets_count = 0;
+        unhide_metas (arg);
+        struct dict_node *np = NULL;
+        struct dict_node *setname = NULL;
+        struct ipsets_names *obj;
+        char *domain = NULL;
+
+        if (daemon->dh_ipsets == NULL)
+          daemon->dh_ipsets = new_dictnode (NULL, 0);
+
+        if (daemon->dh_ipset_names == NULL)
+          daemon->dh_ipset_names = new_dictnode (NULL, 0);
+
+        if (arg && *arg == '/')
+          {
+            arg++;
+            while ((end = split_chr (arg, '/')))
+              {
+                /* elide leading dots - they are implied in the search algorithm */
+                while (*arg == '.')
+                  arg++;
+                /* # matches everything and becomes a zero length domain string */
+                if (strcmp (arg, "#") == 0 || !*arg)
+                  /* ignore match all domain directive # for now */
+                  /* domain = ""; */
+                  ;
+                else if (strlen (arg) != 0 && !(domain = canonicalise_opt (arg)))
+                  option = '?';
+
+                if (domain != NULL)
+                  np = add_or_lookup_domain (daemon->dh_ipsets, domain);
+
+                arg = end;
+              }
+          }
+
+        if (!arg || !*arg)
+          {
+            option = '?';
+            break;
+          }
+        size = 2;
+        for (end = arg; *end; ++end)
+          if (*end == ',')
+            ++size;
+
+        sets = sets_pos = opt_malloc (sizeof (char *) * size);
+
+        do
+          {
+            end = split (arg);
+            // only store one copy of setname in daemon->dh_ipset_names
+            setname = add_or_lookup_dictnode(daemon->dh_ipset_names, arg);
+            *sets_pos++ = setname->label;
+            sets_count++;
+            arg = end;
+          }
+        while (end);
+
+        *sets_pos = NULL;
+        if (np != NULL)
+          {
+            obj = opt_malloc(sizeof(struct ipsets_names));
+            obj->sets = sets;
+            obj->count = sets_count;
+            np->obj = (void *) obj;
+          }
+
+        break;
       }
 #endif
       
-- 
1.7.10.4




More information about the Dnsmasq-discuss mailing list