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