version 1.1.1.4, 2021/03/17 00:56:46
|
version 1.1.1.5, 2023/09/27 11:02:07
|
Line 1
|
Line 1
|
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley | /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley |
|
|
This program is free software; you can redistribute it and/or modify |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
it under the terms of the GNU General Public License as published by |
Line 168 struct myoption {
|
Line 168 struct myoption {
|
#define LOPT_SINGLE_PORT 359 |
#define LOPT_SINGLE_PORT 359 |
#define LOPT_SCRIPT_TIME 360 |
#define LOPT_SCRIPT_TIME 360 |
#define LOPT_PXE_VENDOR 361 |
#define LOPT_PXE_VENDOR 361 |
| #define LOPT_DYNHOST 362 |
| #define LOPT_LOG_DEBUG 363 |
| #define LOPT_UMBRELLA 364 |
| #define LOPT_CMARK_ALST_EN 365 |
| #define LOPT_CMARK_ALST 366 |
| #define LOPT_QUIET_TFTP 367 |
| #define LOPT_NFTSET 368 |
| #define LOPT_FILTER_A 369 |
| #define LOPT_FILTER_AAAA 370 |
| #define LOPT_STRIP_SBNET 371 |
| #define LOPT_STRIP_MAC 372 |
| #define LOPT_CONF_OPT 373 |
| #define LOPT_CONF_SCRIPT 374 |
| #define LOPT_RANDPORT_LIM 375 |
| #define LOPT_FAST_RETRY 376 |
| #define LOPT_STALE_CACHE 377 |
| #define LOPT_NORR 378 |
| #define LOPT_NO_IDENT 379 |
| |
#ifdef HAVE_GETOPT_LONG |
#ifdef HAVE_GETOPT_LONG |
static const struct option opts[] = |
static const struct option opts[] = |
#else |
#else |
Line 205 static const struct myoption opts[] =
|
Line 223 static const struct myoption opts[] =
|
{ "ignore-address", 1, 0, LOPT_IGNORE_ADDR }, |
{ "ignore-address", 1, 0, LOPT_IGNORE_ADDR }, |
{ "selfmx", 0, 0, 'e' }, |
{ "selfmx", 0, 0, 'e' }, |
{ "filterwin2k", 0, 0, 'f' }, |
{ "filterwin2k", 0, 0, 'f' }, |
|
{ "filter-A", 0, 0, LOPT_FILTER_A }, |
|
{ "filter-AAAA", 0, 0, LOPT_FILTER_AAAA }, |
{ "pid-file", 2, 0, 'x' }, |
{ "pid-file", 2, 0, 'x' }, |
{ "strict-order", 0, 0, 'o' }, |
{ "strict-order", 0, 0, 'o' }, |
{ "server", 1, 0, 'S' }, |
{ "server", 1, 0, 'S' }, |
Line 212 static const struct myoption opts[] =
|
Line 232 static const struct myoption opts[] =
|
{ "local", 1, 0, LOPT_LOCAL }, |
{ "local", 1, 0, LOPT_LOCAL }, |
{ "address", 1, 0, 'A' }, |
{ "address", 1, 0, 'A' }, |
{ "conf-file", 2, 0, 'C' }, |
{ "conf-file", 2, 0, 'C' }, |
|
{ "conf-script", 1, 0, LOPT_CONF_SCRIPT }, |
{ "no-resolv", 0, 0, 'R' }, |
{ "no-resolv", 0, 0, 'R' }, |
{ "expand-hosts", 0, 0, 'E' }, |
{ "expand-hosts", 0, 0, 'E' }, |
{ "localmx", 0, 0, 'L' }, |
{ "localmx", 0, 0, 'L' }, |
{ "local-ttl", 1, 0, 'T' }, |
{ "local-ttl", 1, 0, 'T' }, |
{ "no-negcache", 0, 0, 'N' }, |
{ "no-negcache", 0, 0, 'N' }, |
|
{ "no-round-robin", 0, 0, LOPT_NORR }, |
{ "addn-hosts", 1, 0, 'H' }, |
{ "addn-hosts", 1, 0, 'H' }, |
{ "hostsdir", 1, 0, LOPT_HOST_INOTIFY }, |
{ "hostsdir", 1, 0, LOPT_HOST_INOTIFY }, |
{ "query-port", 1, 0, 'Q' }, |
{ "query-port", 1, 0, 'Q' }, |
Line 303 static const struct myoption opts[] =
|
Line 325 static const struct myoption opts[] =
|
{ "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES }, |
{ "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES }, |
{ "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND }, |
{ "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND }, |
{ "add-mac", 2, 0, LOPT_ADD_MAC }, |
{ "add-mac", 2, 0, LOPT_ADD_MAC }, |
|
{ "strip-mac", 0, 0, LOPT_STRIP_MAC }, |
{ "add-subnet", 2, 0, LOPT_ADD_SBNET }, |
{ "add-subnet", 2, 0, LOPT_ADD_SBNET }, |
|
{ "strip-subnet", 0, 0, LOPT_STRIP_SBNET }, |
{ "add-cpe-id", 1, 0 , LOPT_CPE_ID }, |
{ "add-cpe-id", 1, 0 , LOPT_CPE_ID }, |
{ "proxy-dnssec", 0, 0, LOPT_DNSSEC }, |
{ "proxy-dnssec", 0, 0, LOPT_DNSSEC }, |
{ "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR }, |
{ "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR }, |
Line 321 static const struct myoption opts[] =
|
Line 345 static const struct myoption opts[] =
|
{ "auth-sec-servers", 1, 0, LOPT_AUTHSFS }, |
{ "auth-sec-servers", 1, 0, LOPT_AUTHSFS }, |
{ "auth-peer", 1, 0, LOPT_AUTHPEER }, |
{ "auth-peer", 1, 0, LOPT_AUTHPEER }, |
{ "ipset", 1, 0, LOPT_IPSET }, |
{ "ipset", 1, 0, LOPT_IPSET }, |
|
{ "nftset", 1, 0, LOPT_NFTSET }, |
|
{ "connmark-allowlist-enable", 2, 0, LOPT_CMARK_ALST_EN }, |
|
{ "connmark-allowlist", 1, 0, LOPT_CMARK_ALST }, |
{ "synth-domain", 1, 0, LOPT_SYNTH }, |
{ "synth-domain", 1, 0, LOPT_SYNTH }, |
{ "dnssec", 0, 0, LOPT_SEC_VALID }, |
{ "dnssec", 0, 0, LOPT_SEC_VALID }, |
{ "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR }, |
{ "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR }, |
Line 341 static const struct myoption opts[] =
|
Line 368 static const struct myoption opts[] =
|
{ "dumpfile", 1, 0, LOPT_DUMPFILE }, |
{ "dumpfile", 1, 0, LOPT_DUMPFILE }, |
{ "dumpmask", 1, 0, LOPT_DUMPMASK }, |
{ "dumpmask", 1, 0, LOPT_DUMPMASK }, |
{ "dhcp-ignore-clid", 0, 0, LOPT_IGNORE_CLID }, |
{ "dhcp-ignore-clid", 0, 0, LOPT_IGNORE_CLID }, |
|
{ "dynamic-host", 1, 0, LOPT_DYNHOST }, |
|
{ "log-debug", 0, 0, LOPT_LOG_DEBUG }, |
|
{ "umbrella", 2, 0, LOPT_UMBRELLA }, |
|
{ "quiet-tftp", 0, 0, LOPT_QUIET_TFTP }, |
|
{ "port-limit", 1, 0, LOPT_RANDPORT_LIM }, |
|
{ "fast-dns-retry", 2, 0, LOPT_FAST_RETRY }, |
|
{ "use-stale-cache", 2, 0 , LOPT_STALE_CACHE }, |
|
{ "no-ident", 0, 0, LOPT_NO_IDENT }, |
{ NULL, 0, 0, 0 } |
{ NULL, 0, 0, 0 } |
}; |
}; |
|
|
Line 368 static struct {
|
Line 403 static struct {
|
{ 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL }, |
{ 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL }, |
{ 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL }, |
{ 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL }, |
{ 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL }, |
{ 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL }, |
|
{ LOPT_FILTER_A, OPT_FILTER_A, NULL, gettext_noop("Don't include IPv4 addresses in DNS answers."), NULL }, |
|
{ LOPT_FILTER_AAAA, OPT_FILTER_AAAA, NULL, gettext_noop("Don't include IPv6 addresses in DNS answers."), NULL }, |
{ 'F', ARG_DUP, "<ipaddr>,...", gettext_noop("Enable DHCP in the range given with lease duration."), NULL }, |
{ 'F', ARG_DUP, "<ipaddr>,...", gettext_noop("Enable DHCP in the range given with lease duration."), NULL }, |
{ 'g', ARG_ONE, "<groupname>", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP }, |
{ 'g', ARG_ONE, "<groupname>", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP }, |
{ 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL }, |
{ 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL }, |
Line 396 static struct {
|
Line 433 static struct {
|
{ 'M', ARG_DUP, "<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL }, |
{ 'M', ARG_DUP, "<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL }, |
{ 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE }, |
{ 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE }, |
{ 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL }, |
{ 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL }, |
|
{ LOPT_STALE_CACHE, ARG_ONE, "[=<max_expired>]", gettext_noop("Use expired cache data for faster reply."), NULL }, |
{ 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE }, |
{ 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE }, |
{ 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL }, |
{ 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL }, |
{ LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL}, |
{ LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL}, |
Line 403 static struct {
|
Line 441 static struct {
|
{ 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" }, |
{ 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" }, |
{ 'q', ARG_DUP, NULL, gettext_noop("Log DNS queries."), NULL }, |
{ 'q', ARG_DUP, NULL, gettext_noop("Log DNS queries."), NULL }, |
{ 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL }, |
{ 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL }, |
|
{ LOPT_RANDPORT_LIM, ARG_ONE, "#ports", gettext_noop("Set maximum number of random originating ports for a query."), NULL }, |
{ 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL }, |
{ 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL }, |
{ 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE }, |
{ 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE }, |
{ LOPT_SERVERS_FILE, ARG_ONE, "<path>", gettext_noop("Specify path to file with server= options"), NULL }, |
{ LOPT_SERVERS_FILE, ARG_ONE, "<path>", gettext_noop("Specify path to file with server= options"), NULL }, |
Line 416 static struct {
|
Line 455 static struct {
|
{ LOPT_MAXTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL }, |
{ LOPT_MAXTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL }, |
{ LOPT_MAXCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live ceiling for cache."), NULL }, |
{ LOPT_MAXCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live ceiling for cache."), NULL }, |
{ LOPT_MINCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live floor for cache."), NULL }, |
{ LOPT_MINCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live floor for cache."), NULL }, |
|
{ LOPT_FAST_RETRY, ARG_ONE, "<milliseconds>", gettext_noop("Retry DNS queries after this many milliseconds."), NULL}, |
{ 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER }, |
{ 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER }, |
{ 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL }, |
{ 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL }, |
{ 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL }, |
{ 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL }, |
Line 443 static struct {
|
Line 483 static struct {
|
{ LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change scripts as this user."), NULL }, |
{ LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change scripts as this user."), NULL }, |
{ LOPT_SCRIPT_ARP, OPT_SCRIPT_ARP, NULL, gettext_noop("Call dhcp-script with changes to local ARP table."), NULL }, |
{ LOPT_SCRIPT_ARP, OPT_SCRIPT_ARP, NULL, gettext_noop("Call dhcp-script with changes to local ARP table."), NULL }, |
{ '7', ARG_DUP, "<path>", gettext_noop("Read configuration from all the files in this directory."), NULL }, |
{ '7', ARG_DUP, "<path>", gettext_noop("Read configuration from all the files in this directory."), NULL }, |
|
{ LOPT_CONF_SCRIPT, ARG_DUP, "<path>", gettext_noop("Execute file and read configuration from stdin."), NULL }, |
{ '8', ARG_ONE, "<facility>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL }, |
{ '8', ARG_ONE, "<facility>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL }, |
{ '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL }, |
{ '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL }, |
{ '0', ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" }, |
{ '0', ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" }, |
Line 481 static struct {
|
Line 522 static struct {
|
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL }, |
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL }, |
{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL }, |
{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL }, |
{ LOPT_ADD_MAC, ARG_DUP, "[=base64|text]", gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL }, |
{ LOPT_ADD_MAC, ARG_DUP, "[=base64|text]", gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL }, |
|
{ LOPT_STRIP_MAC, OPT_STRIP_MAC, NULL, gettext_noop("Strip MAC information from queries."), NULL }, |
{ LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL }, |
{ LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL }, |
|
{ LOPT_STRIP_SBNET, OPT_STRIP_ECS, NULL, gettext_noop("Strip ECS information from queries."), NULL }, |
{ LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client identification to forwarded DNS queries."), NULL }, |
{ LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client identification to forwarded DNS queries."), NULL }, |
{ LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL }, |
{ LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL }, |
{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL }, |
{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL }, |
Line 491 static struct {
|
Line 534 static struct {
|
{ LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL }, |
{ LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL }, |
{ LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL }, |
{ LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL }, |
{ LOPT_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL }, |
{ LOPT_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL }, |
|
{ LOPT_DYNHOST, ARG_DUP, "<name>,[<IPv4>][,<IPv6>],<interface-name>", gettext_noop("Specify host record in interface subnet"), NULL }, |
{ LOPT_CAA, ARG_DUP, "<name>,<flags>,<tag>,<value>", gettext_noop("Specify certification authority authorization record"), NULL }, |
{ LOPT_CAA, ARG_DUP, "<name>,<flags>,<tag>,<value>", gettext_noop("Specify certification authority authorization record"), NULL }, |
{ LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL }, |
{ LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL }, |
{ LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL }, |
{ LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL }, |
Line 501 static struct {
|
Line 545 static struct {
|
{ LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL }, |
{ LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL }, |
{ LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL }, |
{ LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL }, |
{ LOPT_IPSET, ARG_DUP, "/<domain>[/<domain>...]/<ipset>...", gettext_noop("Specify ipsets to which matching domains should be added"), NULL }, |
{ LOPT_IPSET, ARG_DUP, "/<domain>[/<domain>...]/<ipset>...", gettext_noop("Specify ipsets to which matching domains should be added"), NULL }, |
|
{ LOPT_NFTSET, ARG_DUP, "/<domain>[/<domain>...]/<nftset>...", gettext_noop("Specify nftables sets to which matching domains should be added"), NULL }, |
|
{ LOPT_CMARK_ALST_EN, ARG_ONE, "[=<mask>]", gettext_noop("Enable filtering of DNS queries with connection-track marks."), NULL }, |
|
{ LOPT_CMARK_ALST, ARG_DUP, "<connmark>[/<mask>][,<pattern>[/<pattern>...]]", gettext_noop("Set allowed DNS patterns for a connection-track mark."), NULL }, |
{ LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for synthesised names"), NULL }, |
{ LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for synthesised names"), NULL }, |
{ LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL }, |
{ LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL }, |
{ LOPT_TRUST_ANCHOR, ARG_DUP, "<domain>,[<class>],...", gettext_noop("Specify trust anchor key digest."), NULL }, |
{ LOPT_TRUST_ANCHOR, ARG_DUP, "<domain>,[<class>],...", gettext_noop("Specify trust anchor key digest."), NULL }, |
Line 512 static struct {
|
Line 559 static struct {
|
{ LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL }, |
{ LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL }, |
{ LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL }, |
{ LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL }, |
{ LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL }, |
{ LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL }, |
|
{ LOPT_LOG_DEBUG, OPT_LOG_DEBUG, NULL, gettext_noop("Log debugging information."), 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_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops."), NULL }, |
{ LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL }, |
{ LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL }, |
Line 521 static struct {
|
Line 569 static struct {
|
{ LOPT_DUMPFILE, ARG_ONE, "<path>", gettext_noop("Path to debug packet dump file"), NULL }, |
{ LOPT_DUMPFILE, ARG_ONE, "<path>", gettext_noop("Path to debug packet dump file"), NULL }, |
{ LOPT_DUMPMASK, ARG_ONE, "<hex>", gettext_noop("Mask which packets to dump"), NULL }, |
{ LOPT_DUMPMASK, ARG_ONE, "<hex>", gettext_noop("Mask which packets to dump"), NULL }, |
{ LOPT_SCRIPT_TIME, OPT_LEASE_RENEW, NULL, gettext_noop("Call dhcp-script when lease expiry changes."), NULL }, |
{ LOPT_SCRIPT_TIME, OPT_LEASE_RENEW, NULL, gettext_noop("Call dhcp-script when lease expiry changes."), NULL }, |
|
{ LOPT_UMBRELLA, ARG_ONE, "[=<optspec>]", gettext_noop("Send Cisco Umbrella identifiers including remote IP."), NULL }, |
|
{ LOPT_QUIET_TFTP, OPT_QUIET_TFTP, NULL, gettext_noop("Do not log routine TFTP."), NULL }, |
|
{ LOPT_NORR, OPT_NORR, NULL, gettext_noop("Suppress round-robin ordering of DNS records."), NULL }, |
|
{ LOPT_NO_IDENT, OPT_NO_IDENT, NULL, gettext_noop("Do not add CHAOS TXT records."), NULL }, |
{ 0, 0, NULL, NULL, NULL } |
{ 0, 0, NULL, NULL, NULL } |
}; |
}; |
|
|
Line 635 static char *canonicalise_opt(char *s)
|
Line 687 static char *canonicalise_opt(char *s)
|
if (!s) |
if (!s) |
return 0; |
return 0; |
|
|
|
if (strlen(s) == 0) |
|
return opt_malloc(1); /* Heap-allocated empty string */ |
|
|
unhide_metas(s); |
unhide_metas(s); |
if (!(ret = canonicalise(s, &nomem)) && nomem) |
if (!(ret = canonicalise(s, &nomem)) && nomem) |
{ |
{ |
Line 647 static char *canonicalise_opt(char *s)
|
Line 702 static char *canonicalise_opt(char *s)
|
return ret; |
return ret; |
} |
} |
|
|
static int atoi_check(char *a, int *res) | static int numeric_check(char *a) |
{ |
{ |
char *p; |
char *p; |
|
|
Line 660 static int atoi_check(char *a, int *res)
|
Line 715 static int atoi_check(char *a, int *res)
|
if (*p < '0' || *p > '9') |
if (*p < '0' || *p > '9') |
return 0; |
return 0; |
|
|
|
return 1; |
|
} |
|
|
|
static int atoi_check(char *a, int *res) |
|
{ |
|
if (!numeric_check(a)) |
|
return 0; |
*res = atoi(a); |
*res = atoi(a); |
return 1; |
return 1; |
} |
} |
|
|
|
static int strtoul_check(char *a, u32 *res) |
|
{ |
|
unsigned long x; |
|
|
|
if (!numeric_check(a)) |
|
return 0; |
|
x = strtoul(a, NULL, 10); |
|
if (errno || x > UINT32_MAX) { |
|
errno = 0; |
|
return 0; |
|
} |
|
*res = (u32)x; |
|
return 1; |
|
} |
|
|
static int atoi_check16(char *a, int *res) |
static int atoi_check16(char *a, int *res) |
{ |
{ |
if (!(atoi_check(a, res)) || |
if (!(atoi_check(a, res)) || |
Line 755 static void do_usage(void)
|
Line 832 static void do_usage(void)
|
|
|
if (usage[i].arg) |
if (usage[i].arg) |
{ |
{ |
strcpy(buff, usage[i].arg); | safe_strncpy(buff, usage[i].arg, sizeof(buff)); |
for (j = 0; tab[j].handle; j++) |
for (j = 0; tab[j].handle; j++) |
if (tab[j].handle == *(usage[i].arg)) |
if (tab[j].handle == *(usage[i].arg)) |
sprintf(buff, "%d", tab[j].val); |
sprintf(buff, "%d", tab[j].val); |
Line 781 static char *parse_mysockaddr(char *arg, union mysocka
|
Line 858 static char *parse_mysockaddr(char *arg, union mysocka
|
return NULL; |
return NULL; |
} |
} |
|
|
char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags) | char *parse_server(char *arg, struct server_details *sdetails) |
{ |
{ |
int source_port = 0, serv_port = NAMESERVER_PORT; | sdetails->serv_port = NAMESERVER_PORT; |
char *portno, *source; | char *portno; |
char *interface_opt = NULL; | int ecode = 0; |
int scope_index = 0; | struct addrinfo hints; |
char *scope_id; | |
| memset(&hints, 0, sizeof(struct addrinfo)); |
|
|
if (!arg || strlen(arg) == 0) | *sdetails->interface = 0; |
| sdetails->addr_type = AF_UNSPEC; |
| |
| if (strcmp(arg, "#") == 0) |
{ |
{ |
*flags |= SERV_NO_ADDR; | if (sdetails->flags) |
*interface = 0; | *sdetails->flags |= SERV_USE_RESOLV; |
| sdetails->addr_type = AF_LOCAL; |
| sdetails->valid = 1; |
return NULL; |
return NULL; |
} |
} |
| |
if ((source = split_chr(arg, '@')) && /* is there a source. */ | if ((sdetails->source = split_chr(arg, '@')) && /* is there a source. */ |
(portno = split_chr(source, '#')) && | (portno = split_chr(sdetails->source, '#')) && |
!atoi_check16(portno, &source_port)) | !atoi_check16(portno, &sdetails->source_port)) |
return _("bad port"); |
return _("bad port"); |
|
|
if ((portno = split_chr(arg, '#')) && /* is there a port no. */ |
if ((portno = split_chr(arg, '#')) && /* is there a port no. */ |
!atoi_check16(portno, &serv_port)) | !atoi_check16(portno, &sdetails->serv_port)) |
return _("bad port"); |
return _("bad port"); |
|
|
scope_id = split_chr(arg, '%'); | sdetails->scope_id = split_chr(arg, '%'); |
|
|
if (source) { | if (sdetails->source) { |
interface_opt = split_chr(source, '@'); | sdetails->interface_opt = split_chr(sdetails->source, '@'); |
|
|
if (interface_opt) | if (sdetails->interface_opt) |
{ |
{ |
#if defined(SO_BINDTODEVICE) |
#if defined(SO_BINDTODEVICE) |
safe_strncpy(interface, interface_opt, IF_NAMESIZE); | safe_strncpy(sdetails->interface, sdetails->source, IF_NAMESIZE); |
| sdetails->source = sdetails->interface_opt; |
#else |
#else |
return _("interface binding not supported"); |
return _("interface binding not supported"); |
#endif |
#endif |
} |
} |
} |
} |
|
|
if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0) | if (inet_pton(AF_INET, arg, &sdetails->addr->in.sin_addr) > 0) |
| sdetails->addr_type = AF_INET; |
| else if (inet_pton(AF_INET6, arg, &sdetails->addr->in6.sin6_addr) > 0) |
| sdetails->addr_type = AF_INET6; |
| else |
{ |
{ |
addr->in.sin_port = htons(serv_port); | /* if the argument is neither an IPv4 not an IPv6 address, it might be a |
addr->sa.sa_family = source_addr->sa.sa_family = AF_INET; | hostname and we should try to resolve it to a suitable address. */ |
| memset(&hints, 0, sizeof(hints)); |
| /* The AI_ADDRCONFIG flag ensures that then IPv4 addresses are returned in |
| the result only if the local system has at least one IPv4 address |
| configured, and IPv6 addresses are returned only if the local system |
| has at least one IPv6 address configured. The loopback address is not |
| considered for this case as valid as a configured address. This flag is |
| useful on, for example, IPv4-only systems, to ensure that getaddrinfo() |
| does not return IPv6 socket addresses that would always fail in |
| subsequent connect() or bind() attempts. */ |
| hints.ai_flags = AI_ADDRCONFIG; |
| #if defined(HAVE_IDN) && defined(AI_IDN) |
| /* If the AI_IDN flag is specified and we have glibc 2.3.4 or newer, then |
| the node name given in node is converted to IDN format if necessary. |
| The source encoding is that of the current locale. */ |
| hints.ai_flags |= AI_IDN; |
| #endif |
| /* The value AF_UNSPEC indicates that getaddrinfo() should return socket |
| addresses for any address family (either IPv4 or IPv6, for example) |
| that can be used with node <arg> and service "domain". */ |
| hints.ai_family = AF_UNSPEC; |
| |
| /* Get addresses suitable for sending datagrams. We assume that we can use the |
| same addresses for TCP connections. Settting this to zero gets each address |
| threes times, for SOCK_STREAM, SOCK_RAW and SOCK_DGRAM, which is not useful. */ |
| hints.ai_socktype = SOCK_DGRAM; |
| |
| /* Get address associated with this hostname */ |
| ecode = getaddrinfo(arg, NULL, &hints, &sdetails->hostinfo); |
| if (ecode == 0) |
| { |
| /* The getaddrinfo() function allocated and initialized a linked list of |
| addrinfo structures, one for each network address that matches node |
| and service, subject to the restrictions imposed by our <hints> |
| above, and returns a pointer to the start of the list in <hostinfo>. |
| The items in the linked list are linked by the <ai_next> field. */ |
| sdetails->valid = 1; |
| sdetails->orig_hostinfo = sdetails->hostinfo; |
| return NULL; |
| } |
| else |
| { |
| /* Lookup failed, return human readable error string */ |
| if (ecode == EAI_AGAIN) |
| return _("Cannot resolve server name"); |
| else |
| return _((char*)gai_strerror(ecode)); |
| } |
| } |
| |
| sdetails->valid = 1; |
| return NULL; |
| } |
| |
| char *parse_server_addr(struct server_details *sdetails) |
| { |
| if (sdetails->addr_type == AF_INET) |
| { |
| sdetails->addr->in.sin_port = htons(sdetails->serv_port); |
| sdetails->addr->sa.sa_family = sdetails->source_addr->sa.sa_family = AF_INET; |
#ifdef HAVE_SOCKADDR_SA_LEN |
#ifdef HAVE_SOCKADDR_SA_LEN |
source_addr->in.sin_len = addr->in.sin_len = sizeof(struct sockaddr_in); | sdetails->source_addr->in.sin_len = sdetails->addr->in.sin_len = sizeof(struct sockaddr_in); |
#endif |
#endif |
source_addr->in.sin_addr.s_addr = INADDR_ANY; | sdetails->source_addr->in.sin_addr.s_addr = INADDR_ANY; |
source_addr->in.sin_port = htons(daemon->query_port); | sdetails->source_addr->in.sin_port = htons(daemon->query_port); |
|
|
if (source) | if (sdetails->source) |
{ |
{ |
if (flags) | if (sdetails->flags) |
*flags |= SERV_HAS_SOURCE; | *sdetails->flags |= SERV_HAS_SOURCE; |
source_addr->in.sin_port = htons(source_port); | sdetails->source_addr->in.sin_port = htons(sdetails->source_port); |
if (!(inet_pton(AF_INET, source, &source_addr->in.sin_addr) > 0)) | if (inet_pton(AF_INET, sdetails->source, &sdetails->source_addr->in.sin_addr) == 0) |
{ |
{ |
|
if (inet_pton(AF_INET6, sdetails->source, &sdetails->source_addr->in6.sin6_addr) == 1) |
|
{ |
|
sdetails->source_addr->sa.sa_family = AF_INET6; |
|
/* When resolving a server IP by hostname, we can simply skip mismatching |
|
server / source IP pairs. Otherwise, when an IP address is given directly, |
|
this is a fatal error. */ |
|
if (!sdetails->orig_hostinfo) |
|
return _("cannot use IPv4 server address with IPv6 source address"); |
|
} |
|
else |
|
{ |
#if defined(SO_BINDTODEVICE) |
#if defined(SO_BINDTODEVICE) |
if (interface_opt) | if (sdetails->interface_opt) |
return _("interface can only be specified once"); | return _("interface can only be specified once"); |
| |
source_addr->in.sin_addr.s_addr = INADDR_ANY; | sdetails->source_addr->in.sin_addr.s_addr = INADDR_ANY; |
safe_strncpy(interface, source, IF_NAMESIZE); | safe_strncpy(sdetails->interface, sdetails->source, IF_NAMESIZE); |
#else |
#else |
return _("interface binding not supported"); | return _("interface binding not supported"); |
#endif |
#endif |
|
} |
} |
} |
} |
} |
} |
} |
else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0) | else if (sdetails->addr_type == AF_INET6) |
{ |
{ |
if (scope_id && (scope_index = if_nametoindex(scope_id)) == 0) | if (sdetails->scope_id && (sdetails->scope_index = if_nametoindex(sdetails->scope_id)) == 0) |
return _("bad interface name"); |
return _("bad interface name"); |
| |
addr->in6.sin6_port = htons(serv_port); | sdetails->addr->in6.sin6_port = htons(sdetails->serv_port); |
addr->in6.sin6_scope_id = scope_index; | sdetails->addr->in6.sin6_scope_id = sdetails->scope_index; |
source_addr->in6.sin6_addr = in6addr_any; | sdetails->source_addr->in6.sin6_addr = in6addr_any; |
source_addr->in6.sin6_port = htons(daemon->query_port); | sdetails->source_addr->in6.sin6_port = htons(daemon->query_port); |
source_addr->in6.sin6_scope_id = 0; | sdetails->source_addr->in6.sin6_scope_id = 0; |
addr->sa.sa_family = source_addr->sa.sa_family = AF_INET6; | sdetails->addr->sa.sa_family = sdetails->source_addr->sa.sa_family = AF_INET6; |
addr->in6.sin6_flowinfo = source_addr->in6.sin6_flowinfo = 0; | sdetails->addr->in6.sin6_flowinfo = sdetails->source_addr->in6.sin6_flowinfo = 0; |
#ifdef HAVE_SOCKADDR_SA_LEN |
#ifdef HAVE_SOCKADDR_SA_LEN |
addr->in6.sin6_len = source_addr->in6.sin6_len = sizeof(addr->in6); | sdetails->addr->in6.sin6_len = sdetails->source_addr->in6.sin6_len = sizeof(sdetails->addr->in6); |
#endif |
#endif |
if (source) | if (sdetails->source) |
{ |
{ |
if (flags) | if (sdetails->flags) |
*flags |= SERV_HAS_SOURCE; | *sdetails->flags |= SERV_HAS_SOURCE; |
source_addr->in6.sin6_port = htons(source_port); | sdetails->source_addr->in6.sin6_port = htons(sdetails->source_port); |
if (inet_pton(AF_INET6, source, &source_addr->in6.sin6_addr) == 0) | if (inet_pton(AF_INET6, sdetails->source, &sdetails->source_addr->in6.sin6_addr) == 0) |
{ |
{ |
|
if (inet_pton(AF_INET, sdetails->source, &sdetails->source_addr->in.sin_addr) == 1) |
|
{ |
|
sdetails->source_addr->sa.sa_family = AF_INET; |
|
/* When resolving a server IP by hostname, we can simply skip mismatching |
|
server / source IP pairs. Otherwise, when an IP address is given directly, |
|
this is a fatal error. */ |
|
if(!sdetails->orig_hostinfo) |
|
return _("cannot use IPv6 server address with IPv4 source address"); |
|
} |
|
else |
|
{ |
#if defined(SO_BINDTODEVICE) |
#if defined(SO_BINDTODEVICE) |
if (interface_opt) | if (sdetails->interface_opt) |
return _("interface can only be specified once"); | return _("interface can only be specified once"); |
| |
source_addr->in6.sin6_addr = in6addr_any; | sdetails->source_addr->in6.sin6_addr = in6addr_any; |
safe_strncpy(interface, source, IF_NAMESIZE); | safe_strncpy(sdetails->interface, sdetails->source, IF_NAMESIZE); |
#else |
#else |
return _("interface binding not supported"); | return _("interface binding not supported"); |
#endif |
#endif |
|
} |
} |
} |
} |
} |
} |
} |
else | else if (sdetails->addr_type != AF_LOCAL) |
return _("bad address"); |
return _("bad address"); |
| |
return NULL; |
return NULL; |
} |
} |
|
|
static struct server *add_rev4(struct in_addr addr, int msize) | int parse_server_next(struct server_details *sdetails) |
{ |
{ |
struct server *serv = opt_malloc(sizeof(struct server)); | /* Looping over resolved addresses? */ |
in_addr_t a = ntohl(addr.s_addr); | if (sdetails->hostinfo) |
char *p; | { |
| /* Get address type */ |
| sdetails->addr_type = sdetails->hostinfo->ai_family; |
|
|
memset(serv, 0, sizeof(struct server)); | /* Get address */ |
p = serv->domain = opt_malloc(29); /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */ | if (sdetails->addr_type == AF_INET) |
| memcpy(&sdetails->addr->in.sin_addr, |
| &((struct sockaddr_in *) sdetails->hostinfo->ai_addr)->sin_addr, |
| sizeof(sdetails->addr->in.sin_addr)); |
| else if (sdetails->addr_type == AF_INET6) |
| memcpy(&sdetails->addr->in6.sin6_addr, |
| &((struct sockaddr_in6 *) sdetails->hostinfo->ai_addr)->sin6_addr, |
| sizeof(sdetails->addr->in6.sin6_addr)); |
|
|
switch (msize) | /* Iterate to the next available address */ |
| sdetails->valid = sdetails->hostinfo->ai_next != NULL; |
| sdetails->hostinfo = sdetails->hostinfo->ai_next; |
| return 1; |
| } |
| else if (sdetails->valid) |
{ |
{ |
case 32: | /* When using an IP address, we return the address only once */ |
p += sprintf(p, "%u.", a & 0xff); | sdetails->valid = 0; |
/* fall through */ | return 1; |
case 24: | |
p += sprintf(p, "%d.", (a >> 8) & 0xff); | |
/* fall through */ | |
case 16: | |
p += sprintf(p, "%d.", (a >> 16) & 0xff); | |
/* fall through */ | |
case 8: | |
p += sprintf(p, "%d.", (a >> 24) & 0xff); | |
break; | |
default: | |
free(serv->domain); | |
free(serv); | |
return NULL; | |
} |
} |
|
/* Stop iterating here, we used all available addresses */ |
|
return 0; |
|
} |
|
|
p += sprintf(p, "in-addr.arpa"); | static char *domain_rev4(int from_file, char *server, struct in_addr *addr4, int size) |
| { |
| int i, j; |
| char *string; |
| int msize; |
| u16 flags = 0; |
| char domain[29]; /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */ |
| union mysockaddr serv_addr, source_addr; |
| char interface[IF_NAMESIZE+1]; |
| int count = 1, rem, addrbytes, addrbits; |
| struct server_details sdetails; |
| |
| memset(&sdetails, 0, sizeof(struct server_details)); |
| sdetails.addr = &serv_addr; |
| sdetails.source_addr = &source_addr; |
| sdetails.interface = interface; |
| sdetails.flags = &flags; |
| |
| if (!server) |
| flags = SERV_LITERAL_ADDRESS; |
| else if ((string = parse_server(server, &sdetails))) |
| return string; |
|
|
serv->flags = SERV_HAS_DOMAIN; | if (from_file) |
serv->next = daemon->servers; | flags |= SERV_FROM_FILE; |
daemon->servers = serv; | |
| rem = size & 0x7; |
| addrbytes = (32 - size) >> 3; |
| addrbits = (32 - size) & 7; |
| |
| if (size > 32 || size < 1) |
| return _("bad IPv4 prefix length"); |
| |
| /* Zero out last address bits according to CIDR mask */ |
| ((u8 *)addr4)[3-addrbytes] &= ~((1 << addrbits)-1); |
| |
| size = size & ~0x7; |
| |
| if (rem != 0) |
| count = 1 << (8 - rem); |
| |
| for (i = 0; i < count; i++) |
| { |
| *domain = 0; |
| string = domain; |
| msize = size/8; |
| |
| for (j = (rem == 0) ? msize-1 : msize; j >= 0; j--) |
| { |
| int dig = ((unsigned char *)addr4)[j]; |
| |
| if (j == msize) |
| dig += i; |
| |
| string += sprintf(string, "%d.", dig); |
| } |
| |
| sprintf(string, "in-addr.arpa"); |
|
|
return serv; | if (flags & SERV_LITERAL_ADDRESS) |
| { |
| if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL)) |
| return _("error"); |
| } |
| else |
| { |
| /* Always reset server as valid here, so we can add the same upstream |
| server address multiple times for each x.y.z.in-addr.arpa */ |
| sdetails.valid = 1; |
| while (parse_server_next(&sdetails)) |
| { |
| if ((string = parse_server_addr(&sdetails))) |
| return string; |
| |
| if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL)) |
| return _("error"); |
| } |
|
|
|
if (sdetails.orig_hostinfo) |
|
freeaddrinfo(sdetails.orig_hostinfo); |
|
} |
|
} |
|
|
|
return NULL; |
} |
} |
|
|
static struct server *add_rev6(struct in6_addr *addr, int msize) | static char *domain_rev6(int from_file, char *server, struct in6_addr *addr6, int size) |
{ |
{ |
struct server *serv = opt_malloc(sizeof(struct server)); | int i, j; |
char *p; | char *string; |
int i; | int msize; |
| u16 flags = 0; |
memset(serv, 0, sizeof(struct server)); | char domain[73]; /* strlen("32*<n.>ip6.arpa")+1 */ |
p = serv->domain = opt_malloc(73); /* strlen("32*<n.>ip6.arpa")+1 */ | union mysockaddr serv_addr, source_addr; |
| char interface[IF_NAMESIZE+1]; |
| int count = 1, rem, addrbytes, addrbits; |
| struct server_details sdetails; |
|
|
for (i = msize-1; i >= 0; i -= 4) | memset(&sdetails, 0, sizeof(struct server_details)); |
{ | sdetails.addr = &serv_addr; |
int dig = ((unsigned char *)addr)[i>>3]; | sdetails.source_addr = &source_addr; |
p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4); | sdetails.interface = interface; |
} | sdetails.flags = &flags; |
p += sprintf(p, "ip6.arpa"); | |
| if (!server) |
| flags = SERV_LITERAL_ADDRESS; |
| else if ((string = parse_server(server, &sdetails))) |
| return string; |
| |
| if (from_file) |
| flags |= SERV_FROM_FILE; |
|
|
serv->flags = SERV_HAS_DOMAIN; | rem = size & 0x3; |
serv->next = daemon->servers; | addrbytes = (128 - size) >> 3; |
daemon->servers = serv; | addrbits = (128 - size) & 7; |
|
|
return serv; | if (size > 128 || size < 1) |
| return _("bad IPv6 prefix length"); |
| |
| /* Zero out last address bits according to CIDR mask */ |
| addr6->s6_addr[15-addrbytes] &= ~((1 << addrbits) - 1); |
| |
| size = size & ~0x3; |
| |
| if (rem != 0) |
| count = 1 << (4 - rem); |
| |
| for (i = 0; i < count; i++) |
| { |
| *domain = 0; |
| string = domain; |
| msize = size/4; |
| |
| for (j = (rem == 0) ? msize-1 : msize; j >= 0; j--) |
| { |
| int dig = ((unsigned char *)addr6)[j>>1]; |
| |
| dig = j & 1 ? dig & 15 : dig >> 4; |
| |
| if (j == msize) |
| dig += i; |
| |
| string += sprintf(string, "%.1x.", dig); |
| } |
| |
| sprintf(string, "ip6.arpa"); |
| |
| if (flags & SERV_LITERAL_ADDRESS) |
| { |
| if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL)) |
| return _("error"); |
| } |
| else |
| { |
| /* Always reset server as valid here, so we can add the same upstream |
| server address multiple times for each x.y.z.ip6.arpa */ |
| sdetails.valid = 1; |
| while (parse_server_next(&sdetails)) |
| { |
| if ((string = parse_server_addr(&sdetails))) |
| return string; |
| |
| if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL)) |
| return _("error"); |
| } |
| |
| if (sdetails.orig_hostinfo) |
| freeaddrinfo(sdetails.orig_hostinfo); |
| } |
| } |
| |
| return NULL; |
} |
} |
|
|
#ifdef HAVE_DHCP |
#ifdef HAVE_DHCP |
Line 1038 static void dhcp_config_free(struct dhcp_config *confi
|
Line 1354 static void dhcp_config_free(struct dhcp_config *confi
|
|
|
if (config->flags & CONFIG_CLID) |
if (config->flags & CONFIG_CLID) |
free(config->clid); |
free(config->clid); |
|
if (config->flags & CONFIG_NAME) |
|
free(config->hostname); |
|
|
#ifdef HAVE_DHCP6 |
#ifdef HAVE_DHCP6 |
if (config->flags & CONFIG_ADDR6) |
if (config->flags & CONFIG_ADDR6) |
Line 1154 static int parse_dhcp_opt(char *errstr, char *arg, int
|
Line 1472 static int parse_dhcp_opt(char *errstr, char *arg, int
|
{ |
{ |
new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7); |
new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7); |
new->flags |= DHOPT_VENDOR; |
new->flags |= DHOPT_VENDOR; |
|
if ((new->flags & DHOPT_ENCAPSULATE) || flags == DHOPT_MATCH) |
|
goto_err(_("inappropriate vendor:")); |
} |
} |
else if (strstr(arg, "encap:") == arg) |
else if (strstr(arg, "encap:") == arg) |
{ |
{ |
new->u.encap = atoi(arg+6); |
new->u.encap = atoi(arg+6); |
new->flags |= DHOPT_ENCAPSULATE; |
new->flags |= DHOPT_ENCAPSULATE; |
|
if ((new->flags & DHOPT_VENDOR) || flags == DHOPT_MATCH) |
|
goto_err(_("inappropriate encap:")); |
} |
} |
else if (strstr(arg, "vi-encap:") == arg) |
else if (strstr(arg, "vi-encap:") == arg) |
{ |
{ |
Line 1633 void reset_option_bool(unsigned int opt)
|
Line 1955 void reset_option_bool(unsigned int opt)
|
option_var(opt) &= ~(option_val(opt)); |
option_var(opt) &= ~(option_val(opt)); |
} |
} |
|
|
static void server_list_free(struct server *list) |
|
{ |
|
while (list) |
|
{ |
|
struct server *tmp = list; |
|
list = list->next; |
|
free(tmp); |
|
} |
|
} |
|
|
|
static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only) |
static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only) |
{ |
{ |
int i; |
int i; |
Line 1695 static int one_opt(int option, char *arg, char *errstr
|
Line 2007 static int one_opt(int option, char *arg, char *errstr
|
break; |
break; |
} |
} |
|
|
|
case LOPT_CONF_SCRIPT: /* --conf-script */ |
|
{ |
|
char *file = opt_string_alloc(arg); |
|
if (file) |
|
{ |
|
one_file(file, LOPT_CONF_SCRIPT); |
|
free(file); |
|
} |
|
break; |
|
} |
|
|
case '7': /* --conf-dir */ |
case '7': /* --conf-dir */ |
{ |
{ |
DIR *dir_stream; |
DIR *dir_stream; |
Line 1801 static int one_opt(int option, char *arg, char *errstr
|
Line 2124 static int one_opt(int option, char *arg, char *errstr
|
new->next = li; |
new->next = li; |
*up = new; |
*up = new; |
} |
} |
|
else |
|
free(path); |
|
|
} |
} |
|
|
Line 1967 static int one_opt(int option, char *arg, char *errstr
|
Line 2292 static int one_opt(int option, char *arg, char *errstr
|
|
|
if (!(name = canonicalise_opt(arg)) || |
if (!(name = canonicalise_opt(arg)) || |
(comma && !(target = canonicalise_opt(comma)))) |
(comma && !(target = canonicalise_opt(comma)))) |
ret_err(_("bad MX name")); | { |
| free(name); |
| free(target); |
| ret_err(_("bad MX name")); |
| } |
|
|
new = opt_malloc(sizeof(struct mx_srv_record)); |
new = opt_malloc(sizeof(struct mx_srv_record)); |
new->next = daemon->mxnames; |
new->next = daemon->mxnames; |
Line 2017 static int one_opt(int option, char *arg, char *errstr
|
Line 2346 static int one_opt(int option, char *arg, char *errstr
|
|
|
case LOPT_DHCP_HOST: /* --dhcp-hostsfile */ |
case LOPT_DHCP_HOST: /* --dhcp-hostsfile */ |
case LOPT_DHCP_OPTS: /* --dhcp-optsfile */ |
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 */ |
case 'H': /* --addn-hosts */ |
{ |
{ |
struct hostsfile *new = opt_malloc(sizeof(struct hostsfile)); |
struct hostsfile *new = opt_malloc(sizeof(struct hostsfile)); |
static unsigned int hosts_index = SRC_AH; |
|
new->fname = opt_string_alloc(arg); |
new->fname = opt_string_alloc(arg); |
new->index = hosts_index++; | new->index = daemon->host_index++; |
new->flags = 0; |
new->flags = 0; |
if (option == 'H') |
if (option == 'H') |
{ |
{ |
Line 2041 static int one_opt(int option, char *arg, char *errstr
|
Line 2366 static int one_opt(int option, char *arg, char *errstr
|
{ |
{ |
new->next = daemon->dhcp_opts_file; |
new->next = daemon->dhcp_opts_file; |
daemon->dhcp_opts_file = new; |
daemon->dhcp_opts_file = new; |
} |
|
else |
|
{ |
|
new->next = daemon->dynamic_dirs; |
|
daemon->dynamic_dirs = new; |
|
if (option == LOPT_DHCP_INOTIFY) |
|
new->flags |= AH_DHCP_HST; |
|
else if (option == LOPT_DHOPT_INOTIFY) |
|
new->flags |= AH_DHCP_OPT; |
|
else if (option == LOPT_HOST_INOTIFY) |
|
new->flags |= AH_HOSTS; |
|
} |
} |
|
|
break; |
break; |
} |
} |
|
|
|
case LOPT_DHCP_INOTIFY: /* --dhcp-hostsdir */ |
|
case LOPT_DHOPT_INOTIFY: /* --dhcp-optsdir */ |
|
case LOPT_HOST_INOTIFY: /* --hostsdir */ |
|
{ |
|
struct dyndir *new = opt_malloc(sizeof(struct dyndir)); |
|
new->dname = opt_string_alloc(arg); |
|
new->flags = 0; |
|
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; |
|
} |
|
|
case LOPT_AUTHSERV: /* --auth-server */ |
case LOPT_AUTHSERV: /* --auth-server */ |
comma = split(arg); |
comma = split(arg); |
Line 2118 static int one_opt(int option, char *arg, char *errstr
|
Line 2451 static int one_opt(int option, char *arg, char *errstr
|
comma = split(arg); |
comma = split(arg); |
|
|
new = opt_malloc(sizeof(struct auth_zone)); |
new = opt_malloc(sizeof(struct auth_zone)); |
new->domain = opt_string_alloc(arg); | new->domain = canonicalise_opt(arg); |
new->subnet = NULL; | if (!new->domain) |
| ret_err_free(_("invalid auth-zone"), new); |
| new->subnet = NULL; |
new->exclude = NULL; |
new->exclude = NULL; |
new->interface_names = NULL; |
new->interface_names = NULL; |
new->next = daemon->auth_zones; |
new->next = daemon->auth_zones; |
Line 2203 static int one_opt(int option, char *arg, char *errstr
|
Line 2538 static int one_opt(int option, char *arg, char *errstr
|
arg = comma; |
arg = comma; |
comma = split(arg); |
comma = split(arg); |
daemon->hostmaster = opt_string_alloc(arg); |
daemon->hostmaster = opt_string_alloc(arg); |
for (cp = daemon->hostmaster; *cp; cp++) | for (cp = daemon->hostmaster; cp && *cp; cp++) |
if (*cp == '@') |
if (*cp == '@') |
*cp = '.'; |
*cp = '.'; |
|
|
Line 2231 static int one_opt(int option, char *arg, char *errstr
|
Line 2566 static int one_opt(int option, char *arg, char *errstr
|
set_option_bool(OPT_RESOLV_DOMAIN); |
set_option_bool(OPT_RESOLV_DOMAIN); |
else |
else |
{ |
{ |
char *d; | char *d, *d_raw = arg; |
comma = split(arg); |
comma = split(arg); |
if (!(d = canonicalise_opt(arg))) | if (!(d = canonicalise_opt(d_raw))) |
ret_err(gen_err); |
ret_err(gen_err); |
else |
else |
{ |
{ |
|
free(d); /* allocate this again below. */ |
if (comma) |
if (comma) |
{ |
{ |
struct cond_domain *new = opt_malloc(sizeof(struct cond_domain)); |
struct cond_domain *new = opt_malloc(sizeof(struct cond_domain)); |
Line 2244 static int one_opt(int option, char *arg, char *errstr
|
Line 2580 static int one_opt(int option, char *arg, char *errstr
|
|
|
new->prefix = NULL; |
new->prefix = NULL; |
new->indexed = 0; |
new->indexed = 0; |
|
new->prefixlen = 0; |
|
|
unhide_metas(comma); |
unhide_metas(comma); |
if ((netpart = split_chr(comma, '/'))) |
if ((netpart = split_chr(comma, '/'))) |
Line 2255 static int one_opt(int option, char *arg, char *errstr
|
Line 2592 static int one_opt(int option, char *arg, char *errstr
|
ret_err_free(gen_err, new); |
ret_err_free(gen_err, new); |
else if (inet_pton(AF_INET, comma, &new->start)) |
else if (inet_pton(AF_INET, comma, &new->start)) |
{ |
{ |
int mask = (1 << (32 - msize)) - 1; | int mask; |
| |
| if (msize > 32) |
| ret_err_free(_("bad prefix length"), new); |
| |
| mask = (1 << (32 - msize)) - 1; |
new->is6 = 0; |
new->is6 = 0; |
new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask); |
new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask); |
new->end.s_addr = new->start.s_addr | htonl(mask); |
new->end.s_addr = new->start.s_addr | htonl(mask); |
Line 2267 static int one_opt(int option, char *arg, char *errstr
|
Line 2609 static int one_opt(int option, char *arg, char *errstr
|
strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN) |
strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN) |
ret_err_free(_("bad prefix"), new); |
ret_err_free(_("bad prefix"), new); |
} |
} |
else if (strcmp(arg, "local") != 0 || | else if (strcmp(arg, "local") != 0) |
(msize != 8 && msize != 16 && msize != 24)) | |
ret_err_free(gen_err, new); |
ret_err_free(gen_err, new); |
else |
else |
{ |
{ |
/* generate the equivalent of | /* local=/xxx.yyy.zzz.in-addr.arpa/ */ |
local=/xxx.yyy.zzz.in-addr.arpa/ */ | domain_rev4(0, NULL, &new->start, msize); |
struct server *serv = add_rev4(new->start, msize); | |
if (!serv) | |
ret_err_free(_("bad prefix"), new); | |
| |
serv->flags |= SERV_NO_ADDR; | |
| |
/* local=/<domain>/ */ |
/* local=/<domain>/ */ |
serv = opt_malloc(sizeof(struct server)); | /* d_raw can't failed to canonicalise here, checked above. */ |
memset(serv, 0, sizeof(struct server)); | add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, d_raw, NULL); |
serv->domain = d; | |
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR; | |
serv->next = daemon->servers; | |
daemon->servers = serv; | |
} |
} |
} |
} |
} |
} |
else if (inet_pton(AF_INET6, comma, &new->start6)) |
else if (inet_pton(AF_INET6, comma, &new->start6)) |
{ |
{ |
u64 mask = (1LLU << (128 - msize)) - 1LLU; | u64 mask, addrpart = addr6part(&new->start6); |
u64 addrpart = addr6part(&new->start6); | |
| if (msize > 128) |
| ret_err_free(_("bad prefix length"), new); |
| |
| mask = (1LLU << (128 - msize)) - 1LLU; |
| |
new->is6 = 1; |
new->is6 = 1; |
|
new->prefixlen = msize; |
|
|
/* prefix==64 overflows the mask calculation above */ |
/* prefix==64 overflows the mask calculation above */ |
if (msize == 64) | if (msize <= 64) |
mask = (u64)-1LL; |
mask = (u64)-1LL; |
|
|
new->end6 = new->start6; |
new->end6 = new->start6; |
setaddr6part(&new->start6, addrpart & ~mask); |
setaddr6part(&new->start6, addrpart & ~mask); |
setaddr6part(&new->end6, addrpart | mask); |
setaddr6part(&new->end6, addrpart | mask); |
|
|
if (msize < 64) | if (arg) |
ret_err_free(gen_err, new); | |
else if (arg) | |
{ |
{ |
if (option != 's') |
if (option != 's') |
{ |
{ |
Line 2314 static int one_opt(int option, char *arg, char *errstr
|
Line 2650 static int one_opt(int option, char *arg, char *errstr
|
strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN) |
strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN) |
ret_err_free(_("bad prefix"), new); |
ret_err_free(_("bad prefix"), new); |
} |
} |
else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0)) | else if (strcmp(arg, "local") != 0) |
ret_err_free(gen_err, new); |
ret_err_free(gen_err, new); |
else |
else |
{ |
{ |
/* generate the equivalent of |
/* generate the equivalent of |
local=/xxx.yyy.zzz.ip6.arpa/ */ |
local=/xxx.yyy.zzz.ip6.arpa/ */ |
struct server *serv = add_rev6(&new->start6, msize); | domain_rev6(0, NULL, &new->start6, msize); |
serv->flags |= SERV_NO_ADDR; | |
|
|
/* local=/<domain>/ */ |
/* local=/<domain>/ */ |
serv = opt_malloc(sizeof(struct server)); | /* d_raw can't failed to canonicalise here, checked above. */ |
memset(serv, 0, sizeof(struct server)); | add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, d_raw, NULL); |
serv->domain = d; | |
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR; | |
serv->next = daemon->servers; | |
daemon->servers = serv; | |
} |
} |
} |
} |
} |
} |
Line 2358 static int one_opt(int option, char *arg, char *errstr
|
Line 2689 static int one_opt(int option, char *arg, char *errstr
|
else if (!inet_pton(AF_INET6, arg, &new->end6)) |
else if (!inet_pton(AF_INET6, arg, &new->end6)) |
ret_err_free(gen_err, new); |
ret_err_free(gen_err, new); |
} |
} |
else | else if (option == 's') |
| { |
| /* subnet from interface. */ |
| new->interface = opt_string_alloc(comma); |
| new->al = NULL; |
| } |
| else |
ret_err_free(gen_err, new); |
ret_err_free(gen_err, new); |
| |
if (option != 's' && prefstr) |
if (option != 's' && prefstr) |
{ |
{ |
if (!(new->prefix = canonicalise_opt(prefstr)) || |
if (!(new->prefix = canonicalise_opt(prefstr)) || |
Line 2369 static int one_opt(int option, char *arg, char *errstr
|
Line 2706 static int one_opt(int option, char *arg, char *errstr
|
} |
} |
} |
} |
|
|
new->domain = d; | new->domain = canonicalise_opt(d_raw); |
if (option == 's') |
if (option == 's') |
{ |
{ |
new->next = daemon->cond_domain; |
new->next = daemon->cond_domain; |
Line 2378 static int one_opt(int option, char *arg, char *errstr
|
Line 2715 static int one_opt(int option, char *arg, char *errstr
|
else |
else |
{ |
{ |
char *star; |
char *star; |
new->next = daemon->synth_domains; |
|
daemon->synth_domains = new; |
|
if (new->prefix && |
if (new->prefix && |
(star = strrchr(new->prefix, '*')) |
(star = strrchr(new->prefix, '*')) |
&& *(star+1) == 0) |
&& *(star+1) == 0) |
{ |
{ |
*star = 0; |
*star = 0; |
new->indexed = 1; |
new->indexed = 1; |
|
if (new->is6 && new->prefixlen < 64) |
|
ret_err_free(_("prefix length too small"), new); |
} |
} |
|
new->next = daemon->synth_domains; |
|
daemon->synth_domains = new; |
} |
} |
} |
} |
else if (option == 's') |
else if (option == 's') |
daemon->domain_suffix = d; | daemon->domain_suffix = canonicalise_opt(d_raw); |
else |
else |
ret_err(gen_err); |
ret_err(gen_err); |
} |
} |
Line 2402 static int one_opt(int option, char *arg, char *errstr
|
Line 2741 static int one_opt(int option, char *arg, char *errstr
|
daemon->dns_client_id = opt_string_alloc(arg); |
daemon->dns_client_id = opt_string_alloc(arg); |
break; |
break; |
|
|
|
case LOPT_UMBRELLA: /* --umbrella */ |
|
set_option_bool(OPT_UMBRELLA); |
|
while (arg) |
|
{ |
|
comma = split(arg); |
|
if (strstr(arg, "deviceid:")) |
|
{ |
|
char *p; |
|
u8 *u = daemon->umbrella_device; |
|
char word[3]; |
|
|
|
arg += 9; |
|
if (strlen(arg) != 16) |
|
ret_err(gen_err); |
|
|
|
for (p = arg; *p; p++) |
|
if (!isxdigit((unsigned char)*p)) |
|
ret_err(gen_err); |
|
|
|
set_option_bool(OPT_UMBRELLA_DEVID); |
|
|
|
for (i = 0; i < (int)sizeof(daemon->umbrella_device); i++, arg+=2) |
|
{ |
|
memcpy(word, &(arg[0]), 2); |
|
*u++ = strtoul(word, NULL, 16); |
|
} |
|
} |
|
else if (strstr(arg, "orgid:")) |
|
{ |
|
if (!strtoul_check(arg+6, &daemon->umbrella_org)) |
|
ret_err(gen_err); |
|
} |
|
else if (strstr(arg, "assetid:")) |
|
{ |
|
if (!strtoul_check(arg+8, &daemon->umbrella_asset)) |
|
ret_err(gen_err); |
|
} |
|
else |
|
ret_err(gen_err); |
|
|
|
arg = comma; |
|
} |
|
break; |
|
|
case LOPT_ADD_MAC: /* --add-mac */ |
case LOPT_ADD_MAC: /* --add-mac */ |
if (!arg) |
if (!arg) |
set_option_bool(OPT_ADD_MAC); |
set_option_bool(OPT_ADD_MAC); |
Line 2480 static int one_opt(int option, char *arg, char *errstr
|
Line 2863 static int one_opt(int option, char *arg, char *errstr
|
case 'B': /* --bogus-nxdomain */ |
case 'B': /* --bogus-nxdomain */ |
case LOPT_IGNORE_ADDR: /* --ignore-address */ |
case LOPT_IGNORE_ADDR: /* --ignore-address */ |
{ |
{ |
struct in_addr addr; | union all_addr addr; |
| int prefix, is6 = 0; |
| struct bogus_addr *baddr; |
| |
unhide_metas(arg); |
unhide_metas(arg); |
if (arg && (inet_pton(AF_INET, arg, &addr) > 0)) | |
| if (!arg || |
| ((comma = split_chr(arg, '/')) && !atoi_check(comma, &prefix))) |
| ret_err(gen_err); |
| |
| if (inet_pton(AF_INET6, arg, &addr.addr6) == 1) |
| is6 = 1; |
| else if (inet_pton(AF_INET, arg, &addr.addr4) != 1) |
| ret_err(gen_err); |
| |
| if (!comma) |
{ |
{ |
struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr)); | if (is6) |
if (option == 'B') | prefix = 128; |
{ | |
baddr->next = daemon->bogus_addr; | |
daemon->bogus_addr = baddr; | |
} | |
else |
else |
{ | prefix = 32; |
baddr->next = daemon->ignore_addr; | |
daemon->ignore_addr = baddr; | |
} | |
baddr->addr = addr; | |
} |
} |
|
|
|
if (prefix > 128 || (!is6 && prefix > 32)) |
|
ret_err(gen_err); |
|
|
|
baddr = opt_malloc(sizeof(struct bogus_addr)); |
|
if (option == 'B') |
|
{ |
|
baddr->next = daemon->bogus_addr; |
|
daemon->bogus_addr = baddr; |
|
} |
else |
else |
ret_err(gen_err); /* error */ | { |
break; | baddr->next = daemon->ignore_addr; |
} | daemon->ignore_addr = baddr; |
| } |
| |
| baddr->prefix = prefix; |
| baddr->is6 = is6; |
| baddr->addr = addr; |
| break; |
| } |
|
|
case 'a': /* --listen-address */ |
case 'a': /* --listen-address */ |
case LOPT_AUTHPEER: /* --auth-peer */ |
case LOPT_AUTHPEER: /* --auth-peer */ |
Line 2544 static int one_opt(int option, char *arg, char *errstr
|
Line 2949 static int one_opt(int option, char *arg, char *errstr
|
} while (arg); |
} while (arg); |
break; |
break; |
|
|
|
case LOPT_NO_REBIND: /* --rebind-domain-ok */ |
|
{ |
|
struct rebind_domain *new; |
|
|
|
unhide_metas(arg); |
|
|
|
if (*arg == '/') |
|
arg++; |
|
|
|
do { |
|
comma = split_chr(arg, '/'); |
|
new = opt_malloc(sizeof(struct rebind_domain)); |
|
new->domain = canonicalise_opt(arg); |
|
new->next = daemon->no_rebind; |
|
daemon->no_rebind = new; |
|
arg = comma; |
|
} while (arg && *arg); |
|
|
|
break; |
|
} |
|
|
case 'S': /* --server */ |
case 'S': /* --server */ |
case LOPT_LOCAL: /* --local */ |
case LOPT_LOCAL: /* --local */ |
case 'A': /* --address */ |
case 'A': /* --address */ |
case LOPT_NO_REBIND: /* --rebind-domain-ok */ |
|
{ |
{ |
struct server *serv, *newlist = NULL; | char *lastdomain = NULL, *domain = "", *cur_domain; |
| u16 flags = 0; |
| char *err; |
| union all_addr addr; |
| union mysockaddr serv_addr, source_addr; |
| char interface[IF_NAMESIZE+1]; |
| struct server_details sdetails; |
| |
| memset(&sdetails, 0, sizeof(struct server_details)); |
| sdetails.addr = &serv_addr; |
| sdetails.source_addr = &source_addr; |
| sdetails.interface = interface; |
| sdetails.flags = &flags; |
| |
unhide_metas(arg); |
unhide_metas(arg); |
|
|
if (arg && (*arg == '/' || option == LOPT_NO_REBIND)) | /* split the domain args, if any and skip to the end of them. */ |
| if (arg && *arg == '/') |
{ |
{ |
int rebind = !(*arg == '/'); | char *last; |
char *end = NULL; | |
if (!rebind) | domain = lastdomain = ++arg; |
arg++; | |
while (rebind || (end = split_chr(arg, '/'))) | while ((last = split_chr(arg, '/'))) |
{ |
{ |
char *domain = NULL; | lastdomain = arg; |
/* elide leading dots - they are implied in the search algorithm */ | arg = last; |
while (*arg == '.') arg++; | |
/* # matches everything and becomes a zero length domain string */ | |
if (strcmp(arg, "#") == 0) | |
domain = ""; | |
else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg))) | |
ret_err(gen_err); | |
serv = opt_malloc(sizeof(struct server)); | |
memset(serv, 0, sizeof(struct server)); | |
serv->next = newlist; | |
newlist = serv; | |
serv->domain = domain; | |
serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS; | |
arg = end; | |
if (rebind) | |
break; | |
} |
} |
if (!newlist) |
|
ret_err(gen_err); |
|
} |
} |
else |
|
{ |
|
newlist = opt_malloc(sizeof(struct server)); |
|
memset(newlist, 0, sizeof(struct server)); |
|
#ifdef HAVE_LOOP |
|
newlist->uid = rand32(); |
|
#endif |
|
} |
|
|
|
if (servers_only && option == 'S') | if (!arg || !*arg) |
newlist->flags |= SERV_FROM_FILE; | flags = SERV_LITERAL_ADDRESS; |
| else if (option == 'A') |
if (option == 'A') | |
{ |
{ |
newlist->flags |= SERV_LITERAL_ADDRESS; | /* # as literal address means return zero address for 4 and 6 */ |
if (!(newlist->flags & SERV_TYPE)) | if (strcmp(arg, "#") == 0) |
{ | flags = SERV_ALL_ZEROS | SERV_LITERAL_ADDRESS; |
server_list_free(newlist); | else if (inet_pton(AF_INET, arg, &addr.addr4) > 0) |
ret_err(gen_err); | flags = SERV_4ADDR | SERV_LITERAL_ADDRESS; |
} | else if (inet_pton(AF_INET6, arg, &addr.addr6) > 0) |
| flags = SERV_6ADDR | SERV_LITERAL_ADDRESS; |
| else |
| ret_err(_("Bad address in --address")); |
} |
} |
else if (option == LOPT_NO_REBIND) | else |
newlist->flags |= SERV_NO_REBIND; | |
| |
if (!arg || !*arg) | |
{ |
{ |
if (!(newlist->flags & SERV_NO_REBIND)) | if ((err = parse_server(arg, &sdetails))) |
newlist->flags |= SERV_NO_ADDR; /* no server */ | ret_err(err); |
} |
} |
|
|
else if (strcmp(arg, "#") == 0) | if (servers_only && option == 'S') |
newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */ | flags |= SERV_FROM_FILE; |
else | |
| cur_domain = domain; |
| while ((flags & SERV_LITERAL_ADDRESS) || parse_server_next(&sdetails)) |
{ |
{ |
char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags); | cur_domain = domain; |
if (err) | |
| if (!(flags & SERV_LITERAL_ADDRESS) && (err = parse_server_addr(&sdetails))) |
| ret_err(err); |
| |
| /* When source is set only use DNS records of the same type and skip all others */ |
| if (flags & SERV_HAS_SOURCE && sdetails.addr_type != sdetails.source_addr->sa.sa_family) |
| continue; |
| |
| while (1) |
{ |
{ |
server_list_free(newlist); | /* server=//1.2.3.4 is special. */ |
ret_err(err); | if (lastdomain) |
| { |
| if (strlen(cur_domain) == 0) |
| flags |= SERV_FOR_NODOTS; |
| else |
| flags &= ~SERV_FOR_NODOTS; |
| |
| /* address=/#/ matches the same as without domain */ |
| if (option == 'A' && cur_domain[0] == '#' && cur_domain[1] == 0) |
| cur_domain[0] = 0; |
| } |
| |
| if (!add_update_server(flags, sdetails.addr, sdetails.source_addr, sdetails.interface, cur_domain, &addr)) |
| ret_err(gen_err); |
| |
| if (!lastdomain || cur_domain == lastdomain) |
| break; |
| |
| cur_domain += strlen(cur_domain) + 1; |
} |
} |
|
|
|
if (flags & SERV_LITERAL_ADDRESS) |
|
break; |
} |
} |
|
|
|
if (sdetails.orig_hostinfo) |
|
freeaddrinfo(sdetails.orig_hostinfo); |
|
|
serv = newlist; | break; |
while (serv->next) | |
{ | |
serv->next->flags |= serv->flags & ~(SERV_HAS_DOMAIN | SERV_FOR_NODOTS); | |
serv->next->addr = serv->addr; | |
serv->next->source_addr = serv->source_addr; | |
strcpy(serv->next->interface, serv->interface); | |
serv = serv->next; | |
} | |
serv->next = daemon->servers; | |
daemon->servers = newlist; | |
break; | |
} |
} |
|
|
case LOPT_REV_SERV: /* --rev-server */ |
case LOPT_REV_SERV: /* --rev-server */ |
{ |
{ |
char *string; |
char *string; |
int size; |
int size; |
struct server *serv; |
|
struct in_addr addr4; |
struct in_addr addr4; |
struct in6_addr addr6; |
struct in6_addr addr6; |
| |
unhide_metas(arg); |
unhide_metas(arg); |
if (!arg) |
if (!arg) |
ret_err(gen_err); |
ret_err(gen_err); |
|
|
comma=split(arg); |
comma=split(arg); |
|
|
if (!(string = split_chr(arg, '/')) || !atoi_check(string, &size)) |
|
ret_err(gen_err); |
|
|
|
|
if (!(string = split_chr(arg, '/')) || !atoi_check(string, &size)) |
|
size = -1; |
|
|
if (inet_pton(AF_INET, arg, &addr4)) |
if (inet_pton(AF_INET, arg, &addr4)) |
{ |
{ |
serv = add_rev4(addr4, size); | if (size == -1) |
if (!serv) | size = 32; |
ret_err(_("bad prefix")); | |
| if ((string = domain_rev4(servers_only, comma, &addr4, size))) |
| ret_err(string); |
} |
} |
else if (inet_pton(AF_INET6, arg, &addr6)) |
else if (inet_pton(AF_INET6, arg, &addr6)) |
serv = add_rev6(&addr6, size); | { |
| if (size == -1) |
| size = 128; |
| |
| if ((string = domain_rev6(servers_only, comma, &addr6, size))) |
| ret_err(string); |
| } |
else |
else |
ret_err(gen_err); |
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; |
break; |
} |
} |
|
|
case LOPT_IPSET: /* --ipset */ |
case LOPT_IPSET: /* --ipset */ |
|
case LOPT_NFTSET: /* --nftset */ |
#ifndef HAVE_IPSET |
#ifndef HAVE_IPSET |
ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives")); | if (option == LOPT_IPSET) |
break; | { |
#else | ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives")); |
| break; |
| } |
| #endif |
| #ifndef HAVE_NFTSET |
| if (option == LOPT_NFTSET) |
| { |
| ret_err(_("recompile with HAVE_NFTSET defined to enable nftset directives")); |
| break; |
| } |
| #endif |
| |
{ |
{ |
struct ipsets ipsets_head; |
struct ipsets ipsets_head; |
struct ipsets *ipsets = &ipsets_head; |
struct ipsets *ipsets = &ipsets_head; |
|
struct ipsets **daemon_sets = |
|
(option == LOPT_IPSET) ? &daemon->ipsets : &daemon->nftsets; |
int size; |
int size; |
char *end; |
char *end; |
char **sets, **sets_pos; |
char **sets, **sets_pos; |
Line 2729 static int one_opt(int option, char *arg, char *errstr
|
Line 3177 static int one_opt(int option, char *arg, char *errstr
|
sets = sets_pos = opt_malloc(sizeof(char *) * size); |
sets = sets_pos = opt_malloc(sizeof(char *) * size); |
|
|
do { |
do { |
|
char *p; |
end = split(arg); |
end = split(arg); |
*sets_pos++ = opt_string_alloc(arg); | *sets_pos = opt_string_alloc(arg); |
| /* Use '#' to delimit table and set */ |
| if (option == LOPT_NFTSET) |
| while ((p = strchr(*sets_pos, '#'))) |
| *p = ' '; |
| sets_pos++; |
arg = end; |
arg = end; |
} while (end); |
} while (end); |
*sets_pos = 0; |
*sets_pos = 0; |
for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next) |
for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next) |
ipsets->next->sets = sets; |
ipsets->next->sets = sets; |
ipsets->next = daemon->ipsets; | ipsets->next = *daemon_sets; |
daemon->ipsets = ipsets_head.next; | *daemon_sets = ipsets_head.next; |
|
|
break; |
break; |
} |
} |
|
|
|
case LOPT_CMARK_ALST_EN: /* --connmark-allowlist-enable */ |
|
#ifndef HAVE_CONNTRACK |
|
ret_err(_("recompile with HAVE_CONNTRACK defined to enable connmark-allowlist directives")); |
|
break; |
|
#else |
|
{ |
|
u32 mask = UINT32_MAX; |
|
|
|
if (arg) |
|
if (!strtoul_check(arg, &mask) || mask < 1) |
|
ret_err(gen_err); |
|
|
|
set_option_bool(OPT_CMARK_ALST_EN); |
|
daemon->allowlist_mask = mask; |
|
break; |
|
} |
#endif |
#endif |
|
|
|
case LOPT_CMARK_ALST: /* --connmark-allowlist */ |
|
#ifndef HAVE_CONNTRACK |
|
ret_err(_("recompile with HAVE_CONNTRACK defined to enable connmark-allowlist directives")); |
|
break; |
|
#else |
|
{ |
|
struct allowlist *allowlists; |
|
char **patterns, **patterns_pos; |
|
u32 mark, mask = UINT32_MAX; |
|
size_t num_patterns = 0; |
|
|
|
char *c, *m = NULL; |
|
char *separator; |
|
unhide_metas(arg); |
|
if (!arg) |
|
ret_err(gen_err); |
|
c = arg; |
|
if (*c < '0' || *c > '9') |
|
ret_err(gen_err); |
|
while (*c && *c != ',') |
|
{ |
|
if (*c == '/') |
|
{ |
|
if (m) |
|
ret_err(gen_err); |
|
*c = '\0'; |
|
m = ++c; |
|
} |
|
if (*c < '0' || *c > '9') |
|
ret_err(gen_err); |
|
c++; |
|
} |
|
separator = c; |
|
if (!*separator) |
|
break; |
|
while (c && *c) |
|
{ |
|
char *end = strchr(++c, '/'); |
|
if (end) |
|
*end = '\0'; |
|
if (strcmp(c, "*") && !is_valid_dns_name_pattern(c)) |
|
ret_err(gen_err); |
|
if (end) |
|
*end = '/'; |
|
if (num_patterns >= UINT16_MAX - 1) |
|
ret_err(gen_err); |
|
num_patterns++; |
|
c = end; |
|
} |
|
|
|
*separator = '\0'; |
|
if (!strtoul_check(arg, &mark) || mark < 1 || mark > UINT32_MAX) |
|
ret_err(gen_err); |
|
if (m) |
|
if (!strtoul_check(m, &mask) || mask < 1 || mask > UINT32_MAX || (mark & ~mask)) |
|
ret_err(gen_err); |
|
if (num_patterns) |
|
*separator = ','; |
|
for (allowlists = daemon->allowlists; allowlists; allowlists = allowlists->next) |
|
if (allowlists->mark == mark && allowlists->mask == mask) |
|
ret_err(gen_err); |
|
|
|
patterns = opt_malloc((num_patterns + 1) * sizeof(char *)); |
|
if (!patterns) |
|
goto fail_cmark_allowlist; |
|
patterns_pos = patterns; |
|
c = separator; |
|
while (c && *c) |
|
{ |
|
char *end = strchr(++c, '/'); |
|
if (end) |
|
*end = '\0'; |
|
if (!(*patterns_pos++ = opt_string_alloc(c))) |
|
goto fail_cmark_allowlist; |
|
if (end) |
|
*end = '/'; |
|
c = end; |
|
} |
|
*patterns_pos++ = NULL; |
|
|
|
allowlists = opt_malloc(sizeof(struct allowlist)); |
|
if (!allowlists) |
|
goto fail_cmark_allowlist; |
|
memset(allowlists, 0, sizeof(struct allowlist)); |
|
allowlists->mark = mark; |
|
allowlists->mask = mask; |
|
allowlists->patterns = patterns; |
|
allowlists->next = daemon->allowlists; |
|
daemon->allowlists = allowlists; |
|
break; |
|
|
|
fail_cmark_allowlist: |
|
if (patterns) |
|
{ |
|
for (patterns_pos = patterns; *patterns_pos; patterns_pos++) |
|
{ |
|
free(*patterns_pos); |
|
*patterns_pos = NULL; |
|
} |
|
free(patterns); |
|
patterns = NULL; |
|
} |
|
if (allowlists) |
|
{ |
|
free(allowlists); |
|
allowlists = NULL; |
|
} |
|
ret_err(gen_err); |
|
} |
|
#endif |
|
|
case 'c': /* --cache-size */ |
case 'c': /* --cache-size */ |
{ |
{ |
int size; |
int size; |
Line 2820 static int one_opt(int option, char *arg, char *errstr
|
Line 3402 static int one_opt(int option, char *arg, char *errstr
|
if (daemon->query_port == 0) |
if (daemon->query_port == 0) |
daemon->osport = 1; |
daemon->osport = 1; |
break; |
break; |
|
|
|
case LOPT_RANDPORT_LIM: /* --port-limit */ |
|
if (!atoi_check(arg, &daemon->randport_limit) || (daemon->randport_limit < 1)) |
|
ret_err(gen_err); |
|
break; |
|
|
case 'T': /* --local-ttl */ |
case 'T': /* --local-ttl */ |
case LOPT_NEGTTL: /* --neg-ttl */ |
case LOPT_NEGTTL: /* --neg-ttl */ |
Line 2855 static int one_opt(int option, char *arg, char *errstr
|
Line 3442 static int one_opt(int option, char *arg, char *errstr
|
daemon->local_ttl = (unsigned long)ttl; |
daemon->local_ttl = (unsigned long)ttl; |
break; |
break; |
} |
} |
|
|
|
case LOPT_FAST_RETRY: |
|
daemon->fast_retry_timeout = TIMEOUT; |
|
|
|
if (!arg) |
|
daemon->fast_retry_time = DEFAULT_FAST_RETRY; |
|
else |
|
{ |
|
int retry; |
|
|
|
comma = split(arg); |
|
if (!atoi_check(arg, &retry) || retry < 50) |
|
ret_err(gen_err); |
|
daemon->fast_retry_time = retry; |
|
|
|
if (comma) |
|
{ |
|
if (!atoi_check(comma, &retry)) |
|
ret_err(gen_err); |
|
daemon->fast_retry_timeout = retry/1000; |
|
} |
|
} |
|
break; |
|
|
#ifdef HAVE_DHCP |
#ifdef HAVE_DHCP |
case 'X': /* --dhcp-lease-max */ |
case 'X': /* --dhcp-lease-max */ |
if (!atoi_check(arg, &daemon->dhcp_max)) |
if (!atoi_check(arg, &daemon->dhcp_max)) |
Line 3389 static int one_opt(int option, char *arg, char *errstr
|
Line 3999 static int one_opt(int option, char *arg, char *errstr
|
for (configs = daemon->dhcp_conf; configs; configs = configs->next) |
for (configs = daemon->dhcp_conf; configs; configs = configs->next) |
if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr) |
if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr) |
{ |
{ |
sprintf(errstr, _("duplicate dhcp-host IP address %s"), inet_ntoa(in)); | inet_ntop(AF_INET, &in, daemon->addrbuff, ADDRSTRLEN); |
| sprintf(errstr, _("duplicate dhcp-host IP address %s"), |
| daemon->addrbuff); |
| dhcp_config_free(new); |
return 0; |
return 0; |
} |
} |
} |
} |
Line 3553 static int one_opt(int option, char *arg, char *errstr
|
Line 4166 static int one_opt(int option, char *arg, char *errstr
|
|
|
case LOPT_NAME_MATCH: /* --dhcp-name-match */ |
case LOPT_NAME_MATCH: /* --dhcp-name-match */ |
{ |
{ |
struct dhcp_match_name *new = opt_malloc(sizeof(struct dhcp_match_name)); | struct dhcp_match_name *new; |
struct dhcp_netid *id = opt_malloc(sizeof(struct dhcp_netid)); | |
ssize_t len; |
ssize_t len; |
|
|
if (!(comma = split(arg)) || (len = strlen(comma)) == 0) |
if (!(comma = split(arg)) || (len = strlen(comma)) == 0) |
ret_err(gen_err); |
ret_err(gen_err); |
|
|
|
new = opt_malloc(sizeof(struct dhcp_match_name)); |
new->wildcard = 0; |
new->wildcard = 0; |
new->netid = id; | new->netid = opt_malloc(sizeof(struct dhcp_netid)); |
id->net = opt_string_alloc(set_prefix(arg)); | new->netid->net = opt_string_alloc(set_prefix(arg)); |
|
|
if (comma[len-1] == '*') |
if (comma[len-1] == '*') |
{ |
{ |
Line 3766 static int one_opt(int option, char *arg, char *errstr
|
Line 4379 static int one_opt(int option, char *arg, char *errstr
|
} |
} |
} |
} |
|
|
|
dhcp_netid_free(new->netid); |
|
free(new); |
ret_err(gen_err); |
ret_err(gen_err); |
} |
} |
|
|
Line 3800 static int one_opt(int option, char *arg, char *errstr
|
Line 4415 static int one_opt(int option, char *arg, char *errstr
|
case LOPT_SUBSCR: /* --dhcp-subscrid */ |
case LOPT_SUBSCR: /* --dhcp-subscrid */ |
{ |
{ |
unsigned char *p; |
unsigned char *p; |
int dig = 0; | int dig, colon; |
struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor)); |
struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor)); |
|
|
if (!(comma = split(arg))) |
if (!(comma = split(arg))) |
Line 3824 static int one_opt(int option, char *arg, char *errstr
|
Line 4439 static int one_opt(int option, char *arg, char *errstr
|
else |
else |
comma = arg; |
comma = arg; |
|
|
for (p = (unsigned char *)comma; *p; p++) | for (dig = 0, colon = 0, p = (unsigned char *)comma; *p; p++) |
if (isxdigit(*p)) |
if (isxdigit(*p)) |
dig = 1; |
dig = 1; |
else if (*p != ':') | else if (*p == ':') |
| colon = 1; |
| else |
break; |
break; |
|
|
unhide_metas(comma); |
unhide_metas(comma); |
if (option == 'U' || option == 'j' || *p || !dig) | if (option == 'U' || option == 'j' || *p || !dig || !colon) |
{ |
{ |
new->len = strlen(comma); |
new->len = strlen(comma); |
new->data = opt_malloc(new->len); |
new->data = opt_malloc(new->len); |
Line 3953 static int one_opt(int option, char *arg, char *errstr
|
Line 4571 static int one_opt(int option, char *arg, char *errstr
|
} |
} |
} |
} |
break; |
break; |
| |
case LOPT_RELAY: /* --dhcp-relay */ |
case LOPT_RELAY: /* --dhcp-relay */ |
{ |
{ |
struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay)); |
struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay)); |
comma = split(arg); | char *two = split(arg); |
new->interface = opt_string_alloc(split(comma)); | char *three = split(two); |
| |
new->iface_index = 0; |
new->iface_index = 0; |
if (inet_pton(AF_INET, arg, &new->local) && inet_pton(AF_INET, comma, &new->server)) | |
| if (two) |
{ |
{ |
new->next = daemon->relay4; | if (inet_pton(AF_INET, arg, &new->local)) |
daemon->relay4 = new; | { |
} | char *hash = split_chr(two, '#'); |
| |
| if (!hash || !atoi_check16(hash, &new->port)) |
| new->port = DHCP_SERVER_PORT; |
| |
| if (!inet_pton(AF_INET, two, &new->server)) |
| { |
| new->server.addr4.s_addr = 0; |
| |
| /* Fail for three arg version where there are not two addresses. |
| Also fail when broadcasting to wildcard address. */ |
| if (three || strchr(two, '*')) |
| two = NULL; |
| else |
| three = two; |
| } |
| |
| new->next = daemon->relay4; |
| daemon->relay4 = new; |
| } |
#ifdef HAVE_DHCP6 |
#ifdef HAVE_DHCP6 |
else if (inet_pton(AF_INET6, arg, &new->local) && inet_pton(AF_INET6, comma, &new->server)) | else if (inet_pton(AF_INET6, arg, &new->local)) |
{ | { |
new->next = daemon->relay6; | char *hash = split_chr(two, '#'); |
daemon->relay6 = new; | |
} | if (!hash || !atoi_check16(hash, &new->port)) |
| new->port = DHCPV6_SERVER_PORT; |
| |
| if (!inet_pton(AF_INET6, two, &new->server)) |
| { |
| inet_pton(AF_INET6, ALL_SERVERS, &new->server.addr6); |
| /* Fail for three arg version where there are not two addresses. |
| Also fail when multicasting to wildcard address. */ |
| if (three || strchr(two, '*')) |
| two = NULL; |
| else |
| three = two; |
| } |
| new->next = daemon->relay6; |
| daemon->relay6 = new; |
| } |
#endif |
#endif |
else | |
| new->interface = opt_string_alloc(three); |
| } |
| |
| if (!two) |
{ |
{ |
free(new->interface); |
free(new->interface); |
ret_err_free(_("Bad dhcp-relay"), new); |
ret_err_free(_("Bad dhcp-relay"), new); |
Line 4075 err:
|
Line 4733 err:
|
} |
} |
|
|
case LOPT_INTNAME: /* --interface-name */ |
case LOPT_INTNAME: /* --interface-name */ |
|
case LOPT_DYNHOST: /* --dynamic-host */ |
{ |
{ |
struct interface_name *new, **up; |
struct interface_name *new, **up; |
char *domain = NULL; | char *domain = arg; |
| |
comma = split(arg); | |
|
|
if (!comma || !(domain = canonicalise_opt(arg))) | arg = split(arg); |
ret_err(_("bad interface name")); | |
|
|
new = opt_malloc(sizeof(struct interface_name)); |
new = opt_malloc(sizeof(struct interface_name)); |
new->next = NULL; | memset(new, 0, sizeof(struct interface_name)); |
new->addr = NULL; | new->flags = IN4 | IN6; |
|
|
/* Add to the end of the list, so that first name |
/* Add to the end of the list, so that first name |
of an interface is used for PTR lookups. */ |
of an interface is used for PTR lookups. */ |
for (up = &daemon->int_names; *up; up = &((*up)->next)); |
for (up = &daemon->int_names; *up; up = &((*up)->next)); |
*up = new; |
*up = new; |
new->name = domain; | |
new->family = 0; | while ((comma = split(arg))) |
arg = split_chr(comma, '/'); | |
if (arg) | |
{ |
{ |
if (strcmp(arg, "4") == 0) | if (inet_pton(AF_INET, arg, &new->proto4)) |
new->family = AF_INET; | new->flags |= INP4; |
else if (strcmp(arg, "6") == 0) | else if (inet_pton(AF_INET6, arg, &new->proto6)) |
new->family = AF_INET6; | new->flags |= INP6; |
else |
else |
|
break; |
|
|
|
arg = comma; |
|
} |
|
|
|
if ((comma = split_chr(arg, '/'))) |
|
{ |
|
if (strcmp(comma, "4") == 0) |
|
new->flags &= ~IN6; |
|
else if (strcmp(comma, "6") == 0) |
|
new->flags &= ~IN4; |
|
else |
ret_err_free(gen_err, new); |
ret_err_free(gen_err, new); |
} | } |
new->intr = opt_string_alloc(comma); | |
| new->intr = opt_string_alloc(arg); |
| |
| if (option == LOPT_DYNHOST) |
| { |
| if (!(new->flags & (INP4 | INP6))) |
| ret_err(_("missing address in dynamic host")); |
| |
| if (!(new->flags & IN4) || !(new->flags & IN6)) |
| arg = NULL; /* provoke error below */ |
| |
| new->flags &= ~(IN4 | IN6); |
| } |
| else |
| { |
| if (new->flags & (INP4 | INP6)) |
| arg = NULL; /* provoke error below */ |
| } |
| |
| if (!domain || !arg || !(new->name = canonicalise_opt(domain))) |
| ret_err(option == LOPT_DYNHOST ? |
| _("bad dynamic host") : _("bad interface name")); |
| |
break; |
break; |
} |
} |
|
|
case LOPT_CNAME: /* --cname */ |
case LOPT_CNAME: /* --cname */ |
{ |
{ |
struct cname *new; |
struct cname *new; |
char *alias, *target, *last, *pen; | char *alias, *target=NULL, *last, *pen; |
int ttl = -1; |
int ttl = -1; |
|
|
for (last = pen = NULL, comma = arg; comma; comma = split(comma)) |
for (last = pen = NULL, comma = arg; comma; comma = split(comma)) |
Line 4126 err:
|
Line 4814 err:
|
if (pen != arg && atoi_check(last, &ttl)) |
if (pen != arg && atoi_check(last, &ttl)) |
last = pen; |
last = pen; |
|
|
target = canonicalise_opt(last); |
|
|
|
while (arg != last) |
while (arg != last) |
{ |
{ |
int arglen = strlen(arg); |
int arglen = strlen(arg); |
alias = canonicalise_opt(arg); |
alias = canonicalise_opt(arg); |
|
|
|
if (!target) |
|
target = canonicalise_opt(last); |
if (!alias || !target) |
if (!alias || !target) |
{ |
{ |
free(target); |
free(target); |
Line 4154 err:
|
Line 4842 err:
|
new->target = target; |
new->target = target; |
new->ttl = ttl; |
new->ttl = ttl; |
|
|
for (arg += arglen+1; *arg && isspace(*arg); arg++); | for (arg += arglen+1; *arg && isspace((unsigned char)*arg); arg++); |
} |
} |
|
|
break; |
break; |
Line 4431 err:
|
Line 5119 err:
|
} |
} |
else |
else |
{ |
{ |
int nomem; | char *canon = canonicalise_opt(arg); |
char *canon = canonicalise(arg, &nomem); | |
struct name_list *nl; |
struct name_list *nl; |
if (!canon) |
if (!canon) |
{ |
{ |
struct name_list *tmp = new->names, *next; | struct name_list *tmp, *next; |
for (tmp = new->names; tmp; tmp = next) |
for (tmp = new->names; tmp; tmp = next) |
{ |
{ |
next = tmp->next; |
next = tmp->next; |
Line 4473 err:
|
Line 5160 err:
|
break; |
break; |
} |
} |
|
|
|
case LOPT_STALE_CACHE: |
|
{ |
|
int max_expiry = STALE_CACHE_EXPIRY; |
|
if (arg) |
|
{ |
|
/* Don't accept negative TTLs here, they'd have the counter-intuitive |
|
side-effect of evicting cache records before they expire */ |
|
if (!atoi_check(arg, &max_expiry) || max_expiry < 0) |
|
ret_err(gen_err); |
|
/* Store "serve expired forever" as -1 internally, the option isn't |
|
active for daemon->cache_max_expiry == 0 */ |
|
if (max_expiry == 0) |
|
max_expiry = -1; |
|
} |
|
daemon->cache_max_expiry = max_expiry; |
|
break; |
|
} |
|
|
#ifdef HAVE_DNSSEC |
#ifdef HAVE_DNSSEC |
case LOPT_DNSSEC_STAMP: /* --dnssec-timestamp */ |
case LOPT_DNSSEC_STAMP: /* --dnssec-timestamp */ |
daemon->timestamp_file = opt_string_alloc(arg); |
daemon->timestamp_file = opt_string_alloc(arg); |
Line 4528 err:
|
Line 5233 err:
|
unhide_metas(keyhex); |
unhide_metas(keyhex); |
/* 4034: "Whitespace is allowed within digits" */ |
/* 4034: "Whitespace is allowed within digits" */ |
for (cp = keyhex; *cp; ) |
for (cp = keyhex; *cp; ) |
if (isspace(*cp)) | if (isspace((unsigned char)*cp)) |
for (cp1 = cp; *cp1; cp1++) |
for (cp1 = cp; *cp1; cp1++) |
*cp1 = *(cp1+1); |
*cp1 = *(cp1+1); |
else |
else |
Line 4554 err:
|
Line 5259 err:
|
return 1; |
return 1; |
} |
} |
|
|
static void read_file(char *file, FILE *f, int hard_opt) | static void read_file(char *file, FILE *f, int hard_opt, int from_script) |
{ |
{ |
volatile int lineno = 0; |
volatile int lineno = 0; |
char *buff = daemon->namebuff; |
char *buff = daemon->namebuff; |
Line 4562 static void read_file(char *file, FILE *f, int hard_op
|
Line 5267 static void read_file(char *file, FILE *f, int hard_op
|
while (fgets(buff, MAXDNAME, f)) |
while (fgets(buff, MAXDNAME, f)) |
{ |
{ |
int white, i; |
int white, i; |
volatile int option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt; | volatile int option; |
char *errmess, *p, *arg, *start; |
char *errmess, *p, *arg, *start; |
size_t len; |
size_t len; |
|
|
|
option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt; |
|
|
/* Memory allocation failure longjmps here if mem_recover == 1 */ |
/* Memory allocation failure longjmps here if mem_recover == 1 */ |
if (option != 0 || hard_opt == LOPT_REV_SERV) |
if (option != 0 || hard_opt == LOPT_REV_SERV) |
{ |
{ |
Line 4573 static void read_file(char *file, FILE *f, int hard_op
|
Line 5280 static void read_file(char *file, FILE *f, int hard_op
|
continue; |
continue; |
mem_recover = 1; |
mem_recover = 1; |
} |
} |
| |
arg = NULL; |
arg = NULL; |
lineno++; |
lineno++; |
errmess = NULL; |
errmess = NULL; |
Line 4614 static void read_file(char *file, FILE *f, int hard_op
|
Line 5321 static void read_file(char *file, FILE *f, int hard_op
|
memmove(p, p+1, strlen(p+1)+1); |
memmove(p, p+1, strlen(p+1)+1); |
} |
} |
|
|
if (isspace(*p)) | if (isspace((unsigned char)*p)) |
{ |
{ |
*p = ' '; |
*p = ' '; |
white = 1; |
white = 1; |
Line 4679 static void read_file(char *file, FILE *f, int hard_op
|
Line 5386 static void read_file(char *file, FILE *f, int hard_op
|
|
|
if (errmess || !one_opt(option, arg, daemon->namebuff, _("error"), 0, hard_opt == LOPT_REV_SERV)) |
if (errmess || !one_opt(option, arg, daemon->namebuff, _("error"), 0, hard_opt == LOPT_REV_SERV)) |
{ |
{ |
sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file); | if (from_script) |
| sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" in output from %s"), file); |
| else |
| sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file); |
| |
if (hard_opt != 0) |
if (hard_opt != 0) |
my_syslog(LOG_ERR, "%s", daemon->namebuff); |
my_syslog(LOG_ERR, "%s", daemon->namebuff); |
else |
else |
Line 4688 static void read_file(char *file, FILE *f, int hard_op
|
Line 5399 static void read_file(char *file, FILE *f, int hard_op
|
} |
} |
|
|
mem_recover = 0; |
mem_recover = 0; |
fclose(f); |
|
} |
} |
|
|
#if defined(HAVE_DHCP) && defined(HAVE_INOTIFY) |
#if defined(HAVE_DHCP) && defined(HAVE_INOTIFY) |
Line 4708 int option_read_dynfile(char *file, int flags)
|
Line 5418 int option_read_dynfile(char *file, int flags)
|
static int one_file(char *file, int hard_opt) |
static int one_file(char *file, int hard_opt) |
{ |
{ |
FILE *f; |
FILE *f; |
int nofile_ok = 0; | int nofile_ok = 0, do_popen = 0; |
static int read_stdin = 0; |
static int read_stdin = 0; |
static struct fileread { |
static struct fileread { |
dev_t dev; |
dev_t dev; |
Line 4716 static int one_file(char *file, int hard_opt)
|
Line 5426 static int one_file(char *file, int hard_opt)
|
struct fileread *next; |
struct fileread *next; |
} *filesread = NULL; |
} *filesread = NULL; |
|
|
if (hard_opt == '7') | if (hard_opt == LOPT_CONF_OPT) |
{ |
{ |
/* default conf-file reading */ |
/* default conf-file reading */ |
hard_opt = 0; |
hard_opt = 0; |
nofile_ok = 1; |
nofile_ok = 1; |
} |
} |
|
|
if (hard_opt == 0 && strcmp(file, "-") == 0) | if (hard_opt == LOPT_CONF_SCRIPT) |
| { |
| hard_opt = 0; |
| do_popen = 1; |
| } |
| |
| if (hard_opt == 0 && !do_popen && strcmp(file, "-") == 0) |
{ |
{ |
if (read_stdin == 1) |
if (read_stdin == 1) |
return 1; |
return 1; |
Line 4750 static int one_file(char *file, int hard_opt)
|
Line 5466 static int one_file(char *file, int hard_opt)
|
r->dev = statbuf.st_dev; |
r->dev = statbuf.st_dev; |
r->ino = statbuf.st_ino; |
r->ino = statbuf.st_ino; |
} |
} |
| |
if (!(f = fopen(file, "r"))) | if (do_popen) |
| { |
| if (!(f = popen(file, "r"))) |
| die(_("cannot execute %s: %s"), file, EC_FILE); |
| } |
| else if (!(f = fopen(file, "r"))) |
{ |
{ |
if (errno == ENOENT && nofile_ok) |
if (errno == ENOENT && nofile_ok) |
return 1; /* No conffile, all done. */ |
return 1; /* No conffile, all done. */ |
Line 4769 static int one_file(char *file, int hard_opt)
|
Line 5490 static int one_file(char *file, int hard_opt)
|
} |
} |
} |
} |
|
|
read_file(file, f, hard_opt); | read_file(file, f, hard_opt, do_popen); |
| |
| if (do_popen) |
| { |
| int rc; |
| |
| if ((rc = pclose(f)) == -1) |
| die(_("error executing %s: %s"), file, EC_MISC); |
| |
| if (rc != 0) |
| die(_("%s returns non-zero error code"), file, rc+10); |
| } |
| else |
| fclose(f); |
| |
return 1; |
return 1; |
} |
} |
|
|
|
static int file_filter(const struct dirent *ent) |
|
{ |
|
size_t lenfile = strlen(ent->d_name); |
|
|
|
/* ignore emacs backups and dotfiles */ |
|
|
|
if (lenfile == 0 || |
|
ent->d_name[lenfile - 1] == '~' || |
|
(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') || |
|
ent->d_name[0] == '.') |
|
return 0; |
|
|
|
return 1; |
|
} |
/* expand any name which is a directory */ |
/* expand any name which is a directory */ |
struct hostsfile *expand_filelist(struct hostsfile *list) |
struct hostsfile *expand_filelist(struct hostsfile *list) |
{ |
{ |
unsigned int i; |
unsigned int i; |
struct hostsfile *ah; | int entcnt, n; |
| struct hostsfile *ah, *last, *next, **up; |
| struct dirent **namelist; |
|
|
/* find largest used index */ |
/* find largest used index */ |
for (i = SRC_AH, ah = list; ah; ah = ah->next) |
for (i = SRC_AH, ah = list; ah; ah = ah->next) |
{ |
{ |
|
last = ah; |
|
|
if (i <= ah->index) |
if (i <= ah->index) |
i = ah->index + 1; |
i = ah->index + 1; |
|
|
Line 4797 struct hostsfile *expand_filelist(struct hostsfile *li
|
Line 5550 struct hostsfile *expand_filelist(struct hostsfile *li
|
struct stat buf; |
struct stat buf; |
if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode)) |
if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode)) |
{ |
{ |
DIR *dir_stream; |
|
struct dirent *ent; |
struct dirent *ent; |
|
|
/* don't read this as a file */ |
/* don't read this as a file */ |
ah->flags |= AH_INACTIVE; |
ah->flags |= AH_INACTIVE; |
|
|
if (!(dir_stream = opendir(ah->fname))) | entcnt = scandir(ah->fname, &namelist, file_filter, alphasort); |
| if (entcnt < 0) |
my_syslog(LOG_ERR, _("cannot access directory %s: %s"), |
my_syslog(LOG_ERR, _("cannot access directory %s: %s"), |
ah->fname, strerror(errno)); |
ah->fname, strerror(errno)); |
else |
else |
{ |
{ |
while ((ent = readdir(dir_stream))) | for (n = 0; n < entcnt; n++) |
{ |
{ |
|
ent = namelist[n]; |
size_t lendir = strlen(ah->fname); |
size_t lendir = strlen(ah->fname); |
size_t lenfile = strlen(ent->d_name); |
size_t lenfile = strlen(ent->d_name); |
struct hostsfile *ah1; |
struct hostsfile *ah1; |
char *path; |
char *path; |
|
|
/* ignore emacs backups and dotfiles */ |
|
if (lenfile == 0 || |
|
ent->d_name[lenfile - 1] == '~' || |
|
(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') || |
|
ent->d_name[0] == '.') |
|
continue; |
|
|
|
/* see if we have an existing record. |
/* see if we have an existing record. |
dir is ah->fname |
dir is ah->fname |
file is ent->d_name |
file is ent->d_name |
path to match is ah1->fname */ |
path to match is ah1->fname */ |
|
|
for (ah1 = list; ah1; ah1 = ah1->next) | for (up = &list, ah1 = list; ah1; ah1 = next) |
{ |
{ |
|
next = ah1->next; |
|
|
if (lendir < strlen(ah1->fname) && |
if (lendir < strlen(ah1->fname) && |
strstr(ah1->fname, ah->fname) == ah1->fname && |
strstr(ah1->fname, ah->fname) == ah1->fname && |
ah1->fname[lendir] == '/' && |
ah1->fname[lendir] == '/' && |
strcmp(ah1->fname + lendir + 1, ent->d_name) == 0) |
strcmp(ah1->fname + lendir + 1, ent->d_name) == 0) |
{ |
{ |
ah1->flags &= ~AH_INACTIVE; |
ah1->flags &= ~AH_INACTIVE; |
|
/* If found, remove from list to re-insert at the end. |
|
Unless it's already at the end. */ |
|
if (last != ah1) |
|
*up = next; |
break; |
break; |
} |
} |
|
|
|
up = &ah1->next; |
} |
} |
|
|
/* make new record */ |
/* make new record */ |
Line 4857 struct hostsfile *expand_filelist(struct hostsfile *li
|
Line 5612 struct hostsfile *expand_filelist(struct hostsfile *li
|
ah1->fname = path; |
ah1->fname = path; |
ah1->index = i++; |
ah1->index = i++; |
ah1->flags = AH_DIR; |
ah1->flags = AH_DIR; |
ah1->next = list; |
|
list = ah1; |
|
} |
} |
|
|
|
/* Edge case, may be the last in the list anyway */ |
|
if (last != ah1) |
|
last->next = ah1; |
|
ah1->next = NULL; |
|
last = ah1; |
|
|
/* inactivate record if not regular file */ |
/* inactivate record if not regular file */ |
if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode)) |
if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode)) |
ah1->flags |= AH_INACTIVE; |
ah1->flags |= AH_INACTIVE; |
|
|
} |
} |
closedir(dir_stream); |
|
} |
} |
|
free(namelist); |
} |
} |
} |
} |
|
|
Line 4885 void read_servers_file(void)
|
Line 5644 void read_servers_file(void)
|
} |
} |
|
|
mark_servers(SERV_FROM_FILE); |
mark_servers(SERV_FROM_FILE); |
|
read_file(daemon->servers_file, f, LOPT_REV_SERV, 0); |
|
fclose(f); |
cleanup_servers(); |
cleanup_servers(); |
| check_servers(0); |
read_file(daemon->servers_file, f, LOPT_REV_SERV); | |
} |
} |
|
|
|
|
Line 4903 static void clear_dynamic_conf(void)
|
Line 5663 static void clear_dynamic_conf(void)
|
|
|
if (configs->flags & CONFIG_BANK) |
if (configs->flags & CONFIG_BANK) |
{ |
{ |
struct hwaddr_config *mac, *tmp; | *up = cp; |
struct dhcp_netid_list *list, *tmplist; | dhcp_config_free(configs); |
| |
for (mac = configs->hwaddr; mac; mac = tmp) | |
{ | |
tmp = mac->next; | |
free(mac); | |
} | |
| |
if (configs->flags & CONFIG_CLID) | |
free(configs->clid); | |
| |
for (list = configs->netid; list; list = tmplist) | |
{ | |
free(list->list); | |
tmplist = list->next; | |
free(list); | |
} | |
| |
if (configs->flags & CONFIG_NAME) | |
free(configs->hostname); | |
| |
*up = configs->next; | |
free(configs); | |
} |
} |
else |
else |
up = &configs->next; |
up = &configs->next; |
Line 4936 static void clear_dynamic_conf(void)
|
Line 5674 static void clear_dynamic_conf(void)
|
static void clear_dynamic_opt(void) |
static void clear_dynamic_opt(void) |
{ |
{ |
struct dhcp_opt *opts, *cp, **up; |
struct dhcp_opt *opts, *cp, **up; |
struct dhcp_netid *id, *next; |
|
|
|
for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp) |
for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp) |
{ |
{ |
Line 4944 static void clear_dynamic_opt(void)
|
Line 5681 static void clear_dynamic_opt(void)
|
|
|
if (opts->flags & DHOPT_BANK) |
if (opts->flags & DHOPT_BANK) |
{ |
{ |
if ((opts->flags & DHOPT_VENDOR)) | *up = cp; |
free(opts->u.vendor_class); | dhcp_opt_free(opts); |
free(opts->val); | |
for (id = opts->netid; id; id = next) | |
{ | |
next = id->next; | |
free(id->net); | |
free(id); | |
} | |
*up = opts->next; | |
free(opts); | |
} |
} |
else |
else |
up = &opts->next; |
up = &opts->next; |
Line 5014 void read_opts(int argc, char **argv, char *compile_op
|
Line 5742 void read_opts(int argc, char **argv, char *compile_op
|
daemon = opt_malloc(sizeof(struct daemon)); |
daemon = opt_malloc(sizeof(struct daemon)); |
memset(daemon, 0, sizeof(struct daemon)); |
memset(daemon, 0, sizeof(struct daemon)); |
daemon->namebuff = buff; |
daemon->namebuff = buff; |
| daemon->addrbuff = safe_malloc(ADDRSTRLEN); |
| |
/* Set defaults - everything else is zero or NULL */ |
/* Set defaults - everything else is zero or NULL */ |
daemon->cachesize = CACHESIZ; |
daemon->cachesize = CACHESIZ; |
daemon->ftabsize = FTABSIZ; |
daemon->ftabsize = FTABSIZ; |
Line 5034 void read_opts(int argc, char **argv, char *compile_op
|
Line 5763 void read_opts(int argc, char **argv, char *compile_op
|
daemon->soa_refresh = SOA_REFRESH; |
daemon->soa_refresh = SOA_REFRESH; |
daemon->soa_retry = SOA_RETRY; |
daemon->soa_retry = SOA_RETRY; |
daemon->soa_expiry = SOA_EXPIRY; |
daemon->soa_expiry = SOA_EXPIRY; |
daemon->max_port = MAX_PORT; | daemon->randport_limit = 1; |
daemon->min_port = MIN_PORT; | daemon->host_index = SRC_AH; |
| |
#ifndef NO_ID | /* See comment above make_servers(). Optimises server-read code. */ |
add_txt("version.bind", "dnsmasq-" VERSION, 0 ); | mark_servers(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); | |
#endif | |
| |
while (1) |
while (1) |
{ |
{ |
#ifdef HAVE_GETOPT_LONG |
#ifdef HAVE_GETOPT_LONG |
Line 5144 void read_opts(int argc, char **argv, char *compile_op
|
Line 5861 void read_opts(int argc, char **argv, char *compile_op
|
free(conffile); |
free(conffile); |
} |
} |
else |
else |
one_file(CONFFILE, '7'); | one_file(CONFFILE, LOPT_CONF_OPT); |
| |
| /* Add TXT records if wanted */ |
| #ifndef NO_ID |
| if (!option_bool(OPT_NO_IDENT)) |
| { |
| 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); |
| } |
| #endif |
|
|
/* port might not be known when the address is parsed - fill in here */ |
/* port might not be known when the address is parsed - fill in here */ |
if (daemon->servers) |
if (daemon->servers) |