Annotation of embedaddon/dnsmasq/src/option.c, revision 1.1.1.5
1.1.1.5 ! misho 1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
1.1 misho 2:
3: This program is free software; you can redistribute it and/or modify
4: it under the terms of the GNU General Public License as published by
5: the Free Software Foundation; version 2 dated June, 1991, or
6: (at your option) version 3 dated 29 June, 2007.
7:
8: This program is distributed in the hope that it will be useful,
9: but WITHOUT ANY WARRANTY; without even the implied warranty of
10: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11: GNU General Public License for more details.
12:
13: You should have received a copy of the GNU General Public License
14: along with this program. If not, see <http://www.gnu.org/licenses/>.
15: */
16:
17: /* define this to get facilitynames */
18: #define SYSLOG_NAMES
19: #include "dnsmasq.h"
20: #include <setjmp.h>
21:
22: static volatile int mem_recover = 0;
23: static jmp_buf mem_jmp;
24: static int one_file(char *file, int hard_opt);
25:
26: /* Solaris headers don't have facility names. */
27: #ifdef HAVE_SOLARIS_NETWORK
28: static const struct {
29: char *c_name;
30: unsigned int c_val;
31: } facilitynames[] = {
32: { "kern", LOG_KERN },
33: { "user", LOG_USER },
34: { "mail", LOG_MAIL },
35: { "daemon", LOG_DAEMON },
36: { "auth", LOG_AUTH },
37: { "syslog", LOG_SYSLOG },
38: { "lpr", LOG_LPR },
39: { "news", LOG_NEWS },
40: { "uucp", LOG_UUCP },
41: { "audit", LOG_AUDIT },
42: { "cron", LOG_CRON },
43: { "local0", LOG_LOCAL0 },
44: { "local1", LOG_LOCAL1 },
45: { "local2", LOG_LOCAL2 },
46: { "local3", LOG_LOCAL3 },
47: { "local4", LOG_LOCAL4 },
48: { "local5", LOG_LOCAL5 },
49: { "local6", LOG_LOCAL6 },
50: { "local7", LOG_LOCAL7 },
51: { NULL, 0 }
52: };
53: #endif
54:
55: #ifndef HAVE_GETOPT_LONG
56: struct myoption {
57: const char *name;
58: int has_arg;
59: int *flag;
60: int val;
61: };
62: #endif
63:
64: #define OPTSTRING "951yZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:W:Y:2:4:6:7:8:0:3:"
65:
66: /* options which don't have a one-char version */
1.1.1.2 misho 67: #define LOPT_RELOAD 256
68: #define LOPT_NO_NAMES 257
69: #define LOPT_TFTP 258
70: #define LOPT_SECURE 259
71: #define LOPT_PREFIX 260
72: #define LOPT_PTR 261
73: #define LOPT_BRIDGE 262
74: #define LOPT_TFTP_MAX 263
75: #define LOPT_FORCE 264
76: #define LOPT_NOBLOCK 265
77: #define LOPT_LOG_OPTS 266
78: #define LOPT_MAX_LOGS 267
79: #define LOPT_CIRCUIT 268
80: #define LOPT_REMOTE 269
81: #define LOPT_SUBSCR 270
82: #define LOPT_INTNAME 271
83: #define LOPT_BANK 272
84: #define LOPT_DHCP_HOST 273
85: #define LOPT_APREF 274
86: #define LOPT_OVERRIDE 275
87: #define LOPT_TFTPPORTS 276
88: #define LOPT_REBIND 277
89: #define LOPT_NOLAST 278
90: #define LOPT_OPTS 279
91: #define LOPT_DHCP_OPTS 280
92: #define LOPT_MATCH 281
93: #define LOPT_BROADCAST 282
94: #define LOPT_NEGTTL 283
95: #define LOPT_ALTPORT 284
96: #define LOPT_SCRIPTUSR 285
97: #define LOPT_LOCAL 286
98: #define LOPT_NAPTR 287
99: #define LOPT_MINPORT 288
100: #define LOPT_DHCP_FQDN 289
101: #define LOPT_CNAME 290
102: #define LOPT_PXE_PROMT 291
103: #define LOPT_PXE_SERV 292
104: #define LOPT_TEST 293
105: #define LOPT_TAG_IF 294
106: #define LOPT_PROXY 295
107: #define LOPT_GEN_NAMES 296
108: #define LOPT_MAXTTL 297
109: #define LOPT_NO_REBIND 298
110: #define LOPT_LOC_REBND 299
111: #define LOPT_ADD_MAC 300
112: #define LOPT_DNSSEC 301
113: #define LOPT_INCR_ADDR 302
114: #define LOPT_CONNTRACK 303
115: #define LOPT_FQDN 304
116: #define LOPT_LUASCRIPT 305
117: #define LOPT_RA 306
118: #define LOPT_DUID 307
119: #define LOPT_HOST_REC 308
120: #define LOPT_TFTP_LC 309
121: #define LOPT_RR 310
122: #define LOPT_CLVERBIND 311
123: #define LOPT_MAXCTTL 312
124: #define LOPT_AUTHZONE 313
125: #define LOPT_AUTHSERV 314
126: #define LOPT_AUTHTTL 315
127: #define LOPT_AUTHSOA 316
128: #define LOPT_AUTHSFS 317
129: #define LOPT_AUTHPEER 318
130: #define LOPT_IPSET 319
131: #define LOPT_SYNTH 320
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
1.1.1.3 misho 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
1.1.1.4 misho 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
1.1.1.5 ! misho 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:
1.1 misho 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' },
1.1.1.3 misho 201: { "log-queries", 2, 0, 'q' },
1.1 misho 202: { "user", 2, 0, 'u' },
203: { "group", 2, 0, 'g' },
204: { "resolv-file", 2, 0, 'r' },
1.1.1.2 misho 205: { "servers-file", 1, 0, LOPT_SERVERS_FILE },
1.1 misho 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' },
1.1.1.2 misho 220: { "local-service", 0, 0, LOPT_LOCAL_SERVICE },
1.1 misho 221: { "bogus-priv", 0, 0, 'b' },
222: { "bogus-nxdomain", 1, 0, 'B' },
1.1.1.3 misho 223: { "ignore-address", 1, 0, LOPT_IGNORE_ADDR },
1.1 misho 224: { "selfmx", 0, 0, 'e' },
225: { "filterwin2k", 0, 0, 'f' },
1.1.1.5 ! misho 226: { "filter-A", 0, 0, LOPT_FILTER_A },
! 227: { "filter-AAAA", 0, 0, LOPT_FILTER_AAAA },
1.1 misho 228: { "pid-file", 2, 0, 'x' },
229: { "strict-order", 0, 0, 'o' },
230: { "server", 1, 0, 'S' },
1.1.1.2 misho 231: { "rev-server", 1, 0, LOPT_REV_SERV },
1.1 misho 232: { "local", 1, 0, LOPT_LOCAL },
233: { "address", 1, 0, 'A' },
234: { "conf-file", 2, 0, 'C' },
1.1.1.5 ! misho 235: { "conf-script", 1, 0, LOPT_CONF_SCRIPT },
1.1 misho 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' },
1.1.1.5 ! misho 241: { "no-round-robin", 0, 0, LOPT_NORR },
1.1 misho 242: { "addn-hosts", 1, 0, 'H' },
1.1.1.3 misho 243: { "hostsdir", 1, 0, LOPT_HOST_INOTIFY },
1.1 misho 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' },
1.1.1.4 misho 261: { "caa-record", 1, 0 , LOPT_CAA },
1.1 misho 262: { "dns-rr", 1, 0, LOPT_RR },
263: { "enable-dbus", 2, 0, '1' },
1.1.1.4 misho 264: { "enable-ubus", 2, 0, LOPT_UBUS },
1.1 misho 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' },
1.1.1.4 misho 272: { "script-on-renewal", 0, 0, LOPT_SCRIPT_TIME},
1.1 misho 273: { "dns-forward-max", 1, 0, '0' },
274: { "clear-on-reload", 0, 0, LOPT_RELOAD },
275: { "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
1.1.1.2 misho 276: { "enable-tftp", 2, 0, LOPT_TFTP },
1.1 misho 277: { "tftp-secure", 0, 0, LOPT_SECURE },
1.1.1.3 misho 278: { "tftp-no-fail", 0, 0, LOPT_TFTP_NO_FAIL },
1.1.1.4 misho 279: { "tftp-unique-root", 2, 0, LOPT_APREF },
1.1 misho 280: { "tftp-root", 1, 0, LOPT_PREFIX },
281: { "tftp-max", 1, 0, LOPT_TFTP_MAX },
1.1.1.3 misho 282: { "tftp-mtu", 1, 0, LOPT_TFTP_MTU },
1.1 misho 283: { "tftp-lowercase", 0, 0, LOPT_TFTP_LC },
1.1.1.4 misho 284: { "tftp-single-port", 0, 0, LOPT_SINGLE_PORT },
1.1 misho 285: { "ptr-record", 1, 0, LOPT_PTR },
286: { "naptr-record", 1, 0, LOPT_NAPTR },
287: { "bridge-interface", 1, 0 , LOPT_BRIDGE },
1.1.1.4 misho 288: { "shared-network", 1, 0, LOPT_SHARED_NET },
1.1 misho 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 },
1.1.1.4 misho 296: { "dhcp-pxe-vendor", 1, 0, LOPT_PXE_VENDOR },
1.1 misho 297: { "interface-name", 1, 0, LOPT_INTNAME },
298: { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
299: { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
1.1.1.3 misho 300: { "dhcp-hostsdir", 1, 0, LOPT_DHCP_INOTIFY },
301: { "dhcp-optsdir", 1, 0, LOPT_DHOPT_INOTIFY },
1.1 misho 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 },
1.1.1.4 misho 307: { "dhcp-match", 1, 0, LOPT_MATCH },
308: { "dhcp-name-match", 1, 0, LOPT_NAME_MATCH },
1.1 misho 309: { "dhcp-broadcast", 2, 0, LOPT_BROADCAST },
310: { "neg-ttl", 1, 0, LOPT_NEGTTL },
311: { "max-ttl", 1, 0, LOPT_MAXTTL },
1.1.1.3 misho 312: { "min-cache-ttl", 1, 0, LOPT_MINCTTL },
1.1 misho 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 },
1.1.1.3 misho 317: { "max-port", 1, 0, LOPT_MAXPORT },
1.1 misho 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 },
1.1.1.3 misho 327: { "add-mac", 2, 0, LOPT_ADD_MAC },
1.1.1.5 ! misho 328: { "strip-mac", 0, 0, LOPT_STRIP_MAC },
1.1.1.2 misho 329: { "add-subnet", 2, 0, LOPT_ADD_SBNET },
1.1.1.5 ! misho 330: { "strip-subnet", 0, 0, LOPT_STRIP_SBNET },
1.1.1.3 misho 331: { "add-cpe-id", 1, 0 , LOPT_CPE_ID },
1.1 misho 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 },
1.1.1.5 ! misho 348: { "nftset", 1, 0, LOPT_NFTSET },
! 349: { "connmark-allowlist-enable", 2, 0, LOPT_CMARK_ALST_EN },
! 350: { "connmark-allowlist", 1, 0, LOPT_CMARK_ALST },
1.1.1.2 misho 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 },
1.1.1.4 misho 355: { "dnssec-check-unsigned", 2, 0, LOPT_DNSSEC_CHECK },
1.1.1.2 misho 356: { "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME },
1.1.1.3 misho 357: { "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP },
1.1.1.2 misho 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 },
1.1.1.3 misho 363: { "dns-loop-detect", 0, 0, LOPT_LOOP_DETECT },
364: { "script-arp", 0, 0, LOPT_SCRIPT_ARP },
365: { "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },
1.1.1.4 misho 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 },
1.1.1.5 ! misho 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 },
1.1 misho 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 },
1.1.1.5 ! misho 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 },
1.1 misho 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 },
1.1.1.3 misho 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 },
1.1 misho 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 },
1.1.1.3 misho 418: { LOPT_HOST_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read hosts files from a directory."), NULL },
1.1 misho 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 },
1.1.1.4 misho 425: { LOPT_PXE_VENDOR, ARG_DUP, "<vendor>[,...]", gettext_noop("Specify vendor class to match for PXE requests."), NULL },
1.1 misho 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 },
1.1.1.5 ! misho 436: { LOPT_STALE_CACHE, ARG_ONE, "[=<max_expired>]", gettext_noop("Use expired cache data for faster reply."), NULL },
1.1 misho 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)."), "*" },
1.1.1.3 misho 442: { 'q', ARG_DUP, NULL, gettext_noop("Log DNS queries."), NULL },
1.1 misho 443: { 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
1.1.1.5 ! misho 444: { LOPT_RANDPORT_LIM, ARG_ONE, "#ports", gettext_noop("Set maximum number of random originating ports for a query."), NULL },
1.1 misho 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 },
1.1.1.2 misho 447: { LOPT_SERVERS_FILE, ARG_ONE, "<path>", gettext_noop("Specify path to file with server= options"), NULL },
1.1 misho 448: { 'S', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
1.1.1.2 misho 449: { LOPT_REV_SERV, ARG_DUP, "<addr>/<prefix>,<ipaddr>", gettext_noop("Specify address of upstream servers for reverse address queries"), NULL },
1.1 misho 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 },
1.1.1.3 misho 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 },
1.1.1.5 ! misho 458: { LOPT_FAST_RETRY, ARG_ONE, "<milliseconds>", gettext_noop("Retry DNS queries after this many milliseconds."), NULL},
1.1 misho 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 },
1.1.1.3 misho 464: { 'w', 0, NULL, gettext_noop("Display this message. Use --help dhcp or --help dhcp6 for known DHCP options."), NULL },
1.1 misho 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 },
1.1.1.4 misho 474: { LOPT_UBUS, ARG_ONE, "[=<busname>]", gettext_noop("Enable the UBus interface."), NULL },
1.1 misho 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 },
1.1.1.4 misho 479: { LOPT_SHARED_NET, ARG_DUP, "<iface>|<addr>,<addr>", gettext_noop("Specify extra networks sharing a broadcast domain for DHCP"), NULL},
1.1 misho 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 },
1.1.1.3 misho 484: { LOPT_SCRIPT_ARP, OPT_SCRIPT_ARP, NULL, gettext_noop("Call dhcp-script with changes to local ARP table."), NULL },
1.1 misho 485: { '7', ARG_DUP, "<path>", gettext_noop("Read configuration from all the files in this directory."), NULL },
1.1.1.5 ! misho 486: { LOPT_CONF_SCRIPT, ARG_DUP, "<path>", gettext_noop("Execute file and read configuration from stdin."), NULL },
1.1.1.4 misho 487: { '8', ARG_ONE, "<facility>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL },
1.1 misho 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 },
1.1.1.2 misho 493: { LOPT_TFTP, ARG_DUP, "[=<intr>[,<intr>]]", gettext_noop("Enable integrated read-only TFTP server."), NULL },
1.1 misho 494: { LOPT_PREFIX, ARG_DUP, "<dir>[,<iface>]", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
1.1.1.4 misho 495: { LOPT_APREF, ARG_DUP, "[=ip|mac]", gettext_noop("Add client IP or hardware address to tftp-root."), NULL },
1.1 misho 496: { LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
1.1.1.3 misho 497: { LOPT_TFTP_NO_FAIL, OPT_TFTP_NO_FAIL, NULL, gettext_noop("Do not terminate the service if TFTP directories are inaccessible."), NULL },
1.1.1.4 misho 498: { LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent TFTP transfers (defaults to %s)."), "#" },
1.1.1.3 misho 499: { LOPT_TFTP_MTU, ARG_ONE, "<integer>", gettext_noop("Maximum MTU to use for TFTP transfers."), NULL },
1.1 misho 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 },
1.1.1.4 misho 503: { LOPT_SINGLE_PORT, OPT_SINGLE_PORT, NULL, gettext_noop("Use only one port for TFTP server."), NULL },
1.1 misho 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 },
1.1.1.4 misho 511: { LOPT_NAME_MATCH, ARG_DUP, "set:<tag>,<string>[*]", gettext_noop("Set tag if client provides given name."), NULL },
1.1 misho 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 },
1.1.1.3 misho 515: { LOPT_MAXPORT, ARG_ONE, "<port>", gettext_noop("Specify highest port available for DNS query transmission."), NULL },
1.1 misho 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 },
1.1.1.4 misho 519: { LOPT_RELAY, ARG_DUP, "<local-addr>,<server>[,<iface>]", gettext_noop("Relay DHCP requests to a remote server"), NULL},
1.1.1.3 misho 520: { LOPT_CNAME, ARG_DUP, "<alias>,<target>[,<ttl>]", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
1.1 misho 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 },
1.1.1.3 misho 524: { LOPT_ADD_MAC, ARG_DUP, "[=base64|text]", gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
1.1.1.5 ! misho 525: { LOPT_STRIP_MAC, OPT_STRIP_MAC, NULL, gettext_noop("Strip MAC information from queries."), NULL },
1.1.1.3 misho 526: { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL },
1.1.1.5 ! misho 527: { LOPT_STRIP_SBNET, OPT_STRIP_ECS, NULL, gettext_noop("Strip ECS information from queries."), NULL },
1.1.1.3 misho 528: { LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client identification to forwarded DNS queries."), NULL },
1.1.1.2 misho 529: { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
1.1 misho 530: { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
1.1.1.4 misho 531: { LOPT_IGNORE_CLID, OPT_IGNORE_CLID, NULL, gettext_noop("Ignore client identifier option sent by DHCP clients."), NULL },
1.1 misho 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 },
1.1.1.3 misho 536: { LOPT_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
1.1.1.5 ! misho 537: { LOPT_DYNHOST, ARG_DUP, "<name>,[<IPv4>][,<IPv6>],<interface-name>", gettext_noop("Specify host record in interface subnet"), NULL },
1.1.1.4 misho 538: { LOPT_CAA, ARG_DUP, "<name>,<flags>,<tag>,<value>", gettext_noop("Specify certification authority authorization record"), NULL },
1.1 misho 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 },
1.1.1.4 misho 544: { LOPT_AUTHSOA, ARG_ONE, "<serial>[,...]", gettext_noop("Set authoritative zone information"), NULL },
1.1 misho 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 },
1.1.1.4 misho 547: { LOPT_IPSET, ARG_DUP, "/<domain>[/<domain>...]/<ipset>...", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },
1.1.1.5 ! misho 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 },
1.1.1.2 misho 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 },
1.1.1.4 misho 555: { LOPT_DNSSEC_CHECK, ARG_DUP, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
1.1.1.2 misho 556: { LOPT_DNSSEC_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL },
1.1.1.3 misho 557: { LOPT_DNSSEC_STAMP, ARG_ONE, "<path>", gettext_noop("Timestamp file to verify system clock for DNSSEC"), NULL },
1.1.1.4 misho 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 },
1.1.1.2 misho 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 },
1.1.1.5 ! misho 562: { LOPT_LOG_DEBUG, OPT_LOG_DEBUG, NULL, gettext_noop("Log debugging information."), NULL },
1.1.1.3 misho 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 },
1.1.1.4 misho 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 },
1.1.1.5 ! misho 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 },
1.1 misho 576: { 0, 0, NULL, NULL, NULL }
577: };
578:
1.1.1.4 misho 579: /* We hide metacharacters in quoted strings by mapping them into the ASCII control
1.1 misho 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:
1.1.1.4 misho 638: static char *opt_string_alloc(const char *cp)
1.1 misho 639: {
640: char *ret = NULL;
1.1.1.4 misho 641: size_t len;
1.1 misho 642:
1.1.1.4 misho 643: if (cp && (len = strlen(cp)) != 0)
1.1 misho 644: {
1.1.1.4 misho 645: ret = opt_malloc(len+1);
646: memcpy(ret, cp, len+1);
1.1 misho 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:
1.1.1.5 ! misho 690: if (strlen(s) == 0)
! 691: return opt_malloc(1); /* Heap-allocated empty string */
! 692:
1.1 misho 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:
1.1.1.5 ! misho 705: static int numeric_check(char *a)
1.1 misho 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:
1.1.1.5 ! misho 718: return 1;
! 719: }
! 720:
! 721: static int atoi_check(char *a, int *res)
! 722: {
! 723: if (!numeric_check(a))
! 724: return 0;
1.1 misho 725: *res = atoi(a);
726: return 1;
727: }
728:
1.1.1.5 ! misho 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:
1.1 misho 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: }
1.1.1.2 misho 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
1.1.1.4 misho 765:
766: #ifndef NO_ID
1.1.1.2 misho 767: static void add_txt(char *name, char *txt, int stat)
1.1 misho 768: {
769: struct txt_record *r = opt_malloc(sizeof(struct txt_record));
1.1.1.2 misho 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: }
1.1.1.4 misho 779:
1.1.1.2 misho 780: r->stat = stat;
1.1 misho 781: r->name = opt_string_alloc(name);
782: r->next = daemon->txt;
783: daemon->txt = r;
784: r->class = C_CHAOS;
785: }
1.1.1.4 misho 786: #endif
1.1 misho 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);
1.1.1.4 misho 831: printf("%-55.55s", buff);
1.1 misho 832:
833: if (usage[i].arg)
834: {
1.1.1.5 ! misho 835: safe_strncpy(buff, usage[i].arg, sizeof(buff));
1.1 misho 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)
1.1.1.4 misho 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)
1.1 misho 848:
1.1.1.3 misho 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:
1.1.1.5 ! misho 861: char *parse_server(char *arg, struct server_details *sdetails)
1.1 misho 862: {
1.1.1.5 ! misho 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));
1.1 misho 869:
1.1.1.5 ! misho 870: *sdetails->interface = 0;
! 871: sdetails->addr_type = AF_UNSPEC;
! 872:
! 873: if (strcmp(arg, "#") == 0)
1.1.1.2 misho 874: {
1.1.1.5 ! misho 875: if (sdetails->flags)
! 876: *sdetails->flags |= SERV_USE_RESOLV;
! 877: sdetails->addr_type = AF_LOCAL;
! 878: sdetails->valid = 1;
1.1.1.2 misho 879: return NULL;
880: }
1.1.1.5 ! misho 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))
1.1 misho 885: return _("bad port");
886:
887: if ((portno = split_chr(arg, '#')) && /* is there a port no. */
1.1.1.5 ! misho 888: !atoi_check16(portno, &sdetails->serv_port))
1.1 misho 889: return _("bad port");
890:
1.1.1.5 ! misho 891: sdetails->scope_id = split_chr(arg, '%');
1.1 misho 892:
1.1.1.5 ! misho 893: if (sdetails->source) {
! 894: sdetails->interface_opt = split_chr(sdetails->source, '@');
1.1.1.4 misho 895:
1.1.1.5 ! misho 896: if (sdetails->interface_opt)
1.1.1.4 misho 897: {
898: #if defined(SO_BINDTODEVICE)
1.1.1.5 ! misho 899: safe_strncpy(sdetails->interface, sdetails->source, IF_NAMESIZE);
! 900: sdetails->source = sdetails->interface_opt;
1.1.1.4 misho 901: #else
902: return _("interface binding not supported");
903: #endif
904: }
905: }
906:
1.1.1.5 ! misho 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)
1.1 misho 971: {
1.1.1.5 ! misho 972: sdetails->addr->in.sin_port = htons(sdetails->serv_port);
! 973: sdetails->addr->sa.sa_family = sdetails->source_addr->sa.sa_family = AF_INET;
1.1 misho 974: #ifdef HAVE_SOCKADDR_SA_LEN
1.1.1.5 ! misho 975: sdetails->source_addr->in.sin_len = sdetails->addr->in.sin_len = sizeof(struct sockaddr_in);
1.1 misho 976: #endif
1.1.1.5 ! misho 977: sdetails->source_addr->in.sin_addr.s_addr = INADDR_ANY;
! 978: sdetails->source_addr->in.sin_port = htons(daemon->query_port);
1.1 misho 979:
1.1.1.5 ! misho 980: if (sdetails->source)
1.1 misho 981: {
1.1.1.5 ! misho 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)
1.1 misho 986: {
1.1.1.5 ! misho 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: {
1.1 misho 998: #if defined(SO_BINDTODEVICE)
1.1.1.5 ! misho 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);
1.1 misho 1004: #else
1.1.1.5 ! misho 1005: return _("interface binding not supported");
1.1 misho 1006: #endif
1.1.1.5 ! misho 1007: }
1.1 misho 1008: }
1009: }
1010: }
1.1.1.5 ! misho 1011: else if (sdetails->addr_type == AF_INET6)
1.1 misho 1012: {
1.1.1.5 ! misho 1013: if (sdetails->scope_id && (sdetails->scope_index = if_nametoindex(sdetails->scope_id)) == 0)
1.1 misho 1014: return _("bad interface name");
1.1.1.5 ! misho 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;
1.1 misho 1023: #ifdef HAVE_SOCKADDR_SA_LEN
1.1.1.5 ! misho 1024: sdetails->addr->in6.sin6_len = sdetails->source_addr->in6.sin6_len = sizeof(sdetails->addr->in6);
1.1 misho 1025: #endif
1.1.1.5 ! misho 1026: if (sdetails->source)
1.1 misho 1027: {
1.1.1.5 ! misho 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)
1.1 misho 1032: {
1.1.1.5 ! misho 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: {
1.1 misho 1044: #if defined(SO_BINDTODEVICE)
1.1.1.5 ! misho 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);
1.1 misho 1050: #else
1.1.1.5 ! misho 1051: return _("interface binding not supported");
1.1 misho 1052: #endif
1.1.1.5 ! misho 1053: }
1.1 misho 1054: }
1055: }
1056: }
1.1.1.5 ! misho 1057: else if (sdetails->addr_type != AF_LOCAL)
1.1 misho 1058: return _("bad address");
1.1.1.5 ! misho 1059:
1.1 misho 1060: return NULL;
1061: }
1062:
1.1.1.5 ! misho 1063: int parse_server_next(struct server_details *sdetails)
1.1.1.2 misho 1064: {
1.1.1.5 ! misho 1065: /* Looping over resolved addresses? */
! 1066: if (sdetails->hostinfo)
1.1.1.4 misho 1067: {
1.1.1.5 ! misho 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;
1.1.1.4 misho 1091: }
1.1.1.5 ! misho 1092: /* Stop iterating here, we used all available addresses */
! 1093: return 0;
! 1094: }
1.1.1.4 misho 1095:
1.1.1.5 ! misho 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;
1.1.1.2 misho 1118:
1.1.1.5 ! misho 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");
1.1.1.2 misho 1154:
1.1.1.5 ! misho 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: }
1.1.1.2 misho 1173:
1.1.1.5 ! misho 1174: if (sdetails.orig_hostinfo)
! 1175: freeaddrinfo(sdetails.orig_hostinfo);
! 1176: }
! 1177: }
! 1178:
! 1179: return NULL;
1.1.1.2 misho 1180: }
1181:
1.1.1.5 ! misho 1182: static char *domain_rev6(int from_file, char *server, struct in6_addr *addr6, int size)
1.1.1.2 misho 1183: {
1.1.1.5 ! misho 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;
1.1.1.2 misho 1193:
1.1.1.5 ! misho 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;
1.1.1.2 misho 1211:
1.1.1.5 ! misho 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: }
1.1.1.2 misho 1266:
1.1.1.5 ! misho 1267: return NULL;
1.1.1.2 misho 1268: }
1269:
1.1 misho 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:
1.1.1.4 misho 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);
1.1.1.5 ! misho 1357: if (config->flags & CONFIG_NAME)
! 1358: free(config->hostname);
1.1.1.4 misho 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:
1.1 misho 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;
1.1.1.2 misho 1409: int option_ok = 0;
1.1 misho 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;
1.1.1.2 misho 1429: option_ok = 1;
1.1 misho 1430: break;
1431: }
1432:
1433: if (strstr(arg, "option:") == arg)
1434: {
1.1.1.2 misho 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: }
1.1 misho 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;
1.1.1.2 misho 1455: option_ok = 1;
1.1 misho 1456: }
1457: else
1458: {
1.1.1.2 misho 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: }
1.1 misho 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;
1.1.1.5 ! misho 1475: if ((new->flags & DHOPT_ENCAPSULATE) || flags == DHOPT_MATCH)
! 1476: goto_err(_("inappropriate vendor:"));
1.1 misho 1477: }
1478: else if (strstr(arg, "encap:") == arg)
1479: {
1480: new->u.encap = atoi(arg+6);
1481: new->flags |= DHOPT_ENCAPSULATE;
1.1.1.5 ! misho 1482: if ((new->flags & DHOPT_VENDOR) || flags == DHOPT_MATCH)
! 1483: goto_err(_("inappropriate encap:"));
1.1 misho 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: {
1.1.1.2 misho 1491: option_ok = 1;
1.1 misho 1492: break;
1493: }
1494: }
1495: else
1496: {
1497: /* allow optional "net:" or "tag:" for consistency */
1.1.1.4 misho 1498: const char *name = (is_tag_prefix(arg)) ? arg+4 : set_prefix(arg);
1499: new->netid = dhcp_netid_create(name, new->netid);
1.1 misho 1500: }
1501:
1502: arg = comma;
1503: }
1504:
1505: #ifdef HAVE_DHCP6
1506: if (is6)
1507: {
1508: if (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))
1.1.1.4 misho 1509: goto_err(_("unsupported encapsulation for IPv6 option"));
1.1 misho 1510:
1511: if (opt_len == 0 &&
1512: !(new->flags & DHOPT_RFC3925))
1.1.1.2 misho 1513: opt_len = lookup_dhcp_len(AF_INET6, new->opt);
1.1 misho 1514: }
1515: else
1516: #endif
1517: if (opt_len == 0 &&
1518: !(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
1.1.1.2 misho 1519: opt_len = lookup_dhcp_len(AF_INET, new->opt);
1.1 misho 1520:
1521: /* option may be missing with rfc3925 match */
1.1.1.2 misho 1522: if (!option_ok)
1.1.1.4 misho 1523: goto_err(_("bad dhcp-option"));
1.1 misho 1524:
1525: if (comma)
1526: {
1527: /* characterise the value */
1528: char c;
1.1.1.4 misho 1529: int found_dig = 0, found_colon = 0;
1.1 misho 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;
1.1.1.4 misho 1543: found_colon = 1;
1.1 misho 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: {
1.1.1.4 misho 1553: is_dec = is_hex = 0;
1.1 misho 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;
1.1.1.4 misho 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
1.1 misho 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))
1.1.1.4 misho 1601: goto_err(_("bad IP address"));
1.1 misho 1602:
1603: if (is6 && !is_addr6)
1.1.1.4 misho 1604: goto_err(_("bad IPv6 address"));
1.1 misho 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;
1.1.1.4 misho 1623: /* fall through */
1.1 misho 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, '/');
1.1.1.3 misho 1696: if (!inet_pton(AF_INET, cp, &in))
1.1.1.4 misho 1697: goto_err(_("bad IPv4 address"));
1.1 misho 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: }
1.1.1.4 misho 1742:
1743: goto_err(_("bad IPv6 address"));
1.1 misho 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)))
1.1.1.4 misho 1770: goto_err(_("bad domain in dhcp-option"));
1.1 misho 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 */
1.1.1.4 misho 1817: if (new->opt == OPTION_SIP_SERVER && m)
1.1 misho 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: {
1.1.1.4 misho 1855: unsigned char *p = NULL, *q, *newp, *end;
1.1 misho 1856: int len = 0;
1.1.1.4 misho 1857: int header_size = (is6 && new->opt == OPTION6_NTP_SERVER) ? 4 : 0;
1.1 misho 1858: arg = comma;
1859: comma = split(arg);
1860:
1861: while (arg && *arg)
1862: {
1863: char *dom = canonicalise_opt(arg);
1864: if (!dom)
1.1.1.4 misho 1865: goto_err(_("bad domain in dhcp-option"));
1.1 misho 1866:
1.1.1.4 misho 1867: newp = opt_malloc(len + header_size + strlen(dom) + 2);
1.1 misho 1868:
1869: if (p)
1870: {
1871: memcpy(newp, p, len);
1872: free(p);
1873: }
1874:
1875: p = newp;
1.1.1.4 misho 1876: q = p + len;
1877: end = do_rfc1035_name(q + header_size, dom, NULL);
1.1 misho 1878: *end++ = 0;
1.1.1.4 misho 1879: if (is6 && new->opt == OPTION6_NTP_SERVER)
1880: {
1881: PUTSHORT(NTP_SUBOPTION_SRV_FQDN, q);
1882: PUTSHORT(end - q - 2, q);
1883: }
1.1 misho 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))))
1.1.1.4 misho 1909: goto_err(_("dhcp-option too long"));
1.1 misho 1910:
1911: if (flags == DHOPT_MATCH)
1912: {
1913: if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||
1914: !new->netid ||
1915: new->netid->next)
1.1.1.4 misho 1916: goto_err(_("illegal dhcp-match"));
1.1 misho 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;
1.1.1.4 misho 1941: on_error:
1942: dhcp_opt_free(new);
1943: return 0;
1.1 misho 1944: }
1945:
1946: #endif
1947:
1948: void set_option_bool(unsigned int opt)
1949: {
1.1.1.4 misho 1950: option_var(opt) |= option_val(opt);
1.1 misho 1951: }
1952:
1953: void reset_option_bool(unsigned int opt)
1954: {
1.1.1.4 misho 1955: option_var(opt) &= ~(option_val(opt));
1956: }
1957:
1.1.1.2 misho 1958: static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only)
1.1 misho 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:
1.1.1.5 ! misho 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:
1.1 misho 2021: case '7': /* --conf-dir */
2022: {
2023: DIR *dir_stream;
2024: struct dirent *ent;
2025: char *directory, *path;
2026: struct list {
1.1.1.4 misho 2027: char *name;
1.1 misho 2028: struct list *next;
1.1.1.4 misho 2029: } *ignore_suffix = NULL, *match_suffix = NULL, *files = NULL, *li;
1.1 misho 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);
1.1.1.3 misho 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 */
1.1.1.4 misho 2051: li->name = opt_string_alloc(arg+1);
1.1.1.3 misho 2052: }
2053: }
2054: else
2055: {
2056: li->next = ignore_suffix;
2057: ignore_suffix = li;
2058: /* Have to copy: buffer is overwritten */
1.1.1.4 misho 2059: li->name = opt_string_alloc(arg);
1.1.1.3 misho 2060: }
2061: }
2062: }
1.1 misho 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:
1.1.1.3 misho 2079: if (match_suffix)
2080: {
2081: for (li = match_suffix; li; li = li->next)
2082: {
2083: /* check for required suffices */
1.1.1.4 misho 2084: size_t ls = strlen(li->name);
1.1.1.3 misho 2085: if (len > ls &&
1.1.1.4 misho 2086: strcmp(li->name, &ent->d_name[len - ls]) == 0)
1.1.1.3 misho 2087: break;
2088: }
2089: if (!li)
2090: continue;
2091: }
2092:
1.1 misho 2093: for (li = ignore_suffix; li; li = li->next)
2094: {
2095: /* check for proscribed suffices */
1.1.1.4 misho 2096: size_t ls = strlen(li->name);
1.1 misho 2097: if (len > ls &&
1.1.1.4 misho 2098: strcmp(li->name, &ent->d_name[len - ls]) == 0)
1.1 misho 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))
1.1.1.4 misho 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: }
1.1.1.5 ! misho 2127: else
! 2128: free(path);
1.1.1.4 misho 2129:
1.1 misho 2130: }
1.1.1.4 misho 2131:
2132: for (li = files; li; li = li->next)
2133: one_file(li->name, 0);
2134:
1.1 misho 2135: closedir(dir_stream);
2136: free(directory);
2137: for(; ignore_suffix; ignore_suffix = li)
2138: {
2139: li = ignore_suffix->next;
1.1.1.4 misho 2140: free(ignore_suffix->name);
1.1 misho 2141: free(ignore_suffix);
2142: }
1.1.1.3 misho 2143: for(; match_suffix; match_suffix = li)
2144: {
2145: li = match_suffix->next;
1.1.1.4 misho 2146: free(match_suffix->name);
1.1.1.3 misho 2147: free(match_suffix);
2148: }
1.1.1.4 misho 2149: for(; files; files = li)
2150: {
2151: li = files->next;
2152: free(files->name);
2153: free(files);
2154: }
1.1 misho 2155: break;
2156: }
2157:
1.1.1.2 misho 2158: case LOPT_ADD_SBNET: /* --add-subnet */
2159: set_option_bool(OPT_CLIENT_SUBNET);
2160: if (arg)
2161: {
1.1.1.3 misho 2162: char *err, *end;
1.1.1.2 misho 2163: comma = split(arg);
1.1.1.3 misho 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)
1.1.1.4 misho 2171: ret_err_free(err, new);
1.1.1.3 misho 2172: if (!atoi_check(end, &new->mask))
1.1.1.4 misho 2173: ret_err_free(gen_err, new);
1.1.1.3 misho 2174: new->addr_used = 1;
2175: }
2176: else if (!atoi_check(arg, &new->mask))
1.1.1.4 misho 2177: ret_err_free(gen_err, new);
1.1.1.3 misho 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)
1.1.1.4 misho 2189: ret_err_free(err, new);
1.1.1.3 misho 2190: if (!atoi_check(end, &new->mask))
1.1.1.4 misho 2191: ret_err_free(gen_err, new);
1.1.1.3 misho 2192: new->addr_used = 1;
2193: }
2194: else
2195: {
2196: if (!atoi_check(comma, &new->mask))
1.1.1.4 misho 2197: ret_err_free(gen_err, new);
1.1.1.3 misho 2198: }
2199:
2200: daemon->add_subnet6 = new;
2201: }
1.1.1.2 misho 2202: }
2203: break;
2204:
1.1 misho 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;
1.1.1.4 misho 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:
1.1 misho 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;
1.1.1.4 misho 2241:
1.1 misho 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: }
1.1.1.2 misho 2275:
2276: case LOPT_SERVERS_FILE:
2277: daemon->servers_file = opt_string_alloc(arg);
2278: break;
1.1 misho 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))))
1.1.1.5 ! misho 2295: {
! 2296: free(name);
! 2297: free(target);
! 2298: ret_err(_("bad MX name"));
! 2299: }
1.1 misho 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:
1.1.1.4 misho 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:
1.1 misho 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 */
1.1.1.4 misho 2332: # if !defined(HAVE_SCRIPT)
1.1 misho 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:
1.1.1.3 misho 2347: case LOPT_DHCP_HOST: /* --dhcp-hostsfile */
2348: case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
2349: case 'H': /* --addn-hosts */
1.1 misho 2350: {
2351: struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
2352: new->fname = opt_string_alloc(arg);
1.1.1.5 ! misho 2353: new->index = daemon->host_index++;
1.1 misho 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;
1.1.1.3 misho 2369: }
2370:
1.1 misho 2371: break;
2372: }
1.1.1.5 ! misho 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: }
1.1 misho 2392:
2393: case LOPT_AUTHSERV: /* --auth-server */
1.1.1.4 misho 2394: comma = split(arg);
1.1 misho 2395:
2396: daemon->authserver = opt_string_alloc(arg);
1.1.1.4 misho 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: };
1.1 misho 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));
1.1.1.5 ! misho 2454: new->domain = canonicalise_opt(arg);
! 2455: if (!new->domain)
! 2456: ret_err_free(_("invalid auth-zone"), new);
! 2457: new->subnet = NULL;
1.1.1.4 misho 2458: new->exclude = NULL;
1.1.1.2 misho 2459: new->interface_names = NULL;
1.1 misho 2460: new->next = daemon->auth_zones;
2461: daemon->auth_zones = new;
2462:
2463: while ((arg = comma))
2464: {
2465: int prefixlen = 0;
1.1.1.4 misho 2466: int is_exclude = 0;
1.1 misho 2467: char *prefix;
1.1.1.2 misho 2468: struct addrlist *subnet = NULL;
1.1.1.4 misho 2469: union all_addr addr;
1.1 misho 2470:
2471: comma = split(arg);
2472: prefix = split_chr(arg, '/');
2473:
2474: if (prefix && !atoi_check(prefix, &prefixlen))
2475: ret_err(gen_err);
2476:
1.1.1.4 misho 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))
1.1 misho 2484: {
1.1.1.2 misho 2485: subnet = opt_malloc(sizeof(struct addrlist));
1.1 misho 2486: subnet->prefixlen = (prefixlen == 0) ? 24 : prefixlen;
1.1.1.2 misho 2487: subnet->flags = ADDRLIST_LITERAL;
1.1 misho 2488: }
1.1.1.4 misho 2489: else if (inet_pton(AF_INET6, arg, &addr.addr6))
1.1 misho 2490: {
1.1.1.2 misho 2491: subnet = opt_malloc(sizeof(struct addrlist));
1.1 misho 2492: subnet->prefixlen = (prefixlen == 0) ? 64 : prefixlen;
1.1.1.2 misho 2493: subnet->flags = ADDRLIST_LITERAL | ADDRLIST_IPV6;
1.1 misho 2494: }
1.1.1.2 misho 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;
1.1.1.4 misho 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: }
1.1.1.2 misho 2527: }
1.1 misho 2528: }
2529: break;
2530: }
1.1.1.2 misho 2531:
1.1 misho 2532: case LOPT_AUTHSOA: /* --auth-soa */
2533: comma = split(arg);
1.1.1.2 misho 2534: daemon->soa_sn = (u32)atoi(arg);
1.1 misho 2535: if (comma)
2536: {
2537: char *cp;
2538: arg = comma;
2539: comma = split(arg);
2540: daemon->hostmaster = opt_string_alloc(arg);
1.1.1.5 ! misho 2541: for (cp = daemon->hostmaster; cp && *cp; cp++)
1.1 misho 2542: if (*cp == '@')
2543: *cp = '.';
2544:
2545: if (comma)
2546: {
2547: arg = comma;
2548: comma = split(arg);
1.1.1.2 misho 2549: daemon->soa_refresh = (u32)atoi(arg);
1.1 misho 2550: if (comma)
2551: {
2552: arg = comma;
2553: comma = split(arg);
1.1.1.2 misho 2554: daemon->soa_retry = (u32)atoi(arg);
1.1 misho 2555: if (comma)
1.1.1.3 misho 2556: daemon->soa_expiry = (u32)atoi(comma);
1.1 misho 2557: }
2558: }
2559: }
2560:
2561: break;
2562:
1.1.1.2 misho 2563: case 's': /* --domain */
2564: case LOPT_SYNTH: /* --synth-domain */
1.1 misho 2565: if (strcmp (arg, "#") == 0)
2566: set_option_bool(OPT_RESOLV_DOMAIN);
2567: else
2568: {
1.1.1.5 ! misho 2569: char *d, *d_raw = arg;
1.1 misho 2570: comma = split(arg);
1.1.1.5 ! misho 2571: if (!(d = canonicalise_opt(d_raw)))
1.1 misho 2572: ret_err(gen_err);
2573: else
2574: {
1.1.1.5 ! misho 2575: free(d); /* allocate this again below. */
1.1 misho 2576: if (comma)
2577: {
2578: struct cond_domain *new = opt_malloc(sizeof(struct cond_domain));
2579: char *netpart;
1.1.1.2 misho 2580:
2581: new->prefix = NULL;
1.1.1.4 misho 2582: new->indexed = 0;
1.1.1.5 ! misho 2583: new->prefixlen = 0;
1.1.1.4 misho 2584:
1.1 misho 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))
1.1.1.4 misho 2592: ret_err_free(gen_err, new);
1.1 misho 2593: else if (inet_pton(AF_INET, comma, &new->start))
2594: {
1.1.1.5 ! misho 2595: int mask;
! 2596:
! 2597: if (msize > 32)
! 2598: ret_err_free(_("bad prefix length"), new);
! 2599:
! 2600: mask = (1 << (32 - msize)) - 1;
1.1 misho 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: {
1.1.1.2 misho 2606: if (option != 's')
2607: {
2608: if (!(new->prefix = canonicalise_opt(arg)) ||
2609: strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
1.1.1.4 misho 2610: ret_err_free(_("bad prefix"), new);
1.1.1.2 misho 2611: }
1.1.1.5 ! misho 2612: else if (strcmp(arg, "local") != 0)
1.1.1.4 misho 2613: ret_err_free(gen_err, new);
1.1 misho 2614: else
2615: {
1.1.1.5 ! misho 2616: /* local=/xxx.yyy.zzz.in-addr.arpa/ */
! 2617: domain_rev4(0, NULL, &new->start, msize);
! 2618:
1.1.1.3 misho 2619: /* local=/<domain>/ */
1.1.1.5 ! misho 2620: /* d_raw can't failed to canonicalise here, checked above. */
! 2621: add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, d_raw, NULL);
1.1 misho 2622: }
2623: }
2624: }
2625: else if (inet_pton(AF_INET6, comma, &new->start6))
2626: {
1.1.1.5 ! misho 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:
1.1 misho 2634: new->is6 = 1;
1.1.1.5 ! misho 2635: new->prefixlen = msize;
1.1.1.2 misho 2636:
1.1 misho 2637: /* prefix==64 overflows the mask calculation above */
1.1.1.5 ! misho 2638: if (msize <= 64)
1.1 misho 2639: mask = (u64)-1LL;
1.1.1.2 misho 2640:
1.1 misho 2641: new->end6 = new->start6;
2642: setaddr6part(&new->start6, addrpart & ~mask);
2643: setaddr6part(&new->end6, addrpart | mask);
2644:
1.1.1.5 ! misho 2645: if (arg)
1.1 misho 2646: {
1.1.1.2 misho 2647: if (option != 's')
2648: {
2649: if (!(new->prefix = canonicalise_opt(arg)) ||
2650: strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
1.1.1.4 misho 2651: ret_err_free(_("bad prefix"), new);
1.1.1.2 misho 2652: }
1.1.1.5 ! misho 2653: else if (strcmp(arg, "local") != 0)
1.1.1.4 misho 2654: ret_err_free(gen_err, new);
1.1 misho 2655: else
2656: {
1.1.1.2 misho 2657: /* generate the equivalent of
2658: local=/xxx.yyy.zzz.ip6.arpa/ */
1.1.1.5 ! misho 2659: domain_rev6(0, NULL, &new->start6, msize);
1.1.1.3 misho 2660:
2661: /* local=/<domain>/ */
1.1.1.5 ! misho 2662: /* d_raw can't failed to canonicalise here, checked above. */
! 2663: add_update_server(SERV_LITERAL_ADDRESS, NULL, NULL, NULL, d_raw, NULL);
1.1 misho 2664: }
2665: }
2666: }
2667: else
1.1.1.4 misho 2668: ret_err_free(gen_err, new);
1.1 misho 2669: }
1.1.1.2 misho 2670: else
1.1 misho 2671: {
1.1.1.2 misho 2672: char *prefstr;
1.1 misho 2673: arg = split(comma);
1.1.1.2 misho 2674: prefstr = split(arg);
2675:
1.1 misho 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))
1.1.1.4 misho 2682: ret_err_free(gen_err, new);
1.1 misho 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))
1.1.1.4 misho 2690: ret_err_free(gen_err, new);
1.1 misho 2691: }
1.1.1.5 ! misho 2692: else if (option == 's')
! 2693: {
! 2694: /* subnet from interface. */
! 2695: new->interface = opt_string_alloc(comma);
! 2696: new->al = NULL;
! 2697: }
! 2698: else
1.1.1.4 misho 2699: ret_err_free(gen_err, new);
1.1.1.5 ! misho 2700:
1.1.1.2 misho 2701: if (option != 's' && prefstr)
2702: {
2703: if (!(new->prefix = canonicalise_opt(prefstr)) ||
2704: strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
1.1.1.4 misho 2705: ret_err_free(_("bad prefix"), new);
1.1.1.2 misho 2706: }
1.1 misho 2707: }
2708:
1.1.1.5 ! misho 2709: new->domain = canonicalise_opt(d_raw);
1.1.1.2 misho 2710: if (option == 's')
2711: {
2712: new->next = daemon->cond_domain;
2713: daemon->cond_domain = new;
2714: }
2715: else
2716: {
1.1.1.4 misho 2717: char *star;
2718: if (new->prefix &&
2719: (star = strrchr(new->prefix, '*'))
2720: && *(star+1) == 0)
2721: {
2722: *star = 0;
2723: new->indexed = 1;
1.1.1.5 ! misho 2724: if (new->is6 && new->prefixlen < 64)
! 2725: ret_err_free(_("prefix length too small"), new);
1.1.1.4 misho 2726: }
1.1.1.5 ! misho 2727: new->next = daemon->synth_domains;
! 2728: daemon->synth_domains = new;
1.1.1.2 misho 2729: }
1.1 misho 2730: }
1.1.1.2 misho 2731: else if (option == 's')
1.1.1.5 ! misho 2732: daemon->domain_suffix = canonicalise_opt(d_raw);
1.1.1.2 misho 2733: else
2734: ret_err(gen_err);
1.1 misho 2735: }
2736: }
2737: break;
2738:
1.1.1.3 misho 2739: case LOPT_CPE_ID: /* --add-dns-client */
2740: if (arg)
2741: daemon->dns_client_id = opt_string_alloc(arg);
2742: break;
2743:
1.1.1.5 ! misho 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:
1.1.1.3 misho 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:
1.1 misho 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:
1.1.1.2 misho 2832: case LOPT_TFTP: /* --enable-tftp */
2833: set_option_bool(OPT_TFTP);
2834: if (!arg)
2835: break;
2836: /* fall through */
2837:
1.1 misho 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: }
1.1.1.2 misho 2849: else if (option == LOPT_TFTP)
2850: {
2851: new->next = daemon->tftp_interfaces;
2852: daemon->tftp_interfaces = new;
2853: }
1.1 misho 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 */
1.1.1.3 misho 2864: case LOPT_IGNORE_ADDR: /* --ignore-address */
2865: {
1.1.1.5 ! misho 2866: union all_addr addr;
! 2867: int prefix, is6 = 0;
! 2868: struct bogus_addr *baddr;
! 2869:
1.1 misho 2870: unhide_metas(arg);
1.1.1.5 ! misho 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)
1.1 misho 2882: {
1.1.1.5 ! misho 2883: if (is6)
! 2884: prefix = 128;
1.1.1.3 misho 2885: else
1.1.1.5 ! misho 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;
1.1 misho 2897: }
2898: else
1.1.1.5 ! misho 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: }
1.1 misho 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);
1.1.1.2 misho 2916: if (arg && (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0))
1.1 misho 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
1.1.1.4 misho 2935: ret_err_free(gen_err, new);
1.1 misho 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:
1.1.1.5 ! misho 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:
1.1 misho 2973: case 'S': /* --server */
2974: case LOPT_LOCAL: /* --local */
2975: case 'A': /* --address */
2976: {
1.1.1.5 ! misho 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:
1.1 misho 2991: unhide_metas(arg);
2992:
1.1.1.5 ! misho 2993: /* split the domain args, if any and skip to the end of them. */
! 2994: if (arg && *arg == '/')
1.1 misho 2995: {
1.1.1.5 ! misho 2996: char *last;
! 2997:
! 2998: domain = lastdomain = ++arg;
! 2999:
! 3000: while ((last = split_chr(arg, '/')))
1.1.1.4 misho 3001: {
1.1.1.5 ! misho 3002: lastdomain = arg;
! 3003: arg = last;
1.1.1.4 misho 3004: }
1.1 misho 3005: }
3006:
3007: if (!arg || !*arg)
1.1.1.5 ! misho 3008: flags = SERV_LITERAL_ADDRESS;
! 3009: else if (option == 'A')
1.1 misho 3010: {
1.1.1.5 ! misho 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"));
1.1 misho 3020: }
3021: else
3022: {
1.1.1.5 ! misho 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)
1.1.1.4 misho 3043: {
1.1.1.5 ! misho 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;
1.1.1.4 misho 3064: }
1.1.1.5 ! misho 3065:
! 3066: if (flags & SERV_LITERAL_ADDRESS)
! 3067: break;
1.1 misho 3068: }
1.1.1.5 ! misho 3069:
! 3070: if (sdetails.orig_hostinfo)
! 3071: freeaddrinfo(sdetails.orig_hostinfo);
1.1 misho 3072:
1.1.1.5 ! misho 3073: break;
1.1 misho 3074: }
3075:
1.1.1.2 misho 3076: case LOPT_REV_SERV: /* --rev-server */
3077: {
3078: char *string;
3079: int size;
3080: struct in_addr addr4;
3081: struct in6_addr addr6;
1.1.1.5 ! misho 3082:
1.1.1.2 misho 3083: unhide_metas(arg);
1.1.1.4 misho 3084: if (!arg)
1.1.1.2 misho 3085: ret_err(gen_err);
1.1.1.4 misho 3086:
3087: comma=split(arg);
3088:
1.1.1.5 ! misho 3089: if (!(string = split_chr(arg, '/')) || !atoi_check(string, &size))
! 3090: size = -1;
! 3091:
1.1.1.2 misho 3092: if (inet_pton(AF_INET, arg, &addr4))
1.1.1.4 misho 3093: {
1.1.1.5 ! misho 3094: if (size == -1)
! 3095: size = 32;
! 3096:
! 3097: if ((string = domain_rev4(servers_only, comma, &addr4, size)))
! 3098: ret_err(string);
1.1.1.4 misho 3099: }
1.1.1.2 misho 3100: else if (inet_pton(AF_INET6, arg, &addr6))
1.1.1.5 ! misho 3101: {
! 3102: if (size == -1)
! 3103: size = 128;
! 3104:
! 3105: if ((string = domain_rev6(servers_only, comma, &addr6, size)))
! 3106: ret_err(string);
! 3107: }
1.1.1.2 misho 3108: else
3109: ret_err(gen_err);
3110:
3111: break;
3112: }
3113:
1.1 misho 3114: case LOPT_IPSET: /* --ipset */
1.1.1.5 ! misho 3115: case LOPT_NFTSET: /* --nftset */
1.1 misho 3116: #ifndef HAVE_IPSET
1.1.1.5 ! misho 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:
1.1 misho 3131: {
3132: struct ipsets ipsets_head;
3133: struct ipsets *ipsets = &ipsets_head;
1.1.1.5 ! misho 3134: struct ipsets **daemon_sets =
! 3135: (option == LOPT_IPSET) ? &daemon->ipsets : &daemon->nftsets;
1.1 misho 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)))
1.1.1.4 misho 3154: ret_err(gen_err);
1.1 misho 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: }
1.1.1.4 misho 3169:
1.1 misho 3170: if (!arg || !*arg)
1.1.1.4 misho 3171: ret_err(gen_err);
3172:
3173: for (size = 2, end = arg; *end; ++end)
1.1 misho 3174: if (*end == ',')
3175: ++size;
3176:
3177: sets = sets_pos = opt_malloc(sizeof(char *) * size);
3178:
3179: do {
1.1.1.5 ! misho 3180: char *p;
1.1 misho 3181: end = split(arg);
1.1.1.5 ! misho 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++;
1.1 misho 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;
1.1.1.5 ! misho 3193: ipsets->next = *daemon_sets;
! 3194: *daemon_sets = ipsets_head.next;
1.1 misho 3195:
3196: break;
3197: }
1.1.1.5 ! misho 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: }
1.1 misho 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;
1.1.1.4 misho 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;
1.1 misho 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:
1.1.1.3 misho 3364: case LOPT_MAXPORT: /* --max-port */
3365: if (!atoi_check16(arg, &daemon->max_port))
3366: ret_err(gen_err);
3367: break;
3368:
1.1 misho 3369: case '0': /* --dns-forward-max */
3370: if (!atoi_check(arg, &daemon->ftabsize))
3371: ret_err(gen_err);
3372: break;
3373:
1.1.1.3 misho 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:
1.1 misho 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;
1.1.1.5 ! misho 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;
1.1 misho 3410:
3411: case 'T': /* --local-ttl */
3412: case LOPT_NEGTTL: /* --neg-ttl */
3413: case LOPT_MAXTTL: /* --max-ttl */
1.1.1.3 misho 3414: case LOPT_MINCTTL: /* --min-cache-ttl */
1.1 misho 3415: case LOPT_MAXCTTL: /* --max-cache-ttl */
3416: case LOPT_AUTHTTL: /* --auth-ttl */
1.1.1.3 misho 3417: case LOPT_DHCPTTL: /* --dhcp-ttl */
1.1 misho 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;
1.1.1.3 misho 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: }
1.1 misho 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;
1.1.1.3 misho 3436: else if (option == LOPT_DHCPTTL)
3437: {
3438: daemon->dhcp_ttl = (unsigned long)ttl;
3439: daemon->use_dhcp_ttl = 1;
3440: }
1.1 misho 3441: else
3442: daemon->local_ttl = (unsigned long)ttl;
3443: break;
3444: }
1.1.1.5 ! misho 3445:
! 3446: case LOPT_FAST_RETRY:
! 3447: daemon->fast_retry_timeout = TIMEOUT;
1.1 misho 3448:
1.1.1.5 ! misho 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:
1.1 misho 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:
1.1.1.3 misho 3482: case LOPT_TFTP_MTU: /* --tftp-mtu */
3483: if (!atoi_check(arg, &daemon->tftp_mtu))
3484: ret_err(gen_err);
3485: break;
3486:
1.1 misho 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;
1.1.1.4 misho 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;
1.1 misho 3524: #endif
3525:
3526: case LOPT_BRIDGE: /* --bridge-interface */
3527: {
1.1.1.4 misho 3528: struct dhcp_bridge *new;
3529:
1.1 misho 3530: if (!(comma = split(arg)) || strlen(arg) > IF_NAMESIZE - 1 )
3531: ret_err(_("bad bridge-interface"));
3532:
1.1.1.4 misho 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:
1.1 misho 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
1.1.1.4 misho 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:
1.1 misho 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: {
1.1.1.2 misho 3620: /* ignore empty tag */
1.1.1.4 misho 3621: if (arg[4])
3622: new->filter = dhcp_netid_create(arg+4, new->filter);
1.1 misho 3623: }
3624: else
3625: {
3626: if (new->netid.net)
1.1.1.4 misho 3627: {
3628: dhcp_context_free(new);
3629: ret_err(_("only one tag allowed"));
3630: }
1.1 misho 3631: else
1.1.1.4 misho 3632: new->netid.net = opt_string_alloc(set_prefix(arg));
1.1 misho 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)
1.1.1.4 misho 3648: {
3649: dhcp_context_free(new);
3650: ret_err(_("bad dhcp-range"));
3651: }
1.1 misho 3652:
3653: if (inet_pton(AF_INET, a[0], &new->start))
3654: {
3655: new->next = daemon->dhcp;
1.1.1.4 misho 3656: new->lease_time = DEFLEASE;
1.1 misho 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))
1.1.1.4 misho 3664: {
3665: dhcp_context_free(new);
3666: ret_err(_("bad dhcp-range"));
3667: }
1.1 misho 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], '.') &&
1.1.1.2 misho 3677: (inet_pton(AF_INET, a[2], &new->netmask) > 0))
1.1 misho 3678: {
3679: new->flags |= CONTEXT_NETMASK;
3680: leasepos = 3;
3681: if (!is_same_net(new->start, new->end, new->netmask))
1.1.1.4 misho 3682: {
3683: dhcp_context_free(new);
3684: ret_err(_("inconsistent DHCP range"));
3685: }
1.1.1.3 misho 3686:
1.1 misho 3687:
1.1.1.3 misho 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: }
1.1 misho 3694: }
3695: }
3696: #ifdef HAVE_DHCP6
3697: else if (inet_pton(AF_INET6, a[0], &new->start6))
3698: {
1.1.1.4 misho 3699: const char *err = NULL;
3700:
1.1.1.2 misho 3701: new->flags |= CONTEXT_V6;
1.1 misho 3702: new->prefix = 64; /* default */
3703: new->end6 = new->start6;
1.1.1.4 misho 3704: new->lease_time = DEFLEASE6;
1.1.1.2 misho 3705: new->next = daemon->dhcp6;
3706: daemon->dhcp6 = new;
3707:
1.1 misho 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 )
1.1.1.3 misho 3713: new->flags |= CONTEXT_RA;
1.1 misho 3714: else if (strcmp(a[leasepos], "ra-names") == 0)
3715: new->flags |= CONTEXT_RA_NAME | CONTEXT_RA;
1.1.1.3 misho 3716: else if (strcmp(a[leasepos], "ra-advrouter") == 0)
3717: new->flags |= CONTEXT_RA_ROUTER | CONTEXT_RA;
1.1 misho 3718: else if (strcmp(a[leasepos], "ra-stateless") == 0)
3719: new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA;
1.1.1.3 misho 3720: else if (strcmp(a[leasepos], "off-link") == 0)
3721: new->flags |= CONTEXT_RA_OFF_LINK;
1.1 misho 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: }
1.1.1.2 misho 3732:
1.1 misho 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:
1.1.1.4 misho 3747: if (new->prefix > 64)
1.1.1.2 misho 3748: {
1.1.1.3 misho 3749: if (new->flags & CONTEXT_RA)
1.1.1.4 misho 3750: err=(_("prefix length must be exactly 64 for RA subnets"));
1.1.1.2 misho 3751: else if (new->flags & CONTEXT_TEMPLATE)
1.1.1.4 misho 3752: err=(_("prefix length must be exactly 64 for subnet constructors"));
1.1.1.2 misho 3753: }
1.1.1.4 misho 3754: else if (new->prefix < 64)
3755: err=(_("prefix length must be at least 64"));
1.1.1.2 misho 3756:
1.1.1.4 misho 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: }
1.1.1.2 misho 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))
1.1.1.4 misho 3775: {
3776: dhcp_context_free(new);
3777: ret_err(_("prefix must be zero with \"constructor:\" argument"));
3778: }
1.1.1.2 misho 3779: }
3780:
1.1 misho 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
1.1.1.4 misho 3790: {
3791: dhcp_context_free(new);
3792: ret_err(_("bad dhcp-range"));
3793: }
1.1 misho 3794:
3795: if (leasepos < k)
3796: {
1.1.1.3 misho 3797: if (leasepos != k-1)
1.1.1.4 misho 3798: {
3799: dhcp_context_free(new);
3800: ret_err(_("bad dhcp-range"));
3801: }
1.1.1.3 misho 3802:
1.1 misho 3803: if (strcmp(a[leasepos], "infinite") == 0)
1.1.1.4 misho 3804: {
3805: new->lease_time = 0xffffffff;
3806: new->flags |= CONTEXT_SETLEASE;
3807: }
1.1 misho 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;
1.1.1.4 misho 3824: /* fall through */
1.1 misho 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))
1.1.1.4 misho 3843: ret_err_free(_("bad dhcp-range"), new);
1.1 misho 3844:
3845: new->lease_time = atoi(a[leasepos]) * fac;
1.1.1.4 misho 3846: new->flags |= CONTEXT_SETLEASE;
1.1 misho 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: }
1.1.1.4 misho 3854:
1.1 misho 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;
1.1.1.4 misho 3870: new->filter = NULL;
3871: new->clid = NULL;
1.1 misho 3872: #ifdef HAVE_DHCP6
1.1.1.4 misho 3873: new->addr6 = NULL;
3874: #endif
1.1 misho 3875:
1.1.1.4 misho 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: }
1.1 misho 3939:
1.1.1.4 misho 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: }
1.1 misho 3960:
1.1.1.4 misho 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: }
1.1 misho 3971: #endif
1.1.1.4 misho 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)
1.1 misho 4001: {
1.1.1.5 ! misho 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);
1.1.1.4 misho 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;
1.1 misho 4047:
1.1.1.4 misho 4048: if (*cp)
1.1 misho 4049: {
1.1.1.4 misho 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: }
1.1.1.2 misho 4085:
1.1 misho 4086: daemon->dhcp_conf = new;
4087: break;
4088: }
1.1.1.4 misho 4089:
1.1 misho 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: {
1.1.1.4 misho 4122: struct dhcp_netid *newtag = dhcp_netid_create(arg+4, NULL);
1.1 misho 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;
1.1.1.4 misho 4139: dhcp_netid_free(newtag);
1.1 misho 4140: break;
4141: }
4142: }
4143:
4144: arg = comma;
4145: }
4146:
4147: if (!new->set)
1.1.1.4 misho 4148: {
4149: dhcp_netid_free(new->tag);
4150: dhcp_netid_list_free(new->set);
4151: ret_err_free(_("bad tag-if"), new);
4152: }
1.1 misho 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)));
1.1.1.4 misho 4166:
4167: case LOPT_NAME_MATCH: /* --dhcp-name-match */
1.1 misho 4168: {
1.1.1.5 ! misho 4169: struct dhcp_match_name *new;
1.1.1.4 misho 4170: ssize_t len;
4171:
4172: if (!(comma = split(arg)) || (len = strlen(comma)) == 0)
4173: ret_err(gen_err);
4174:
1.1.1.5 ! misho 4175: new = opt_malloc(sizeof(struct dhcp_match_name));
1.1.1.4 misho 4176: new->wildcard = 0;
1.1.1.5 ! misho 4177: new->netid = opt_malloc(sizeof(struct dhcp_netid));
! 4178: new->netid->net = opt_string_alloc(set_prefix(arg));
1.1.1.4 misho 4179:
4180: if (comma[len-1] == '*')
1.1 misho 4181: {
1.1.1.4 misho 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);
1.1 misho 4196:
4197: if (!arg)
1.1.1.4 misho 4198: {
4199: ret_err(gen_err);
4200: }
1.1 misho 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);
1.1.1.2 misho 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: }
1.1 misho 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: }
1.1.1.2 misho 4240:
1.1 misho 4241: break;
4242: }
4243:
1.1.1.4 misho 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:
1.1 misho 4269: case LOPT_PXE_PROMT: /* --pxe-prompt */
4270: {
4271: struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
4272: int timeout;
1.1.1.4 misho 4273:
1.1 misho 4274: new->netid = NULL;
4275: new->opt = 10; /* PXE_MENU_PROMPT */
1.1.1.4 misho 4276: new->netid = dhcp_tags(&arg);
1.1 misho 4277:
4278: if (!arg)
1.1.1.4 misho 4279: {
4280: dhcp_opt_free(new);
4281: ret_err(gen_err);
4282: }
1.1 misho 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:
1.1.1.4 misho 4291: new->u.vendor_class = NULL;
4292: new->flags = DHOPT_VENDOR | DHOPT_VENDOR_PXE;
1.1 misho 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",
1.1.1.3 misho 4311: "IA32_EFI", "x86-64_EFI", "Xscale_EFI", "BC_EFI",
4312: "ARM32_EFI", "ARM64_EFI", NULL };
1.1 misho 4313: static int boottype = 32768;
4314:
4315: new->netid = NULL;
4316: new->sname = NULL;
4317: new->server.s_addr = 0;
1.1.1.4 misho 4318: new->netid = dhcp_tags(&arg);
1.1 misho 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:
1.1.1.5 ! misho 4382: dhcp_netid_free(new->netid);
! 4383: free(new);
1.1 misho 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)
1.1.1.4 misho 4398: {
4399: free(new->netid.net);
4400: ret_err_free(gen_err, new);
4401: }
1.1 misho 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;
1.1.1.5 ! misho 4418: int dig, colon;
1.1 misho 4419: struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
4420:
4421: if (!(comma = split(arg)))
1.1.1.4 misho 4422: ret_err_free(gen_err, new);
1.1 misho 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)
1.1.1.4 misho 4432: {
4433: free(new->netid.net);
4434: ret_err_free(gen_err, new);
4435: }
1.1 misho 4436: else
4437: new->enterprise = atoi(arg+11);
4438: }
4439: else
4440: comma = arg;
4441:
1.1.1.5 ! misho 4442: for (dig = 0, colon = 0, p = (unsigned char *)comma; *p; p++)
1.1 misho 4443: if (isxdigit(*p))
4444: dig = 1;
1.1.1.5 ! misho 4445: else if (*p == ':')
! 4446: colon = 1;
! 4447: else
1.1 misho 4448: break;
1.1.1.5 ! misho 4449:
1.1 misho 4450: unhide_metas(comma);
1.1.1.5 ! misho 4451: if (option == 'U' || option == 'j' || *p || !dig || !colon)
1.1 misho 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);
1.1.1.4 misho 4541: list = dhcp_netid_create(is_tag_prefix(arg) ? arg+4 :arg, list);
1.1 misho 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);
1.1.1.2 misho 4554: if (!(inet_pton(AF_INET, arg, &new->addr) > 0))
1.1.1.4 misho 4555: ret_err_free(_("bad dhcp-proxy address"), new);
1.1 misho 4556: new->next = daemon->override_relays;
4557: daemon->override_relays = new;
4558: arg = comma;
1.1.1.4 misho 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: }
1.1 misho 4572: }
4573: break;
1.1.1.5 ! misho 4574:
1.1.1.2 misho 4575: case LOPT_RELAY: /* --dhcp-relay */
4576: {
4577: struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
1.1.1.5 ! misho 4578: char *two = split(arg);
! 4579: char *three = split(two);
! 4580:
1.1.1.2 misho 4581: new->iface_index = 0;
1.1.1.5 ! misho 4582:
! 4583: if (two)
1.1.1.2 misho 4584: {
1.1.1.5 ! misho 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: }
1.1.1.2 misho 4607: #ifdef HAVE_DHCP6
1.1.1.5 ! misho 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: }
1.1.1.2 misho 4628: #endif
1.1.1.5 ! misho 4629:
! 4630: new->interface = opt_string_alloc(three);
! 4631: }
! 4632:
! 4633: if (!two)
1.1.1.4 misho 4634: {
4635: free(new->interface);
4636: ret_err_free(_("Bad dhcp-relay"), new);
4637: }
1.1.1.2 misho 4638:
4639: break;
4640: }
4641:
1.1 misho 4642: #endif
4643:
4644: #ifdef HAVE_DHCP6
1.1.1.2 misho 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;
1.1.1.4 misho 4651: new->mtu = 0;
4652: new->mtu_name = NULL;
1.1.1.2 misho 4653: new->name = opt_string_alloc(arg);
1.1.1.4 misho 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: }
1.1.1.2 misho 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)))
1.1.1.4 misho 4677: {
4678: err:
4679: free(new->name);
4680: ret_err_free(_("bad RA-params"), new);
4681: }
1.1.1.2 misho 4682:
4683: new->next = daemon->ra_interfaces;
4684: daemon->ra_interfaces = new;
4685: }
4686: break;
4687:
1.1 misho 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) ||
1.1.1.2 misho 4721: (!(inet_pton(AF_INET, a[0], &new->in) > 0)) ||
1.1.1.4 misho 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"));
1.1 misho 4725:
4726: if (dash &&
1.1.1.2 misho 4727: (!(inet_pton(AF_INET, dash, &new->end) > 0) ||
1.1 misho 4728: !is_same_net(new->in, new->end, new->mask) ||
4729: ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
1.1.1.4 misho 4730: ret_err_free(_("invalid alias range"), new);
1.1 misho 4731:
4732: break;
4733: }
4734:
4735: case LOPT_INTNAME: /* --interface-name */
1.1.1.5 ! misho 4736: case LOPT_DYNHOST: /* --dynamic-host */
1.1 misho 4737: {
4738: struct interface_name *new, **up;
1.1.1.5 ! misho 4739: char *domain = arg;
1.1 misho 4740:
1.1.1.5 ! misho 4741: arg = split(arg);
1.1 misho 4742:
4743: new = opt_malloc(sizeof(struct interface_name));
1.1.1.5 ! misho 4744: memset(new, 0, sizeof(struct interface_name));
! 4745: new->flags = IN4 | IN6;
1.1.1.2 misho 4746:
1.1 misho 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;
1.1.1.5 ! misho 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, '/')))
1.1.1.2 misho 4765: {
1.1.1.5 ! misho 4766: if (strcmp(comma, "4") == 0)
! 4767: new->flags &= ~IN6;
! 4768: else if (strcmp(comma, "6") == 0)
! 4769: new->flags &= ~IN4;
1.1.1.2 misho 4770: else
1.1.1.4 misho 4771: ret_err_free(gen_err, new);
1.1.1.5 ! misho 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:
1.1 misho 4796: break;
4797: }
4798:
4799: case LOPT_CNAME: /* --cname */
4800: {
4801: struct cname *new;
1.1.1.5 ! misho 4802: char *alias, *target=NULL, *last, *pen;
1.1.1.3 misho 4803: int ttl = -1;
1.1 misho 4804:
1.1.1.4 misho 4805: for (last = pen = NULL, comma = arg; comma; comma = split(comma))
4806: {
4807: pen = last;
4808: last = comma;
4809: }
4810:
4811: if (!pen)
1.1 misho 4812: ret_err(_("bad CNAME"));
1.1.1.4 misho 4813:
4814: if (pen != arg && atoi_check(last, &ttl))
4815: last = pen;
4816:
4817: while (arg != last)
1.1 misho 4818: {
1.1.1.4 misho 4819: int arglen = strlen(arg);
4820: alias = canonicalise_opt(arg);
4821:
1.1.1.5 ! misho 4822: if (!target)
! 4823: target = canonicalise_opt(last);
1.1.1.4 misho 4824: if (!alias || !target)
4825: {
4826: free(target);
4827: free(alias);
4828: ret_err(_("bad CNAME"));
4829: }
4830:
1.1 misho 4831: for (new = daemon->cnames; new; new = new->next)
1.1.1.4 misho 4832: if (hostname_isequal(new->alias, alias))
4833: {
4834: free(target);
4835: free(alias);
4836: ret_err(_("duplicate CNAME"));
4837: }
1.1 misho 4838: new = opt_malloc(sizeof(struct cname));
4839: new->next = daemon->cnames;
4840: daemon->cnames = new;
4841: new->alias = alias;
4842: new->target = target;
1.1.1.3 misho 4843: new->ttl = ttl;
1.1.1.4 misho 4844:
1.1.1.5 ! misho 4845: for (arg += arglen+1; *arg && isspace((unsigned char)*arg); arg++);
1.1 misho 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))))
1.1.1.4 misho 4860: {
4861: free(dom);
4862: free(target);
4863: ret_err(_("bad PTR record"));
4864: }
1.1 misho 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;
1.1.1.4 misho 4882: char *name=NULL, *replace = NULL;
1.1 misho 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]))))
1.1.1.4 misho 4895: {
4896: free(name);
4897: free(replace);
4898: ret_err(_("bad NAPTR record"));
4899: }
1.1 misho 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;
1.1.1.3 misho 4919: size_t len = 0;
1.1 misho 4920: char *data;
1.1.1.4 misho 4921: int class;
1.1 misho 4922:
4923: comma = split(arg);
4924: data = split(comma);
4925:
4926: new = opt_malloc(sizeof(struct txt_record));
1.1.1.4 misho 4927: new->name = NULL;
1.1 misho 4928:
1.1.1.4 misho 4929: if (!atoi_check(comma, &class) ||
1.1 misho 4930: !(new->name = canonicalise_opt(arg)) ||
4931: (data && (len = parse_hex(data, (unsigned char *)data, -1, NULL, NULL)) == -1U))
1.1.1.4 misho 4932: {
4933: free(new->name);
4934: ret_err_free(_("bad RR record"), new);
4935: }
4936:
1.1 misho 4937: new->len = 0;
1.1.1.4 misho 4938: new->class = class;
4939: new->next = daemon->rr;
4940: daemon->rr = new;
1.1 misho 4941:
4942: if (data)
4943: {
1.1.1.4 misho 4944: new->txt = opt_malloc(len);
1.1 misho 4945: new->len = len;
4946: memcpy(new->txt, data, len);
4947: }
4948:
4949: break;
4950: }
4951:
1.1.1.4 misho 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:
1.1 misho 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;
1.1.1.2 misho 4993: new->stat = 0;
4994:
1.1 misho 4995: if (!(new->name = canonicalise_opt(arg)))
1.1.1.4 misho 4996: ret_err_free(_("bad TXT record"), new);
1.1 misho 4997:
1.1.1.4 misho 4998: new->next = daemon->txt;
4999: daemon->txt = new;
1.1 misho 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)))
1.1.1.4 misho 5046: ret_err_free(_("bad SRV target"), name);
1.1 misho 5047:
5048: if (comma)
5049: {
5050: arg = comma;
5051: comma = split(arg);
5052: if (!atoi_check16(arg, &port))
1.1.1.4 misho 5053: {
5054: free(name);
5055: ret_err_free(_("invalid port number"), target);
5056: }
1.1 misho 5057:
5058: if (comma)
5059: {
5060: arg = comma;
5061: comma = split(arg);
5062: if (!atoi_check16(arg, &priority))
1.1.1.4 misho 5063: {
5064: free(name);
5065: ret_err_free(_("invalid priority"), target);
5066: }
1.1.1.3 misho 5067: if (comma && !atoi_check16(comma, &weight))
1.1.1.4 misho 5068: {
5069: free(name);
5070: ret_err_free(_("invalid weight"), target);
5071: }
1.1 misho 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: {
1.1.1.4 misho 5090: struct host_record *new;
1.1.1.3 misho 5091:
1.1 misho 5092: if (!arg || !(comma = split(arg)))
5093: ret_err(_("Bad host-record"));
5094:
1.1.1.4 misho 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:
1.1 misho 5100: while (arg)
5101: {
1.1.1.4 misho 5102: union all_addr addr;
1.1.1.3 misho 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);
1.1.1.4 misho 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: }
1.1 misho 5120: else
5121: {
1.1.1.5 ! misho 5122: char *canon = canonicalise_opt(arg);
1.1.1.4 misho 5123: struct name_list *nl;
1.1 misho 5124: if (!canon)
1.1.1.4 misho 5125: {
1.1.1.5 ! misho 5126: struct name_list *tmp, *next;
1.1.1.4 misho 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: }
1.1 misho 5134:
1.1.1.4 misho 5135: nl = opt_malloc(sizeof(struct name_list));
1.1 misho 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: }
1.1.1.2 misho 5162:
1.1.1.5 ! misho 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:
1.1.1.2 misho 5181: #ifdef HAVE_DNSSEC
1.1.1.4 misho 5182: case LOPT_DNSSEC_STAMP: /* --dnssec-timestamp */
1.1.1.3 misho 5183: daemon->timestamp_file = opt_string_alloc(arg);
5184: break;
5185:
1.1.1.4 misho 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 */
1.1.1.2 misho 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;
1.1.1.4 misho 5203: new->name = NULL;
1.1.1.2 misho 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)))
1.1.1.4 misho 5228: ret_err_free(_("bad trust anchor"), new);
1.1.1.2 misho 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; )
1.1.1.5 ! misho 5236: if (isspace((unsigned char)*cp))
1.1.1.2 misho 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)
1.1.1.4 misho 5242: {
5243: free(new->name);
5244: ret_err_free(_("bad HEX in trust anchor"), new);
5245: }
1.1.1.2 misho 5246:
5247: new->next = daemon->ds;
5248: daemon->ds = new;
5249:
5250: break;
5251: }
5252: #endif
5253:
1.1 misho 5254: default:
1.1.1.2 misho 5255: ret_err(_("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"));
1.1 misho 5256:
5257: }
5258:
5259: return 1;
5260: }
5261:
1.1.1.5 ! misho 5262: static void read_file(char *file, FILE *f, int hard_opt, int from_script)
1.1 misho 5263: {
5264: volatile int lineno = 0;
5265: char *buff = daemon->namebuff;
5266:
5267: while (fgets(buff, MAXDNAME, f))
5268: {
1.1.1.2 misho 5269: int white, i;
1.1.1.5 ! misho 5270: volatile int option;
1.1.1.4 misho 5271: char *errmess, *p, *arg, *start;
1.1 misho 5272: size_t len;
5273:
1.1.1.5 ! misho 5274: option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt;
! 5275:
1.1 misho 5276: /* Memory allocation failure longjmps here if mem_recover == 1 */
1.1.1.2 misho 5277: if (option != 0 || hard_opt == LOPT_REV_SERV)
1.1 misho 5278: {
5279: if (setjmp(mem_jmp))
5280: continue;
5281: mem_recover = 1;
5282: }
1.1.1.5 ! misho 5283:
1.1.1.4 misho 5284: arg = NULL;
1.1 misho 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:
1.1.1.5 ! misho 5324: if (isspace((unsigned char)*p))
1.1 misho 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");
1.1.1.2 misho 5379: else if (hard_opt == LOPT_REV_SERV && option != 'S' && option != LOPT_REV_SERV)
5380: errmess = _("illegal option");
1.1 misho 5381: }
5382:
5383: oops:
5384: if (errmess)
5385: strcpy(daemon->namebuff, errmess);
5386:
1.1.1.4 misho 5387: if (errmess || !one_opt(option, arg, daemon->namebuff, _("error"), 0, hard_opt == LOPT_REV_SERV))
1.1 misho 5388: {
1.1.1.5 ! misho 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:
1.1 misho 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:
1.1.1.4 misho 5404: #if defined(HAVE_DHCP) && defined(HAVE_INOTIFY)
1.1.1.3 misho 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:
1.1 misho 5418: static int one_file(char *file, int hard_opt)
5419: {
5420: FILE *f;
1.1.1.5 ! misho 5421: int nofile_ok = 0, do_popen = 0;
1.1 misho 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:
1.1.1.5 ! misho 5429: if (hard_opt == LOPT_CONF_OPT)
1.1 misho 5430: {
5431: /* default conf-file reading */
5432: hard_opt = 0;
5433: nofile_ok = 1;
5434: }
5435:
1.1.1.5 ! misho 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)
1.1 misho 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: }
1.1.1.5 ! misho 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")))
1.1 misho 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:
1.1.1.5 ! misho 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:
1.1 misho 5508: return 1;
5509: }
5510:
1.1.1.5 ! misho 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: }
1.1 misho 5525: /* expand any name which is a directory */
5526: struct hostsfile *expand_filelist(struct hostsfile *list)
5527: {
1.1.1.2 misho 5528: unsigned int i;
1.1.1.5 ! misho 5529: int entcnt, n;
! 5530: struct hostsfile *ah, *last, *next, **up;
! 5531: struct dirent **namelist;
1.1 misho 5532:
1.1.1.2 misho 5533: /* find largest used index */
5534: for (i = SRC_AH, ah = list; ah; ah = ah->next)
1.1 misho 5535: {
1.1.1.5 ! misho 5536: last = ah;
! 5537:
1.1 misho 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;
1.1.1.3 misho 5557:
1.1.1.5 ! misho 5558: entcnt = scandir(ah->fname, &namelist, file_filter, alphasort);
! 5559: if (entcnt < 0)
1.1 misho 5560: my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
5561: ah->fname, strerror(errno));
5562: else
5563: {
1.1.1.5 ! misho 5564: for (n = 0; n < entcnt; n++)
1.1 misho 5565: {
1.1.1.5 ! misho 5566: ent = namelist[n];
1.1 misho 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:
1.1.1.5 ! misho 5577: for (up = &list, ah1 = list; ah1; ah1 = next)
1.1 misho 5578: {
1.1.1.5 ! misho 5579: next = ah1->next;
! 5580:
1.1 misho 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;
1.1.1.5 ! misho 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;
1.1 misho 5591: break;
5592: }
1.1.1.5 ! misho 5593:
! 5594: up = &ah1->next;
1.1 misho 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: }
1.1.1.5 ! misho 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;
1.1 misho 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: }
1.1.1.5 ! misho 5629: free(namelist);
1.1 misho 5630: }
5631: }
5632:
5633: return list;
5634: }
5635:
1.1.1.2 misho 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);
1.1.1.5 ! misho 5647: read_file(daemon->servers_file, f, LOPT_REV_SERV, 0);
! 5648: fclose(f);
1.1.1.2 misho 5649: cleanup_servers();
1.1.1.5 ! misho 5650: check_servers(0);
1.1.1.2 misho 5651: }
5652:
1.1 misho 5653:
5654: #ifdef HAVE_DHCP
1.1.1.4 misho 5655: static void clear_dynamic_conf(void)
1.1 misho 5656: {
1.1.1.4 misho 5657: struct dhcp_config *configs, *cp, **up;
1.1 misho 5658:
1.1.1.4 misho 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)
1.1 misho 5665: {
1.1.1.5 ! misho 5666: *up = cp;
! 5667: dhcp_config_free(configs);
1.1.1.4 misho 5668: }
5669: else
5670: up = &configs->next;
5671: }
5672: }
1.1 misho 5673:
1.1.1.4 misho 5674: static void clear_dynamic_opt(void)
5675: {
5676: struct dhcp_opt *opts, *cp, **up;
1.1 misho 5677:
1.1.1.4 misho 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: {
1.1.1.5 ! misho 5684: *up = cp;
! 5685: dhcp_opt_free(opts);
1.1 misho 5686: }
1.1.1.4 misho 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: {
1.1 misho 5705: daemon->dhcp_hosts_file = expand_filelist(daemon->dhcp_hosts_file);
5706: for (hf = daemon->dhcp_hosts_file; hf; hf = hf->next)
1.1.1.4 misho 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: }
1.1 misho 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: }
1.1.1.4 misho 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
1.1 misho 5729: }
5730: #endif
1.1.1.4 misho 5731:
1.1 misho 5732: void read_opts(int argc, char **argv, char *compile_opts)
5733: {
1.1.1.4 misho 5734: size_t argbuf_size = MAXDNAME;
5735: char *argbuf = opt_malloc(argbuf_size);
1.1 misho 5736: char *buff = opt_malloc(MAXDNAME);
1.1.1.4 misho 5737: int option, testmode = 0;
5738: char *arg, *conffile = NULL;
1.1 misho 5739:
5740: opterr = 0;
5741:
5742: daemon = opt_malloc(sizeof(struct daemon));
5743: memset(daemon, 0, sizeof(struct daemon));
5744: daemon->namebuff = buff;
1.1.1.5 ! misho 5745: daemon->addrbuff = safe_malloc(ADDRSTRLEN);
! 5746:
1.1 misho 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;
1.1.1.5 ! misho 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:
1.1 misho 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: {
1.1.1.4 misho 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;
1.1 misho 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: {
1.1.1.4 misho 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: }
1.1 misho 5844: }
5845: else
5846: {
5847: #ifdef HAVE_GETOPT_LONG
1.1.1.2 misho 5848: if (!one_opt(option, arg, daemon->namebuff, _("try --help"), 1, 0))
1.1 misho 5849: #else
1.1.1.2 misho 5850: if (!one_opt(option, arg, daemon->namebuff, _("try -w"), 1, 0))
1.1 misho 5851: #endif
5852: die(_("bad command line options: %s"), daemon->namebuff, EC_BADCONF);
5853: }
5854: }
5855:
1.1.1.4 misho 5856: free(argbuf);
5857:
1.1 misho 5858: if (conffile)
1.1.1.3 misho 5859: {
1.1.1.4 misho 5860: one_file(conffile, 0);
5861: free(conffile);
1.1.1.3 misho 5862: }
1.1.1.4 misho 5863: else
1.1.1.5 ! misho 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
1.1 misho 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);
1.1.1.3 misho 5896: }
5897: }
1.1 misho 5898:
1.1.1.3 misho 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: {
1.1.1.4 misho 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: }
1.1.1.3 misho 5930:
1.1.1.4 misho 5931: /* Find any CNAME loops.*/
1.1.1.3 misho 5932: for (cn = daemon->cnames; cn; cn = cn->next)
1.1.1.4 misho 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: }
1.1.1.3 misho 5948: }
5949:
1.1 misho 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: }
1.1.1.4 misho 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: }
1.1 misho 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:
1.1.1.2 misho 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:
1.1 misho 6067: if (testmode)
6068: {
6069: fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
6070: exit(0);
6071: }
6072: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>