summaryrefslogtreecommitdiff
path: root/src/option.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/option.c')
-rw-r--r--src/option.c1380
1 files changed, 861 insertions, 519 deletions
diff --git a/src/option.c b/src/option.c
index d358d99..dbe5f90 100644
--- a/src/option.c
+++ b/src/option.c
@@ -1,4 +1,4 @@
-/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
+/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -129,9 +129,6 @@ struct myoption {
#define LOPT_AUTHPEER 318
#define LOPT_IPSET 319
#define LOPT_SYNTH 320
-#ifdef OPTION6_PREFIX_CLASS
-#define LOPT_PREF_CLSS 321
-#endif
#define LOPT_RELAY 323
#define LOPT_RA_PARAM 324
#define LOPT_ADD_SBNET 325
@@ -160,6 +157,16 @@ struct myoption {
#define LOPT_DHCPTTL 348
#define LOPT_TFTP_MTU 349
#define LOPT_REPLY_DELAY 350
+#define LOPT_RAPID_COMMIT 351
+#define LOPT_DUMPFILE 352
+#define LOPT_DUMPMASK 353
+#define LOPT_UBUS 354
+#define LOPT_NAME_MATCH 355
+#define LOPT_CAA 356
+#define LOPT_SHARED_NET 357
+#define LOPT_IGNORE_CLID 358
+#define LOPT_SINGLE_PORT 359
+#define LOPT_SCRIPT_TIME 360
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -228,8 +235,10 @@ static const struct myoption opts[] =
{ "srv-host", 1, 0, 'W' },
{ "localise-queries", 0, 0, 'y' },
{ "txt-record", 1, 0, 'Y' },
+ { "caa-record", 1, 0 , LOPT_CAA },
{ "dns-rr", 1, 0, LOPT_RR },
{ "enable-dbus", 2, 0, '1' },
+ { "enable-ubus", 2, 0, LOPT_UBUS },
{ "bootp-dynamic", 2, 0, '3' },
{ "dhcp-mac", 1, 0, '4' },
{ "no-ping", 0, 0, '5' },
@@ -237,6 +246,7 @@ static const struct myoption opts[] =
{ "conf-dir", 1, 0, '7' },
{ "log-facility", 1, 0 ,'8' },
{ "leasefile-ro", 0, 0, '9' },
+ { "script-on-renewal", 0, 0, LOPT_SCRIPT_TIME},
{ "dns-forward-max", 1, 0, '0' },
{ "clear-on-reload", 0, 0, LOPT_RELOAD },
{ "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
@@ -248,9 +258,11 @@ static const struct myoption opts[] =
{ "tftp-max", 1, 0, LOPT_TFTP_MAX },
{ "tftp-mtu", 1, 0, LOPT_TFTP_MTU },
{ "tftp-lowercase", 0, 0, LOPT_TFTP_LC },
+ { "tftp-single-port", 0, 0, LOPT_SINGLE_PORT },
{ "ptr-record", 1, 0, LOPT_PTR },
{ "naptr-record", 1, 0, LOPT_NAPTR },
{ "bridge-interface", 1, 0 , LOPT_BRIDGE },
+ { "shared-network", 1, 0, LOPT_SHARED_NET },
{ "dhcp-option-force", 1, 0, LOPT_FORCE },
{ "tftp-no-blocksize", 0, 0, LOPT_NOBLOCK },
{ "log-dhcp", 0, 0, LOPT_LOG_OPTS },
@@ -268,7 +280,8 @@ static const struct myoption opts[] =
{ "stop-dns-rebind", 0, 0, LOPT_REBIND },
{ "rebind-domain-ok", 1, 0, LOPT_NO_REBIND },
{ "all-servers", 0, 0, LOPT_NOLAST },
- { "dhcp-match", 1, 0, LOPT_MATCH },
+ { "dhcp-match", 1, 0, LOPT_MATCH },
+ { "dhcp-name-match", 1, 0, LOPT_NAME_MATCH },
{ "dhcp-broadcast", 2, 0, LOPT_BROADCAST },
{ "neg-ttl", 1, 0, LOPT_NEGTTL },
{ "max-ttl", 1, 0, LOPT_MAXTTL },
@@ -310,12 +323,9 @@ static const struct myoption opts[] =
{ "dnssec", 0, 0, LOPT_SEC_VALID },
{ "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR },
{ "dnssec-debug", 0, 0, LOPT_DNSSEC_DEBUG },
- { "dnssec-check-unsigned", 0, 0, LOPT_DNSSEC_CHECK },
+ { "dnssec-check-unsigned", 2, 0, LOPT_DNSSEC_CHECK },
{ "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME },
{ "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP },
-#ifdef OPTION6_PREFIX_CLASS
- { "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
-#endif
{ "dhcp-relay", 1, 0, LOPT_RELAY },
{ "ra-param", 1, 0, LOPT_RA_PARAM },
{ "quiet-dhcp", 0, 0, LOPT_QUIET_DHCP },
@@ -325,6 +335,10 @@ static const struct myoption opts[] =
{ "script-arp", 0, 0, LOPT_SCRIPT_ARP },
{ "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },
{ "dhcp-reply-delay", 1, 0, LOPT_REPLY_DELAY },
+ { "dhcp-rapid-commit", 0, 0, LOPT_RAPID_COMMIT },
+ { "dumpfile", 1, 0, LOPT_DUMPFILE },
+ { "dumpmask", 1, 0, LOPT_DUMPMASK },
+ { "dhcp-ignore-clid", 0, 0, LOPT_IGNORE_CLID },
{ NULL, 0, 0, 0 }
};
@@ -414,10 +428,12 @@ static struct {
{ 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
{ 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
{ '1', ARG_ONE, "[=<busname>]", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
+ { LOPT_UBUS, ARG_ONE, "[=<busname>]", gettext_noop("Enable the UBus interface."), NULL },
{ '2', ARG_DUP, "<interface>", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
{ '3', ARG_DUP, "[=tag:<tag>]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
{ '4', ARG_DUP, "set:<tag>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
{ LOPT_BRIDGE, ARG_DUP, "<iface>,<alias>..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL },
+ { LOPT_SHARED_NET, ARG_DUP, "<iface>|<addr>,<addr>", gettext_noop("Specify extra networks sharing a broadcast domain for DHCP"), NULL},
{ '5', OPT_NO_PING, NULL, gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
{ '6', ARG_ONE, "<path>", gettext_noop("Shell script to run on DHCP lease creation and destruction."), NULL },
{ LOPT_LUASCRIPT, ARG_DUP, "path", gettext_noop("Lua script to run on DHCP lease creation and destruction."), NULL },
@@ -440,6 +456,7 @@ static struct {
{ LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
{ LOPT_TFTP_LC, OPT_TFTP_LC, NULL, gettext_noop("Convert TFTP filenames to lowercase"), NULL },
{ LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
+ { LOPT_SINGLE_PORT, OPT_SINGLE_PORT, NULL, gettext_noop("Use only one port for TFTP server."), NULL },
{ LOPT_LOG_OPTS, OPT_LOG_OPTS, NULL, gettext_noop("Extra logging for DHCP."), NULL },
{ LOPT_MAX_LOGS, ARG_ONE, "[=<integer>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL },
{ LOPT_REBIND, OPT_NO_REBIND, NULL, gettext_noop("Stop DNS rebinding. Filter private IP ranges when resolving."), NULL },
@@ -447,6 +464,7 @@ static struct {
{ LOPT_NO_REBIND, ARG_DUP, "/<domain>/", gettext_noop("Inhibit DNS-rebind protection on this domain."), NULL },
{ LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL },
{ LOPT_MATCH, ARG_DUP, "set:<tag>,<optspec>", gettext_noop("Set tag if client includes matching option in request."), NULL },
+ { LOPT_NAME_MATCH, ARG_DUP, "set:<tag>,<string>[*]", gettext_noop("Set tag if client provides given name."), NULL },
{ LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
{ LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
{ LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
@@ -464,11 +482,13 @@ static struct {
{ LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client identification to forwarded DNS queries."), NULL },
{ LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
+ { LOPT_IGNORE_CLID, OPT_IGNORE_CLID, NULL, gettext_noop("Ignore client identifier option sent by DHCP clients."), NULL },
{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
{ LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow DHCP clients to do their own DDNS updates."), NULL },
{ LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
{ LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
{ LOPT_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
+ { LOPT_CAA, ARG_DUP, "<name>,<flags>,<tag>,<value>", gettext_noop("Specify certification authority authorization record"), NULL },
{ LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
{ LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL },
{ LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>", gettext_noop("Export local names to global DNS"), NULL },
@@ -482,12 +502,9 @@ static struct {
{ LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
{ LOPT_TRUST_ANCHOR, ARG_DUP, "<domain>,[<class>],...", gettext_noop("Specify trust anchor key digest."), NULL },
{ LOPT_DNSSEC_DEBUG, OPT_DNSSEC_DEBUG, NULL, gettext_noop("Disable upstream checking for DNSSEC debugging."), NULL },
- { LOPT_DNSSEC_CHECK, OPT_DNSSEC_NO_SIGN, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
+ { LOPT_DNSSEC_CHECK, ARG_DUP, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
{ LOPT_DNSSEC_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL },
{ LOPT_DNSSEC_STAMP, ARG_ONE, "<path>", gettext_noop("Timestamp file to verify system clock for DNSSEC"), NULL },
-#ifdef OPTION6_PREFIX_CLASS
- { LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
-#endif
{ LOPT_RA_PARAM, ARG_DUP, "<iface>,[mtu:<value>|<interface>|off,][<prio>,]<intval>[,<lifetime>]", gettext_noop("Set MTU, priority, resend-interval and router-lifetime"), NULL },
{ LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
{ LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
@@ -497,6 +514,10 @@ static struct {
{ LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses 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 },
+ { LOPT_DUMPFILE, ARG_ONE, "<path>", gettext_noop("Path to debug packet dump file"), NULL },
+ { LOPT_DUMPMASK, ARG_ONE, "<hex>", gettext_noop("Mask which packets to dump"), NULL },
+ { LOPT_SCRIPT_TIME, OPT_LEASE_RENEW, NULL, gettext_noop("Call dhcp-script when lease expiry changes."), NULL },
{ 0, 0, NULL, NULL, NULL }
};
@@ -559,14 +580,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);
@@ -741,15 +763,15 @@ 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)
{
if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
addr->sa.sa_family = AF_INET;
-#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
addr->sa.sa_family = AF_INET6;
-#endif
else
return _("bad address");
@@ -761,10 +783,8 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
int source_port = 0, serv_port = NAMESERVER_PORT;
char *portno, *source;
char *interface_opt = NULL;
-#ifdef HAVE_IPV6
int scope_index = 0;
char *scope_id;
-#endif
if (!arg || strlen(arg) == 0)
{
@@ -782,9 +802,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
!atoi_check16(portno, &serv_port))
return _("bad port");
-#ifdef HAVE_IPV6
scope_id = split_chr(arg, '%');
-#endif
if (source) {
interface_opt = split_chr(source, '@');
@@ -792,7 +810,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
if (interface_opt)
{
#if defined(SO_BINDTODEVICE)
- strncpy(interface, interface_opt, IF_NAMESIZE - 1);
+ safe_strncpy(interface, interface_opt, IF_NAMESIZE);
#else
return _("interface binding not supported");
#endif
@@ -821,14 +839,13 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
return _("interface can only be specified once");
source_addr->in.sin_addr.s_addr = INADDR_ANY;
- strncpy(interface, source, IF_NAMESIZE - 1);
+ safe_strncpy(interface, source, IF_NAMESIZE);
#else
return _("interface binding not supported");
#endif
}
}
}
-#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
{
if (scope_id && (scope_index = if_nametoindex(scope_id)) == 0)
@@ -856,14 +873,13 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
return _("interface can only be specified once");
source_addr->in6.sin6_addr = in6addr_any;
- strncpy(interface, source, IF_NAMESIZE - 1);
+ safe_strncpy(interface, source, IF_NAMESIZE);
#else
return _("interface binding not supported");
#endif
}
}
}
-#endif
else
return _("bad address");
@@ -894,6 +910,8 @@ static struct server *add_rev4(struct in_addr addr, int msize)
p += sprintf(p, "%d.", (a >> 24) & 0xff);
break;
default:
+ free(serv->domain);
+ free(serv);
return NULL;
}
@@ -948,6 +966,116 @@ 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);
+ dhcp_netid_free(config->filter);
+
+ if (config->flags & CONFIG_CLID)
+ free(config->clid);
+
+#ifdef HAVE_DHCP6
+ if (config->flags & CONFIG_ADDR6)
+ {
+ struct addrlist *addr, *tmp;
+
+ for (addr = config->addr6; addr; addr = tmp)
+ {
+ tmp = addr->next;
+ free(addr);
+ }
+ }
+#endif
+
+ free(config);
+ }
+}
+
+static void dhcp_context_free(struct dhcp_context *ctx)
+{
+ if (ctx)
+ {
+ dhcp_netid_free(ctx->filter);
+ free(ctx->netid.net);
+#ifdef HAVE_DHCP6
+ free(ctx->template_interface);
+#endif
+ 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)
{
@@ -955,7 +1083,6 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
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;
@@ -1042,14 +1169,9 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
}
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;
@@ -1059,7 +1181,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
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))
@@ -1073,13 +1195,13 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
/* option may be missing with rfc3925 match */
if (!option_ok)
- ret_err(_("bad dhcp-option"));
+ goto_err(_("bad dhcp-option"));
if (comma)
{
/* characterise the value */
char c;
- int found_dig = 0;
+ int found_dig = 0, found_colon = 0;
is_addr = is_addr6 = is_hex = is_dec = is_string = 1;
addrs = digs = 1;
dots = 0;
@@ -1093,6 +1215,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
{
digs++;
is_dec = is_addr = 0;
+ found_colon = 1;
}
else if (c == '/')
{
@@ -1102,7 +1225,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
}
else if (c == '.')
{
- is_addr6 = is_dec = is_hex = 0;
+ is_dec = is_hex = 0;
dots++;
}
else if (c == '-')
@@ -1134,6 +1257,15 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
if (!found_dig)
is_dec = is_addr = 0;
+
+ if (!found_colon)
+ is_addr6 = 0;
+
+#ifdef HAVE_DHCP6
+ /* NTP server option takes hex, addresses or FQDN */
+ if (is6 && new->opt == OPTION6_NTP_SERVER && !is_hex)
+ opt_len |= is_addr6 ? OT_ADDR_LIST : OT_RFC1035_NAME;
+#endif
/* We know that some options take addresses */
if (opt_len & OT_ADDR_LIST)
@@ -1141,10 +1273,10 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
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))
@@ -1237,7 +1369,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
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);
@@ -1282,8 +1414,8 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
op += IN6ADDRSZ;
continue;
}
-
- ret_err(_("bad IPv6 address"));
+
+ goto_err(_("bad IPv6 address"));
}
new->len = op - new->val;
}
@@ -1310,7 +1442,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
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;
}
@@ -1357,7 +1489,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
}
/* RFC 3361, enc byte is zero for names */
- if (new->opt == OPTION_SIP_SERVER)
+ if (new->opt == OPTION_SIP_SERVER && m)
m[0] = 0;
new->len = (int) len + header_size;
new->val = m;
@@ -1395,8 +1527,9 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
}
else if (comma && (opt_len & OT_RFC1035_NAME))
{
- unsigned char *p = NULL, *newp, *end;
+ unsigned char *p = NULL, *q, *newp, *end;
int len = 0;
+ int header_size = (is6 && new->opt == OPTION6_NTP_SERVER) ? 4 : 0;
arg = comma;
comma = split(arg);
@@ -1404,9 +1537,9 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
{
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);
+ newp = opt_malloc(len + header_size + strlen(dom) + 2);
if (p)
{
@@ -1415,8 +1548,14 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
}
p = newp;
- end = do_rfc1035_name(p + len, dom, NULL);
+ q = p + len;
+ end = do_rfc1035_name(q + header_size, dom, NULL);
*end++ = 0;
+ if (is6 && new->opt == OPTION6_NTP_SERVER)
+ {
+ PUTSHORT(NTP_SUBOPTION_SRV_FQDN, q);
+ PUTSHORT(end - q - 2, q);
+ }
len = end - p;
free(dom);
@@ -1442,14 +1581,14 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
((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)
{
@@ -1474,24 +1613,31 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
}
return 1;
+on_error:
+ dhcp_opt_free(new);
+ return 0;
}
#endif
void set_option_bool(unsigned int opt)
{
- if (opt < 32)
- daemon->options |= 1u << opt;
- else
- daemon->options2 |= 1u << (opt - 32);
+ option_var(opt) |= option_val(opt);
}
void reset_option_bool(unsigned int opt)
{
- if (opt < 32)
- daemon->options &= ~(1u << opt);
- else
- daemon->options2 &= ~(1u << (opt - 32));
+ 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)
@@ -1552,9 +1698,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
struct dirent *ent;
char *directory, *path;
struct list {
- char *suffix;
+ char *name;
struct list *next;
- } *ignore_suffix = NULL, *match_suffix = NULL, *li;
+ } *ignore_suffix = NULL, *match_suffix = NULL, *files = NULL, *li;
comma = split(arg);
if (!(directory = opt_string_alloc(arg)))
@@ -1576,7 +1722,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
li->next = match_suffix;
match_suffix = li;
/* Have to copy: buffer is overwritten */
- li->suffix = opt_string_alloc(arg+1);
+ li->name = opt_string_alloc(arg+1);
}
}
else
@@ -1584,7 +1730,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
li->next = ignore_suffix;
ignore_suffix = li;
/* Have to copy: buffer is overwritten */
- li->suffix = opt_string_alloc(arg);
+ li->name = opt_string_alloc(arg);
}
}
}
@@ -1609,9 +1755,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
for (li = match_suffix; li; li = li->next)
{
/* check for required suffices */
- size_t ls = strlen(li->suffix);
+ size_t ls = strlen(li->name);
if (len > ls &&
- strcmp(li->suffix, &ent->d_name[len - ls]) == 0)
+ strcmp(li->name, &ent->d_name[len - ls]) == 0)
break;
}
if (!li)
@@ -1621,9 +1767,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
for (li = ignore_suffix; li; li = li->next)
{
/* check for proscribed suffices */
- size_t ls = strlen(li->suffix);
+ size_t ls = strlen(li->name);
if (len > ls &&
- strcmp(li->suffix, &ent->d_name[len - ls]) == 0)
+ strcmp(li->name, &ent->d_name[len - ls]) == 0)
break;
}
if (li)
@@ -1640,25 +1786,44 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
/* only reg files allowed. */
if (S_ISREG(buf.st_mode))
- one_file(path, 0);
-
- free(path);
+ {
+ /* sort files into order. */
+ struct list **up, *new = opt_malloc(sizeof(struct list));
+ new->name = path;
+
+ for (up = &files, li = files; li; up = &li->next, li = li->next)
+ if (strcmp(li->name, path) >=0)
+ break;
+
+ new->next = li;
+ *up = new;
+ }
+
}
-
+
+ for (li = files; li; li = li->next)
+ one_file(li->name, 0);
+
closedir(dir_stream);
free(directory);
for(; ignore_suffix; ignore_suffix = li)
{
li = ignore_suffix->next;
- free(ignore_suffix->suffix);
+ free(ignore_suffix->name);
free(ignore_suffix);
}
for(; match_suffix; match_suffix = li)
{
li = match_suffix->next;
- free(match_suffix->suffix);
+ free(match_suffix->name);
free(match_suffix);
}
+ for(; files; files = li)
+ {
+ li = files->next;
+ free(files->name);
+ free(files);
+ }
break;
}
@@ -1675,13 +1840,13 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
/* 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;
@@ -1693,15 +1858,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
/* 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;
@@ -1716,7 +1881,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
else
daemon->dbus_name = DNSMASQ_SERVICE;
break;
-
+
+ case LOPT_UBUS: /* --enable-ubus */
+ set_option_bool(OPT_UBUS);
+ if (arg)
+ daemon->ubus_name = opt_string_alloc(arg);
+ else
+ daemon->ubus_name = DNSMASQ_UBUS_NAME;
+ break;
+
case '8': /* --log-facility */
/* may be a filename */
if (strchr(arg, '/') || strcmp (arg, "-") == 0)
@@ -1737,7 +1910,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
#endif
}
break;
-
+
case 'x': /* --pid-file */
daemon->runfile = opt_string_alloc(arg);
break;
@@ -1808,6 +1981,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
ret_err(_("bad MX target"));
break;
+ case LOPT_DUMPFILE: /* --dumpfile */
+ daemon->dump_file = opt_string_alloc(arg);
+ break;
+
+ case LOPT_DUMPMASK: /* --dumpmask */
+ daemon->dump_mask = strtol(arg, NULL, 0);
+ break;
+
#ifdef HAVE_DHCP
case 'l': /* --dhcp-leasefile */
daemon->lease_file = opt_string_alloc(arg);
@@ -1816,9 +1997,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
/* Sorry about the gross pre-processor abuse */
case '6': /* --dhcp-script */
case LOPT_LUASCRIPT: /* --dhcp-luascript */
-# if defined(NO_FORK)
- ret_err(_("cannot run scripts under uClinux"));
-# elif !defined(HAVE_SCRIPT)
+# if !defined(HAVE_SCRIPT)
ret_err(_("recompile with HAVE_SCRIPT defined to enable lease-change scripts"));
# else
if (option == LOPT_LUASCRIPT)
@@ -1875,47 +2054,42 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
break;
}
-
-#ifdef HAVE_AUTH
case LOPT_AUTHSERV: /* --auth-server */
- if (!(comma = split(arg)))
- ret_err(gen_err);
+ comma = split(arg);
daemon->authserver = opt_string_alloc(arg);
- arg = comma;
- do {
- struct iname *new = opt_malloc(sizeof(struct iname));
- comma = split(arg);
- new->name = NULL;
- unhide_metas(arg);
- if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0)
- new->addr.sa.sa_family = AF_INET;
-#ifdef HAVE_IPV6
- else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
- new->addr.sa.sa_family = AF_INET6;
-#endif
- else
- {
- char *fam = split_chr(arg, '/');
- new->name = opt_string_alloc(arg);
- new->addr.sa.sa_family = 0;
- if (fam)
- {
- if (strcmp(fam, "4") == 0)
- new->addr.sa.sa_family = AF_INET;
-#ifdef HAVE_IPV6
- else if (strcmp(fam, "6") == 0)
- new->addr.sa.sa_family = AF_INET6;
-#endif
- else
- ret_err(gen_err);
- }
- }
- new->next = daemon->authinterface;
- daemon->authinterface = new;
-
- arg = comma;
- } while (arg);
+
+ while ((arg = comma))
+ {
+ struct iname *new = opt_malloc(sizeof(struct iname));
+ comma = split(arg);
+ new->name = NULL;
+ unhide_metas(arg);
+ if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0)
+ new->addr.sa.sa_family = AF_INET;
+ else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
+ new->addr.sa.sa_family = AF_INET6;
+ else
+ {
+ char *fam = split_chr(arg, '/');
+ new->name = opt_string_alloc(arg);
+ new->addr.sa.sa_family = 0;
+ if (fam)
+ {
+ if (strcmp(fam, "4") == 0)
+ new->addr.sa.sa_family = AF_INET;
+ else if (strcmp(fam, "6") == 0)
+ new->addr.sa.sa_family = AF_INET6;
+ else
+ {
+ free(new->name);
+ ret_err_free(gen_err, new);
+ }
+ }
+ }
+ new->next = daemon->authinterface;
+ daemon->authinterface = new;
+ };
break;
@@ -1954,7 +2128,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
int is_exclude = 0;
char *prefix;
struct addrlist *subnet = NULL;
- struct all_addr addr;
+ union all_addr addr;
comma = split(arg);
prefix = split_chr(arg, '/');
@@ -1968,20 +2142,18 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
arg = arg+8;
}
- if (inet_pton(AF_INET, arg, &addr.addr.addr4))
+ if (inet_pton(AF_INET, arg, &addr.addr4))
{
subnet = opt_malloc(sizeof(struct addrlist));
subnet->prefixlen = (prefixlen == 0) ? 24 : prefixlen;
subnet->flags = ADDRLIST_LITERAL;
}
-#ifdef HAVE_IPV6
- else if (inet_pton(AF_INET6, arg, &addr.addr.addr6))
+ else if (inet_pton(AF_INET6, arg, &addr.addr6))
{
subnet = opt_malloc(sizeof(struct addrlist));
subnet->prefixlen = (prefixlen == 0) ? 64 : prefixlen;
subnet->flags = ADDRLIST_LITERAL | ADDRLIST_IPV6;
}
-#endif
else
{
struct auth_name_list *name = opt_malloc(sizeof(struct auth_name_list));
@@ -1993,10 +2165,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{
if (prefixlen == 4)
name->flags &= ~AUTH6;
-#ifdef HAVE_IPV6
else if (prefixlen == 6)
name->flags &= ~AUTH4;
-#endif
else
ret_err(gen_err);
}
@@ -2051,7 +2221,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
break;
-#endif
case 's': /* --domain */
case LOPT_SYNTH: /* --synth-domain */
@@ -2080,7 +2249,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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;
@@ -2093,18 +2262,18 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{
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;
@@ -2118,7 +2287,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
}
}
-#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, comma, &new->start6))
{
u64 mask = (1LLU << (128 - msize)) - 1LLU;
@@ -2134,17 +2302,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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
@@ -2162,9 +2330,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
}
}
-#endif
else
- ret_err(gen_err);
+ ret_err_free(gen_err, new);
}
else
{
@@ -2178,26 +2345,24 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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);
}
-#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, comma, &new->start6))
{
new->is6 = 1;
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);
}
-#endif
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);
}
}
@@ -2212,7 +2377,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
char *star;
new->next = daemon->synth_domains;
daemon->synth_domains = new;
- if ((star = strrchr(new->prefix, '*')) && *(star+1) == 0)
+ if (new->prefix &&
+ (star = strrchr(new->prefix, '*'))
+ && *(star+1) == 0)
{
*star = 0;
new->indexed = 1;
@@ -2346,7 +2513,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->addr.in.sin_len = sizeof(new->addr.in);
#endif
}
-#ifdef HAVE_IPV6
else if (arg && inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
{
new->addr.sa.sa_family = AF_INET6;
@@ -2357,9 +2523,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->addr.in6.sin6_len = sizeof(new->addr.in6);
#endif
}
-#endif
else
- ret_err(gen_err);
+ ret_err_free(gen_err, new);
new->used = 0;
if (option == 'a')
@@ -2400,7 +2565,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (strcmp(arg, "#") == 0)
domain = "";
else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
- option = '?';
+ ret_err(gen_err);
serv = opt_malloc(sizeof(struct server));
memset(serv, 0, sizeof(struct server));
serv->next = newlist;
@@ -2430,7 +2595,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{
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;
@@ -2442,22 +2610,21 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
else if (strcmp(arg, "#") == 0)
- {
- newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
- if (newlist->flags & SERV_LITERAL_ADDRESS)
- ret_err(gen_err);
- }
+ newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
else
{
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;
while (serv->next)
{
- serv->next->flags = serv->flags;
+ serv->next->flags |= serv->flags & ~(SERV_HAS_DOMAIN | SERV_FOR_NODOTS);
serv->next->addr = serv->addr;
serv->next->source_addr = serv->source_addr;
strcpy(serv->next->interface, serv->interface);
@@ -2474,24 +2641,25 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
int size;
struct server *serv;
struct in_addr addr4;
-#ifdef HAVE_IPV6
struct in6_addr addr6;
-#endif
unhide_metas(arg);
- if (!arg || !(comma=split(arg)) || !(string = split_chr(arg, '/')) || !atoi_check(string, &size))
+ if (!arg)
ret_err(gen_err);
+
+ comma=split(arg);
+ if (!(string = split_chr(arg, '/')) || !atoi_check(string, &size))
+ ret_err(gen_err);
+
if (inet_pton(AF_INET, arg, &addr4))
{
serv = add_rev4(addr4, size);
if (!serv)
ret_err(_("bad prefix"));
}
-#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, arg, &addr6))
serv = add_rev6(&addr6, size);
-#endif
else
ret_err(gen_err);
@@ -2532,7 +2700,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (strcmp(arg, "#") == 0 || !*arg)
domain = "";
else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg)))
- option = '?';
+ ret_err(gen_err);
ipsets->next = opt_malloc(sizeof(struct ipsets));
ipsets = ipsets->next;
memset(ipsets, 0, sizeof(struct ipsets));
@@ -2547,13 +2715,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
memset(ipsets, 0, sizeof(struct ipsets));
ipsets->domain = "";
}
+
if (!arg || !*arg)
- {
- option = '?';
- break;
- }
- size = 2;
- for (end = arg; *end; ++end)
+ ret_err(gen_err);
+
+ for (size = 2, end = arg; *end; ++end)
if (*end == ',')
++size;
@@ -2586,8 +2752,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (size < 0)
size = 0;
- else if (size > 10000)
- size = 10000;
+
+ /* Note that for very large cache sizes, the malloc()
+ will overflow. For the size of the cache record
+ at the time this was noted, the value of "very large"
+ was 46684428. Limit to an order of magnitude less than
+ that to be safe from changes to the cache record. */
+ if (size > 5000000)
+ size = 5000000;
daemon->cachesize = size;
}
@@ -2774,6 +2946,44 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
#ifdef HAVE_DHCP
+ case LOPT_SHARED_NET: /* --shared-network */
+ {
+ struct shared_network *new = opt_malloc(sizeof(struct shared_network));
+
+#ifdef HAVE_DHCP6
+ new->shared_addr.s_addr = 0;
+#endif
+ new->if_index = 0;
+
+ if (!(comma = split(arg)))
+ {
+ snerr:
+ free(new);
+ ret_err(_("bad shared-network"));
+ }
+
+ if (inet_pton(AF_INET, comma, &new->shared_addr))
+ {
+ if (!inet_pton(AF_INET, arg, &new->match_addr) &&
+ !(new->if_index = if_nametoindex(arg)))
+ goto snerr;
+ }
+#ifdef HAVE_DHCP6
+ else if (inet_pton(AF_INET6, comma, &new->shared_addr6))
+ {
+ if (!inet_pton(AF_INET6, arg, &new->match_addr6) &&
+ !(new->if_index = if_nametoindex(arg)))
+ goto snerr;
+ }
+#endif
+ else
+ goto snerr;
+
+ new->next = daemon->shared_networks;
+ daemon->shared_networks = new;
+ break;
+ }
+
case 'F': /* --dhcp-range */
{
int k, leasepos = 2;
@@ -2781,13 +2991,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
memset (new, 0, sizeof(*new));
- new->lease_time = DEFLEASE;
-
- if (!arg)
- {
- option = '?';
- break;
- }
while(1)
{
@@ -2801,21 +3004,19 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{
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;
}
@@ -2831,11 +3032,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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))
{
new->next = daemon->dhcp;
+ new->lease_time = DEFLEASE;
daemon->dhcp = new;
new->end = new->start;
if (strcmp(a[1], "static") == 0)
@@ -2843,7 +3048,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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))
{
@@ -2858,7 +3066,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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], '.') &&
@@ -2872,9 +3083,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
#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;
+ new->lease_time = DEFLEASE6;
new->next = daemon->dhcp6;
daemon->dhcp6 = new;
@@ -2917,19 +3131,24 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
}
- 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))
@@ -2940,7 +3159,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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))
@@ -2952,15 +3174,24 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
#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;
+ {
+ new->lease_time = 0xffffffff;
+ new->flags |= CONTEXT_SETLEASE;
+ }
else if (strcmp(a[leasepos], "deprecated") == 0)
new->flags |= CONTEXT_DEPRECATE;
else
@@ -2996,9 +3227,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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;
+ new->flags |= CONTEXT_SETLEASE;
/* Leases of a minute or less confuse
some clients, notably Apple's */
if (new->lease_time < 120)
@@ -3006,14 +3238,13 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
}
}
+
break;
}
case LOPT_BANK:
case 'G': /* --dhcp-host */
{
- int j, k = 0;
- char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
struct dhcp_config *new;
struct in_addr in;
@@ -3023,185 +3254,223 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
new->hwaddr = NULL;
new->netid = NULL;
-
- if ((a[0] = arg))
- for (k = 1; k < 7; k++)
- if (!(a[k] = split(a[k-1])))
- break;
-
- for (j = 0; j < k; j++)
- if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
- {
- char *arg = a[j];
-
- if ((arg[0] == 'i' || arg[0] == 'I') &&
- (arg[1] == 'd' || arg[1] == 'D') &&
- arg[2] == ':')
- {
- if (arg[3] == '*')
- new->flags |= CONFIG_NOCLID;
- else
- {
- int len;
- arg += 3; /* dump id: */
- if (strchr(arg, ':'))
- len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
- else
- {
- unhide_metas(arg);
- len = (int) strlen(arg);
- }
-
- if (len == -1)
- ret_err(_("bad hex constant"));
- else if ((new->clid = opt_malloc(len)))
- {
- new->flags |= CONFIG_CLID;
- new->clid_len = len;
- memcpy(new->clid, arg, len);
- }
- }
- }
- /* 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);
- }
- else if (strstr(arg, "tag:") == arg)
- ret_err(_("cannot match tags in --dhcp-host"));
+ new->filter = NULL;
+ new->clid = NULL;
#ifdef HAVE_DHCP6
- else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
- {
- arg[strlen(arg)-1] = 0;
- arg++;
-
- if (!inet_pton(AF_INET6, arg, &new->addr6))
- ret_err(_("bad IPv6 address"));
+ new->addr6 = NULL;
+#endif
- for (i= 0; i < 8; i++)
- if (new->addr6.s6_addr[i] != 0)
- break;
+ while (arg)
+ {
+ comma = split(arg);
+ if (strchr(arg, ':')) /* ethernet address, netid or binary CLID */
+ {
+ if ((arg[0] == 'i' || arg[0] == 'I') &&
+ (arg[1] == 'd' || arg[1] == 'D') &&
+ arg[2] == ':')
+ {
+ if (arg[3] == '*')
+ new->flags |= CONFIG_NOCLID;
+ else
+ {
+ int len;
+ arg += 3; /* dump id: */
+ if (strchr(arg, ':'))
+ len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
+ else
+ {
+ unhide_metas(arg);
+ len = (int) strlen(arg);
+ }
+
+ if (len == -1)
+ {
+ dhcp_config_free(new);
+ ret_err(_("bad hex constant"));
+ }
+ else if ((new->clid = opt_malloc(len)))
+ {
+ new->flags |= CONFIG_CLID;
+ new->clid_len = len;
+ memcpy(new->clid, arg, len);
+ }
+ }
+ }
+ /* dhcp-host has strange backwards-compat needs. */
+ else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg)
+ {
+ struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
+ newlist->next = new->netid;
+ new->netid = newlist;
+ newlist->list = dhcp_netid_create(arg+4, NULL);
+ }
+ else if (strstr(arg, "tag:") == arg)
+ new->filter = dhcp_netid_create(arg+4, new->filter);
+
+#ifdef HAVE_DHCP6
+ else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
+ {
+ char *pref;
+ struct in6_addr in6;
+ struct addrlist *new_addr;
+
+ arg[strlen(arg)-1] = 0;
+ arg++;
+ pref = split_chr(arg, '/');
+
+ if (!inet_pton(AF_INET6, arg, &in6))
+ {
+ dhcp_config_free(new);
+ ret_err(_("bad IPv6 address"));
+ }
- /* set WILDCARD if network part all zeros */
- if (i == 8)
- new->flags |= CONFIG_WILDCARD;
+ new_addr = opt_malloc(sizeof(struct addrlist));
+ new_addr->next = new->addr6;
+ new_addr->flags = 0;
+ new_addr->addr.addr6 = in6;
+ new->addr6 = new_addr;
+
+ if (pref)
+ {
+ u64 addrpart = addr6part(&in6);
+
+ if (!atoi_check(pref, &new_addr->prefixlen) ||
+ new_addr->prefixlen > 128 ||
+ ((((u64)1<<(128-new_addr->prefixlen))-1) & addrpart) != 0)
+ {
+ dhcp_config_free(new);
+ ret_err(_("bad IPv6 prefix"));
+ }
+
+ new_addr->flags |= ADDRLIST_PREFIX;
+ }
- new->flags |= CONFIG_ADDR6;
- }
+ for (i= 0; i < 8; i++)
+ if (in6.s6_addr[i] != 0)
+ break;
+
+ /* set WILDCARD if network part all zeros */
+ if (i == 8)
+ new_addr->flags |= ADDRLIST_WILDCARD;
+
+ new->flags |= CONFIG_ADDR6;
+ }
#endif
- else
- {
- 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"));
- else
- {
-
- newhw->next = new->hwaddr;
- new->hwaddr = newhw;
- }
- }
- }
- else if (strchr(a[j], '.') && (inet_pton(AF_INET, a[j], &in) > 0))
- {
- struct dhcp_config *configs;
-
- new->addr = in;
- new->flags |= CONFIG_ADDR;
-
- /* If the same IP appears in more than one host config, then DISCOVER
- for one of the hosts will get the address, but REQUEST will be NAKed,
- since the address is reserved by the other one -> protocol loop. */
- for (configs = daemon->dhcp_conf; configs; configs = configs->next)
- if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr)
+ else
{
- sprintf(errstr, _("duplicate dhcp-host IP address %s"), inet_ntoa(in));
- return 0;
- }
- }
- else
- {
- char *cp, *lastp = NULL, last = 0;
- int fac = 1, isdig = 0;
-
- if (strlen(a[j]) > 1)
- {
- lastp = a[j] + strlen(a[j]) - 1;
- last = *lastp;
- switch (last)
+ struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
+ if ((newhw->hwaddr_len = parse_hex(arg, newhw->hwaddr, DHCP_CHADDR_MAX,
+ &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
+ {
+ free(newhw);
+ dhcp_config_free(new);
+ ret_err(_("bad hex constant"));
+ }
+ else
+ {
+ newhw->next = new->hwaddr;
+ new->hwaddr = newhw;
+ }
+ }
+ }
+ else if (strchr(arg, '.') && (inet_pton(AF_INET, arg, &in) > 0))
+ {
+ struct dhcp_config *configs;
+
+ new->addr = in;
+ new->flags |= CONFIG_ADDR;
+
+ /* If the same IP appears in more than one host config, then DISCOVER
+ for one of the hosts will get the address, but REQUEST will be NAKed,
+ since the address is reserved by the other one -> protocol loop. */
+ for (configs = daemon->dhcp_conf; configs; configs = configs->next)
+ if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr)
{
- case 'w':
- case 'W':
- fac *= 7;
- /* fall through */
- case 'd':
- case 'D':
- fac *= 24;
- /* fall through */
- case 'h':
- case 'H':
- fac *= 60;
- /* fall through */
- case 'm':
- case 'M':
- fac *= 60;
- /* fall through */
- case 's':
- case 'S':
- *lastp = 0;
- }
- }
-
- for (cp = a[j]; *cp; cp++)
- if (isdigit((unsigned char)*cp))
- isdig = 1;
- else if (*cp != ' ')
- break;
+ sprintf(errstr, _("duplicate dhcp-host IP address %s"), inet_ntoa(in));
+ return 0;
+ }
+ }
+ else
+ {
+ char *cp, *lastp = NULL, last = 0;
+ int fac = 1, isdig = 0;
+
+ if (strlen(arg) > 1)
+ {
+ lastp = arg + strlen(arg) - 1;
+ last = *lastp;
+ switch (last)
+ {
+ case 'w':
+ case 'W':
+ fac *= 7;
+ /* fall through */
+ case 'd':
+ case 'D':
+ fac *= 24;
+ /* fall through */
+ case 'h':
+ case 'H':
+ fac *= 60;
+ /* fall through */
+ case 'm':
+ case 'M':
+ fac *= 60;
+ /* fall through */
+ case 's':
+ case 'S':
+ *lastp = 0;
+ }
+ }
+
+ for (cp = arg; *cp; cp++)
+ if (isdigit((unsigned char)*cp))
+ isdig = 1;
+ else if (*cp != ' ')
+ break;
+
+ if (*cp)
+ {
+ if (lastp)
+ *lastp = last;
+ if (strcmp(arg, "infinite") == 0)
+ {
+ new->lease_time = 0xffffffff;
+ new->flags |= CONFIG_TIME;
+ }
+ else if (strcmp(arg, "ignore") == 0)
+ new->flags |= CONFIG_DISABLE;
+ else
+ {
+ if (!(new->hostname = canonicalise_opt(arg)) ||
+ !legal_hostname(new->hostname))
+ {
+ dhcp_config_free(new);
+ ret_err(_("bad DHCP host name"));
+ }
+
+ new->flags |= CONFIG_NAME;
+ new->domain = strip_hostname(new->hostname);
+ }
+ }
+ else if (isdig)
+ {
+ new->lease_time = atoi(arg) * fac;
+ /* Leases of a minute or less confuse
+ some clients, notably Apple's */
+ if (new->lease_time < 120)
+ new->lease_time = 120;
+ new->flags |= CONFIG_TIME;
+ }
+ }
+
+ arg = comma;
+ }
- if (*cp)
- {
- if (lastp)
- *lastp = last;
- if (strcmp(a[j], "infinite") == 0)
- {
- new->lease_time = 0xffffffff;
- new->flags |= CONFIG_TIME;
- }
- else if (strcmp(a[j], "ignore") == 0)
- new->flags |= CONFIG_DISABLE;
- else
- {
- if (!(new->hostname = canonicalise_opt(a[j])) ||
- !legal_hostname(new->hostname))
- ret_err(_("bad DHCP host name"));
-
- new->flags |= CONFIG_NAME;
- new->domain = strip_hostname(new->hostname);
- }
- }
- else if (isdig)
- {
- new->lease_time = atoi(a[j]) * fac;
- /* Leases of a minute or less confuse
- some clients, notably Apple's */
- if (new->lease_time < 120)
- new->lease_time = 120;
- new->flags |= CONFIG_TIME;
- }
- }
-
daemon->dhcp_conf = new;
break;
}
-
+
case LOPT_TAG_IF: /* --tag-if */
{
struct tag_if *new = opt_malloc(sizeof(struct tag_if));
@@ -3234,10 +3503,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
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)
{
@@ -3254,7 +3520,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
else
{
new->set = NULL;
- free(newtag);
+ dhcp_netid_free(newtag);
break;
}
}
@@ -3263,7 +3529,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
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;
}
@@ -3277,22 +3547,41 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
option == LOPT_FORCE ? DHOPT_FORCE :
(option == LOPT_MATCH ? DHOPT_MATCH :
(option == LOPT_OPTS ? DHOPT_BANK : 0)));
-
- case 'M': /* --dhcp-boot */
+
+ case LOPT_NAME_MATCH: /* --dhcp-name-match */
{
- struct dhcp_netid *id = NULL;
- while (is_tag_prefix(arg))
+ struct dhcp_match_name *new = opt_malloc(sizeof(struct dhcp_match_name));
+ struct dhcp_netid *id = opt_malloc(sizeof(struct dhcp_netid));
+ ssize_t len;
+
+ if (!(comma = split(arg)) || (len = strlen(comma)) == 0)
+ ret_err(gen_err);
+
+ new->wildcard = 0;
+ new->netid = id;
+ id->net = opt_string_alloc(set_prefix(arg));
+
+ if (comma[len-1] == '*')
{
- 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;
- };
+ comma[len-1] = 0;
+ new->wildcard = 1;
+ }
+ new->name = opt_string_alloc(comma);
+
+ new->next = daemon->dhcp_name_match;
+ daemon->dhcp_name_match = new;
+
+ break;
+ }
+
+ case 'M': /* --dhcp-boot */
+ {
+ struct dhcp_netid *id = dhcp_tags(&arg);
if (!arg)
- ret_err(gen_err);
+ {
+ ret_err(gen_err);
+ }
else
{
char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL;
@@ -3338,19 +3627,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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);
+ {
+ ret_err(gen_err);
+ }
else
{
struct delay_config *new;
@@ -3375,19 +3657,13 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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);
+ {
+ dhcp_opt_free(new);
+ ret_err(gen_err);
+ }
else
{
comma = split(arg);
@@ -3423,17 +3699,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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++)
@@ -3510,7 +3777,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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;
@@ -3520,24 +3790,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
break;
-#ifdef OPTION6_PREFIX_CLASS
- case LOPT_PREF_CLSS: /* --dhcp-prefix-class */
- {
- struct prefix_class *new = opt_malloc(sizeof(struct prefix_class));
-
- if (!(comma = split(arg)) ||
- !atoi_check16(comma, &new->class))
- ret_err(gen_err);
-
- new->tag.net = opt_string_alloc(set_prefix(arg));
- new->next = daemon->prefix_classes;
- daemon->prefix_classes = new;
-
- break;
- }
-#endif
-
-
case 'U': /* --dhcp-vendorclass */
case 'j': /* --dhcp-userclass */
case LOPT_CIRCUIT: /* --dhcp-circuitid */
@@ -3549,7 +3801,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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,
@@ -3559,7 +3811,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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);
}
@@ -3661,14 +3916,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
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;
}
@@ -3682,7 +3931,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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;
@@ -3708,7 +3957,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
#endif
else
- ret_err(_("Bad dhcp-relay"));
+ {
+ free(new->interface);
+ ret_err_free(_("Bad dhcp-relay"), new);
+ }
break;
}
@@ -3748,8 +4000,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
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;
@@ -3790,17 +4045,15 @@ err:
if ((k < 2) ||
(!(inet_pton(AF_INET, a[0], &new->in) > 0)) ||
- (!(inet_pton(AF_INET, a[1], &new->out) > 0)))
- option = '?';
-
- if (k == 3 && !inet_pton(AF_INET, a[2], &new->mask))
- option = '?';
+ (!(inet_pton(AF_INET, a[1], &new->out) > 0)) ||
+ (k == 3 && !inet_pton(AF_INET, a[2], &new->mask)))
+ ret_err(_("missing address in alias"));
if (dash &&
(!(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;
}
@@ -3830,12 +4083,10 @@ err:
{
if (strcmp(arg, "4") == 0)
new->family = AF_INET;
-#ifdef HAVE_IPV6
else if (strcmp(arg, "6") == 0)
new->family = AF_INET6;
-#endif
else
- ret_err(gen_err);
+ ret_err_free(gen_err, new);
}
new->intr = opt_string_alloc(comma);
break;
@@ -3867,11 +4118,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;
@@ -3894,7 +4153,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));
@@ -3912,7 +4175,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++)
@@ -3925,7 +4188,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));
@@ -3947,26 +4214,30 @@ 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)
{
- new->txt=opt_malloc(len);
+ new->txt = opt_malloc(len);
new->len = len;
memcpy(new->txt, data, len);
}
@@ -3974,6 +4245,37 @@ err:
break;
}
+ case LOPT_CAA: /* --caa-record */
+ {
+ struct txt_record *new;
+ char *tag, *value;
+ int flags;
+
+ comma = split(arg);
+ tag = split(comma);
+ value = split(tag);
+
+ new = opt_malloc(sizeof(struct txt_record));
+ new->next = daemon->rr;
+ daemon->rr = new;
+
+ if (!atoi_check(comma, &flags) || !tag || !value || !(new->name = canonicalise_opt(arg)))
+ ret_err(_("bad CAA record"));
+
+ unhide_metas(tag);
+ unhide_metas(value);
+
+ new->len = strlen(tag) + strlen(value) + 2;
+ new->txt = opt_malloc(new->len);
+ new->txt[0] = flags;
+ new->txt[1] = strlen(tag);
+ memcpy(&new->txt[2], tag, strlen(tag));
+ memcpy(&new->txt[2 + strlen(tag)], value, strlen(value));
+ new->class = T_CAA;
+
+ break;
+ }
+
case 'Y': /* --txt-record */
{
struct txt_record *new;
@@ -3983,14 +4285,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);
@@ -4037,24 +4339,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);
+ }
}
}
}
@@ -4073,16 +4383,19 @@ 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;
+ new->flags = 0;
+
while (arg)
{
- struct all_addr addr;
+ union all_addr addr;
char *dig;
for (dig = arg; *dig != 0; dig++)
@@ -4090,20 +4403,33 @@ err:
break;
if (*dig == 0)
new->ttl = atoi(arg);
- else if (inet_pton(AF_INET, arg, &addr))
- new->addr = addr.addr.addr4;
-#ifdef HAVE_IPV6
- else if (inet_pton(AF_INET6, arg, &addr))
- new->addr6 = addr.addr.addr6;
-#endif
+ else if (inet_pton(AF_INET, arg, &addr.addr4))
+ {
+ new->addr = addr.addr4;
+ new->flags |= HR_4;
+ }
+ else if (inet_pton(AF_INET6, arg, &addr.addr6))
+ {
+ new->addr6 = addr.addr6;
+ new->flags |= HR_6;
+ }
else
{
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;
@@ -4132,17 +4458,28 @@ err:
}
#ifdef HAVE_DNSSEC
- case LOPT_DNSSEC_STAMP:
+ case LOPT_DNSSEC_STAMP: /* --dnssec-timestamp */
daemon->timestamp_file = opt_string_alloc(arg);
break;
- case LOPT_TRUST_ANCHOR:
+ case LOPT_DNSSEC_CHECK: /* --dnssec-check-unsigned */
+ if (arg)
+ {
+ if (strcmp(arg, "no") == 0)
+ set_option_bool(OPT_DNSSEC_IGN_NS);
+ else
+ ret_err(_("bad value for dnssec-check-unsigned"));
+ }
+ break;
+
+ case LOPT_TRUST_ANCHOR: /* --trust-anchor */
{
struct ds_config *new = opt_malloc(sizeof(struct ds_config));
char *cp, *cp1, *keyhex, *digest, *algo = NULL;
int len;
new->class = C_IN;
+ new->name = NULL;
if ((comma = split(arg)) && (algo = split(comma)))
{
@@ -4167,7 +4504,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;
@@ -4181,7 +4518,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;
@@ -4321,7 +4661,7 @@ static void read_file(char *file, FILE *f, int hard_opt)
if (errmess)
strcpy(daemon->namebuff, errmess);
- if (errmess || !one_opt(option, arg, buff, _("error"), 0, hard_opt == LOPT_REV_SERV))
+ if (errmess || !one_opt(option, arg, daemon->namebuff, _("error"), 0, hard_opt == LOPT_REV_SERV))
{
sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file);
if (hard_opt != 0)
@@ -4650,8 +4990,8 @@ void read_opts(int argc, char **argv, char *compile_opts)
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;
@@ -4725,8 +5065,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
argbuf_size = strlen(optarg) + 1;
argbuf = opt_malloc(argbuf_size);
}
- strncpy(argbuf, optarg, argbuf_size);
- argbuf[argbuf_size-1] = 0;
+ safe_strncpy(argbuf, optarg, argbuf_size);
arg = argbuf;
}
else
@@ -4761,8 +5100,14 @@ void read_opts(int argc, char **argv, char *compile_opts)
}
else if (option == 'C')
{
- conffile_opt = 0; /* file must exist */
- conffile = opt_string_alloc(arg);
+ if (!conffile)
+ conffile = opt_string_alloc(arg);
+ else
+ {
+ char *extra = opt_string_alloc(arg);
+ one_file(extra, 0);
+ free(extra);
+ }
}
else
{
@@ -4779,10 +5124,11 @@ void read_opts(int argc, char **argv, char *compile_opts)
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)
@@ -4793,10 +5139,8 @@ void read_opts(int argc, char **argv, char *compile_opts)
{
if (tmp->source_addr.sa.sa_family == AF_INET)
tmp->source_addr.in.sin_port = htons(daemon->query_port);
-#ifdef HAVE_IPV6
else if (tmp->source_addr.sa.sa_family == AF_INET6)
tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
-#endif
}
}
@@ -4816,7 +5160,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
#define NOLOOP 1
#define TESTLOOP 2
- /* Fill in TTL for CNAMES noe we have local_ttl.
+ /* Fill in TTL for CNAMES now we have local_ttl.
Also prepare to do loop detection. */
for (cn = daemon->cnames; cn; cn = cn->next)
{
@@ -4857,10 +5201,8 @@ void read_opts(int argc, char **argv, char *compile_opts)
for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)
if (tmp->addr.sa.sa_family == AF_INET)
tmp->addr.in.sin_port = htons(daemon->port);
-#ifdef HAVE_IPV6
else if (tmp->addr.sa.sa_family == AF_INET6)
tmp->addr.in6.sin6_port = htons(daemon->port);
-#endif /* IPv6 */
}
/* create default, if not specified */