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