Diff for /embedaddon/dnsmasq/src/option.c between versions 1.1.1.2 and 1.1.1.4

version 1.1.1.2, 2014/06/15 16:31:38 version 1.1.1.4, 2021/03/17 00:56:46
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
   
    This program is free software; you can redistribute it and/or modify     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     it under the terms of the GNU General Public License as published by
Line 129  struct myoption { Line 129  struct myoption {
 #define LOPT_AUTHPEER      318  #define LOPT_AUTHPEER      318
 #define LOPT_IPSET         319  #define LOPT_IPSET         319
 #define LOPT_SYNTH         320  #define LOPT_SYNTH         320
 #ifdef OPTION6_PREFIX_CLASS   
 #define LOPT_PREF_CLSS     321  
 #endif  
 #define LOPT_RELAY         323  #define LOPT_RELAY         323
 #define LOPT_RA_PARAM      324  #define LOPT_RA_PARAM      324
 #define LOPT_ADD_SBNET     325  #define LOPT_ADD_SBNET     325
Line 146  struct myoption { Line 143  struct myoption {
 #define LOPT_DNSSEC_CHECK  334  #define LOPT_DNSSEC_CHECK  334
 #define LOPT_LOCAL_SERVICE 335  #define LOPT_LOCAL_SERVICE 335
 #define LOPT_DNSSEC_TIME   336  #define LOPT_DNSSEC_TIME   336
#define LOPT_LOOP_DETECT   337
 #define LOPT_IGNORE_ADDR   338
 #define LOPT_MINCTTL       339
 #define LOPT_DHCP_INOTIFY  340
 #define LOPT_DHOPT_INOTIFY 341
 #define LOPT_HOST_INOTIFY  342
 #define LOPT_DNSSEC_STAMP  343
 #define LOPT_TFTP_NO_FAIL  344
 #define LOPT_MAXPORT       345
 #define LOPT_CPE_ID        346
 #define LOPT_SCRIPT_ARP    347
 #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
 #define LOPT_PXE_VENDOR    361
  
 #ifdef HAVE_GETOPT_LONG  #ifdef HAVE_GETOPT_LONG
 static const struct option opts[] =    static const struct option opts[] =  
 #else  #else
Line 158  static const struct myoption opts[] =  Line 180  static const struct myoption opts[] = 
     { "no-poll", 0, 0, 'n' },      { "no-poll", 0, 0, 'n' },
     { "help", 0, 0, 'w' },      { "help", 0, 0, 'w' },
     { "no-daemon", 0, 0, 'd' },      { "no-daemon", 0, 0, 'd' },
    { "log-queries", 0, 0, 'q' },    { "log-queries", 2, 0, 'q' },
     { "user", 2, 0, 'u' },      { "user", 2, 0, 'u' },
     { "group", 2, 0, 'g' },      { "group", 2, 0, 'g' },
     { "resolv-file", 2, 0, 'r' },      { "resolv-file", 2, 0, 'r' },
Line 180  static const struct myoption opts[] =  Line 202  static const struct myoption opts[] = 
     { "local-service", 0, 0, LOPT_LOCAL_SERVICE },      { "local-service", 0, 0, LOPT_LOCAL_SERVICE },
     { "bogus-priv", 0, 0, 'b' },      { "bogus-priv", 0, 0, 'b' },
     { "bogus-nxdomain", 1, 0, 'B' },      { "bogus-nxdomain", 1, 0, 'B' },
       { "ignore-address", 1, 0, LOPT_IGNORE_ADDR },
     { "selfmx", 0, 0, 'e' },      { "selfmx", 0, 0, 'e' },
     { "filterwin2k", 0, 0, 'f' },      { "filterwin2k", 0, 0, 'f' },
     { "pid-file", 2, 0, 'x' },      { "pid-file", 2, 0, 'x' },
Line 195  static const struct myoption opts[] =  Line 218  static const struct myoption opts[] = 
     { "local-ttl", 1, 0, 'T' },      { "local-ttl", 1, 0, 'T' },
     { "no-negcache", 0, 0, 'N' },      { "no-negcache", 0, 0, 'N' },
     { "addn-hosts", 1, 0, 'H' },      { "addn-hosts", 1, 0, 'H' },
       { "hostsdir", 1, 0, LOPT_HOST_INOTIFY },
     { "query-port", 1, 0, 'Q' },      { "query-port", 1, 0, 'Q' },
     { "except-interface", 1, 0, 'I' },      { "except-interface", 1, 0, 'I' },
     { "no-dhcp-interface", 1, 0, '2' },      { "no-dhcp-interface", 1, 0, '2' },
Line 212  static const struct myoption opts[] =  Line 236  static const struct myoption opts[] = 
     { "srv-host", 1, 0, 'W' },      { "srv-host", 1, 0, 'W' },
     { "localise-queries", 0, 0, 'y' },      { "localise-queries", 0, 0, 'y' },
     { "txt-record", 1, 0, 'Y' },      { "txt-record", 1, 0, 'Y' },
       { "caa-record", 1, 0 , LOPT_CAA },
     { "dns-rr", 1, 0, LOPT_RR },      { "dns-rr", 1, 0, LOPT_RR },
     { "enable-dbus", 2, 0, '1' },      { "enable-dbus", 2, 0, '1' },
       { "enable-ubus", 2, 0, LOPT_UBUS },
     { "bootp-dynamic", 2, 0, '3' },      { "bootp-dynamic", 2, 0, '3' },
     { "dhcp-mac", 1, 0, '4' },      { "dhcp-mac", 1, 0, '4' },
     { "no-ping", 0, 0, '5' },      { "no-ping", 0, 0, '5' },
Line 221  static const struct myoption opts[] =  Line 247  static const struct myoption opts[] = 
     { "conf-dir", 1, 0, '7' },      { "conf-dir", 1, 0, '7' },
     { "log-facility", 1, 0 ,'8' },      { "log-facility", 1, 0 ,'8' },
     { "leasefile-ro", 0, 0, '9' },      { "leasefile-ro", 0, 0, '9' },
       { "script-on-renewal", 0, 0, LOPT_SCRIPT_TIME},
     { "dns-forward-max", 1, 0, '0' },      { "dns-forward-max", 1, 0, '0' },
     { "clear-on-reload", 0, 0, LOPT_RELOAD },      { "clear-on-reload", 0, 0, LOPT_RELOAD },
     { "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },      { "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
     { "enable-tftp", 2, 0, LOPT_TFTP },      { "enable-tftp", 2, 0, LOPT_TFTP },
     { "tftp-secure", 0, 0, LOPT_SECURE },      { "tftp-secure", 0, 0, LOPT_SECURE },
    { "tftp-unique-root", 0, 0, LOPT_APREF },    { "tftp-no-fail", 0, 0, LOPT_TFTP_NO_FAIL },
     { "tftp-unique-root", 2, 0, LOPT_APREF },
     { "tftp-root", 1, 0, LOPT_PREFIX },      { "tftp-root", 1, 0, LOPT_PREFIX },
     { "tftp-max", 1, 0, LOPT_TFTP_MAX },      { "tftp-max", 1, 0, LOPT_TFTP_MAX },
       { "tftp-mtu", 1, 0, LOPT_TFTP_MTU },
     { "tftp-lowercase", 0, 0, LOPT_TFTP_LC },      { "tftp-lowercase", 0, 0, LOPT_TFTP_LC },
       { "tftp-single-port", 0, 0, LOPT_SINGLE_PORT },
     { "ptr-record", 1, 0, LOPT_PTR },      { "ptr-record", 1, 0, LOPT_PTR },
     { "naptr-record", 1, 0, LOPT_NAPTR },      { "naptr-record", 1, 0, LOPT_NAPTR },
     { "bridge-interface", 1, 0 , LOPT_BRIDGE },      { "bridge-interface", 1, 0 , LOPT_BRIDGE },
       { "shared-network", 1, 0, LOPT_SHARED_NET },
     { "dhcp-option-force", 1, 0, LOPT_FORCE },      { "dhcp-option-force", 1, 0, LOPT_FORCE },
     { "tftp-no-blocksize", 0, 0, LOPT_NOBLOCK },      { "tftp-no-blocksize", 0, 0, LOPT_NOBLOCK },
     { "log-dhcp", 0, 0, LOPT_LOG_OPTS },      { "log-dhcp", 0, 0, LOPT_LOG_OPTS },
Line 240  static const struct myoption opts[] =  Line 271  static const struct myoption opts[] = 
     { "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },      { "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
     { "dhcp-remoteid", 1, 0, LOPT_REMOTE },      { "dhcp-remoteid", 1, 0, LOPT_REMOTE },
     { "dhcp-subscrid", 1, 0, LOPT_SUBSCR },      { "dhcp-subscrid", 1, 0, LOPT_SUBSCR },
       { "dhcp-pxe-vendor", 1, 0, LOPT_PXE_VENDOR },
     { "interface-name", 1, 0, LOPT_INTNAME },      { "interface-name", 1, 0, LOPT_INTNAME },
     { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },      { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
     { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },      { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
       { "dhcp-hostsdir", 1, 0, LOPT_DHCP_INOTIFY },
       { "dhcp-optsdir", 1, 0, LOPT_DHOPT_INOTIFY },
     { "dhcp-no-override", 0, 0, LOPT_OVERRIDE },      { "dhcp-no-override", 0, 0, LOPT_OVERRIDE },
     { "tftp-port-range", 1, 0, LOPT_TFTPPORTS },      { "tftp-port-range", 1, 0, LOPT_TFTPPORTS },
     { "stop-dns-rebind", 0, 0, LOPT_REBIND },      { "stop-dns-rebind", 0, 0, LOPT_REBIND },
     { "rebind-domain-ok", 1, 0, LOPT_NO_REBIND },      { "rebind-domain-ok", 1, 0, LOPT_NO_REBIND },
     { "all-servers", 0, 0, LOPT_NOLAST },       { "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 },      { "dhcp-broadcast", 2, 0, LOPT_BROADCAST },
     { "neg-ttl", 1, 0, LOPT_NEGTTL },      { "neg-ttl", 1, 0, LOPT_NEGTTL },
     { "max-ttl", 1, 0, LOPT_MAXTTL },      { "max-ttl", 1, 0, LOPT_MAXTTL },
       { "min-cache-ttl", 1, 0, LOPT_MINCTTL },
     { "max-cache-ttl", 1, 0, LOPT_MAXCTTL },      { "max-cache-ttl", 1, 0, LOPT_MAXCTTL },
     { "dhcp-alternate-port", 2, 0, LOPT_ALTPORT },      { "dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
     { "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },      { "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
     { "min-port", 1, 0, LOPT_MINPORT },      { "min-port", 1, 0, LOPT_MINPORT },
       { "max-port", 1, 0, LOPT_MAXPORT },
     { "dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN },      { "dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN },
     { "cname", 1, 0, LOPT_CNAME },      { "cname", 1, 0, LOPT_CNAME },
     { "pxe-prompt", 1, 0, LOPT_PXE_PROMT },      { "pxe-prompt", 1, 0, LOPT_PXE_PROMT },
Line 265  static const struct myoption opts[] =  Line 302  static const struct myoption opts[] = 
     { "dhcp-proxy", 2, 0, LOPT_PROXY },      { "dhcp-proxy", 2, 0, LOPT_PROXY },
     { "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES },      { "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES },
     { "rebind-localhost-ok", 0, 0,  LOPT_LOC_REBND },      { "rebind-localhost-ok", 0, 0,  LOPT_LOC_REBND },
    { "add-mac", 0, 0, LOPT_ADD_MAC },    { "add-mac", 2, 0, LOPT_ADD_MAC },
     { "add-subnet", 2, 0, LOPT_ADD_SBNET },      { "add-subnet", 2, 0, LOPT_ADD_SBNET },
       { "add-cpe-id", 1, 0 , LOPT_CPE_ID },
     { "proxy-dnssec", 0, 0, LOPT_DNSSEC },      { "proxy-dnssec", 0, 0, LOPT_DNSSEC },
     { "dhcp-sequential-ip", 0, 0,  LOPT_INCR_ADDR },      { "dhcp-sequential-ip", 0, 0,  LOPT_INCR_ADDR },
     { "conntrack", 0, 0, LOPT_CONNTRACK },      { "conntrack", 0, 0, LOPT_CONNTRACK },
Line 287  static const struct myoption opts[] =  Line 325  static const struct myoption opts[] = 
     { "dnssec", 0, 0, LOPT_SEC_VALID },      { "dnssec", 0, 0, LOPT_SEC_VALID },
     { "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR },      { "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR },
     { "dnssec-debug", 0, 0, LOPT_DNSSEC_DEBUG },      { "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-no-timecheck", 0, 0, LOPT_DNSSEC_TIME },
#ifdef OPTION6_PREFIX_CLASS     { "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP },
    { "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS }, 
#endif 
     { "dhcp-relay", 1, 0, LOPT_RELAY },      { "dhcp-relay", 1, 0, LOPT_RELAY },
     { "ra-param", 1, 0, LOPT_RA_PARAM },      { "ra-param", 1, 0, LOPT_RA_PARAM },
     { "quiet-dhcp", 0, 0, LOPT_QUIET_DHCP },      { "quiet-dhcp", 0, 0, LOPT_QUIET_DHCP },
     { "quiet-dhcp6", 0, 0, LOPT_QUIET_DHCP6 },      { "quiet-dhcp6", 0, 0, LOPT_QUIET_DHCP6 },
     { "quiet-ra", 0, 0, LOPT_QUIET_RA },      { "quiet-ra", 0, 0, LOPT_QUIET_RA },
       { "dns-loop-detect", 0, 0, LOPT_LOOP_DETECT },
       { "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 }      { NULL, 0, 0, 0 }
   };    };
   
Line 329  static struct { Line 373  static struct {
   { 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },    { 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
   { LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL },    { LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL },
   { LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL },    { LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL },
     { LOPT_DHCP_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from a directory."), NULL }, 
     { LOPT_DHOPT_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP options from a directory."), NULL }, 
   { LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },    { LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },
   { 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },    { 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
   { 'H', ARG_DUP, "<path>", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },    { 'H', ARG_DUP, "<path>", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
     { LOPT_HOST_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read hosts files from a directory."), NULL },
   { 'i', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) to listen on."), NULL },    { 'i', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) to listen on."), NULL },
   { 'I', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },    { 'I', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
   { 'j', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },    { 'j', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
   { LOPT_CIRCUIT, ARG_DUP, "set:<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },    { LOPT_CIRCUIT, ARG_DUP, "set:<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
   { LOPT_REMOTE, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },    { LOPT_REMOTE, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
   { LOPT_SUBSCR, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },    { LOPT_SUBSCR, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
     { LOPT_PXE_VENDOR, ARG_DUP, "<vendor>[,...]", gettext_noop("Specify vendor class to match for PXE requests."), NULL },
   { 'J', ARG_DUP, "tag:<tag>...", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },    { 'J', ARG_DUP, "tag:<tag>...", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
   { LOPT_BROADCAST, ARG_DUP, "[=tag:<tag>...]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },     { LOPT_BROADCAST, ARG_DUP, "[=tag:<tag>...]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL }, 
   { 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },    { 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
Line 353  static struct { Line 401  static struct {
   { LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},    { LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},
   { 'p', ARG_ONE, "<integer>", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },    { 'p', ARG_ONE, "<integer>", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
   { 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },    { 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
  { 'q', OPT_LOG, NULL, gettext_noop("Log DNS queries."), NULL },  { 'q', ARG_DUP, NULL, gettext_noop("Log DNS queries."), NULL },
   { 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL },    { 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
   { 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },    { 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
   { 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },     { 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE }, 
Line 366  static struct { Line 414  static struct {
   { 'T', ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },    { 'T', ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
   { LOPT_NEGTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },    { LOPT_NEGTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
   { LOPT_MAXTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL },    { LOPT_MAXTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL },
     { LOPT_MAXCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live ceiling for cache."), NULL },
     { LOPT_MINCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live floor for cache."), NULL },
   { 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },     { 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER }, 
   { 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },    { 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
   { 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },    { 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
   { 'V', ARG_DUP, "<ipaddr>,<ipaddr>,<netmask>", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },    { 'V', ARG_DUP, "<ipaddr>,<ipaddr>,<netmask>", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },
   { 'W', ARG_DUP, "<name>,<target>,...", gettext_noop("Specify a SRV record."), NULL },    { 'W', ARG_DUP, "<name>,<target>,...", gettext_noop("Specify a SRV record."), NULL },
  { 'w', 0, NULL, gettext_noop("Display this message. Use --help dhcp for known DHCP options."), NULL },  { 'w', 0, NULL, gettext_noop("Display this message. Use --help dhcp or --help dhcp6 for known DHCP options."), NULL },
   { 'x', ARG_ONE, "<path>", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE },    { 'x', ARG_ONE, "<path>", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE },
   { 'X', ARG_ONE, "<integer>", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },    { 'X', ARG_ONE, "<integer>", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },
   { 'y', OPT_LOCALISE, NULL, gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL },    { 'y', OPT_LOCALISE, NULL, gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL },
Line 381  static struct { Line 431  static struct {
   { 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },    { '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 },    { '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 },    { '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 },    { '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 },    { '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 },    { '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_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 },    { '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 },    { '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 },    { LOPT_LUASCRIPT, ARG_DUP, "path", gettext_noop("Lua script to run on DHCP lease creation and destruction."), NULL },
   { LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change scripts as this user."), NULL },    { LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change scripts as this user."), NULL },
     { LOPT_SCRIPT_ARP, OPT_SCRIPT_ARP, NULL, gettext_noop("Call dhcp-script with changes to local ARP table."), NULL },
   { '7', ARG_DUP, "<path>", gettext_noop("Read configuration from all the files in this directory."), NULL },    { '7', ARG_DUP, "<path>", gettext_noop("Read configuration from all the files in this directory."), NULL },
  { '8', ARG_ONE, "<facilty>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL },  { '8', ARG_ONE, "<facility>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL },
   { '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL },    { '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL },
   { '0', ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" },     { '0', ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" }, 
   { LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },    { LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
Line 398  static struct { Line 451  static struct {
   { LOPT_OVERRIDE, OPT_NO_OVERRIDE, NULL, gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL },    { LOPT_OVERRIDE, OPT_NO_OVERRIDE, NULL, gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL },
   { LOPT_TFTP, ARG_DUP, "[=<intr>[,<intr>]]", gettext_noop("Enable integrated read-only TFTP server."), NULL },    { LOPT_TFTP, ARG_DUP, "[=<intr>[,<intr>]]", gettext_noop("Enable integrated read-only TFTP server."), NULL },
   { LOPT_PREFIX, ARG_DUP, "<dir>[,<iface>]", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },    { LOPT_PREFIX, ARG_DUP, "<dir>[,<iface>]", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
  { LOPT_APREF, OPT_TFTP_APREF, NULL, gettext_noop("Add client IP address to tftp-root."), NULL },  { LOPT_APREF, ARG_DUP, "[=ip|mac]", gettext_noop("Add client IP or hardware address to tftp-root."), NULL },
   { LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },    { LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
  { LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },  { LOPT_TFTP_NO_FAIL, OPT_TFTP_NO_FAIL, NULL, gettext_noop("Do not terminate the service if TFTP directories are inaccessible."), NULL },
   { LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent TFTP transfers (defaults to %s)."), "#" },
   { LOPT_TFTP_MTU, ARG_ONE, "<integer>", gettext_noop("Maximum MTU to use for TFTP transfers."), NULL },
   { LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },    { 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_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_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_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_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 },    { LOPT_REBIND, OPT_NO_REBIND, NULL, gettext_noop("Stop DNS rebinding. Filter private IP ranges when resolving."), NULL },
Line 411  static struct { Line 467  static struct {
   { LOPT_NO_REBIND, ARG_DUP, "/<domain>/", gettext_noop("Inhibit DNS-rebind protection on this domain."), NULL },    { 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_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_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_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_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 },    { LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
     { LOPT_MAXPORT, ARG_ONE, "<port>", gettext_noop("Specify highest port available for DNS query transmission."), NULL },
   { LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL },    { LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL },
   { LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},    { LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
   { LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },    { LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
  { LOPT_RELAY, ARG_DUP, "<local-addr>,<server>[,<interface>]", gettext_noop("Relay DHCP requests to a remote server"), NULL},  { LOPT_RELAY, ARG_DUP, "<local-addr>,<server>[,<iface>]", gettext_noop("Relay DHCP requests to a remote server"), NULL},
  { LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },  { LOPT_CNAME, ARG_DUP, "<alias>,<target>[,<ttl>]", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
   { LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },    { LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
   { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },    { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
   { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },    { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
  { LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },  { LOPT_ADD_MAC, ARG_DUP, "[=base64|text]", gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
  { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add requestor's IP subnet to forwarded DNS queries."), NULL },  { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL },
   { 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_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_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_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_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_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_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
  { LOPT_HOST_REC, ARG_DUP, "<name>,<address>", gettext_noop("Specify host (A/AAAA and PTR) records"), 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_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_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 },    { LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>", gettext_noop("Export local names to global DNS"), NULL },
   { LOPT_AUTHZONE, ARG_DUP, "<domain>,[<subnet>...]", gettext_noop("Domain to export to global DNS"), NULL },    { LOPT_AUTHZONE, ARG_DUP, "<domain>,[<subnet>...]", gettext_noop("Domain to export to global DNS"), NULL },
   { LOPT_AUTHTTL, ARG_ONE, "<integer>", gettext_noop("Set TTL for authoritative replies"), NULL },    { LOPT_AUTHTTL, ARG_ONE, "<integer>", gettext_noop("Set TTL for authoritative replies"), NULL },
  { LOPT_AUTHSOA, ARG_ONE, "<serial>[,...]", gettext_noop("Set authoritive zone information"), NULL },  { LOPT_AUTHSOA, ARG_ONE, "<serial>[,...]", gettext_noop("Set authoritative zone information"), NULL },
   { LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },    { LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
   { LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL },    { LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL },
  { LOPT_IPSET, ARG_DUP, "/<domain>/<ipset>[,<ipset>...]", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },  { LOPT_IPSET, ARG_DUP, "/<domain>[/<domain>...]/<ipset>...", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },
   { LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for synthesised names"), NULL },    { LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for synthesised names"), NULL },
   { LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL },    { 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_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_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_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL },
#ifdef OPTION6_PREFIX_CLASS   { LOPT_DNSSEC_STAMP, ARG_ONE, "<path>", gettext_noop("Timestamp file to verify system clock for DNSSEC"), NULL },
  { LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },  { LOPT_RA_PARAM, ARG_DUP, "<iface>,[mtu:<value>|<interface>|off,][<prio>,]<intval>[,<lifetime>]", gettext_noop("Set MTU, priority, resend-interval and router-lifetime"), NULL },
#endif 
  { LOPT_RA_PARAM, ARG_DUP, "<interface>,[high,|low,]<interval>[,<lifetime>]", gettext_noop("Set priority, resend-interval and router-lifetime"), NULL }, 
   { LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), 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 },    { LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
   { LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },    { LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
  { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks"), NULL },  { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks."), NULL },
   { LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops."), NULL },
   { LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL }, 
   { LOPT_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 }    { 0, 0, NULL, NULL, NULL }
 };   }; 
   
/* We hide metacharaters in quoted strings by mapping them into the ASCII control/* We hide metacharacters in quoted strings by mapping them into the ASCII control
    character space. Note that the \0, \t \b \r \033 and \n characters are carefully placed in the     character space. Note that the \0, \t \b \r \033 and \n characters are carefully placed in the
    following sequence so that they map to themselves: it is therefore possible to call     following sequence so that they map to themselves: it is therefore possible to call
    unhide_metas repeatedly on string without breaking things.     unhide_metas repeatedly on string without breaking things.
Line 516  static void *opt_malloc(size_t size) Line 583  static void *opt_malloc(size_t size)
   return ret;    return ret;
 }  }
   
static char *opt_string_alloc(char *cp)static char *opt_string_alloc(const char *cp)
 {  {
   char *ret = NULL;    char *ret = NULL;
     size_t len;
       
  if (cp && strlen(cp) != 0)  if (cp && (len = strlen(cp)) != 0)
     {      {
      ret = opt_malloc(strlen(cp)+1);      ret = opt_malloc(len+1);
      strcpy(ret, cp);       memcpy(ret, cp, len+1); 
               
       /* restore hidden metachars */        /* restore hidden metachars */
       unhide_metas(ret);        unhide_metas(ret);
Line 617  static int atoi_check8(char *a, int *res) Line 685  static int atoi_check8(char *a, int *res)
   return 1;    return 1;
 }  }
 #endif  #endif
        
 #ifndef NO_ID
 static void add_txt(char *name, char *txt, int stat)  static void add_txt(char *name, char *txt, int stat)
 {  {
   struct txt_record *r = opt_malloc(sizeof(struct txt_record));    struct txt_record *r = opt_malloc(sizeof(struct txt_record));
Line 630  static void add_txt(char *name, char *txt, int stat) Line 699  static void add_txt(char *name, char *txt, int stat)
       *(r->txt) = len;        *(r->txt) = len;
       memcpy((r->txt)+1, txt, len);        memcpy((r->txt)+1, txt, len);
     }      }
  
   r->stat = stat;    r->stat = stat;
   r->name = opt_string_alloc(name);    r->name = opt_string_alloc(name);
   r->next = daemon->txt;    r->next = daemon->txt;
   daemon->txt = r;    daemon->txt = r;
   r->class = C_CHAOS;    r->class = C_CHAOS;
 }  }
   #endif
   
 static void do_usage(void)  static void do_usage(void)
 {  {
Line 681  static void do_usage(void) Line 751  static void do_usage(void)
         sprintf(buff, "    ");          sprintf(buff, "    ");
               
       sprintf(buff+4, "--%s%s%s", opts[j].name, eq, desc);        sprintf(buff+4, "--%s%s%s", opts[j].name, eq, desc);
      printf("%-40.40s", buff);      printf("%-55.55s", buff);
                             
       if (usage[i].arg)        if (usage[i].arg)
         {          {
Line 696  static void do_usage(void) Line 766  static void do_usage(void)
 }  }
   
 #define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)  #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;
     else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
       addr->sa.sa_family = AF_INET6;
     else
       return _("bad address");
      
     return NULL;
   }
   
 char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags)  char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags)
 {  {
   int source_port = 0, serv_port = NAMESERVER_PORT;    int source_port = 0, serv_port = NAMESERVER_PORT;
   char *portno, *source;    char *portno, *source;
#ifdef HAVE_IPV6  char *interface_opt = NULL;
   int scope_index = 0;    int scope_index = 0;
   char *scope_id;    char *scope_id;
 #endif  
       
   if (!arg || strlen(arg) == 0)    if (!arg || strlen(arg) == 0)
     {      {
Line 722  char *parse_server(char *arg, union mysockaddr *addr,  Line 805  char *parse_server(char *arg, union mysockaddr *addr, 
       !atoi_check16(portno, &serv_port))        !atoi_check16(portno, &serv_port))
     return _("bad port");      return _("bad port");
       
 #ifdef HAVE_IPV6  
   scope_id = split_chr(arg, '%');    scope_id = split_chr(arg, '%');
 #endif  
       
     if (source) {
       interface_opt = split_chr(source, '@');
   
       if (interface_opt)
         {
   #if defined(SO_BINDTODEVICE)
           safe_strncpy(interface, interface_opt, IF_NAMESIZE);
   #else
           return _("interface binding not supported");
   #endif
         }
     }
   
   if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)    if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
     {      {
       addr->in.sin_port = htons(serv_port);             addr->in.sin_port = htons(serv_port);     
Line 744  char *parse_server(char *arg, union mysockaddr *addr,  Line 838  char *parse_server(char *arg, union mysockaddr *addr, 
           if (!(inet_pton(AF_INET, source, &source_addr->in.sin_addr) > 0))            if (!(inet_pton(AF_INET, source, &source_addr->in.sin_addr) > 0))
             {              {
 #if defined(SO_BINDTODEVICE)  #if defined(SO_BINDTODEVICE)
                 if (interface_opt)
                   return _("interface can only be specified once");
                 
               source_addr->in.sin_addr.s_addr = INADDR_ANY;                source_addr->in.sin_addr.s_addr = INADDR_ANY;
              strncpy(interface, source, IF_NAMESIZE - 1);              safe_strncpy(interface, source, IF_NAMESIZE);
 #else  #else
               return _("interface binding not supported");                return _("interface binding not supported");
 #endif  #endif
             }              }
         }          }
     }      }
 #ifdef HAVE_IPV6  
   else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)    else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
     {      {
       if (scope_id && (scope_index = if_nametoindex(scope_id)) == 0)        if (scope_id && (scope_index = if_nametoindex(scope_id)) == 0)
Line 776  char *parse_server(char *arg, union mysockaddr *addr,  Line 872  char *parse_server(char *arg, union mysockaddr *addr, 
           if (inet_pton(AF_INET6, source, &source_addr->in6.sin6_addr) == 0)            if (inet_pton(AF_INET6, source, &source_addr->in6.sin6_addr) == 0)
             {              {
 #if defined(SO_BINDTODEVICE)  #if defined(SO_BINDTODEVICE)
              source_addr->in6.sin6_addr = in6addr_any;               if (interface_opt)
              strncpy(interface, source, IF_NAMESIZE - 1);                return _("interface can only be specified once");
               
               source_addr->in6.sin6_addr = in6addr_any;
               safe_strncpy(interface, source, IF_NAMESIZE);
 #else  #else
               return _("interface binding not supported");                return _("interface binding not supported");
 #endif  #endif
             }              }
         }          }
     }      }
 #endif  
   else    else
     return _("bad address");      return _("bad address");
   
Line 794  char *parse_server(char *arg, union mysockaddr *addr,  Line 892  char *parse_server(char *arg, union mysockaddr *addr, 
 static struct server *add_rev4(struct in_addr addr, int msize)  static struct server *add_rev4(struct in_addr addr, int msize)
 {  {
   struct server *serv = opt_malloc(sizeof(struct server));    struct server *serv = opt_malloc(sizeof(struct server));
  in_addr_t  a = ntohl(addr.s_addr) >> 8;  in_addr_t  a = ntohl(addr.s_addr);
   char *p;    char *p;
   
   memset(serv, 0, sizeof(struct server));    memset(serv, 0, sizeof(struct server));
  p = serv->domain = opt_malloc(25); /* strlen("xxx.yyy.zzz.in-addr.arpa")+1 */  p = serv->domain = opt_malloc(29); /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */
 
   switch (msize)
     {
     case 32:
       p += sprintf(p, "%u.", a & 0xff);
       /* fall through */
     case 24:
       p += sprintf(p, "%d.", (a >> 8) & 0xff);
       /* fall through */
     case 16:
       p += sprintf(p, "%d.", (a >> 16) & 0xff);
       /* fall through */
     case 8:
       p += sprintf(p, "%d.", (a >> 24) & 0xff);
       break;
     default:
       free(serv->domain);
       free(serv);
       return NULL;
     }
 
   p += sprintf(p, "in-addr.arpa");
       
   if (msize == 24)  
     p += sprintf(p, "%d.", a & 0xff);  
   a = a >> 8;  
   if (msize != 8)  
     p += sprintf(p, "%d.", a & 0xff);  
   a = a >> 8;  
   p += sprintf(p, "%d.in-addr.arpa", a & 0xff);  
     
   serv->flags = SERV_HAS_DOMAIN;    serv->flags = SERV_HAS_DOMAIN;
   serv->next = daemon->servers;    serv->next = daemon->servers;
   daemon->servers = serv;    daemon->servers = serv;
Line 857  static char *set_prefix(char *arg) Line 969  static char *set_prefix(char *arg)
    return 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 */  /* This is too insanely large to keep in-line in the switch */
 static int parse_dhcp_opt(char *errstr, char *arg, int flags)  static int parse_dhcp_opt(char *errstr, char *arg, int flags)
 {  {
Line 864  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1086  static int parse_dhcp_opt(char *errstr, char *arg, int
   char lenchar = 0, *cp;    char lenchar = 0, *cp;
   int addrs, digs, is_addr, is_addr6, is_hex, is_dec, is_string, dots;    int addrs, digs, is_addr, is_addr6, is_hex, is_dec, is_string, dots;
   char *comma = NULL;    char *comma = NULL;
   struct dhcp_netid *np = NULL;  
   u16 opt_len = 0;    u16 opt_len = 0;
   int is6 = 0;    int is6 = 0;
   int option_ok = 0;    int option_ok = 0;
Line 951  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1172  static int parse_dhcp_opt(char *errstr, char *arg, int
         }          }
       else        else
         {          {
           new->netid = opt_malloc(sizeof (struct dhcp_netid));  
           /* allow optional "net:" or "tag:" for consistency */            /* allow optional "net:" or "tag:" for consistency */
          if (is_tag_prefix(arg))          const char *name = (is_tag_prefix(arg)) ? arg+4 : set_prefix(arg);
            new->netid->net = opt_string_alloc(arg+4);          new->netid = dhcp_netid_create(name, new->netid);
          else 
            new->netid->net = opt_string_alloc(set_prefix(arg)); 
          new->netid->next = np; 
          np = new->netid; 
         }          }
               
       arg = comma;         arg = comma; 
Line 968  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1184  static int parse_dhcp_opt(char *errstr, char *arg, int
   if (is6)    if (is6)
     {      {
       if (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))        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 &&        if (opt_len == 0 &&
           !(new->flags & DHOPT_RFC3925))            !(new->flags & DHOPT_RFC3925))
Line 982  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1198  static int parse_dhcp_opt(char *errstr, char *arg, int
       
   /* option may be missing with rfc3925 match */    /* option may be missing with rfc3925 match */
   if (!option_ok)    if (!option_ok)
    ret_err(_("bad dhcp-option"));    goto_err(_("bad dhcp-option"));
       
   if (comma)    if (comma)
     {      {
       /* characterise the value */        /* characterise the value */
       char c;        char c;
      int found_dig = 0;      int found_dig = 0, found_colon = 0;
       is_addr = is_addr6 = is_hex = is_dec = is_string = 1;        is_addr = is_addr6 = is_hex = is_dec = is_string = 1;
       addrs = digs = 1;        addrs = digs = 1;
       dots = 0;        dots = 0;
Line 1002  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1218  static int parse_dhcp_opt(char *errstr, char *arg, int
           {            {
             digs++;              digs++;
             is_dec = is_addr = 0;              is_dec = is_addr = 0;
               found_colon = 1;
           }            }
         else if (c == '/')           else if (c == '/') 
           {            {
Line 1011  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1228  static int parse_dhcp_opt(char *errstr, char *arg, int
           }             } 
         else if (c == '.')                else if (c == '.')      
           {            {
            is_addr6 = is_dec = is_hex = 0;            is_dec = is_hex = 0;
             dots++;              dots++;
           }            }
         else if (c == '-')          else if (c == '-')
Line 1043  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1260  static int parse_dhcp_opt(char *errstr, char *arg, int
             
       if (!found_dig)        if (!found_dig)
         is_dec = is_addr = 0;          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 */        /* We know that some options take addresses */
       if (opt_len & OT_ADDR_LIST)        if (opt_len & OT_ADDR_LIST)
Line 1050  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1276  static int parse_dhcp_opt(char *errstr, char *arg, int
           is_string = is_dec = is_hex = 0;            is_string = is_dec = is_hex = 0;
                       
           if (!is6 && (!is_addr || dots == 0))            if (!is6 && (!is_addr || dots == 0))
            ret_err(_("bad IP address"));            goto_err(_("bad IP address"));
   
            if (is6 && !is_addr6)             if (is6 && !is_addr6)
             ret_err(_("bad IPv6 address"));             goto_err(_("bad IPv6 address"));
         }          }
       /* or names */        /* or names */
       else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING))        else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING))
Line 1072  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1298  static int parse_dhcp_opt(char *errstr, char *arg, int
             case 'd':              case 'd':
             case 'D':              case 'D':
               fac *= 24;                fac *= 24;
              /* fall though */              /* fall through */
             case 'h':              case 'h':
             case 'H':              case 'H':
               fac *= 60;                fac *= 60;
Line 1145  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1371  static int parse_dhcp_opt(char *errstr, char *arg, int
               cp = comma;                cp = comma;
               comma = split(cp);                comma = split(cp);
               slash = split_chr(cp, '/');                slash = split_chr(cp, '/');
              inet_pton(AF_INET, cp, &in);              if (!inet_pton(AF_INET, cp, &in))
                 goto_err(_("bad IPv4 address"));
               if (!slash)                if (!slash)
                 {                  {
                   memcpy(op, &in, INADDRSZ);                    memcpy(op, &in, INADDRSZ);
Line 1190  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1417  static int parse_dhcp_opt(char *errstr, char *arg, int
                   op += IN6ADDRSZ;                    op += IN6ADDRSZ;
                   continue;                    continue;
                 }                  }
          
              ret_err(_("bad IPv6 address"));              goto_err(_("bad IPv6 address"));
             }               } 
           new->len = op - new->val;            new->len = op - new->val;
         }          }
Line 1218  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1445  static int parse_dhcp_opt(char *errstr, char *arg, int
                   if (strcmp (arg, ".") != 0)                    if (strcmp (arg, ".") != 0)
                     {                      {
                       if (!(dom = canonicalise_opt(arg)))                        if (!(dom = canonicalise_opt(arg)))
                        ret_err(_("bad domain in dhcp-option"));                        goto_err(_("bad domain in dhcp-option"));
                                                   
                       domlen = strlen(dom) + 2;                        domlen = strlen(dom) + 2;
                     }                      }
Line 1265  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1492  static int parse_dhcp_opt(char *errstr, char *arg, int
                 }                  }
               
               /* RFC 3361, enc byte is zero for names */                /* RFC 3361, enc byte is zero for names */
              if (new->opt == OPTION_SIP_SERVER)              if (new->opt == OPTION_SIP_SERVER && m)
                 m[0] = 0;                  m[0] = 0;
               new->len = (int) len + header_size;                new->len = (int) len + header_size;
               new->val = m;                new->val = m;
Line 1303  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1530  static int parse_dhcp_opt(char *errstr, char *arg, int
             }              }
           else if (comma && (opt_len & OT_RFC1035_NAME))            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 len = 0;
                 int header_size = (is6 && new->opt == OPTION6_NTP_SERVER) ? 4 : 0;
               arg = comma;                arg = comma;
               comma = split(arg);                comma = split(arg);
                               
Line 1312  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1540  static int parse_dhcp_opt(char *errstr, char *arg, int
                 {                  {
                   char *dom = canonicalise_opt(arg);                    char *dom = canonicalise_opt(arg);
                   if (!dom)                    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)                    if (p)
                     {                      {
Line 1323  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1551  static int parse_dhcp_opt(char *errstr, char *arg, int
                     }                      }
                                       
                   p = newp;                    p = newp;
                  end = do_rfc1035_name(p + len, dom);                  q = p + len;
                   end = do_rfc1035_name(q + header_size, dom, NULL);
                   *end++ = 0;                    *end++ = 0;
                     if (is6 && new->opt == OPTION6_NTP_SERVER)
                       {
                         PUTSHORT(NTP_SUBOPTION_SRV_FQDN, q);
                         PUTSHORT(end - q - 2, q);
                       }
                   len = end - p;                    len = end - p;
                   free(dom);                    free(dom);
   
Line 1350  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1584  static int parse_dhcp_opt(char *errstr, char *arg, int
       ((new->len > 255) ||         ((new->len > 255) || 
       (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) ||        (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) ||
        (new->len > 250 && (new->flags & DHOPT_RFC3925))))         (new->len > 250 && (new->flags & DHOPT_RFC3925))))
    ret_err(_("dhcp-option too long"));    goto_err(_("dhcp-option too long"));
       
   if (flags == DHOPT_MATCH)    if (flags == DHOPT_MATCH)
     {      {
       if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||        if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||
           !new->netid ||            !new->netid ||
           new->netid->next)            new->netid->next)
        ret_err(_("illegal dhcp-match"));        goto_err(_("illegal dhcp-match"));
                 
       if (is6)        if (is6)
         {          {
Line 1382  static int parse_dhcp_opt(char *errstr, char *arg, int Line 1616  static int parse_dhcp_opt(char *errstr, char *arg, int
     }      }
           
   return 1;    return 1;
   on_error:
     dhcp_opt_free(new);
     return 0;
 }  }
   
 #endif  #endif
   
 void set_option_bool(unsigned int opt)  void set_option_bool(unsigned int opt)
 {  {
  if (opt < 32)  option_var(opt) |= option_val(opt);
    daemon->options |= 1u << opt; 
  else 
    daemon->options2 |= 1u << (opt - 32); 
 }  }
   
 void reset_option_bool(unsigned int opt)  void reset_option_bool(unsigned int opt)
 {  {
  if (opt < 32)  option_var(opt) &= ~(option_val(opt));
    daemon->options &= ~(1u << opt); 
  else 
    daemon->options2 &= ~(1u << (opt - 32)); 
 }  }
   
   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)  static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only)
 {        {      
   int i;    int i;
Line 1460  static int one_opt(int option, char *arg, char *errstr Line 1701  static int one_opt(int option, char *arg, char *errstr
         struct dirent *ent;          struct dirent *ent;
         char *directory, *path;          char *directory, *path;
         struct list {          struct list {
          char *suffix;          char *name;
           struct list *next;            struct list *next;
        } *ignore_suffix = NULL, *li;        } *ignore_suffix = NULL, *match_suffix = NULL, *files = NULL, *li;
                   
         comma = split(arg);          comma = split(arg);
         if (!(directory = opt_string_alloc(arg)))          if (!(directory = opt_string_alloc(arg)))
Line 1471  static int one_opt(int option, char *arg, char *errstr Line 1712  static int one_opt(int option, char *arg, char *errstr
         for (arg = comma; arg; arg = comma)           for (arg = comma; arg; arg = comma) 
           {            {
             comma = split(arg);              comma = split(arg);
            li = opt_malloc(sizeof(struct list));            if (strlen(arg) != 0)
            li->next = ignore_suffix;              {
            ignore_suffix = li;                li = opt_malloc(sizeof(struct list));
            /* Have to copy: buffer is overwritten */                if (*arg == '*')
            li->suffix = opt_string_alloc(arg);                  {
          };                    /* "*" with no suffix is a no-op */
                     if (arg[1] == 0)
                       free(li);
                     else
                       {
                         li->next = match_suffix;
                         match_suffix = li;
                         /* Have to copy: buffer is overwritten */
                         li->name = opt_string_alloc(arg+1);
                       }
                   }
                 else
                   {
                     li->next = ignore_suffix;
                     ignore_suffix = li;
                     /* Have to copy: buffer is overwritten */
                     li->name = opt_string_alloc(arg);
                   }
               }
           }
                   
         if (!(dir_stream = opendir(directory)))          if (!(dir_stream = opendir(directory)))
           die(_("cannot access directory %s: %s"), directory, EC_FILE);            die(_("cannot access directory %s: %s"), directory, EC_FILE);
Line 1493  static int one_opt(int option, char *arg, char *errstr Line 1753  static int one_opt(int option, char *arg, char *errstr
                 ent->d_name[0] == '.')                  ent->d_name[0] == '.')
               continue;                continue;
   
               if (match_suffix)
                 {
                   for (li = match_suffix; li; li = li->next)
                     {
                       /* check for required suffices */
                       size_t ls = strlen(li->name);
                       if (len > ls &&
                           strcmp(li->name, &ent->d_name[len - ls]) == 0)
                         break;
                     }
                   if (!li)
                     continue;
                 }
               
             for (li = ignore_suffix; li; li = li->next)              for (li = ignore_suffix; li; li = li->next)
               {                {
                 /* check for proscribed suffices */                  /* check for proscribed suffices */
                size_t ls = strlen(li->suffix);                size_t ls = strlen(li->name);
                 if (len > ls &&                  if (len > ls &&
                    strcmp(li->suffix, &ent->d_name[len - ls]) == 0)                    strcmp(li->name, &ent->d_name[len - ls]) == 0)
                   break;                    break;
               }                }
             if (li)              if (li)
Line 1515  static int one_opt(int option, char *arg, char *errstr Line 1789  static int one_opt(int option, char *arg, char *errstr
                           
             /* only reg files allowed. */              /* only reg files allowed. */
             if (S_ISREG(buf.st_mode))              if (S_ISREG(buf.st_mode))
              one_file(path, 0);              {
                            /* sort files into order. */
            free(path);                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);          closedir(dir_stream);
         free(directory);          free(directory);
         for(; ignore_suffix; ignore_suffix = li)          for(; ignore_suffix; ignore_suffix = li)
           {            {
             li = ignore_suffix->next;              li = ignore_suffix->next;
            free(ignore_suffix->suffix);            free(ignore_suffix->name);
             free(ignore_suffix);              free(ignore_suffix);
           }            }
                      for(; match_suffix; match_suffix = li)
           {
             li = match_suffix->next;
             free(match_suffix->name);
             free(match_suffix);
           }
         for(; files; files = li)
           {
             li = files->next;
             free(files->name);
             free(files);
           }
         break;          break;
       }        }
   
Line 1536  static int one_opt(int option, char *arg, char *errstr Line 1834  static int one_opt(int option, char *arg, char *errstr
       set_option_bool(OPT_CLIENT_SUBNET);        set_option_bool(OPT_CLIENT_SUBNET);
       if (arg)        if (arg)
         {          {
             char *err, *end;
           comma = split(arg);            comma = split(arg);
          if (!atoi_check(arg, &daemon->addr4_netmask) || 
              (comma && !atoi_check(comma, &daemon->addr6_netmask)))          struct mysubnet* new = opt_malloc(sizeof(struct mysubnet));
             ret_err(gen_err);          if ((end = split_chr(arg, '/')))
             {
               /* has subnet+len */
               err = parse_mysockaddr(arg, &new->addr);
               if (err)
                 ret_err_free(err, new);
               if (!atoi_check(end, &new->mask))
                 ret_err_free(gen_err, new);
               new->addr_used = 1;
             } 
           else if (!atoi_check(arg, &new->mask))
             ret_err_free(gen_err, new);
             
           daemon->add_subnet4 = new;
 
           if (comma)
             {
               new = opt_malloc(sizeof(struct mysubnet));
               if ((end = split_chr(comma, '/')))
                 {
                   /* has subnet+len */
                   err = parse_mysockaddr(comma, &new->addr);
                   if (err)
                     ret_err_free(err, new);
                   if (!atoi_check(end, &new->mask))
                     ret_err_free(gen_err, new);
                   new->addr_used = 1;
                 }
               else
                 {
                   if (!atoi_check(comma, &new->mask))
                     ret_err_free(gen_err, new);
                 }
           
               daemon->add_subnet6 = new;
             }
         }          }
       break;        break;
   
Line 1550  static int one_opt(int option, char *arg, char *errstr Line 1884  static int one_opt(int option, char *arg, char *errstr
       else        else
         daemon->dbus_name = DNSMASQ_SERVICE;          daemon->dbus_name = DNSMASQ_SERVICE;
       break;        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 */      case '8': /* --log-facility */
       /* may be a filename */        /* may be a filename */
       if (strchr(arg, '/') || strcmp (arg, "-") == 0)        if (strchr(arg, '/') || strcmp (arg, "-") == 0)
Line 1571  static int one_opt(int option, char *arg, char *errstr Line 1913  static int one_opt(int option, char *arg, char *errstr
 #endif  #endif
         }          }
       break;        break;
      
     case 'x': /* --pid-file */      case 'x': /* --pid-file */
       daemon->runfile = opt_string_alloc(arg);        daemon->runfile = opt_string_alloc(arg);
       break;        break;
Line 1642  static int one_opt(int option, char *arg, char *errstr Line 1984  static int one_opt(int option, char *arg, char *errstr
         ret_err(_("bad MX target"));          ret_err(_("bad MX target"));
       break;        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        #ifdef HAVE_DHCP      
     case 'l':  /* --dhcp-leasefile */      case 'l':  /* --dhcp-leasefile */
       daemon->lease_file = opt_string_alloc(arg);        daemon->lease_file = opt_string_alloc(arg);
Line 1650  static int one_opt(int option, char *arg, char *errstr Line 2000  static int one_opt(int option, char *arg, char *errstr
       /* Sorry about the gross pre-processor abuse */        /* Sorry about the gross pre-processor abuse */
     case '6':             /* --dhcp-script */      case '6':             /* --dhcp-script */
     case LOPT_LUASCRIPT:  /* --dhcp-luascript */      case LOPT_LUASCRIPT:  /* --dhcp-luascript */
#  if defined(NO_FORK)#  if !defined(HAVE_SCRIPT)
      ret_err(_("cannot run scripts under uClinux")); 
#  elif !defined(HAVE_SCRIPT) 
       ret_err(_("recompile with HAVE_SCRIPT defined to enable lease-change scripts"));        ret_err(_("recompile with HAVE_SCRIPT defined to enable lease-change scripts"));
 #  else  #  else
       if (option == LOPT_LUASCRIPT)        if (option == LOPT_LUASCRIPT)
Line 1667  static int one_opt(int option, char *arg, char *errstr Line 2015  static int one_opt(int option, char *arg, char *errstr
       break;        break;
 #endif /* HAVE_DHCP */  #endif /* HAVE_DHCP */
   
    case LOPT_DHCP_HOST: /* --dhcp-hostfile */    case LOPT_DHCP_HOST:     /* --dhcp-hostsfile */
    case LOPT_DHCP_OPTS: /* --dhcp-optsfile */    case LOPT_DHCP_OPTS:     /* --dhcp-optsfile */
    case 'H': /* --addn-hosts */    case LOPT_DHCP_INOTIFY:  /* --dhcp-hostsdir */
     case LOPT_DHOPT_INOTIFY: /* --dhcp-optsdir */
     case LOPT_HOST_INOTIFY:  /* --hostsdir */
     case 'H':                /* --addn-hosts */
       {        {
         struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));          struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
         static unsigned int hosts_index = SRC_AH;          static unsigned int hosts_index = SRC_AH;
Line 1691  static int one_opt(int option, char *arg, char *errstr Line 2042  static int one_opt(int option, char *arg, char *errstr
             new->next = daemon->dhcp_opts_file;              new->next = daemon->dhcp_opts_file;
             daemon->dhcp_opts_file = new;              daemon->dhcp_opts_file = new;
           }                   }       
           else 
             {
               new->next = daemon->dynamic_dirs;
               daemon->dynamic_dirs = new; 
               if (option == LOPT_DHCP_INOTIFY)
                 new->flags |= AH_DHCP_HST;
               else if (option == LOPT_DHOPT_INOTIFY)
                 new->flags |= AH_DHCP_OPT;
               else if (option == LOPT_HOST_INOTIFY)
                 new->flags |= AH_HOSTS;
             }
           
         break;          break;
       }        }
               
   
 #ifdef HAVE_AUTH  
     case LOPT_AUTHSERV: /* --auth-server */      case LOPT_AUTHSERV: /* --auth-server */
      if (!(comma = split(arg)))      comma = split(arg);
        ret_err(gen_err); 
               
       daemon->authserver = opt_string_alloc(arg);        daemon->authserver = opt_string_alloc(arg);
      arg = comma;      
      do {      while ((arg = comma))
        struct iname *new = opt_malloc(sizeof(struct iname));        {
        comma = split(arg);          struct iname *new = opt_malloc(sizeof(struct iname));
        new->name = NULL;          comma = split(arg);
        unhide_metas(arg);          new->name = NULL;
        if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0)          unhide_metas(arg);
          new->addr.sa.sa_family = AF_INET;          if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0)
#ifdef HAVE_IPV6            new->addr.sa.sa_family = AF_INET;
        else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)          else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
          new->addr.sa.sa_family = AF_INET6;            new->addr.sa.sa_family = AF_INET6;
#endif          else
        else            {
          {              char *fam = split_chr(arg, '/');
            char *fam = split_chr(arg, '/');              new->name = opt_string_alloc(arg);
            new->name = opt_string_alloc(arg);              new->addr.sa.sa_family = 0;
            new->addr.sa.sa_family = 0;              if (fam)
            if (fam)                {
              {                  if (strcmp(fam, "4") == 0)
                if (strcmp(fam, "4") == 0)                    new->addr.sa.sa_family = AF_INET;
                  new->addr.sa.sa_family = AF_INET;                  else if (strcmp(fam, "6") == 0)
#ifdef HAVE_IPV6                    new->addr.sa.sa_family = AF_INET6;
                else if (strcmp(fam, "6") == 0)                  else
                  new->addr.sa.sa_family = AF_INET6;                  {
#endif                    free(new->name);
                else                    ret_err_free(gen_err, new);
                  ret_err(gen_err);                  }
              }                 } 
          }            }
        new->next = daemon->authinterface;          new->next = daemon->authinterface;
        daemon->authinterface = new;          daemon->authinterface = new;
                };
        arg = comma; 
      } while (arg); 
                           
       break;        break;
   
Line 1762  static int one_opt(int option, char *arg, char *errstr Line 2120  static int one_opt(int option, char *arg, char *errstr
         new = opt_malloc(sizeof(struct auth_zone));          new = opt_malloc(sizeof(struct auth_zone));
         new->domain = opt_string_alloc(arg);          new->domain = opt_string_alloc(arg);
         new->subnet = NULL;          new->subnet = NULL;
           new->exclude = NULL;
         new->interface_names = NULL;          new->interface_names = NULL;
         new->next = daemon->auth_zones;          new->next = daemon->auth_zones;
         daemon->auth_zones = new;          daemon->auth_zones = new;
Line 1769  static int one_opt(int option, char *arg, char *errstr Line 2128  static int one_opt(int option, char *arg, char *errstr
         while ((arg = comma))          while ((arg = comma))
           {            {
             int prefixlen = 0;              int prefixlen = 0;
               int is_exclude = 0;
             char *prefix;              char *prefix;
             struct addrlist *subnet =  NULL;              struct addrlist *subnet =  NULL;
            struct all_addr addr;            union all_addr addr;
   
             comma = split(arg);              comma = split(arg);
             prefix = split_chr(arg, '/');              prefix = split_chr(arg, '/');
Line 1779  static int one_opt(int option, char *arg, char *errstr Line 2139  static int one_opt(int option, char *arg, char *errstr
             if (prefix && !atoi_check(prefix, &prefixlen))              if (prefix && !atoi_check(prefix, &prefixlen))
               ret_err(gen_err);                ret_err(gen_err);
                           
            if (inet_pton(AF_INET, arg, &addr.addr.addr4))            if (strstr(arg, "exclude:") == arg)
               {                {
                       is_exclude = 1;
                       arg = arg+8;
                 }
   
               if (inet_pton(AF_INET, arg, &addr.addr4))
                 {
                 subnet = opt_malloc(sizeof(struct addrlist));                  subnet = opt_malloc(sizeof(struct addrlist));
                 subnet->prefixlen = (prefixlen == 0) ? 24 : prefixlen;                  subnet->prefixlen = (prefixlen == 0) ? 24 : prefixlen;
                 subnet->flags = ADDRLIST_LITERAL;                  subnet->flags = ADDRLIST_LITERAL;
               }                }
#ifdef HAVE_IPV6            else if (inet_pton(AF_INET6, arg, &addr.addr6))
            else if (inet_pton(AF_INET6, arg, &addr.addr.addr6)) 
               {                {
                 subnet = opt_malloc(sizeof(struct addrlist));                  subnet = opt_malloc(sizeof(struct addrlist));
                 subnet->prefixlen = (prefixlen == 0) ? 64 : prefixlen;                  subnet->prefixlen = (prefixlen == 0) ? 64 : prefixlen;
                 subnet->flags = ADDRLIST_LITERAL | ADDRLIST_IPV6;                  subnet->flags = ADDRLIST_LITERAL | ADDRLIST_IPV6;
               }                }
 #endif  
             else               else 
               {                {
                 struct auth_name_list *name =  opt_malloc(sizeof(struct auth_name_list));                  struct auth_name_list *name =  opt_malloc(sizeof(struct auth_name_list));
Line 1804  static int one_opt(int option, char *arg, char *errstr Line 2168  static int one_opt(int option, char *arg, char *errstr
                   {                    {
                     if (prefixlen == 4)                      if (prefixlen == 4)
                       name->flags &= ~AUTH6;                        name->flags &= ~AUTH6;
 #ifdef HAVE_IPV6  
                     else if (prefixlen == 6)                      else if (prefixlen == 6)
                       name->flags &= ~AUTH4;                        name->flags &= ~AUTH4;
 #endif  
                     else                      else
                       ret_err(gen_err);                        ret_err(gen_err);
                   }                    }
Line 1816  static int one_opt(int option, char *arg, char *errstr Line 2178  static int one_opt(int option, char *arg, char *errstr
             if (subnet)              if (subnet)
               {                {
                 subnet->addr = addr;                  subnet->addr = addr;
                subnet->next = new->subnet;
                new->subnet = subnet;                if (is_exclude)
                   {
                     subnet->next = new->exclude;
                     new->exclude = subnet;
                   }
                 else
                   {
                     subnet->next = new->subnet;
                     new->subnet = subnet;
                   }
               }                }
           }            }
         break;          break;
Line 1847  static int one_opt(int option, char *arg, char *errstr Line 2218  static int one_opt(int option, char *arg, char *errstr
                   comma = split(arg);                     comma = split(arg); 
                   daemon->soa_retry = (u32)atoi(arg);                    daemon->soa_retry = (u32)atoi(arg);
                   if (comma)                    if (comma)
                    {                    daemon->soa_expiry = (u32)atoi(comma);
                      arg = comma; 
                      comma = split(arg);  
                      daemon->soa_expiry = (u32)atoi(arg); 
                    } 
                 }                  }
             }              }
         }          }
   
       break;        break;
 #endif  
   
     case 's':         /* --domain */      case 's':         /* --domain */
     case LOPT_SYNTH:  /* --synth-domain */      case LOPT_SYNTH:  /* --synth-domain */
Line 1877  static int one_opt(int option, char *arg, char *errstr Line 2243  static int one_opt(int option, char *arg, char *errstr
                   char *netpart;                    char *netpart;
                                       
                   new->prefix = NULL;                    new->prefix = NULL;
                  new->indexed = 0;
                   
                   unhide_metas(comma);                    unhide_metas(comma);
                   if ((netpart = split_chr(comma, '/')))                    if ((netpart = split_chr(comma, '/')))
                     {                      {
Line 1885  static int one_opt(int option, char *arg, char *errstr Line 2252  static int one_opt(int option, char *arg, char *errstr
   
                       arg = split(netpart);                        arg = split(netpart);
                       if (!atoi_check(netpart, &msize))                        if (!atoi_check(netpart, &msize))
                        ret_err(gen_err);                        ret_err_free(gen_err, new);
                       else if (inet_pton(AF_INET, comma, &new->start))                        else if (inet_pton(AF_INET, comma, &new->start))
                         {                          {
                           int mask = (1 << (32 - msize)) - 1;                            int mask = (1 << (32 - msize)) - 1;
Line 1898  static int one_opt(int option, char *arg, char *errstr Line 2265  static int one_opt(int option, char *arg, char *errstr
                                 {                                  {
                                   if (!(new->prefix = canonicalise_opt(arg)) ||                                    if (!(new->prefix = canonicalise_opt(arg)) ||
                                       strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)                                        strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
                                    ret_err(_("bad prefix"));                                    ret_err_free(_("bad prefix"), new);
                                 }                                  }
                               else if (strcmp(arg, "local") != 0 ||                                else if (strcmp(arg, "local") != 0 ||
                                        (msize != 8 && msize != 16 && msize != 24))                                         (msize != 8 && msize != 16 && msize != 24))
                                ret_err(gen_err);                                ret_err_free(gen_err, new);
                               else                                else
                                 {                                  {
                                    /* generate the equivalent of                                     /* generate the equivalent of
                                       local=/<domain>/  
                                       local=/xxx.yyy.zzz.in-addr.arpa/ */                                        local=/xxx.yyy.zzz.in-addr.arpa/ */
                                   struct server *serv = add_rev4(new->start, msize);                                    struct server *serv = add_rev4(new->start, msize);
                                     if (!serv)
                                       ret_err_free(_("bad prefix"), new);
   
                                   serv->flags |= SERV_NO_ADDR;                                    serv->flags |= SERV_NO_ADDR;
   
                                     /* local=/<domain>/ */
                                     serv = opt_malloc(sizeof(struct server));
                                     memset(serv, 0, sizeof(struct server));
                                     serv->domain = d;
                                     serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
                                     serv->next = daemon->servers;
                                     daemon->servers = serv;
                                 }                                  }
                             }                              }
                         }                          }
 #ifdef HAVE_IPV6  
                       else if (inet_pton(AF_INET6, comma, &new->start6))                        else if (inet_pton(AF_INET6, comma, &new->start6))
                         {                          {
                           u64 mask = (1LLU << (128 - msize)) - 1LLU;                            u64 mask = (1LLU << (128 - msize)) - 1LLU;
Line 1929  static int one_opt(int option, char *arg, char *errstr Line 2305  static int one_opt(int option, char *arg, char *errstr
                           setaddr6part(&new->end6, addrpart | mask);                            setaddr6part(&new->end6, addrpart | mask);
                                                       
                           if (msize < 64)                            if (msize < 64)
                            ret_err(gen_err);                            ret_err_free(gen_err, new);
                           else if (arg)                            else if (arg)
                             {                              {
                               if (option != 's')                                if (option != 's')
                                 {                                  {
                                   if (!(new->prefix = canonicalise_opt(arg)) ||                                    if (!(new->prefix = canonicalise_opt(arg)) ||
                                       strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)                                        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))                                else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
                                ret_err(gen_err);                                ret_err_free(gen_err, new);
                               else                                 else 
                                 {                                  {
                                   /* generate the equivalent of                                    /* generate the equivalent of
                                      local=/<domain>/  
                                      local=/xxx.yyy.zzz.ip6.arpa/ */                                       local=/xxx.yyy.zzz.ip6.arpa/ */
                                   struct server *serv = add_rev6(&new->start6, msize);                                    struct server *serv = add_rev6(&new->start6, msize);
                                   serv->flags |= SERV_NO_ADDR;                                    serv->flags |= SERV_NO_ADDR;
                                     
                                     /* local=/<domain>/ */
                                     serv = opt_malloc(sizeof(struct server));
                                     memset(serv, 0, sizeof(struct server));
                                     serv->domain = d;
                                     serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
                                     serv->next = daemon->servers;
                                     daemon->servers = serv;
                                 }                                  }
                             }                              }
                         }                          }
 #endif  
                       else                        else
                        ret_err(gen_err);                        ret_err_free(gen_err, new);
                     }                      }
                   else                    else
                     {                      {
Line 1966  static int one_opt(int option, char *arg, char *errstr Line 2348  static int one_opt(int option, char *arg, char *errstr
                           if (!arg)                            if (!arg)
                             new->end.s_addr = new->start.s_addr;                              new->end.s_addr = new->start.s_addr;
                           else if (!inet_pton(AF_INET, arg, &new->end))                            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))                        else if (inet_pton(AF_INET6, comma, &new->start6))
                         {                          {
                           new->is6 = 1;                            new->is6 = 1;
                           if (!arg)                            if (!arg)
                             memcpy(&new->end6, &new->start6, IN6ADDRSZ);                              memcpy(&new->end6, &new->start6, IN6ADDRSZ);
                           else if (!inet_pton(AF_INET6, arg, &new->end6))                            else if (!inet_pton(AF_INET6, arg, &new->end6))
                            ret_err(gen_err);                            ret_err_free(gen_err, new);
                         }                          }
 #endif  
                       else                         else 
                        ret_err(gen_err);                        ret_err_free(gen_err, new);
   
                       if (option != 's' && prefstr)                        if (option != 's' && prefstr)
                         {                          {
                           if (!(new->prefix = canonicalise_opt(prefstr)) ||                            if (!(new->prefix = canonicalise_opt(prefstr)) ||
                               strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)                                strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
                            ret_err(_("bad prefix"));                            ret_err_free(_("bad prefix"), new);
                         }                          }
                     }                      }
   
Line 1997  static int one_opt(int option, char *arg, char *errstr Line 2377  static int one_opt(int option, char *arg, char *errstr
                     }                      }
                   else                    else
                     {                      {
                         char *star;
                       new->next = daemon->synth_domains;                        new->next = daemon->synth_domains;
                       daemon->synth_domains = new;                        daemon->synth_domains = new;
                         if (new->prefix &&
                             (star = strrchr(new->prefix, '*'))
                             && *(star+1) == 0)
                           {
                             *star = 0;
                             new->indexed = 1;
                           }
                     }                      }
                 }                  }
               else if (option == 's')                else if (option == 's')
Line 2009  static int one_opt(int option, char *arg, char *errstr Line 2397  static int one_opt(int option, char *arg, char *errstr
         }          }
       break;        break;
               
       case LOPT_CPE_ID: /* --add-dns-client */
         if (arg)
           daemon->dns_client_id = opt_string_alloc(arg);
         break;
   
       case LOPT_ADD_MAC: /* --add-mac */
         if (!arg)
           set_option_bool(OPT_ADD_MAC);
         else
           {
             unhide_metas(arg);
             if (strcmp(arg, "base64") == 0)
               set_option_bool(OPT_MAC_B64);
             else if (strcmp(arg, "text") == 0)
               set_option_bool(OPT_MAC_HEX);
             else
               ret_err(gen_err);
           }
         break;
   
     case 'u':  /* --user */      case 'u':  /* --user */
       daemon->username = opt_string_alloc(arg);        daemon->username = opt_string_alloc(arg);
       break;        break;
Line 2070  static int one_opt(int option, char *arg, char *errstr Line 2478  static int one_opt(int option, char *arg, char *errstr
       break;        break;
               
     case 'B':  /* --bogus-nxdomain */      case 'B':  /* --bogus-nxdomain */
      {    case LOPT_IGNORE_ADDR: /* --ignore-address */
      {
         struct in_addr addr;          struct in_addr addr;
         unhide_metas(arg);          unhide_metas(arg);
         if (arg && (inet_pton(AF_INET, arg, &addr) > 0))          if (arg && (inet_pton(AF_INET, arg, &addr) > 0))
           {            {
             struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));              struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
            baddr->next = daemon->bogus_addr;            if (option == 'B')
            daemon->bogus_addr = baddr;              {
                 baddr->next = daemon->bogus_addr;
                 daemon->bogus_addr = baddr;
               }
             else
               {
                 baddr->next = daemon->ignore_addr;
                 daemon->ignore_addr = baddr;
               }
             baddr->addr = addr;              baddr->addr = addr;
           }            }
         else          else
Line 2099  static int one_opt(int option, char *arg, char *errstr Line 2516  static int one_opt(int option, char *arg, char *errstr
             new->addr.in.sin_len = sizeof(new->addr.in);              new->addr.in.sin_len = sizeof(new->addr.in);
 #endif  #endif
           }            }
 #ifdef HAVE_IPV6  
         else if (arg && inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)          else if (arg && inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
           {            {
             new->addr.sa.sa_family = AF_INET6;              new->addr.sa.sa_family = AF_INET6;
Line 2110  static int one_opt(int option, char *arg, char *errstr Line 2526  static int one_opt(int option, char *arg, char *errstr
             new->addr.in6.sin6_len = sizeof(new->addr.in6);              new->addr.in6.sin6_len = sizeof(new->addr.in6);
 #endif  #endif
           }            }
 #endif  
         else          else
          ret_err(gen_err);          ret_err_free(gen_err, new);
   
         new->used = 0;          new->used = 0;
         if (option == 'a')          if (option == 'a')
Line 2153  static int one_opt(int option, char *arg, char *errstr Line 2568  static int one_opt(int option, char *arg, char *errstr
                 if (strcmp(arg, "#") == 0)                  if (strcmp(arg, "#") == 0)
                   domain = "";                    domain = "";
                 else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))                  else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
                  option = '?';                  ret_err(gen_err);
                 serv = opt_malloc(sizeof(struct server));                  serv = opt_malloc(sizeof(struct server));
                 memset(serv, 0, sizeof(struct server));                  memset(serv, 0, sizeof(struct server));
                 serv->next = newlist;                  serv->next = newlist;
Line 2171  static int one_opt(int option, char *arg, char *errstr Line 2586  static int one_opt(int option, char *arg, char *errstr
           {            {
             newlist = opt_malloc(sizeof(struct server));              newlist = opt_malloc(sizeof(struct server));
             memset(newlist, 0, sizeof(struct server));              memset(newlist, 0, sizeof(struct server));
   #ifdef HAVE_LOOP
               newlist->uid = rand32();
   #endif
           }            }
                   
         if (servers_only && option == 'S')          if (servers_only && option == 'S')
Line 2180  static int one_opt(int option, char *arg, char *errstr Line 2598  static int one_opt(int option, char *arg, char *errstr
           {            {
             newlist->flags |= SERV_LITERAL_ADDRESS;              newlist->flags |= SERV_LITERAL_ADDRESS;
             if (!(newlist->flags & SERV_TYPE))              if (!(newlist->flags & SERV_TYPE))
              ret_err(gen_err);              {
                 server_list_free(newlist);
                 ret_err(gen_err);
               }
           }            }
         else if (option == LOPT_NO_REBIND)          else if (option == LOPT_NO_REBIND)
           newlist->flags |= SERV_NO_REBIND;            newlist->flags |= SERV_NO_REBIND;
Line 2189  static int one_opt(int option, char *arg, char *errstr Line 2610  static int one_opt(int option, char *arg, char *errstr
           {            {
             if (!(newlist->flags & SERV_NO_REBIND))              if (!(newlist->flags & SERV_NO_REBIND))
               newlist->flags |= SERV_NO_ADDR; /* no server */                newlist->flags |= SERV_NO_ADDR; /* no server */
             if (newlist->flags & SERV_LITERAL_ADDRESS)  
               ret_err(gen_err);  
           }            }
   
         else if (strcmp(arg, "#") == 0)          else if (strcmp(arg, "#") == 0)
          {          newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
            newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */ 
            if (newlist->flags & SERV_LITERAL_ADDRESS) 
              ret_err(gen_err); 
          } 
         else          else
           {            {
             char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);              char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
             if (err)              if (err)
              ret_err(err);              {
                 server_list_free(newlist);
                 ret_err(err);
               }
           }            }
                   
         serv = newlist;          serv = newlist;
         while (serv->next)          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->addr = serv->addr;
             serv->next->source_addr = serv->source_addr;              serv->next->source_addr = serv->source_addr;
             strcpy(serv->next->interface, serv->interface);              strcpy(serv->next->interface, serv->interface);
Line 2226  static int one_opt(int option, char *arg, char *errstr Line 2644  static int one_opt(int option, char *arg, char *errstr
         int size;          int size;
         struct server *serv;          struct server *serv;
         struct in_addr addr4;          struct in_addr addr4;
 #ifdef HAVE_IPV6  
         struct in6_addr addr6;          struct in6_addr addr6;
 #endif  
     
         unhide_metas(arg);          unhide_metas(arg);
        if (!arg || !(comma=split(arg)) || !(string = split_chr(arg, '/')) || !atoi_check(string, &size))        if (!arg)
           ret_err(gen_err);            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))          if (inet_pton(AF_INET, arg, &addr4))
          serv = add_rev4(addr4, size);          {
#ifdef HAVE_IPV6            serv = add_rev4(addr4, size);
             if (!serv)
               ret_err(_("bad prefix"));
           }
         else if (inet_pton(AF_INET6, arg, &addr6))          else if (inet_pton(AF_INET6, arg, &addr6))
           serv = add_rev6(&addr6, size);            serv = add_rev6(&addr6, size);
 #endif  
         else          else
           ret_err(gen_err);            ret_err(gen_err);
     
Line 2280  static int one_opt(int option, char *arg, char *errstr Line 2703  static int one_opt(int option, char *arg, char *errstr
                  if (strcmp(arg, "#") == 0 || !*arg)                   if (strcmp(arg, "#") == 0 || !*arg)
                    domain = "";                     domain = "";
                  else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg)))                   else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg)))
                   option = '?';                   ret_err(gen_err);
                  ipsets->next = opt_malloc(sizeof(struct ipsets));                   ipsets->next = opt_malloc(sizeof(struct ipsets));
                  ipsets = ipsets->next;                   ipsets = ipsets->next;
                  memset(ipsets, 0, sizeof(struct ipsets));                   memset(ipsets, 0, sizeof(struct ipsets));
Line 2295  static int one_opt(int option, char *arg, char *errstr Line 2718  static int one_opt(int option, char *arg, char *errstr
              memset(ipsets, 0, sizeof(struct ipsets));               memset(ipsets, 0, sizeof(struct ipsets));
              ipsets->domain = "";               ipsets->domain = "";
            }             }
            
          if (!arg || !*arg)           if (!arg || !*arg)
           {           ret_err(gen_err);
             option = '?';         
             break;         for (size = 2, end = arg; *end; ++end) 
           } 
         size = 2; 
         for (end = arg; *end; ++end)  
            if (*end == ',')             if (*end == ',')
                ++size;                 ++size;
             
Line 2334  static int one_opt(int option, char *arg, char *errstr Line 2755  static int one_opt(int option, char *arg, char *errstr
                           
             if (size < 0)              if (size < 0)
               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;              daemon->cachesize = size;
           }            }
Line 2352  static int one_opt(int option, char *arg, char *errstr Line 2779  static int one_opt(int option, char *arg, char *errstr
         ret_err(gen_err);          ret_err(gen_err);
       break;        break;
   
       case LOPT_MAXPORT:  /* --max-port */
         if (!atoi_check16(arg, &daemon->max_port))
           ret_err(gen_err);
         break;
   
     case '0':  /* --dns-forward-max */      case '0':  /* --dns-forward-max */
       if (!atoi_check(arg, &daemon->ftabsize))        if (!atoi_check(arg, &daemon->ftabsize))
         ret_err(gen_err);          ret_err(gen_err);
       break;          break;  
           
       case 'q': /* --log-queries */
         set_option_bool(OPT_LOG);
         if (arg && strcmp(arg, "extra") == 0)
           set_option_bool(OPT_EXTRALOG);
         break;
   
     case LOPT_MAX_LOGS:  /* --log-async */      case LOPT_MAX_LOGS:  /* --log-async */
       daemon->max_logs = LOG_MAX; /* default */        daemon->max_logs = LOG_MAX; /* default */
       if (arg && !atoi_check(arg, &daemon->max_logs))        if (arg && !atoi_check(arg, &daemon->max_logs))
Line 2386  static int one_opt(int option, char *arg, char *errstr Line 2824  static int one_opt(int option, char *arg, char *errstr
     case 'T':         /* --local-ttl */      case 'T':         /* --local-ttl */
     case LOPT_NEGTTL: /* --neg-ttl */      case LOPT_NEGTTL: /* --neg-ttl */
     case LOPT_MAXTTL: /* --max-ttl */      case LOPT_MAXTTL: /* --max-ttl */
       case LOPT_MINCTTL: /* --min-cache-ttl */
     case LOPT_MAXCTTL: /* --max-cache-ttl */      case LOPT_MAXCTTL: /* --max-cache-ttl */
     case LOPT_AUTHTTL: /* --auth-ttl */      case LOPT_AUTHTTL: /* --auth-ttl */
       case LOPT_DHCPTTL: /* --dhcp-ttl */
       {        {
         int ttl;          int ttl;
         if (!atoi_check(arg, &ttl))          if (!atoi_check(arg, &ttl))
Line 2396  static int one_opt(int option, char *arg, char *errstr Line 2836  static int one_opt(int option, char *arg, char *errstr
           daemon->neg_ttl = (unsigned long)ttl;            daemon->neg_ttl = (unsigned long)ttl;
         else if (option == LOPT_MAXTTL)          else if (option == LOPT_MAXTTL)
           daemon->max_ttl = (unsigned long)ttl;            daemon->max_ttl = (unsigned long)ttl;
           else if (option == LOPT_MINCTTL)
             {
               if (ttl > TTL_FLOOR_LIMIT)
                 ttl = TTL_FLOOR_LIMIT;
               daemon->min_cache_ttl = (unsigned long)ttl;
             }
         else if (option == LOPT_MAXCTTL)          else if (option == LOPT_MAXCTTL)
           daemon->max_cache_ttl = (unsigned long)ttl;            daemon->max_cache_ttl = (unsigned long)ttl;
         else if (option == LOPT_AUTHTTL)          else if (option == LOPT_AUTHTTL)
           daemon->auth_ttl = (unsigned long)ttl;            daemon->auth_ttl = (unsigned long)ttl;
           else if (option == LOPT_DHCPTTL)
             {
               daemon->dhcp_ttl = (unsigned long)ttl;
               daemon->use_dhcp_ttl = 1;
             }
         else          else
           daemon->local_ttl = (unsigned long)ttl;            daemon->local_ttl = (unsigned long)ttl;
         break;          break;
Line 2418  static int one_opt(int option, char *arg, char *errstr Line 2869  static int one_opt(int option, char *arg, char *errstr
         ret_err(gen_err);          ret_err(gen_err);
       break;          break;  
   
       case LOPT_TFTP_MTU:  /*  --tftp-mtu */
         if (!atoi_check(arg, &daemon->tftp_mtu))
           ret_err(gen_err);
         break;
   
     case LOPT_PREFIX: /* --tftp-prefix */      case LOPT_PREFIX: /* --tftp-prefix */
       comma = split(arg);        comma = split(arg);
       if (comma)        if (comma)
Line 2446  static int one_opt(int option, char *arg, char *errstr Line 2902  static int one_opt(int option, char *arg, char *errstr
         }           } 
               
       break;        break;
   
       case LOPT_APREF: /* --tftp-unique-root */
         if (!arg || strcasecmp(arg, "ip") == 0)
           set_option_bool(OPT_TFTP_APREF_IP);
         else if (strcasecmp(arg, "mac") == 0)
           set_option_bool(OPT_TFTP_APREF_MAC);
         else
           ret_err(gen_err);
         break;
 #endif  #endif
                               
     case LOPT_BRIDGE:   /* --bridge-interface */      case LOPT_BRIDGE:   /* --bridge-interface */
       {        {
        struct dhcp_bridge *new = opt_malloc(sizeof(struct dhcp_bridge));        struct dhcp_bridge *new;
 
         if (!(comma = split(arg)) || strlen(arg) > IF_NAMESIZE - 1 )          if (!(comma = split(arg)) || strlen(arg) > IF_NAMESIZE - 1 )
           ret_err(_("bad bridge-interface"));            ret_err(_("bad bridge-interface"));
           
         strcpy(new->iface, arg);  
         new->alias = NULL;  
         new->next = daemon->bridges;  
         daemon->bridges = new;  
   
           for (new = daemon->bridges; new; new = new->next)
             if (strcmp(new->iface, arg) == 0)
               break;
   
           if (!new)
             {
                new = opt_malloc(sizeof(struct dhcp_bridge));
                strcpy(new->iface, arg);
                new->alias = NULL;
                new->next = daemon->bridges;
                daemon->bridges = new;
             }
           
         do {          do {
           arg = comma;            arg = comma;
           comma = split(arg);            comma = split(arg);
Line 2475  static int one_opt(int option, char *arg, char *errstr Line 2949  static int one_opt(int option, char *arg, char *errstr
       }        }
   
 #ifdef HAVE_DHCP  #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 */      case 'F':  /* --dhcp-range */
       {        {
         int k, leasepos = 2;          int k, leasepos = 2;
Line 2482  static int one_opt(int option, char *arg, char *errstr Line 2994  static int one_opt(int option, char *arg, char *errstr
         struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));          struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
                   
         memset (new, 0, sizeof(*new));          memset (new, 0, sizeof(*new));
         new->lease_time = DEFLEASE;  
                   
         if (!arg)  
           {  
             option = '?';  
             break;  
           }  
           
         while(1)          while(1)
           {            {
             for (cp = arg; *cp; cp++)              for (cp = arg; *cp; cp++)
Line 2502  static int one_opt(int option, char *arg, char *errstr Line 3007  static int one_opt(int option, char *arg, char *errstr
               {                {
                 if (is_tag_prefix(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 */                      /* ignore empty tag */
                    if (tt->net)                    if (arg[4])
                      new->filter = tt;                      new->filter = dhcp_netid_create(arg+4, new->filter);
                   }                    }
                 else                  else
                   {                    {
                     if (new->netid.net)                      if (new->netid.net)
                      ret_err(_("only one tag allowed"));                      {
                    else if (strstr(arg, "set:") == arg)                        dhcp_context_free(new);
                      new->netid.net = opt_string_alloc(arg+4);                        ret_err(_("only one tag allowed"));
                       }
                     else                      else
                      new->netid.net = opt_string_alloc(arg);                      new->netid.net = opt_string_alloc(set_prefix(arg));
                   }                    }
                 arg = comma;                  arg = comma;
               }                }
Line 2532  static int one_opt(int option, char *arg, char *errstr Line 3035  static int one_opt(int option, char *arg, char *errstr
             break;              break;
                   
         if (k < 2)          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))          if (inet_pton(AF_INET, a[0], &new->start))
           {            {
             new->next = daemon->dhcp;              new->next = daemon->dhcp;
               new->lease_time = DEFLEASE;
             daemon->dhcp = new;              daemon->dhcp = new;
             new->end = new->start;              new->end = new->start;
             if (strcmp(a[1], "static") == 0)              if (strcmp(a[1], "static") == 0)
Line 2544  static int one_opt(int option, char *arg, char *errstr Line 3051  static int one_opt(int option, char *arg, char *errstr
             else if (strcmp(a[1], "proxy") == 0)              else if (strcmp(a[1], "proxy") == 0)
               new->flags |= CONTEXT_PROXY;                new->flags |= CONTEXT_PROXY;
             else if (!inet_pton(AF_INET, a[1], &new->end))              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))              if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
               {                {
Line 2559  static int one_opt(int option, char *arg, char *errstr Line 3069  static int one_opt(int option, char *arg, char *errstr
                 new->flags |= CONTEXT_NETMASK;                  new->flags |= CONTEXT_NETMASK;
                 leasepos = 3;                  leasepos = 3;
                 if (!is_same_net(new->start, new->end, new->netmask))                  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], '.') &&                  if (k >= 4 && strchr(a[3], '.') &&  
                (inet_pton(AF_INET, a[3], &new->broadcast) > 0))                    (inet_pton(AF_INET, a[3], &new->broadcast) > 0))
              {                  {
                new->flags |= CONTEXT_BRDCAST;                    new->flags |= CONTEXT_BRDCAST;
                leasepos = 4;                    leasepos = 4;
                   }
               }                }
           }            }
 #ifdef HAVE_DHCP6  #ifdef HAVE_DHCP6
         else if (inet_pton(AF_INET6, a[0], &new->start6))          else if (inet_pton(AF_INET6, a[0], &new->start6))
           {            {
               const char *err = NULL;
   
             new->flags |= CONTEXT_V6;               new->flags |= CONTEXT_V6; 
             new->prefix = 64; /* default */              new->prefix = 64; /* default */
             new->end6 = new->start6;              new->end6 = new->start6;
               new->lease_time = DEFLEASE6;
             new->next = daemon->dhcp6;              new->next = daemon->dhcp6;
             daemon->dhcp6 = new;              daemon->dhcp6 = new;
   
Line 2583  static int one_opt(int option, char *arg, char *errstr Line 3100  static int one_opt(int option, char *arg, char *errstr
                 if (strcmp(a[leasepos], "static") == 0)                  if (strcmp(a[leasepos], "static") == 0)
                   new->flags |= CONTEXT_STATIC | CONTEXT_DHCP;                    new->flags |= CONTEXT_STATIC | CONTEXT_DHCP;
                 else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 )                  else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 )
                  new->flags |= CONTEXT_RA_ONLY | CONTEXT_RA;                  new->flags |= CONTEXT_RA;
                 else if (strcmp(a[leasepos], "ra-names") == 0)                  else if (strcmp(a[leasepos], "ra-names") == 0)
                   new->flags |= CONTEXT_RA_NAME | CONTEXT_RA;                    new->flags |= CONTEXT_RA_NAME | CONTEXT_RA;
                   else if (strcmp(a[leasepos], "ra-advrouter") == 0)
                     new->flags |= CONTEXT_RA_ROUTER | CONTEXT_RA;
                 else if (strcmp(a[leasepos], "ra-stateless") == 0)                  else if (strcmp(a[leasepos], "ra-stateless") == 0)
                   new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA;                    new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA;
                   else if (strcmp(a[leasepos], "off-link") == 0)
                     new->flags |= CONTEXT_RA_OFF_LINK;
                 else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6))                  else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6))
                   new->flags |= CONTEXT_DHCP;                     new->flags |= CONTEXT_DHCP; 
                 else if (strstr(a[leasepos], "constructor:") == a[leasepos])                  else if (strstr(a[leasepos], "constructor:") == a[leasepos])
Line 2613  static int one_opt(int option, char *arg, char *errstr Line 3134  static int one_opt(int option, char *arg, char *errstr
                   }                    }
               }                }
                           
            if (new->prefix != 64)            if (new->prefix > 64)
               {                {
                if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))                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)                  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"));
               }                }
            else if (new->prefix < 64)
            if (new->prefix < 64)              err=(_("prefix length must be at least 64"));
              ret_err(_("prefix length must be at least 64")); 
                           
            if (!is_same_net6(&new->start6, &new->end6, new->prefix))            if (!err && !is_same_net6(&new->start6, &new->end6, new->prefix))
              ret_err(_("inconsistent DHCPv6 range"));              err=(_("inconsistent DHCPv6 range"));
   
               if (err)
                 {
                   dhcp_context_free(new);
                   ret_err(err);
                 }
   
             /* dhcp-range=:: enables DHCP stateless on any interface */              /* dhcp-range=:: enables DHCP stateless on any interface */
             if (IN6_IS_ADDR_UNSPECIFIED(&new->start6) && !(new->flags & CONTEXT_TEMPLATE))              if (IN6_IS_ADDR_UNSPECIFIED(&new->start6) && !(new->flags & CONTEXT_TEMPLATE))
               new->prefix = 0;                new->prefix = 0;
Line 2636  static int one_opt(int option, char *arg, char *errstr Line 3162  static int one_opt(int option, char *arg, char *errstr
                 struct in6_addr zero;                  struct in6_addr zero;
                 memset(&zero, 0, sizeof(zero));                  memset(&zero, 0, sizeof(zero));
                 if (!is_same_net6(&zero, &new->start6, new->prefix))                  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))              if (addr6part(&new->start6) > addr6part(&new->end6))
Line 2648  static int one_opt(int option, char *arg, char *errstr Line 3177  static int one_opt(int option, char *arg, char *errstr
           }            }
 #endif  #endif
         else          else
          ret_err(_("bad dhcp-range"));          {
             dhcp_context_free(new);
             ret_err(_("bad dhcp-range"));
           }
                   
         if (leasepos < k)          if (leasepos < k)
           {            {
               if (leasepos != k-1)
                 {
                   dhcp_context_free(new);
                   ret_err(_("bad dhcp-range"));
                 }
               
             if (strcmp(a[leasepos], "infinite") == 0)              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)              else if (strcmp(a[leasepos], "deprecated") == 0)
               new->flags |= CONTEXT_DEPRECATE;                new->flags |= CONTEXT_DEPRECATE;
             else              else
Line 2670  static int one_opt(int option, char *arg, char *errstr Line 3211  static int one_opt(int option, char *arg, char *errstr
                       case 'd':                        case 'd':
                       case 'D':                        case 'D':
                         fac *= 24;                          fac *= 24;
                        /* fall though */                        /* fall through */
                       case 'h':                        case 'h':
                       case 'H':                        case 'H':
                         fac *= 60;                          fac *= 60;
Line 2689  static int one_opt(int option, char *arg, char *errstr Line 3230  static int one_opt(int option, char *arg, char *errstr
                         break;                          break;
   
                     if (*cp || (leasepos+1 < k))                      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->lease_time = atoi(a[leasepos]) * fac;
                       new->flags |= CONTEXT_SETLEASE;
                     /* Leases of a minute or less confuse                      /* Leases of a minute or less confuse
                        some clients, notably Apple's */                         some clients, notably Apple's */
                     if (new->lease_time < 120)                      if (new->lease_time < 120)
Line 2699  static int one_opt(int option, char *arg, char *errstr Line 3241  static int one_opt(int option, char *arg, char *errstr
                   }                    }
               }                }
           }            }
   
         break;          break;
       }        }
   
     case LOPT_BANK:      case LOPT_BANK:
     case 'G':  /* --dhcp-host */      case 'G':  /* --dhcp-host */
       {        {
         int j, k = 0;  
         char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };  
         struct dhcp_config *new;          struct dhcp_config *new;
         struct in_addr in;          struct in_addr in;
                   
Line 2716  static int one_opt(int option, char *arg, char *errstr Line 3257  static int one_opt(int option, char *arg, char *errstr
         new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;          new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
         new->hwaddr = NULL;          new->hwaddr = NULL;
         new->netid = NULL;          new->netid = NULL;
        new->filter = NULL;
        if ((a[0] = arg))        new->clid = NULL;
          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")); 
 #ifdef HAVE_DHCP6  #ifdef HAVE_DHCP6
              else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')        new->addr6 = NULL;
                {#endif
                  arg[strlen(arg)-1] = 0;
                  arg++;        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);
                                       
                  if (!inet_pton(AF_INET6, arg, &new->addr6))#ifdef HAVE_DHCP6
                    ret_err(_("bad IPv6 address"));                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"));
                       }
   
                  for (i= 0; i < 8; i++)                    new_addr = opt_malloc(sizeof(struct addrlist));
                    if (new->addr6.s6_addr[i] != 0)                    new_addr->next = new->addr6;
                      break;                    new_addr->flags = 0;
                    new_addr->addr.addr6 = in6;
                  /* set WILDCARD if network part all zeros */                    new->addr6 = new_addr;
                  if (i == 8)                    
                    new->flags |= CONFIG_WILDCARD;                    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  #endif
              else                else
                {                  {
                  struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));                    struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
                  if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,                     if ((newhw->hwaddr_len = parse_hex(arg, newhw->hwaddr, DHCP_CHADDR_MAX, 
                                                     &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)                                                       &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
                    ret_err(_("bad hex constant"));                      {
                  else                        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)
                     {                      {
                                            sprintf(errstr, _("duplicate dhcp-host IP address %s"),  inet_ntoa(in));
                      newhw->next = new->hwaddr;                      return 0;
                      new->hwaddr = newhw;                    }         
                    }                             }
                }            else
            }              {
          else if (strchr(a[j], '.') && (inet_pton(AF_INET, a[j], &in) > 0))                char *cp, *lastp = NULL, last = 0;
            {                int fac = 1, isdig = 0;
              struct dhcp_config *configs;                
                              if (strlen(arg) > 1)
              new->addr = in;                  {
              new->flags |= CONFIG_ADDR;                    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 the same IP appears in more than one host config, then DISCOVER                if (*cp)
                 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) 
                   {                    {
                    sprintf(errstr, _("duplicate dhcp-host IP address %s"),  inet_ntoa(in));                    if (lastp)
                    return 0;                      *lastp = last;
                  }                               if (strcmp(arg, "infinite") == 0)
            }                      {
          else                        new->lease_time = 0xffffffff;
            {                        new->flags |= CONFIG_TIME;
              char *cp, *lastp = NULL, last = 0;                      }
              int fac = 1, isdig = 0;                    else if (strcmp(arg, "ignore") == 0)
                                    new->flags |= CONFIG_DISABLE;
              if (strlen(a[j]) > 1)                    else
                {                      {
                  lastp = a[j] + strlen(a[j]) - 1;                        if (!(new->hostname = canonicalise_opt(arg)) ||
                  last = *lastp;                            !legal_hostname(new->hostname))
                  switch (last)                          {
                    {                            dhcp_config_free(new);
                    case 'w':                            ret_err(_("bad DHCP host name"));
                    case 'W':                          }
                      fac *= 7;                        
                      /* fall through */                        new->flags |= CONFIG_NAME;
                    case 'd':                        new->domain = strip_hostname(new->hostname);                    
                    case 'D':                      }
                      fac *= 24;                  }
                      /* fall through */                else if (isdig)
                    case 'h':                  {
                    case 'H':                    new->lease_time = atoi(arg) * fac; 
                      fac *= 60;                    /* Leases of a minute or less confuse
                      /* fall through */                       some clients, notably Apple's */
                    case 'm':                    if (new->lease_time < 120)
                    case 'M':                      new->lease_time = 120;
                      fac *= 60;                    new->flags |= CONFIG_TIME;
                      /* 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; 
   
              if (*cp)            arg = comma;
                {          }
                  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;          daemon->dhcp_conf = new;
         break;          break;
       }        }
      
     case LOPT_TAG_IF:  /* --tag-if */      case LOPT_TAG_IF:  /* --tag-if */
       {        {
         struct tag_if *new = opt_malloc(sizeof(struct tag_if));          struct tag_if *new = opt_malloc(sizeof(struct tag_if));
Line 2928  static int one_opt(int option, char *arg, char *errstr Line 3506  static int one_opt(int option, char *arg, char *errstr
               }                }
             else              else
               {                {
                struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));                struct dhcp_netid *newtag = dhcp_netid_create(arg+4, NULL);
                newtag->net = opt_malloc(len - 3); 
                strcpy(newtag->net, arg+4); 
                unhide_metas(newtag->net); 
   
                 if (strstr(arg, "set:") == arg)                  if (strstr(arg, "set:") == arg)
                   {                    {
Line 2948  static int one_opt(int option, char *arg, char *errstr Line 3523  static int one_opt(int option, char *arg, char *errstr
                 else                   else 
                   {                    {
                     new->set = NULL;                      new->set = NULL;
                    free(newtag);                    dhcp_netid_free(newtag);
                     break;                      break;
                   }                    }
               }                }
Line 2957  static int one_opt(int option, char *arg, char *errstr Line 3532  static int one_opt(int option, char *arg, char *errstr
           }            }
   
         if (!new->set)          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;          break;
       }        }
Line 2971  static int one_opt(int option, char *arg, char *errstr Line 3550  static int one_opt(int option, char *arg, char *errstr
                             option == LOPT_FORCE ? DHOPT_FORCE :                               option == LOPT_FORCE ? DHOPT_FORCE : 
                             (option == LOPT_MATCH ? DHOPT_MATCH :                              (option == LOPT_MATCH ? DHOPT_MATCH :
                              (option == LOPT_OPTS ? DHOPT_BANK : 0)));                               (option == LOPT_OPTS ? DHOPT_BANK : 0)));
     
    case 'M': /* --dhcp-boot */    case LOPT_NAME_MATCH: /* --dhcp-name-match */
       {        {
        struct dhcp_netid *id = NULL;        struct dhcp_match_name *new = opt_malloc(sizeof(struct dhcp_match_name));
        while (is_tag_prefix(arg))        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));            comma[len-1] = 0;
            newid->next = id;            new->wildcard = 1;
            id = newid;          }
            comma = split(arg);        new->name = opt_string_alloc(comma);
            newid->net = opt_string_alloc(arg+4);
            arg = 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)          if (!arg)
          ret_err(gen_err);          {
             ret_err(gen_err);
           }
         else           else 
           {            {
             char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL;              char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL;
Line 3030  static int one_opt(int option, char *arg, char *errstr Line 3628  static int one_opt(int option, char *arg, char *errstr
         break;          break;
       }        }
   
       case LOPT_REPLY_DELAY: /* --dhcp-reply-delay */
         {
           struct dhcp_netid *id = dhcp_tags(&arg);
           
           if (!arg)
             {
               ret_err(gen_err);
             }
           else
             {
               struct delay_config *new;
               int delay;
               if (!atoi_check(arg, &delay))
                 ret_err(gen_err);
               
               new = opt_malloc(sizeof(struct delay_config));
               new->delay = delay;
               new->netid = id;
               new->next = daemon->delay_conf;
               daemon->delay_conf = new;
             }
           
           break;
         }
         
     case LOPT_PXE_PROMT:  /* --pxe-prompt */      case LOPT_PXE_PROMT:  /* --pxe-prompt */
        {         {
          struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));           struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
          int timeout;           int timeout;
         
          new->netid = NULL;           new->netid = NULL;
          new->opt = 10; /* PXE_MENU_PROMPT */           new->opt = 10; /* PXE_MENU_PROMPT */
         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)           if (!arg)
           ret_err(gen_err);           {
              dhcp_opt_free(new);
              ret_err(gen_err);
            }
          else           else
            {             {
              comma = split(arg);               comma = split(arg);
Line 3058  static int one_opt(int option, char *arg, char *errstr Line 3675  static int one_opt(int option, char *arg, char *errstr
              new->val = opt_malloc(new->len);               new->val = opt_malloc(new->len);
              memcpy(new->val + 1, arg, new->len - 1);               memcpy(new->val + 1, arg, new->len - 1);
                             
             new->u.vendor_class = (unsigned char *)"PXEClient";             new->u.vendor_class = NULL;
             new->flags = DHOPT_VENDOR;             new->flags = DHOPT_VENDOR | DHOPT_VENDOR_PXE;
                             
              if (comma && atoi_check(comma, &timeout))               if (comma && atoi_check(comma, &timeout))
                *(new->val) = timeout;                 *(new->val) = timeout;
Line 3078  static int one_opt(int option, char *arg, char *errstr Line 3695  static int one_opt(int option, char *arg, char *errstr
        {         {
          struct pxe_service *new = opt_malloc(sizeof(struct pxe_service));           struct pxe_service *new = opt_malloc(sizeof(struct pxe_service));
          char *CSA[] = { "x86PC", "PC98", "IA64_EFI", "Alpha", "Arc_x86", "Intel_Lean_Client",           char *CSA[] = { "x86PC", "PC98", "IA64_EFI", "Alpha", "Arc_x86", "Intel_Lean_Client",
                         "IA32_EFI", "BC_EFI", "Xscale_EFI", "x86-64_EFI", NULL };                           "IA32_EFI", "x86-64_EFI", "Xscale_EFI", "BC_EFI",
                          "ARM32_EFI", "ARM64_EFI", NULL };  
          static int boottype = 32768;           static int boottype = 32768;
                     
          new->netid = NULL;           new->netid = NULL;
          new->sname = NULL;           new->sname = NULL;
          new->server.s_addr = 0;           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)))           if (arg && (comma = split(arg)))
            {             {
              for (i = 0; CSA[i]; i++)               for (i = 0; CSA[i]; i++)
Line 3171  static int one_opt(int option, char *arg, char *errstr Line 3780  static int one_opt(int option, char *arg, char *errstr
             unhide_metas(comma);              unhide_metas(comma);
             new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);              new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
             if (new->hwaddr_len == -1)              if (new->hwaddr_len == -1)
              ret_err(gen_err);              {
                 free(new->netid.net);
                 ret_err_free(gen_err, new);
               }
             else              else
               {                {
                 new->next = daemon->dhcp_macs;                  new->next = daemon->dhcp_macs;
Line 3181  static int one_opt(int option, char *arg, char *errstr Line 3793  static int one_opt(int option, char *arg, char *errstr
       }        }
       break;        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 'U':           /* --dhcp-vendorclass */
     case 'j':           /* --dhcp-userclass */      case 'j':           /* --dhcp-userclass */
     case LOPT_CIRCUIT:  /* --dhcp-circuitid */      case LOPT_CIRCUIT:  /* --dhcp-circuitid */
Line 3210  static int one_opt(int option, char *arg, char *errstr Line 3804  static int one_opt(int option, char *arg, char *errstr
          struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));           struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
                     
          if (!(comma = split(arg)))           if (!(comma = split(arg)))
           ret_err(gen_err);           ret_err_free(gen_err, new);
                   
          new->netid.net = opt_string_alloc(set_prefix(arg));           new->netid.net = opt_string_alloc(set_prefix(arg));
          /* check for hex string - must digits may include : must not have nothing else,            /* check for hex string - must digits may include : must not have nothing else, 
Line 3220  static int one_opt(int option, char *arg, char *errstr Line 3814  static int one_opt(int option, char *arg, char *errstr
          if ((comma = split(arg)))           if ((comma = split(arg)))
            {             {
              if (option  != 'U' || strstr(arg, "enterprise:") != arg)               if (option  != 'U' || strstr(arg, "enterprise:") != arg)
               ret_err(gen_err);               {
                  free(new->netid.net);
                  ret_err_free(gen_err, new);
                }
              else               else
                new->enterprise = atoi(arg+11);                 new->enterprise = atoi(arg+11);
            }             }
Line 3322  static int one_opt(int option, char *arg, char *errstr Line 3919  static int one_opt(int option, char *arg, char *errstr
           }            }
                   
         while (arg) {          while (arg) {
           struct dhcp_netid *member = opt_malloc(sizeof(struct dhcp_netid));  
           comma = split(arg);            comma = split(arg);
          member->next = list;          list = dhcp_netid_create(is_tag_prefix(arg) ? arg+4 :arg, list);
          list = member; 
          if (is_tag_prefix(arg)) 
            member->net = opt_string_alloc(arg+4); 
          else 
            member->net = opt_string_alloc(arg); 
           arg = comma;            arg = comma;
         }          }
                   
Line 3343  static int one_opt(int option, char *arg, char *errstr Line 3934  static int one_opt(int option, char *arg, char *errstr
         struct addr_list *new = opt_malloc(sizeof(struct addr_list));          struct addr_list *new = opt_malloc(sizeof(struct addr_list));
         comma = split(arg);          comma = split(arg);
         if (!(inet_pton(AF_INET, arg, &new->addr) > 0))          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;          new->next = daemon->override_relays;
         daemon->override_relays = new;          daemon->override_relays = new;
         arg = comma;          arg = comma;
           }
             break;
   
       case LOPT_PXE_VENDOR: /* --dhcp-pxe-vendor */
         {
           while (arg) {
             struct dhcp_pxe_vendor *new = opt_malloc(sizeof(struct dhcp_pxe_vendor));
             comma = split(arg);
             new->data = opt_string_alloc(arg);
             new->next = daemon->dhcp_pxe_vendors;
             daemon->dhcp_pxe_vendors = new;
             arg = comma;
           }
       }        }
       break;        break;
   
Line 3369  static int one_opt(int option, char *arg, char *errstr Line 3973  static int one_opt(int option, char *arg, char *errstr
           }            }
 #endif  #endif
         else          else
          ret_err(_("Bad dhcp-relay"));          {
             free(new->interface);
             ret_err_free(_("Bad dhcp-relay"), new);
           }
                   
         break;          break;
       }        }
Line 3383  static int one_opt(int option, char *arg, char *errstr Line 3990  static int one_opt(int option, char *arg, char *errstr
           struct ra_interface *new = opt_malloc(sizeof(struct ra_interface));            struct ra_interface *new = opt_malloc(sizeof(struct ra_interface));
           new->lifetime = -1;            new->lifetime = -1;
           new->prio = 0;            new->prio = 0;
             new->mtu = 0;
             new->mtu_name = NULL;
           new->name = opt_string_alloc(arg);            new->name = opt_string_alloc(arg);
             if (strcasestr(comma, "mtu:") == comma)
               {
                 arg = comma + 4;
                 if (!(comma = split(comma)))
                   goto err;
                 if (!strcasecmp(arg, "off"))
                   new->mtu = -1;
                 else if (!atoi_check(arg, &new->mtu))
                   new->mtu_name = opt_string_alloc(arg);
                 else if (new->mtu < 1280)
                   goto err;
               }
           if (strcasestr(comma, "high") == comma || strcasestr(comma, "low") == comma)            if (strcasestr(comma, "high") == comma || strcasestr(comma, "low") == comma)
             {              {
               if (*comma == 'l' || *comma == 'L')                if (*comma == 'l' || *comma == 'L')
Line 3395  static int one_opt(int option, char *arg, char *errstr Line 4016  static int one_opt(int option, char *arg, char *errstr
            arg = split(comma);             arg = split(comma);
            if (!atoi_check(comma, &new->interval) ||              if (!atoi_check(comma, &new->interval) || 
               (arg && !atoi_check(arg, &new->lifetime)))                (arg && !atoi_check(arg, &new->lifetime)))
            ret_err(_("bad RA-params"));             {
 err:
                free(new->name);
                ret_err_free(_("bad RA-params"), new);
              }
                       
           new->next = daemon->ra_interfaces;            new->next = daemon->ra_interfaces;
           daemon->ra_interfaces = new;            daemon->ra_interfaces = new;
Line 3436  static int one_opt(int option, char *arg, char *errstr Line 4061  static int one_opt(int option, char *arg, char *errstr
   
         if ((k < 2) ||           if ((k < 2) || 
             (!(inet_pton(AF_INET, a[0], &new->in) > 0)) ||              (!(inet_pton(AF_INET, a[0], &new->in) > 0)) ||
            (!(inet_pton(AF_INET, a[1], &new->out) > 0)))            (!(inet_pton(AF_INET, a[1], &new->out) > 0)) ||
          option = '?';            (k == 3 && !inet_pton(AF_INET, a[2], &new->mask)))
           ret_err(_("missing address in alias"));
                   
         if (k == 3)  
           inet_pton(AF_INET, a[2], &new->mask);  
           
         if (dash &&           if (dash && 
             (!(inet_pton(AF_INET, dash, &new->end) > 0) ||              (!(inet_pton(AF_INET, dash, &new->end) > 0) ||
              !is_same_net(new->in, new->end, new->mask) ||               !is_same_net(new->in, new->end, new->mask) ||
              ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))               ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
          ret_err(_("invalid alias range"));          ret_err_free(_("invalid alias range"), new);
                   
         break;          break;
       }        }
Line 3476  static int one_opt(int option, char *arg, char *errstr Line 4099  static int one_opt(int option, char *arg, char *errstr
           {            {
             if (strcmp(arg, "4") == 0)              if (strcmp(arg, "4") == 0)
               new->family = AF_INET;                new->family = AF_INET;
 #ifdef HAVE_IPV6  
             else if (strcmp(arg, "6") == 0)              else if (strcmp(arg, "6") == 0)
               new->family = AF_INET6;                new->family = AF_INET6;
 #endif  
             else              else
              ret_err(gen_err);              ret_err_free(gen_err, new);
           }             } 
         new->intr = opt_string_alloc(comma);          new->intr = opt_string_alloc(comma);
         break;          break;
Line 3490  static int one_opt(int option, char *arg, char *errstr Line 4111  static int one_opt(int option, char *arg, char *errstr
     case LOPT_CNAME: /* --cname */      case LOPT_CNAME: /* --cname */
       {        {
         struct cname *new;          struct cname *new;
        char *alias;        char *alias, *target, *last, *pen;
        char *target;        int ttl = -1;
   
        if (!(comma = split(arg)))        for (last = pen = NULL, comma = arg; comma; comma = split(comma))
          ret_err(gen_err);          {
                    pen = last;
        alias = canonicalise_opt(arg);            last = comma;
        target = canonicalise_opt(comma);          }
            
        if (!alias || !target)        if (!pen)
           ret_err(_("bad CNAME"));            ret_err(_("bad CNAME"));
        else        
         if (pen != arg && atoi_check(last, &ttl))
           last = pen;
                 
         target = canonicalise_opt(last);
 
         while (arg != last)
           {            {
               int arglen = strlen(arg);
               alias = canonicalise_opt(arg);
   
               if (!alias || !target)
                 {
                   free(target);
                   free(alias);
                   ret_err(_("bad CNAME"));
                 }
               
             for (new = daemon->cnames; new; new = new->next)              for (new = daemon->cnames; new; new = new->next)
              if (hostname_isequal(new->alias, arg))              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 = opt_malloc(sizeof(struct cname));
             new->next = daemon->cnames;              new->next = daemon->cnames;
             daemon->cnames = new;              daemon->cnames = new;
             new->alias = alias;              new->alias = alias;
             new->target = target;              new->target = target;
               new->ttl = ttl;
   
               for (arg += arglen+1; *arg && isspace(*arg); arg++);
           }            }
               
         break;          break;
Line 3525  static int one_opt(int option, char *arg, char *errstr Line 4169  static int one_opt(int option, char *arg, char *errstr
                   
         if (!(dom = canonicalise_opt(arg)) ||          if (!(dom = canonicalise_opt(arg)) ||
             (comma && !(target = canonicalise_opt(comma))))              (comma && !(target = canonicalise_opt(comma))))
          ret_err(_("bad PTR record"));          {
             free(dom);
             free(target);
             ret_err(_("bad PTR record"));
           }
         else          else
           {            {
             new = opt_malloc(sizeof(struct ptr_record));              new = opt_malloc(sizeof(struct ptr_record));
Line 3543  static int one_opt(int option, char *arg, char *errstr Line 4191  static int one_opt(int option, char *arg, char *errstr
         int k = 0;          int k = 0;
         struct naptr *new;          struct naptr *new;
         int order, pref;          int order, pref;
        char *name, *replace = NULL;        char *name=NULL, *replace = NULL;
   
         if ((a[0] = arg))          if ((a[0] = arg))
           for (k = 1; k < 7; k++)            for (k = 1; k < 7; k++)
Line 3556  static int one_opt(int option, char *arg, char *errstr Line 4204  static int one_opt(int option, char *arg, char *errstr
             !atoi_check16(a[1], &order) ||               !atoi_check16(a[1], &order) || 
             !atoi_check16(a[2], &pref) ||              !atoi_check16(a[2], &pref) ||
             (k == 7 && !(replace = canonicalise_opt(a[6]))))              (k == 7 && !(replace = canonicalise_opt(a[6]))))
          ret_err(_("bad NAPTR record"));          {
             free(name);
             free(replace);
             ret_err(_("bad NAPTR record"));
           }
         else          else
           {            {
             new = opt_malloc(sizeof(struct naptr));              new = opt_malloc(sizeof(struct naptr));
Line 3576  static int one_opt(int option, char *arg, char *errstr Line 4228  static int one_opt(int option, char *arg, char *errstr
     case LOPT_RR: /* dns-rr */      case LOPT_RR: /* dns-rr */
       {        {
         struct txt_record *new;          struct txt_record *new;
        size_t len = len;        size_t len = 0;
         char *data;          char *data;
        int val;        int class;
   
         comma = split(arg);          comma = split(arg);
         data = split(comma);          data = split(comma);
                                   
         new = opt_malloc(sizeof(struct txt_record));          new = opt_malloc(sizeof(struct txt_record));
        new->next = daemon->rr;        new->name = NULL;
        daemon->rr = new; 
                   
        if (!atoi_check(comma, &val) ||         if (!atoi_check(comma, &class) || 
             !(new->name = canonicalise_opt(arg)) ||              !(new->name = canonicalise_opt(arg)) ||
             (data && (len = parse_hex(data, (unsigned char *)data, -1, NULL, NULL)) == -1U))              (data && (len = parse_hex(data, (unsigned char *)data, -1, NULL, NULL)) == -1U))
          ret_err(_("bad RR record"));          {
                            free(new->name);
        new->class = val;            ret_err_free(_("bad RR record"), new);
           }
 
         new->len = 0;          new->len = 0;
           new->class = class;
           new->next = daemon->rr;
           daemon->rr = new;
                   
         if (data)          if (data)
           {            {
            new->txt=opt_malloc(len);            new->txt = opt_malloc(len);
             new->len = len;              new->len = len;
             memcpy(new->txt, data, len);              memcpy(new->txt, data, len);
           }            }
Line 3605  static int one_opt(int option, char *arg, char *errstr Line 4261  static int one_opt(int option, char *arg, char *errstr
         break;          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 */      case 'Y':  /* --txt-record */
       {        {
         struct txt_record *new;          struct txt_record *new;
Line 3614  static int one_opt(int option, char *arg, char *errstr Line 4301  static int one_opt(int option, char *arg, char *errstr
         comma = split(arg);          comma = split(arg);
                                   
         new = opt_malloc(sizeof(struct txt_record));          new = opt_malloc(sizeof(struct txt_record));
         new->next = daemon->txt;  
         daemon->txt = new;  
         new->class = C_IN;          new->class = C_IN;
         new->stat = 0;          new->stat = 0;
   
         if (!(new->name = canonicalise_opt(arg)))          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 = comma ? strlen(comma) : 0;
         len += (len/255) + 1; /* room for extra counts */          len += (len/255) + 1; /* room for extra counts */
         new->txt = p = opt_malloc(len);          new->txt = p = opt_malloc(len);
Line 3668  static int one_opt(int option, char *arg, char *errstr Line 4355  static int one_opt(int option, char *arg, char *errstr
             arg = comma;              arg = comma;
             comma = split(arg);              comma = split(arg);
             if (!(target = canonicalise_opt(arg)))              if (!(target = canonicalise_opt(arg)))
              ret_err(_("bad SRV target"));              ret_err_free(_("bad SRV target"), name);
                                   
             if (comma)              if (comma)
               {                {
                 arg = comma;                  arg = comma;
                 comma = split(arg);                  comma = split(arg);
                 if (!atoi_check16(arg, &port))                  if (!atoi_check16(arg, &port))
                  ret_err(_("invalid port number"));                  {
                     free(name);
                     ret_err_free(_("invalid port number"), target);
                   }
                                   
                 if (comma)                  if (comma)
                   {                    {
                     arg = comma;                      arg = comma;
                     comma = split(arg);                      comma = split(arg);
                     if (!atoi_check16(arg, &priority))                      if (!atoi_check16(arg, &priority))
                      ret_err(_("invalid priority"));                      {
                                                free(name);
                    if (comma)                        ret_err_free(_("invalid priority"), target);
                      { 
                        arg = comma; 
                        comma = split(arg); 
                        if (!atoi_check16(arg, &weight)) 
                          ret_err(_("invalid weight")); 
                       }                        }
                       if (comma && !atoi_check16(comma, &weight))
                         {
                           free(name);
                           ret_err_free(_("invalid weight"), target);
                         }
                   }                    }
               }                }
           }            }
Line 3709  static int one_opt(int option, char *arg, char *errstr Line 4399  static int one_opt(int option, char *arg, char *errstr
               
     case LOPT_HOST_REC: /* --host-record */      case LOPT_HOST_REC: /* --host-record */
       {        {
        struct host_record *new = opt_malloc(sizeof(struct host_record));        struct host_record *new;
        memset(new, 0, sizeof(struct host_record));
         
         if (!arg || !(comma = split(arg)))          if (!arg || !(comma = split(arg)))
           ret_err(_("Bad host-record"));            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)          while (arg)
           {            {
            struct all_addr addr;            union all_addr addr;
            if (inet_pton(AF_INET, arg, &addr))            char *dig;
              new->addr = addr.addr.addr4;
#ifdef HAVE_IPV6            for (dig = arg; *dig != 0; dig++)
            else if (inet_pton(AF_INET6, arg, &addr))              if (*dig < '0' || *dig > '9')
              new->addr6 = addr.addr.addr6;                break;
#endif            if (*dig == 0)
               new->ttl = atoi(arg);
             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              else
               {                {
                 int nomem;                  int nomem;
                 char *canon = canonicalise(arg, &nomem);                  char *canon = canonicalise(arg, &nomem);
                struct name_list *nl = opt_malloc(sizeof(struct name_list));                struct name_list *nl;
                 if (!canon)                  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;                  nl->name = canon;
                 /* keep order, so that PTR record goes to first name */                  /* keep order, so that PTR record goes to first name */
                 nl->next = NULL;                  nl->next = NULL;
Line 3760  static int one_opt(int option, char *arg, char *errstr Line 4474  static int one_opt(int option, char *arg, char *errstr
       }        }
   
 #ifdef HAVE_DNSSEC  #ifdef HAVE_DNSSEC
    case LOPT_TRUST_ANCHOR:    case LOPT_DNSSEC_STAMP: /* --dnssec-timestamp */
       daemon->timestamp_file = opt_string_alloc(arg); 
       break;
 
     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));          struct ds_config *new = opt_malloc(sizeof(struct ds_config));
         char *cp, *cp1, *keyhex, *digest, *algo = NULL;          char *cp, *cp1, *keyhex, *digest, *algo = NULL;
         int len;          int len;
                   
         new->class = C_IN;          new->class = C_IN;
           new->name = NULL;
   
         if ((comma = split(arg)) && (algo = split(comma)))          if ((comma = split(arg)) && (algo = split(comma)))
           {            {
Line 3791  static int one_opt(int option, char *arg, char *errstr Line 4520  static int one_opt(int option, char *arg, char *errstr
             !atoi_check8(algo, &new->algo) ||              !atoi_check8(algo, &new->algo) ||
             !atoi_check8(digest, &new->digest_type) ||              !atoi_check8(digest, &new->digest_type) ||
             !(new->name = canonicalise_opt(arg)))              !(new->name = canonicalise_opt(arg)))
          ret_err(_("bad trust anchor"));          ret_err_free(_("bad trust anchor"), new);
                           
         /* Upper bound on length */          /* Upper bound on length */
         len = (2*strlen(keyhex))+1;          len = (2*strlen(keyhex))+1;
Line 3805  static int one_opt(int option, char *arg, char *errstr Line 4534  static int one_opt(int option, char *arg, char *errstr
           else            else
             cp++;              cp++;
         if ((new->digestlen = parse_hex(keyhex, (unsigned char *)new->digest, len, NULL, NULL)) == -1)          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;          new->next = daemon->ds;
         daemon->ds = new;          daemon->ds = new;
Line 3831  static void read_file(char *file, FILE *f, int hard_op Line 4563  static void read_file(char *file, FILE *f, int hard_op
     {      {
       int white, i;        int white, i;
       volatile int option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt;        volatile int option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt;
      char *errmess, *p, *arg = NULL, *start;      char *errmess, *p, *arg, *start;
       size_t len;        size_t len;
   
       /* Memory allocation failure longjmps here if mem_recover == 1 */         /* Memory allocation failure longjmps here if mem_recover == 1 */ 
Line 3842  static void read_file(char *file, FILE *f, int hard_op Line 4574  static void read_file(char *file, FILE *f, int hard_op
           mem_recover = 1;            mem_recover = 1;
         }          }
               
         arg = NULL;
       lineno++;        lineno++;
       errmess = NULL;        errmess = NULL;
               
Line 3944  static void read_file(char *file, FILE *f, int hard_op Line 4677  static void read_file(char *file, FILE *f, int hard_op
       if (errmess)        if (errmess)
         strcpy(daemon->namebuff, 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);            sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file);
           if (hard_opt != 0)            if (hard_opt != 0)
Line 3958  static void read_file(char *file, FILE *f, int hard_op Line 4691  static void read_file(char *file, FILE *f, int hard_op
   fclose(f);    fclose(f);
 }  }
   
   #if defined(HAVE_DHCP) && defined(HAVE_INOTIFY)
   int option_read_dynfile(char *file, int flags)
   {
     my_syslog(MS_DHCP | LOG_INFO, _("read %s"), file);
     
     if (flags & AH_DHCP_HST)
       return one_file(file, LOPT_BANK);
     else if (flags & AH_DHCP_OPT)
       return one_file(file, LOPT_OPTS);
     
     return 0;
   }
   #endif
   
 static int one_file(char *file, int hard_opt)  static int one_file(char *file, int hard_opt)
 {  {
   FILE *f;    FILE *f;
Line 4055  struct hostsfile *expand_filelist(struct hostsfile *li Line 4802  struct hostsfile *expand_filelist(struct hostsfile *li
                           
             /* don't read this as a file */              /* don't read this as a file */
             ah->flags |= AH_INACTIVE;              ah->flags |= AH_INACTIVE;
            
             if (!(dir_stream = opendir(ah->fname)))              if (!(dir_stream = opendir(ah->fname)))
               my_syslog(LOG_ERR, _("cannot access directory %s: %s"),                 my_syslog(LOG_ERR, _("cannot access directory %s: %s"), 
                         ah->fname, strerror(errno));                          ah->fname, strerror(errno));
Line 4145  void read_servers_file(void) Line 4892  void read_servers_file(void)
     
   
 #ifdef HAVE_DHCP  #ifdef HAVE_DHCP
void reread_dhcp(void)static void clear_dynamic_conf(void)
 {  {
  struct hostsfile *hf;  struct dhcp_config *configs, *cp, **up;
 
  if (daemon->dhcp_hosts_file) 
    { 
      struct dhcp_config *configs, *cp, **up; 
       
      /* remove existing... */  /* remove existing... */
      for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)  for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
     {
       cp = configs->next;
       
       if (configs->flags & CONFIG_BANK)
         {          {
          cp = configs->next;          struct hwaddr_config *mac, *tmp;
           struct dhcp_netid_list *list, *tmplist;
                       
          if (configs->flags & CONFIG_BANK)          for (mac = configs->hwaddr; mac; mac = tmp)
             {              {
              struct hwaddr_config *mac, *tmp;              tmp = mac->next;
              struct dhcp_netid_list *list, *tmplist;              free(mac);
                          }
              for (mac = configs->hwaddr; mac; mac = tmp)          
                {          if (configs->flags & CONFIG_CLID)
                  tmp = mac->next;            free(configs->clid);
                  free(mac);          
                }          for (list = configs->netid; list; list = tmplist)
             {
               free(list->list);
               tmplist = list->next;
               free(list);
             }
           
           if (configs->flags & CONFIG_NAME)
             free(configs->hostname);
           
           *up = configs->next;
           free(configs);
         }
       else
         up = &configs->next;
     }
 }
   
              if (configs->flags & CONFIG_CLID)static void clear_dynamic_opt(void)
                free(configs->clid);{
   struct dhcp_opt *opts, *cp, **up;
   struct dhcp_netid *id, *next;
   
              for (list = configs->netid; list; list = tmplist)  for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
                {    {
                  free(list->list);      cp = opts->next;
                  tmplist = list->next;      
                  free(list);      if (opts->flags & DHOPT_BANK)
                }        {
                        if ((opts->flags & DHOPT_VENDOR))
              if (configs->flags & CONFIG_NAME)            free(opts->u.vendor_class);
                free(configs->hostname);          free(opts->val);
                        for (id = opts->netid; id; id = next)
              *up = configs->next;            {
              free(configs);              next = id->next;
               free(id->net);
               free(id);
             }              }
          else          *up = opts->next;
            up = &configs->next;          free(opts);
         }          }
            else
         up = &opts->next;
     }
 }
 
 void reread_dhcp(void)
 {
    struct hostsfile *hf;
 
    /* Do these even if there is no daemon->dhcp_hosts_file or
       daemon->dhcp_opts_file since entries may have been created by the
       inotify dynamic file reading system. */
    
    clear_dynamic_conf();
    clear_dynamic_opt();
 
    if (daemon->dhcp_hosts_file)
     {
       daemon->dhcp_hosts_file = expand_filelist(daemon->dhcp_hosts_file);        daemon->dhcp_hosts_file = expand_filelist(daemon->dhcp_hosts_file);
       for (hf = daemon->dhcp_hosts_file; hf; hf = hf->next)        for (hf = daemon->dhcp_hosts_file; hf; hf = hf->next)
         if (!(hf->flags & AH_INACTIVE))        if (!(hf->flags & AH_INACTIVE))
           {          {
             if (one_file(hf->fname, LOPT_BANK))              if (one_file(hf->fname, LOPT_BANK))  
               my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);              my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
           }          }
     }      }
   
   if (daemon->dhcp_opts_file)    if (daemon->dhcp_opts_file)
     {      {
       struct dhcp_opt *opts, *cp, **up;  
       struct dhcp_netid *id, *next;  
   
       for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)  
         {  
           cp = opts->next;  
             
           if (opts->flags & DHOPT_BANK)  
             {  
               if ((opts->flags & DHOPT_VENDOR))  
                 free(opts->u.vendor_class);  
               free(opts->val);  
               for (id = opts->netid; id; id = next)  
                 {  
                   next = id->next;  
                   free(id->net);  
                   free(id);  
                 }  
               *up = opts->next;  
               free(opts);  
             }  
           else  
             up = &opts->next;  
         }  
         
       daemon->dhcp_opts_file = expand_filelist(daemon->dhcp_opts_file);        daemon->dhcp_opts_file = expand_filelist(daemon->dhcp_opts_file);
       for (hf = daemon->dhcp_opts_file; hf; hf = hf->next)        for (hf = daemon->dhcp_opts_file; hf; hf = hf->next)
         if (!(hf->flags & AH_INACTIVE))          if (!(hf->flags & AH_INACTIVE))
Line 4233  void reread_dhcp(void) Line 4993  void reread_dhcp(void)
               my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);                my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
           }            }
     }      }
   
   #  ifdef HAVE_INOTIFY
     /* Setup notify and read pre-existing files. */
     set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
   #  endif
 }  }
 #endif  #endif
    
 void read_opts(int argc, char **argv, char *compile_opts)  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);    char *buff = opt_malloc(MAXDNAME);
  int option, conffile_opt = '7', testmode = 0;  int option, testmode = 0;
  char *arg, *conffile = CONFFILE;  char *arg, *conffile = NULL;
               
   opterr = 0;    opterr = 0;
   
Line 4267  void read_opts(int argc, char **argv, char *compile_op Line 5034  void read_opts(int argc, char **argv, char *compile_op
   daemon->soa_refresh = SOA_REFRESH;    daemon->soa_refresh = SOA_REFRESH;
   daemon->soa_retry = SOA_RETRY;    daemon->soa_retry = SOA_RETRY;
   daemon->soa_expiry = SOA_EXPIRY;    daemon->soa_expiry = SOA_EXPIRY;
     daemon->max_port = MAX_PORT;
     daemon->min_port = MIN_PORT;
   
   #ifndef NO_ID
   add_txt("version.bind", "dnsmasq-" VERSION, 0 );    add_txt("version.bind", "dnsmasq-" VERSION, 0 );
   add_txt("authors.bind", "Simon Kelley", 0);    add_txt("authors.bind", "Simon Kelley", 0);
   add_txt("copyright.bind", COPYRIGHT, 0);    add_txt("copyright.bind", COPYRIGHT, 0);
Line 4279  void read_opts(int argc, char **argv, char *compile_op Line 5050  void read_opts(int argc, char **argv, char *compile_op
   add_txt("auth.bind", NULL, TXT_STAT_AUTH);    add_txt("auth.bind", NULL, TXT_STAT_AUTH);
 #endif  #endif
   add_txt("servers.bind", NULL, TXT_STAT_SERVERS);    add_txt("servers.bind", NULL, TXT_STAT_SERVERS);
   #endif
   
   while (1)     while (1) 
     {      {
Line 4303  void read_opts(int argc, char **argv, char *compile_op Line 5075  void read_opts(int argc, char **argv, char *compile_op
       /* Copy optarg so that argv doesn't get changed */        /* Copy optarg so that argv doesn't get changed */
       if (optarg)        if (optarg)
         {          {
          strncpy(buff, optarg, MAXDNAME);          if (strlen(optarg) >= argbuf_size)
          buff[MAXDNAME-1] = 0;            {
          arg = buff;              free(argbuf);
               argbuf_size = strlen(optarg) + 1;
               argbuf = opt_malloc(argbuf_size);
             }
           safe_strncpy(argbuf, optarg, argbuf_size);
           arg = argbuf;
         }          }
       else        else
         arg = NULL;          arg = NULL;
Line 4339  void read_opts(int argc, char **argv, char *compile_op Line 5116  void read_opts(int argc, char **argv, char *compile_op
         }          }
       else if (option == 'C')        else if (option == 'C')
         {          {
          conffile_opt = 0; /* file must exist */          if (!conffile)
          conffile = opt_string_alloc(arg);            conffile = opt_string_alloc(arg);
           else
             {
               char *extra = opt_string_alloc(arg);
               one_file(extra, 0);
               free(extra);
             }
         }          }
       else        else
         {          {
Line 4353  void read_opts(int argc, char **argv, char *compile_op Line 5136  void read_opts(int argc, char **argv, char *compile_op
         }          }
     }      }
   
     free(argbuf);
   
   if (conffile)    if (conffile)
    one_file(conffile, conffile_opt);    {
       one_file(conffile, 0);
       free(conffile);
     }
   else
     one_file(CONFFILE, '7');
   
   /* port might not be known when the address is parsed - fill in here */    /* port might not be known when the address is parsed - fill in here */
   if (daemon->servers)    if (daemon->servers)
Line 4365  void read_opts(int argc, char **argv, char *compile_op Line 5155  void read_opts(int argc, char **argv, char *compile_op
           {            {
             if (tmp->source_addr.sa.sa_family == AF_INET)              if (tmp->source_addr.sa.sa_family == AF_INET)
               tmp->source_addr.in.sin_port = htons(daemon->query_port);                tmp->source_addr.in.sin_port = htons(daemon->query_port);
 #ifdef HAVE_IPV6  
             else if (tmp->source_addr.sa.sa_family == AF_INET6)              else if (tmp->source_addr.sa.sa_family == AF_INET6)
               tmp->source_addr.in6.sin6_port = htons(daemon->query_port);                tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
#endif           }
          }     } 
    } 
       
     if (daemon->host_records)
       {
         struct host_record *hr;
         
         for (hr = daemon->host_records; hr; hr = hr->next)
           if (hr->ttl == -1)
             hr->ttl = daemon->local_ttl;
       }
   
     if (daemon->cnames)
       {
         struct cname *cn, *cn2, *cn3;
   
   #define NOLOOP 1
   #define TESTLOOP 2      
   
         /* Fill in TTL for CNAMES now we have local_ttl.
            Also prepare to do loop detection. */
         for (cn = daemon->cnames; cn; cn = cn->next)
           {
             if (cn->ttl == -1)
               cn->ttl = daemon->local_ttl;
             cn->flag = 0;
             cn->targetp = NULL;
             for (cn2 = daemon->cnames; cn2; cn2 = cn2->next)
               if (hostname_isequal(cn->target, cn2->alias))
                 {
                   cn->targetp = cn2;
                   break;
                 }
           }
         
         /* Find any CNAME loops.*/
         for (cn = daemon->cnames; cn; cn = cn->next)
           {
             for (cn2 = cn->targetp; cn2; cn2 = cn2->targetp)
               {
                 if (cn2->flag == NOLOOP)
                   break;
                 
                 if (cn2->flag == TESTLOOP)
                   die(_("CNAME loop involving %s"), cn->alias, EC_BADCONF);
                 
                 cn2->flag = TESTLOOP;
               }
             
             for (cn3 = cn->targetp; cn3 != cn2; cn3 = cn3->targetp)
               cn3->flag = NOLOOP;
           }
       }
   
   if (daemon->if_addrs)    if (daemon->if_addrs)
     {        {  
       struct iname *tmp;        struct iname *tmp;
       for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)        for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)
         if (tmp->addr.sa.sa_family == AF_INET)          if (tmp->addr.sa.sa_family == AF_INET)
           tmp->addr.in.sin_port = htons(daemon->port);            tmp->addr.in.sin_port = htons(daemon->port);
 #ifdef HAVE_IPV6  
         else if (tmp->addr.sa.sa_family == AF_INET6)          else if (tmp->addr.sa.sa_family == AF_INET6)
           tmp->addr.in6.sin6_port = htons(daemon->port);            tmp->addr.in6.sin6_port = htons(daemon->port);
 #endif /* IPv6 */  
     }      }
                   
   /* create default, if not specified */    /* create default, if not specified */
Line 4390  void read_opts(int argc, char **argv, char *compile_op Line 5227  void read_opts(int argc, char **argv, char *compile_op
       strcpy(buff, "hostmaster.");        strcpy(buff, "hostmaster.");
       strcat(buff, daemon->authserver);        strcat(buff, daemon->authserver);
       daemon->hostmaster = opt_string_alloc(buff);        daemon->hostmaster = opt_string_alloc(buff);
       }
   
     if (!daemon->dhcp_pxe_vendors)
       {
         daemon->dhcp_pxe_vendors = opt_malloc(sizeof(struct dhcp_pxe_vendor));
         daemon->dhcp_pxe_vendors->data = opt_string_alloc(DHCP_PXE_DEF_VENDOR);
         daemon->dhcp_pxe_vendors->next = NULL;
     }      }
       
   /* only one of these need be specified: the other defaults to the host-name */    /* only one of these need be specified: the other defaults to the host-name */

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.4


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>