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