--- embedaddon/dnsmasq/src/option.c 2013/07/29 19:37:40 1.1.1.1 +++ embedaddon/dnsmasq/src/option.c 2014/06/15 16:31:38 1.1.1.2 @@ -1,4 +1,4 @@ -/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley +/* dnsmasq is Copyright (c) 2000-2014 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 @@ -64,73 +64,88 @@ struct myoption { #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:" /* options which don't have a one-char version */ -#define LOPT_RELOAD 256 -#define LOPT_NO_NAMES 257 -#define LOPT_TFTP 258 -#define LOPT_SECURE 259 -#define LOPT_PREFIX 260 -#define LOPT_PTR 261 -#define LOPT_BRIDGE 262 -#define LOPT_TFTP_MAX 263 -#define LOPT_FORCE 264 -#define LOPT_NOBLOCK 265 -#define LOPT_LOG_OPTS 266 -#define LOPT_MAX_LOGS 267 -#define LOPT_CIRCUIT 268 -#define LOPT_REMOTE 269 -#define LOPT_SUBSCR 270 -#define LOPT_INTNAME 271 -#define LOPT_BANK 272 -#define LOPT_DHCP_HOST 273 -#define LOPT_APREF 274 -#define LOPT_OVERRIDE 275 -#define LOPT_TFTPPORTS 276 -#define LOPT_REBIND 277 -#define LOPT_NOLAST 278 -#define LOPT_OPTS 279 -#define LOPT_DHCP_OPTS 280 -#define LOPT_MATCH 281 -#define LOPT_BROADCAST 282 -#define LOPT_NEGTTL 283 -#define LOPT_ALTPORT 284 -#define LOPT_SCRIPTUSR 285 -#define LOPT_LOCAL 286 -#define LOPT_NAPTR 287 -#define LOPT_MINPORT 288 -#define LOPT_DHCP_FQDN 289 -#define LOPT_CNAME 290 -#define LOPT_PXE_PROMT 291 -#define LOPT_PXE_SERV 292 -#define LOPT_TEST 293 -#define LOPT_TAG_IF 294 -#define LOPT_PROXY 295 -#define LOPT_GEN_NAMES 296 -#define LOPT_MAXTTL 297 -#define LOPT_NO_REBIND 298 -#define LOPT_LOC_REBND 299 -#define LOPT_ADD_MAC 300 -#define LOPT_DNSSEC 301 -#define LOPT_INCR_ADDR 302 -#define LOPT_CONNTRACK 303 -#define LOPT_FQDN 304 -#define LOPT_LUASCRIPT 305 -#define LOPT_RA 306 -#define LOPT_DUID 307 -#define LOPT_HOST_REC 308 -#define LOPT_TFTP_LC 309 -#define LOPT_RR 310 -#define LOPT_CLVERBIND 311 -#define LOPT_MAXCTTL 312 -#define LOPT_AUTHZONE 313 -#define LOPT_AUTHSERV 314 -#define LOPT_AUTHTTL 315 -#define LOPT_AUTHSOA 316 -#define LOPT_AUTHSFS 317 -#define LOPT_AUTHPEER 318 -#define LOPT_IPSET 319 +#define LOPT_RELOAD 256 +#define LOPT_NO_NAMES 257 +#define LOPT_TFTP 258 +#define LOPT_SECURE 259 +#define LOPT_PREFIX 260 +#define LOPT_PTR 261 +#define LOPT_BRIDGE 262 +#define LOPT_TFTP_MAX 263 +#define LOPT_FORCE 264 +#define LOPT_NOBLOCK 265 +#define LOPT_LOG_OPTS 266 +#define LOPT_MAX_LOGS 267 +#define LOPT_CIRCUIT 268 +#define LOPT_REMOTE 269 +#define LOPT_SUBSCR 270 +#define LOPT_INTNAME 271 +#define LOPT_BANK 272 +#define LOPT_DHCP_HOST 273 +#define LOPT_APREF 274 +#define LOPT_OVERRIDE 275 +#define LOPT_TFTPPORTS 276 +#define LOPT_REBIND 277 +#define LOPT_NOLAST 278 +#define LOPT_OPTS 279 +#define LOPT_DHCP_OPTS 280 +#define LOPT_MATCH 281 +#define LOPT_BROADCAST 282 +#define LOPT_NEGTTL 283 +#define LOPT_ALTPORT 284 +#define LOPT_SCRIPTUSR 285 +#define LOPT_LOCAL 286 +#define LOPT_NAPTR 287 +#define LOPT_MINPORT 288 +#define LOPT_DHCP_FQDN 289 +#define LOPT_CNAME 290 +#define LOPT_PXE_PROMT 291 +#define LOPT_PXE_SERV 292 +#define LOPT_TEST 293 +#define LOPT_TAG_IF 294 +#define LOPT_PROXY 295 +#define LOPT_GEN_NAMES 296 +#define LOPT_MAXTTL 297 +#define LOPT_NO_REBIND 298 +#define LOPT_LOC_REBND 299 +#define LOPT_ADD_MAC 300 +#define LOPT_DNSSEC 301 +#define LOPT_INCR_ADDR 302 +#define LOPT_CONNTRACK 303 +#define LOPT_FQDN 304 +#define LOPT_LUASCRIPT 305 +#define LOPT_RA 306 +#define LOPT_DUID 307 +#define LOPT_HOST_REC 308 +#define LOPT_TFTP_LC 309 +#define LOPT_RR 310 +#define LOPT_CLVERBIND 311 +#define LOPT_MAXCTTL 312 +#define LOPT_AUTHZONE 313 +#define LOPT_AUTHSERV 314 +#define LOPT_AUTHTTL 315 +#define LOPT_AUTHSOA 316 +#define LOPT_AUTHSFS 317 +#define LOPT_AUTHPEER 318 +#define LOPT_IPSET 319 +#define LOPT_SYNTH 320 #ifdef OPTION6_PREFIX_CLASS -#define LOPT_PREF_CLSS 320 +#define LOPT_PREF_CLSS 321 #endif +#define LOPT_RELAY 323 +#define LOPT_RA_PARAM 324 +#define LOPT_ADD_SBNET 325 +#define LOPT_QUIET_DHCP 326 +#define LOPT_QUIET_DHCP6 327 +#define LOPT_QUIET_RA 328 +#define LOPT_SEC_VALID 329 +#define LOPT_TRUST_ANCHOR 330 +#define LOPT_DNSSEC_DEBUG 331 +#define LOPT_REV_SERV 332 +#define LOPT_SERVERS_FILE 333 +#define LOPT_DNSSEC_CHECK 334 +#define LOPT_LOCAL_SERVICE 335 +#define LOPT_DNSSEC_TIME 336 #ifdef HAVE_GETOPT_LONG static const struct option opts[] = @@ -147,6 +162,7 @@ static const struct myoption opts[] = { "user", 2, 0, 'u' }, { "group", 2, 0, 'g' }, { "resolv-file", 2, 0, 'r' }, + { "servers-file", 1, 0, LOPT_SERVERS_FILE }, { "mx-host", 1, 0, 'm' }, { "mx-target", 1, 0, 't' }, { "cache-size", 2, 0, 'c' }, @@ -161,6 +177,7 @@ static const struct myoption opts[] = { "domain-suffix", 1, 0, 's' }, { "interface", 1, 0, 'i' }, { "listen-address", 1, 0, 'a' }, + { "local-service", 0, 0, LOPT_LOCAL_SERVICE }, { "bogus-priv", 0, 0, 'b' }, { "bogus-nxdomain", 1, 0, 'B' }, { "selfmx", 0, 0, 'e' }, @@ -168,6 +185,7 @@ static const struct myoption opts[] = { "pid-file", 2, 0, 'x' }, { "strict-order", 0, 0, 'o' }, { "server", 1, 0, 'S' }, + { "rev-server", 1, 0, LOPT_REV_SERV }, { "local", 1, 0, LOPT_LOCAL }, { "address", 1, 0, 'A' }, { "conf-file", 2, 0, 'C' }, @@ -206,7 +224,7 @@ static const struct myoption opts[] = { "dns-forward-max", 1, 0, '0' }, { "clear-on-reload", 0, 0, LOPT_RELOAD }, { "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES }, - { "enable-tftp", 0, 0, LOPT_TFTP }, + { "enable-tftp", 2, 0, LOPT_TFTP }, { "tftp-secure", 0, 0, LOPT_SECURE }, { "tftp-unique-root", 0, 0, LOPT_APREF }, { "tftp-root", 1, 0, LOPT_PREFIX }, @@ -248,6 +266,7 @@ static const struct myoption opts[] = { "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES }, { "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND }, { "add-mac", 0, 0, LOPT_ADD_MAC }, + { "add-subnet", 2, 0, LOPT_ADD_SBNET }, { "proxy-dnssec", 0, 0, LOPT_DNSSEC }, { "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR }, { "conntrack", 0, 0, LOPT_CONNTRACK }, @@ -264,9 +283,20 @@ static const struct myoption opts[] = { "auth-sec-servers", 1, 0, LOPT_AUTHSFS }, { "auth-peer", 1, 0, LOPT_AUTHPEER }, { "ipset", 1, 0, LOPT_IPSET }, + { "synth-domain", 1, 0, LOPT_SYNTH }, + { "dnssec", 0, 0, LOPT_SEC_VALID }, + { "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR }, + { "dnssec-debug", 0, 0, LOPT_DNSSEC_DEBUG }, + { "dnssec-check-unsigned", 0, 0, LOPT_DNSSEC_CHECK }, + { "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME }, #ifdef OPTION6_PREFIX_CLASS { "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS }, #endif + { "dhcp-relay", 1, 0, LOPT_RELAY }, + { "ra-param", 1, 0, LOPT_RA_PARAM }, + { "quiet-dhcp", 0, 0, LOPT_QUIET_DHCP }, + { "quiet-dhcp6", 0, 0, LOPT_QUIET_DHCP6 }, + { "quiet-ra", 0, 0, LOPT_QUIET_RA }, { NULL, 0, 0, 0 } }; @@ -327,7 +357,9 @@ static struct { { '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 }, + { LOPT_SERVERS_FILE, ARG_ONE, "", gettext_noop("Specify path to file with server= options"), NULL }, { 'S', ARG_DUP, "//", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL }, + { LOPT_REV_SERV, ARG_DUP, "/,", gettext_noop("Specify address of upstream servers for reverse address queries"), NULL }, { LOPT_LOCAL, ARG_DUP, "//", gettext_noop("Never forward queries to specified domains."), NULL }, { 's', ARG_DUP, "[,]", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL }, { 't', ARG_ONE, "", gettext_noop("Specify default target in an MX record."), NULL }, @@ -364,7 +396,7 @@ static struct { { LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE }, { LOPT_NO_NAMES, ARG_DUP, "[=tag:]...", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL }, { LOPT_OVERRIDE, OPT_NO_OVERRIDE, NULL, gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL }, - { LOPT_TFTP, OPT_TFTP, NULL, gettext_noop("Enable integrated read-only TFTP server."), NULL }, + { LOPT_TFTP, ARG_DUP, "[=[,]]", gettext_noop("Enable integrated read-only TFTP server."), NULL }, { 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 }, @@ -385,12 +417,14 @@ static struct { { 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_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_DNSSEC, OPT_DNSSEC, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL }, + { LOPT_ADD_SBNET, ARG_ONE, "[,]", gettext_noop("Add requestor's IP subnet 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 }, @@ -406,9 +440,20 @@ static struct { { LOPT_AUTHSFS, ARG_DUP, "[,...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL }, { LOPT_AUTHPEER, ARG_DUP, "[,...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL }, { LOPT_IPSET, ARG_DUP, "//[,...]", gettext_noop("Specify ipsets to which matching domains should be added"), NULL }, + { LOPT_SYNTH, ARG_DUP, ",,[]", gettext_noop("Specify a domain and address range for synthesised names"), NULL }, + { LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL }, + { LOPT_TRUST_ANCHOR, ARG_DUP, ",[],...", gettext_noop("Specify trust anchor key digest."), NULL }, + { LOPT_DNSSEC_DEBUG, OPT_DNSSEC_DEBUG, NULL, gettext_noop("Disable upstream checking for DNSSEC debugging."), NULL }, + { LOPT_DNSSEC_CHECK, OPT_DNSSEC_NO_SIGN, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL }, + { LOPT_DNSSEC_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL }, #ifdef OPTION6_PREFIX_CLASS { LOPT_PREF_CLSS, ARG_DUP, "set:tag,", gettext_noop("Specify DHCPv6 prefix class"), NULL }, #endif + { LOPT_RA_PARAM, ARG_DUP, ",[high,|low,][,]", gettext_noop("Set priority, resend-interval and router-lifetime"), NULL }, + { LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL }, + { LOPT_QUIET_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 }, { 0, 0, NULL, NULL, NULL } }; @@ -560,20 +605,37 @@ static int atoi_check16(char *a, int *res) return 1; } + +#ifdef HAVE_DNSSEC +static int atoi_check8(char *a, int *res) +{ + if (!(atoi_check(a, res)) || + *res < 0 || + *res > 0xff) + return 0; + + return 1; +} +#endif -static void add_txt(char *name, char *txt) +static void add_txt(char *name, char *txt, int stat) { - size_t len = strlen(txt); struct txt_record *r = opt_malloc(sizeof(struct txt_record)); + + if (txt) + { + size_t len = strlen(txt); + r->txt = opt_malloc(len+1); + r->len = len+1; + *(r->txt) = len; + memcpy((r->txt)+1, txt, len); + } + r->stat = stat; r->name = opt_string_alloc(name); r->next = daemon->txt; daemon->txt = r; r->class = C_CHAOS; - r->txt = opt_malloc(len+1); - r->len = len+1; - *(r->txt) = len; - memcpy((r->txt)+1, txt, len); } static void do_usage(void) @@ -644,6 +706,13 @@ char *parse_server(char *arg, union mysockaddr *addr, char *scope_id; #endif + if (!arg || strlen(arg) == 0) + { + *flags |= SERV_NO_ADDR; + *interface = 0; + return NULL; + } + if ((source = split_chr(arg, '@')) && /* is there a source. */ (portno = split_chr(source, '#')) && !atoi_check16(portno, &source_port)) @@ -657,7 +726,7 @@ char *parse_server(char *arg, union mysockaddr *addr, scope_id = split_chr(arg, '%'); #endif - if ((addr->in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1) + if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0) { addr->in.sin_port = htons(serv_port); addr->sa.sa_family = source_addr->sa.sa_family = AF_INET; @@ -672,7 +741,7 @@ char *parse_server(char *arg, union mysockaddr *addr, if (flags) *flags |= SERV_HAS_SOURCE; source_addr->in.sin_port = htons(source_port); - if ((source_addr->in.sin_addr.s_addr = inet_addr(source)) == (in_addr_t) -1) + if (!(inet_pton(AF_INET, source, &source_addr->in.sin_addr) > 0)) { #if defined(SO_BINDTODEVICE) source_addr->in.sin_addr.s_addr = INADDR_ANY; @@ -722,6 +791,54 @@ char *parse_server(char *arg, union mysockaddr *addr, return NULL; } +static struct server *add_rev4(struct in_addr addr, int msize) +{ + struct server *serv = opt_malloc(sizeof(struct server)); + in_addr_t a = ntohl(addr.s_addr) >> 8; + char *p; + + memset(serv, 0, sizeof(struct server)); + p = serv->domain = opt_malloc(25); /* strlen("xxx.yyy.zzz.in-addr.arpa")+1 */ + + if (msize == 24) + p += sprintf(p, "%d.", a & 0xff); + a = a >> 8; + if (msize != 8) + p += sprintf(p, "%d.", a & 0xff); + a = a >> 8; + p += sprintf(p, "%d.in-addr.arpa", a & 0xff); + + serv->flags = SERV_HAS_DOMAIN; + serv->next = daemon->servers; + daemon->servers = serv; + + return serv; + +} + +static struct server *add_rev6(struct in6_addr *addr, int msize) +{ + struct server *serv = opt_malloc(sizeof(struct server)); + char *p; + int i; + + memset(serv, 0, sizeof(struct server)); + p = serv->domain = opt_malloc(73); /* strlen("32*ip6.arpa")+1 */ + + for (i = msize-1; i >= 0; i -= 4) + { + int dig = ((unsigned char *)addr)[i>>3]; + p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4); + } + p += sprintf(p, "ip6.arpa"); + + serv->flags = SERV_HAS_DOMAIN; + serv->next = daemon->servers; + daemon->servers = serv; + + return serv; +} + #ifdef HAVE_DHCP static int is_tag_prefix(char *arg) @@ -750,6 +867,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int struct dhcp_netid *np = NULL; u16 opt_len = 0; int is6 = 0; + int option_ok = 0; new->len = 0; new->flags = flags; @@ -769,16 +887,19 @@ static int parse_dhcp_opt(char *errstr, char *arg, int { new->opt = atoi(arg); opt_len = 0; + option_ok = 1; break; } if (strstr(arg, "option:") == arg) { - new->opt = lookup_dhcp_opt(AF_INET, arg+7); - opt_len = lookup_dhcp_len(AF_INET, new->opt); - /* option: must follow tag and vendor string. */ - if ((opt_len & OT_INTERNAL) && flags != DHOPT_MATCH) - new->opt = 0; + if ((new->opt = lookup_dhcp_opt(AF_INET, arg+7)) != -1) + { + opt_len = lookup_dhcp_len(AF_INET, new->opt); + /* option: must follow tag and vendor string. */ + if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH) + option_ok = 1; + } break; } #ifdef HAVE_DHCP6 @@ -792,13 +913,16 @@ static int parse_dhcp_opt(char *errstr, char *arg, int { new->opt = atoi(arg+8); opt_len = 0; + option_ok = 1; } else { - new->opt = lookup_dhcp_opt(AF_INET6, arg+8); - opt_len = lookup_dhcp_len(AF_INET6, new->opt); - if ((opt_len & OT_INTERNAL) && flags != DHOPT_MATCH) - new->opt = 0; + if ((new->opt = lookup_dhcp_opt(AF_INET6, arg+8)) != -1) + { + opt_len = lookup_dhcp_len(AF_INET6, new->opt); + if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH) + option_ok = 1; + } } /* option6:| must follow tag and vendor string. */ is6 = 1; @@ -821,7 +945,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int new->flags |= DHOPT_RFC3925; if (flags == DHOPT_MATCH) { - new->opt = 1; /* avoid error below */ + option_ok = 1; break; } } @@ -848,16 +972,16 @@ static int parse_dhcp_opt(char *errstr, char *arg, int if (opt_len == 0 && !(new->flags & DHOPT_RFC3925)) - opt_len = lookup_dhcp_len(AF_INET6 ,new->opt); + opt_len = lookup_dhcp_len(AF_INET6, new->opt); } else #endif if (opt_len == 0 && !(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925))) - opt_len = lookup_dhcp_len(AF_INET ,new->opt); + opt_len = lookup_dhcp_len(AF_INET, new->opt); /* option may be missing with rfc3925 match */ - if (new->opt == 0) + if (!option_ok) ret_err(_("bad dhcp-option")); if (comma) @@ -1021,7 +1145,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int cp = comma; comma = split(cp); slash = split_chr(cp, '/'); - in.s_addr = inet_addr(cp); + inet_pton(AF_INET, cp, &in); if (!slash) { memcpy(op, &in, INADDRSZ); @@ -1278,7 +1402,7 @@ void reset_option_bool(unsigned int opt) daemon->options2 &= ~(1u << (opt - 32)); } -static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line) +static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only) { int i; char *comma; @@ -1408,6 +1532,17 @@ static int one_opt(int option, char *arg, char *errstr break; } + case LOPT_ADD_SBNET: /* --add-subnet */ + set_option_bool(OPT_CLIENT_SUBNET); + if (arg) + { + comma = split(arg); + if (!atoi_check(arg, &daemon->addr4_netmask) || + (comma && !atoi_check(comma, &daemon->addr6_netmask))) + ret_err(gen_err); + } + break; + case '1': /* --enable-dbus */ set_option_bool(OPT_DBUS); if (arg) @@ -1470,6 +1605,10 @@ static int one_opt(int option, char *arg, char *errstr daemon->resolv_files = list; break; } + + case LOPT_SERVERS_FILE: + daemon->servers_file = opt_string_alloc(arg); + break; case 'm': /* --mx-host */ { @@ -1533,7 +1672,7 @@ static int one_opt(int option, char *arg, char *errstr case 'H': /* --addn-hosts */ { struct hostsfile *new = opt_malloc(sizeof(struct hostsfile)); - static int hosts_index = 1; + static unsigned int hosts_index = SRC_AH; new->fname = opt_string_alloc(arg); new->index = hosts_index++; new->flags = 0; @@ -1555,6 +1694,8 @@ static int one_opt(int option, char *arg, char *errstr break; } + +#ifdef HAVE_AUTH case LOPT_AUTHSERV: /* --auth-server */ if (!(comma = split(arg))) ret_err(gen_err); @@ -1566,15 +1707,29 @@ static int one_opt(int option, char *arg, char *errstr comma = split(arg); new->name = NULL; unhide_metas(arg); - if ((new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1) + if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0) new->addr.sa.sa_family = AF_INET; #ifdef HAVE_IPV6 else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0) new->addr.sa.sa_family = AF_INET6; #endif else - new->name = opt_string_alloc(arg); - + { + char *fam = split_chr(arg, '/'); + new->name = opt_string_alloc(arg); + new->addr.sa.sa_family = 0; + if (fam) + { + if (strcmp(fam, "4") == 0) + new->addr.sa.sa_family = AF_INET; +#ifdef HAVE_IPV6 + else if (strcmp(fam, "6") == 0) + new->addr.sa.sa_family = AF_INET6; +#endif + else + ret_err(gen_err); + } + } new->next = daemon->authinterface; daemon->authinterface = new; @@ -1607,6 +1762,7 @@ static int one_opt(int option, char *arg, char *errstr new = opt_malloc(sizeof(struct auth_zone)); new->domain = opt_string_alloc(arg); new->subnet = NULL; + new->interface_names = NULL; new->next = daemon->auth_zones; daemon->auth_zones = new; @@ -1614,10 +1770,8 @@ static int one_opt(int option, char *arg, char *errstr { int prefixlen = 0; char *prefix; - struct subnet *subnet = opt_malloc(sizeof(struct subnet)); - - subnet->next = new->subnet; - new->subnet = subnet; + struct addrlist *subnet = NULL; + struct all_addr addr; comma = split(arg); prefix = split_chr(arg, '/'); @@ -1625,29 +1779,53 @@ static int one_opt(int option, char *arg, char *errstr if (prefix && !atoi_check(prefix, &prefixlen)) ret_err(gen_err); - if (inet_pton(AF_INET, arg, &subnet->addr4)) + if (inet_pton(AF_INET, arg, &addr.addr.addr4)) { - if ((prefixlen & 0x07) != 0 || prefixlen > 24) - ret_err(_("bad prefix")); + subnet = opt_malloc(sizeof(struct addrlist)); subnet->prefixlen = (prefixlen == 0) ? 24 : prefixlen; - subnet->is6 = 0; + subnet->flags = ADDRLIST_LITERAL; } #ifdef HAVE_IPV6 - else if (inet_pton(AF_INET6, arg, &subnet->addr6)) + else if (inet_pton(AF_INET6, arg, &addr.addr.addr6)) { + subnet = opt_malloc(sizeof(struct addrlist)); subnet->prefixlen = (prefixlen == 0) ? 64 : prefixlen; - subnet->is6 = 1; + subnet->flags = ADDRLIST_LITERAL | ADDRLIST_IPV6; } #endif - else - ret_err(gen_err); + else + { + struct auth_name_list *name = opt_malloc(sizeof(struct auth_name_list)); + name->name = opt_string_alloc(arg); + name->flags = AUTH4 | AUTH6; + name->next = new->interface_names; + new->interface_names = name; + if (prefix) + { + if (prefixlen == 4) + name->flags &= ~AUTH6; +#ifdef HAVE_IPV6 + else if (prefixlen == 6) + name->flags &= ~AUTH4; +#endif + else + ret_err(gen_err); + } + } + + if (subnet) + { + subnet->addr = addr; + subnet->next = new->subnet; + new->subnet = subnet; + } } break; } - + case LOPT_AUTHSOA: /* --auth-soa */ comma = split(arg); - atoi_check(arg, (int *)&daemon->soa_sn); + daemon->soa_sn = (u32)atoi(arg); if (comma) { char *cp; @@ -1662,25 +1840,27 @@ static int one_opt(int option, char *arg, char *errstr { arg = comma; comma = split(arg); - atoi_check(arg, (int *)&daemon->soa_refresh); + daemon->soa_refresh = (u32)atoi(arg); if (comma) { arg = comma; comma = split(arg); - atoi_check(arg, (int *)&daemon->soa_retry); + daemon->soa_retry = (u32)atoi(arg); if (comma) { arg = comma; comma = split(arg); - atoi_check(arg, (int *)&daemon->soa_expiry); + daemon->soa_expiry = (u32)atoi(arg); } } } } break; +#endif - case 's': /* --domain */ + case 's': /* --domain */ + case LOPT_SYNTH: /* --synth-domain */ if (strcmp (arg, "#") == 0) set_option_bool(OPT_RESOLV_DOMAIN); else @@ -1695,6 +1875,8 @@ static int one_opt(int option, char *arg, char *errstr { struct cond_domain *new = opt_malloc(sizeof(struct cond_domain)); char *netpart; + + new->prefix = NULL; unhide_metas(comma); if ((netpart = split_chr(comma, '/'))) @@ -1712,40 +1894,22 @@ static int one_opt(int option, char *arg, char *errstr new->end.s_addr = new->start.s_addr | htonl(mask); if (arg) { - /* generate the equivalent of - local=// - local=/xxx.yyy.zzz.in-addr.arpa/ */ - - if (strcmp(arg, "local") != 0 || - (msize != 8 && msize != 16 && msize != 24)) + if (option != 's') + { + if (!(new->prefix = canonicalise_opt(arg)) || + strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN) + ret_err(_("bad prefix")); + } + else if (strcmp(arg, "local") != 0 || + (msize != 8 && msize != 16 && msize != 24)) ret_err(gen_err); else { - struct server *serv = opt_malloc(sizeof(struct server)); - in_addr_t a = ntohl(new->start.s_addr) >> 8; - char *p; - - memset(serv, 0, sizeof(struct server)); - serv->domain = d; - serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR; - serv->next = daemon->servers; - daemon->servers = serv; - - serv = opt_malloc(sizeof(struct server)); - memset(serv, 0, sizeof(struct server)); - p = serv->domain = opt_malloc(25); /* strlen("xxx.yyy.zzz.in-addr.arpa")+1 */ - - if (msize == 24) - p += sprintf(p, "%d.", a & 0xff); - a = a >> 8; - if (msize != 8) - p += sprintf(p, "%d.", a & 0xff); - a = a >> 8; - p += sprintf(p, "%d.in-addr.arpa", a & 0xff); - - serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR; - serv->next = daemon->servers; - daemon->servers = serv; + /* 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; } } } @@ -1755,11 +1919,11 @@ static int one_opt(int option, char *arg, char *errstr u64 mask = (1LLU << (128 - msize)) - 1LLU; u64 addrpart = addr6part(&new->start6); new->is6 = 1; - + /* prefix==64 overflows the mask calculation above */ if (msize == 64) mask = (u64)-1LL; - + new->end6 = new->start6; setaddr6part(&new->start6, addrpart & ~mask); setaddr6part(&new->end6, addrpart | mask); @@ -1768,37 +1932,21 @@ static int one_opt(int option, char *arg, char *errstr ret_err(gen_err); else if (arg) { - /* generate the equivalent of - local=// - local=/xxx.yyy.zzz.ip6.arpa/ */ - - if (strcmp(arg, "local") != 0 || ((msize & 4) != 0)) + if (option != 's') + { + if (!(new->prefix = canonicalise_opt(arg)) || + strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN) + ret_err(_("bad prefix")); + } + else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0)) ret_err(gen_err); else { - struct server *serv = opt_malloc(sizeof(struct server)); - char *p; - - memset(serv, 0, sizeof(struct server)); - serv->domain = d; - serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR; - serv->next = daemon->servers; - daemon->servers = serv; - - serv = opt_malloc(sizeof(struct server)); - memset(serv, 0, sizeof(struct server)); - p = serv->domain = opt_malloc(73); /* strlen("32*ip6.arpa")+1 */ - - for (i = msize-1; i >= 0; i -= 4) - { - int dig = ((unsigned char *)&new->start6)[i>>3]; - p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4); - } - p += sprintf(p, "ip6.arpa"); - - serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR; - serv->next = daemon->servers; - daemon->servers = serv; + /* generate the equivalent of + local=// + local=/xxx.yyy.zzz.ip6.arpa/ */ + struct server *serv = add_rev6(&new->start6, msize); + serv->flags |= SERV_NO_ADDR; } } } @@ -1806,9 +1954,12 @@ static int one_opt(int option, char *arg, char *errstr else ret_err(gen_err); } - else + else { + char *prefstr; arg = split(comma); + prefstr = split(arg); + if (inet_pton(AF_INET, comma, &new->start)) { new->is6 = 0; @@ -1829,14 +1980,31 @@ static int one_opt(int option, char *arg, char *errstr #endif else ret_err(gen_err); + + if (option != 's' && prefstr) + { + if (!(new->prefix = canonicalise_opt(prefstr)) || + strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN) + ret_err(_("bad prefix")); + } } new->domain = d; - new->next = daemon->cond_domain; - daemon->cond_domain = new; + if (option == 's') + { + new->next = daemon->cond_domain; + daemon->cond_domain = new; + } + else + { + new->next = daemon->synth_domains; + daemon->synth_domains = new; + } } - else + else if (option == 's') daemon->domain_suffix = d; + else + ret_err(gen_err); } } break; @@ -1870,6 +2038,12 @@ static int one_opt(int option, char *arg, char *errstr } while (arg); break; + case LOPT_TFTP: /* --enable-tftp */ + set_option_bool(OPT_TFTP); + if (!arg) + break; + /* fall through */ + case 'I': /* --except-interface */ case '2': /* --no-dhcp-interface */ do { @@ -1881,6 +2055,11 @@ static int one_opt(int option, char *arg, char *errstr new->next = daemon->if_except; daemon->if_except = new; } + else if (option == LOPT_TFTP) + { + new->next = daemon->tftp_interfaces; + daemon->tftp_interfaces = new; + } else { new->next = daemon->dhcp_except; @@ -1894,7 +2073,7 @@ static int one_opt(int option, char *arg, char *errstr { struct in_addr addr; unhide_metas(arg); - if (arg && (addr.s_addr = inet_addr(arg)) != (in_addr_t)-1) + if (arg && (inet_pton(AF_INET, arg, &addr) > 0)) { struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr)); baddr->next = daemon->bogus_addr; @@ -1912,7 +2091,7 @@ static int one_opt(int option, char *arg, char *errstr struct iname *new = opt_malloc(sizeof(struct iname)); comma = split(arg); unhide_metas(arg); - if (arg && (new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1) + if (arg && (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0)) { new->addr.sa.sa_family = AF_INET; new->addr.in.sin_port = 0; @@ -1994,6 +2173,9 @@ static int one_opt(int option, char *arg, char *errstr memset(newlist, 0, sizeof(struct server)); } + if (servers_only && option == 'S') + newlist->flags |= SERV_FROM_FILE; + if (option == 'A') { newlist->flags |= SERV_LITERAL_ADDRESS; @@ -2038,6 +2220,40 @@ static int one_opt(int option, char *arg, char *errstr break; } + case LOPT_REV_SERV: /* --rev-server */ + { + char *string; + int size; + struct server *serv; + struct in_addr addr4; +#ifdef HAVE_IPV6 + struct in6_addr addr6; +#endif + + unhide_metas(arg); + if (!arg || !(comma=split(arg)) || !(string = split_chr(arg, '/')) || !atoi_check(string, &size)) + ret_err(gen_err); + + if (inet_pton(AF_INET, arg, &addr4)) + serv = add_rev4(addr4, size); +#ifdef HAVE_IPV6 + else if (inet_pton(AF_INET6, arg, &addr6)) + serv = add_rev6(&addr6, size); +#endif + else + ret_err(gen_err); + + string = parse_server(comma, &serv->addr, &serv->source_addr, serv->interface, &serv->flags); + + if (string) + ret_err(string); + + if (servers_only) + serv->flags |= SERV_FROM_FILE; + + break; + } + case LOPT_IPSET: /* --ipset */ #ifndef HAVE_IPSET ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives")); @@ -2289,7 +2505,9 @@ static int one_opt(int option, char *arg, char *errstr struct dhcp_netid *tt = opt_malloc(sizeof (struct dhcp_netid)); tt->net = opt_string_alloc(arg+4); tt->next = new->filter; - new->filter = tt; + /* ignore empty tag */ + if (tt->net) + new->filter = tt; } else { @@ -2336,7 +2554,7 @@ static int one_opt(int option, char *arg, char *errstr } if (k >= 3 && strchr(a[2], '.') && - ((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1)) + (inet_pton(AF_INET, a[2], &new->netmask) > 0)) { new->flags |= CONTEXT_NETMASK; leasepos = 3; @@ -2345,7 +2563,7 @@ static int one_opt(int option, char *arg, char *errstr } if (k >= 4 && strchr(a[3], '.') && - ((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1)) + (inet_pton(AF_INET, a[3], &new->broadcast) > 0)) { new->flags |= CONTEXT_BRDCAST; leasepos = 4; @@ -2354,13 +2572,12 @@ static int one_opt(int option, char *arg, char *errstr #ifdef HAVE_DHCP6 else if (inet_pton(AF_INET6, a[0], &new->start6)) { + new->flags |= CONTEXT_V6; new->prefix = 64; /* default */ new->end6 = new->start6; - - /* dhcp-range=:: enables DHCP stateless on any interface */ - if (IN6_IS_ADDR_UNSPECIFIED(&new->start6)) - new->prefix = 0; - + new->next = daemon->dhcp6; + daemon->dhcp6 = new; + for (leasepos = 1; leasepos < k; leasepos++) { if (strcmp(a[leasepos], "static") == 0) @@ -2381,10 +2598,7 @@ static int one_opt(int option, char *arg, char *errstr else break; } - - new->next = daemon->dhcp6; - daemon->dhcp6 = new; - + /* bare integer < 128 is prefix value */ if (leasepos < k) { @@ -2396,20 +2610,35 @@ static int one_opt(int option, char *arg, char *errstr { new->prefix = pref; leasepos++; - if (new->prefix != 64) - { - if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))) - ret_err(_("prefix must be exactly 64 for RA subnets")); - else if (new->template_interface) - ret_err(_("prefix must be exactly 64 for subnet constructors")); - } - if (new->prefix < 64) - ret_err(_("prefix must be at least 64")); } } + if (new->prefix != 64) + { + if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))) + 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")); + } + + if (new->prefix < 64) + ret_err(_("prefix length must be at least 64")); + if (!is_same_net6(&new->start6, &new->end6, new->prefix)) ret_err(_("inconsistent DHCPv6 range")); + + /* dhcp-range=:: enables DHCP stateless on any interface */ + if (IN6_IS_ADDR_UNSPECIFIED(&new->start6) && !(new->flags & CONTEXT_TEMPLATE)) + new->prefix = 0; + + if (new->flags & CONTEXT_TEMPLATE) + { + struct in6_addr zero; + memset(&zero, 0, sizeof(zero)); + if (!is_same_net6(&zero, &new->start6, new->prefix)) + ret_err(_("prefix must be zero with \"constructor:\" argument")); + } + if (addr6part(&new->start6) > addr6part(&new->end6)) { struct in6_addr tmp = new->start6; @@ -2477,7 +2706,7 @@ static int one_opt(int option, char *arg, char *errstr case 'G': /* --dhcp-host */ { int j, k = 0; - char *a[6] = { NULL, NULL, NULL, NULL, NULL, NULL }; + char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; struct dhcp_config *new; struct in_addr in; @@ -2489,7 +2718,7 @@ static int one_opt(int option, char *arg, char *errstr new->netid = NULL; if ((a[0] = arg)) - for (k = 1; k < 6; k++) + for (k = 1; k < 7; k++) if (!(a[k] = split(a[k-1]))) break; @@ -2575,7 +2804,7 @@ static int one_opt(int option, char *arg, char *errstr } } } - else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1) + else if (strchr(a[j], '.') && (inet_pton(AF_INET, a[j], &in) > 0)) { struct dhcp_config *configs; @@ -2595,7 +2824,7 @@ static int one_opt(int option, char *arg, char *errstr else { char *cp, *lastp = NULL, last = 0; - int fac = 1; + int fac = 1, isdig = 0; if (strlen(a[j]) > 1) { @@ -2626,9 +2855,11 @@ static int one_opt(int option, char *arg, char *errstr } for (cp = a[j]; *cp; cp++) - if (!isdigit((unsigned char)*cp) && *cp != ' ') + if (isdigit((unsigned char)*cp)) + isdig = 1; + else if (*cp != ' ') break; - + if (*cp) { if (lastp) @@ -2650,7 +2881,7 @@ static int one_opt(int option, char *arg, char *errstr new->domain = strip_hostname(new->hostname); } } - else + else if (isdig) { new->lease_time = atoi(a[j]) * fac; /* Leases of a minute or less confuse @@ -2772,17 +3003,17 @@ static int one_opt(int option, char *arg, char *errstr if (comma) { unhide_metas(comma); - if ((dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1) { - - /* - * The user may have specified the tftp hostname here. - * save it so that it can be resolved/looked up during - * actual dhcp_reply(). - */ - - tftp_sname = opt_string_alloc(comma); - dhcp_next_server.s_addr = 0; - } + if (!(inet_pton(AF_INET, comma, &dhcp_next_server) > 0)) + { + /* + * The user may have specified the tftp hostname here. + * save it so that it can be resolved/looked up during + * actual dhcp_reply(). + */ + + tftp_sname = opt_string_alloc(comma); + dhcp_next_server.s_addr = 0; + } } } @@ -2795,7 +3026,7 @@ static int one_opt(int option, char *arg, char *errstr new->next = daemon->boot_config; daemon->boot_config = new; } - + break; } @@ -3111,16 +3342,66 @@ static int one_opt(int option, char *arg, char *errstr while (arg) { struct addr_list *new = opt_malloc(sizeof(struct addr_list)); comma = split(arg); - if ((new->addr.s_addr = inet_addr(arg)) == (in_addr_t)-1) + if (!(inet_pton(AF_INET, arg, &new->addr) > 0)) ret_err(_("bad dhcp-proxy address")); new->next = daemon->override_relays; daemon->override_relays = new; arg = comma; } break; + + case LOPT_RELAY: /* --dhcp-relay */ + { + struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay)); + comma = split(arg); + new->interface = opt_string_alloc(split(comma)); + new->iface_index = 0; + if (inet_pton(AF_INET, arg, &new->local) && inet_pton(AF_INET, comma, &new->server)) + { + new->next = daemon->relay4; + daemon->relay4 = new; + } +#ifdef HAVE_DHCP6 + else if (inet_pton(AF_INET6, arg, &new->local) && inet_pton(AF_INET6, comma, &new->server)) + { + new->next = daemon->relay6; + daemon->relay6 = new; + } #endif + else + ret_err(_("Bad dhcp-relay")); + + break; + } + +#endif #ifdef HAVE_DHCP6 + case LOPT_RA_PARAM: /* --ra-param */ + if ((comma = split(arg))) + { + struct ra_interface *new = opt_malloc(sizeof(struct ra_interface)); + new->lifetime = -1; + new->prio = 0; + new->name = opt_string_alloc(arg); + if (strcasestr(comma, "high") == comma || strcasestr(comma, "low") == comma) + { + if (*comma == 'l' || *comma == 'L') + new->prio = 0x18; + else + new->prio = 0x08; + comma = split(comma); + } + arg = split(comma); + if (!atoi_check(comma, &new->interval) || + (arg && !atoi_check(arg, &new->lifetime))) + ret_err(_("bad RA-params")); + + new->next = daemon->ra_interfaces; + daemon->ra_interfaces = new; + } + break; + case LOPT_DUID: /* --dhcp-duid */ if (!(comma = split(arg)) || !atoi_check(arg, (int *)&daemon->duid_enterprise)) ret_err(_("bad DUID")); @@ -3154,15 +3435,15 @@ static int one_opt(int option, char *arg, char *errstr dash = split_chr(a[0], '-'); if ((k < 2) || - ((new->in.s_addr = inet_addr(a[0])) == (in_addr_t)-1) || - ((new->out.s_addr = inet_addr(a[1])) == (in_addr_t)-1)) + (!(inet_pton(AF_INET, a[0], &new->in) > 0)) || + (!(inet_pton(AF_INET, a[1], &new->out) > 0))) option = '?'; if (k == 3) - new->mask.s_addr = inet_addr(a[2]); + inet_pton(AF_INET, a[2], &new->mask); if (dash && - ((new->end.s_addr = inet_addr(dash)) == (in_addr_t)-1 || + (!(inet_pton(AF_INET, dash, &new->end) > 0) || !is_same_net(new->in, new->end, new->mask) || ntohl(new->in.s_addr) > ntohl(new->end.s_addr))) ret_err(_("invalid alias range")); @@ -3182,11 +3463,26 @@ static int one_opt(int option, char *arg, char *errstr new = opt_malloc(sizeof(struct interface_name)); new->next = NULL; + new->addr = NULL; + /* Add to the end of the list, so that first name of an interface is used for PTR lookups. */ for (up = &daemon->int_names; *up; up = &((*up)->next)); *up = new; new->name = domain; + new->family = 0; + arg = split_chr(comma, '/'); + if (arg) + { + if (strcmp(arg, "4") == 0) + new->family = AF_INET; +#ifdef HAVE_IPV6 + else if (strcmp(arg, "6") == 0) + new->family = AF_INET6; +#endif + else + ret_err(gen_err); + } new->intr = opt_string_alloc(comma); break; } @@ -3280,7 +3576,7 @@ static int one_opt(int option, char *arg, char *errstr case LOPT_RR: /* dns-rr */ { struct txt_record *new; - size_t len; + size_t len = len; char *data; int val; @@ -3321,7 +3617,8 @@ static int one_opt(int option, char *arg, char *errstr new->next = daemon->txt; daemon->txt = new; new->class = C_IN; - + new->stat = 0; + if (!(new->name = canonicalise_opt(arg))) ret_err(_("bad TXT record")); @@ -3461,9 +3758,64 @@ static int one_opt(int option, char *arg, char *errstr daemon->host_records_tail = new; break; } - + +#ifdef HAVE_DNSSEC + case LOPT_TRUST_ANCHOR: + { + struct ds_config *new = opt_malloc(sizeof(struct ds_config)); + char *cp, *cp1, *keyhex, *digest, *algo = NULL; + int len; + + new->class = C_IN; + + if ((comma = split(arg)) && (algo = split(comma))) + { + int class = 0; + if (strcmp(comma, "IN") == 0) + class = C_IN; + else if (strcmp(comma, "CH") == 0) + class = C_CHAOS; + else if (strcmp(comma, "HS") == 0) + class = C_HESIOD; + + if (class != 0) + { + new->class = class; + comma = algo; + algo = split(comma); + } + } + + if (!comma || !algo || !(digest = split(algo)) || !(keyhex = split(digest)) || + !atoi_check16(comma, &new->keytag) || + !atoi_check8(algo, &new->algo) || + !atoi_check8(digest, &new->digest_type) || + !(new->name = canonicalise_opt(arg))) + ret_err(_("bad trust anchor")); + + /* Upper bound on length */ + len = (2*strlen(keyhex))+1; + new->digest = opt_malloc(len); + unhide_metas(keyhex); + /* 4034: "Whitespace is allowed within digits" */ + for (cp = keyhex; *cp; ) + if (isspace(*cp)) + for (cp1 = cp; *cp1; cp1++) + *cp1 = *(cp1+1); + else + cp++; + if ((new->digestlen = parse_hex(keyhex, (unsigned char *)new->digest, len, NULL, NULL)) == -1) + ret_err(_("bad HEX in trust anchor")); + + new->next = daemon->ds; + daemon->ds = new; + + break; + } +#endif + default: - ret_err(_("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DBus support)")); + ret_err(_("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)")); } @@ -3477,12 +3829,13 @@ static void read_file(char *file, FILE *f, int hard_op while (fgets(buff, MAXDNAME, f)) { - int white, i, option = hard_opt; + int white, i; + volatile int option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt; char *errmess, *p, *arg = NULL, *start; size_t len; /* Memory allocation failure longjmps here if mem_recover == 1 */ - if (option != 0) + if (option != 0 || hard_opt == LOPT_REV_SERV) { if (setjmp(mem_jmp)) continue; @@ -3583,13 +3936,15 @@ static void read_file(char *file, FILE *f, int hard_op errmess = _("extraneous parameter"); else if (opts[i].has_arg == 1 && !arg) errmess = _("missing parameter"); + else if (hard_opt == LOPT_REV_SERV && option != 'S' && option != LOPT_REV_SERV) + errmess = _("illegal option"); } oops: if (errmess) strcpy(daemon->namebuff, errmess); - if (errmess || !one_opt(option, arg, buff, _("error"), 0)) + if (errmess || !one_opt(option, arg, buff, _("error"), 0, hard_opt == LOPT_REV_SERV)) { sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file); if (hard_opt != 0) @@ -3674,10 +4029,11 @@ static int one_file(char *file, int hard_opt) /* expand any name which is a directory */ struct hostsfile *expand_filelist(struct hostsfile *list) { - int i; + unsigned int i; struct hostsfile *ah; - for (i = 0, ah = list; ah; ah = ah->next) + /* find largest used index */ + for (i = SRC_AH, ah = list; ah; ah = ah->next) { if (i <= ah->index) i = ah->index + 1; @@ -3771,7 +4127,23 @@ struct hostsfile *expand_filelist(struct hostsfile *li return list; } +void read_servers_file(void) +{ + FILE *f; + if (!(f = fopen(daemon->servers_file, "r"))) + { + my_syslog(LOG_ERR, _("cannot read %s: %s"), daemon->servers_file, strerror(errno)); + return; + } + + mark_servers(SERV_FROM_FILE); + cleanup_servers(); + + read_file(daemon->servers_file, f, LOPT_REV_SERV); +} + + #ifdef HAVE_DHCP void reread_dhcp(void) { @@ -3895,9 +4267,18 @@ 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; - add_txt("version.bind", "dnsmasq-" VERSION ); - add_txt("authors.bind", "Simon Kelley"); - add_txt("copyright.bind", COPYRIGHT); + add_txt("version.bind", "dnsmasq-" VERSION, 0 ); + add_txt("authors.bind", "Simon Kelley", 0); + add_txt("copyright.bind", COPYRIGHT, 0); + add_txt("cachesize.bind", NULL, TXT_STAT_CACHESIZE); + add_txt("insertions.bind", NULL, TXT_STAT_INSERTS); + add_txt("evictions.bind", NULL, TXT_STAT_EVICTIONS); + add_txt("misses.bind", NULL, TXT_STAT_MISSES); + add_txt("hits.bind", NULL, TXT_STAT_HITS); +#ifdef HAVE_AUTH + add_txt("auth.bind", NULL, TXT_STAT_AUTH); +#endif + add_txt("servers.bind", NULL, TXT_STAT_SERVERS); while (1) { @@ -3964,9 +4345,9 @@ void read_opts(int argc, char **argv, char *compile_op else { #ifdef HAVE_GETOPT_LONG - if (!one_opt(option, arg, daemon->namebuff, _("try --help"), 1)) + if (!one_opt(option, arg, daemon->namebuff, _("try --help"), 1, 0)) #else - if (!one_opt(option, arg, daemon->namebuff, _("try -w"), 1)) + if (!one_opt(option, arg, daemon->namebuff, _("try -w"), 1, 0)) #endif die(_("bad command line options: %s"), daemon->namebuff, EC_BADCONF); } @@ -4097,6 +4478,11 @@ void read_opts(int argc, char **argv, char *compile_op } else if (option_bool(OPT_DHCP_FQDN)) die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF); + + /* If there's access-control config, then ignore --local-service, it's intended + as a system default to keep otherwise unconfigured installations safe. */ + if (daemon->if_names || daemon->if_except || daemon->if_addrs || daemon->authserver) + reset_option_bool(OPT_LOCAL_SERVICE); if (testmode) {