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