File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / option.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:56:46 2021 UTC (3 years, 4 months ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_84, HEAD
dnsmasq 2.84

    1: /* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
    2: 
    3:    This program is free software; you can redistribute it and/or modify
    4:    it under the terms of the GNU General Public License as published by
    5:    the Free Software Foundation; version 2 dated June, 1991, or
    6:    (at your option) version 3 dated 29 June, 2007.
    7:  
    8:    This program is distributed in the hope that it will be useful,
    9:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   10:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11:    GNU General Public License for more details.
   12:      
   13:    You should have received a copy of the GNU General Public License
   14:    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   15: */
   16: 
   17: /* define this to get facilitynames */
   18: #define SYSLOG_NAMES
   19: #include "dnsmasq.h"
   20: #include <setjmp.h>
   21: 
   22: static volatile int mem_recover = 0;
   23: static jmp_buf mem_jmp;
   24: static int one_file(char *file, int hard_opt);
   25: 
   26: /* Solaris headers don't have facility names. */
   27: #ifdef HAVE_SOLARIS_NETWORK
   28: static const struct {
   29:   char *c_name;
   30:   unsigned int c_val;
   31: }  facilitynames[] = {
   32:   { "kern",   LOG_KERN },
   33:   { "user",   LOG_USER },
   34:   { "mail",   LOG_MAIL },
   35:   { "daemon", LOG_DAEMON },
   36:   { "auth",   LOG_AUTH },
   37:   { "syslog", LOG_SYSLOG },
   38:   { "lpr",    LOG_LPR },
   39:   { "news",   LOG_NEWS },
   40:   { "uucp",   LOG_UUCP },
   41:   { "audit",  LOG_AUDIT },
   42:   { "cron",   LOG_CRON },
   43:   { "local0", LOG_LOCAL0 },
   44:   { "local1", LOG_LOCAL1 },
   45:   { "local2", LOG_LOCAL2 },
   46:   { "local3", LOG_LOCAL3 },
   47:   { "local4", LOG_LOCAL4 },
   48:   { "local5", LOG_LOCAL5 },
   49:   { "local6", LOG_LOCAL6 },
   50:   { "local7", LOG_LOCAL7 },
   51:   { NULL, 0 }
   52: };
   53: #endif
   54: 
   55: #ifndef HAVE_GETOPT_LONG
   56: struct myoption {
   57:   const char *name;
   58:   int has_arg;
   59:   int *flag;
   60:   int val;
   61: };
   62: #endif
   63: 
   64: #define OPTSTRING "951yZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:W:Y:2:4:6:7:8:0:3:"
   65: 
   66: /* options which don't have a one-char version */
   67: #define LOPT_RELOAD        256
   68: #define LOPT_NO_NAMES      257
   69: #define LOPT_TFTP          258
   70: #define LOPT_SECURE        259
   71: #define LOPT_PREFIX        260
   72: #define LOPT_PTR           261
   73: #define LOPT_BRIDGE        262
   74: #define LOPT_TFTP_MAX      263
   75: #define LOPT_FORCE         264
   76: #define LOPT_NOBLOCK       265
   77: #define LOPT_LOG_OPTS      266
   78: #define LOPT_MAX_LOGS      267
   79: #define LOPT_CIRCUIT       268
   80: #define LOPT_REMOTE        269
   81: #define LOPT_SUBSCR        270
   82: #define LOPT_INTNAME       271
   83: #define LOPT_BANK          272
   84: #define LOPT_DHCP_HOST     273
   85: #define LOPT_APREF         274
   86: #define LOPT_OVERRIDE      275
   87: #define LOPT_TFTPPORTS     276
   88: #define LOPT_REBIND        277
   89: #define LOPT_NOLAST        278
   90: #define LOPT_OPTS          279
   91: #define LOPT_DHCP_OPTS     280
   92: #define LOPT_MATCH         281
   93: #define LOPT_BROADCAST     282
   94: #define LOPT_NEGTTL        283
   95: #define LOPT_ALTPORT       284
   96: #define LOPT_SCRIPTUSR     285
   97: #define LOPT_LOCAL         286
   98: #define LOPT_NAPTR         287
   99: #define LOPT_MINPORT       288
  100: #define LOPT_DHCP_FQDN     289
  101: #define LOPT_CNAME         290
  102: #define LOPT_PXE_PROMT     291
  103: #define LOPT_PXE_SERV      292
  104: #define LOPT_TEST          293
  105: #define LOPT_TAG_IF        294
  106: #define LOPT_PROXY         295
  107: #define LOPT_GEN_NAMES     296
  108: #define LOPT_MAXTTL        297
  109: #define LOPT_NO_REBIND     298
  110: #define LOPT_LOC_REBND     299
  111: #define LOPT_ADD_MAC       300
  112: #define LOPT_DNSSEC        301
  113: #define LOPT_INCR_ADDR     302
  114: #define LOPT_CONNTRACK     303
  115: #define LOPT_FQDN          304
  116: #define LOPT_LUASCRIPT     305
  117: #define LOPT_RA            306
  118: #define LOPT_DUID          307
  119: #define LOPT_HOST_REC      308
  120: #define LOPT_TFTP_LC       309
  121: #define LOPT_RR            310
  122: #define LOPT_CLVERBIND     311
  123: #define LOPT_MAXCTTL       312
  124: #define LOPT_AUTHZONE      313
  125: #define LOPT_AUTHSERV      314
  126: #define LOPT_AUTHTTL       315
  127: #define LOPT_AUTHSOA       316
  128: #define LOPT_AUTHSFS       317
  129: #define LOPT_AUTHPEER      318
  130: #define LOPT_IPSET         319
  131: #define LOPT_SYNTH         320
  132: #define LOPT_RELAY         323
  133: #define LOPT_RA_PARAM      324
  134: #define LOPT_ADD_SBNET     325
  135: #define LOPT_QUIET_DHCP    326
  136: #define LOPT_QUIET_DHCP6   327
  137: #define LOPT_QUIET_RA      328
  138: #define LOPT_SEC_VALID     329
  139: #define LOPT_TRUST_ANCHOR  330
  140: #define LOPT_DNSSEC_DEBUG  331
  141: #define LOPT_REV_SERV      332
  142: #define LOPT_SERVERS_FILE  333
  143: #define LOPT_DNSSEC_CHECK  334
  144: #define LOPT_LOCAL_SERVICE 335
  145: #define LOPT_DNSSEC_TIME   336
  146: #define LOPT_LOOP_DETECT   337
  147: #define LOPT_IGNORE_ADDR   338
  148: #define LOPT_MINCTTL       339
  149: #define LOPT_DHCP_INOTIFY  340
  150: #define LOPT_DHOPT_INOTIFY 341
  151: #define LOPT_HOST_INOTIFY  342
  152: #define LOPT_DNSSEC_STAMP  343
  153: #define LOPT_TFTP_NO_FAIL  344
  154: #define LOPT_MAXPORT       345
  155: #define LOPT_CPE_ID        346
  156: #define LOPT_SCRIPT_ARP    347
  157: #define LOPT_DHCPTTL       348
  158: #define LOPT_TFTP_MTU      349
  159: #define LOPT_REPLY_DELAY   350
  160: #define LOPT_RAPID_COMMIT  351
  161: #define LOPT_DUMPFILE      352
  162: #define LOPT_DUMPMASK      353
  163: #define LOPT_UBUS          354
  164: #define LOPT_NAME_MATCH    355
  165: #define LOPT_CAA           356
  166: #define LOPT_SHARED_NET    357
  167: #define LOPT_IGNORE_CLID   358
  168: #define LOPT_SINGLE_PORT   359
  169: #define LOPT_SCRIPT_TIME   360
  170: #define LOPT_PXE_VENDOR    361
  171:  
  172: #ifdef HAVE_GETOPT_LONG
  173: static const struct option opts[] =  
  174: #else
  175: static const struct myoption opts[] = 
  176: #endif
  177:   { 
  178:     { "version", 0, 0, 'v' },
  179:     { "no-hosts", 0, 0, 'h' },
  180:     { "no-poll", 0, 0, 'n' },
  181:     { "help", 0, 0, 'w' },
  182:     { "no-daemon", 0, 0, 'd' },
  183:     { "log-queries", 2, 0, 'q' },
  184:     { "user", 2, 0, 'u' },
  185:     { "group", 2, 0, 'g' },
  186:     { "resolv-file", 2, 0, 'r' },
  187:     { "servers-file", 1, 0, LOPT_SERVERS_FILE },
  188:     { "mx-host", 1, 0, 'm' },
  189:     { "mx-target", 1, 0, 't' },
  190:     { "cache-size", 2, 0, 'c' },
  191:     { "port", 1, 0, 'p' },
  192:     { "dhcp-leasefile", 2, 0, 'l' },
  193:     { "dhcp-lease", 1, 0, 'l' },
  194:     { "dhcp-host", 1, 0, 'G' },
  195:     { "dhcp-range", 1, 0, 'F' },
  196:     { "dhcp-option", 1, 0, 'O' },
  197:     { "dhcp-boot", 1, 0, 'M' },
  198:     { "domain", 1, 0, 's' },
  199:     { "domain-suffix", 1, 0, 's' },
  200:     { "interface", 1, 0, 'i' },
  201:     { "listen-address", 1, 0, 'a' },
  202:     { "local-service", 0, 0, LOPT_LOCAL_SERVICE },
  203:     { "bogus-priv", 0, 0, 'b' },
  204:     { "bogus-nxdomain", 1, 0, 'B' },
  205:     { "ignore-address", 1, 0, LOPT_IGNORE_ADDR },
  206:     { "selfmx", 0, 0, 'e' },
  207:     { "filterwin2k", 0, 0, 'f' },
  208:     { "pid-file", 2, 0, 'x' },
  209:     { "strict-order", 0, 0, 'o' },
  210:     { "server", 1, 0, 'S' },
  211:     { "rev-server", 1, 0, LOPT_REV_SERV },
  212:     { "local", 1, 0, LOPT_LOCAL },
  213:     { "address", 1, 0, 'A' },
  214:     { "conf-file", 2, 0, 'C' },
  215:     { "no-resolv", 0, 0, 'R' },
  216:     { "expand-hosts", 0, 0, 'E' },
  217:     { "localmx", 0, 0, 'L' },
  218:     { "local-ttl", 1, 0, 'T' },
  219:     { "no-negcache", 0, 0, 'N' },
  220:     { "addn-hosts", 1, 0, 'H' },
  221:     { "hostsdir", 1, 0, LOPT_HOST_INOTIFY },
  222:     { "query-port", 1, 0, 'Q' },
  223:     { "except-interface", 1, 0, 'I' },
  224:     { "no-dhcp-interface", 1, 0, '2' },
  225:     { "domain-needed", 0, 0, 'D' },
  226:     { "dhcp-lease-max", 1, 0, 'X' },
  227:     { "bind-interfaces", 0, 0, 'z' },
  228:     { "read-ethers", 0, 0, 'Z' },
  229:     { "alias", 1, 0, 'V' },
  230:     { "dhcp-vendorclass", 1, 0, 'U' },
  231:     { "dhcp-userclass", 1, 0, 'j' },
  232:     { "dhcp-ignore", 1, 0, 'J' },
  233:     { "edns-packet-max", 1, 0, 'P' },
  234:     { "keep-in-foreground", 0, 0, 'k' },
  235:     { "dhcp-authoritative", 0, 0, 'K' },
  236:     { "srv-host", 1, 0, 'W' },
  237:     { "localise-queries", 0, 0, 'y' },
  238:     { "txt-record", 1, 0, 'Y' },
  239:     { "caa-record", 1, 0 , LOPT_CAA },
  240:     { "dns-rr", 1, 0, LOPT_RR },
  241:     { "enable-dbus", 2, 0, '1' },
  242:     { "enable-ubus", 2, 0, LOPT_UBUS },
  243:     { "bootp-dynamic", 2, 0, '3' },
  244:     { "dhcp-mac", 1, 0, '4' },
  245:     { "no-ping", 0, 0, '5' },
  246:     { "dhcp-script", 1, 0, '6' },
  247:     { "conf-dir", 1, 0, '7' },
  248:     { "log-facility", 1, 0 ,'8' },
  249:     { "leasefile-ro", 0, 0, '9' },
  250:     { "script-on-renewal", 0, 0, LOPT_SCRIPT_TIME},
  251:     { "dns-forward-max", 1, 0, '0' },
  252:     { "clear-on-reload", 0, 0, LOPT_RELOAD },
  253:     { "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
  254:     { "enable-tftp", 2, 0, LOPT_TFTP },
  255:     { "tftp-secure", 0, 0, LOPT_SECURE },
  256:     { "tftp-no-fail", 0, 0, LOPT_TFTP_NO_FAIL },
  257:     { "tftp-unique-root", 2, 0, LOPT_APREF },
  258:     { "tftp-root", 1, 0, LOPT_PREFIX },
  259:     { "tftp-max", 1, 0, LOPT_TFTP_MAX },
  260:     { "tftp-mtu", 1, 0, LOPT_TFTP_MTU },
  261:     { "tftp-lowercase", 0, 0, LOPT_TFTP_LC },
  262:     { "tftp-single-port", 0, 0, LOPT_SINGLE_PORT },
  263:     { "ptr-record", 1, 0, LOPT_PTR },
  264:     { "naptr-record", 1, 0, LOPT_NAPTR },
  265:     { "bridge-interface", 1, 0 , LOPT_BRIDGE },
  266:     { "shared-network", 1, 0, LOPT_SHARED_NET },
  267:     { "dhcp-option-force", 1, 0, LOPT_FORCE },
  268:     { "tftp-no-blocksize", 0, 0, LOPT_NOBLOCK },
  269:     { "log-dhcp", 0, 0, LOPT_LOG_OPTS },
  270:     { "log-async", 2, 0, LOPT_MAX_LOGS },
  271:     { "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
  272:     { "dhcp-remoteid", 1, 0, LOPT_REMOTE },
  273:     { "dhcp-subscrid", 1, 0, LOPT_SUBSCR },
  274:     { "dhcp-pxe-vendor", 1, 0, LOPT_PXE_VENDOR },
  275:     { "interface-name", 1, 0, LOPT_INTNAME },
  276:     { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
  277:     { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
  278:     { "dhcp-hostsdir", 1, 0, LOPT_DHCP_INOTIFY },
  279:     { "dhcp-optsdir", 1, 0, LOPT_DHOPT_INOTIFY },
  280:     { "dhcp-no-override", 0, 0, LOPT_OVERRIDE },
  281:     { "tftp-port-range", 1, 0, LOPT_TFTPPORTS },
  282:     { "stop-dns-rebind", 0, 0, LOPT_REBIND },
  283:     { "rebind-domain-ok", 1, 0, LOPT_NO_REBIND },
  284:     { "all-servers", 0, 0, LOPT_NOLAST }, 
  285:     { "dhcp-match", 1, 0, LOPT_MATCH },
  286:     { "dhcp-name-match", 1, 0, LOPT_NAME_MATCH },
  287:     { "dhcp-broadcast", 2, 0, LOPT_BROADCAST },
  288:     { "neg-ttl", 1, 0, LOPT_NEGTTL },
  289:     { "max-ttl", 1, 0, LOPT_MAXTTL },
  290:     { "min-cache-ttl", 1, 0, LOPT_MINCTTL },
  291:     { "max-cache-ttl", 1, 0, LOPT_MAXCTTL },
  292:     { "dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
  293:     { "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
  294:     { "min-port", 1, 0, LOPT_MINPORT },
  295:     { "max-port", 1, 0, LOPT_MAXPORT },
  296:     { "dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN },
  297:     { "cname", 1, 0, LOPT_CNAME },
  298:     { "pxe-prompt", 1, 0, LOPT_PXE_PROMT },
  299:     { "pxe-service", 1, 0, LOPT_PXE_SERV },
  300:     { "test", 0, 0, LOPT_TEST },
  301:     { "tag-if", 1, 0, LOPT_TAG_IF },
  302:     { "dhcp-proxy", 2, 0, LOPT_PROXY },
  303:     { "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES },
  304:     { "rebind-localhost-ok", 0, 0,  LOPT_LOC_REBND },
  305:     { "add-mac", 2, 0, LOPT_ADD_MAC },
  306:     { "add-subnet", 2, 0, LOPT_ADD_SBNET },
  307:     { "add-cpe-id", 1, 0 , LOPT_CPE_ID },
  308:     { "proxy-dnssec", 0, 0, LOPT_DNSSEC },
  309:     { "dhcp-sequential-ip", 0, 0,  LOPT_INCR_ADDR },
  310:     { "conntrack", 0, 0, LOPT_CONNTRACK },
  311:     { "dhcp-client-update", 0, 0, LOPT_FQDN },
  312:     { "dhcp-luascript", 1, 0, LOPT_LUASCRIPT },
  313:     { "enable-ra", 0, 0, LOPT_RA },
  314:     { "dhcp-duid", 1, 0, LOPT_DUID },
  315:     { "host-record", 1, 0, LOPT_HOST_REC },
  316:     { "bind-dynamic", 0, 0, LOPT_CLVERBIND },
  317:     { "auth-zone", 1, 0, LOPT_AUTHZONE },
  318:     { "auth-server", 1, 0, LOPT_AUTHSERV },
  319:     { "auth-ttl", 1, 0, LOPT_AUTHTTL },
  320:     { "auth-soa", 1, 0, LOPT_AUTHSOA },
  321:     { "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
  322:     { "auth-peer", 1, 0, LOPT_AUTHPEER }, 
  323:     { "ipset", 1, 0, LOPT_IPSET },
  324:     { "synth-domain", 1, 0, LOPT_SYNTH },
  325:     { "dnssec", 0, 0, LOPT_SEC_VALID },
  326:     { "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR },
  327:     { "dnssec-debug", 0, 0, LOPT_DNSSEC_DEBUG },
  328:     { "dnssec-check-unsigned", 2, 0, LOPT_DNSSEC_CHECK },
  329:     { "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME },
  330:     { "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP },
  331:     { "dhcp-relay", 1, 0, LOPT_RELAY },
  332:     { "ra-param", 1, 0, LOPT_RA_PARAM },
  333:     { "quiet-dhcp", 0, 0, LOPT_QUIET_DHCP },
  334:     { "quiet-dhcp6", 0, 0, LOPT_QUIET_DHCP6 },
  335:     { "quiet-ra", 0, 0, LOPT_QUIET_RA },
  336:     { "dns-loop-detect", 0, 0, LOPT_LOOP_DETECT },
  337:     { "script-arp", 0, 0, LOPT_SCRIPT_ARP },
  338:     { "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },
  339:     { "dhcp-reply-delay", 1, 0, LOPT_REPLY_DELAY },
  340:     { "dhcp-rapid-commit", 0, 0, LOPT_RAPID_COMMIT },
  341:     { "dumpfile", 1, 0, LOPT_DUMPFILE },
  342:     { "dumpmask", 1, 0, LOPT_DUMPMASK },
  343:     { "dhcp-ignore-clid", 0, 0,  LOPT_IGNORE_CLID },
  344:     { NULL, 0, 0, 0 }
  345:   };
  346: 
  347: 
  348: #define ARG_DUP       OPT_LAST
  349: #define ARG_ONE       OPT_LAST + 1
  350: #define ARG_USED_CL   OPT_LAST + 2
  351: #define ARG_USED_FILE OPT_LAST + 3
  352: 
  353: static struct {
  354:   int opt;
  355:   unsigned int rept;
  356:   char * const flagdesc;
  357:   char * const desc;
  358:   char * const arg;
  359: } usage[] = {
  360:   { 'a', ARG_DUP, "<ipaddr>",  gettext_noop("Specify local address(es) to listen on."), NULL },
  361:   { 'A', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Return ipaddr for all hosts in specified domains."), NULL },
  362:   { 'b', OPT_BOGUSPRIV, NULL, gettext_noop("Fake reverse lookups for RFC1918 private address ranges."), NULL },
  363:   { 'B', ARG_DUP, "<ipaddr>", gettext_noop("Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."), NULL }, 
  364:   { 'c', ARG_ONE, "<integer>", gettext_noop("Specify the size of the cache in entries (defaults to %s)."), "$" },
  365:   { 'C', ARG_DUP, "<path>", gettext_noop("Specify configuration file (defaults to %s)."), CONFFILE },
  366:   { 'd', OPT_DEBUG, NULL, gettext_noop("Do NOT fork into the background: run in debug mode."), NULL },
  367:   { 'D', OPT_NODOTS_LOCAL, NULL, gettext_noop("Do NOT forward queries with no domain part."), NULL }, 
  368:   { 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL },
  369:   { 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
  370:   { 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
  371:   { 'F', ARG_DUP, "<ipaddr>,...", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
  372:   { 'g', ARG_ONE, "<groupname>", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
  373:   { 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
  374:   { LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL },
  375:   { LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL },
  376:   { LOPT_DHCP_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from a directory."), NULL }, 
  377:   { LOPT_DHOPT_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP options from a directory."), NULL }, 
  378:   { LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },
  379:   { 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
  380:   { 'H', ARG_DUP, "<path>", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
  381:   { LOPT_HOST_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read hosts files from a directory."), NULL },
  382:   { 'i', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) to listen on."), NULL },
  383:   { 'I', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
  384:   { 'j', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
  385:   { LOPT_CIRCUIT, ARG_DUP, "set:<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
  386:   { LOPT_REMOTE, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
  387:   { LOPT_SUBSCR, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
  388:   { LOPT_PXE_VENDOR, ARG_DUP, "<vendor>[,...]", gettext_noop("Specify vendor class to match for PXE requests."), NULL },
  389:   { 'J', ARG_DUP, "tag:<tag>...", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
  390:   { LOPT_BROADCAST, ARG_DUP, "[=tag:<tag>...]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL }, 
  391:   { 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
  392:   { 'K', OPT_AUTHORITATIVE, NULL, gettext_noop("Assume we are the only DHCP server on the local network."), NULL },
  393:   { 'l', ARG_ONE, "<path>", gettext_noop("Specify where to store DHCP leases (defaults to %s)."), LEASEFILE },
  394:   { 'L', OPT_LOCALMX, NULL, gettext_noop("Return MX records for local hosts."), NULL },
  395:   { 'm', ARG_DUP, "<host_name>,<target>,<pref>", gettext_noop("Specify an MX record."), NULL },
  396:   { 'M', ARG_DUP, "<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL },
  397:   { 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE }, 
  398:   { 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL },
  399:   { 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE },
  400:   { 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL },
  401:   { LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},
  402:   { 'p', ARG_ONE, "<integer>", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
  403:   { 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
  404:   { 'q', ARG_DUP, NULL, gettext_noop("Log DNS queries."), NULL },
  405:   { 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
  406:   { 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
  407:   { 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE }, 
  408:   { LOPT_SERVERS_FILE, ARG_ONE, "<path>", gettext_noop("Specify path to file with server= options"), NULL },
  409:   { 'S', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
  410:   { LOPT_REV_SERV, ARG_DUP, "<addr>/<prefix>,<ipaddr>", gettext_noop("Specify address of upstream servers for reverse address queries"), NULL },
  411:   { LOPT_LOCAL, ARG_DUP, "/<domain>/", gettext_noop("Never forward queries to specified domains."), NULL },
  412:   { 's', ARG_DUP, "<domain>[,<range>]", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
  413:   { 't', ARG_ONE, "<host_name>", gettext_noop("Specify default target in an MX record."), NULL },
  414:   { 'T', ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
  415:   { LOPT_NEGTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
  416:   { LOPT_MAXTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL },
  417:   { LOPT_MAXCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live ceiling for cache."), NULL },
  418:   { LOPT_MINCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live floor for cache."), NULL },
  419:   { 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER }, 
  420:   { 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
  421:   { 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
  422:   { 'V', ARG_DUP, "<ipaddr>,<ipaddr>,<netmask>", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },
  423:   { 'W', ARG_DUP, "<name>,<target>,...", gettext_noop("Specify a SRV record."), NULL },
  424:   { 'w', 0, NULL, gettext_noop("Display this message. Use --help dhcp or --help dhcp6 for known DHCP options."), NULL },
  425:   { 'x', ARG_ONE, "<path>", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE },
  426:   { 'X', ARG_ONE, "<integer>", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },
  427:   { 'y', OPT_LOCALISE, NULL, gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL },
  428:   { 'Y', ARG_DUP, "<name>,<txt>[,<txt]", gettext_noop("Specify TXT DNS record."), NULL },
  429:   { LOPT_PTR, ARG_DUP, "<name>,<target>", gettext_noop("Specify PTR DNS record."), NULL },
  430:   { LOPT_INTNAME, ARG_DUP, "<name>,<interface>", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
  431:   { 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
  432:   { 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
  433:   { '1', ARG_ONE, "[=<busname>]", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
  434:   { LOPT_UBUS, ARG_ONE, "[=<busname>]", gettext_noop("Enable the UBus interface."), NULL },
  435:   { '2', ARG_DUP, "<interface>", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
  436:   { '3', ARG_DUP, "[=tag:<tag>]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
  437:   { '4', ARG_DUP, "set:<tag>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
  438:   { LOPT_BRIDGE, ARG_DUP, "<iface>,<alias>..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL },
  439:   { LOPT_SHARED_NET, ARG_DUP, "<iface>|<addr>,<addr>", gettext_noop("Specify extra networks sharing a broadcast domain for DHCP"), NULL},
  440:   { '5', OPT_NO_PING, NULL, gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
  441:   { '6', ARG_ONE, "<path>", gettext_noop("Shell script to run on DHCP lease creation and destruction."), NULL },
  442:   { LOPT_LUASCRIPT, ARG_DUP, "path", gettext_noop("Lua script to run on DHCP lease creation and destruction."), NULL },
  443:   { LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change scripts as this user."), NULL },
  444:   { LOPT_SCRIPT_ARP, OPT_SCRIPT_ARP, NULL, gettext_noop("Call dhcp-script with changes to local ARP table."), NULL },
  445:   { '7', ARG_DUP, "<path>", gettext_noop("Read configuration from all the files in this directory."), NULL },
  446:   { '8', ARG_ONE, "<facility>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL },
  447:   { '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL },
  448:   { '0', ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" }, 
  449:   { LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
  450:   { LOPT_NO_NAMES, ARG_DUP, "[=tag:<tag>]...", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
  451:   { LOPT_OVERRIDE, OPT_NO_OVERRIDE, NULL, gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL },
  452:   { LOPT_TFTP, ARG_DUP, "[=<intr>[,<intr>]]", gettext_noop("Enable integrated read-only TFTP server."), NULL },
  453:   { LOPT_PREFIX, ARG_DUP, "<dir>[,<iface>]", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
  454:   { LOPT_APREF, ARG_DUP, "[=ip|mac]", gettext_noop("Add client IP or hardware address to tftp-root."), NULL },
  455:   { LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
  456:   { LOPT_TFTP_NO_FAIL, OPT_TFTP_NO_FAIL, NULL, gettext_noop("Do not terminate the service if TFTP directories are inaccessible."), NULL },
  457:   { LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent TFTP transfers (defaults to %s)."), "#" },
  458:   { LOPT_TFTP_MTU, ARG_ONE, "<integer>", gettext_noop("Maximum MTU to use for TFTP transfers."), NULL },
  459:   { LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
  460:   { LOPT_TFTP_LC, OPT_TFTP_LC, NULL, gettext_noop("Convert TFTP filenames to lowercase"), NULL },
  461:   { LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
  462:   { LOPT_SINGLE_PORT, OPT_SINGLE_PORT, NULL, gettext_noop("Use only one port for TFTP server."), NULL },
  463:   { LOPT_LOG_OPTS, OPT_LOG_OPTS, NULL, gettext_noop("Extra logging for DHCP."), NULL },
  464:   { LOPT_MAX_LOGS, ARG_ONE, "[=<integer>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL },
  465:   { LOPT_REBIND, OPT_NO_REBIND, NULL, gettext_noop("Stop DNS rebinding. Filter private IP ranges when resolving."), NULL },
  466:   { LOPT_LOC_REBND, OPT_LOCAL_REBIND, NULL, gettext_noop("Allow rebinding of 127.0.0.0/8, for RBL servers."), NULL },
  467:   { LOPT_NO_REBIND, ARG_DUP, "/<domain>/", gettext_noop("Inhibit DNS-rebind protection on this domain."), NULL },
  468:   { LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL },
  469:   { LOPT_MATCH, ARG_DUP, "set:<tag>,<optspec>", gettext_noop("Set tag if client includes matching option in request."), NULL },
  470:   { LOPT_NAME_MATCH, ARG_DUP, "set:<tag>,<string>[*]", gettext_noop("Set tag if client provides given name."), NULL },
  471:   { LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
  472:   { LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
  473:   { LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
  474:   { LOPT_MAXPORT, ARG_ONE, "<port>", gettext_noop("Specify highest port available for DNS query transmission."), NULL },
  475:   { LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL },
  476:   { LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
  477:   { LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
  478:   { LOPT_RELAY, ARG_DUP, "<local-addr>,<server>[,<iface>]", gettext_noop("Relay DHCP requests to a remote server"), NULL},
  479:   { LOPT_CNAME, ARG_DUP, "<alias>,<target>[,<ttl>]", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
  480:   { LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
  481:   { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
  482:   { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
  483:   { LOPT_ADD_MAC, ARG_DUP, "[=base64|text]", gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
  484:   { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL },
  485:   { LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client identification to forwarded DNS queries."), NULL },
  486:   { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
  487:   { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
  488:   { LOPT_IGNORE_CLID, OPT_IGNORE_CLID, NULL, gettext_noop("Ignore client identifier option sent by DHCP clients."), NULL },
  489:   { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
  490:   { LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow DHCP clients to do their own DDNS updates."), NULL },
  491:   { LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
  492:   { LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
  493:   { LOPT_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
  494:   { LOPT_CAA, ARG_DUP, "<name>,<flags>,<tag>,<value>", gettext_noop("Specify certification authority authorization record"), NULL },  
  495:   { LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
  496:   { LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL },
  497:   { LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>", gettext_noop("Export local names to global DNS"), NULL },
  498:   { LOPT_AUTHZONE, ARG_DUP, "<domain>,[<subnet>...]", gettext_noop("Domain to export to global DNS"), NULL },
  499:   { LOPT_AUTHTTL, ARG_ONE, "<integer>", gettext_noop("Set TTL for authoritative replies"), NULL },
  500:   { LOPT_AUTHSOA, ARG_ONE, "<serial>[,...]", gettext_noop("Set authoritative zone information"), NULL },
  501:   { LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
  502:   { LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL },
  503:   { LOPT_IPSET, ARG_DUP, "/<domain>[/<domain>...]/<ipset>...", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },
  504:   { LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for synthesised names"), NULL },
  505:   { LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
  506:   { LOPT_TRUST_ANCHOR, ARG_DUP, "<domain>,[<class>],...", gettext_noop("Specify trust anchor key digest."), NULL },
  507:   { LOPT_DNSSEC_DEBUG, OPT_DNSSEC_DEBUG, NULL, gettext_noop("Disable upstream checking for DNSSEC debugging."), NULL },
  508:   { LOPT_DNSSEC_CHECK, ARG_DUP, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
  509:   { LOPT_DNSSEC_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL },
  510:   { LOPT_DNSSEC_STAMP, ARG_ONE, "<path>", gettext_noop("Timestamp file to verify system clock for DNSSEC"), NULL },
  511:   { LOPT_RA_PARAM, ARG_DUP, "<iface>,[mtu:<value>|<interface>|off,][<prio>,]<intval>[,<lifetime>]", gettext_noop("Set MTU, priority, resend-interval and router-lifetime"), NULL },
  512:   { LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
  513:   { LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
  514:   { LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
  515:   { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks."), NULL },
  516:   { LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops."), NULL },
  517:   { LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL }, 
  518:   { LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL }, 
  519:   { LOPT_REPLY_DELAY, ARG_ONE, "<integer>", gettext_noop("Delay DHCP replies for at least number of seconds."), NULL },
  520:   { LOPT_RAPID_COMMIT, OPT_RAPID_COMMIT, NULL, gettext_noop("Enables DHCPv4 Rapid Commit option."), NULL },
  521:   { LOPT_DUMPFILE, ARG_ONE, "<path>", gettext_noop("Path to debug packet dump file"), NULL },
  522:   { LOPT_DUMPMASK, ARG_ONE, "<hex>", gettext_noop("Mask which packets to dump"), NULL },
  523:   { LOPT_SCRIPT_TIME, OPT_LEASE_RENEW, NULL, gettext_noop("Call dhcp-script when lease expiry changes."), NULL },
  524:   { 0, 0, NULL, NULL, NULL }
  525: }; 
  526: 
  527: /* We hide metacharacters in quoted strings by mapping them into the ASCII control
  528:    character space. Note that the \0, \t \b \r \033 and \n characters are carefully placed in the
  529:    following sequence so that they map to themselves: it is therefore possible to call
  530:    unhide_metas repeatedly on string without breaking things.
  531:    The transformation gets undone by opt_canonicalise, atoi_check and opt_string_alloc, and a 
  532:    couple of other places. 
  533:    Note that space is included here so that
  534:    --dhcp-option=3, string
  535:    has five characters, whilst
  536:    --dhcp-option=3," string"
  537:    has six.
  538: */
  539: 
  540: static const char meta[] = "\000123456 \b\t\n78\r90abcdefABCDE\033F:,.";
  541: 
  542: static char hide_meta(char c)
  543: {
  544:   unsigned int i;
  545: 
  546:   for (i = 0; i < (sizeof(meta) - 1); i++)
  547:     if (c == meta[i])
  548:       return (char)i;
  549:   
  550:   return c;
  551: }
  552: 
  553: static char unhide_meta(char cr)
  554: { 
  555:   unsigned int c = cr;
  556:   
  557:   if (c < (sizeof(meta) - 1))
  558:     cr = meta[c];
  559:   
  560:   return cr;
  561: }
  562: 
  563: static void unhide_metas(char *cp)
  564: {
  565:   if (cp)
  566:     for(; *cp; cp++)
  567:       *cp = unhide_meta(*cp);
  568: }
  569: 
  570: static void *opt_malloc(size_t size)
  571: {
  572:   void *ret;
  573: 
  574:   if (mem_recover)
  575:     {
  576:       ret = whine_malloc(size);
  577:       if (!ret)
  578: 	longjmp(mem_jmp, 1);
  579:     }
  580:   else
  581:     ret = safe_malloc(size);
  582:   
  583:   return ret;
  584: }
  585: 
  586: static char *opt_string_alloc(const char *cp)
  587: {
  588:   char *ret = NULL;
  589:   size_t len;
  590:   
  591:   if (cp && (len = strlen(cp)) != 0)
  592:     {
  593:       ret = opt_malloc(len+1);
  594:       memcpy(ret, cp, len+1); 
  595:       
  596:       /* restore hidden metachars */
  597:       unhide_metas(ret);
  598:     }
  599:     
  600:   return ret;
  601: }
  602: 
  603: 
  604: /* find next comma, split string with zero and eliminate spaces.
  605:    return start of string following comma */
  606: 
  607: static char *split_chr(char *s, char c)
  608: {
  609:   char *comma, *p;
  610: 
  611:   if (!s || !(comma = strchr(s, c)))
  612:     return NULL;
  613:   
  614:   p = comma;
  615:   *comma = ' ';
  616:   
  617:   for (; *comma == ' '; comma++);
  618:  
  619:   for (; (p >= s) && *p == ' '; p--)
  620:     *p = 0;
  621:     
  622:   return comma;
  623: }
  624: 
  625: static char *split(char *s)
  626: {
  627:   return split_chr(s, ',');
  628: }
  629: 
  630: static char *canonicalise_opt(char *s)
  631: {
  632:   char *ret;
  633:   int nomem;
  634: 
  635:   if (!s)
  636:     return 0;
  637: 
  638:   unhide_metas(s);
  639:   if (!(ret = canonicalise(s, &nomem)) && nomem)
  640:     {
  641:       if (mem_recover)
  642: 	longjmp(mem_jmp, 1);
  643:       else
  644: 	die(_("could not get memory"), NULL, EC_NOMEM);
  645:     }
  646: 
  647:   return ret;
  648: }
  649: 
  650: static int atoi_check(char *a, int *res)
  651: {
  652:   char *p;
  653: 
  654:   if (!a)
  655:     return 0;
  656: 
  657:   unhide_metas(a);
  658:   
  659:   for (p = a; *p; p++)
  660:      if (*p < '0' || *p > '9')
  661:        return 0;
  662: 
  663:   *res = atoi(a);
  664:   return 1;
  665: }
  666: 
  667: static int atoi_check16(char *a, int *res)
  668: {
  669:   if (!(atoi_check(a, res)) ||
  670:       *res < 0 ||
  671:       *res > 0xffff)
  672:     return 0;
  673: 
  674:   return 1;
  675: }
  676: 
  677: #ifdef HAVE_DNSSEC
  678: static int atoi_check8(char *a, int *res)
  679: {
  680:   if (!(atoi_check(a, res)) ||
  681:       *res < 0 ||
  682:       *res > 0xff)
  683:     return 0;
  684: 
  685:   return 1;
  686: }
  687: #endif
  688: 
  689: #ifndef NO_ID
  690: static void add_txt(char *name, char *txt, int stat)
  691: {
  692:   struct txt_record *r = opt_malloc(sizeof(struct txt_record));
  693: 
  694:   if (txt)
  695:     {
  696:       size_t len = strlen(txt);
  697:       r->txt = opt_malloc(len+1);
  698:       r->len = len+1;
  699:       *(r->txt) = len;
  700:       memcpy((r->txt)+1, txt, len);
  701:     }
  702: 
  703:   r->stat = stat;
  704:   r->name = opt_string_alloc(name);
  705:   r->next = daemon->txt;
  706:   daemon->txt = r;
  707:   r->class = C_CHAOS;
  708: }
  709: #endif
  710: 
  711: static void do_usage(void)
  712: {
  713:   char buff[100];
  714:   int i, j;
  715: 
  716:   struct {
  717:     char handle;
  718:     int val;
  719:   } tab[] = {
  720:     { '$', CACHESIZ },
  721:     { '*', EDNS_PKTSZ },
  722:     { '&', MAXLEASES },
  723:     { '!', FTABSIZ },
  724:     { '#', TFTP_MAX_CONNECTIONS },
  725:     { '\0', 0 }
  726:   };
  727: 
  728:   printf(_("Usage: dnsmasq [options]\n\n"));
  729: #ifndef HAVE_GETOPT_LONG
  730:   printf(_("Use short options only on the command line.\n"));
  731: #endif
  732:   printf(_("Valid options are:\n"));
  733:   
  734:   for (i = 0; usage[i].opt != 0; i++)
  735:     {
  736:       char *desc = usage[i].flagdesc; 
  737:       char *eq = "=";
  738:       
  739:       if (!desc || *desc == '[')
  740: 	eq = "";
  741:       
  742:       if (!desc)
  743: 	desc = "";
  744: 
  745:       for ( j = 0; opts[j].name; j++)
  746: 	if (opts[j].val == usage[i].opt)
  747: 	  break;
  748:       if (usage[i].opt < 256)
  749: 	sprintf(buff, "-%c, ", usage[i].opt);
  750:       else
  751: 	sprintf(buff, "    ");
  752:       
  753:       sprintf(buff+4, "--%s%s%s", opts[j].name, eq, desc);
  754:       printf("%-55.55s", buff);
  755: 	     
  756:       if (usage[i].arg)
  757: 	{
  758: 	  strcpy(buff, usage[i].arg);
  759: 	  for (j = 0; tab[j].handle; j++)
  760: 	    if (tab[j].handle == *(usage[i].arg))
  761: 	      sprintf(buff, "%d", tab[j].val);
  762: 	}
  763:       printf(_(usage[i].desc), buff);
  764:       printf("\n");
  765:     }
  766: }
  767: 
  768: #define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
  769: #define ret_err_free(x,m) do { strcpy(errstr, (x)); free((m)); return 0; } while (0)
  770: #define goto_err(x) do { strcpy(errstr, (x)); goto on_error; } while (0)
  771: 
  772: static char *parse_mysockaddr(char *arg, union mysockaddr *addr) 
  773: {
  774:   if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
  775:     addr->sa.sa_family = AF_INET;
  776:   else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
  777:     addr->sa.sa_family = AF_INET6;
  778:   else
  779:     return _("bad address");
  780:    
  781:   return NULL;
  782: }
  783: 
  784: char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags)
  785: {
  786:   int source_port = 0, serv_port = NAMESERVER_PORT;
  787:   char *portno, *source;
  788:   char *interface_opt = NULL;
  789:   int scope_index = 0;
  790:   char *scope_id;
  791:   
  792:   if (!arg || strlen(arg) == 0)
  793:     {
  794:       *flags |= SERV_NO_ADDR;
  795:       *interface = 0;
  796:       return NULL;
  797:     }
  798: 
  799:   if ((source = split_chr(arg, '@')) && /* is there a source. */
  800:       (portno = split_chr(source, '#')) &&
  801:       !atoi_check16(portno, &source_port))
  802:     return _("bad port");
  803:   
  804:   if ((portno = split_chr(arg, '#')) && /* is there a port no. */
  805:       !atoi_check16(portno, &serv_port))
  806:     return _("bad port");
  807:   
  808:   scope_id = split_chr(arg, '%');
  809:   
  810:   if (source) {
  811:     interface_opt = split_chr(source, '@');
  812: 
  813:     if (interface_opt)
  814:       {
  815: #if defined(SO_BINDTODEVICE)
  816: 	safe_strncpy(interface, interface_opt, IF_NAMESIZE);
  817: #else
  818: 	return _("interface binding not supported");
  819: #endif
  820:       }
  821:   }
  822: 
  823:   if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
  824:     {
  825:       addr->in.sin_port = htons(serv_port);	
  826:       addr->sa.sa_family = source_addr->sa.sa_family = AF_INET;
  827: #ifdef HAVE_SOCKADDR_SA_LEN
  828:       source_addr->in.sin_len = addr->in.sin_len = sizeof(struct sockaddr_in);
  829: #endif
  830:       source_addr->in.sin_addr.s_addr = INADDR_ANY;
  831:       source_addr->in.sin_port = htons(daemon->query_port);
  832:       
  833:       if (source)
  834: 	{
  835: 	  if (flags)
  836: 	    *flags |= SERV_HAS_SOURCE;
  837: 	  source_addr->in.sin_port = htons(source_port);
  838: 	  if (!(inet_pton(AF_INET, source, &source_addr->in.sin_addr) > 0))
  839: 	    {
  840: #if defined(SO_BINDTODEVICE)
  841: 	      if (interface_opt)
  842: 		return _("interface can only be specified once");
  843: 	      
  844: 	      source_addr->in.sin_addr.s_addr = INADDR_ANY;
  845: 	      safe_strncpy(interface, source, IF_NAMESIZE);
  846: #else
  847: 	      return _("interface binding not supported");
  848: #endif
  849: 	    }
  850: 	}
  851:     }
  852:   else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
  853:     {
  854:       if (scope_id && (scope_index = if_nametoindex(scope_id)) == 0)
  855: 	return _("bad interface name");
  856:       
  857:       addr->in6.sin6_port = htons(serv_port);
  858:       addr->in6.sin6_scope_id = scope_index;
  859:       source_addr->in6.sin6_addr = in6addr_any; 
  860:       source_addr->in6.sin6_port = htons(daemon->query_port);
  861:       source_addr->in6.sin6_scope_id = 0;
  862:       addr->sa.sa_family = source_addr->sa.sa_family = AF_INET6;
  863:       addr->in6.sin6_flowinfo = source_addr->in6.sin6_flowinfo = 0;
  864: #ifdef HAVE_SOCKADDR_SA_LEN
  865:       addr->in6.sin6_len = source_addr->in6.sin6_len = sizeof(addr->in6);
  866: #endif
  867:       if (source)
  868: 	{
  869: 	  if (flags)
  870: 	    *flags |= SERV_HAS_SOURCE;
  871: 	  source_addr->in6.sin6_port = htons(source_port);
  872: 	  if (inet_pton(AF_INET6, source, &source_addr->in6.sin6_addr) == 0)
  873: 	    {
  874: #if defined(SO_BINDTODEVICE)
  875: 	      if (interface_opt)
  876: 		return _("interface can only be specified once");
  877: 	      
  878: 	      source_addr->in6.sin6_addr = in6addr_any;
  879: 	      safe_strncpy(interface, source, IF_NAMESIZE);
  880: #else
  881: 	      return _("interface binding not supported");
  882: #endif
  883: 	    }
  884: 	}
  885:     }
  886:   else
  887:     return _("bad address");
  888: 
  889:   return NULL;
  890: }
  891: 
  892: static struct server *add_rev4(struct in_addr addr, int msize)
  893: {
  894:   struct server *serv = opt_malloc(sizeof(struct server));
  895:   in_addr_t  a = ntohl(addr.s_addr);
  896:   char *p;
  897: 
  898:   memset(serv, 0, sizeof(struct server));
  899:   p = serv->domain = opt_malloc(29); /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */
  900: 
  901:   switch (msize)
  902:     {
  903:     case 32:
  904:       p += sprintf(p, "%u.", a & 0xff);
  905:       /* fall through */
  906:     case 24:
  907:       p += sprintf(p, "%d.", (a >> 8) & 0xff);
  908:       /* fall through */
  909:     case 16:
  910:       p += sprintf(p, "%d.", (a >> 16) & 0xff);
  911:       /* fall through */
  912:     case 8:
  913:       p += sprintf(p, "%d.", (a >> 24) & 0xff);
  914:       break;
  915:     default:
  916:       free(serv->domain);
  917:       free(serv);
  918:       return NULL;
  919:     }
  920: 
  921:   p += sprintf(p, "in-addr.arpa");
  922:   
  923:   serv->flags = SERV_HAS_DOMAIN;
  924:   serv->next = daemon->servers;
  925:   daemon->servers = serv;
  926: 
  927:   return serv;
  928: 
  929: }
  930: 
  931: static struct server *add_rev6(struct in6_addr *addr, int msize)
  932: {
  933:   struct server *serv = opt_malloc(sizeof(struct server));
  934:   char *p;
  935:   int i;
  936: 				  
  937:   memset(serv, 0, sizeof(struct server));
  938:   p = serv->domain = opt_malloc(73); /* strlen("32*<n.>ip6.arpa")+1 */
  939:   
  940:   for (i = msize-1; i >= 0; i -= 4)
  941:     { 
  942:       int dig = ((unsigned char *)addr)[i>>3];
  943:       p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
  944:     }
  945:   p += sprintf(p, "ip6.arpa");
  946:   
  947:   serv->flags = SERV_HAS_DOMAIN;
  948:   serv->next = daemon->servers;
  949:   daemon->servers = serv;
  950:   
  951:   return serv;
  952: }
  953: 
  954: #ifdef HAVE_DHCP
  955: 
  956: static int is_tag_prefix(char *arg)
  957: {
  958:   if (arg && (strstr(arg, "net:") == arg || strstr(arg, "tag:") == arg))
  959:     return 1;
  960:   
  961:   return 0;
  962: }
  963: 
  964: static char *set_prefix(char *arg)
  965: {
  966:    if (strstr(arg, "set:") == arg)
  967:      return arg+4;
  968:    
  969:    return arg;
  970: }
  971: 
  972: static struct dhcp_netid *dhcp_netid_create(const char *net, struct dhcp_netid *next)
  973: {
  974:   struct dhcp_netid *tt;
  975:   tt = opt_malloc(sizeof (struct dhcp_netid));
  976:   tt->net = opt_string_alloc(net);
  977:   tt->next = next;
  978:   return tt;
  979: }
  980: 
  981: static void dhcp_netid_free(struct dhcp_netid *nid)
  982: {
  983:   while (nid)
  984:     {
  985:       struct dhcp_netid *tmp = nid;
  986:       nid = nid->next;
  987:       free(tmp->net);
  988:       free(tmp);
  989:     }
  990: }
  991: 
  992: /* Parse one or more tag:s before parameters.
  993:  * Moves arg to the end of tags. */
  994: static struct dhcp_netid * dhcp_tags(char **arg)
  995: {
  996:   struct dhcp_netid *id = NULL;
  997: 
  998:   while (is_tag_prefix(*arg))
  999:     {
 1000:       char *comma = split(*arg);
 1001:       id = dhcp_netid_create((*arg)+4, id);
 1002:       *arg = comma;
 1003:     };
 1004:   if (!*arg)
 1005:     {
 1006:       dhcp_netid_free(id);
 1007:       id = NULL;
 1008:     }
 1009:   return id;
 1010: }
 1011: 
 1012: static void dhcp_netid_list_free(struct dhcp_netid_list *netid)
 1013: {
 1014:   while (netid)
 1015:     {
 1016:       struct dhcp_netid_list *tmplist = netid;
 1017:       netid = netid->next;
 1018:       dhcp_netid_free(tmplist->list);
 1019:       free(tmplist);
 1020:     }
 1021: }
 1022: 
 1023: static void dhcp_config_free(struct dhcp_config *config)
 1024: {
 1025:   if (config)
 1026:     {
 1027:       struct hwaddr_config *hwaddr = config->hwaddr;
 1028:       
 1029:       while (hwaddr)
 1030:         {
 1031: 	  struct hwaddr_config *tmp = hwaddr;
 1032:           hwaddr = hwaddr->next;
 1033: 	  free(tmp);
 1034:         }
 1035:       
 1036:       dhcp_netid_list_free(config->netid);
 1037:       dhcp_netid_free(config->filter);
 1038:       
 1039:       if (config->flags & CONFIG_CLID)
 1040:         free(config->clid);
 1041: 
 1042: #ifdef HAVE_DHCP6
 1043:       if (config->flags & CONFIG_ADDR6)
 1044: 	{
 1045: 	  struct addrlist *addr, *tmp;
 1046: 	  
 1047: 	  for (addr = config->addr6; addr; addr = tmp)
 1048: 	    {
 1049: 	      tmp = addr->next;
 1050: 	      free(addr);
 1051: 	    }
 1052: 	}
 1053: #endif
 1054: 
 1055:       free(config);
 1056:     }
 1057: }
 1058: 
 1059: static void dhcp_context_free(struct dhcp_context *ctx)
 1060: {
 1061:   if (ctx)
 1062:     {
 1063:       dhcp_netid_free(ctx->filter);
 1064:       free(ctx->netid.net);
 1065: #ifdef HAVE_DHCP6
 1066:       free(ctx->template_interface);
 1067: #endif
 1068:       free(ctx);
 1069:     }
 1070: }
 1071: 
 1072: static void dhcp_opt_free(struct dhcp_opt *opt)
 1073: {
 1074:   if (opt->flags & DHOPT_VENDOR)
 1075:     free(opt->u.vendor_class);
 1076:   dhcp_netid_free(opt->netid);
 1077:   free(opt->val);
 1078:   free(opt);
 1079: }
 1080: 
 1081: 
 1082: /* This is too insanely large to keep in-line in the switch */
 1083: static int parse_dhcp_opt(char *errstr, char *arg, int flags)
 1084: {
 1085:   struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
 1086:   char lenchar = 0, *cp;
 1087:   int addrs, digs, is_addr, is_addr6, is_hex, is_dec, is_string, dots;
 1088:   char *comma = NULL;
 1089:   u16 opt_len = 0;
 1090:   int is6 = 0;
 1091:   int option_ok = 0;
 1092: 
 1093:   new->len = 0;
 1094:   new->flags = flags;
 1095:   new->netid = NULL;
 1096:   new->val = NULL;
 1097:   new->opt = 0;
 1098:   
 1099:   while (arg)
 1100:     {
 1101:       comma = split(arg);      
 1102: 
 1103:       for (cp = arg; *cp; cp++)
 1104: 	if (*cp < '0' || *cp > '9')
 1105: 	  break;
 1106:       
 1107:       if (!*cp)
 1108: 	{
 1109: 	  new->opt = atoi(arg);
 1110: 	  opt_len = 0;
 1111: 	  option_ok = 1;
 1112: 	  break;
 1113: 	}
 1114:       
 1115:       if (strstr(arg, "option:") == arg)
 1116: 	{
 1117: 	  if ((new->opt = lookup_dhcp_opt(AF_INET, arg+7)) != -1)
 1118: 	    {
 1119: 	      opt_len = lookup_dhcp_len(AF_INET, new->opt);
 1120: 	      /* option:<optname> must follow tag and vendor string. */
 1121: 	      if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
 1122: 		option_ok = 1;
 1123: 	    }
 1124: 	  break;
 1125: 	}
 1126: #ifdef HAVE_DHCP6
 1127:       else if (strstr(arg, "option6:") == arg)
 1128: 	{
 1129: 	  for (cp = arg+8; *cp; cp++)
 1130: 	    if (*cp < '0' || *cp > '9')
 1131: 	      break;
 1132: 	 
 1133: 	  if (!*cp)
 1134: 	    {
 1135: 	      new->opt = atoi(arg+8);
 1136: 	      opt_len = 0;
 1137: 	      option_ok = 1;
 1138: 	    }
 1139: 	  else
 1140: 	    {
 1141: 	      if ((new->opt = lookup_dhcp_opt(AF_INET6, arg+8)) != -1)
 1142: 		{
 1143: 		  opt_len = lookup_dhcp_len(AF_INET6, new->opt);
 1144: 		  if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
 1145: 		    option_ok = 1;
 1146: 		}
 1147: 	    }
 1148: 	  /* option6:<opt>|<optname> must follow tag and vendor string. */
 1149: 	  is6 = 1;
 1150: 	  break;
 1151: 	}
 1152: #endif
 1153:       else if (strstr(arg, "vendor:") == arg)
 1154: 	{
 1155: 	  new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7);
 1156: 	  new->flags |= DHOPT_VENDOR;
 1157: 	}
 1158:       else if (strstr(arg, "encap:") == arg)
 1159: 	{
 1160: 	  new->u.encap = atoi(arg+6);
 1161: 	  new->flags |= DHOPT_ENCAPSULATE;
 1162: 	}
 1163:       else if (strstr(arg, "vi-encap:") == arg)
 1164: 	{
 1165: 	  new->u.encap = atoi(arg+9);
 1166: 	  new->flags |= DHOPT_RFC3925;
 1167: 	  if (flags == DHOPT_MATCH)
 1168: 	    {
 1169: 	      option_ok = 1;
 1170: 	      break;
 1171: 	    }
 1172: 	}
 1173:       else
 1174: 	{
 1175: 	  /* allow optional "net:" or "tag:" for consistency */
 1176: 	  const char *name = (is_tag_prefix(arg)) ? arg+4 : set_prefix(arg);
 1177: 	  new->netid = dhcp_netid_create(name, new->netid);
 1178: 	}
 1179:       
 1180:       arg = comma; 
 1181:     }
 1182: 
 1183: #ifdef HAVE_DHCP6
 1184:   if (is6)
 1185:     {
 1186:       if (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))
 1187: 	goto_err(_("unsupported encapsulation for IPv6 option"));
 1188:       
 1189:       if (opt_len == 0 &&
 1190: 	  !(new->flags & DHOPT_RFC3925))
 1191: 	opt_len = lookup_dhcp_len(AF_INET6, new->opt);
 1192:     }
 1193:   else
 1194: #endif
 1195:     if (opt_len == 0 &&
 1196: 	!(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
 1197:       opt_len = lookup_dhcp_len(AF_INET, new->opt);
 1198:   
 1199:   /* option may be missing with rfc3925 match */
 1200:   if (!option_ok)
 1201:     goto_err(_("bad dhcp-option"));
 1202:   
 1203:   if (comma)
 1204:     {
 1205:       /* characterise the value */
 1206:       char c;
 1207:       int found_dig = 0, found_colon = 0;
 1208:       is_addr = is_addr6 = is_hex = is_dec = is_string = 1;
 1209:       addrs = digs = 1;
 1210:       dots = 0;
 1211:       for (cp = comma; (c = *cp); cp++)
 1212: 	if (c == ',')
 1213: 	  {
 1214: 	    addrs++;
 1215: 	    is_dec = is_hex = 0;
 1216: 	  }
 1217: 	else if (c == ':')
 1218: 	  {
 1219: 	    digs++;
 1220: 	    is_dec = is_addr = 0;
 1221: 	    found_colon = 1;
 1222: 	  }
 1223: 	else if (c == '/') 
 1224: 	  {
 1225: 	    is_addr6 = is_dec = is_hex = 0;
 1226: 	    if (cp == comma) /* leading / means a pathname */
 1227: 	      is_addr = 0;
 1228: 	  } 
 1229: 	else if (c == '.')	
 1230: 	  {
 1231: 	    is_dec = is_hex = 0;
 1232: 	    dots++;
 1233: 	  }
 1234: 	else if (c == '-')
 1235: 	  is_hex = is_addr = is_addr6 = 0;
 1236: 	else if (c == ' ')
 1237: 	  is_dec = is_hex = 0;
 1238: 	else if (!(c >='0' && c <= '9'))
 1239: 	  {
 1240: 	    is_addr = 0;
 1241: 	    if (cp[1] == 0 && is_dec &&
 1242: 		(c == 'b' || c == 's' || c == 'i'))
 1243: 	      {
 1244: 		lenchar = c;
 1245: 		*cp = 0;
 1246: 	      }
 1247: 	    else
 1248: 	      is_dec = 0;
 1249: 	    if (!((c >='A' && c <= 'F') ||
 1250: 		  (c >='a' && c <= 'f') || 
 1251: 		  (c == '*' && (flags & DHOPT_MATCH))))
 1252: 	      {
 1253: 		is_hex = 0;
 1254: 		if (c != '[' && c != ']')
 1255: 		  is_addr6 = 0;
 1256: 	      }
 1257: 	  }
 1258: 	else
 1259: 	  found_dig = 1;
 1260:      
 1261:       if (!found_dig)
 1262: 	is_dec = is_addr = 0;
 1263: 
 1264:       if (!found_colon)
 1265: 	is_addr6 = 0;
 1266: 
 1267: #ifdef HAVE_DHCP6
 1268:       /* NTP server option takes hex, addresses or FQDN */
 1269:       if (is6 && new->opt == OPTION6_NTP_SERVER && !is_hex)
 1270: 	opt_len |= is_addr6 ? OT_ADDR_LIST : OT_RFC1035_NAME;
 1271: #endif
 1272:      
 1273:       /* We know that some options take addresses */
 1274:       if (opt_len & OT_ADDR_LIST)
 1275: 	{
 1276: 	  is_string = is_dec = is_hex = 0;
 1277: 	  
 1278: 	  if (!is6 && (!is_addr || dots == 0))
 1279: 	    goto_err(_("bad IP address"));
 1280: 
 1281: 	   if (is6 && !is_addr6)
 1282: 	     goto_err(_("bad IPv6 address"));
 1283: 	}
 1284:       /* or names */
 1285:       else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING))
 1286: 	is_addr6 = is_addr = is_dec = is_hex = 0;
 1287:       
 1288:       if (found_dig && (opt_len & OT_TIME) && strlen(comma) > 0)
 1289: 	{
 1290: 	  int val, fac = 1;
 1291: 
 1292: 	  switch (comma[strlen(comma) - 1])
 1293: 	    {
 1294: 	    case 'w':
 1295: 	    case 'W':
 1296: 	      fac *= 7;
 1297: 	      /* fall through */
 1298: 	    case 'd':
 1299: 	    case 'D':
 1300: 	      fac *= 24;
 1301: 	      /* fall through */
 1302: 	    case 'h':
 1303: 	    case 'H':
 1304: 	      fac *= 60;
 1305: 	      /* fall through */
 1306: 	    case 'm':
 1307: 	    case 'M':
 1308: 	      fac *= 60;
 1309: 	      /* fall through */
 1310: 	    case 's':
 1311: 	    case 'S':
 1312: 	      comma[strlen(comma) - 1] = 0;
 1313: 	    }
 1314: 	  
 1315: 	  new->len = 4;
 1316: 	  new->val = opt_malloc(4);
 1317: 	  val = atoi(comma);
 1318: 	  *((int *)new->val) = htonl(val * fac);	  
 1319: 	}  
 1320:       else if (is_hex && digs > 1)
 1321: 	{
 1322: 	  new->len = digs;
 1323: 	  new->val = opt_malloc(new->len);
 1324: 	  parse_hex(comma, new->val, digs, (flags & DHOPT_MATCH) ? &new->u.wildcard_mask : NULL, NULL);
 1325: 	  new->flags |= DHOPT_HEX;
 1326: 	}
 1327:       else if (is_dec)
 1328: 	{
 1329: 	  int i, val = atoi(comma);
 1330: 	  /* assume numeric arg is 1 byte except for
 1331: 	     options where it is known otherwise.
 1332: 	     For vendor class option, we have to hack. */
 1333: 	  if (opt_len != 0)
 1334: 	    new->len = opt_len;
 1335: 	  else if (val & 0xffff0000)
 1336: 	    new->len = 4;
 1337: 	  else if (val & 0xff00)
 1338: 	    new->len = 2;
 1339: 	  else
 1340: 	    new->len = 1;
 1341: 
 1342: 	  if (lenchar == 'b')
 1343: 	    new->len = 1;
 1344: 	  else if (lenchar == 's')
 1345: 	    new->len = 2;
 1346: 	  else if (lenchar == 'i')
 1347: 	    new->len = 4;
 1348: 	  
 1349: 	  new->val = opt_malloc(new->len);
 1350: 	  for (i=0; i<new->len; i++)
 1351: 	    new->val[i] = val>>((new->len - i - 1)*8);
 1352: 	}
 1353:       else if (is_addr && !is6)	
 1354: 	{
 1355: 	  struct in_addr in;
 1356: 	  unsigned char *op;
 1357: 	  char *slash;
 1358: 	  /* max length of address/subnet descriptor is five bytes,
 1359: 	     add one for the option 120 enc byte too */
 1360: 	  new->val = op = opt_malloc((5 * addrs) + 1);
 1361: 	  new->flags |= DHOPT_ADDR;
 1362: 
 1363: 	  if (!(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) && 
 1364: 	      new->opt == OPTION_SIP_SERVER)
 1365: 	    {
 1366: 	      *(op++) = 1; /* RFC 3361 "enc byte" */
 1367: 	      new->flags &= ~DHOPT_ADDR;
 1368: 	    }
 1369: 	  while (addrs--) 
 1370: 	    {
 1371: 	      cp = comma;
 1372: 	      comma = split(cp);
 1373: 	      slash = split_chr(cp, '/');
 1374: 	      if (!inet_pton(AF_INET, cp, &in))
 1375: 		goto_err(_("bad IPv4 address"));
 1376: 	      if (!slash)
 1377: 		{
 1378: 		  memcpy(op, &in, INADDRSZ);
 1379: 		  op += INADDRSZ;
 1380: 		}
 1381: 	      else
 1382: 		{
 1383: 		  unsigned char *p = (unsigned char *)&in;
 1384: 		  int netsize = atoi(slash);
 1385: 		  *op++ = netsize;
 1386: 		  if (netsize > 0)
 1387: 		    *op++ = *p++;
 1388: 		  if (netsize > 8)
 1389: 		    *op++ = *p++;
 1390: 		  if (netsize > 16)
 1391: 		    *op++ = *p++;
 1392: 		  if (netsize > 24)
 1393: 		    *op++ = *p++;
 1394: 		  new->flags &= ~DHOPT_ADDR; /* cannot re-write descriptor format */
 1395: 		} 
 1396: 	    }
 1397: 	  new->len = op - new->val;
 1398: 	}
 1399:       else if (is_addr6 && is6)
 1400: 	{
 1401: 	  unsigned char *op;
 1402: 	  new->val = op = opt_malloc(16 * addrs);
 1403: 	  new->flags |= DHOPT_ADDR6;
 1404: 	  while (addrs--) 
 1405: 	    {
 1406: 	      cp = comma;
 1407: 	      comma = split(cp);
 1408: 	      
 1409: 	      /* check for [1234::7] */
 1410: 	      if (*cp == '[')
 1411: 		cp++;
 1412: 	      if (strlen(cp) > 1 && cp[strlen(cp)-1] == ']')
 1413: 		cp[strlen(cp)-1] = 0;
 1414: 	      
 1415: 	      if (inet_pton(AF_INET6, cp, op))
 1416: 		{
 1417: 		  op += IN6ADDRSZ;
 1418: 		  continue;
 1419: 		}
 1420: 
 1421: 	      goto_err(_("bad IPv6 address"));
 1422: 	    } 
 1423: 	  new->len = op - new->val;
 1424: 	}
 1425:       else if (is_string)
 1426: 	{
 1427:  	  /* text arg */
 1428: 	  if ((new->opt == OPTION_DOMAIN_SEARCH || new->opt == OPTION_SIP_SERVER) &&
 1429: 	      !is6 && !(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
 1430: 	    {
 1431: 	      /* dns search, RFC 3397, or SIP, RFC 3361 */
 1432: 	      unsigned char *q, *r, *tail;
 1433: 	      unsigned char *p, *m = NULL, *newp;
 1434: 	      size_t newlen, len = 0;
 1435: 	      int header_size = (new->opt == OPTION_DOMAIN_SEARCH) ? 0 : 1;
 1436: 	      
 1437: 	      arg = comma;
 1438: 	      comma = split(arg);
 1439: 	      
 1440: 	      while (arg && *arg)
 1441: 		{
 1442: 		  char *in, *dom = NULL;
 1443: 		  size_t domlen = 1;
 1444: 		  /* Allow "." as an empty domain */
 1445: 		  if (strcmp (arg, ".") != 0)
 1446: 		    {
 1447: 		      if (!(dom = canonicalise_opt(arg)))
 1448: 			goto_err(_("bad domain in dhcp-option"));
 1449: 			
 1450: 		      domlen = strlen(dom) + 2;
 1451: 		    }
 1452: 		      
 1453: 		  newp = opt_malloc(len + domlen + header_size);
 1454: 		  if (m)
 1455: 		    {
 1456: 		      memcpy(newp, m, header_size + len);
 1457: 		      free(m);
 1458: 		    }
 1459: 		  m = newp;
 1460: 		  p = m + header_size;
 1461: 		  q = p + len;
 1462: 		  
 1463: 		  /* add string on the end in RFC1035 format */
 1464: 		  for (in = dom; in && *in;) 
 1465: 		    {
 1466: 		      unsigned char *cp = q++;
 1467: 		      int j;
 1468: 		      for (j = 0; *in && (*in != '.'); in++, j++)
 1469: 			*q++ = *in;
 1470: 		      *cp = j;
 1471: 		      if (*in)
 1472: 			in++;
 1473: 		    }
 1474: 		  *q++ = 0;
 1475: 		  free(dom);
 1476: 		  
 1477: 		  /* Now tail-compress using earlier names. */
 1478: 		  newlen = q - p;
 1479: 		  for (tail = p + len; *tail; tail += (*tail) + 1)
 1480: 		    for (r = p; r - p < (int)len; r += (*r) + 1)
 1481: 		      if (strcmp((char *)r, (char *)tail) == 0)
 1482: 			{
 1483: 			  PUTSHORT((r - p) | 0xc000, tail); 
 1484: 			  newlen = tail - p;
 1485: 			  goto end;
 1486: 			}
 1487: 		end:
 1488: 		  len = newlen;
 1489: 		  
 1490: 		  arg = comma;
 1491: 		  comma = split(arg);
 1492: 		}
 1493:       
 1494: 	      /* RFC 3361, enc byte is zero for names */
 1495: 	      if (new->opt == OPTION_SIP_SERVER && m)
 1496: 		m[0] = 0;
 1497: 	      new->len = (int) len + header_size;
 1498: 	      new->val = m;
 1499: 	    }
 1500: #ifdef HAVE_DHCP6
 1501: 	  else if (comma && (opt_len & OT_CSTRING))
 1502: 	    {
 1503: 	      /* length fields are two bytes so need 16 bits for each string */
 1504: 	      int i, commas = 1;
 1505: 	      unsigned char *p, *newp;
 1506: 
 1507: 	      for (i = 0; comma[i]; i++)
 1508: 		if (comma[i] == ',')
 1509: 		  commas++;
 1510: 	      
 1511: 	      newp = opt_malloc(strlen(comma)+(2*commas));	  
 1512: 	      p = newp;
 1513: 	      arg = comma;
 1514: 	      comma = split(arg);
 1515: 	      
 1516: 	      while (arg && *arg)
 1517: 		{
 1518: 		  u16 len = strlen(arg);
 1519: 		  unhide_metas(arg);
 1520: 		  PUTSHORT(len, p);
 1521: 		  memcpy(p, arg, len);
 1522: 		  p += len; 
 1523: 
 1524: 		  arg = comma;
 1525: 		  comma = split(arg);
 1526: 		}
 1527: 
 1528: 	      new->val = newp;
 1529: 	      new->len = p - newp;
 1530: 	    }
 1531: 	  else if (comma && (opt_len & OT_RFC1035_NAME))
 1532: 	    {
 1533: 	      unsigned char *p = NULL, *q, *newp, *end;
 1534: 	      int len = 0;
 1535: 	      int header_size = (is6 && new->opt == OPTION6_NTP_SERVER) ? 4 : 0;
 1536: 	      arg = comma;
 1537: 	      comma = split(arg);
 1538: 	      
 1539: 	      while (arg && *arg)
 1540: 		{
 1541: 		  char *dom = canonicalise_opt(arg);
 1542: 		  if (!dom)
 1543: 		    goto_err(_("bad domain in dhcp-option"));
 1544: 		    		  
 1545: 		  newp = opt_malloc(len + header_size + strlen(dom) + 2);
 1546: 		  
 1547: 		  if (p)
 1548: 		    {
 1549: 		      memcpy(newp, p, len);
 1550: 		      free(p);
 1551: 		    }
 1552: 		  
 1553: 		  p = newp;
 1554: 		  q = p + len;
 1555: 		  end = do_rfc1035_name(q + header_size, dom, NULL);
 1556: 		  *end++ = 0;
 1557: 		  if (is6 && new->opt == OPTION6_NTP_SERVER)
 1558: 		    {
 1559: 		      PUTSHORT(NTP_SUBOPTION_SRV_FQDN, q);
 1560: 		      PUTSHORT(end - q - 2, q);
 1561: 		    }
 1562: 		  len = end - p;
 1563: 		  free(dom);
 1564: 
 1565: 		  arg = comma;
 1566: 		  comma = split(arg);
 1567: 		}
 1568: 	      
 1569: 	      new->val = p;
 1570: 	      new->len = len;
 1571: 	    }
 1572: #endif
 1573: 	  else
 1574: 	    {
 1575: 	      new->len = strlen(comma);
 1576: 	      /* keep terminating zero on string */
 1577: 	      new->val = (unsigned char *)opt_string_alloc(comma);
 1578: 	      new->flags |= DHOPT_STRING;
 1579: 	    }
 1580: 	}
 1581:     }
 1582: 
 1583:   if (!is6 && 
 1584:       ((new->len > 255) || 
 1585:       (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) ||
 1586:        (new->len > 250 && (new->flags & DHOPT_RFC3925))))
 1587:     goto_err(_("dhcp-option too long"));
 1588:   
 1589:   if (flags == DHOPT_MATCH)
 1590:     {
 1591:       if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||
 1592: 	  !new->netid ||
 1593: 	  new->netid->next)
 1594: 	goto_err(_("illegal dhcp-match"));
 1595:        
 1596:       if (is6)
 1597: 	{
 1598: 	  new->next = daemon->dhcp_match6;
 1599: 	  daemon->dhcp_match6 = new;
 1600: 	}
 1601:       else
 1602: 	{
 1603: 	  new->next = daemon->dhcp_match;
 1604: 	  daemon->dhcp_match = new;
 1605: 	}
 1606:     }
 1607:   else if (is6)
 1608:     {
 1609:       new->next = daemon->dhcp_opts6;
 1610:       daemon->dhcp_opts6 = new;
 1611:     }
 1612:   else
 1613:     {
 1614:       new->next = daemon->dhcp_opts;
 1615:       daemon->dhcp_opts = new;
 1616:     }
 1617:     
 1618:   return 1;
 1619: on_error:
 1620:   dhcp_opt_free(new);
 1621:   return 0;
 1622: }
 1623: 
 1624: #endif
 1625: 
 1626: void set_option_bool(unsigned int opt)
 1627: {
 1628:   option_var(opt) |= option_val(opt);
 1629: }
 1630: 
 1631: void reset_option_bool(unsigned int opt)
 1632: {
 1633:   option_var(opt) &= ~(option_val(opt));
 1634: }
 1635: 
 1636: static void server_list_free(struct server *list)
 1637: {
 1638:   while (list)
 1639:     {
 1640:       struct server *tmp = list;
 1641:       list = list->next;
 1642:       free(tmp);
 1643:     }
 1644: }
 1645: 
 1646: static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only)
 1647: {      
 1648:   int i;
 1649:   char *comma;
 1650: 
 1651:   if (option == '?')
 1652:     ret_err(gen_err);
 1653:   
 1654:   for (i=0; usage[i].opt != 0; i++)
 1655:     if (usage[i].opt == option)
 1656:       {
 1657: 	 int rept = usage[i].rept;
 1658: 	 
 1659: 	 if (command_line)
 1660: 	   {
 1661: 	     /* command line */
 1662: 	     if (rept == ARG_USED_CL)
 1663: 	       ret_err(_("illegal repeated flag"));
 1664: 	     if (rept == ARG_ONE)
 1665: 	       usage[i].rept = ARG_USED_CL;
 1666: 	   }
 1667: 	 else
 1668: 	   {
 1669: 	     /* allow file to override command line */
 1670: 	     if (rept == ARG_USED_FILE)
 1671: 	       ret_err(_("illegal repeated keyword"));
 1672: 	     if (rept == ARG_USED_CL || rept == ARG_ONE)
 1673: 	       usage[i].rept = ARG_USED_FILE;
 1674: 	   }
 1675: 
 1676: 	 if (rept != ARG_DUP && rept != ARG_ONE && rept != ARG_USED_CL) 
 1677: 	   {
 1678: 	     set_option_bool(rept);
 1679: 	     return 1;
 1680: 	   }
 1681:        
 1682: 	 break;
 1683:       }
 1684:   
 1685:   switch (option)
 1686:     { 
 1687:     case 'C': /* --conf-file */
 1688:       {
 1689: 	char *file = opt_string_alloc(arg);
 1690: 	if (file)
 1691: 	  {
 1692: 	    one_file(file, 0);
 1693: 	    free(file);
 1694: 	  }
 1695: 	break;
 1696:       }
 1697: 
 1698:     case '7': /* --conf-dir */	      
 1699:       {
 1700: 	DIR *dir_stream;
 1701: 	struct dirent *ent;
 1702: 	char *directory, *path;
 1703: 	struct list {
 1704: 	  char *name;
 1705: 	  struct list *next;
 1706: 	} *ignore_suffix = NULL, *match_suffix = NULL, *files = NULL, *li;
 1707: 	
 1708: 	comma = split(arg);
 1709: 	if (!(directory = opt_string_alloc(arg)))
 1710: 	  break;
 1711: 	
 1712: 	for (arg = comma; arg; arg = comma) 
 1713: 	  {
 1714: 	    comma = split(arg);
 1715: 	    if (strlen(arg) != 0)
 1716: 	      {
 1717: 		li = opt_malloc(sizeof(struct list));
 1718: 		if (*arg == '*')
 1719: 		  {
 1720: 		    /* "*" with no suffix is a no-op */
 1721: 		    if (arg[1] == 0)
 1722: 		      free(li);
 1723: 		    else
 1724: 		      {
 1725: 			li->next = match_suffix;
 1726: 			match_suffix = li;
 1727: 			/* Have to copy: buffer is overwritten */
 1728: 			li->name = opt_string_alloc(arg+1);
 1729: 		      }
 1730: 		  }
 1731: 		else
 1732: 		  {
 1733: 		    li->next = ignore_suffix;
 1734: 		    ignore_suffix = li;
 1735: 		    /* Have to copy: buffer is overwritten */
 1736: 		    li->name = opt_string_alloc(arg);
 1737: 		  }
 1738: 	      }
 1739: 	  }
 1740: 	
 1741: 	if (!(dir_stream = opendir(directory)))
 1742: 	  die(_("cannot access directory %s: %s"), directory, EC_FILE);
 1743: 	
 1744: 	while ((ent = readdir(dir_stream)))
 1745: 	  {
 1746: 	    size_t len = strlen(ent->d_name);
 1747: 	    struct stat buf;
 1748: 	    
 1749: 	    /* ignore emacs backups and dotfiles */
 1750: 	    if (len == 0 ||
 1751: 		ent->d_name[len - 1] == '~' ||
 1752: 		(ent->d_name[0] == '#' && ent->d_name[len - 1] == '#') ||
 1753: 		ent->d_name[0] == '.')
 1754: 	      continue;
 1755: 
 1756: 	    if (match_suffix)
 1757: 	      {
 1758: 		for (li = match_suffix; li; li = li->next)
 1759: 		  {
 1760: 		    /* check for required suffices */
 1761: 		    size_t ls = strlen(li->name);
 1762: 		    if (len > ls &&
 1763: 			strcmp(li->name, &ent->d_name[len - ls]) == 0)
 1764: 		      break;
 1765: 		  }
 1766: 		if (!li)
 1767: 		  continue;
 1768: 	      }
 1769: 	    
 1770: 	    for (li = ignore_suffix; li; li = li->next)
 1771: 	      {
 1772: 		/* check for proscribed suffices */
 1773: 		size_t ls = strlen(li->name);
 1774: 		if (len > ls &&
 1775: 		    strcmp(li->name, &ent->d_name[len - ls]) == 0)
 1776: 		  break;
 1777: 	      }
 1778: 	    if (li)
 1779: 	      continue;
 1780: 	    
 1781: 	    path = opt_malloc(strlen(directory) + len + 2);
 1782: 	    strcpy(path, directory);
 1783: 	    strcat(path, "/");
 1784: 	    strcat(path, ent->d_name);
 1785: 
 1786: 	    /* files must be readable */
 1787: 	    if (stat(path, &buf) == -1)
 1788: 	      die(_("cannot access %s: %s"), path, EC_FILE);
 1789: 	    
 1790: 	    /* only reg files allowed. */
 1791: 	    if (S_ISREG(buf.st_mode))
 1792: 	      {
 1793: 		/* sort files into order. */
 1794: 		struct list **up, *new = opt_malloc(sizeof(struct list));
 1795: 		new->name = path;
 1796: 		
 1797: 		for (up = &files, li = files; li; up = &li->next, li = li->next)
 1798: 		  if (strcmp(li->name, path) >=0)
 1799: 		    break;
 1800: 
 1801: 		new->next = li;
 1802: 		*up = new;
 1803: 	      }
 1804: 
 1805: 	  }
 1806: 
 1807: 	for (li = files; li; li = li->next)
 1808: 	  one_file(li->name, 0);
 1809:       	
 1810: 	closedir(dir_stream);
 1811: 	free(directory);
 1812: 	for(; ignore_suffix; ignore_suffix = li)
 1813: 	  {
 1814: 	    li = ignore_suffix->next;
 1815: 	    free(ignore_suffix->name);
 1816: 	    free(ignore_suffix);
 1817: 	  }
 1818: 	for(; match_suffix; match_suffix = li)
 1819: 	  {
 1820: 	    li = match_suffix->next;
 1821: 	    free(match_suffix->name);
 1822: 	    free(match_suffix);
 1823: 	  }
 1824: 	for(; files; files = li)
 1825: 	  {
 1826: 	    li = files->next;
 1827: 	    free(files->name);
 1828: 	    free(files);
 1829: 	  }
 1830: 	break;
 1831:       }
 1832: 
 1833:     case LOPT_ADD_SBNET: /* --add-subnet */
 1834:       set_option_bool(OPT_CLIENT_SUBNET);
 1835:       if (arg)
 1836: 	{
 1837:           char *err, *end;
 1838: 	  comma = split(arg);
 1839: 
 1840:           struct mysubnet* new = opt_malloc(sizeof(struct mysubnet));
 1841:           if ((end = split_chr(arg, '/')))
 1842: 	    {
 1843: 	      /* has subnet+len */
 1844: 	      err = parse_mysockaddr(arg, &new->addr);
 1845: 	      if (err)
 1846: 		ret_err_free(err, new);
 1847: 	      if (!atoi_check(end, &new->mask))
 1848: 		ret_err_free(gen_err, new);
 1849: 	      new->addr_used = 1;
 1850: 	    } 
 1851: 	  else if (!atoi_check(arg, &new->mask))
 1852: 	    ret_err_free(gen_err, new);
 1853: 	    
 1854:           daemon->add_subnet4 = new;
 1855: 
 1856:           if (comma)
 1857:             {
 1858: 	      new = opt_malloc(sizeof(struct mysubnet));
 1859: 	      if ((end = split_chr(comma, '/')))
 1860: 		{
 1861: 		  /* has subnet+len */
 1862:                   err = parse_mysockaddr(comma, &new->addr);
 1863:                   if (err)
 1864:                     ret_err_free(err, new);
 1865:                   if (!atoi_check(end, &new->mask))
 1866:                     ret_err_free(gen_err, new);
 1867:                   new->addr_used = 1;
 1868:                 }
 1869:               else
 1870:                 {
 1871:                   if (!atoi_check(comma, &new->mask))
 1872:                     ret_err_free(gen_err, new);
 1873:                 }
 1874:           
 1875: 	      daemon->add_subnet6 = new;
 1876: 	    }
 1877: 	}
 1878:       break;
 1879: 
 1880:     case '1': /* --enable-dbus */
 1881:       set_option_bool(OPT_DBUS);
 1882:       if (arg)
 1883: 	daemon->dbus_name = opt_string_alloc(arg);
 1884:       else
 1885: 	daemon->dbus_name = DNSMASQ_SERVICE;
 1886:       break;
 1887: 
 1888:     case LOPT_UBUS: /* --enable-ubus */
 1889:       set_option_bool(OPT_UBUS);
 1890:       if (arg)
 1891: 	daemon->ubus_name = opt_string_alloc(arg);
 1892:       else
 1893: 	daemon->ubus_name = DNSMASQ_UBUS_NAME;
 1894:       break;
 1895: 
 1896:     case '8': /* --log-facility */
 1897:       /* may be a filename */
 1898:       if (strchr(arg, '/') || strcmp (arg, "-") == 0)
 1899: 	daemon->log_file = opt_string_alloc(arg);
 1900:       else
 1901: 	{	  
 1902: #ifdef __ANDROID__
 1903: 	  ret_err(_("setting log facility is not possible under Android"));
 1904: #else
 1905: 	  for (i = 0; facilitynames[i].c_name; i++)
 1906: 	    if (hostname_isequal((char *)facilitynames[i].c_name, arg))
 1907: 	      break;
 1908: 	  
 1909: 	  if (facilitynames[i].c_name)
 1910: 	    daemon->log_fac = facilitynames[i].c_val;
 1911: 	  else
 1912: 	    ret_err(_("bad log facility"));
 1913: #endif
 1914: 	}
 1915:       break;
 1916: 
 1917:     case 'x': /* --pid-file */
 1918:       daemon->runfile = opt_string_alloc(arg);
 1919:       break;
 1920: 
 1921:     case 'r': /* --resolv-file */
 1922:       {
 1923: 	char *name = opt_string_alloc(arg);
 1924: 	struct resolvc *new, *list = daemon->resolv_files;
 1925: 	
 1926: 	if (list && list->is_default)
 1927: 	  {
 1928: 	    /* replace default resolv file - possibly with nothing */
 1929: 	    if (name)
 1930: 	      {
 1931: 		list->is_default = 0;
 1932: 		list->name = name;
 1933: 	      }
 1934: 	    else
 1935: 	      list = NULL;
 1936: 	  }
 1937: 	else if (name)
 1938: 	  {
 1939: 	    new = opt_malloc(sizeof(struct resolvc));
 1940: 	    new->next = list;
 1941: 	    new->name = name;
 1942: 	    new->is_default = 0;
 1943: 	    new->mtime = 0;
 1944: 	    new->logged = 0;
 1945: 	    list = new;
 1946: 	  }
 1947: 	daemon->resolv_files = list;
 1948: 	break;
 1949:       }
 1950: 
 1951:     case LOPT_SERVERS_FILE:
 1952:       daemon->servers_file = opt_string_alloc(arg);
 1953:       break;
 1954:       
 1955:     case 'm':  /* --mx-host */
 1956:       {
 1957: 	int pref = 1;
 1958: 	struct mx_srv_record *new;
 1959: 	char *name, *target = NULL;
 1960: 
 1961: 	if ((comma = split(arg)))
 1962: 	  {
 1963: 	    char *prefstr;
 1964: 	    if ((prefstr = split(comma)) && !atoi_check16(prefstr, &pref))
 1965: 	      ret_err(_("bad MX preference"));
 1966: 	  }
 1967: 	
 1968: 	if (!(name = canonicalise_opt(arg)) || 
 1969: 	    (comma && !(target = canonicalise_opt(comma))))
 1970: 	  ret_err(_("bad MX name"));
 1971: 	
 1972: 	new = opt_malloc(sizeof(struct mx_srv_record));
 1973: 	new->next = daemon->mxnames;
 1974: 	daemon->mxnames = new;
 1975: 	new->issrv = 0;
 1976: 	new->name = name;
 1977: 	new->target = target; /* may be NULL */
 1978: 	new->weight = pref;
 1979: 	break;
 1980:       }
 1981:       
 1982:     case 't': /*  --mx-target */
 1983:       if (!(daemon->mxtarget = canonicalise_opt(arg)))
 1984: 	ret_err(_("bad MX target"));
 1985:       break;
 1986: 
 1987:     case LOPT_DUMPFILE:  /* --dumpfile */
 1988:       daemon->dump_file = opt_string_alloc(arg);
 1989:       break;
 1990: 
 1991:     case LOPT_DUMPMASK:  /* --dumpmask */
 1992:       daemon->dump_mask = strtol(arg, NULL, 0);
 1993:       break;
 1994:       
 1995: #ifdef HAVE_DHCP      
 1996:     case 'l':  /* --dhcp-leasefile */
 1997:       daemon->lease_file = opt_string_alloc(arg);
 1998:       break;
 1999:       
 2000:       /* Sorry about the gross pre-processor abuse */
 2001:     case '6':             /* --dhcp-script */
 2002:     case LOPT_LUASCRIPT:  /* --dhcp-luascript */
 2003: #  if !defined(HAVE_SCRIPT)
 2004:       ret_err(_("recompile with HAVE_SCRIPT defined to enable lease-change scripts"));
 2005: #  else
 2006:       if (option == LOPT_LUASCRIPT)
 2007: #    if !defined(HAVE_LUASCRIPT)
 2008: 	ret_err(_("recompile with HAVE_LUASCRIPT defined to enable Lua scripts"));
 2009: #    else
 2010:         daemon->luascript = opt_string_alloc(arg);
 2011: #    endif
 2012:       else
 2013:         daemon->lease_change_command = opt_string_alloc(arg);
 2014: #  endif
 2015:       break;
 2016: #endif /* HAVE_DHCP */
 2017: 
 2018:     case LOPT_DHCP_HOST:     /* --dhcp-hostsfile */
 2019:     case LOPT_DHCP_OPTS:     /* --dhcp-optsfile */
 2020:     case LOPT_DHCP_INOTIFY:  /* --dhcp-hostsdir */
 2021:     case LOPT_DHOPT_INOTIFY: /* --dhcp-optsdir */
 2022:     case LOPT_HOST_INOTIFY:  /* --hostsdir */
 2023:     case 'H':                /* --addn-hosts */
 2024:       {
 2025: 	struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
 2026: 	static unsigned int hosts_index = SRC_AH;
 2027: 	new->fname = opt_string_alloc(arg);
 2028: 	new->index = hosts_index++;
 2029: 	new->flags = 0;
 2030: 	if (option == 'H')
 2031: 	  {
 2032: 	    new->next = daemon->addn_hosts;
 2033: 	    daemon->addn_hosts = new;
 2034: 	  }
 2035: 	else if (option == LOPT_DHCP_HOST)
 2036: 	  {
 2037: 	    new->next = daemon->dhcp_hosts_file;
 2038: 	    daemon->dhcp_hosts_file = new;
 2039: 	  }
 2040: 	else if (option == LOPT_DHCP_OPTS)
 2041: 	  {
 2042: 	    new->next = daemon->dhcp_opts_file;
 2043: 	    daemon->dhcp_opts_file = new;
 2044: 	  } 	  
 2045: 	else 
 2046: 	  {
 2047: 	    new->next = daemon->dynamic_dirs;
 2048: 	    daemon->dynamic_dirs = new; 
 2049: 	    if (option == LOPT_DHCP_INOTIFY)
 2050: 	      new->flags |= AH_DHCP_HST;
 2051: 	    else if (option == LOPT_DHOPT_INOTIFY)
 2052: 	      new->flags |= AH_DHCP_OPT;
 2053: 	    else if (option == LOPT_HOST_INOTIFY)
 2054: 	      new->flags |= AH_HOSTS;
 2055: 	  }
 2056: 	
 2057: 	break;
 2058:       }
 2059:       
 2060:     case LOPT_AUTHSERV: /* --auth-server */
 2061:       comma = split(arg);
 2062:       
 2063:       daemon->authserver = opt_string_alloc(arg);
 2064:       
 2065:       while ((arg = comma))
 2066: 	{
 2067: 	  struct iname *new = opt_malloc(sizeof(struct iname));
 2068: 	  comma = split(arg);
 2069: 	  new->name = NULL;
 2070: 	  unhide_metas(arg);
 2071: 	  if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0)
 2072: 	    new->addr.sa.sa_family = AF_INET;
 2073: 	  else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
 2074: 	    new->addr.sa.sa_family = AF_INET6;
 2075: 	  else
 2076: 	    {
 2077: 	      char *fam = split_chr(arg, '/');
 2078: 	      new->name = opt_string_alloc(arg);
 2079: 	      new->addr.sa.sa_family = 0;
 2080: 	      if (fam)
 2081: 		{
 2082: 		  if (strcmp(fam, "4") == 0)
 2083: 		    new->addr.sa.sa_family = AF_INET;
 2084: 		  else if (strcmp(fam, "6") == 0)
 2085: 		    new->addr.sa.sa_family = AF_INET6;
 2086: 		  else
 2087: 		  {
 2088: 		    free(new->name);
 2089: 		    ret_err_free(gen_err, new);
 2090: 		  }
 2091: 		} 
 2092: 	    }
 2093: 	  new->next = daemon->authinterface;
 2094: 	  daemon->authinterface = new;
 2095: 	};
 2096:             
 2097:       break;
 2098: 
 2099:     case LOPT_AUTHSFS: /* --auth-sec-servers */
 2100:       {
 2101: 	struct name_list *new;
 2102: 
 2103: 	do {
 2104: 	  comma = split(arg);
 2105: 	  new = opt_malloc(sizeof(struct name_list));
 2106: 	  new->name = opt_string_alloc(arg);
 2107: 	  new->next = daemon->secondary_forward_server;
 2108: 	  daemon->secondary_forward_server = new;
 2109: 	  arg = comma;
 2110: 	} while (arg);
 2111: 	break;
 2112:       }
 2113: 	
 2114:     case LOPT_AUTHZONE: /* --auth-zone */
 2115:       {
 2116: 	struct auth_zone *new;
 2117: 	
 2118: 	comma = split(arg);
 2119: 		
 2120: 	new = opt_malloc(sizeof(struct auth_zone));
 2121: 	new->domain = opt_string_alloc(arg);
 2122: 	new->subnet = NULL;
 2123: 	new->exclude = NULL;
 2124: 	new->interface_names = NULL;
 2125: 	new->next = daemon->auth_zones;
 2126: 	daemon->auth_zones = new;
 2127: 
 2128: 	while ((arg = comma))
 2129: 	  {
 2130: 	    int prefixlen = 0;
 2131: 	    int is_exclude = 0;
 2132: 	    char *prefix;
 2133: 	    struct addrlist *subnet =  NULL;
 2134: 	    union all_addr addr;
 2135: 
 2136: 	    comma = split(arg);
 2137: 	    prefix = split_chr(arg, '/');
 2138: 	    
 2139: 	    if (prefix && !atoi_check(prefix, &prefixlen))
 2140: 	      ret_err(gen_err);
 2141: 	    
 2142: 	    if (strstr(arg, "exclude:") == arg)
 2143: 	      {
 2144: 		    is_exclude = 1;
 2145: 		    arg = arg+8;
 2146: 	      }
 2147: 
 2148: 	    if (inet_pton(AF_INET, arg, &addr.addr4))
 2149: 	      {
 2150: 		subnet = opt_malloc(sizeof(struct addrlist));
 2151: 		subnet->prefixlen = (prefixlen == 0) ? 24 : prefixlen;
 2152: 		subnet->flags = ADDRLIST_LITERAL;
 2153: 	      }
 2154: 	    else if (inet_pton(AF_INET6, arg, &addr.addr6))
 2155: 	      {
 2156: 		subnet = opt_malloc(sizeof(struct addrlist));
 2157: 		subnet->prefixlen = (prefixlen == 0) ? 64 : prefixlen;
 2158: 		subnet->flags = ADDRLIST_LITERAL | ADDRLIST_IPV6;
 2159: 	      }
 2160: 	    else 
 2161: 	      {
 2162: 		struct auth_name_list *name =  opt_malloc(sizeof(struct auth_name_list));
 2163: 		name->name = opt_string_alloc(arg);
 2164: 		name->flags = AUTH4 | AUTH6;
 2165: 		name->next = new->interface_names;
 2166: 		new->interface_names = name;
 2167: 		if (prefix)
 2168: 		  {
 2169: 		    if (prefixlen == 4)
 2170: 		      name->flags &= ~AUTH6;
 2171: 		    else if (prefixlen == 6)
 2172: 		      name->flags &= ~AUTH4;
 2173: 		    else
 2174: 		      ret_err(gen_err);
 2175: 		  }
 2176: 	      }
 2177: 	    
 2178: 	    if (subnet)
 2179: 	      {
 2180: 		subnet->addr = addr;
 2181: 
 2182: 		if (is_exclude)
 2183: 		  {
 2184: 		    subnet->next = new->exclude;
 2185: 		    new->exclude = subnet;
 2186: 		  }
 2187: 		else
 2188: 		  {
 2189: 		    subnet->next = new->subnet;
 2190: 		    new->subnet = subnet;
 2191: 		  }
 2192: 	      }
 2193: 	  }
 2194: 	break;
 2195:       }
 2196:       
 2197:     case  LOPT_AUTHSOA: /* --auth-soa */
 2198:       comma = split(arg);
 2199:       daemon->soa_sn = (u32)atoi(arg);
 2200:       if (comma)
 2201: 	{
 2202: 	  char *cp;
 2203: 	  arg = comma;
 2204: 	  comma = split(arg);
 2205: 	  daemon->hostmaster = opt_string_alloc(arg);
 2206: 	  for (cp = daemon->hostmaster; *cp; cp++)
 2207: 	    if (*cp == '@')
 2208: 	      *cp = '.';
 2209: 
 2210: 	  if (comma)
 2211: 	    {
 2212: 	      arg = comma;
 2213: 	      comma = split(arg); 
 2214: 	      daemon->soa_refresh = (u32)atoi(arg);
 2215: 	      if (comma)
 2216: 		{
 2217: 		  arg = comma;
 2218: 		  comma = split(arg); 
 2219: 		  daemon->soa_retry = (u32)atoi(arg);
 2220: 		  if (comma)
 2221: 		    daemon->soa_expiry = (u32)atoi(comma);
 2222: 		}
 2223: 	    }
 2224: 	}
 2225: 
 2226:       break;
 2227: 
 2228:     case 's':         /* --domain */
 2229:     case LOPT_SYNTH:  /* --synth-domain */
 2230:       if (strcmp (arg, "#") == 0)
 2231: 	set_option_bool(OPT_RESOLV_DOMAIN);
 2232:       else
 2233: 	{
 2234: 	  char *d;
 2235: 	  comma = split(arg);
 2236: 	  if (!(d = canonicalise_opt(arg)))
 2237: 	    ret_err(gen_err);
 2238: 	  else
 2239: 	    {
 2240: 	      if (comma)
 2241: 		{
 2242: 		  struct cond_domain *new = opt_malloc(sizeof(struct cond_domain));
 2243: 		  char *netpart;
 2244: 		  
 2245: 		  new->prefix = NULL;
 2246: 		  new->indexed = 0;
 2247: 		  
 2248: 		  unhide_metas(comma);
 2249: 		  if ((netpart = split_chr(comma, '/')))
 2250: 		    {
 2251: 		      int msize;
 2252: 
 2253: 		      arg = split(netpart);
 2254: 		      if (!atoi_check(netpart, &msize))
 2255: 			ret_err_free(gen_err, new);
 2256: 		      else if (inet_pton(AF_INET, comma, &new->start))
 2257: 			{
 2258: 			  int mask = (1 << (32 - msize)) - 1;
 2259: 			  new->is6 = 0; 			  
 2260: 			  new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask);
 2261: 			  new->end.s_addr = new->start.s_addr | htonl(mask);
 2262: 			  if (arg)
 2263: 			    {
 2264: 			      if (option != 's')
 2265: 				{
 2266: 				  if (!(new->prefix = canonicalise_opt(arg)) ||
 2267: 				      strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
 2268: 				    ret_err_free(_("bad prefix"), new);
 2269: 				}
 2270: 			      else if (strcmp(arg, "local") != 0 ||
 2271: 				       (msize != 8 && msize != 16 && msize != 24))
 2272: 				ret_err_free(gen_err, new);
 2273: 			      else
 2274: 				{
 2275: 				   /* generate the equivalent of
 2276: 				      local=/xxx.yyy.zzz.in-addr.arpa/ */
 2277: 				  struct server *serv = add_rev4(new->start, msize);
 2278: 				  if (!serv)
 2279: 				    ret_err_free(_("bad prefix"), new);
 2280: 
 2281: 				  serv->flags |= SERV_NO_ADDR;
 2282: 
 2283: 				  /* local=/<domain>/ */
 2284: 				  serv = opt_malloc(sizeof(struct server));
 2285: 				  memset(serv, 0, sizeof(struct server));
 2286: 				  serv->domain = d;
 2287: 				  serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
 2288: 				  serv->next = daemon->servers;
 2289: 				  daemon->servers = serv;
 2290: 				}
 2291: 			    }
 2292: 			}
 2293: 		      else if (inet_pton(AF_INET6, comma, &new->start6))
 2294: 			{
 2295: 			  u64 mask = (1LLU << (128 - msize)) - 1LLU;
 2296: 			  u64 addrpart = addr6part(&new->start6);
 2297: 			  new->is6 = 1;
 2298: 			  
 2299: 			  /* prefix==64 overflows the mask calculation above */
 2300: 			  if (msize == 64)
 2301: 			    mask = (u64)-1LL;
 2302: 			  
 2303: 			  new->end6 = new->start6;
 2304: 			  setaddr6part(&new->start6, addrpart & ~mask);
 2305: 			  setaddr6part(&new->end6, addrpart | mask);
 2306: 			  
 2307: 			  if (msize < 64)
 2308: 			    ret_err_free(gen_err, new);
 2309: 			  else if (arg)
 2310: 			    {
 2311: 			      if (option != 's')
 2312: 				{
 2313: 				  if (!(new->prefix = canonicalise_opt(arg)) ||
 2314: 				      strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
 2315: 				    ret_err_free(_("bad prefix"), new);
 2316: 				}	
 2317: 			      else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
 2318: 				ret_err_free(gen_err, new);
 2319: 			      else 
 2320: 				{
 2321: 				  /* generate the equivalent of
 2322: 				     local=/xxx.yyy.zzz.ip6.arpa/ */
 2323: 				  struct server *serv = add_rev6(&new->start6, msize);
 2324: 				  serv->flags |= SERV_NO_ADDR;
 2325: 				  
 2326: 				  /* local=/<domain>/ */
 2327: 				  serv = opt_malloc(sizeof(struct server));
 2328: 				  memset(serv, 0, sizeof(struct server));
 2329: 				  serv->domain = d;
 2330: 				  serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
 2331: 				  serv->next = daemon->servers;
 2332: 				  daemon->servers = serv;
 2333: 				}
 2334: 			    }
 2335: 			}
 2336: 		      else
 2337: 			ret_err_free(gen_err, new);
 2338: 		    }
 2339: 		  else
 2340: 		    {
 2341: 		      char *prefstr;
 2342: 		      arg = split(comma);
 2343: 		      prefstr = split(arg);
 2344: 
 2345: 		      if (inet_pton(AF_INET, comma, &new->start))
 2346: 			{
 2347: 			  new->is6 = 0;
 2348: 			  if (!arg)
 2349: 			    new->end.s_addr = new->start.s_addr;
 2350: 			  else if (!inet_pton(AF_INET, arg, &new->end))
 2351: 			    ret_err_free(gen_err, new);
 2352: 			}
 2353: 		      else if (inet_pton(AF_INET6, comma, &new->start6))
 2354: 			{
 2355: 			  new->is6 = 1;
 2356: 			  if (!arg)
 2357: 			    memcpy(&new->end6, &new->start6, IN6ADDRSZ);
 2358: 			  else if (!inet_pton(AF_INET6, arg, &new->end6))
 2359: 			    ret_err_free(gen_err, new);
 2360: 			}
 2361: 		      else 
 2362: 			ret_err_free(gen_err, new);
 2363: 
 2364: 		      if (option != 's' && prefstr)
 2365: 			{
 2366: 			  if (!(new->prefix = canonicalise_opt(prefstr)) ||
 2367: 			      strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
 2368: 			    ret_err_free(_("bad prefix"), new);
 2369: 			}
 2370: 		    }
 2371: 
 2372: 		  new->domain = d;
 2373: 		  if (option  == 's')
 2374: 		    {
 2375: 		      new->next = daemon->cond_domain;
 2376: 		      daemon->cond_domain = new;
 2377: 		    }
 2378: 		  else
 2379: 		    {
 2380: 		      char *star;
 2381: 		      new->next = daemon->synth_domains;
 2382: 		      daemon->synth_domains = new;
 2383: 		      if (new->prefix &&
 2384: 			  (star = strrchr(new->prefix, '*'))
 2385: 			  && *(star+1) == 0)
 2386: 			{
 2387: 			  *star = 0;
 2388: 			  new->indexed = 1;
 2389: 			}
 2390: 		    }
 2391: 		}
 2392: 	      else if (option == 's')
 2393: 		daemon->domain_suffix = d;
 2394: 	      else 
 2395: 		ret_err(gen_err);
 2396: 	    }
 2397: 	}
 2398:       break;
 2399:       
 2400:     case LOPT_CPE_ID: /* --add-dns-client */
 2401:       if (arg)
 2402: 	daemon->dns_client_id = opt_string_alloc(arg);
 2403:       break;
 2404: 
 2405:     case LOPT_ADD_MAC: /* --add-mac */
 2406:       if (!arg)
 2407: 	set_option_bool(OPT_ADD_MAC);
 2408:       else
 2409: 	{
 2410: 	  unhide_metas(arg);
 2411: 	  if (strcmp(arg, "base64") == 0)
 2412: 	    set_option_bool(OPT_MAC_B64);
 2413: 	  else if (strcmp(arg, "text") == 0)
 2414: 	    set_option_bool(OPT_MAC_HEX);
 2415: 	  else
 2416: 	    ret_err(gen_err);
 2417: 	}
 2418:       break;
 2419: 
 2420:     case 'u':  /* --user */
 2421:       daemon->username = opt_string_alloc(arg);
 2422:       break;
 2423:       
 2424:     case 'g':  /* --group */
 2425:       daemon->groupname = opt_string_alloc(arg);
 2426:       daemon->group_set = 1;
 2427:       break;
 2428: 
 2429: #ifdef HAVE_DHCP
 2430:     case LOPT_SCRIPTUSR: /* --scriptuser */
 2431:       daemon->scriptuser = opt_string_alloc(arg);
 2432:       break;
 2433: #endif
 2434:       
 2435:     case 'i':  /* --interface */
 2436:       do {
 2437: 	struct iname *new = opt_malloc(sizeof(struct iname));
 2438: 	comma = split(arg);
 2439: 	new->next = daemon->if_names;
 2440: 	daemon->if_names = new;
 2441: 	/* new->name may be NULL if someone does
 2442: 	   "interface=" to disable all interfaces except loop. */
 2443: 	new->name = opt_string_alloc(arg);
 2444: 	new->used = 0;
 2445: 	arg = comma;
 2446:       } while (arg);
 2447:       break;
 2448:       
 2449:     case LOPT_TFTP: /* --enable-tftp */
 2450:       set_option_bool(OPT_TFTP);
 2451:       if (!arg)
 2452: 	break;
 2453:       /* fall through */
 2454: 
 2455:     case 'I':  /* --except-interface */
 2456:     case '2':  /* --no-dhcp-interface */
 2457:       do {
 2458: 	struct iname *new = opt_malloc(sizeof(struct iname));
 2459: 	comma = split(arg);
 2460: 	new->name = opt_string_alloc(arg);
 2461: 	if (option == 'I')
 2462: 	  {
 2463: 	    new->next = daemon->if_except;
 2464: 	    daemon->if_except = new;
 2465: 	  }
 2466: 	else if (option == LOPT_TFTP)
 2467: 	   {
 2468: 	    new->next = daemon->tftp_interfaces;
 2469: 	    daemon->tftp_interfaces = new;
 2470: 	  }
 2471: 	else
 2472: 	  {
 2473: 	    new->next = daemon->dhcp_except;
 2474: 	    daemon->dhcp_except = new;
 2475: 	  }
 2476: 	arg = comma;
 2477:       } while (arg);
 2478:       break;
 2479:       
 2480:     case 'B':  /* --bogus-nxdomain */
 2481:     case LOPT_IGNORE_ADDR: /* --ignore-address */
 2482:      {
 2483: 	struct in_addr addr;
 2484: 	unhide_metas(arg);
 2485: 	if (arg && (inet_pton(AF_INET, arg, &addr) > 0))
 2486: 	  {
 2487: 	    struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
 2488: 	    if (option == 'B')
 2489: 	      {
 2490: 		baddr->next = daemon->bogus_addr;
 2491: 		daemon->bogus_addr = baddr;
 2492: 	      }
 2493: 	    else
 2494: 	      {
 2495: 		baddr->next = daemon->ignore_addr;
 2496: 		daemon->ignore_addr = baddr;
 2497: 	      }
 2498: 	    baddr->addr = addr;
 2499: 	  }
 2500: 	else
 2501: 	  ret_err(gen_err); /* error */
 2502: 	break;	
 2503:       }
 2504:       
 2505:     case 'a':  /* --listen-address */
 2506:     case LOPT_AUTHPEER: /* --auth-peer */
 2507:       do {
 2508: 	struct iname *new = opt_malloc(sizeof(struct iname));
 2509: 	comma = split(arg);
 2510: 	unhide_metas(arg);
 2511: 	if (arg && (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0))
 2512: 	  {
 2513: 	    new->addr.sa.sa_family = AF_INET;
 2514: 	    new->addr.in.sin_port = 0;
 2515: #ifdef HAVE_SOCKADDR_SA_LEN
 2516: 	    new->addr.in.sin_len = sizeof(new->addr.in);
 2517: #endif
 2518: 	  }
 2519: 	else if (arg && inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
 2520: 	  {
 2521: 	    new->addr.sa.sa_family = AF_INET6;
 2522: 	    new->addr.in6.sin6_flowinfo = 0;
 2523: 	    new->addr.in6.sin6_scope_id = 0;
 2524: 	    new->addr.in6.sin6_port = 0;
 2525: #ifdef HAVE_SOCKADDR_SA_LEN
 2526: 	    new->addr.in6.sin6_len = sizeof(new->addr.in6);
 2527: #endif
 2528: 	  }
 2529: 	else
 2530: 	  ret_err_free(gen_err, new);
 2531: 
 2532: 	new->used = 0;
 2533: 	if (option == 'a')
 2534: 	  {
 2535: 	    new->next = daemon->if_addrs;
 2536: 	    daemon->if_addrs = new;
 2537: 	  }
 2538: 	else
 2539: 	  {
 2540: 	    new->next = daemon->auth_peers;
 2541: 	    daemon->auth_peers = new;
 2542: 	  } 
 2543: 	arg = comma;
 2544:       } while (arg);
 2545:       break;
 2546:       
 2547:     case 'S':            /*  --server */
 2548:     case LOPT_LOCAL:     /*  --local */
 2549:     case 'A':            /*  --address */
 2550:     case LOPT_NO_REBIND: /*  --rebind-domain-ok */
 2551:       {
 2552: 	struct server *serv, *newlist = NULL;
 2553: 	
 2554: 	unhide_metas(arg);
 2555: 	
 2556: 	if (arg && (*arg == '/' || option == LOPT_NO_REBIND))
 2557: 	  {
 2558: 	    int rebind = !(*arg == '/');
 2559: 	    char *end = NULL;
 2560: 	    if (!rebind)
 2561: 	      arg++;
 2562: 	    while (rebind || (end = split_chr(arg, '/')))
 2563: 	      {
 2564: 		char *domain = NULL;
 2565: 		/* elide leading dots - they are implied in the search algorithm */
 2566: 		while (*arg == '.') arg++;
 2567: 		/* # matches everything and becomes a zero length domain string */
 2568: 		if (strcmp(arg, "#") == 0)
 2569: 		  domain = "";
 2570: 		else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
 2571: 		  ret_err(gen_err);
 2572: 		serv = opt_malloc(sizeof(struct server));
 2573: 		memset(serv, 0, sizeof(struct server));
 2574: 		serv->next = newlist;
 2575: 		newlist = serv;
 2576: 		serv->domain = domain;
 2577: 		serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
 2578: 		arg = end;
 2579: 		if (rebind)
 2580: 		  break;
 2581: 	      }
 2582: 	    if (!newlist)
 2583: 	      ret_err(gen_err);
 2584: 	  }
 2585: 	else
 2586: 	  {
 2587: 	    newlist = opt_malloc(sizeof(struct server));
 2588: 	    memset(newlist, 0, sizeof(struct server));
 2589: #ifdef HAVE_LOOP
 2590: 	    newlist->uid = rand32();
 2591: #endif
 2592: 	  }
 2593: 	
 2594: 	if (servers_only && option == 'S')
 2595: 	  newlist->flags |= SERV_FROM_FILE;
 2596: 	
 2597: 	if (option == 'A')
 2598: 	  {
 2599: 	    newlist->flags |= SERV_LITERAL_ADDRESS;
 2600: 	    if (!(newlist->flags & SERV_TYPE))
 2601: 	      {
 2602: 	        server_list_free(newlist);
 2603: 	        ret_err(gen_err);
 2604: 	      }
 2605: 	  }
 2606: 	else if (option == LOPT_NO_REBIND)
 2607: 	  newlist->flags |= SERV_NO_REBIND;
 2608: 	
 2609: 	if (!arg || !*arg)
 2610: 	  {
 2611: 	    if (!(newlist->flags & SERV_NO_REBIND))
 2612: 	      newlist->flags |= SERV_NO_ADDR; /* no server */
 2613: 	  }
 2614: 
 2615: 	else if (strcmp(arg, "#") == 0)
 2616: 	  newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
 2617: 	else
 2618: 	  {
 2619: 	    char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
 2620: 	    if (err)
 2621: 	      {
 2622: 	        server_list_free(newlist);
 2623: 	        ret_err(err);
 2624: 	      }
 2625: 	  }
 2626: 	
 2627: 	serv = newlist;
 2628: 	while (serv->next)
 2629: 	  {
 2630: 	    serv->next->flags |= serv->flags & ~(SERV_HAS_DOMAIN | SERV_FOR_NODOTS);
 2631: 	    serv->next->addr = serv->addr;
 2632: 	    serv->next->source_addr = serv->source_addr;
 2633: 	    strcpy(serv->next->interface, serv->interface);
 2634: 	    serv = serv->next;
 2635: 	  }
 2636: 	serv->next = daemon->servers;
 2637: 	daemon->servers = newlist;
 2638: 	break;
 2639:       }
 2640: 
 2641:     case LOPT_REV_SERV: /* --rev-server */
 2642:       {
 2643: 	char *string;
 2644: 	int size;
 2645: 	struct server *serv;
 2646: 	struct in_addr addr4;
 2647: 	struct in6_addr addr6;
 2648:  
 2649: 	unhide_metas(arg);
 2650: 	if (!arg)
 2651: 	  ret_err(gen_err);
 2652: 	
 2653: 	comma=split(arg);
 2654: 
 2655: 	if (!(string = split_chr(arg, '/')) || !atoi_check(string, &size))
 2656: 	  ret_err(gen_err);
 2657: 	
 2658: 	if (inet_pton(AF_INET, arg, &addr4))
 2659: 	  {
 2660: 	    serv = add_rev4(addr4, size);
 2661: 	    if (!serv)
 2662: 	      ret_err(_("bad prefix"));
 2663: 	  }
 2664: 	else if (inet_pton(AF_INET6, arg, &addr6))
 2665: 	  serv = add_rev6(&addr6, size);
 2666: 	else
 2667: 	  ret_err(gen_err);
 2668:  
 2669: 	string = parse_server(comma, &serv->addr, &serv->source_addr, serv->interface, &serv->flags);
 2670: 	
 2671: 	if (string)
 2672: 	  ret_err(string);
 2673: 	
 2674: 	if (servers_only)
 2675: 	  serv->flags |= SERV_FROM_FILE;
 2676: 	
 2677: 	break;
 2678:       }
 2679: 
 2680:     case LOPT_IPSET: /* --ipset */
 2681: #ifndef HAVE_IPSET
 2682:       ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
 2683:       break;
 2684: #else
 2685:       {
 2686: 	 struct ipsets ipsets_head;
 2687: 	 struct ipsets *ipsets = &ipsets_head;
 2688: 	 int size;
 2689: 	 char *end;
 2690: 	 char **sets, **sets_pos;
 2691: 	 memset(ipsets, 0, sizeof(struct ipsets));
 2692: 	 unhide_metas(arg);
 2693: 	 if (arg && *arg == '/') 
 2694: 	   {
 2695: 	     arg++;
 2696: 	     while ((end = split_chr(arg, '/'))) 
 2697: 	       {
 2698: 		 char *domain = NULL;
 2699: 		 /* elide leading dots - they are implied in the search algorithm */
 2700: 		 while (*arg == '.')
 2701: 		   arg++;
 2702: 		 /* # matches everything and becomes a zero length domain string */
 2703: 		 if (strcmp(arg, "#") == 0 || !*arg)
 2704: 		   domain = "";
 2705: 		 else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg)))
 2706: 		   ret_err(gen_err);
 2707: 		 ipsets->next = opt_malloc(sizeof(struct ipsets));
 2708: 		 ipsets = ipsets->next;
 2709: 		 memset(ipsets, 0, sizeof(struct ipsets));
 2710: 		 ipsets->domain = domain;
 2711: 		 arg = end;
 2712: 	       }
 2713: 	   } 
 2714: 	 else 
 2715: 	   {
 2716: 	     ipsets->next = opt_malloc(sizeof(struct ipsets));
 2717: 	     ipsets = ipsets->next;
 2718: 	     memset(ipsets, 0, sizeof(struct ipsets));
 2719: 	     ipsets->domain = "";
 2720: 	   }
 2721: 	 
 2722: 	 if (!arg || !*arg)
 2723: 	   ret_err(gen_err);
 2724: 	 
 2725: 	 for (size = 2, end = arg; *end; ++end) 
 2726: 	   if (*end == ',')
 2727: 	       ++size;
 2728:      
 2729: 	 sets = sets_pos = opt_malloc(sizeof(char *) * size);
 2730: 	 
 2731: 	 do {
 2732: 	   end = split(arg);
 2733: 	   *sets_pos++ = opt_string_alloc(arg);
 2734: 	   arg = end;
 2735: 	 } while (end);
 2736: 	 *sets_pos = 0;
 2737: 	 for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next)
 2738: 	   ipsets->next->sets = sets;
 2739: 	 ipsets->next = daemon->ipsets;
 2740: 	 daemon->ipsets = ipsets_head.next;
 2741: 	 
 2742: 	 break;
 2743:       }
 2744: #endif
 2745:       
 2746:     case 'c':  /* --cache-size */
 2747:       {
 2748: 	int size;
 2749: 	
 2750: 	if (!atoi_check(arg, &size))
 2751: 	  ret_err(gen_err);
 2752: 	else
 2753: 	  {
 2754: 	    /* zero is OK, and means no caching. */
 2755: 	    
 2756: 	    if (size < 0)
 2757: 	      size = 0;
 2758: 
 2759: 	    /* Note that for very large cache sizes, the malloc()
 2760: 	       will overflow. For the size of the cache record
 2761: 	       at the time this was noted, the value of "very large"
 2762:                was 46684428. Limit to an order of magnitude less than
 2763: 	       that to be safe from changes to the cache record. */
 2764: 	    if (size > 5000000)
 2765: 	      size = 5000000;
 2766: 	    
 2767: 	    daemon->cachesize = size;
 2768: 	  }
 2769: 	break;
 2770:       }
 2771:       
 2772:     case 'p':  /* --port */
 2773:       if (!atoi_check16(arg, &daemon->port))
 2774: 	ret_err(gen_err);
 2775:       break;
 2776:     
 2777:     case LOPT_MINPORT:  /* --min-port */
 2778:       if (!atoi_check16(arg, &daemon->min_port))
 2779: 	ret_err(gen_err);
 2780:       break;
 2781: 
 2782:     case LOPT_MAXPORT:  /* --max-port */
 2783:       if (!atoi_check16(arg, &daemon->max_port))
 2784: 	ret_err(gen_err);
 2785:       break;
 2786: 
 2787:     case '0':  /* --dns-forward-max */
 2788:       if (!atoi_check(arg, &daemon->ftabsize))
 2789: 	ret_err(gen_err);
 2790:       break;  
 2791:     
 2792:     case 'q': /* --log-queries */
 2793:       set_option_bool(OPT_LOG);
 2794:       if (arg && strcmp(arg, "extra") == 0)
 2795: 	set_option_bool(OPT_EXTRALOG);
 2796:       break;
 2797: 
 2798:     case LOPT_MAX_LOGS:  /* --log-async */
 2799:       daemon->max_logs = LOG_MAX; /* default */
 2800:       if (arg && !atoi_check(arg, &daemon->max_logs))
 2801: 	ret_err(gen_err);
 2802:       else if (daemon->max_logs > 100)
 2803: 	daemon->max_logs = 100;
 2804:       break;  
 2805: 
 2806:     case 'P': /* --edns-packet-max */
 2807:       {
 2808: 	int i;
 2809: 	if (!atoi_check(arg, &i))
 2810: 	  ret_err(gen_err);
 2811: 	daemon->edns_pktsz = (unsigned short)i;	
 2812: 	break;
 2813:       }
 2814:       
 2815:     case 'Q':  /* --query-port */
 2816:       if (!atoi_check16(arg, &daemon->query_port))
 2817: 	ret_err(gen_err);
 2818:       /* if explicitly set to zero, use single OS ephemeral port
 2819: 	 and disable random ports */
 2820:       if (daemon->query_port == 0)
 2821: 	daemon->osport = 1;
 2822:       break;
 2823:       
 2824:     case 'T':         /* --local-ttl */
 2825:     case LOPT_NEGTTL: /* --neg-ttl */
 2826:     case LOPT_MAXTTL: /* --max-ttl */
 2827:     case LOPT_MINCTTL: /* --min-cache-ttl */
 2828:     case LOPT_MAXCTTL: /* --max-cache-ttl */
 2829:     case LOPT_AUTHTTL: /* --auth-ttl */
 2830:     case LOPT_DHCPTTL: /* --dhcp-ttl */
 2831:       {
 2832: 	int ttl;
 2833: 	if (!atoi_check(arg, &ttl))
 2834: 	  ret_err(gen_err);
 2835: 	else if (option == LOPT_NEGTTL)
 2836: 	  daemon->neg_ttl = (unsigned long)ttl;
 2837: 	else if (option == LOPT_MAXTTL)
 2838: 	  daemon->max_ttl = (unsigned long)ttl;
 2839: 	else if (option == LOPT_MINCTTL)
 2840: 	  {
 2841: 	    if (ttl > TTL_FLOOR_LIMIT)
 2842: 	      ttl = TTL_FLOOR_LIMIT;
 2843: 	    daemon->min_cache_ttl = (unsigned long)ttl;
 2844: 	  }
 2845: 	else if (option == LOPT_MAXCTTL)
 2846: 	  daemon->max_cache_ttl = (unsigned long)ttl;
 2847: 	else if (option == LOPT_AUTHTTL)
 2848: 	  daemon->auth_ttl = (unsigned long)ttl;
 2849: 	else if (option == LOPT_DHCPTTL)
 2850: 	  {
 2851: 	    daemon->dhcp_ttl = (unsigned long)ttl;
 2852: 	    daemon->use_dhcp_ttl = 1;
 2853: 	  }
 2854: 	else
 2855: 	  daemon->local_ttl = (unsigned long)ttl;
 2856: 	break;
 2857:       }
 2858:       
 2859: #ifdef HAVE_DHCP
 2860:     case 'X': /* --dhcp-lease-max */
 2861:       if (!atoi_check(arg, &daemon->dhcp_max))
 2862: 	ret_err(gen_err);
 2863:       break;
 2864: #endif
 2865:       
 2866: #ifdef HAVE_TFTP
 2867:     case LOPT_TFTP_MAX:  /*  --tftp-max */
 2868:       if (!atoi_check(arg, &daemon->tftp_max))
 2869: 	ret_err(gen_err);
 2870:       break;  
 2871: 
 2872:     case LOPT_TFTP_MTU:  /*  --tftp-mtu */
 2873:       if (!atoi_check(arg, &daemon->tftp_mtu))
 2874: 	ret_err(gen_err);
 2875:       break;
 2876: 
 2877:     case LOPT_PREFIX: /* --tftp-prefix */
 2878:       comma = split(arg);
 2879:       if (comma)
 2880: 	{
 2881: 	  struct tftp_prefix *new = opt_malloc(sizeof(struct tftp_prefix));
 2882: 	  new->interface = opt_string_alloc(comma);
 2883: 	  new->prefix = opt_string_alloc(arg);
 2884: 	  new->next = daemon->if_prefix;
 2885: 	  daemon->if_prefix = new;
 2886: 	}
 2887:       else
 2888: 	daemon->tftp_prefix = opt_string_alloc(arg);
 2889:       break;
 2890: 
 2891:     case LOPT_TFTPPORTS: /* --tftp-port-range */
 2892:       if (!(comma = split(arg)) || 
 2893: 	  !atoi_check16(arg, &daemon->start_tftp_port) ||
 2894: 	  !atoi_check16(comma, &daemon->end_tftp_port))
 2895: 	ret_err(_("bad port range"));
 2896:       
 2897:       if (daemon->start_tftp_port > daemon->end_tftp_port)
 2898: 	{
 2899: 	  int tmp = daemon->start_tftp_port;
 2900: 	  daemon->start_tftp_port = daemon->end_tftp_port;
 2901: 	  daemon->end_tftp_port = tmp;
 2902: 	} 
 2903:       
 2904:       break;
 2905: 
 2906:     case LOPT_APREF: /* --tftp-unique-root */
 2907:       if (!arg || strcasecmp(arg, "ip") == 0)
 2908:         set_option_bool(OPT_TFTP_APREF_IP);
 2909:       else if (strcasecmp(arg, "mac") == 0)
 2910:         set_option_bool(OPT_TFTP_APREF_MAC);
 2911:       else
 2912:         ret_err(gen_err);
 2913:       break;
 2914: #endif
 2915: 	      
 2916:     case LOPT_BRIDGE:   /* --bridge-interface */
 2917:       {
 2918: 	struct dhcp_bridge *new;
 2919: 
 2920: 	if (!(comma = split(arg)) || strlen(arg) > IF_NAMESIZE - 1 )
 2921: 	  ret_err(_("bad bridge-interface"));
 2922: 
 2923: 	for (new = daemon->bridges; new; new = new->next)
 2924: 	  if (strcmp(new->iface, arg) == 0)
 2925: 	    break;
 2926: 
 2927: 	if (!new)
 2928: 	  {
 2929: 	     new = opt_malloc(sizeof(struct dhcp_bridge));
 2930: 	     strcpy(new->iface, arg);
 2931: 	     new->alias = NULL;
 2932: 	     new->next = daemon->bridges;
 2933: 	     daemon->bridges = new;
 2934: 	  }
 2935: 	
 2936: 	do {
 2937: 	  arg = comma;
 2938: 	  comma = split(arg);
 2939: 	  if (strlen(arg) != 0 && strlen(arg) <= IF_NAMESIZE - 1)
 2940: 	    {
 2941: 	      struct dhcp_bridge *b = opt_malloc(sizeof(struct dhcp_bridge)); 
 2942: 	      b->next = new->alias;
 2943: 	      new->alias = b;
 2944: 	      strcpy(b->iface, arg);
 2945: 	    }
 2946: 	} while (comma);
 2947: 	
 2948: 	break;
 2949:       }
 2950: 
 2951: #ifdef HAVE_DHCP
 2952:     case LOPT_SHARED_NET: /* --shared-network */
 2953:       {
 2954: 	struct shared_network *new = opt_malloc(sizeof(struct shared_network));
 2955: 
 2956: #ifdef HAVE_DHCP6
 2957: 	new->shared_addr.s_addr = 0;
 2958: #endif
 2959: 	new->if_index = 0;
 2960: 	
 2961: 	if (!(comma = split(arg)))
 2962: 	  {
 2963: 	  snerr:
 2964: 	    free(new);
 2965: 	    ret_err(_("bad shared-network"));
 2966: 	  }
 2967: 	
 2968: 	if (inet_pton(AF_INET, comma, &new->shared_addr))
 2969: 	  {
 2970: 	    if (!inet_pton(AF_INET, arg, &new->match_addr) &&
 2971: 		!(new->if_index = if_nametoindex(arg)))
 2972: 	      goto snerr;
 2973: 	  }
 2974: #ifdef HAVE_DHCP6
 2975: 	else if (inet_pton(AF_INET6, comma, &new->shared_addr6))
 2976: 	  {
 2977: 	    if (!inet_pton(AF_INET6, arg, &new->match_addr6) &&
 2978: 		!(new->if_index = if_nametoindex(arg)))
 2979: 	      goto snerr;
 2980: 	  }
 2981: #endif
 2982: 	else
 2983: 	  goto snerr;
 2984: 
 2985: 	new->next = daemon->shared_networks;
 2986: 	daemon->shared_networks = new;
 2987: 	break;
 2988:       }
 2989: 	  
 2990:     case 'F':  /* --dhcp-range */
 2991:       {
 2992: 	int k, leasepos = 2;
 2993: 	char *cp, *a[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
 2994: 	struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
 2995: 	
 2996: 	memset (new, 0, sizeof(*new));
 2997: 	
 2998: 	while(1)
 2999: 	  {
 3000: 	    for (cp = arg; *cp; cp++)
 3001: 	      if (!(*cp == ' ' || *cp == '.' || *cp == ':' || 
 3002: 		    (*cp >= 'a' && *cp <= 'f') || (*cp >= 'A' && *cp <= 'F') ||
 3003: 		    (*cp >='0' && *cp <= '9')))
 3004: 		break;
 3005: 	    
 3006: 	    if (*cp != ',' && (comma = split(arg)))
 3007: 	      {
 3008: 		if (is_tag_prefix(arg))
 3009: 		  {
 3010: 		    /* ignore empty tag */
 3011: 		    if (arg[4])
 3012: 		      new->filter = dhcp_netid_create(arg+4, new->filter);
 3013: 		  }
 3014: 		else
 3015: 		  {
 3016: 		    if (new->netid.net)
 3017: 		      {
 3018: 			dhcp_context_free(new);
 3019: 			ret_err(_("only one tag allowed"));
 3020: 		      }
 3021: 		    else
 3022: 		      new->netid.net = opt_string_alloc(set_prefix(arg));
 3023: 		  }
 3024: 		arg = comma;
 3025: 	      }
 3026: 	    else
 3027: 	      {
 3028: 		a[0] = arg;
 3029: 		break;
 3030: 	      }
 3031: 	  }
 3032: 	
 3033: 	for (k = 1; k < 8; k++)
 3034: 	  if (!(a[k] = split(a[k-1])))
 3035: 	    break;
 3036: 	
 3037: 	if (k < 2)
 3038: 	  {
 3039: 	    dhcp_context_free(new);
 3040: 	    ret_err(_("bad dhcp-range"));
 3041: 	  }
 3042: 	
 3043: 	if (inet_pton(AF_INET, a[0], &new->start))
 3044: 	  {
 3045: 	    new->next = daemon->dhcp;
 3046: 	    new->lease_time = DEFLEASE;
 3047: 	    daemon->dhcp = new;
 3048: 	    new->end = new->start;
 3049: 	    if (strcmp(a[1], "static") == 0)
 3050: 	      new->flags |= CONTEXT_STATIC;
 3051: 	    else if (strcmp(a[1], "proxy") == 0)
 3052: 	      new->flags |= CONTEXT_PROXY;
 3053: 	    else if (!inet_pton(AF_INET, a[1], &new->end))
 3054: 	      {
 3055: 		dhcp_context_free(new);
 3056: 		ret_err(_("bad dhcp-range"));
 3057: 	      }
 3058: 	    
 3059: 	    if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
 3060: 	      {
 3061: 		struct in_addr tmp = new->start;
 3062: 		new->start = new->end;
 3063: 		new->end = tmp;
 3064: 	      }
 3065: 	    
 3066: 	    if (k >= 3 && strchr(a[2], '.') &&  
 3067: 		(inet_pton(AF_INET, a[2], &new->netmask) > 0))
 3068: 	      {
 3069: 		new->flags |= CONTEXT_NETMASK;
 3070: 		leasepos = 3;
 3071: 		if (!is_same_net(new->start, new->end, new->netmask))
 3072: 		  {
 3073: 		    dhcp_context_free(new);
 3074: 		    ret_err(_("inconsistent DHCP range"));
 3075: 		  }
 3076: 		
 3077: 	    
 3078: 		if (k >= 4 && strchr(a[3], '.') &&  
 3079: 		    (inet_pton(AF_INET, a[3], &new->broadcast) > 0))
 3080: 		  {
 3081: 		    new->flags |= CONTEXT_BRDCAST;
 3082: 		    leasepos = 4;
 3083: 		  }
 3084: 	      }
 3085: 	  }
 3086: #ifdef HAVE_DHCP6
 3087: 	else if (inet_pton(AF_INET6, a[0], &new->start6))
 3088: 	  {
 3089: 	    const char *err = NULL;
 3090: 
 3091: 	    new->flags |= CONTEXT_V6; 
 3092: 	    new->prefix = 64; /* default */
 3093: 	    new->end6 = new->start6;
 3094: 	    new->lease_time = DEFLEASE6;
 3095: 	    new->next = daemon->dhcp6;
 3096: 	    daemon->dhcp6 = new;
 3097: 
 3098: 	    for (leasepos = 1; leasepos < k; leasepos++)
 3099: 	      {
 3100: 		if (strcmp(a[leasepos], "static") == 0)
 3101: 		  new->flags |= CONTEXT_STATIC | CONTEXT_DHCP;
 3102: 		else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 )
 3103: 		  new->flags |= CONTEXT_RA;
 3104: 		else if (strcmp(a[leasepos], "ra-names") == 0)
 3105: 		  new->flags |= CONTEXT_RA_NAME | CONTEXT_RA;
 3106: 		else if (strcmp(a[leasepos], "ra-advrouter") == 0)
 3107: 		  new->flags |= CONTEXT_RA_ROUTER | CONTEXT_RA;
 3108: 		else if (strcmp(a[leasepos], "ra-stateless") == 0)
 3109: 		  new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA;
 3110: 		else if (strcmp(a[leasepos], "off-link") == 0)
 3111: 		  new->flags |= CONTEXT_RA_OFF_LINK;
 3112: 		else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6))
 3113: 		  new->flags |= CONTEXT_DHCP; 
 3114: 		else if (strstr(a[leasepos], "constructor:") == a[leasepos])
 3115: 		  {
 3116: 		    new->template_interface = opt_string_alloc(a[leasepos] + 12);
 3117: 		    new->flags |= CONTEXT_TEMPLATE;
 3118: 		  }
 3119: 		else  
 3120: 		  break;
 3121: 	      }
 3122: 	   	    	     
 3123: 	    /* bare integer < 128 is prefix value */
 3124: 	    if (leasepos < k)
 3125: 	      {
 3126: 		int pref;
 3127: 		for (cp = a[leasepos]; *cp; cp++)
 3128: 		  if (!(*cp >= '0' && *cp <= '9'))
 3129: 		    break;
 3130: 		if (!*cp && (pref = atoi(a[leasepos])) <= 128)
 3131: 		  {
 3132: 		    new->prefix = pref;
 3133: 		    leasepos++;
 3134: 		  }
 3135: 	      }
 3136: 	    
 3137: 	    if (new->prefix > 64)
 3138: 	      {
 3139: 		if (new->flags & CONTEXT_RA)
 3140: 		  err=(_("prefix length must be exactly 64 for RA subnets"));
 3141: 		else if (new->flags & CONTEXT_TEMPLATE)
 3142: 		  err=(_("prefix length must be exactly 64 for subnet constructors"));
 3143: 	      }
 3144: 	    else if (new->prefix < 64)
 3145: 	      err=(_("prefix length must be at least 64"));
 3146: 	    
 3147: 	    if (!err && !is_same_net6(&new->start6, &new->end6, new->prefix))
 3148: 	      err=(_("inconsistent DHCPv6 range"));
 3149: 
 3150: 	    if (err)
 3151: 	      {
 3152: 		dhcp_context_free(new);
 3153: 		ret_err(err);
 3154: 	      }
 3155: 
 3156: 	    /* dhcp-range=:: enables DHCP stateless on any interface */
 3157: 	    if (IN6_IS_ADDR_UNSPECIFIED(&new->start6) && !(new->flags & CONTEXT_TEMPLATE))
 3158: 	      new->prefix = 0;
 3159: 	    
 3160: 	    if (new->flags & CONTEXT_TEMPLATE)
 3161: 	      {
 3162: 		struct in6_addr zero;
 3163: 		memset(&zero, 0, sizeof(zero));
 3164: 		if (!is_same_net6(&zero, &new->start6, new->prefix))
 3165: 		  {
 3166: 		    dhcp_context_free(new);
 3167: 		    ret_err(_("prefix must be zero with \"constructor:\" argument"));
 3168: 		  }
 3169: 	      }
 3170: 	    
 3171: 	    if (addr6part(&new->start6) > addr6part(&new->end6))
 3172: 	      {
 3173: 		struct in6_addr tmp = new->start6;
 3174: 		new->start6 = new->end6;
 3175: 		new->end6 = tmp;
 3176: 	      }
 3177: 	  }
 3178: #endif
 3179: 	else
 3180: 	  {
 3181: 	    dhcp_context_free(new);
 3182: 	    ret_err(_("bad dhcp-range"));
 3183: 	  }
 3184: 	
 3185: 	if (leasepos < k)
 3186: 	  {
 3187: 	    if (leasepos != k-1)
 3188: 	      {
 3189: 		dhcp_context_free(new);
 3190: 		ret_err(_("bad dhcp-range"));
 3191: 	      }
 3192: 	    
 3193: 	    if (strcmp(a[leasepos], "infinite") == 0)
 3194: 	      {
 3195: 		new->lease_time = 0xffffffff;
 3196: 		new->flags |= CONTEXT_SETLEASE;
 3197: 	      }
 3198: 	    else if (strcmp(a[leasepos], "deprecated") == 0)
 3199: 	      new->flags |= CONTEXT_DEPRECATE;
 3200: 	    else
 3201: 	      {
 3202: 		int fac = 1;
 3203: 		if (strlen(a[leasepos]) > 0)
 3204: 		  {
 3205: 		    switch (a[leasepos][strlen(a[leasepos]) - 1])
 3206: 		      {
 3207: 		      case 'w':
 3208: 		      case 'W':
 3209: 			fac *= 7;
 3210: 			/* fall through */
 3211: 		      case 'd':
 3212: 		      case 'D':
 3213: 			fac *= 24;
 3214: 			/* fall through */
 3215: 		      case 'h':
 3216: 		      case 'H':
 3217: 			fac *= 60;
 3218: 			/* fall through */
 3219: 		      case 'm':
 3220: 		      case 'M':
 3221: 			fac *= 60;
 3222: 			/* fall through */
 3223: 		      case 's':
 3224: 		      case 'S':
 3225: 			a[leasepos][strlen(a[leasepos]) - 1] = 0;
 3226: 		      }
 3227: 		    
 3228: 		    for (cp = a[leasepos]; *cp; cp++)
 3229: 		      if (!(*cp >= '0' && *cp <= '9'))
 3230: 			break;
 3231: 
 3232: 		    if (*cp || (leasepos+1 < k))
 3233: 		      ret_err_free(_("bad dhcp-range"), new);
 3234: 		    
 3235: 		    new->lease_time = atoi(a[leasepos]) * fac;
 3236: 		    new->flags |= CONTEXT_SETLEASE;
 3237: 		    /* Leases of a minute or less confuse
 3238: 		       some clients, notably Apple's */
 3239: 		    if (new->lease_time < 120)
 3240: 		      new->lease_time = 120;
 3241: 		  }
 3242: 	      }
 3243: 	  }
 3244: 
 3245: 	break;
 3246:       }
 3247: 
 3248:     case LOPT_BANK:
 3249:     case 'G':  /* --dhcp-host */
 3250:       {
 3251: 	struct dhcp_config *new;
 3252: 	struct in_addr in;
 3253: 	
 3254: 	new = opt_malloc(sizeof(struct dhcp_config));
 3255: 	
 3256: 	new->next = daemon->dhcp_conf;
 3257: 	new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
 3258: 	new->hwaddr = NULL;
 3259: 	new->netid = NULL;
 3260: 	new->filter = NULL;
 3261: 	new->clid = NULL;
 3262: #ifdef HAVE_DHCP6
 3263: 	new->addr6 = NULL;
 3264: #endif
 3265: 
 3266: 	while (arg)
 3267: 	  {
 3268: 	    comma = split(arg);
 3269: 	    if (strchr(arg, ':')) /* ethernet address, netid or binary CLID */
 3270: 	      {
 3271: 		if ((arg[0] == 'i' || arg[0] == 'I') &&
 3272: 		    (arg[1] == 'd' || arg[1] == 'D') &&
 3273: 		    arg[2] == ':')
 3274: 		  {
 3275: 		    if (arg[3] == '*')
 3276: 		      new->flags |= CONFIG_NOCLID;
 3277: 		    else
 3278: 		      {
 3279: 			int len;
 3280: 			arg += 3; /* dump id: */
 3281: 			if (strchr(arg, ':'))
 3282: 			  len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
 3283: 			else
 3284: 			  {
 3285: 			    unhide_metas(arg);
 3286: 			    len = (int) strlen(arg);
 3287: 			  }
 3288: 			
 3289: 			if (len == -1)
 3290: 			  {
 3291: 			    dhcp_config_free(new);
 3292: 			    ret_err(_("bad hex constant"));
 3293: 			  }
 3294: 			else if ((new->clid = opt_malloc(len)))
 3295: 			  {
 3296: 			    new->flags |= CONFIG_CLID;
 3297: 			    new->clid_len = len;
 3298: 			    memcpy(new->clid, arg, len);
 3299: 			  }
 3300: 		      }
 3301: 		  }
 3302: 		/* dhcp-host has strange backwards-compat needs. */
 3303: 		else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg)
 3304: 		  {
 3305: 		    struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
 3306: 		    newlist->next = new->netid;
 3307: 		    new->netid = newlist;
 3308: 		    newlist->list = dhcp_netid_create(arg+4, NULL);
 3309: 		  }
 3310: 		else if (strstr(arg, "tag:") == arg)
 3311: 		  new->filter = dhcp_netid_create(arg+4, new->filter);
 3312: 		  
 3313: #ifdef HAVE_DHCP6
 3314: 		else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
 3315: 		  {
 3316: 		    char *pref;
 3317: 		    struct in6_addr in6;
 3318: 		    struct addrlist *new_addr;
 3319: 		    
 3320: 		    arg[strlen(arg)-1] = 0;
 3321: 		    arg++;
 3322: 		    pref = split_chr(arg, '/');
 3323: 		    
 3324: 		    if (!inet_pton(AF_INET6, arg, &in6))
 3325: 		      {
 3326: 			dhcp_config_free(new);
 3327: 			ret_err(_("bad IPv6 address"));
 3328: 		      }
 3329: 
 3330: 		    new_addr = opt_malloc(sizeof(struct addrlist));
 3331: 		    new_addr->next = new->addr6;
 3332: 		    new_addr->flags = 0;
 3333: 		    new_addr->addr.addr6 = in6;
 3334: 		    new->addr6 = new_addr;
 3335: 		    
 3336: 		    if (pref)
 3337: 		      {
 3338: 			u64 addrpart = addr6part(&in6);
 3339: 			
 3340: 			if (!atoi_check(pref, &new_addr->prefixlen) ||
 3341: 			    new_addr->prefixlen > 128 ||
 3342: 			    ((((u64)1<<(128-new_addr->prefixlen))-1) & addrpart) != 0)
 3343: 			  {
 3344: 			    dhcp_config_free(new);
 3345: 			    ret_err(_("bad IPv6 prefix"));
 3346: 			  }
 3347: 			
 3348: 			new_addr->flags |= ADDRLIST_PREFIX;
 3349: 		      }
 3350: 		  
 3351: 		    for (i= 0; i < 8; i++)
 3352: 		      if (in6.s6_addr[i] != 0)
 3353: 			break;
 3354: 		    
 3355: 		    /* set WILDCARD if network part all zeros */
 3356: 		    if (i == 8)
 3357: 		      new_addr->flags |= ADDRLIST_WILDCARD;
 3358: 		    
 3359: 		    new->flags |= CONFIG_ADDR6;
 3360: 		  }
 3361: #endif
 3362: 		else
 3363: 		  {
 3364: 		    struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
 3365: 		    if ((newhw->hwaddr_len = parse_hex(arg, newhw->hwaddr, DHCP_CHADDR_MAX, 
 3366: 						       &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
 3367: 		      {
 3368: 			free(newhw);
 3369: 			dhcp_config_free(new);
 3370: 			ret_err(_("bad hex constant"));
 3371: 		      }
 3372: 		    else
 3373: 		      {
 3374: 			newhw->next = new->hwaddr;
 3375: 			new->hwaddr = newhw;
 3376: 		      }		    
 3377: 		  }
 3378: 	      }
 3379: 	    else if (strchr(arg, '.') && (inet_pton(AF_INET, arg, &in) > 0))
 3380: 	      {
 3381: 		struct dhcp_config *configs;
 3382: 		
 3383: 		new->addr = in;
 3384: 		new->flags |= CONFIG_ADDR;
 3385: 		
 3386: 		/* If the same IP appears in more than one host config, then DISCOVER
 3387: 		   for one of the hosts will get the address, but REQUEST will be NAKed,
 3388: 		   since the address is reserved by the other one -> protocol loop. */
 3389: 		for (configs = daemon->dhcp_conf; configs; configs = configs->next) 
 3390: 		  if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr)
 3391: 		    {
 3392: 		      sprintf(errstr, _("duplicate dhcp-host IP address %s"),  inet_ntoa(in));
 3393: 		      return 0;
 3394: 		    }	      
 3395: 	      }
 3396: 	    else
 3397: 	      {
 3398: 		char *cp, *lastp = NULL, last = 0;
 3399: 		int fac = 1, isdig = 0;
 3400: 		
 3401: 		if (strlen(arg) > 1)
 3402: 		  {
 3403: 		    lastp = arg + strlen(arg) - 1;
 3404: 		    last = *lastp;
 3405: 		    switch (last)
 3406: 		      {
 3407: 		      case 'w':
 3408: 		      case 'W':
 3409: 			fac *= 7;
 3410: 			/* fall through */
 3411: 		      case 'd':
 3412: 		      case 'D':
 3413: 			fac *= 24;
 3414: 			/* fall through */
 3415: 		      case 'h':
 3416: 		      case 'H':
 3417: 			fac *= 60;
 3418: 			/* fall through */
 3419: 		      case 'm':
 3420: 		      case 'M':
 3421: 			fac *= 60;
 3422: 			/* fall through */
 3423: 		      case 's':
 3424: 		      case 'S':
 3425: 			*lastp = 0;
 3426: 		      }
 3427: 		  }
 3428: 		
 3429: 		for (cp = arg; *cp; cp++)
 3430: 		  if (isdigit((unsigned char)*cp))
 3431: 		    isdig = 1;
 3432: 		  else if (*cp != ' ')
 3433: 		    break;
 3434: 
 3435: 		if (*cp)
 3436: 		  {
 3437: 		    if (lastp)
 3438: 		      *lastp = last;
 3439: 		    if (strcmp(arg, "infinite") == 0)
 3440: 		      {
 3441: 			new->lease_time = 0xffffffff;
 3442: 			new->flags |= CONFIG_TIME;
 3443: 		      }
 3444: 		    else if (strcmp(arg, "ignore") == 0)
 3445: 		      new->flags |= CONFIG_DISABLE;
 3446: 		    else
 3447: 		      {
 3448: 			if (!(new->hostname = canonicalise_opt(arg)) ||
 3449: 			    !legal_hostname(new->hostname))
 3450: 			  {
 3451: 			    dhcp_config_free(new);
 3452: 			    ret_err(_("bad DHCP host name"));
 3453: 			  }
 3454: 			
 3455: 			new->flags |= CONFIG_NAME;
 3456: 			new->domain = strip_hostname(new->hostname);			
 3457: 		      }
 3458: 		  }
 3459: 		else if (isdig)
 3460: 		  {
 3461: 		    new->lease_time = atoi(arg) * fac; 
 3462: 		    /* Leases of a minute or less confuse
 3463: 		       some clients, notably Apple's */
 3464: 		    if (new->lease_time < 120)
 3465: 		      new->lease_time = 120;
 3466: 		    new->flags |= CONFIG_TIME;
 3467: 		  }
 3468: 	      }
 3469: 
 3470: 	    arg = comma;
 3471: 	  }
 3472: 
 3473: 	daemon->dhcp_conf = new;
 3474: 	break;
 3475:       }
 3476:       
 3477:     case LOPT_TAG_IF:  /* --tag-if */
 3478:       {
 3479: 	struct tag_if *new = opt_malloc(sizeof(struct tag_if));
 3480: 		
 3481: 	new->tag = NULL;
 3482: 	new->set = NULL;
 3483: 	new->next = NULL;
 3484: 	
 3485: 	/* preserve order */
 3486: 	if (!daemon->tag_if)
 3487: 	  daemon->tag_if = new;
 3488: 	else
 3489: 	  {
 3490: 	    struct tag_if *tmp;
 3491: 	    for (tmp = daemon->tag_if; tmp->next; tmp = tmp->next);
 3492: 	    tmp->next = new;
 3493: 	  }
 3494: 
 3495: 	while (arg)
 3496: 	  {
 3497: 	    size_t len;
 3498: 
 3499: 	    comma = split(arg);
 3500: 	    len = strlen(arg);
 3501: 
 3502: 	    if (len < 5)
 3503: 	      {
 3504: 		new->set = NULL;
 3505: 		break;
 3506: 	      }
 3507: 	    else
 3508: 	      {
 3509: 		struct dhcp_netid *newtag = dhcp_netid_create(arg+4, NULL);
 3510: 
 3511: 		if (strstr(arg, "set:") == arg)
 3512: 		  {
 3513: 		    struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
 3514: 		    newlist->next = new->set;
 3515: 		    new->set = newlist;
 3516: 		    newlist->list = newtag;
 3517: 		  }
 3518: 		else if (strstr(arg, "tag:") == arg)
 3519: 		  {
 3520: 		    newtag->next = new->tag;
 3521: 		    new->tag = newtag;
 3522: 		  }
 3523: 		else 
 3524: 		  {
 3525: 		    new->set = NULL;
 3526: 		    dhcp_netid_free(newtag);
 3527: 		    break;
 3528: 		  }
 3529: 	      }
 3530: 	    
 3531: 	    arg = comma;
 3532: 	  }
 3533: 
 3534: 	if (!new->set)
 3535: 	  {
 3536: 	    dhcp_netid_free(new->tag);
 3537: 	    dhcp_netid_list_free(new->set);
 3538: 	    ret_err_free(_("bad tag-if"), new);
 3539: 	  }
 3540: 	  
 3541: 	break;
 3542:       }
 3543: 
 3544:       
 3545:     case 'O':           /* --dhcp-option */
 3546:     case LOPT_FORCE:    /* --dhcp-option-force */
 3547:     case LOPT_OPTS:
 3548:     case LOPT_MATCH:    /* --dhcp-match */
 3549:       return parse_dhcp_opt(errstr, arg, 
 3550: 			    option == LOPT_FORCE ? DHOPT_FORCE : 
 3551: 			    (option == LOPT_MATCH ? DHOPT_MATCH :
 3552: 			     (option == LOPT_OPTS ? DHOPT_BANK : 0)));
 3553: 
 3554:     case LOPT_NAME_MATCH: /* --dhcp-name-match */
 3555:       {
 3556: 	struct dhcp_match_name *new = opt_malloc(sizeof(struct dhcp_match_name));
 3557: 	struct dhcp_netid *id = opt_malloc(sizeof(struct dhcp_netid));
 3558: 	ssize_t len;
 3559: 	
 3560: 	if (!(comma = split(arg)) || (len = strlen(comma)) == 0)
 3561: 	  ret_err(gen_err);
 3562: 
 3563: 	new->wildcard = 0;
 3564: 	new->netid = id;
 3565: 	id->net = opt_string_alloc(set_prefix(arg));
 3566: 
 3567: 	if (comma[len-1] == '*')
 3568: 	  {
 3569: 	    comma[len-1] = 0;
 3570: 	    new->wildcard = 1;
 3571: 	  }
 3572: 	new->name = opt_string_alloc(comma);
 3573: 
 3574: 	new->next = daemon->dhcp_name_match;
 3575: 	daemon->dhcp_name_match = new;
 3576: 
 3577: 	break;
 3578:       }
 3579:       
 3580:     case 'M': /* --dhcp-boot */
 3581:       {
 3582: 	struct dhcp_netid *id = dhcp_tags(&arg);
 3583: 	
 3584: 	if (!arg)
 3585: 	  {
 3586: 	    ret_err(gen_err);
 3587: 	  }
 3588: 	else 
 3589: 	  {
 3590: 	    char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL;
 3591: 	    struct in_addr dhcp_next_server;
 3592: 	    struct dhcp_boot *new;
 3593: 	    comma = split(arg);
 3594: 	    dhcp_file = opt_string_alloc(arg);
 3595: 	    dhcp_next_server.s_addr = 0;
 3596: 	    if (comma)
 3597: 	      {
 3598: 		arg = comma;
 3599: 		comma = split(arg);
 3600: 		dhcp_sname = opt_string_alloc(arg);
 3601: 		if (comma)
 3602: 		  {
 3603: 		    unhide_metas(comma);
 3604: 		    if (!(inet_pton(AF_INET, comma, &dhcp_next_server) > 0))
 3605: 		      {
 3606: 			/*
 3607: 			 * The user may have specified the tftp hostname here.
 3608: 			 * save it so that it can be resolved/looked up during
 3609: 			 * actual dhcp_reply().
 3610: 			 */	
 3611: 			
 3612: 			tftp_sname = opt_string_alloc(comma);
 3613: 			dhcp_next_server.s_addr = 0;
 3614: 		      }
 3615: 		  }
 3616: 	      }
 3617: 	    
 3618: 	    new = opt_malloc(sizeof(struct dhcp_boot));
 3619: 	    new->file = dhcp_file;
 3620: 	    new->sname = dhcp_sname;
 3621: 	    new->tftp_sname = tftp_sname;
 3622: 	    new->next_server = dhcp_next_server;
 3623: 	    new->netid = id;
 3624: 	    new->next = daemon->boot_config;
 3625: 	    daemon->boot_config = new;
 3626: 	  }
 3627:       
 3628: 	break;
 3629:       }
 3630: 
 3631:     case LOPT_REPLY_DELAY: /* --dhcp-reply-delay */
 3632:       {
 3633: 	struct dhcp_netid *id = dhcp_tags(&arg);
 3634: 	
 3635: 	if (!arg)
 3636: 	  {
 3637: 	    ret_err(gen_err);
 3638: 	  }
 3639: 	else
 3640: 	  {
 3641: 	    struct delay_config *new;
 3642: 	    int delay;
 3643: 	    if (!atoi_check(arg, &delay))
 3644:               ret_err(gen_err);
 3645: 	    
 3646: 	    new = opt_malloc(sizeof(struct delay_config));
 3647: 	    new->delay = delay;
 3648: 	    new->netid = id;
 3649:             new->next = daemon->delay_conf;
 3650:             daemon->delay_conf = new;
 3651: 	  }
 3652: 	
 3653: 	break;
 3654:       }
 3655:       
 3656:     case LOPT_PXE_PROMT:  /* --pxe-prompt */
 3657:        {
 3658: 	 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
 3659: 	 int timeout;
 3660: 	 
 3661: 	 new->netid = NULL;
 3662: 	 new->opt = 10; /* PXE_MENU_PROMPT */
 3663: 	 new->netid = dhcp_tags(&arg);
 3664: 	 
 3665: 	 if (!arg)
 3666: 	   {
 3667: 	     dhcp_opt_free(new);
 3668: 	     ret_err(gen_err);
 3669: 	   }
 3670: 	 else
 3671: 	   {
 3672: 	     comma = split(arg);
 3673: 	     unhide_metas(arg);
 3674: 	     new->len = strlen(arg) + 1;
 3675: 	     new->val = opt_malloc(new->len);
 3676: 	     memcpy(new->val + 1, arg, new->len - 1);
 3677: 	     
 3678: 	     new->u.vendor_class = NULL;
 3679: 	     new->flags = DHOPT_VENDOR | DHOPT_VENDOR_PXE;
 3680: 	     
 3681: 	     if (comma && atoi_check(comma, &timeout))
 3682: 	       *(new->val) = timeout;
 3683: 	     else
 3684: 	       *(new->val) = 255;
 3685: 
 3686: 	     new->next = daemon->dhcp_opts;
 3687: 	     daemon->dhcp_opts = new;
 3688: 	     daemon->enable_pxe = 1;
 3689: 	   }
 3690: 	 
 3691: 	 break;
 3692:        }
 3693:        
 3694:     case LOPT_PXE_SERV:  /* --pxe-service */
 3695:        {
 3696: 	 struct pxe_service *new = opt_malloc(sizeof(struct pxe_service));
 3697: 	 char *CSA[] = { "x86PC", "PC98", "IA64_EFI", "Alpha", "Arc_x86", "Intel_Lean_Client",
 3698: 			 "IA32_EFI", "x86-64_EFI", "Xscale_EFI", "BC_EFI",
 3699: 			 "ARM32_EFI", "ARM64_EFI", NULL };  
 3700: 	 static int boottype = 32768;
 3701: 	 
 3702: 	 new->netid = NULL;
 3703: 	 new->sname = NULL;
 3704: 	 new->server.s_addr = 0;
 3705: 	 new->netid = dhcp_tags(&arg);
 3706: 
 3707: 	 if (arg && (comma = split(arg)))
 3708: 	   {
 3709: 	     for (i = 0; CSA[i]; i++)
 3710: 	       if (strcasecmp(CSA[i], arg) == 0)
 3711: 		 break;
 3712: 	     
 3713: 	     if (CSA[i] || atoi_check(arg, &i))
 3714: 	       {
 3715: 		 arg = comma;
 3716: 		 comma = split(arg);
 3717: 		 
 3718: 		 new->CSA = i;
 3719: 		 new->menu = opt_string_alloc(arg);
 3720: 		 
 3721: 		 if (!comma)
 3722: 		   {
 3723: 		     new->type = 0; /* local boot */
 3724: 		     new->basename = NULL;
 3725: 		   }
 3726: 		 else
 3727: 		   {
 3728: 		     arg = comma;
 3729: 		     comma = split(arg);
 3730: 		     if (atoi_check(arg, &i))
 3731: 		       {
 3732: 			 new->type = i;
 3733: 			 new->basename = NULL;
 3734: 		       }
 3735: 		     else
 3736: 		       {
 3737: 			 new->type = boottype++;
 3738: 			 new->basename = opt_string_alloc(arg);
 3739: 		       }
 3740: 		     
 3741: 		     if (comma)
 3742: 		       {
 3743: 			 if (!inet_pton(AF_INET, comma, &new->server))
 3744: 			   {
 3745: 			     new->server.s_addr = 0;
 3746: 			     new->sname = opt_string_alloc(comma);
 3747: 			   }
 3748: 		       
 3749: 		       }
 3750: 		   }
 3751: 		 
 3752: 		 /* Order matters */
 3753: 		 new->next = NULL;
 3754: 		 if (!daemon->pxe_services)
 3755: 		   daemon->pxe_services = new; 
 3756: 		 else
 3757: 		   {
 3758: 		     struct pxe_service *s;
 3759: 		     for (s = daemon->pxe_services; s->next; s = s->next);
 3760: 		     s->next = new;
 3761: 		   }
 3762: 		 
 3763: 		 daemon->enable_pxe = 1;
 3764: 		 break;
 3765: 		
 3766: 	       }
 3767: 	   }
 3768: 	 
 3769: 	 ret_err(gen_err);
 3770:        }
 3771: 	 
 3772:     case '4':  /* --dhcp-mac */
 3773:       {
 3774: 	if (!(comma = split(arg)))
 3775: 	  ret_err(gen_err);
 3776: 	else
 3777: 	  {
 3778: 	    struct dhcp_mac *new = opt_malloc(sizeof(struct dhcp_mac));
 3779: 	    new->netid.net = opt_string_alloc(set_prefix(arg));
 3780: 	    unhide_metas(comma);
 3781: 	    new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
 3782: 	    if (new->hwaddr_len == -1)
 3783: 	      {
 3784: 		free(new->netid.net);
 3785: 		ret_err_free(gen_err, new);
 3786: 	      }
 3787: 	    else
 3788: 	      {
 3789: 		new->next = daemon->dhcp_macs;
 3790: 		daemon->dhcp_macs = new;
 3791: 	      }
 3792: 	  }
 3793:       }
 3794:       break;
 3795: 
 3796:     case 'U':           /* --dhcp-vendorclass */
 3797:     case 'j':           /* --dhcp-userclass */
 3798:     case LOPT_CIRCUIT:  /* --dhcp-circuitid */
 3799:     case LOPT_REMOTE:   /* --dhcp-remoteid */
 3800:     case LOPT_SUBSCR:   /* --dhcp-subscrid */
 3801:       {
 3802: 	 unsigned char *p;
 3803: 	 int dig = 0;
 3804: 	 struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
 3805: 	 
 3806: 	 if (!(comma = split(arg)))
 3807: 	   ret_err_free(gen_err, new);
 3808: 	
 3809: 	 new->netid.net = opt_string_alloc(set_prefix(arg));
 3810: 	 /* check for hex string - must digits may include : must not have nothing else, 
 3811: 	    only allowed for agent-options. */
 3812: 	 
 3813: 	 arg = comma;
 3814: 	 if ((comma = split(arg)))
 3815: 	   {
 3816: 	     if (option  != 'U' || strstr(arg, "enterprise:") != arg)
 3817: 	       {
 3818: 	         free(new->netid.net);
 3819: 	         ret_err_free(gen_err, new);
 3820: 	       }
 3821: 	     else
 3822: 	       new->enterprise = atoi(arg+11);
 3823: 	   }
 3824: 	 else
 3825: 	   comma = arg;
 3826: 	 
 3827: 	 for (p = (unsigned char *)comma; *p; p++)
 3828: 	   if (isxdigit(*p))
 3829: 	     dig = 1;
 3830: 	   else if (*p != ':')
 3831: 	     break;
 3832: 	 unhide_metas(comma);
 3833: 	 if (option == 'U' || option == 'j' || *p || !dig)
 3834: 	   {
 3835: 	     new->len = strlen(comma);  
 3836: 	     new->data = opt_malloc(new->len);
 3837: 	     memcpy(new->data, comma, new->len);
 3838: 	   }
 3839: 	 else
 3840: 	   {
 3841: 	     new->len = parse_hex(comma, (unsigned char *)comma, strlen(comma), NULL, NULL);
 3842: 	     new->data = opt_malloc(new->len);
 3843: 	     memcpy(new->data, comma, new->len);
 3844: 	   }
 3845: 	 
 3846: 	 switch (option)
 3847: 	   {
 3848: 	   case 'j':
 3849: 	     new->match_type = MATCH_USER;
 3850: 	     break;
 3851: 	   case 'U':
 3852: 	     new->match_type = MATCH_VENDOR;
 3853: 	     break; 
 3854: 	   case LOPT_CIRCUIT:
 3855: 	     new->match_type = MATCH_CIRCUIT;
 3856: 	     break;
 3857: 	   case LOPT_REMOTE:
 3858: 	     new->match_type = MATCH_REMOTE;
 3859: 	     break;
 3860: 	   case LOPT_SUBSCR:
 3861: 	     new->match_type = MATCH_SUBSCRIBER;
 3862: 	     break;
 3863: 	   }
 3864: 	 new->next = daemon->dhcp_vendors;
 3865: 	 daemon->dhcp_vendors = new;
 3866: 
 3867: 	 break;
 3868:       }
 3869:       
 3870:     case LOPT_ALTPORT:   /* --dhcp-alternate-port */
 3871:       if (!arg)
 3872: 	{
 3873: 	  daemon->dhcp_server_port = DHCP_SERVER_ALTPORT;
 3874: 	  daemon->dhcp_client_port = DHCP_CLIENT_ALTPORT;
 3875: 	}
 3876:       else
 3877: 	{
 3878: 	  comma = split(arg);
 3879: 	  if (!atoi_check16(arg, &daemon->dhcp_server_port) || 
 3880: 	      (comma && !atoi_check16(comma, &daemon->dhcp_client_port)))
 3881: 	    ret_err(_("invalid port number"));
 3882: 	  if (!comma)
 3883: 	    daemon->dhcp_client_port = daemon->dhcp_server_port+1; 
 3884: 	}
 3885:       break;
 3886: 
 3887:     case 'J':            /* --dhcp-ignore */
 3888:     case LOPT_NO_NAMES:  /* --dhcp-ignore-names */
 3889:     case LOPT_BROADCAST: /* --dhcp-broadcast */
 3890:     case '3':            /* --bootp-dynamic */
 3891:     case LOPT_GEN_NAMES: /* --dhcp-generate-names */
 3892:       {
 3893: 	struct dhcp_netid_list *new = opt_malloc(sizeof(struct dhcp_netid_list));
 3894: 	struct dhcp_netid *list = NULL;
 3895: 	if (option == 'J')
 3896: 	  {
 3897: 	    new->next = daemon->dhcp_ignore;
 3898: 	    daemon->dhcp_ignore = new;
 3899: 	  }
 3900: 	else if (option == LOPT_BROADCAST)
 3901: 	  {
 3902: 	    new->next = daemon->force_broadcast;
 3903: 	    daemon->force_broadcast = new;
 3904: 	  }
 3905: 	else if (option == '3')
 3906: 	  {
 3907: 	    new->next = daemon->bootp_dynamic;
 3908: 	    daemon->bootp_dynamic = new;
 3909: 	  }
 3910: 	else if (option == LOPT_GEN_NAMES)
 3911: 	  {
 3912: 	    new->next = daemon->dhcp_gen_names;
 3913: 	    daemon->dhcp_gen_names = new;
 3914: 	  }
 3915: 	else
 3916: 	  {
 3917: 	    new->next = daemon->dhcp_ignore_names;
 3918: 	    daemon->dhcp_ignore_names = new;
 3919: 	  }
 3920: 	
 3921: 	while (arg) {
 3922: 	  comma = split(arg);
 3923: 	  list = dhcp_netid_create(is_tag_prefix(arg) ? arg+4 :arg, list);
 3924: 	  arg = comma;
 3925: 	}
 3926: 	
 3927: 	new->list = list;
 3928: 	break;
 3929:       }
 3930: 
 3931:     case LOPT_PROXY: /* --dhcp-proxy */
 3932:       daemon->override = 1;
 3933:       while (arg) {
 3934: 	struct addr_list *new = opt_malloc(sizeof(struct addr_list));
 3935: 	comma = split(arg);
 3936: 	if (!(inet_pton(AF_INET, arg, &new->addr) > 0))
 3937: 	  ret_err_free(_("bad dhcp-proxy address"), new);
 3938: 	new->next = daemon->override_relays;
 3939: 	daemon->override_relays = new;
 3940: 	arg = comma;
 3941: 	}
 3942: 	  break;
 3943: 
 3944:     case LOPT_PXE_VENDOR: /* --dhcp-pxe-vendor */
 3945:       {
 3946:         while (arg) {
 3947: 	  struct dhcp_pxe_vendor *new = opt_malloc(sizeof(struct dhcp_pxe_vendor));
 3948: 	  comma = split(arg);
 3949:           new->data = opt_string_alloc(arg);
 3950: 	  new->next = daemon->dhcp_pxe_vendors;
 3951: 	  daemon->dhcp_pxe_vendors = new;
 3952: 	  arg = comma;
 3953: 	}
 3954:       }
 3955:       break;
 3956: 
 3957:     case LOPT_RELAY: /* --dhcp-relay */
 3958:       {
 3959: 	struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
 3960: 	comma = split(arg);
 3961: 	new->interface = opt_string_alloc(split(comma));
 3962: 	new->iface_index = 0;
 3963: 	if (inet_pton(AF_INET, arg, &new->local) && inet_pton(AF_INET, comma, &new->server))
 3964: 	  {
 3965: 	    new->next = daemon->relay4;
 3966: 	    daemon->relay4 = new;
 3967: 	  }
 3968: #ifdef HAVE_DHCP6
 3969: 	else if (inet_pton(AF_INET6, arg, &new->local) && inet_pton(AF_INET6, comma, &new->server))
 3970: 	  {
 3971: 	    new->next = daemon->relay6;
 3972: 	    daemon->relay6 = new;
 3973: 	  }
 3974: #endif
 3975: 	else
 3976: 	  {
 3977: 	    free(new->interface);
 3978: 	    ret_err_free(_("Bad dhcp-relay"), new);
 3979: 	  }
 3980: 	
 3981: 	break;
 3982:       }
 3983: 
 3984: #endif
 3985:       
 3986: #ifdef HAVE_DHCP6
 3987:     case LOPT_RA_PARAM: /* --ra-param */
 3988:       if ((comma = split(arg)))
 3989: 	{
 3990: 	  struct ra_interface *new = opt_malloc(sizeof(struct ra_interface));
 3991: 	  new->lifetime = -1;
 3992: 	  new->prio = 0;
 3993: 	  new->mtu = 0;
 3994: 	  new->mtu_name = NULL;
 3995: 	  new->name = opt_string_alloc(arg);
 3996: 	  if (strcasestr(comma, "mtu:") == comma)
 3997: 	    {
 3998: 	      arg = comma + 4;
 3999: 	      if (!(comma = split(comma)))
 4000: 	        goto err;
 4001: 	      if (!strcasecmp(arg, "off"))
 4002: 	        new->mtu = -1;
 4003: 	      else if (!atoi_check(arg, &new->mtu))
 4004: 	        new->mtu_name = opt_string_alloc(arg);
 4005: 	      else if (new->mtu < 1280)
 4006: 	        goto err;
 4007: 	    }
 4008: 	  if (strcasestr(comma, "high") == comma || strcasestr(comma, "low") == comma)
 4009: 	    {
 4010: 	      if (*comma == 'l' || *comma == 'L')
 4011: 		new->prio = 0x18;
 4012: 	      else
 4013: 		new->prio = 0x08;
 4014: 	      comma = split(comma);
 4015: 	    }
 4016: 	   arg = split(comma);
 4017: 	   if (!atoi_check(comma, &new->interval) || 
 4018: 	      (arg && !atoi_check(arg, &new->lifetime)))
 4019:              {
 4020: err:
 4021: 	       free(new->name);
 4022: 	       ret_err_free(_("bad RA-params"), new);
 4023:              }
 4024: 	  
 4025: 	  new->next = daemon->ra_interfaces;
 4026: 	  daemon->ra_interfaces = new;
 4027: 	}
 4028:       break;
 4029:       
 4030:     case LOPT_DUID: /* --dhcp-duid */
 4031:       if (!(comma = split(arg)) || !atoi_check(arg, (int *)&daemon->duid_enterprise))
 4032: 	ret_err(_("bad DUID"));
 4033:       else
 4034: 	{
 4035: 	  daemon->duid_config_len = parse_hex(comma,(unsigned char *)comma, strlen(comma), NULL, NULL);
 4036: 	  daemon->duid_config = opt_malloc(daemon->duid_config_len);
 4037: 	  memcpy(daemon->duid_config, comma, daemon->duid_config_len);
 4038: 	}
 4039:       break;
 4040: #endif
 4041: 
 4042:     case 'V':  /* --alias */
 4043:       {
 4044: 	char *dash, *a[3] = { NULL, NULL, NULL };
 4045: 	int k = 0;
 4046: 	struct doctor *new = opt_malloc(sizeof(struct doctor));
 4047: 	new->next = daemon->doctors;
 4048: 	daemon->doctors = new;
 4049: 	new->mask.s_addr = 0xffffffff;
 4050: 	new->end.s_addr = 0;
 4051: 
 4052: 	if ((a[0] = arg))
 4053: 	  for (k = 1; k < 3; k++)
 4054: 	    {
 4055: 	      if (!(a[k] = split(a[k-1])))
 4056: 		break;
 4057: 	      unhide_metas(a[k]);
 4058: 	    }
 4059: 	
 4060: 	dash = split_chr(a[0], '-');
 4061: 
 4062: 	if ((k < 2) || 
 4063: 	    (!(inet_pton(AF_INET, a[0], &new->in) > 0)) ||
 4064: 	    (!(inet_pton(AF_INET, a[1], &new->out) > 0)) ||
 4065: 	    (k == 3 && !inet_pton(AF_INET, a[2], &new->mask)))
 4066: 	  ret_err(_("missing address in alias"));
 4067: 	
 4068: 	if (dash && 
 4069: 	    (!(inet_pton(AF_INET, dash, &new->end) > 0) ||
 4070: 	     !is_same_net(new->in, new->end, new->mask) ||
 4071: 	     ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
 4072: 	  ret_err_free(_("invalid alias range"), new);
 4073: 	
 4074: 	break;
 4075:       }
 4076:       
 4077:     case LOPT_INTNAME:  /* --interface-name */
 4078:       {
 4079: 	struct interface_name *new, **up;
 4080: 	char *domain = NULL;
 4081: 
 4082: 	comma = split(arg);
 4083: 	
 4084: 	if (!comma || !(domain = canonicalise_opt(arg)))
 4085: 	  ret_err(_("bad interface name"));
 4086: 	
 4087: 	new = opt_malloc(sizeof(struct interface_name));
 4088: 	new->next = NULL;
 4089: 	new->addr = NULL;
 4090: 	
 4091: 	/* Add to the end of the list, so that first name
 4092: 	   of an interface is used for PTR lookups. */
 4093: 	for (up = &daemon->int_names; *up; up = &((*up)->next));
 4094: 	*up = new;
 4095: 	new->name = domain;
 4096: 	new->family = 0;
 4097: 	arg = split_chr(comma, '/');
 4098: 	if (arg)
 4099: 	  {
 4100: 	    if (strcmp(arg, "4") == 0)
 4101: 	      new->family = AF_INET;
 4102: 	    else if (strcmp(arg, "6") == 0)
 4103: 	      new->family = AF_INET6;
 4104: 	    else
 4105: 	      ret_err_free(gen_err, new);
 4106: 	  } 
 4107: 	new->intr = opt_string_alloc(comma);
 4108: 	break;
 4109:       }
 4110:       
 4111:     case LOPT_CNAME: /* --cname */
 4112:       {
 4113: 	struct cname *new;
 4114: 	char *alias, *target, *last, *pen;
 4115: 	int ttl = -1;
 4116: 
 4117: 	for (last = pen = NULL, comma = arg; comma; comma = split(comma))
 4118: 	  {
 4119: 	    pen = last;
 4120: 	    last = comma;
 4121: 	  }
 4122: 
 4123: 	if (!pen)
 4124: 	  ret_err(_("bad CNAME"));
 4125: 	
 4126: 	if (pen != arg && atoi_check(last, &ttl))
 4127: 	  last = pen;
 4128: 	  	
 4129:     	target = canonicalise_opt(last);
 4130: 
 4131: 	while (arg != last)
 4132: 	  {
 4133: 	    int arglen = strlen(arg);
 4134: 	    alias = canonicalise_opt(arg);
 4135: 
 4136: 	    if (!alias || !target)
 4137: 	      {
 4138: 		free(target);
 4139: 		free(alias);
 4140: 		ret_err(_("bad CNAME"));
 4141: 	      }
 4142: 	    
 4143: 	    for (new = daemon->cnames; new; new = new->next)
 4144: 	      if (hostname_isequal(new->alias, alias))
 4145: 		{
 4146: 		  free(target);
 4147: 		  free(alias);
 4148: 		  ret_err(_("duplicate CNAME"));
 4149: 		}
 4150: 	    new = opt_malloc(sizeof(struct cname));
 4151: 	    new->next = daemon->cnames;
 4152: 	    daemon->cnames = new;
 4153: 	    new->alias = alias;
 4154: 	    new->target = target;
 4155: 	    new->ttl = ttl;
 4156: 
 4157: 	    for (arg += arglen+1; *arg && isspace(*arg); arg++);
 4158: 	  }
 4159:       
 4160: 	break;
 4161:       }
 4162: 
 4163:     case LOPT_PTR:  /* --ptr-record */
 4164:       {
 4165: 	struct ptr_record *new;
 4166: 	char *dom, *target = NULL;
 4167: 
 4168: 	comma = split(arg);
 4169: 	
 4170: 	if (!(dom = canonicalise_opt(arg)) ||
 4171: 	    (comma && !(target = canonicalise_opt(comma))))
 4172: 	  {
 4173: 	    free(dom);
 4174: 	    free(target);
 4175: 	    ret_err(_("bad PTR record"));
 4176: 	  }
 4177: 	else
 4178: 	  {
 4179: 	    new = opt_malloc(sizeof(struct ptr_record));
 4180: 	    new->next = daemon->ptr;
 4181: 	    daemon->ptr = new;
 4182: 	    new->name = dom;
 4183: 	    new->ptr = target;
 4184: 	  }
 4185: 	break;
 4186:       }
 4187: 
 4188:     case LOPT_NAPTR: /* --naptr-record */
 4189:       {
 4190: 	char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
 4191: 	int k = 0;
 4192: 	struct naptr *new;
 4193: 	int order, pref;
 4194: 	char *name=NULL, *replace = NULL;
 4195: 
 4196: 	if ((a[0] = arg))
 4197: 	  for (k = 1; k < 7; k++)
 4198: 	    if (!(a[k] = split(a[k-1])))
 4199: 	      break;
 4200: 	
 4201: 	
 4202: 	if (k < 6 || 
 4203: 	    !(name = canonicalise_opt(a[0])) ||
 4204: 	    !atoi_check16(a[1], &order) || 
 4205: 	    !atoi_check16(a[2], &pref) ||
 4206: 	    (k == 7 && !(replace = canonicalise_opt(a[6]))))
 4207:           {
 4208: 	    free(name);
 4209: 	    free(replace);
 4210: 	    ret_err(_("bad NAPTR record"));
 4211:           }
 4212: 	else
 4213: 	  {
 4214: 	    new = opt_malloc(sizeof(struct naptr));
 4215: 	    new->next = daemon->naptr;
 4216: 	    daemon->naptr = new;
 4217: 	    new->name = name;
 4218: 	    new->flags = opt_string_alloc(a[3]);
 4219: 	    new->services = opt_string_alloc(a[4]);
 4220: 	    new->regexp = opt_string_alloc(a[5]);
 4221: 	    new->replace = replace;
 4222: 	    new->order = order;
 4223: 	    new->pref = pref;
 4224: 	  }
 4225: 	break;
 4226:       }
 4227: 
 4228:     case LOPT_RR: /* dns-rr */
 4229:       {
 4230:        	struct txt_record *new;
 4231: 	size_t len = 0;
 4232: 	char *data;
 4233: 	int class;
 4234: 
 4235: 	comma = split(arg);
 4236: 	data = split(comma);
 4237: 		
 4238: 	new = opt_malloc(sizeof(struct txt_record));
 4239: 	new->name = NULL;
 4240: 	
 4241: 	if (!atoi_check(comma, &class) || 
 4242: 	    !(new->name = canonicalise_opt(arg)) ||
 4243: 	    (data && (len = parse_hex(data, (unsigned char *)data, -1, NULL, NULL)) == -1U))
 4244:           {
 4245:             free(new->name);
 4246: 	    ret_err_free(_("bad RR record"), new);
 4247:           }
 4248: 
 4249: 	new->len = 0;
 4250: 	new->class = class;
 4251: 	new->next = daemon->rr;
 4252: 	daemon->rr = new;
 4253: 	
 4254: 	if (data)
 4255: 	  {
 4256: 	    new->txt = opt_malloc(len);
 4257: 	    new->len = len;
 4258: 	    memcpy(new->txt, data, len);
 4259: 	  }
 4260: 	
 4261: 	break;
 4262:       }
 4263: 
 4264:     case LOPT_CAA: /* --caa-record */
 4265:       {
 4266:        	struct txt_record *new;
 4267: 	char *tag, *value;
 4268: 	int flags;
 4269: 	
 4270: 	comma = split(arg);
 4271: 	tag = split(comma);
 4272: 	value = split(tag);
 4273: 	
 4274: 	new = opt_malloc(sizeof(struct txt_record));
 4275: 	new->next = daemon->rr;
 4276: 	daemon->rr = new;
 4277: 
 4278: 	if (!atoi_check(comma, &flags) || !tag || !value || !(new->name = canonicalise_opt(arg)))
 4279: 	  ret_err(_("bad CAA record"));
 4280: 	
 4281: 	unhide_metas(tag);
 4282: 	unhide_metas(value);
 4283: 
 4284: 	new->len = strlen(tag) + strlen(value) + 2;
 4285: 	new->txt = opt_malloc(new->len);
 4286: 	new->txt[0] = flags;
 4287: 	new->txt[1] = strlen(tag);
 4288: 	memcpy(&new->txt[2], tag, strlen(tag));
 4289: 	memcpy(&new->txt[2 + strlen(tag)], value, strlen(value));
 4290: 	new->class = T_CAA;
 4291: 	
 4292: 	break;
 4293:       }
 4294: 	
 4295:     case 'Y':  /* --txt-record */
 4296:       {
 4297: 	struct txt_record *new;
 4298: 	unsigned char *p, *cnt;
 4299: 	size_t len;
 4300: 
 4301: 	comma = split(arg);
 4302: 		
 4303: 	new = opt_malloc(sizeof(struct txt_record));
 4304: 	new->class = C_IN;
 4305: 	new->stat = 0;
 4306: 
 4307: 	if (!(new->name = canonicalise_opt(arg)))
 4308: 	  ret_err_free(_("bad TXT record"), new);
 4309: 	
 4310: 	new->next = daemon->txt;
 4311: 	daemon->txt = new;
 4312: 	len = comma ? strlen(comma) : 0;
 4313: 	len += (len/255) + 1; /* room for extra counts */
 4314: 	new->txt = p = opt_malloc(len);
 4315: 
 4316: 	cnt = p++;
 4317: 	*cnt = 0;
 4318: 	
 4319: 	while (comma && *comma)
 4320: 	  {
 4321: 	    unsigned char c = (unsigned char)*comma++;
 4322: 
 4323: 	    if (c == ',' || *cnt == 255)
 4324: 	      {
 4325: 		if (c != ',')
 4326: 		  comma--;
 4327: 		cnt = p++;
 4328: 		*cnt = 0;
 4329: 	      }
 4330: 	    else
 4331: 	      {
 4332: 		*p++ = unhide_meta(c);
 4333: 		(*cnt)++;
 4334: 	      }
 4335: 	  }
 4336: 
 4337: 	new->len = p - new->txt;
 4338: 
 4339: 	break;
 4340:       }
 4341:       
 4342:     case 'W':  /* --srv-host */
 4343:       {
 4344: 	int port = 1, priority = 0, weight = 0;
 4345: 	char *name, *target = NULL;
 4346: 	struct mx_srv_record *new;
 4347: 	
 4348: 	comma = split(arg);
 4349: 	
 4350: 	if (!(name = canonicalise_opt(arg)))
 4351: 	  ret_err(_("bad SRV record"));
 4352: 	
 4353: 	if (comma)
 4354: 	  {
 4355: 	    arg = comma;
 4356: 	    comma = split(arg);
 4357: 	    if (!(target = canonicalise_opt(arg)))
 4358: 	      ret_err_free(_("bad SRV target"), name);
 4359: 		
 4360: 	    if (comma)
 4361: 	      {
 4362: 		arg = comma;
 4363: 		comma = split(arg);
 4364: 		if (!atoi_check16(arg, &port))
 4365:                   {
 4366:                     free(name);
 4367: 		    ret_err_free(_("invalid port number"), target);
 4368:                   }
 4369: 		
 4370: 		if (comma)
 4371: 		  {
 4372: 		    arg = comma;
 4373: 		    comma = split(arg);
 4374: 		    if (!atoi_check16(arg, &priority))
 4375:                       {
 4376:                         free(name);
 4377: 		        ret_err_free(_("invalid priority"), target);
 4378: 		      }
 4379: 		    if (comma && !atoi_check16(comma, &weight))
 4380:                       {
 4381:                         free(name);
 4382: 		        ret_err_free(_("invalid weight"), target);
 4383:                       }
 4384: 		  }
 4385: 	      }
 4386: 	  }
 4387: 	
 4388: 	new = opt_malloc(sizeof(struct mx_srv_record));
 4389: 	new->next = daemon->mxnames;
 4390: 	daemon->mxnames = new;
 4391: 	new->issrv = 1;
 4392: 	new->name = name;
 4393: 	new->target = target;
 4394: 	new->srvport = port;
 4395: 	new->priority = priority;
 4396: 	new->weight = weight;
 4397: 	break;
 4398:       }
 4399:       
 4400:     case LOPT_HOST_REC: /* --host-record */
 4401:       {
 4402: 	struct host_record *new;
 4403: 
 4404: 	if (!arg || !(comma = split(arg)))
 4405: 	  ret_err(_("Bad host-record"));
 4406: 	
 4407: 	new = opt_malloc(sizeof(struct host_record));
 4408: 	memset(new, 0, sizeof(struct host_record));
 4409: 	new->ttl = -1;
 4410: 	new->flags = 0;
 4411: 
 4412: 	while (arg)
 4413: 	  {
 4414: 	    union all_addr addr;
 4415: 	    char *dig;
 4416: 
 4417: 	    for (dig = arg; *dig != 0; dig++)
 4418: 	      if (*dig < '0' || *dig > '9')
 4419: 		break;
 4420: 	    if (*dig == 0)
 4421: 	      new->ttl = atoi(arg);
 4422: 	    else if (inet_pton(AF_INET, arg, &addr.addr4))
 4423: 	      {
 4424: 		new->addr = addr.addr4;
 4425: 		new->flags |= HR_4;
 4426: 	      }
 4427: 	    else if (inet_pton(AF_INET6, arg, &addr.addr6))
 4428: 	      {
 4429: 		new->addr6 = addr.addr6;
 4430: 		new->flags |= HR_6;
 4431: 	      }
 4432: 	    else
 4433: 	      {
 4434: 		int nomem;
 4435: 		char *canon = canonicalise(arg, &nomem);
 4436: 		struct name_list *nl;
 4437: 		if (!canon)
 4438:                   {
 4439: 		    struct name_list *tmp = new->names, *next;
 4440: 		    for (tmp = new->names; tmp; tmp = next)
 4441: 		      {
 4442: 			next = tmp->next;
 4443: 			free(tmp);
 4444: 		      }
 4445: 		    ret_err_free(_("Bad name in host-record"), new);
 4446:                   }
 4447: 
 4448: 		nl = opt_malloc(sizeof(struct name_list));
 4449: 		nl->name = canon;
 4450: 		/* keep order, so that PTR record goes to first name */
 4451: 		nl->next = NULL;
 4452: 		if (!new->names)
 4453: 		  new->names = nl;
 4454: 		else
 4455: 		  { 
 4456: 		    struct name_list *tmp;
 4457: 		    for (tmp = new->names; tmp->next; tmp = tmp->next);
 4458: 		    tmp->next = nl;
 4459: 		  }
 4460: 	      }
 4461: 	    
 4462: 	    arg = comma;
 4463: 	    comma = split(arg);
 4464: 	  }
 4465: 
 4466: 	/* Keep list order */
 4467: 	if (!daemon->host_records_tail)
 4468: 	  daemon->host_records = new;
 4469: 	else
 4470: 	  daemon->host_records_tail->next = new;
 4471: 	new->next = NULL;
 4472: 	daemon->host_records_tail = new;
 4473: 	break;
 4474:       }
 4475: 
 4476: #ifdef HAVE_DNSSEC
 4477:     case LOPT_DNSSEC_STAMP: /* --dnssec-timestamp */
 4478:       daemon->timestamp_file = opt_string_alloc(arg); 
 4479:       break;
 4480: 
 4481:     case LOPT_DNSSEC_CHECK: /* --dnssec-check-unsigned */
 4482:       if (arg)
 4483: 	{
 4484: 	  if (strcmp(arg, "no") == 0)
 4485: 	    set_option_bool(OPT_DNSSEC_IGN_NS);
 4486: 	  else
 4487: 	    ret_err(_("bad value for dnssec-check-unsigned"));
 4488: 	}
 4489:       break;
 4490:       
 4491:     case LOPT_TRUST_ANCHOR: /* --trust-anchor */
 4492:       {
 4493: 	struct ds_config *new = opt_malloc(sizeof(struct ds_config));
 4494:       	char *cp, *cp1, *keyhex, *digest, *algo = NULL;
 4495: 	int len;
 4496: 	
 4497: 	new->class = C_IN;
 4498: 	new->name = NULL;
 4499: 
 4500: 	if ((comma = split(arg)) && (algo = split(comma)))
 4501: 	  {
 4502: 	    int class = 0;
 4503: 	    if (strcmp(comma, "IN") == 0)
 4504: 	      class = C_IN;
 4505: 	    else if (strcmp(comma, "CH") == 0)
 4506: 	      class = C_CHAOS;
 4507: 	    else if (strcmp(comma, "HS") == 0)
 4508: 	      class = C_HESIOD;
 4509: 	    
 4510: 	    if (class != 0)
 4511: 	      {
 4512: 		new->class = class;
 4513: 		comma = algo;
 4514: 		algo = split(comma);
 4515: 	      }
 4516: 	  }
 4517: 		  
 4518:        	if (!comma || !algo || !(digest = split(algo)) || !(keyhex = split(digest)) ||
 4519: 	    !atoi_check16(comma, &new->keytag) || 
 4520: 	    !atoi_check8(algo, &new->algo) ||
 4521: 	    !atoi_check8(digest, &new->digest_type) ||
 4522: 	    !(new->name = canonicalise_opt(arg)))
 4523: 	  ret_err_free(_("bad trust anchor"), new);
 4524: 	    
 4525: 	/* Upper bound on length */
 4526: 	len = (2*strlen(keyhex))+1;
 4527: 	new->digest = opt_malloc(len);
 4528: 	unhide_metas(keyhex);
 4529: 	/* 4034: "Whitespace is allowed within digits" */
 4530: 	for (cp = keyhex; *cp; )
 4531: 	  if (isspace(*cp))
 4532: 	    for (cp1 = cp; *cp1; cp1++)
 4533: 	      *cp1 = *(cp1+1);
 4534: 	  else
 4535: 	    cp++;
 4536: 	if ((new->digestlen = parse_hex(keyhex, (unsigned char *)new->digest, len, NULL, NULL)) == -1)
 4537: 	  {
 4538: 	    free(new->name);
 4539: 	    ret_err_free(_("bad HEX in trust anchor"), new);
 4540: 	  }
 4541: 	
 4542: 	new->next = daemon->ds;
 4543: 	daemon->ds = new;
 4544: 	
 4545: 	break;
 4546:       }
 4547: #endif
 4548: 		
 4549:     default:
 4550:       ret_err(_("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"));
 4551:       
 4552:     }
 4553:   
 4554:   return 1;
 4555: }
 4556: 
 4557: static void read_file(char *file, FILE *f, int hard_opt)	
 4558: {
 4559:   volatile int lineno = 0;
 4560:   char *buff = daemon->namebuff;
 4561:   
 4562:   while (fgets(buff, MAXDNAME, f))
 4563:     {
 4564:       int white, i;
 4565:       volatile int option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt;
 4566:       char *errmess, *p, *arg, *start;
 4567:       size_t len;
 4568: 
 4569:       /* Memory allocation failure longjmps here if mem_recover == 1 */ 
 4570:       if (option != 0 || hard_opt == LOPT_REV_SERV)
 4571: 	{
 4572: 	  if (setjmp(mem_jmp))
 4573: 	    continue;
 4574: 	  mem_recover = 1;
 4575: 	}
 4576:       
 4577:       arg = NULL;
 4578:       lineno++;
 4579:       errmess = NULL;
 4580:       
 4581:       /* Implement quotes, inside quotes we allow \\ \" \n and \t 
 4582: 	 metacharacters get hidden also strip comments */
 4583:       for (white = 1, p = buff; *p; p++)
 4584: 	{
 4585: 	  if (*p == '"')
 4586: 	    {
 4587: 	      memmove(p, p+1, strlen(p+1)+1);
 4588: 
 4589: 	      for(; *p && *p != '"'; p++)
 4590: 		{
 4591: 		  if (*p == '\\' && strchr("\"tnebr\\", p[1]))
 4592: 		    {
 4593: 		      if (p[1] == 't')
 4594: 			p[1] = '\t';
 4595: 		      else if (p[1] == 'n')
 4596: 			p[1] = '\n';
 4597: 		      else if (p[1] == 'b')
 4598: 			p[1] = '\b';
 4599: 		      else if (p[1] == 'r')
 4600: 			p[1] = '\r';
 4601: 		      else if (p[1] == 'e') /* escape */
 4602: 			p[1] = '\033';
 4603: 		      memmove(p, p+1, strlen(p+1)+1);
 4604: 		    }
 4605: 		  *p = hide_meta(*p);
 4606: 		}
 4607: 
 4608: 	      if (*p == 0) 
 4609: 		{
 4610: 		  errmess = _("missing \"");
 4611: 		  goto oops; 
 4612: 		}
 4613: 
 4614: 	      memmove(p, p+1, strlen(p+1)+1);
 4615: 	    }
 4616: 
 4617: 	  if (isspace(*p))
 4618: 	    {
 4619: 	      *p = ' ';
 4620: 	      white = 1;
 4621: 	    }
 4622: 	  else 
 4623: 	    {
 4624: 	      if (white && *p == '#')
 4625: 		{ 
 4626: 		  *p = 0;
 4627: 		  break;
 4628: 		}
 4629: 	      white = 0;
 4630: 	    } 
 4631: 	}
 4632: 
 4633:       
 4634:       /* strip leading spaces */
 4635:       for (start = buff; *start && *start == ' '; start++);
 4636:       
 4637:       /* strip trailing spaces */
 4638:       for (len = strlen(start); (len != 0) && (start[len-1] == ' '); len--);
 4639:       
 4640:       if (len == 0)
 4641: 	continue; 
 4642:       else
 4643: 	start[len] = 0;
 4644:       
 4645:       if (option != 0)
 4646: 	arg = start;
 4647:       else if ((p=strchr(start, '=')))
 4648: 	{
 4649: 	  /* allow spaces around "=" */
 4650: 	  for (arg = p+1; *arg == ' '; arg++);
 4651: 	  for (; p >= start && (*p == ' ' || *p == '='); p--)
 4652: 	    *p = 0;
 4653: 	}
 4654:       else
 4655: 	arg = NULL;
 4656: 
 4657:       if (option == 0)
 4658: 	{
 4659: 	  for (option = 0, i = 0; opts[i].name; i++) 
 4660: 	    if (strcmp(opts[i].name, start) == 0)
 4661: 	      {
 4662: 		option = opts[i].val;
 4663: 		break;
 4664: 	      }
 4665: 	  
 4666: 	  if (!option)
 4667: 	    errmess = _("bad option");
 4668: 	  else if (opts[i].has_arg == 0 && arg)
 4669: 	    errmess = _("extraneous parameter");
 4670: 	  else if (opts[i].has_arg == 1 && !arg)
 4671: 	    errmess = _("missing parameter");
 4672: 	  else if (hard_opt == LOPT_REV_SERV && option != 'S' && option != LOPT_REV_SERV)
 4673: 	    errmess = _("illegal option");
 4674: 	}
 4675: 
 4676:     oops:
 4677:       if (errmess)
 4678: 	strcpy(daemon->namebuff, errmess);
 4679: 	  
 4680:       if (errmess || !one_opt(option, arg, daemon->namebuff, _("error"), 0, hard_opt == LOPT_REV_SERV))
 4681: 	{
 4682: 	  sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file);
 4683: 	  if (hard_opt != 0)
 4684: 	    my_syslog(LOG_ERR, "%s", daemon->namebuff);
 4685: 	  else
 4686: 	    die("%s", daemon->namebuff, EC_BADCONF);
 4687: 	}
 4688:     }
 4689: 
 4690:   mem_recover = 0;
 4691:   fclose(f);
 4692: }
 4693: 
 4694: #if defined(HAVE_DHCP) && defined(HAVE_INOTIFY)
 4695: int option_read_dynfile(char *file, int flags)
 4696: {
 4697:   my_syslog(MS_DHCP | LOG_INFO, _("read %s"), file);
 4698:   
 4699:   if (flags & AH_DHCP_HST)
 4700:     return one_file(file, LOPT_BANK);
 4701:   else if (flags & AH_DHCP_OPT)
 4702:     return one_file(file, LOPT_OPTS);
 4703:   
 4704:   return 0;
 4705: }
 4706: #endif
 4707: 
 4708: static int one_file(char *file, int hard_opt)
 4709: {
 4710:   FILE *f;
 4711:   int nofile_ok = 0;
 4712:   static int read_stdin = 0;
 4713:   static struct fileread {
 4714:     dev_t dev;
 4715:     ino_t ino;
 4716:     struct fileread *next;
 4717:   } *filesread = NULL;
 4718:   
 4719:   if (hard_opt == '7')
 4720:     {
 4721:       /* default conf-file reading */
 4722:       hard_opt = 0;
 4723:       nofile_ok = 1;
 4724:     }
 4725: 
 4726:   if (hard_opt == 0 && strcmp(file, "-") == 0)
 4727:     {
 4728:       if (read_stdin == 1)
 4729: 	return 1;
 4730:       read_stdin = 1;
 4731:       file = "stdin";
 4732:       f = stdin;
 4733:     }
 4734:   else
 4735:     {
 4736:       /* ignore repeated files. */
 4737:       struct stat statbuf;
 4738:     
 4739:       if (hard_opt == 0 && stat(file, &statbuf) == 0)
 4740: 	{
 4741: 	  struct fileread *r;
 4742: 	  
 4743: 	  for (r = filesread; r; r = r->next)
 4744: 	    if (r->dev == statbuf.st_dev && r->ino == statbuf.st_ino)
 4745: 	      return 1;
 4746: 	  
 4747: 	  r = safe_malloc(sizeof(struct fileread));
 4748: 	  r->next = filesread;
 4749: 	  filesread = r;
 4750: 	  r->dev = statbuf.st_dev;
 4751: 	  r->ino = statbuf.st_ino;
 4752: 	}
 4753:       
 4754:       if (!(f = fopen(file, "r")))
 4755: 	{   
 4756: 	  if (errno == ENOENT && nofile_ok)
 4757: 	    return 1; /* No conffile, all done. */
 4758: 	  else
 4759: 	    {
 4760: 	      char *str = _("cannot read %s: %s");
 4761: 	      if (hard_opt != 0)
 4762: 		{
 4763: 		  my_syslog(LOG_ERR, str, file, strerror(errno));
 4764: 		  return 0;
 4765: 		}
 4766: 	      else
 4767: 		die(str, file, EC_FILE);
 4768: 	    }
 4769: 	} 
 4770:     }
 4771:   
 4772:   read_file(file, f, hard_opt);
 4773:   return 1;
 4774: }
 4775: 
 4776: /* expand any name which is a directory */
 4777: struct hostsfile *expand_filelist(struct hostsfile *list)
 4778: {
 4779:   unsigned int i;
 4780:   struct hostsfile *ah;
 4781: 
 4782:   /* find largest used index */
 4783:   for (i = SRC_AH, ah = list; ah; ah = ah->next)
 4784:     {
 4785:       if (i <= ah->index)
 4786: 	i = ah->index + 1;
 4787: 
 4788:       if (ah->flags & AH_DIR)
 4789: 	ah->flags |= AH_INACTIVE;
 4790:       else
 4791: 	ah->flags &= ~AH_INACTIVE;
 4792:     }
 4793: 
 4794:   for (ah = list; ah; ah = ah->next)
 4795:     if (!(ah->flags & AH_INACTIVE))
 4796:       {
 4797: 	struct stat buf;
 4798: 	if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode))
 4799: 	  {
 4800: 	    DIR *dir_stream;
 4801: 	    struct dirent *ent;
 4802: 	    
 4803: 	    /* don't read this as a file */
 4804: 	    ah->flags |= AH_INACTIVE;
 4805: 	    
 4806: 	    if (!(dir_stream = opendir(ah->fname)))
 4807: 	      my_syslog(LOG_ERR, _("cannot access directory %s: %s"), 
 4808: 			ah->fname, strerror(errno));
 4809: 	    else
 4810: 	      {
 4811: 		while ((ent = readdir(dir_stream)))
 4812: 		  {
 4813: 		    size_t lendir = strlen(ah->fname);
 4814: 		    size_t lenfile = strlen(ent->d_name);
 4815: 		    struct hostsfile *ah1;
 4816: 		    char *path;
 4817: 		    
 4818: 		    /* ignore emacs backups and dotfiles */
 4819: 		    if (lenfile == 0 || 
 4820: 			ent->d_name[lenfile - 1] == '~' ||
 4821: 			(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
 4822: 			ent->d_name[0] == '.')
 4823: 		      continue;
 4824: 		    
 4825: 		    /* see if we have an existing record.
 4826: 		       dir is ah->fname 
 4827: 		       file is ent->d_name
 4828: 		       path to match is ah1->fname */
 4829: 		    
 4830: 		    for (ah1 = list; ah1; ah1 = ah1->next)
 4831: 		      {
 4832: 			if (lendir < strlen(ah1->fname) &&
 4833: 			    strstr(ah1->fname, ah->fname) == ah1->fname &&
 4834: 			    ah1->fname[lendir] == '/' &&
 4835: 			    strcmp(ah1->fname + lendir + 1, ent->d_name) == 0)
 4836: 			  {
 4837: 			    ah1->flags &= ~AH_INACTIVE;
 4838: 			    break;
 4839: 			  }
 4840: 		      }
 4841: 		    
 4842: 		    /* make new record */
 4843: 		    if (!ah1)
 4844: 		      {
 4845: 			if (!(ah1 = whine_malloc(sizeof(struct hostsfile))))
 4846: 			  continue;
 4847: 			
 4848: 			if (!(path = whine_malloc(lendir + lenfile + 2)))
 4849: 			  {
 4850: 			    free(ah1);
 4851: 			    continue;
 4852: 			  }
 4853: 		      	
 4854: 			strcpy(path, ah->fname);
 4855: 			strcat(path, "/");
 4856: 			strcat(path, ent->d_name);
 4857: 			ah1->fname = path;
 4858: 			ah1->index = i++;
 4859: 			ah1->flags = AH_DIR;
 4860: 			ah1->next = list;
 4861: 			list = ah1;
 4862: 		      }
 4863: 		    
 4864: 		    /* inactivate record if not regular file */
 4865: 		    if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode))
 4866: 		      ah1->flags |= AH_INACTIVE; 
 4867: 		    
 4868: 		  }
 4869: 		closedir(dir_stream);
 4870: 	      }
 4871: 	  }
 4872:       }
 4873:   
 4874:   return list;
 4875: }
 4876: 
 4877: void read_servers_file(void)
 4878: {
 4879:   FILE *f;
 4880: 
 4881:   if (!(f = fopen(daemon->servers_file, "r")))
 4882:     {
 4883:        my_syslog(LOG_ERR, _("cannot read %s: %s"), daemon->servers_file, strerror(errno));
 4884:        return;
 4885:     }
 4886:   
 4887:   mark_servers(SERV_FROM_FILE);
 4888:   cleanup_servers();
 4889:   
 4890:   read_file(daemon->servers_file, f, LOPT_REV_SERV);
 4891: }
 4892:  
 4893: 
 4894: #ifdef HAVE_DHCP
 4895: static void clear_dynamic_conf(void)
 4896: {
 4897:   struct dhcp_config *configs, *cp, **up;
 4898:   
 4899:   /* remove existing... */
 4900:   for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
 4901:     {
 4902:       cp = configs->next;
 4903:       
 4904:       if (configs->flags & CONFIG_BANK)
 4905: 	{
 4906: 	  struct hwaddr_config *mac, *tmp;
 4907: 	  struct dhcp_netid_list *list, *tmplist;
 4908: 	  
 4909: 	  for (mac = configs->hwaddr; mac; mac = tmp)
 4910: 	    {
 4911: 	      tmp = mac->next;
 4912: 	      free(mac);
 4913: 	    }
 4914: 	  
 4915: 	  if (configs->flags & CONFIG_CLID)
 4916: 	    free(configs->clid);
 4917: 	  
 4918: 	  for (list = configs->netid; list; list = tmplist)
 4919: 	    {
 4920: 	      free(list->list);
 4921: 	      tmplist = list->next;
 4922: 	      free(list);
 4923: 	    }
 4924: 	  
 4925: 	  if (configs->flags & CONFIG_NAME)
 4926: 	    free(configs->hostname);
 4927: 	  
 4928: 	  *up = configs->next;
 4929: 	  free(configs);
 4930: 	}
 4931:       else
 4932: 	up = &configs->next;
 4933:     }
 4934: }
 4935: 
 4936: static void clear_dynamic_opt(void)
 4937: {
 4938:   struct dhcp_opt *opts, *cp, **up;
 4939:   struct dhcp_netid *id, *next;
 4940: 
 4941:   for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
 4942:     {
 4943:       cp = opts->next;
 4944:       
 4945:       if (opts->flags & DHOPT_BANK)
 4946: 	{
 4947: 	  if ((opts->flags & DHOPT_VENDOR))
 4948: 	    free(opts->u.vendor_class);
 4949: 	  free(opts->val);
 4950: 	  for (id = opts->netid; id; id = next)
 4951: 	    {
 4952: 	      next = id->next;
 4953: 	      free(id->net);
 4954: 	      free(id);
 4955: 	    }
 4956: 	  *up = opts->next;
 4957: 	  free(opts);
 4958: 	}
 4959:       else
 4960: 	up = &opts->next;
 4961:     }
 4962: }
 4963: 
 4964: void reread_dhcp(void)
 4965: {
 4966:    struct hostsfile *hf;
 4967: 
 4968:    /* Do these even if there is no daemon->dhcp_hosts_file or
 4969:       daemon->dhcp_opts_file since entries may have been created by the
 4970:       inotify dynamic file reading system. */
 4971:    
 4972:    clear_dynamic_conf();
 4973:    clear_dynamic_opt();
 4974: 
 4975:    if (daemon->dhcp_hosts_file)
 4976:     {
 4977:       daemon->dhcp_hosts_file = expand_filelist(daemon->dhcp_hosts_file);
 4978:       for (hf = daemon->dhcp_hosts_file; hf; hf = hf->next)
 4979: 	if (!(hf->flags & AH_INACTIVE))
 4980: 	  {
 4981: 	    if (one_file(hf->fname, LOPT_BANK))  
 4982: 	      my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
 4983: 	  }
 4984:     }
 4985: 
 4986:   if (daemon->dhcp_opts_file)
 4987:     {
 4988:       daemon->dhcp_opts_file = expand_filelist(daemon->dhcp_opts_file);
 4989:       for (hf = daemon->dhcp_opts_file; hf; hf = hf->next)
 4990: 	if (!(hf->flags & AH_INACTIVE))
 4991: 	  {
 4992: 	    if (one_file(hf->fname, LOPT_OPTS))  
 4993: 	      my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
 4994: 	  }
 4995:     }
 4996: 
 4997: #  ifdef HAVE_INOTIFY
 4998:   /* Setup notify and read pre-existing files. */
 4999:   set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
 5000: #  endif
 5001: }
 5002: #endif
 5003: 
 5004: void read_opts(int argc, char **argv, char *compile_opts)
 5005: {
 5006:   size_t argbuf_size = MAXDNAME;
 5007:   char *argbuf = opt_malloc(argbuf_size);
 5008:   char *buff = opt_malloc(MAXDNAME);
 5009:   int option, testmode = 0;
 5010:   char *arg, *conffile = NULL;
 5011:       
 5012:   opterr = 0;
 5013: 
 5014:   daemon = opt_malloc(sizeof(struct daemon));
 5015:   memset(daemon, 0, sizeof(struct daemon));
 5016:   daemon->namebuff = buff;
 5017: 
 5018:   /* Set defaults - everything else is zero or NULL */
 5019:   daemon->cachesize = CACHESIZ;
 5020:   daemon->ftabsize = FTABSIZ;
 5021:   daemon->port = NAMESERVER_PORT;
 5022:   daemon->dhcp_client_port = DHCP_CLIENT_PORT;
 5023:   daemon->dhcp_server_port = DHCP_SERVER_PORT;
 5024:   daemon->default_resolv.is_default = 1;
 5025:   daemon->default_resolv.name = RESOLVFILE;
 5026:   daemon->resolv_files = &daemon->default_resolv;
 5027:   daemon->username = CHUSER;
 5028:   daemon->runfile =  RUNFILE;
 5029:   daemon->dhcp_max = MAXLEASES;
 5030:   daemon->tftp_max = TFTP_MAX_CONNECTIONS;
 5031:   daemon->edns_pktsz = EDNS_PKTSZ;
 5032:   daemon->log_fac = -1;
 5033:   daemon->auth_ttl = AUTH_TTL; 
 5034:   daemon->soa_refresh = SOA_REFRESH;
 5035:   daemon->soa_retry = SOA_RETRY;
 5036:   daemon->soa_expiry = SOA_EXPIRY;
 5037:   daemon->max_port = MAX_PORT;
 5038:   daemon->min_port = MIN_PORT;
 5039: 
 5040: #ifndef NO_ID
 5041:   add_txt("version.bind", "dnsmasq-" VERSION, 0 );
 5042:   add_txt("authors.bind", "Simon Kelley", 0);
 5043:   add_txt("copyright.bind", COPYRIGHT, 0);
 5044:   add_txt("cachesize.bind", NULL, TXT_STAT_CACHESIZE);
 5045:   add_txt("insertions.bind", NULL, TXT_STAT_INSERTS);
 5046:   add_txt("evictions.bind", NULL, TXT_STAT_EVICTIONS);
 5047:   add_txt("misses.bind", NULL, TXT_STAT_MISSES);
 5048:   add_txt("hits.bind", NULL, TXT_STAT_HITS);
 5049: #ifdef HAVE_AUTH
 5050:   add_txt("auth.bind", NULL, TXT_STAT_AUTH);
 5051: #endif
 5052:   add_txt("servers.bind", NULL, TXT_STAT_SERVERS);
 5053: #endif
 5054: 
 5055:   while (1) 
 5056:     {
 5057: #ifdef HAVE_GETOPT_LONG
 5058:       option = getopt_long(argc, argv, OPTSTRING, opts, NULL);
 5059: #else
 5060:       option = getopt(argc, argv, OPTSTRING);
 5061: #endif
 5062:       
 5063:       if (option == -1)
 5064: 	{
 5065: 	  for (; optind < argc; optind++)
 5066: 	    {
 5067: 	      unsigned char *c = (unsigned char *)argv[optind];
 5068: 	      for (; *c != 0; c++)
 5069: 		if (!isspace(*c))
 5070: 		  die(_("junk found in command line"), NULL, EC_BADCONF);
 5071: 	    }
 5072: 	  break;
 5073: 	}
 5074: 
 5075:       /* Copy optarg so that argv doesn't get changed */
 5076:       if (optarg)
 5077: 	{
 5078: 	  if (strlen(optarg) >= argbuf_size)
 5079: 	    {
 5080: 	      free(argbuf);
 5081: 	      argbuf_size = strlen(optarg) + 1;
 5082: 	      argbuf = opt_malloc(argbuf_size);
 5083: 	    }
 5084: 	  safe_strncpy(argbuf, optarg, argbuf_size);
 5085: 	  arg = argbuf;
 5086: 	}
 5087:       else
 5088: 	arg = NULL;
 5089:       
 5090:       /* command-line only stuff */
 5091:       if (option == LOPT_TEST)
 5092: 	testmode = 1;
 5093:       else if (option == 'w')
 5094: 	{
 5095: #ifdef HAVE_DHCP
 5096: 	  if (argc == 3 && strcmp(argv[2], "dhcp") == 0)
 5097: 	    display_opts();
 5098: #ifdef HAVE_DHCP6
 5099: 	  else if (argc == 3 && strcmp(argv[2], "dhcp6") == 0)
 5100: 	    display_opts6();
 5101: #endif
 5102: 	  else
 5103: #endif
 5104: 	    do_usage();
 5105: 
 5106: 	  exit(0);
 5107: 	}
 5108:       else if (option == 'v')
 5109: 	{
 5110: 	  printf(_("Dnsmasq version %s  %s\n"), VERSION, COPYRIGHT);
 5111: 	  printf(_("Compile time options: %s\n\n"), compile_opts); 
 5112: 	  printf(_("This software comes with ABSOLUTELY NO WARRANTY.\n"));
 5113: 	  printf(_("Dnsmasq is free software, and you are welcome to redistribute it\n"));
 5114: 	  printf(_("under the terms of the GNU General Public License, version 2 or 3.\n"));
 5115:           exit(0);
 5116:         }
 5117:       else if (option == 'C')
 5118: 	{
 5119:           if (!conffile)
 5120: 	    conffile = opt_string_alloc(arg);
 5121: 	  else
 5122: 	    {
 5123: 	      char *extra = opt_string_alloc(arg);
 5124: 	      one_file(extra, 0);
 5125: 	      free(extra);
 5126: 	    }
 5127: 	}
 5128:       else
 5129: 	{
 5130: #ifdef HAVE_GETOPT_LONG
 5131: 	  if (!one_opt(option, arg, daemon->namebuff, _("try --help"), 1, 0))
 5132: #else 
 5133: 	    if (!one_opt(option, arg, daemon->namebuff, _("try -w"), 1, 0)) 
 5134: #endif  
 5135: 	    die(_("bad command line options: %s"), daemon->namebuff, EC_BADCONF);
 5136: 	}
 5137:     }
 5138: 
 5139:   free(argbuf);
 5140: 
 5141:   if (conffile)
 5142:     {
 5143:       one_file(conffile, 0);
 5144:       free(conffile);
 5145:     }
 5146:   else
 5147:     one_file(CONFFILE, '7');
 5148: 
 5149:   /* port might not be known when the address is parsed - fill in here */
 5150:   if (daemon->servers)
 5151:     {
 5152:       struct server *tmp;
 5153:       for (tmp = daemon->servers; tmp; tmp = tmp->next)
 5154: 	if (!(tmp->flags & SERV_HAS_SOURCE))
 5155: 	  {
 5156: 	    if (tmp->source_addr.sa.sa_family == AF_INET)
 5157: 	      tmp->source_addr.in.sin_port = htons(daemon->query_port);
 5158: 	    else if (tmp->source_addr.sa.sa_family == AF_INET6)
 5159: 	      tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
 5160: 	  }
 5161:     } 
 5162:   
 5163:   if (daemon->host_records)
 5164:     {
 5165:       struct host_record *hr;
 5166:       
 5167:       for (hr = daemon->host_records; hr; hr = hr->next)
 5168: 	if (hr->ttl == -1)
 5169: 	  hr->ttl = daemon->local_ttl;
 5170:     }
 5171: 
 5172:   if (daemon->cnames)
 5173:     {
 5174:       struct cname *cn, *cn2, *cn3;
 5175: 
 5176: #define NOLOOP 1
 5177: #define TESTLOOP 2      
 5178: 
 5179:       /* Fill in TTL for CNAMES now we have local_ttl.
 5180: 	 Also prepare to do loop detection. */
 5181:       for (cn = daemon->cnames; cn; cn = cn->next)
 5182: 	{
 5183: 	  if (cn->ttl == -1)
 5184: 	    cn->ttl = daemon->local_ttl;
 5185: 	  cn->flag = 0;
 5186: 	  cn->targetp = NULL;
 5187: 	  for (cn2 = daemon->cnames; cn2; cn2 = cn2->next)
 5188: 	    if (hostname_isequal(cn->target, cn2->alias))
 5189: 	      {
 5190: 		cn->targetp = cn2;
 5191: 		break;
 5192: 	      }
 5193: 	}
 5194:       
 5195:       /* Find any CNAME loops.*/
 5196:       for (cn = daemon->cnames; cn; cn = cn->next)
 5197: 	{
 5198: 	  for (cn2 = cn->targetp; cn2; cn2 = cn2->targetp)
 5199: 	    {
 5200: 	      if (cn2->flag == NOLOOP)
 5201: 		break;
 5202: 	      
 5203: 	      if (cn2->flag == TESTLOOP)
 5204: 		die(_("CNAME loop involving %s"), cn->alias, EC_BADCONF);
 5205: 	      
 5206: 	      cn2->flag = TESTLOOP;
 5207: 	    }
 5208: 	  
 5209: 	  for (cn3 = cn->targetp; cn3 != cn2; cn3 = cn3->targetp)
 5210: 	    cn3->flag = NOLOOP;
 5211: 	}
 5212:     }
 5213: 
 5214:   if (daemon->if_addrs)
 5215:     {  
 5216:       struct iname *tmp;
 5217:       for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)
 5218: 	if (tmp->addr.sa.sa_family == AF_INET)
 5219: 	  tmp->addr.in.sin_port = htons(daemon->port);
 5220: 	else if (tmp->addr.sa.sa_family == AF_INET6)
 5221: 	  tmp->addr.in6.sin6_port = htons(daemon->port);
 5222:     }
 5223: 	
 5224:   /* create default, if not specified */
 5225:   if (daemon->authserver && !daemon->hostmaster)
 5226:     {
 5227:       strcpy(buff, "hostmaster.");
 5228:       strcat(buff, daemon->authserver);
 5229:       daemon->hostmaster = opt_string_alloc(buff);
 5230:     }
 5231: 
 5232:   if (!daemon->dhcp_pxe_vendors)
 5233:     {
 5234:       daemon->dhcp_pxe_vendors = opt_malloc(sizeof(struct dhcp_pxe_vendor));
 5235:       daemon->dhcp_pxe_vendors->data = opt_string_alloc(DHCP_PXE_DEF_VENDOR);
 5236:       daemon->dhcp_pxe_vendors->next = NULL;
 5237:     }
 5238:   
 5239:   /* only one of these need be specified: the other defaults to the host-name */
 5240:   if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
 5241:     {
 5242:       struct mx_srv_record *mx;
 5243:       
 5244:       if (gethostname(buff, MAXDNAME) == -1)
 5245: 	die(_("cannot get host-name: %s"), NULL, EC_MISC);
 5246:       
 5247:       for (mx = daemon->mxnames; mx; mx = mx->next)
 5248: 	if (!mx->issrv && hostname_isequal(mx->name, buff))
 5249: 	  break;
 5250:       
 5251:       if ((daemon->mxtarget || option_bool(OPT_LOCALMX)) && !mx)
 5252: 	{
 5253: 	  mx = opt_malloc(sizeof(struct mx_srv_record));
 5254: 	  mx->next = daemon->mxnames;
 5255: 	  mx->issrv = 0;
 5256: 	  mx->target = NULL;
 5257: 	  mx->name = opt_string_alloc(buff);
 5258: 	  daemon->mxnames = mx;
 5259: 	}
 5260:       
 5261:       if (!daemon->mxtarget)
 5262: 	daemon->mxtarget = opt_string_alloc(buff);
 5263: 
 5264:       for (mx = daemon->mxnames; mx; mx = mx->next)
 5265: 	if (!mx->issrv && !mx->target)
 5266: 	  mx->target = daemon->mxtarget;
 5267:     }
 5268: 
 5269:   if (!option_bool(OPT_NO_RESOLV) &&
 5270:       daemon->resolv_files && 
 5271:       daemon->resolv_files->next && 
 5272:       option_bool(OPT_NO_POLL))
 5273:     die(_("only one resolv.conf file allowed in no-poll mode."), NULL, EC_BADCONF);
 5274:   
 5275:   if (option_bool(OPT_RESOLV_DOMAIN))
 5276:     {
 5277:       char *line;
 5278:       FILE *f;
 5279: 
 5280:       if (option_bool(OPT_NO_RESOLV) ||
 5281: 	  !daemon->resolv_files || 
 5282: 	  (daemon->resolv_files)->next)
 5283: 	die(_("must have exactly one resolv.conf to read domain from."), NULL, EC_BADCONF);
 5284:       
 5285:       if (!(f = fopen((daemon->resolv_files)->name, "r")))
 5286: 	die(_("failed to read %s: %s"), (daemon->resolv_files)->name, EC_FILE);
 5287:       
 5288:       while ((line = fgets(buff, MAXDNAME, f)))
 5289: 	{
 5290: 	  char *token = strtok(line, " \t\n\r");
 5291: 	  
 5292: 	  if (!token || strcmp(token, "search") != 0)
 5293: 	    continue;
 5294: 	  
 5295: 	  if ((token = strtok(NULL, " \t\n\r")) &&  
 5296: 	      (daemon->domain_suffix = canonicalise_opt(token)))
 5297: 	    break;
 5298: 	}
 5299: 
 5300:       fclose(f);
 5301: 
 5302:       if (!daemon->domain_suffix)
 5303: 	die(_("no search directive found in %s"), (daemon->resolv_files)->name, EC_MISC);
 5304:     }
 5305: 
 5306:   if (daemon->domain_suffix)
 5307:     {
 5308:        /* add domain for any srv record without one. */
 5309:       struct mx_srv_record *srv;
 5310:       
 5311:       for (srv = daemon->mxnames; srv; srv = srv->next)
 5312: 	if (srv->issrv &&
 5313: 	    strchr(srv->name, '.') && 
 5314: 	    strchr(srv->name, '.') == strrchr(srv->name, '.'))
 5315: 	  {
 5316: 	    strcpy(buff, srv->name);
 5317: 	    strcat(buff, ".");
 5318: 	    strcat(buff, daemon->domain_suffix);
 5319: 	    free(srv->name);
 5320: 	    srv->name = opt_string_alloc(buff);
 5321: 	  }
 5322:     }
 5323:   else if (option_bool(OPT_DHCP_FQDN))
 5324:     die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
 5325: 
 5326:   /* If there's access-control config, then ignore --local-service, it's intended
 5327:      as a system default to keep otherwise unconfigured installations safe. */
 5328:   if (daemon->if_names || daemon->if_except || daemon->if_addrs || daemon->authserver)
 5329:     reset_option_bool(OPT_LOCAL_SERVICE); 
 5330: 
 5331:   if (testmode)
 5332:     {
 5333:       fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
 5334:       exit(0);
 5335:     }
 5336: }  

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