diff options
author | Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> | 2019-03-09 08:40:57 +0000 |
---|---|---|
committer | Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> | 2020-03-04 20:44:23 +0000 |
commit | 3251ac8f2d3de29af2a1584f427246ea702fdbd9 (patch) | |
tree | 6c00b1db0a44edb920cb8a1ba33e3538944981b6 /package/network/services/dnsmasq/patches/0011-Free-config-file-values-on-parsing-errors.patch | |
parent | 633c5137df86e782759e0d88c0facfb2d3f0c424 (diff) |
dnsmasq: bump to v2.81rc1
1st release candidate for v2.81 after 18 months.
Refresh patches & remove all upstreamed leaving:
110-ipset-remove-old-kernel-support.patch
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
Diffstat (limited to 'package/network/services/dnsmasq/patches/0011-Free-config-file-values-on-parsing-errors.patch')
-rw-r--r-- | package/network/services/dnsmasq/patches/0011-Free-config-file-values-on-parsing-errors.patch | 1199 |
1 files changed, 0 insertions, 1199 deletions
diff --git a/package/network/services/dnsmasq/patches/0011-Free-config-file-values-on-parsing-errors.patch b/package/network/services/dnsmasq/patches/0011-Free-config-file-values-on-parsing-errors.patch deleted file mode 100644 index 0b53b30057..0000000000 --- a/package/network/services/dnsmasq/patches/0011-Free-config-file-values-on-parsing-errors.patch +++ /dev/null @@ -1,1199 +0,0 @@ -From 59e470381f84f2fdf0640c7bc67827f3f0c64784 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com> -Date: Fri, 2 Nov 2018 22:39:39 +0000 -Subject: [PATCH 11/32] Free config file values on parsing errors. - -This time I have a little bit more controversal patches. But I think -still useful. They fixes memory leaks that might occur in some cases. -Most dnsmasq errors is fatal, so it does not matter. But some are not. -Some parts are reloaded on SIGHUP signal, so it might leak more than once. - -Some example when it changes the failures. Use dhcp-options file with -this content: - -tag:error,vendor:redhat -option:ntp-server,1.2.3.4.5 -option6:ntp-server,[:::] - -Is not fatal and dnsmasq will start. On each reload command, it would -leak some memory. I validated it using valgrind --leak-check=full -dnsmasq -d. This patch fixes it. It introduces something that might be -considered constructor and destructor of selected structures. - -Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> ---- - src/option.c | 533 ++++++++++++++++++++++++++++++++++----------------- - 1 file changed, 352 insertions(+), 181 deletions(-) - ---- a/src/option.c -+++ b/src/option.c -@@ -577,14 +577,15 @@ static void *opt_malloc(size_t size) - return ret; - } - --static char *opt_string_alloc(char *cp) -+static char *opt_string_alloc(const char *cp) - { - char *ret = NULL; -+ size_t len; - -- if (cp && strlen(cp) != 0) -+ if (cp && (len = strlen(cp)) != 0) - { -- ret = opt_malloc(strlen(cp)+1); -- strcpy(ret, cp); -+ ret = opt_malloc(len+1); -+ memcpy(ret, cp, len+1); - - /* restore hidden metachars */ - unhide_metas(ret); -@@ -759,6 +760,8 @@ static void do_usage(void) - } - - #define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0) -+#define ret_err_free(x,m) do { strcpy(errstr, (x)); free((m)); return 0; } while (0) -+#define goto_err(x) do { strcpy(errstr, (x)); goto on_error; } while (0) - - static char *parse_mysockaddr(char *arg, union mysockaddr *addr) - { -@@ -904,6 +907,8 @@ static struct server *add_rev4(struct in - p += sprintf(p, "%d.", (a >> 24) & 0xff); - break; - default: -+ free(serv->domain); -+ free(serv); - return NULL; - } - -@@ -958,6 +963,97 @@ static char *set_prefix(char *arg) - return arg; - } - -+static struct dhcp_netid * -+dhcp_netid_create(const char *net, struct dhcp_netid *next) -+{ -+ struct dhcp_netid *tt; -+ tt = opt_malloc(sizeof (struct dhcp_netid)); -+ tt->net = opt_string_alloc(net); -+ tt->next = next; -+ return tt; -+} -+ -+static void dhcp_netid_free(struct dhcp_netid *nid) -+{ -+ while (nid) -+ { -+ struct dhcp_netid *tmp = nid; -+ nid = nid->next; -+ free(tmp->net); -+ free(tmp); -+ } -+} -+ -+/* Parse one or more tag:s before parameters. -+ * Moves arg to the end of tags. */ -+static struct dhcp_netid * dhcp_tags(char **arg) -+{ -+ struct dhcp_netid *id = NULL; -+ -+ while (is_tag_prefix(*arg)) -+ { -+ char *comma = split(*arg); -+ id = dhcp_netid_create((*arg)+4, id); -+ *arg = comma; -+ }; -+ if (!*arg) -+ { -+ dhcp_netid_free(id); -+ id = NULL; -+ } -+ return id; -+} -+ -+static void dhcp_netid_list_free(struct dhcp_netid_list *netid) -+{ -+ while (netid) -+ { -+ struct dhcp_netid_list *tmplist = netid; -+ netid = netid->next; -+ dhcp_netid_free(tmplist->list); -+ free(tmplist); -+ } -+} -+ -+static void dhcp_config_free(struct dhcp_config *config) -+{ -+ if (config) -+ { -+ struct hwaddr_config *hwaddr = config->hwaddr; -+ while (hwaddr) -+ { -+ struct hwaddr_config *tmp = hwaddr; -+ hwaddr = hwaddr->next; -+ free(tmp); -+ } -+ dhcp_netid_list_free(config->netid); -+ if (config->flags & CONFIG_CLID) -+ free(config->clid); -+ free(config); -+ } -+} -+ -+static void dhcp_context_free(struct dhcp_context *ctx) -+{ -+ if (ctx) -+ { -+ dhcp_netid_free(ctx->filter); -+ free(ctx->netid.net); -+ free(ctx->template_interface); -+ free(ctx); -+ } -+} -+ -+static void dhcp_opt_free(struct dhcp_opt *opt) -+{ -+ if (opt->flags & DHOPT_VENDOR) -+ free(opt->u.vendor_class); -+ dhcp_netid_free(opt->netid); -+ free(opt->val); -+ free(opt); -+} -+ -+ - /* This is too insanely large to keep in-line in the switch */ - static int parse_dhcp_opt(char *errstr, char *arg, int flags) - { -@@ -965,7 +1061,6 @@ static int parse_dhcp_opt(char *errstr, - char lenchar = 0, *cp; - int addrs, digs, is_addr, is_addr6, is_hex, is_dec, is_string, dots; - char *comma = NULL; -- struct dhcp_netid *np = NULL; - u16 opt_len = 0; - int is6 = 0; - int option_ok = 0; -@@ -1052,14 +1147,9 @@ static int parse_dhcp_opt(char *errstr, - } - else - { -- new->netid = opt_malloc(sizeof (struct dhcp_netid)); - /* allow optional "net:" or "tag:" for consistency */ -- if (is_tag_prefix(arg)) -- new->netid->net = opt_string_alloc(arg+4); -- else -- new->netid->net = opt_string_alloc(set_prefix(arg)); -- new->netid->next = np; -- np = new->netid; -+ const char *name = (is_tag_prefix(arg)) ? arg+4 : set_prefix(arg); -+ new->netid = dhcp_netid_create(name, new->netid); - } - - arg = comma; -@@ -1069,7 +1159,7 @@ static int parse_dhcp_opt(char *errstr, - if (is6) - { - if (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE)) -- ret_err(_("unsupported encapsulation for IPv6 option")); -+ goto_err(_("unsupported encapsulation for IPv6 option")); - - if (opt_len == 0 && - !(new->flags & DHOPT_RFC3925)) -@@ -1083,7 +1173,7 @@ static int parse_dhcp_opt(char *errstr, - - /* option may be missing with rfc3925 match */ - if (!option_ok) -- ret_err(_("bad dhcp-option")); -+ goto_err(_("bad dhcp-option")); - - if (comma) - { -@@ -1151,10 +1241,10 @@ static int parse_dhcp_opt(char *errstr, - is_string = is_dec = is_hex = 0; - - if (!is6 && (!is_addr || dots == 0)) -- ret_err(_("bad IP address")); -+ goto_err(_("bad IP address")); - - if (is6 && !is_addr6) -- ret_err(_("bad IPv6 address")); -+ goto_err(_("bad IPv6 address")); - } - /* or names */ - else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING)) -@@ -1247,7 +1337,7 @@ static int parse_dhcp_opt(char *errstr, - comma = split(cp); - slash = split_chr(cp, '/'); - if (!inet_pton(AF_INET, cp, &in)) -- ret_err(_("bad IPv4 address")); -+ goto_err(_("bad IPv4 address")); - if (!slash) - { - memcpy(op, &in, INADDRSZ); -@@ -1292,8 +1382,8 @@ static int parse_dhcp_opt(char *errstr, - op += IN6ADDRSZ; - continue; - } -- -- ret_err(_("bad IPv6 address")); -+ -+ goto_err(_("bad IPv6 address")); - } - new->len = op - new->val; - } -@@ -1320,7 +1410,7 @@ static int parse_dhcp_opt(char *errstr, - if (strcmp (arg, ".") != 0) - { - if (!(dom = canonicalise_opt(arg))) -- ret_err(_("bad domain in dhcp-option")); -+ goto_err(_("bad domain in dhcp-option")); - - domlen = strlen(dom) + 2; - } -@@ -1414,7 +1504,7 @@ static int parse_dhcp_opt(char *errstr, - { - char *dom = canonicalise_opt(arg); - if (!dom) -- ret_err(_("bad domain in dhcp-option")); -+ goto_err(_("bad domain in dhcp-option")); - - newp = opt_malloc(len + strlen(dom) + 2); - -@@ -1452,14 +1542,14 @@ static int parse_dhcp_opt(char *errstr, - ((new->len > 255) || - (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) || - (new->len > 250 && (new->flags & DHOPT_RFC3925)))) -- ret_err(_("dhcp-option too long")); -+ goto_err(_("dhcp-option too long")); - - if (flags == DHOPT_MATCH) - { - if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) || - !new->netid || - new->netid->next) -- ret_err(_("illegal dhcp-match")); -+ goto_err(_("illegal dhcp-match")); - - if (is6) - { -@@ -1484,6 +1574,9 @@ static int parse_dhcp_opt(char *errstr, - } - - return 1; -+on_error: -+ dhcp_opt_free(new); -+ return 0; - } - - #endif -@@ -1498,6 +1591,16 @@ void reset_option_bool(unsigned int opt) - option_var(opt) &= ~(option_val(opt)); - } - -+static void server_list_free(struct server *list) -+{ -+ while (list) -+ { -+ struct server *tmp = list; -+ list = list->next; -+ free(tmp); -+ } -+} -+ - static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only) - { - int i; -@@ -1679,13 +1782,13 @@ static int one_opt(int option, char *arg - /* has subnet+len */ - err = parse_mysockaddr(arg, &new->addr); - if (err) -- ret_err(err); -+ ret_err_free(err, new); - if (!atoi_check(end, &new->mask)) -- ret_err(gen_err); -+ ret_err_free(gen_err, new); - new->addr_used = 1; - } - else if (!atoi_check(arg, &new->mask)) -- ret_err(gen_err); -+ ret_err_free(gen_err, new); - - daemon->add_subnet4 = new; - -@@ -1697,15 +1800,15 @@ static int one_opt(int option, char *arg - /* has subnet+len */ - err = parse_mysockaddr(comma, &new->addr); - if (err) -- ret_err(err); -+ ret_err_free(err, new); - if (!atoi_check(end, &new->mask)) -- ret_err(gen_err); -+ ret_err_free(gen_err, new); - new->addr_used = 1; - } - else - { - if (!atoi_check(comma, &new->mask)) -- ret_err(gen_err); -+ ret_err_free(gen_err, new); - } - - daemon->add_subnet6 = new; -@@ -1912,7 +2015,10 @@ static int one_opt(int option, char *arg - else if (strcmp(fam, "6") == 0) - new->addr.sa.sa_family = AF_INET6; - else -- ret_err(gen_err); -+ { -+ free(new->name); -+ ret_err_free(gen_err, new); -+ } - } - } - new->next = daemon->authinterface; -@@ -2077,7 +2183,7 @@ static int one_opt(int option, char *arg - - arg = split(netpart); - if (!atoi_check(netpart, &msize)) -- ret_err(gen_err); -+ ret_err_free(gen_err, new); - else if (inet_pton(AF_INET, comma, &new->start)) - { - int mask = (1 << (32 - msize)) - 1; -@@ -2090,18 +2196,18 @@ static int one_opt(int option, char *arg - { - if (!(new->prefix = canonicalise_opt(arg)) || - strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN) -- ret_err(_("bad prefix")); -+ ret_err_free(_("bad prefix"), new); - } - else if (strcmp(arg, "local") != 0 || - (msize != 8 && msize != 16 && msize != 24)) -- ret_err(gen_err); -+ ret_err_free(gen_err, new); - else - { - /* generate the equivalent of - local=/xxx.yyy.zzz.in-addr.arpa/ */ - struct server *serv = add_rev4(new->start, msize); - if (!serv) -- ret_err(_("bad prefix")); -+ ret_err_free(_("bad prefix"), new); - - serv->flags |= SERV_NO_ADDR; - -@@ -2130,17 +2236,17 @@ static int one_opt(int option, char *arg - setaddr6part(&new->end6, addrpart | mask); - - if (msize < 64) -- ret_err(gen_err); -+ ret_err_free(gen_err, new); - else if (arg) - { - if (option != 's') - { - if (!(new->prefix = canonicalise_opt(arg)) || - strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN) -- ret_err(_("bad prefix")); -+ ret_err_free(_("bad prefix"), new); - } - else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0)) -- ret_err(gen_err); -+ ret_err_free(gen_err, new); - else - { - /* generate the equivalent of -@@ -2159,7 +2265,7 @@ static int one_opt(int option, char *arg - } - } - else -- ret_err(gen_err); -+ ret_err_free(gen_err, new); - } - else - { -@@ -2173,7 +2279,7 @@ static int one_opt(int option, char *arg - if (!arg) - new->end.s_addr = new->start.s_addr; - else if (!inet_pton(AF_INET, arg, &new->end)) -- ret_err(gen_err); -+ ret_err_free(gen_err, new); - } - else if (inet_pton(AF_INET6, comma, &new->start6)) - { -@@ -2181,16 +2287,16 @@ static int one_opt(int option, char *arg - if (!arg) - memcpy(&new->end6, &new->start6, IN6ADDRSZ); - else if (!inet_pton(AF_INET6, arg, &new->end6)) -- ret_err(gen_err); -+ ret_err_free(gen_err, new); - } - else -- ret_err(gen_err); -+ ret_err_free(gen_err, new); - - if (option != 's' && prefstr) - { - if (!(new->prefix = canonicalise_opt(prefstr)) || - strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN) -- ret_err(_("bad prefix")); -+ ret_err_free(_("bad prefix"), new); - } - } - -@@ -2352,7 +2458,7 @@ static int one_opt(int option, char *arg - #endif - } - else -- ret_err(gen_err); -+ ret_err_free(gen_err, new); - - new->used = 0; - if (option == 'a') -@@ -2423,7 +2529,10 @@ static int one_opt(int option, char *arg - { - newlist->flags |= SERV_LITERAL_ADDRESS; - if (!(newlist->flags & SERV_TYPE)) -- ret_err(gen_err); -+ { -+ server_list_free(newlist); -+ ret_err(gen_err); -+ } - } - else if (option == LOPT_NO_REBIND) - newlist->flags |= SERV_NO_REBIND; -@@ -2440,7 +2549,10 @@ static int one_opt(int option, char *arg - { - char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags); - if (err) -- ret_err(err); -+ { -+ server_list_free(newlist); -+ ret_err(err); -+ } - } - - serv = newlist; -@@ -2776,21 +2888,19 @@ static int one_opt(int option, char *arg - { - if (is_tag_prefix(arg)) - { -- struct dhcp_netid *tt = opt_malloc(sizeof (struct dhcp_netid)); -- tt->net = opt_string_alloc(arg+4); -- tt->next = new->filter; - /* ignore empty tag */ -- if (tt->net) -- new->filter = tt; -+ if (arg[4]) -+ new->filter = dhcp_netid_create(arg+4, new->filter); - } - else - { - if (new->netid.net) -- ret_err(_("only one tag allowed")); -- else if (strstr(arg, "set:") == arg) -- new->netid.net = opt_string_alloc(arg+4); -+ { -+ dhcp_context_free(new); -+ ret_err(_("only one tag allowed")); -+ } - else -- new->netid.net = opt_string_alloc(arg); -+ new->netid.net = opt_string_alloc(set_prefix(arg)); - } - arg = comma; - } -@@ -2806,7 +2916,10 @@ static int one_opt(int option, char *arg - break; - - if (k < 2) -- ret_err(_("bad dhcp-range")); -+ { -+ dhcp_context_free(new); -+ ret_err(_("bad dhcp-range")); -+ } - - if (inet_pton(AF_INET, a[0], &new->start)) - { -@@ -2818,7 +2931,10 @@ static int one_opt(int option, char *arg - else if (strcmp(a[1], "proxy") == 0) - new->flags |= CONTEXT_PROXY; - else if (!inet_pton(AF_INET, a[1], &new->end)) -- ret_err(_("bad dhcp-range")); -+ { -+ dhcp_context_free(new); -+ ret_err(_("bad dhcp-range")); -+ } - - if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr)) - { -@@ -2833,7 +2949,10 @@ static int one_opt(int option, char *arg - new->flags |= CONTEXT_NETMASK; - leasepos = 3; - if (!is_same_net(new->start, new->end, new->netmask)) -- ret_err(_("inconsistent DHCP range")); -+ { -+ dhcp_context_free(new); -+ ret_err(_("inconsistent DHCP range")); -+ } - - - if (k >= 4 && strchr(a[3], '.') && -@@ -2847,6 +2966,8 @@ static int one_opt(int option, char *arg - #ifdef HAVE_DHCP6 - else if (inet_pton(AF_INET6, a[0], &new->start6)) - { -+ const char *err = NULL; -+ - new->flags |= CONTEXT_V6; - new->prefix = 64; /* default */ - new->end6 = new->start6; -@@ -2892,19 +3013,24 @@ static int one_opt(int option, char *arg - } - } - -- if (new->prefix != 64) -+ if (new->prefix > 64) - { - if (new->flags & CONTEXT_RA) -- ret_err(_("prefix length must be exactly 64 for RA subnets")); -+ err=(_("prefix length must be exactly 64 for RA subnets")); - else if (new->flags & CONTEXT_TEMPLATE) -- ret_err(_("prefix length must be exactly 64 for subnet constructors")); -+ err=(_("prefix length must be exactly 64 for subnet constructors")); - } -- -- if (new->prefix < 64) -- ret_err(_("prefix length must be at least 64")); -+ else if (new->prefix < 64) -+ err=(_("prefix length must be at least 64")); - -- if (!is_same_net6(&new->start6, &new->end6, new->prefix)) -- ret_err(_("inconsistent DHCPv6 range")); -+ if (!err && !is_same_net6(&new->start6, &new->end6, new->prefix)) -+ err=(_("inconsistent DHCPv6 range")); -+ -+ if (err) -+ { -+ dhcp_context_free(new); -+ ret_err(err); -+ } - - /* dhcp-range=:: enables DHCP stateless on any interface */ - if (IN6_IS_ADDR_UNSPECIFIED(&new->start6) && !(new->flags & CONTEXT_TEMPLATE)) -@@ -2915,7 +3041,10 @@ static int one_opt(int option, char *arg - struct in6_addr zero; - memset(&zero, 0, sizeof(zero)); - if (!is_same_net6(&zero, &new->start6, new->prefix)) -- ret_err(_("prefix must be zero with \"constructor:\" argument")); -+ { -+ dhcp_context_free(new); -+ ret_err(_("prefix must be zero with \"constructor:\" argument")); -+ } - } - - if (addr6part(&new->start6) > addr6part(&new->end6)) -@@ -2927,12 +3056,18 @@ static int one_opt(int option, char *arg - } - #endif - else -- ret_err(_("bad dhcp-range")); -+ { -+ dhcp_context_free(new); -+ ret_err(_("bad dhcp-range")); -+ } - - if (leasepos < k) - { - if (leasepos != k-1) -- ret_err(_("bad dhcp-range")); -+ { -+ dhcp_context_free(new); -+ ret_err(_("bad dhcp-range")); -+ } - - if (strcmp(a[leasepos], "infinite") == 0) - new->lease_time = 0xffffffff; -@@ -2971,7 +3106,7 @@ static int one_opt(int option, char *arg - break; - - if (*cp || (leasepos+1 < k)) -- ret_err(_("bad dhcp-range")); -+ ret_err_free(_("bad dhcp-range"), new); - - new->lease_time = atoi(a[leasepos]) * fac; - /* Leases of a minute or less confuse -@@ -2998,6 +3133,7 @@ static int one_opt(int option, char *arg - new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0; - new->hwaddr = NULL; - new->netid = NULL; -+ new->clid = NULL; - - if ((a[0] = arg)) - for (k = 1; k < 7; k++) -@@ -3028,7 +3164,10 @@ static int one_opt(int option, char *arg - } - - if (len == -1) -- ret_err(_("bad hex constant")); -+ { -+ dhcp_config_free(new); -+ ret_err(_("bad hex constant")); -+ } - else if ((new->clid = opt_malloc(len))) - { - new->flags |= CONFIG_CLID; -@@ -3040,17 +3179,17 @@ static int one_opt(int option, char *arg - /* dhcp-host has strange backwards-compat needs. */ - else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg) - { -- struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid)); - struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list)); -- newtag->net = opt_malloc(strlen(arg + 4) + 1); - newlist->next = new->netid; - new->netid = newlist; -- newlist->list = newtag; -- strcpy(newtag->net, arg+4); -- unhide_metas(newtag->net); -+ newlist->list = dhcp_netid_create(arg+4, NULL); - } - else if (strstr(arg, "tag:") == arg) -- ret_err(_("cannot match tags in --dhcp-host")); -+ { -+ -+ dhcp_config_free(new); -+ ret_err(_("cannot match tags in --dhcp-host")); -+ } - #ifdef HAVE_DHCP6 - else if (arg[0] == '[' && arg[strlen(arg)-1] == ']') - { -@@ -3058,7 +3197,10 @@ static int one_opt(int option, char *arg - arg++; - - if (!inet_pton(AF_INET6, arg, &new->addr6)) -- ret_err(_("bad IPv6 address")); -+ { -+ dhcp_config_free(new); -+ ret_err(_("bad IPv6 address")); -+ } - - for (i= 0; i < 8; i++) - if (new->addr6.s6_addr[i] != 0) -@@ -3076,10 +3218,13 @@ static int one_opt(int option, char *arg - struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config)); - if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX, - &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1) -- ret_err(_("bad hex constant")); -+ { -+ free(newhw); -+ dhcp_config_free(new); -+ ret_err(_("bad hex constant")); -+ } - else - { -- - newhw->next = new->hwaddr; - new->hwaddr = newhw; - } -@@ -3156,7 +3301,10 @@ static int one_opt(int option, char *arg - { - if (!(new->hostname = canonicalise_opt(a[j])) || - !legal_hostname(new->hostname)) -- ret_err(_("bad DHCP host name")); -+ { -+ dhcp_config_free(new); -+ ret_err(_("bad DHCP host name")); -+ } - - new->flags |= CONFIG_NAME; - new->domain = strip_hostname(new->hostname); -@@ -3209,10 +3357,7 @@ static int one_opt(int option, char *arg - } - else - { -- struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid)); -- newtag->net = opt_malloc(len - 3); -- strcpy(newtag->net, arg+4); -- unhide_metas(newtag->net); -+ struct dhcp_netid *newtag = dhcp_netid_create(arg+4, NULL); - - if (strstr(arg, "set:") == arg) - { -@@ -3229,7 +3374,7 @@ static int one_opt(int option, char *arg - else - { - new->set = NULL; -- free(newtag); -+ dhcp_netid_free(newtag); - break; - } - } -@@ -3238,7 +3383,11 @@ static int one_opt(int option, char *arg - } - - if (!new->set) -- ret_err(_("bad tag-if")); -+ { -+ dhcp_netid_free(new->tag); -+ dhcp_netid_list_free(new->set); -+ ret_err_free(_("bad tag-if"), new); -+ } - - break; - } -@@ -3281,19 +3430,12 @@ static int one_opt(int option, char *arg - - case 'M': /* --dhcp-boot */ - { -- struct dhcp_netid *id = NULL; -- while (is_tag_prefix(arg)) -- { -- struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid)); -- newid->next = id; -- id = newid; -- comma = split(arg); -- newid->net = opt_string_alloc(arg+4); -- arg = comma; -- }; -+ struct dhcp_netid *id = dhcp_tags(&arg); - -- if (!arg) -- ret_err(gen_err); -+ if (!id) -+ { -+ ret_err(gen_err); -+ } - else - { - char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL; -@@ -3339,19 +3481,12 @@ static int one_opt(int option, char *arg - - case LOPT_REPLY_DELAY: /* --dhcp-reply-delay */ - { -- struct dhcp_netid *id = NULL; -- while (is_tag_prefix(arg)) -- { -- struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid)); -- newid->next = id; -- id = newid; -- comma = split(arg); -- newid->net = opt_string_alloc(arg+4); -- arg = comma; -- }; -+ struct dhcp_netid *id = dhcp_tags(&arg); - -- if (!arg) -- ret_err(gen_err); -+ if (!id) -+ { -+ ret_err(gen_err); -+ } - else - { - struct delay_config *new; -@@ -3376,19 +3511,13 @@ static int one_opt(int option, char *arg - - new->netid = NULL; - new->opt = 10; /* PXE_MENU_PROMPT */ -- -- while (is_tag_prefix(arg)) -- { -- struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid)); -- comma = split(arg); -- nn->next = new->netid; -- new->netid = nn; -- nn->net = opt_string_alloc(arg+4); -- arg = comma; -- } -+ new->netid = dhcp_tags(&arg); - -- if (!arg) -- ret_err(gen_err); -+ if (!new->netid) -+ { -+ dhcp_opt_free(new); -+ ret_err(gen_err); -+ } - else - { - comma = split(arg); -@@ -3424,17 +3553,8 @@ static int one_opt(int option, char *arg - new->netid = NULL; - new->sname = NULL; - new->server.s_addr = 0; -+ new->netid = dhcp_tags(&arg); - -- while (is_tag_prefix(arg)) -- { -- struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid)); -- comma = split(arg); -- nn->next = new->netid; -- new->netid = nn; -- nn->net = opt_string_alloc(arg+4); -- arg = comma; -- } -- - if (arg && (comma = split(arg))) - { - for (i = 0; CSA[i]; i++) -@@ -3511,7 +3631,10 @@ static int one_opt(int option, char *arg - unhide_metas(comma); - new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type); - if (new->hwaddr_len == -1) -- ret_err(gen_err); -+ { -+ free(new->netid.net); -+ ret_err_free(gen_err, new); -+ } - else - { - new->next = daemon->dhcp_macs; -@@ -3528,7 +3651,7 @@ static int one_opt(int option, char *arg - - if (!(comma = split(arg)) || - !atoi_check16(comma, &new->class)) -- ret_err(gen_err); -+ ret_err_free(gen_err, new); - - new->tag.net = opt_string_alloc(set_prefix(arg)); - new->next = daemon->prefix_classes; -@@ -3550,7 +3673,7 @@ static int one_opt(int option, char *arg - struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor)); - - if (!(comma = split(arg))) -- ret_err(gen_err); -+ ret_err_free(gen_err, new); - - new->netid.net = opt_string_alloc(set_prefix(arg)); - /* check for hex string - must digits may include : must not have nothing else, -@@ -3560,7 +3683,10 @@ static int one_opt(int option, char *arg - if ((comma = split(arg))) - { - if (option != 'U' || strstr(arg, "enterprise:") != arg) -- ret_err(gen_err); -+ { -+ free(new->netid.net); -+ ret_err_free(gen_err, new); -+ } - else - new->enterprise = atoi(arg+11); - } -@@ -3662,14 +3788,8 @@ static int one_opt(int option, char *arg - } - - while (arg) { -- struct dhcp_netid *member = opt_malloc(sizeof(struct dhcp_netid)); - comma = split(arg); -- member->next = list; -- list = member; -- if (is_tag_prefix(arg)) -- member->net = opt_string_alloc(arg+4); -- else -- member->net = opt_string_alloc(arg); -+ list = dhcp_netid_create(is_tag_prefix(arg) ? arg+4 :arg, list); - arg = comma; - } - -@@ -3683,7 +3803,7 @@ static int one_opt(int option, char *arg - struct addr_list *new = opt_malloc(sizeof(struct addr_list)); - comma = split(arg); - if (!(inet_pton(AF_INET, arg, &new->addr) > 0)) -- ret_err(_("bad dhcp-proxy address")); -+ ret_err_free(_("bad dhcp-proxy address"), new); - new->next = daemon->override_relays; - daemon->override_relays = new; - arg = comma; -@@ -3709,7 +3829,10 @@ static int one_opt(int option, char *arg - } - #endif - else -- ret_err(_("Bad dhcp-relay")); -+ { -+ free(new->interface); -+ ret_err_free(_("Bad dhcp-relay"), new); -+ } - - break; - } -@@ -3749,8 +3872,11 @@ static int one_opt(int option, char *arg - arg = split(comma); - if (!atoi_check(comma, &new->interval) || - (arg && !atoi_check(arg, &new->lifetime))) -+ { - err: -- ret_err(_("bad RA-params")); -+ free(new->name); -+ ret_err_free(_("bad RA-params"), new); -+ } - - new->next = daemon->ra_interfaces; - daemon->ra_interfaces = new; -@@ -3799,7 +3925,7 @@ err: - (!(inet_pton(AF_INET, dash, &new->end) > 0) || - !is_same_net(new->in, new->end, new->mask) || - ntohl(new->in.s_addr) > ntohl(new->end.s_addr))) -- ret_err(_("invalid alias range")); -+ ret_err_free(_("invalid alias range"), new); - - break; - } -@@ -3832,7 +3958,7 @@ err: - else if (strcmp(arg, "6") == 0) - new->family = AF_INET6; - else -- ret_err(gen_err); -+ ret_err_free(gen_err, new); - } - new->intr = opt_string_alloc(comma); - break; -@@ -3864,11 +3990,19 @@ err: - alias = canonicalise_opt(arg); - - if (!alias || !target) -- ret_err(_("bad CNAME")); -+ { -+ free(target); -+ free(alias); -+ ret_err(_("bad CNAME")); -+ } - - for (new = daemon->cnames; new; new = new->next) - if (hostname_isequal(new->alias, alias)) -- ret_err(_("duplicate CNAME")); -+ { -+ free(target); -+ free(alias); -+ ret_err(_("duplicate CNAME")); -+ } - new = opt_malloc(sizeof(struct cname)); - new->next = daemon->cnames; - daemon->cnames = new; -@@ -3891,7 +4025,11 @@ err: - - if (!(dom = canonicalise_opt(arg)) || - (comma && !(target = canonicalise_opt(comma)))) -- ret_err(_("bad PTR record")); -+ { -+ free(dom); -+ free(target); -+ ret_err(_("bad PTR record")); -+ } - else - { - new = opt_malloc(sizeof(struct ptr_record)); -@@ -3909,7 +4047,7 @@ err: - int k = 0; - struct naptr *new; - int order, pref; -- char *name, *replace = NULL; -+ char *name=NULL, *replace = NULL; - - if ((a[0] = arg)) - for (k = 1; k < 7; k++) -@@ -3922,7 +4060,11 @@ err: - !atoi_check16(a[1], &order) || - !atoi_check16(a[2], &pref) || - (k == 7 && !(replace = canonicalise_opt(a[6])))) -- ret_err(_("bad NAPTR record")); -+ { -+ free(name); -+ free(replace); -+ ret_err(_("bad NAPTR record")); -+ } - else - { - new = opt_malloc(sizeof(struct naptr)); -@@ -3944,22 +4086,26 @@ err: - struct txt_record *new; - size_t len = 0; - char *data; -- int val; -+ int class; - - comma = split(arg); - data = split(comma); - - new = opt_malloc(sizeof(struct txt_record)); -- new->next = daemon->rr; -- daemon->rr = new; -+ new->name = NULL; - -- if (!atoi_check(comma, &val) || -+ if (!atoi_check(comma, &class) || - !(new->name = canonicalise_opt(arg)) || - (data && (len = parse_hex(data, (unsigned char *)data, -1, NULL, NULL)) == -1U)) -- ret_err(_("bad RR record")); -- -- new->class = val; -+ { -+ free(new->name); -+ ret_err_free(_("bad RR record"), new); -+ } -+ - new->len = 0; -+ new->class = class; -+ new->next = daemon->rr; -+ daemon->rr = new; - - if (data) - { -@@ -4011,14 +4157,14 @@ err: - comma = split(arg); - - new = opt_malloc(sizeof(struct txt_record)); -- new->next = daemon->txt; -- daemon->txt = new; - new->class = C_IN; - new->stat = 0; - - if (!(new->name = canonicalise_opt(arg))) -- ret_err(_("bad TXT record")); -+ ret_err_free(_("bad TXT record"), new); - -+ new->next = daemon->txt; -+ daemon->txt = new; - len = comma ? strlen(comma) : 0; - len += (len/255) + 1; /* room for extra counts */ - new->txt = p = opt_malloc(len); -@@ -4065,24 +4211,32 @@ err: - arg = comma; - comma = split(arg); - if (!(target = canonicalise_opt(arg))) -- ret_err(_("bad SRV target")); -+ ret_err_free(_("bad SRV target"), name); - - if (comma) - { - arg = comma; - comma = split(arg); - if (!atoi_check16(arg, &port)) -- ret_err(_("invalid port number")); -+ { -+ free(name); -+ ret_err_free(_("invalid port number"), target); -+ } - - if (comma) - { - arg = comma; - comma = split(arg); - if (!atoi_check16(arg, &priority)) -- ret_err(_("invalid priority")); -- -+ { -+ free(name); -+ ret_err_free(_("invalid priority"), target); -+ } - if (comma && !atoi_check16(comma, &weight)) -- ret_err(_("invalid weight")); -+ { -+ free(name); -+ ret_err_free(_("invalid weight"), target); -+ } - } - } - } -@@ -4101,13 +4255,15 @@ err: - - case LOPT_HOST_REC: /* --host-record */ - { -- struct host_record *new = opt_malloc(sizeof(struct host_record)); -- memset(new, 0, sizeof(struct host_record)); -- new->ttl = -1; -+ struct host_record *new; - - if (!arg || !(comma = split(arg))) - ret_err(_("Bad host-record")); - -+ new = opt_malloc(sizeof(struct host_record)); -+ memset(new, 0, sizeof(struct host_record)); -+ new->ttl = -1; -+ - while (arg) - { - struct all_addr addr; -@@ -4126,10 +4282,19 @@ err: - { - int nomem; - char *canon = canonicalise(arg, &nomem); -- struct name_list *nl = opt_malloc(sizeof(struct name_list)); -+ struct name_list *nl; - if (!canon) -- ret_err(_("Bad name in host-record")); -+ { -+ struct name_list *tmp = new->names, *next; -+ for (tmp = new->names; tmp; tmp = next) -+ { -+ next = tmp->next; -+ free(tmp); -+ } -+ ret_err_free(_("Bad name in host-record"), new); -+ } - -+ nl = opt_malloc(sizeof(struct name_list)); - nl->name = canon; - /* keep order, so that PTR record goes to first name */ - nl->next = NULL; -@@ -4179,6 +4344,7 @@ err: - int len; - - new->class = C_IN; -+ new->name = NULL; - - if ((comma = split(arg)) && (algo = split(comma))) - { -@@ -4203,7 +4369,7 @@ err: - !atoi_check8(algo, &new->algo) || - !atoi_check8(digest, &new->digest_type) || - !(new->name = canonicalise_opt(arg))) -- ret_err(_("bad trust anchor")); -+ ret_err_free(_("bad trust anchor"), new); - - /* Upper bound on length */ - len = (2*strlen(keyhex))+1; -@@ -4217,7 +4383,10 @@ err: - else - cp++; - if ((new->digestlen = parse_hex(keyhex, (unsigned char *)new->digest, len, NULL, NULL)) == -1) -- ret_err(_("bad HEX in trust anchor")); -+ { -+ free(new->name); -+ ret_err_free(_("bad HEX in trust anchor"), new); -+ } - - new->next = daemon->ds; - daemon->ds = new; -@@ -4686,8 +4855,8 @@ void read_opts(int argc, char **argv, ch - size_t argbuf_size = MAXDNAME; - char *argbuf = opt_malloc(argbuf_size); - char *buff = opt_malloc(MAXDNAME); -- int option, conffile_opt = '7', testmode = 0; -- char *arg, *conffile = CONFFILE; -+ int option, testmode = 0; -+ char *arg, *conffile = NULL; - - opterr = 0; - -@@ -4796,7 +4965,8 @@ void read_opts(int argc, char **argv, ch - } - else if (option == 'C') - { -- conffile_opt = 0; /* file must exist */ -+ if (conffile) -+ free(conffile); - conffile = opt_string_alloc(arg); - } - else -@@ -4814,10 +4984,11 @@ void read_opts(int argc, char **argv, ch - - if (conffile) - { -- one_file(conffile, conffile_opt); -- if (conffile_opt == 0) -- free(conffile); -+ one_file(conffile, 0); -+ free(conffile); - } -+ else -+ one_file(CONFFILE, '7'); - - /* port might not be known when the address is parsed - fill in here */ - if (daemon->servers) |