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