--- embedaddon/dnsmasq/src/option.c 2014/06/15 16:31:38 1.1.1.2 +++ embedaddon/dnsmasq/src/option.c 2016/11/02 09:57:01 1.1.1.3 @@ -1,4 +1,4 @@ -/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley +/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -146,7 +146,20 @@ struct myoption { #define LOPT_DNSSEC_CHECK 334 #define LOPT_LOCAL_SERVICE 335 #define LOPT_DNSSEC_TIME 336 - +#define LOPT_LOOP_DETECT 337 +#define LOPT_IGNORE_ADDR 338 +#define LOPT_MINCTTL 339 +#define LOPT_DHCP_INOTIFY 340 +#define LOPT_DHOPT_INOTIFY 341 +#define LOPT_HOST_INOTIFY 342 +#define LOPT_DNSSEC_STAMP 343 +#define LOPT_TFTP_NO_FAIL 344 +#define LOPT_MAXPORT 345 +#define LOPT_CPE_ID 346 +#define LOPT_SCRIPT_ARP 347 +#define LOPT_DHCPTTL 348 +#define LOPT_TFTP_MTU 349 + #ifdef HAVE_GETOPT_LONG static const struct option opts[] = #else @@ -158,7 +171,7 @@ static const struct myoption opts[] = { "no-poll", 0, 0, 'n' }, { "help", 0, 0, 'w' }, { "no-daemon", 0, 0, 'd' }, - { "log-queries", 0, 0, 'q' }, + { "log-queries", 2, 0, 'q' }, { "user", 2, 0, 'u' }, { "group", 2, 0, 'g' }, { "resolv-file", 2, 0, 'r' }, @@ -180,6 +193,7 @@ static const struct myoption opts[] = { "local-service", 0, 0, LOPT_LOCAL_SERVICE }, { "bogus-priv", 0, 0, 'b' }, { "bogus-nxdomain", 1, 0, 'B' }, + { "ignore-address", 1, 0, LOPT_IGNORE_ADDR }, { "selfmx", 0, 0, 'e' }, { "filterwin2k", 0, 0, 'f' }, { "pid-file", 2, 0, 'x' }, @@ -195,6 +209,7 @@ static const struct myoption opts[] = { "local-ttl", 1, 0, 'T' }, { "no-negcache", 0, 0, 'N' }, { "addn-hosts", 1, 0, 'H' }, + { "hostsdir", 1, 0, LOPT_HOST_INOTIFY }, { "query-port", 1, 0, 'Q' }, { "except-interface", 1, 0, 'I' }, { "no-dhcp-interface", 1, 0, '2' }, @@ -226,9 +241,11 @@ static const struct myoption opts[] = { "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES }, { "enable-tftp", 2, 0, LOPT_TFTP }, { "tftp-secure", 0, 0, LOPT_SECURE }, + { "tftp-no-fail", 0, 0, LOPT_TFTP_NO_FAIL }, { "tftp-unique-root", 0, 0, LOPT_APREF }, { "tftp-root", 1, 0, LOPT_PREFIX }, { "tftp-max", 1, 0, LOPT_TFTP_MAX }, + { "tftp-mtu", 1, 0, LOPT_TFTP_MTU }, { "tftp-lowercase", 0, 0, LOPT_TFTP_LC }, { "ptr-record", 1, 0, LOPT_PTR }, { "naptr-record", 1, 0, LOPT_NAPTR }, @@ -243,6 +260,8 @@ static const struct myoption opts[] = { "interface-name", 1, 0, LOPT_INTNAME }, { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST }, { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS }, + { "dhcp-hostsdir", 1, 0, LOPT_DHCP_INOTIFY }, + { "dhcp-optsdir", 1, 0, LOPT_DHOPT_INOTIFY }, { "dhcp-no-override", 0, 0, LOPT_OVERRIDE }, { "tftp-port-range", 1, 0, LOPT_TFTPPORTS }, { "stop-dns-rebind", 0, 0, LOPT_REBIND }, @@ -252,10 +271,12 @@ static const struct myoption opts[] = { "dhcp-broadcast", 2, 0, LOPT_BROADCAST }, { "neg-ttl", 1, 0, LOPT_NEGTTL }, { "max-ttl", 1, 0, LOPT_MAXTTL }, + { "min-cache-ttl", 1, 0, LOPT_MINCTTL }, { "max-cache-ttl", 1, 0, LOPT_MAXCTTL }, { "dhcp-alternate-port", 2, 0, LOPT_ALTPORT }, { "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR }, { "min-port", 1, 0, LOPT_MINPORT }, + { "max-port", 1, 0, LOPT_MAXPORT }, { "dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN }, { "cname", 1, 0, LOPT_CNAME }, { "pxe-prompt", 1, 0, LOPT_PXE_PROMT }, @@ -265,8 +286,9 @@ static const struct myoption opts[] = { "dhcp-proxy", 2, 0, LOPT_PROXY }, { "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES }, { "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND }, - { "add-mac", 0, 0, LOPT_ADD_MAC }, + { "add-mac", 2, 0, LOPT_ADD_MAC }, { "add-subnet", 2, 0, LOPT_ADD_SBNET }, + { "add-cpe-id", 1, 0 , LOPT_CPE_ID }, { "proxy-dnssec", 0, 0, LOPT_DNSSEC }, { "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR }, { "conntrack", 0, 0, LOPT_CONNTRACK }, @@ -289,6 +311,7 @@ static const struct myoption opts[] = { "dnssec-debug", 0, 0, LOPT_DNSSEC_DEBUG }, { "dnssec-check-unsigned", 0, 0, LOPT_DNSSEC_CHECK }, { "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME }, + { "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP }, #ifdef OPTION6_PREFIX_CLASS { "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS }, #endif @@ -297,6 +320,9 @@ static const struct myoption opts[] = { "quiet-dhcp", 0, 0, LOPT_QUIET_DHCP }, { "quiet-dhcp6", 0, 0, LOPT_QUIET_DHCP6 }, { "quiet-ra", 0, 0, LOPT_QUIET_RA }, + { "dns-loop-detect", 0, 0, LOPT_LOOP_DETECT }, + { "script-arp", 0, 0, LOPT_SCRIPT_ARP }, + { "dhcp-ttl", 1, 0 , LOPT_DHCPTTL }, { NULL, 0, 0, 0 } }; @@ -329,9 +355,12 @@ static struct { { 'G', ARG_DUP, "", gettext_noop("Set address or hostname for a specified machine."), NULL }, { LOPT_DHCP_HOST, ARG_DUP, "", gettext_noop("Read DHCP host specs from file."), NULL }, { LOPT_DHCP_OPTS, ARG_DUP, "", gettext_noop("Read DHCP option specs from file."), NULL }, + { LOPT_DHCP_INOTIFY, ARG_DUP, "", gettext_noop("Read DHCP host specs from a directory."), NULL }, + { LOPT_DHOPT_INOTIFY, ARG_DUP, "", gettext_noop("Read DHCP options from a directory."), NULL }, { LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL }, { 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE }, { 'H', ARG_DUP, "", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE }, + { LOPT_HOST_INOTIFY, ARG_DUP, "", gettext_noop("Read hosts files from a directory."), NULL }, { 'i', ARG_DUP, "", gettext_noop("Specify interface(s) to listen on."), NULL }, { 'I', ARG_DUP, "", gettext_noop("Specify interface(s) NOT to listen on.") , NULL }, { 'j', ARG_DUP, "set:,", gettext_noop("Map DHCP user class to tag."), NULL }, @@ -353,7 +382,7 @@ static struct { { LOPT_FORCE, ARG_DUP, "", gettext_noop("DHCP option sent even if the client does not request it."), NULL}, { 'p', ARG_ONE, "", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL }, { 'P', ARG_ONE, "", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" }, - { 'q', OPT_LOG, NULL, gettext_noop("Log DNS queries."), NULL }, + { 'q', ARG_DUP, NULL, gettext_noop("Log DNS queries."), NULL }, { 'Q', ARG_ONE, "", gettext_noop("Force the originating port for upstream DNS queries."), NULL }, { 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL }, { 'r', ARG_DUP, "", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE }, @@ -366,12 +395,14 @@ static struct { { 'T', ARG_ONE, "", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL }, { LOPT_NEGTTL, ARG_ONE, "", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL }, { LOPT_MAXTTL, ARG_ONE, "", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL }, + { LOPT_MAXCTTL, ARG_ONE, "", gettext_noop("Specify time-to-live ceiling for cache."), NULL }, + { LOPT_MINCTTL, ARG_ONE, "", gettext_noop("Specify time-to-live floor for cache."), NULL }, { 'u', ARG_ONE, "", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER }, { 'U', ARG_DUP, "set:,", gettext_noop("Map DHCP vendor class to tag."), NULL }, { 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL }, { 'V', ARG_DUP, ",,", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL }, { 'W', ARG_DUP, ",,...", gettext_noop("Specify a SRV record."), NULL }, - { 'w', 0, NULL, gettext_noop("Display this message. Use --help dhcp for known DHCP options."), NULL }, + { 'w', 0, NULL, gettext_noop("Display this message. Use --help dhcp or --help dhcp6 for known DHCP options."), NULL }, { 'x', ARG_ONE, "", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE }, { 'X', ARG_ONE, "", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" }, { 'y', OPT_LOCALISE, NULL, gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL }, @@ -389,6 +420,7 @@ static struct { { '6', ARG_ONE, "", gettext_noop("Shell script to run on DHCP lease creation and destruction."), NULL }, { LOPT_LUASCRIPT, ARG_DUP, "path", gettext_noop("Lua script to run on DHCP lease creation and destruction."), NULL }, { LOPT_SCRIPTUSR, ARG_ONE, "", gettext_noop("Run lease-change scripts as this user."), NULL }, + { LOPT_SCRIPT_ARP, OPT_SCRIPT_ARP, NULL, gettext_noop("Call dhcp-script with changes to local ARP table."), NULL }, { '7', ARG_DUP, "", gettext_noop("Read configuration from all the files in this directory."), NULL }, { '8', ARG_ONE, "|", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL }, { '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL }, @@ -400,7 +432,9 @@ static struct { { LOPT_PREFIX, ARG_DUP, "[,]", gettext_noop("Export files by TFTP only from the specified subtree."), NULL }, { LOPT_APREF, OPT_TFTP_APREF, NULL, gettext_noop("Add client IP address to tftp-root."), NULL }, { LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL }, + { LOPT_TFTP_NO_FAIL, OPT_TFTP_NO_FAIL, NULL, gettext_noop("Do not terminate the service if TFTP directories are inaccessible."), NULL }, { LOPT_TFTP_MAX, ARG_ONE, "", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" }, + { LOPT_TFTP_MTU, ARG_ONE, "", gettext_noop("Maximum MTU to use for TFTP transfers."), NULL }, { LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL }, { LOPT_TFTP_LC, OPT_TFTP_LC, NULL, gettext_noop("Convert TFTP filenames to lowercase"), NULL }, { LOPT_TFTPPORTS, ARG_ONE, ",", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL }, @@ -414,23 +448,25 @@ static struct { { LOPT_ALTPORT, ARG_ONE, "[=]", gettext_noop("Use alternative ports for DHCP."), NULL }, { LOPT_NAPTR, ARG_DUP, ",", gettext_noop("Specify NAPTR DNS record."), NULL }, { LOPT_MINPORT, ARG_ONE, "", gettext_noop("Specify lowest port available for DNS query transmission."), NULL }, + { LOPT_MAXPORT, ARG_ONE, "", gettext_noop("Specify highest port available for DNS query transmission."), NULL }, { LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL }, { LOPT_GEN_NAMES, ARG_DUP, "[=tag:]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL}, { LOPT_PROXY, ARG_DUP, "[=]...", gettext_noop("Use these DHCP relays as full proxies."), NULL }, { LOPT_RELAY, ARG_DUP, ",[,]", gettext_noop("Relay DHCP requests to a remote server"), NULL}, - { LOPT_CNAME, ARG_DUP, ",", gettext_noop("Specify alias name for LOCAL DNS name."), NULL }, + { LOPT_CNAME, ARG_DUP, ",[,]", gettext_noop("Specify alias name for LOCAL DNS name."), NULL }, { LOPT_PXE_PROMT, ARG_DUP, ",[]", gettext_noop("Prompt to send to PXE clients."), NULL }, { LOPT_PXE_SERV, ARG_DUP, "", gettext_noop("Boot service for PXE menu."), NULL }, { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL }, - { LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL }, - { LOPT_ADD_SBNET, ARG_ONE, "[,]", gettext_noop("Add requestor's IP subnet to forwarded DNS queries."), NULL }, + { LOPT_ADD_MAC, ARG_DUP, "[=base64|text]", gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL }, + { LOPT_ADD_SBNET, ARG_ONE, "[,]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL }, + { LOPT_CPE_ID, ARG_ONE, "", gettext_noop("Add client identification to forwarded DNS queries."), NULL }, { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL }, { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL }, { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL }, { LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow DHCP clients to do their own DDNS updates."), NULL }, { LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL }, { LOPT_DUID, ARG_ONE, ",", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL }, - { LOPT_HOST_REC, ARG_DUP, ",
", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL }, + { LOPT_HOST_REC, ARG_DUP, ",
[,]", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL }, { LOPT_RR, ARG_DUP, ",,[]", gettext_noop("Specify arbitrary DNS resource record"), NULL }, { LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL }, { LOPT_AUTHSERV, ARG_ONE, ",", gettext_noop("Export local names to global DNS"), NULL }, @@ -446,6 +482,7 @@ static struct { { LOPT_DNSSEC_DEBUG, OPT_DNSSEC_DEBUG, NULL, gettext_noop("Disable upstream checking for DNSSEC debugging."), NULL }, { LOPT_DNSSEC_CHECK, OPT_DNSSEC_NO_SIGN, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL }, { LOPT_DNSSEC_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL }, + { LOPT_DNSSEC_STAMP, ARG_ONE, "", gettext_noop("Timestamp file to verify system clock for DNSSEC"), NULL }, #ifdef OPTION6_PREFIX_CLASS { LOPT_PREF_CLSS, ARG_DUP, "set:tag,", gettext_noop("Specify DHCPv6 prefix class"), NULL }, #endif @@ -453,7 +490,10 @@ static struct { { LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL }, { LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL }, { LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL }, - { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks"), NULL }, + { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks."), NULL }, + { LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops."), NULL }, + { LOPT_IGNORE_ADDR, ARG_DUP, "", gettext_noop("Ignore DNS responses containing ipaddr."), NULL }, + { LOPT_DHCPTTL, ARG_ONE, "", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL }, { 0, 0, NULL, NULL, NULL } }; @@ -697,6 +737,20 @@ static void do_usage(void) #define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0) +static char *parse_mysockaddr(char *arg, union mysockaddr *addr) +{ + if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0) + addr->sa.sa_family = AF_INET; +#ifdef HAVE_IPV6 + else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0) + addr->sa.sa_family = AF_INET6; +#endif + else + return _("bad address"); + + return NULL; +} + char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags) { int source_port = 0, serv_port = NAMESERVER_PORT; @@ -1145,7 +1199,8 @@ static int parse_dhcp_opt(char *errstr, char *arg, int cp = comma; comma = split(cp); slash = split_chr(cp, '/'); - inet_pton(AF_INET, cp, &in); + if (!inet_pton(AF_INET, cp, &in)) + ret_err(_("bad IPv4 address")); if (!slash) { memcpy(op, &in, INADDRSZ); @@ -1462,7 +1517,7 @@ static int one_opt(int option, char *arg, char *errstr struct list { char *suffix; struct list *next; - } *ignore_suffix = NULL, *li; + } *ignore_suffix = NULL, *match_suffix = NULL, *li; comma = split(arg); if (!(directory = opt_string_alloc(arg))) @@ -1471,12 +1526,31 @@ static int one_opt(int option, char *arg, char *errstr for (arg = comma; arg; arg = comma) { comma = split(arg); - li = opt_malloc(sizeof(struct list)); - li->next = ignore_suffix; - ignore_suffix = li; - /* Have to copy: buffer is overwritten */ - li->suffix = opt_string_alloc(arg); - }; + if (strlen(arg) != 0) + { + li = opt_malloc(sizeof(struct list)); + if (*arg == '*') + { + /* "*" with no suffix is a no-op */ + if (arg[1] == 0) + free(li); + else + { + li->next = match_suffix; + match_suffix = li; + /* Have to copy: buffer is overwritten */ + li->suffix = opt_string_alloc(arg+1); + } + } + else + { + li->next = ignore_suffix; + ignore_suffix = li; + /* Have to copy: buffer is overwritten */ + li->suffix = opt_string_alloc(arg); + } + } + } if (!(dir_stream = opendir(directory))) die(_("cannot access directory %s: %s"), directory, EC_FILE); @@ -1493,6 +1567,20 @@ static int one_opt(int option, char *arg, char *errstr ent->d_name[0] == '.') continue; + if (match_suffix) + { + for (li = match_suffix; li; li = li->next) + { + /* check for required suffices */ + size_t ls = strlen(li->suffix); + if (len > ls && + strcmp(li->suffix, &ent->d_name[len - ls]) == 0) + break; + } + if (!li) + continue; + } + for (li = ignore_suffix; li; li = li->next) { /* check for proscribed suffices */ @@ -1528,7 +1616,12 @@ static int one_opt(int option, char *arg, char *errstr free(ignore_suffix->suffix); free(ignore_suffix); } - + for(; match_suffix; match_suffix = li) + { + li = match_suffix->next; + free(match_suffix->suffix); + free(match_suffix); + } break; } @@ -1536,10 +1629,46 @@ static int one_opt(int option, char *arg, char *errstr set_option_bool(OPT_CLIENT_SUBNET); if (arg) { + char *err, *end; comma = split(arg); - if (!atoi_check(arg, &daemon->addr4_netmask) || - (comma && !atoi_check(comma, &daemon->addr6_netmask))) - ret_err(gen_err); + + struct mysubnet* new = opt_malloc(sizeof(struct mysubnet)); + if ((end = split_chr(arg, '/'))) + { + /* has subnet+len */ + err = parse_mysockaddr(arg, &new->addr); + if (err) + ret_err(err); + if (!atoi_check(end, &new->mask)) + ret_err(gen_err); + new->addr_used = 1; + } + else if (!atoi_check(arg, &new->mask)) + ret_err(gen_err); + + daemon->add_subnet4 = new; + + if (comma) + { + new = opt_malloc(sizeof(struct mysubnet)); + if ((end = split_chr(comma, '/'))) + { + /* has subnet+len */ + err = parse_mysockaddr(comma, &new->addr); + if (err) + ret_err(err); + if (!atoi_check(end, &new->mask)) + ret_err(gen_err); + new->addr_used = 1; + } + else + { + if (!atoi_check(comma, &new->mask)) + ret_err(gen_err); + } + + daemon->add_subnet6 = new; + } } break; @@ -1667,9 +1796,12 @@ static int one_opt(int option, char *arg, char *errstr break; #endif /* HAVE_DHCP */ - case LOPT_DHCP_HOST: /* --dhcp-hostfile */ - case LOPT_DHCP_OPTS: /* --dhcp-optsfile */ - case 'H': /* --addn-hosts */ + case LOPT_DHCP_HOST: /* --dhcp-hostsfile */ + case LOPT_DHCP_OPTS: /* --dhcp-optsfile */ + case LOPT_DHCP_INOTIFY: /* --dhcp-hostsdir */ + case LOPT_DHOPT_INOTIFY: /* --dhcp-optsdir */ + case LOPT_HOST_INOTIFY: /* --hostsdir */ + case 'H': /* --addn-hosts */ { struct hostsfile *new = opt_malloc(sizeof(struct hostsfile)); static unsigned int hosts_index = SRC_AH; @@ -1691,6 +1823,18 @@ static int one_opt(int option, char *arg, char *errstr new->next = daemon->dhcp_opts_file; daemon->dhcp_opts_file = new; } + else + { + new->next = daemon->dynamic_dirs; + daemon->dynamic_dirs = new; + if (option == LOPT_DHCP_INOTIFY) + new->flags |= AH_DHCP_HST; + else if (option == LOPT_DHOPT_INOTIFY) + new->flags |= AH_DHCP_OPT; + else if (option == LOPT_HOST_INOTIFY) + new->flags |= AH_HOSTS; + } + break; } @@ -1847,11 +1991,7 @@ static int one_opt(int option, char *arg, char *errstr comma = split(arg); daemon->soa_retry = (u32)atoi(arg); if (comma) - { - arg = comma; - comma = split(arg); - daemon->soa_expiry = (u32)atoi(arg); - } + daemon->soa_expiry = (u32)atoi(comma); } } } @@ -1906,10 +2046,17 @@ static int one_opt(int option, char *arg, char *errstr else { /* generate the equivalent of - local=// local=/xxx.yyy.zzz.in-addr.arpa/ */ struct server *serv = add_rev4(new->start, msize); serv->flags |= SERV_NO_ADDR; + + /* local=// */ + serv = opt_malloc(sizeof(struct server)); + memset(serv, 0, sizeof(struct server)); + serv->domain = d; + serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR; + serv->next = daemon->servers; + daemon->servers = serv; } } } @@ -1943,10 +2090,17 @@ static int one_opt(int option, char *arg, char *errstr else { /* generate the equivalent of - local=// local=/xxx.yyy.zzz.ip6.arpa/ */ struct server *serv = add_rev6(&new->start6, msize); serv->flags |= SERV_NO_ADDR; + + /* local=// */ + serv = opt_malloc(sizeof(struct server)); + memset(serv, 0, sizeof(struct server)); + serv->domain = d; + serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR; + serv->next = daemon->servers; + daemon->servers = serv; } } } @@ -2009,6 +2163,26 @@ static int one_opt(int option, char *arg, char *errstr } break; + case LOPT_CPE_ID: /* --add-dns-client */ + if (arg) + daemon->dns_client_id = opt_string_alloc(arg); + break; + + case LOPT_ADD_MAC: /* --add-mac */ + if (!arg) + set_option_bool(OPT_ADD_MAC); + else + { + unhide_metas(arg); + if (strcmp(arg, "base64") == 0) + set_option_bool(OPT_MAC_B64); + else if (strcmp(arg, "text") == 0) + set_option_bool(OPT_MAC_HEX); + else + ret_err(gen_err); + } + break; + case 'u': /* --user */ daemon->username = opt_string_alloc(arg); break; @@ -2070,14 +2244,23 @@ static int one_opt(int option, char *arg, char *errstr break; case 'B': /* --bogus-nxdomain */ - { + case LOPT_IGNORE_ADDR: /* --ignore-address */ + { struct in_addr addr; unhide_metas(arg); if (arg && (inet_pton(AF_INET, arg, &addr) > 0)) { struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr)); - baddr->next = daemon->bogus_addr; - daemon->bogus_addr = baddr; + if (option == 'B') + { + baddr->next = daemon->bogus_addr; + daemon->bogus_addr = baddr; + } + else + { + baddr->next = daemon->ignore_addr; + daemon->ignore_addr = baddr; + } baddr->addr = addr; } else @@ -2171,6 +2354,9 @@ static int one_opt(int option, char *arg, char *errstr { newlist = opt_malloc(sizeof(struct server)); memset(newlist, 0, sizeof(struct server)); +#ifdef HAVE_LOOP + newlist->uid = rand32(); +#endif } if (servers_only && option == 'S') @@ -2189,8 +2375,6 @@ static int one_opt(int option, char *arg, char *errstr { if (!(newlist->flags & SERV_NO_REBIND)) newlist->flags |= SERV_NO_ADDR; /* no server */ - if (newlist->flags & SERV_LITERAL_ADDRESS) - ret_err(gen_err); } else if (strcmp(arg, "#") == 0) @@ -2352,11 +2536,22 @@ static int one_opt(int option, char *arg, char *errstr ret_err(gen_err); break; + case LOPT_MAXPORT: /* --max-port */ + if (!atoi_check16(arg, &daemon->max_port)) + ret_err(gen_err); + break; + case '0': /* --dns-forward-max */ if (!atoi_check(arg, &daemon->ftabsize)) ret_err(gen_err); break; + case 'q': /* --log-queries */ + set_option_bool(OPT_LOG); + if (arg && strcmp(arg, "extra") == 0) + set_option_bool(OPT_EXTRALOG); + break; + case LOPT_MAX_LOGS: /* --log-async */ daemon->max_logs = LOG_MAX; /* default */ if (arg && !atoi_check(arg, &daemon->max_logs)) @@ -2386,8 +2581,10 @@ static int one_opt(int option, char *arg, char *errstr case 'T': /* --local-ttl */ case LOPT_NEGTTL: /* --neg-ttl */ case LOPT_MAXTTL: /* --max-ttl */ + case LOPT_MINCTTL: /* --min-cache-ttl */ case LOPT_MAXCTTL: /* --max-cache-ttl */ case LOPT_AUTHTTL: /* --auth-ttl */ + case LOPT_DHCPTTL: /* --dhcp-ttl */ { int ttl; if (!atoi_check(arg, &ttl)) @@ -2396,10 +2593,21 @@ static int one_opt(int option, char *arg, char *errstr daemon->neg_ttl = (unsigned long)ttl; else if (option == LOPT_MAXTTL) daemon->max_ttl = (unsigned long)ttl; + else if (option == LOPT_MINCTTL) + { + if (ttl > TTL_FLOOR_LIMIT) + ttl = TTL_FLOOR_LIMIT; + daemon->min_cache_ttl = (unsigned long)ttl; + } else if (option == LOPT_MAXCTTL) daemon->max_cache_ttl = (unsigned long)ttl; else if (option == LOPT_AUTHTTL) daemon->auth_ttl = (unsigned long)ttl; + else if (option == LOPT_DHCPTTL) + { + daemon->dhcp_ttl = (unsigned long)ttl; + daemon->use_dhcp_ttl = 1; + } else daemon->local_ttl = (unsigned long)ttl; break; @@ -2418,6 +2626,11 @@ static int one_opt(int option, char *arg, char *errstr ret_err(gen_err); break; + case LOPT_TFTP_MTU: /* --tftp-mtu */ + if (!atoi_check(arg, &daemon->tftp_mtu)) + ret_err(gen_err); + break; + case LOPT_PREFIX: /* --tftp-prefix */ comma = split(arg); if (comma) @@ -2560,13 +2773,14 @@ static int one_opt(int option, char *arg, char *errstr leasepos = 3; if (!is_same_net(new->start, new->end, new->netmask)) ret_err(_("inconsistent DHCP range")); - } + - if (k >= 4 && strchr(a[3], '.') && - (inet_pton(AF_INET, a[3], &new->broadcast) > 0)) - { - new->flags |= CONTEXT_BRDCAST; - leasepos = 4; + if (k >= 4 && strchr(a[3], '.') && + (inet_pton(AF_INET, a[3], &new->broadcast) > 0)) + { + new->flags |= CONTEXT_BRDCAST; + leasepos = 4; + } } } #ifdef HAVE_DHCP6 @@ -2583,11 +2797,15 @@ static int one_opt(int option, char *arg, char *errstr if (strcmp(a[leasepos], "static") == 0) new->flags |= CONTEXT_STATIC | CONTEXT_DHCP; else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 ) - new->flags |= CONTEXT_RA_ONLY | CONTEXT_RA; + new->flags |= CONTEXT_RA; else if (strcmp(a[leasepos], "ra-names") == 0) new->flags |= CONTEXT_RA_NAME | CONTEXT_RA; + else if (strcmp(a[leasepos], "ra-advrouter") == 0) + new->flags |= CONTEXT_RA_ROUTER | CONTEXT_RA; else if (strcmp(a[leasepos], "ra-stateless") == 0) new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA; + else if (strcmp(a[leasepos], "off-link") == 0) + new->flags |= CONTEXT_RA_OFF_LINK; else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6)) new->flags |= CONTEXT_DHCP; else if (strstr(a[leasepos], "constructor:") == a[leasepos]) @@ -2615,7 +2833,7 @@ static int one_opt(int option, char *arg, char *errstr if (new->prefix != 64) { - if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))) + if (new->flags & CONTEXT_RA) ret_err(_("prefix length must be exactly 64 for RA subnets")); else if (new->flags & CONTEXT_TEMPLATE) ret_err(_("prefix length must be exactly 64 for subnet constructors")); @@ -2652,6 +2870,9 @@ static int one_opt(int option, char *arg, char *errstr if (leasepos < k) { + if (leasepos != k-1) + ret_err(_("bad dhcp-range")); + if (strcmp(a[leasepos], "infinite") == 0) new->lease_time = 0xffffffff; else if (strcmp(a[leasepos], "deprecated") == 0) @@ -2746,7 +2967,6 @@ static int one_opt(int option, char *arg, char *errstr } if (len == -1) - ret_err(_("bad hex constant")); else if ((new->clid = opt_malloc(len))) { @@ -3078,7 +3298,8 @@ static int one_opt(int option, char *arg, char *errstr { struct pxe_service *new = opt_malloc(sizeof(struct pxe_service)); char *CSA[] = { "x86PC", "PC98", "IA64_EFI", "Alpha", "Arc_x86", "Intel_Lean_Client", - "IA32_EFI", "BC_EFI", "Xscale_EFI", "x86-64_EFI", NULL }; + "IA32_EFI", "x86-64_EFI", "Xscale_EFI", "BC_EFI", + "ARM32_EFI", "ARM64_EFI", NULL }; static int boottype = 32768; new->netid = NULL; @@ -3439,8 +3660,8 @@ static int one_opt(int option, char *arg, char *errstr (!(inet_pton(AF_INET, a[1], &new->out) > 0))) option = '?'; - if (k == 3) - inet_pton(AF_INET, a[2], &new->mask); + if (k == 3 && !inet_pton(AF_INET, a[2], &new->mask)) + option = '?'; if (dash && (!(inet_pton(AF_INET, dash, &new->end) > 0) || @@ -3490,12 +3711,15 @@ static int one_opt(int option, char *arg, char *errstr case LOPT_CNAME: /* --cname */ { struct cname *new; - char *alias; - char *target; + char *alias, *target, *ttls; + int ttl = -1; if (!(comma = split(arg))) ret_err(gen_err); + if ((ttls = split(comma)) && !atoi_check(ttls, &ttl)) + ret_err(_("bad TTL")); + alias = canonicalise_opt(arg); target = canonicalise_opt(comma); @@ -3511,6 +3735,7 @@ static int one_opt(int option, char *arg, char *errstr daemon->cnames = new; new->alias = alias; new->target = target; + new->ttl = ttl; } break; @@ -3576,7 +3801,7 @@ static int one_opt(int option, char *arg, char *errstr case LOPT_RR: /* dns-rr */ { struct txt_record *new; - size_t len = len; + size_t len = 0; char *data; int val; @@ -3684,13 +3909,8 @@ static int one_opt(int option, char *arg, char *errstr if (!atoi_check16(arg, &priority)) ret_err(_("invalid priority")); - if (comma) - { - arg = comma; - comma = split(arg); - if (!atoi_check16(arg, &weight)) - ret_err(_("invalid weight")); - } + if (comma && !atoi_check16(comma, &weight)) + ret_err(_("invalid weight")); } } } @@ -3711,14 +3931,22 @@ static int one_opt(int option, char *arg, char *errstr { struct host_record *new = opt_malloc(sizeof(struct host_record)); memset(new, 0, sizeof(struct host_record)); - + new->ttl = -1; + if (!arg || !(comma = split(arg))) ret_err(_("Bad host-record")); while (arg) { struct all_addr addr; - if (inet_pton(AF_INET, arg, &addr)) + char *dig; + + for (dig = arg; *dig != 0; dig++) + if (*dig < '0' || *dig > '9') + break; + if (*dig == 0) + new->ttl = atoi(arg); + else if (inet_pton(AF_INET, arg, &addr)) new->addr = addr.addr.addr4; #ifdef HAVE_IPV6 else if (inet_pton(AF_INET6, arg, &addr)) @@ -3760,6 +3988,10 @@ static int one_opt(int option, char *arg, char *errstr } #ifdef HAVE_DNSSEC + case LOPT_DNSSEC_STAMP: + daemon->timestamp_file = opt_string_alloc(arg); + break; + case LOPT_TRUST_ANCHOR: { struct ds_config *new = opt_malloc(sizeof(struct ds_config)); @@ -3958,6 +4190,20 @@ static void read_file(char *file, FILE *f, int hard_op fclose(f); } +#ifdef HAVE_DHCP +int option_read_dynfile(char *file, int flags) +{ + my_syslog(MS_DHCP | LOG_INFO, _("read %s"), file); + + if (flags & AH_DHCP_HST) + return one_file(file, LOPT_BANK); + else if (flags & AH_DHCP_OPT) + return one_file(file, LOPT_OPTS); + + return 0; +} +#endif + static int one_file(char *file, int hard_opt) { FILE *f; @@ -4055,7 +4301,7 @@ struct hostsfile *expand_filelist(struct hostsfile *li /* don't read this as a file */ ah->flags |= AH_INACTIVE; - + if (!(dir_stream = opendir(ah->fname))) my_syslog(LOG_ERR, _("cannot access directory %s: %s"), ah->fname, strerror(errno)); @@ -4267,6 +4513,8 @@ void read_opts(int argc, char **argv, char *compile_op daemon->soa_refresh = SOA_REFRESH; daemon->soa_retry = SOA_RETRY; daemon->soa_expiry = SOA_EXPIRY; + daemon->max_port = MAX_PORT; + add_txt("version.bind", "dnsmasq-" VERSION, 0 ); add_txt("authors.bind", "Simon Kelley", 0); add_txt("copyright.bind", COPYRIGHT, 0); @@ -4354,7 +4602,11 @@ void read_opts(int argc, char **argv, char *compile_op } if (conffile) - one_file(conffile, conffile_opt); + { + one_file(conffile, conffile_opt); + if (conffile_opt == 0) + free(conffile); + } /* port might not be known when the address is parsed - fill in here */ if (daemon->servers) @@ -4369,9 +4621,27 @@ void read_opts(int argc, char **argv, char *compile_op else if (tmp->source_addr.sa.sa_family == AF_INET6) tmp->source_addr.in6.sin6_port = htons(daemon->query_port); #endif - } - } + } + } + if (daemon->host_records) + { + struct host_record *hr; + + for (hr = daemon->host_records; hr; hr = hr->next) + if (hr->ttl == -1) + hr->ttl = daemon->local_ttl; + } + + if (daemon->cnames) + { + struct cname *cn; + + for (cn = daemon->cnames; cn; cn = cn->next) + if (cn->ttl == -1) + cn->ttl = daemon->local_ttl; + } + if (daemon->if_addrs) { struct iname *tmp;