[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