blob: 49b6f3fb174d8c86a8d4b6feb5117d6d6e5212f7 [file] [log] [blame]
San Mehatffd68722010-01-20 09:56:15 -08001/* dnsmasq is Copyright (c) 2000-2009 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
22static volatile int mem_recover = 0;
23static jmp_buf mem_jmp;
24static void one_file(char *file, int nest, int hard_opt);
25
26/* Solaris headers don't have facility names. */
27#ifdef HAVE_SOLARIS_NETWORK
28static 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
56struct 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
106#ifdef HAVE_GETOPT_LONG
107static const struct option opts[] =
108#else
109static const struct myoption opts[] =
110#endif
111 {
112 { "version", 0, 0, 'v' },
113 { "no-hosts", 0, 0, 'h' },
114 { "no-poll", 0, 0, 'n' },
115 { "help", 0, 0, 'w' },
116 { "no-daemon", 0, 0, 'd' },
117 { "log-queries", 0, 0, 'q' },
118 { "user", 2, 0, 'u' },
119 { "group", 2, 0, 'g' },
120 { "resolv-file", 2, 0, 'r' },
121 { "mx-host", 1, 0, 'm' },
122 { "mx-target", 1, 0, 't' },
123 { "cache-size", 2, 0, 'c' },
124 { "port", 1, 0, 'p' },
125 { "dhcp-leasefile", 2, 0, 'l' },
126 { "dhcp-lease", 1, 0, 'l' },
127 { "dhcp-host", 1, 0, 'G' },
128 { "dhcp-range", 1, 0, 'F' },
129 { "dhcp-option", 1, 0, 'O' },
130 { "dhcp-boot", 1, 0, 'M' },
131 { "domain", 1, 0, 's' },
132 { "domain-suffix", 1, 0, 's' },
133 { "interface", 1, 0, 'i' },
134 { "listen-address", 1, 0, 'a' },
135 { "bogus-priv", 0, 0, 'b' },
136 { "bogus-nxdomain", 1, 0, 'B' },
137 { "selfmx", 0, 0, 'e' },
138 { "filterwin2k", 0, 0, 'f' },
139 { "pid-file", 2, 0, 'x' },
140 { "strict-order", 0, 0, 'o' },
141 { "server", 1, 0, 'S' },
142 { "local", 1, 0, LOPT_LOCAL },
143 { "address", 1, 0, 'A' },
144 { "conf-file", 2, 0, 'C' },
145 { "no-resolv", 0, 0, 'R' },
146 { "expand-hosts", 0, 0, 'E' },
147 { "localmx", 0, 0, 'L' },
148 { "local-ttl", 1, 0, 'T' },
149 { "no-negcache", 0, 0, 'N' },
150 { "addn-hosts", 1, 0, 'H' },
151 { "query-port", 1, 0, 'Q' },
152 { "except-interface", 1, 0, 'I' },
153 { "no-dhcp-interface", 1, 0, '2' },
154 { "domain-needed", 0, 0, 'D' },
155 { "dhcp-lease-max", 1, 0, 'X' },
156 { "bind-interfaces", 0, 0, 'z' },
157 { "read-ethers", 0, 0, 'Z' },
158 { "alias", 1, 0, 'V' },
159 { "dhcp-vendorclass", 1, 0, 'U' },
160 { "dhcp-userclass", 1, 0, 'j' },
161 { "dhcp-ignore", 1, 0, 'J' },
162 { "edns-packet-max", 1, 0, 'P' },
163 { "keep-in-foreground", 0, 0, 'k' },
164 { "dhcp-authoritative", 0, 0, 'K' },
165 { "srv-host", 1, 0, 'W' },
166 { "localise-queries", 0, 0, 'y' },
167 { "txt-record", 1, 0, 'Y' },
168 { "enable-dbus", 0, 0, '1' },
169 { "bootp-dynamic", 2, 0, '3' },
170 { "dhcp-mac", 1, 0, '4' },
171 { "no-ping", 0, 0, '5' },
172 { "dhcp-script", 1, 0, '6' },
173 { "conf-dir", 1, 0, '7' },
174 { "log-facility", 1, 0 ,'8' },
175 { "leasefile-ro", 0, 0, '9' },
176 { "dns-forward-max", 1, 0, '0' },
177 { "clear-on-reload", 0, 0, LOPT_RELOAD },
178 { "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
179 { "enable-tftp", 0, 0, LOPT_TFTP },
180 { "tftp-secure", 0, 0, LOPT_SECURE },
181 { "tftp-unique-root", 0, 0, LOPT_APREF },
182 { "tftp-root", 1, 0, LOPT_PREFIX },
183 { "tftp-max", 1, 0, LOPT_TFTP_MAX },
184 { "ptr-record", 1, 0, LOPT_PTR },
185 { "naptr-record", 1, 0, LOPT_NAPTR },
186 { "bridge-interface", 1, 0 , LOPT_BRIDGE },
187 { "dhcp-option-force", 1, 0, LOPT_FORCE },
188 { "tftp-no-blocksize", 0, 0, LOPT_NOBLOCK },
189 { "log-dhcp", 0, 0, LOPT_LOG_OPTS },
190 { "log-async", 2, 0, LOPT_MAX_LOGS },
191 { "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
192 { "dhcp-remoteid", 1, 0, LOPT_REMOTE },
193 { "dhcp-subscrid", 1, 0, LOPT_SUBSCR },
194 { "interface-name", 1, 0, LOPT_INTNAME },
195 { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
196 { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
197 { "dhcp-no-override", 0, 0, LOPT_OVERRIDE },
198 { "tftp-port-range", 1, 0, LOPT_TFTPPORTS },
199 { "stop-dns-rebind", 0, 0, LOPT_REBIND },
200 { "all-servers", 0, 0, LOPT_NOLAST },
201 { "dhcp-match", 1, 0, LOPT_MATCH },
202 { "dhcp-broadcast", 1, 0, LOPT_BROADCAST },
203 { "neg-ttl", 1, 0, LOPT_NEGTTL },
204 { "dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
205 { "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
206 { "min-port", 1, 0, LOPT_MINPORT },
207 { "dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN },
208 { "cname", 1, 0, LOPT_CNAME },
209 { "pxe-prompt", 1, 0, LOPT_PXE_PROMT },
210 { "pxe-service", 1, 0, LOPT_PXE_SERV },
211 { "test", 0, 0, LOPT_TEST },
212 { NULL, 0, 0, 0 }
213 };
214
215/* These must have more the one '1' bit */
216#define ARG_DUP 3
217#define ARG_ONE 5
218#define ARG_USED_CL 7
219#define ARG_USED_FILE 9
220
221static struct {
222 int opt;
223 unsigned int rept;
224 char * const flagdesc;
225 char * const desc;
226 char * const arg;
227} usage[] = {
228 { 'a', ARG_DUP, "ipaddr", gettext_noop("Specify local address(es) to listen on."), NULL },
229 { 'A', ARG_DUP, "/domain/ipaddr", gettext_noop("Return ipaddr for all hosts in specified domains."), NULL },
230 { 'b', OPT_BOGUSPRIV, NULL, gettext_noop("Fake reverse lookups for RFC1918 private address ranges."), NULL },
231 { 'B', ARG_DUP, "ipaddr", gettext_noop("Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."), NULL },
232 { 'c', ARG_ONE, "cachesize", gettext_noop("Specify the size of the cache in entries (defaults to %s)."), "$" },
233 { 'C', ARG_DUP, "path", gettext_noop("Specify configuration file (defaults to %s)."), CONFFILE },
234 { 'd', OPT_DEBUG, NULL, gettext_noop("Do NOT fork into the background: run in debug mode."), NULL },
235 { 'D', OPT_NODOTS_LOCAL, NULL, gettext_noop("Do NOT forward queries with no domain part."), NULL },
236 { 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL },
237 { 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
238 { 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
239 { 'F', ARG_DUP, "ipaddr,ipaddr,time", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
240 { 'g', ARG_ONE, "groupname", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
241 { 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
242 { LOPT_DHCP_HOST, ARG_ONE, "<filename>", gettext_noop("Read DHCP host specs from file"), NULL },
243 { LOPT_DHCP_OPTS, ARG_ONE, "<filename>", gettext_noop("Read DHCP option specs from file"), NULL },
244 { 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
245 { 'H', ARG_DUP, "path", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
246 { 'i', ARG_DUP, "interface", gettext_noop("Specify interface(s) to listen on."), NULL },
247 { 'I', ARG_DUP, "int", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
248 { 'j', ARG_DUP, "<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
249 { LOPT_CIRCUIT, ARG_DUP, "<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
250 { LOPT_REMOTE, ARG_DUP, "<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
251 { LOPT_SUBSCR, ARG_DUP, "<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
252 { 'J', ARG_DUP, "=<id>[,<id>]", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
253 { LOPT_BROADCAST, ARG_DUP, "=<id>[,<id>]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
254 { 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
255 { 'K', OPT_AUTHORITATIVE, NULL, gettext_noop("Assume we are the only DHCP server on the local network."), NULL },
256 { 'l', ARG_ONE, "path", gettext_noop("Specify where to store DHCP leases (defaults to %s)."), LEASEFILE },
257 { 'L', OPT_LOCALMX, NULL, gettext_noop("Return MX records for local hosts."), NULL },
258 { 'm', ARG_DUP, "host_name,target,pref", gettext_noop("Specify an MX record."), NULL },
259 { 'M', ARG_DUP, "<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL },
260 { 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE },
261 { 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL },
262 { 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE },
263 { 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL },
264 { LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},
265 { 'p', ARG_ONE, "number", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
266 { 'P', ARG_ONE, "<size>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
267 { 'q', OPT_LOG, NULL, gettext_noop("Log DNS queries."), NULL },
268 { 'Q', ARG_ONE, "number", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
269 { 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
270 { 'r', ARG_DUP, "path", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
271 { 'S', ARG_DUP, "/domain/ipaddr", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
272 { LOPT_LOCAL, ARG_DUP, "/domain/", gettext_noop("Never forward queries to specified domains."), NULL },
273 { 's', ARG_DUP, "<domain>[,<range>]", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
274 { 't', ARG_ONE, "host_name", gettext_noop("Specify default target in an MX record."), NULL },
275 { 'T', ARG_ONE, "time", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
276 { LOPT_NEGTTL, ARG_ONE, "time", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
277 { 'u', ARG_ONE, "username", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
278 { 'U', ARG_DUP, "<id>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
279 { 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
280 { 'V', ARG_DUP, "addr,addr,mask", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },
281 { 'W', ARG_DUP, "name,target,...", gettext_noop("Specify a SRV record."), NULL },
282 { 'w', 0, NULL, gettext_noop("Display this message. Use --help dhcp for known DHCP options."), NULL },
283 { 'x', ARG_ONE, "path", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE },
284 { 'X', ARG_ONE, "number", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },
285 { 'y', OPT_LOCALISE, NULL, gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL },
286 { 'Y', ARG_DUP, "name,txt....", gettext_noop("Specify TXT DNS record."), NULL },
287 { LOPT_PTR, ARG_DUP, "name,target", gettext_noop("Specify PTR DNS record."), NULL },
288 { LOPT_INTNAME, ARG_DUP, "name,interface", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
289 { 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
290 { 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
291 { '1', OPT_DBUS, NULL, gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
292 { '2', ARG_DUP, "interface", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
293 { '3', ARG_DUP, "[=<id>[,<id>]]", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
294 { '4', ARG_DUP, "<id>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
295 { LOPT_BRIDGE, ARG_DUP, "iface,alias,..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL },
296 { '5', OPT_NO_PING, NULL, gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
297 { '6', ARG_ONE, "path", gettext_noop("Script to run on DHCP lease creation and destruction."), NULL },
298 { '7', ARG_DUP, "path", gettext_noop("Read configuration from all the files in this directory."), NULL },
299 { '8', ARG_ONE, "<facilty>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL },
300 { '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL },
301 { '0', ARG_ONE, "<queries>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" },
302 { LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
303 { LOPT_NO_NAMES, ARG_DUP, "[=<id>[,<id>]]", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
304 { LOPT_OVERRIDE, OPT_NO_OVERRIDE, NULL, gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL },
305 { LOPT_TFTP, OPT_TFTP, NULL, gettext_noop("Enable integrated read-only TFTP server."), NULL },
306 { LOPT_PREFIX, ARG_ONE, "<directory>", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
307 { LOPT_APREF, OPT_TFTP_APREF, NULL, gettext_noop("Add client IP address to tftp-root."), NULL },
308 { LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
309 { LOPT_TFTP_MAX, ARG_ONE, "<connections>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },
310 { LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
311 { LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
312 { LOPT_LOG_OPTS, OPT_LOG_OPTS, NULL, gettext_noop("Extra logging for DHCP."), NULL },
313 { LOPT_MAX_LOGS, ARG_ONE, "[=<log lines>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL },
314 { LOPT_REBIND, OPT_NO_REBIND, NULL, gettext_noop("Stop DNS rebinding. Filter private IP ranges when resolving."), NULL },
315 { LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL },
316 { LOPT_MATCH, ARG_DUP, "<netid>,<optspec>", gettext_noop("Set tag if client includes matching option in request."), NULL },
317 { LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
318 { LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change script as this user."), NULL },
319 { LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
320 { LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
321 { LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL },
322 { LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
323 { LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
324 { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
325 { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
326 { 0, 0, NULL, NULL, NULL }
327};
328
329#ifdef HAVE_DHCP
330/* makes options which take a list of addresses */
331#define OT_ADDR_LIST 0x80
332/* DHCP-internal options, for logging. not valid in config file */
333#define OT_INTERNAL 0x40
334#define OT_NAME 0x20
335
336static const struct {
337 char *name;
338 unsigned char val, size;
339} opttab[] = {
340 { "netmask", 1, OT_ADDR_LIST },
341 { "time-offset", 2, 4 },
342 { "router", 3, OT_ADDR_LIST },
343 { "dns-server", 6, OT_ADDR_LIST },
344 { "log-server", 7, OT_ADDR_LIST },
345 { "lpr-server", 9, OT_ADDR_LIST },
346 { "hostname", 12, OT_INTERNAL | OT_NAME },
347 { "boot-file-size", 13, 2 },
348 { "domain-name", 15, OT_NAME },
349 { "swap-server", 16, OT_ADDR_LIST },
350 { "root-path", 17, 0 },
351 { "extension-path", 18, 0 },
352 { "ip-forward-enable", 19, 1 },
353 { "non-local-source-routing", 20, 1 },
354 { "policy-filter", 21, OT_ADDR_LIST },
355 { "max-datagram-reassembly", 22, 2 },
356 { "default-ttl", 23, 1 },
357 { "mtu", 26, 2 },
358 { "all-subnets-local", 27, 1 },
359 { "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
360 { "router-discovery", 31, 1 },
361 { "router-solicitation", 32, OT_ADDR_LIST },
362 { "static-route", 33, OT_ADDR_LIST },
363 { "trailer-encapsulation", 34, 1 },
364 { "arp-timeout", 35, 4 },
365 { "ethernet-encap", 36, 1 },
366 { "tcp-ttl", 37, 1 },
367 { "tcp-keepalive", 38, 4 },
368 { "nis-domain", 40, 0 },
369 { "nis-server", 41, OT_ADDR_LIST },
370 { "ntp-server", 42, OT_ADDR_LIST },
371 { "vendor-encap", 43, OT_INTERNAL },
372 { "netbios-ns", 44, OT_ADDR_LIST },
373 { "netbios-dd", 45, OT_ADDR_LIST },
374 { "netbios-nodetype", 46, 1 },
375 { "netbios-scope", 47, 0 },
376 { "x-windows-fs", 48, OT_ADDR_LIST },
377 { "x-windows-dm", 49, OT_ADDR_LIST },
378 { "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
379 { "lease-time", 51, OT_INTERNAL },
380 { "option-overload", 52, OT_INTERNAL },
381 { "message-type", 53, OT_INTERNAL, },
382 { "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
383 { "parameter-request", 55, OT_INTERNAL },
384 { "message", 56, OT_INTERNAL },
385 { "max-message-size", 57, OT_INTERNAL },
386 { "T1", 58, OT_INTERNAL },
387 { "T2", 59, OT_INTERNAL },
388 { "vendor-class", 60, 0 },
389 { "client-id", 61,OT_INTERNAL },
390 { "nis+-domain", 64, 0 },
391 { "nis+-server", 65, OT_ADDR_LIST },
392 { "tftp-server", 66, 0 },
393 { "bootfile-name", 67, 0 },
394 { "mobile-ip-home", 68, OT_ADDR_LIST },
395 { "smtp-server", 69, OT_ADDR_LIST },
396 { "pop3-server", 70, OT_ADDR_LIST },
397 { "nntp-server", 71, OT_ADDR_LIST },
398 { "irc-server", 74, OT_ADDR_LIST },
399 { "user-class", 77, 0 },
400 { "FQDN", 81, OT_INTERNAL },
401 { "agent-id", 82, OT_INTERNAL },
402 { "client-arch", 93, 2 },
403 { "client-interface-id", 94, 0 },
404 { "client-machine-id", 97, 0 },
405 { "subnet-select", 118, OT_INTERNAL },
406 { "domain-search", 119, 0 },
407 { "sip-server", 120, 0 },
408 { "classless-static-route", 121, 0 },
409 { "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
410 { NULL, 0, 0 }
411};
412
413char *option_string(unsigned char opt, int *is_ip, int *is_name)
414{
415 int i;
416
417 for (i = 0; opttab[i].name; i++)
418 if (opttab[i].val == opt)
419 {
420 if (is_ip)
421 *is_ip = !!(opttab[i].size & OT_ADDR_LIST);
422 if (is_name)
423 *is_name = !!(opttab[i].size & OT_NAME);
424 return opttab[i].name;
425 }
426
427 return NULL;
428}
429
430#endif
431
432/* We hide metacharaters in quoted strings by mapping them into the ASCII control
433 character space. Note that the \0, \t \b \r \033 and \n characters are carefully placed in the
434 following sequence so that they map to themselves: it is therefore possible to call
435 unhide_metas repeatedly on string without breaking things.
436 The transformation gets undone by opt_canonicalise, atoi_check and opt_string_alloc, and a
437 couple of other places.
438 Note that space is included here so that
439 --dhcp-option=3, string
440 has five characters, whilst
441 --dhcp-option=3," string"
442 has six.
443*/
444
445static const char meta[] = "\000123456 \b\t\n78\r90abcdefABCDE\033F:,.";
446
447static char hide_meta(char c)
448{
449 unsigned int i;
450
451 for (i = 0; i < (sizeof(meta) - 1); i++)
452 if (c == meta[i])
453 return (char)i;
454
455 return c;
456}
457
458static char unhide_meta(char cr)
459{
460 unsigned int c = cr;
461
462 if (c < (sizeof(meta) - 1))
463 cr = meta[c];
464
465 return cr;
466}
467
468static void unhide_metas(char *cp)
469{
470 if (cp)
471 for(; *cp; cp++)
472 *cp = unhide_meta(*cp);
473}
474
475static void *opt_malloc(size_t size)
476{
477 void *ret;
478
479 if (mem_recover)
480 {
481 ret = whine_malloc(size);
482 if (!ret)
483 longjmp(mem_jmp, 1);
484 }
485 else
486 ret = safe_malloc(size);
487
488 return ret;
489}
490
491static char *opt_string_alloc(char *cp)
492{
493 char *ret = NULL;
494
495 if (cp && strlen(cp) != 0)
496 {
497 ret = opt_malloc(strlen(cp)+1);
498 strcpy(ret, cp);
499
500 /* restore hidden metachars */
501 unhide_metas(ret);
502 }
503
504 return ret;
505}
506
507
508/* find next comma, split string with zero and eliminate spaces.
509 return start of string following comma */
510
511static char *split_chr(char *s, char c)
512{
513 char *comma, *p;
514
515 if (!s || !(comma = strchr(s, c)))
516 return NULL;
517
518 p = comma;
519 *comma = ' ';
520
521 for (; isspace((int)*comma); comma++);
522
523 for (; (p >= s) && isspace((int)*p); p--)
524 *p = 0;
525
526 return comma;
527}
528
529static char *split(char *s)
530{
531 return split_chr(s, ',');
532}
533
534static char *canonicalise_opt(char *s)
535{
536 char *ret;
537 int nomem;
538
539 if (!s)
540 return 0;
541
542 unhide_metas(s);
543 if (!(ret = canonicalise(s, &nomem)) && nomem)
544 {
545 if (mem_recover)
546 longjmp(mem_jmp, 1);
547 else
548 die(_("could not get memory"), NULL, EC_NOMEM);
549 }
550
551 return ret;
552}
553
554static int atoi_check(char *a, int *res)
555{
556 char *p;
557
558 if (!a)
559 return 0;
560
561 unhide_metas(a);
562
563 for (p = a; *p; p++)
564 if (*p < '0' || *p > '9')
565 return 0;
566
567 *res = atoi(a);
568 return 1;
569}
570
571static int atoi_check16(char *a, int *res)
572{
573 if (!(atoi_check(a, res)) ||
574 *res < 0 ||
575 *res > 0xffff)
576 return 0;
577
578 return 1;
579}
580
581static void add_txt(char *name, char *txt)
582{
583 size_t len = strlen(txt);
584 struct txt_record *r = opt_malloc(sizeof(struct txt_record));
585
586 r->name = opt_string_alloc(name);
587 r->next = daemon->txt;
588 daemon->txt = r;
589 r->class = C_CHAOS;
590 r->txt = opt_malloc(len+1);
591 r->len = len+1;
592 *(r->txt) = len;
593 memcpy((r->txt)+1, txt, len);
594}
595
596static void do_usage(void)
597{
598 char buff[100];
599 int i, j;
600
601 struct {
602 char handle;
603 int val;
604 } tab[] = {
605 { '$', CACHESIZ },
606 { '*', EDNS_PKTSZ },
607 { '&', MAXLEASES },
608 { '!', FTABSIZ },
609 { '#', TFTP_MAX_CONNECTIONS },
610 { '\0', 0 }
611 };
612
613 printf(_("Usage: dnsmasq [options]\n\n"));
614#ifndef HAVE_GETOPT_LONG
615 printf(_("Use short options only on the command line.\n"));
616#endif
617 printf(_("Valid options are:\n"));
618
619 for (i = 0; usage[i].opt != 0; i++)
620 {
621 char *desc = usage[i].flagdesc;
622 char *eq = "=";
623
624 if (!desc || *desc == '[')
625 eq = "";
626
627 if (!desc)
628 desc = "";
629
630 for ( j = 0; opts[j].name; j++)
631 if (opts[j].val == usage[i].opt)
632 break;
633 if (usage[i].opt < 256)
634 sprintf(buff, "-%c, ", usage[i].opt);
635 else
636 sprintf(buff, " ");
637
638 sprintf(buff+4, "--%s%s%s", opts[j].name, eq, desc);
639 printf("%-36.36s", buff);
640
641 if (usage[i].arg)
642 {
643 strcpy(buff, usage[i].arg);
644 for (j = 0; tab[j].handle; j++)
645 if (tab[j].handle == *(usage[i].arg))
646 sprintf(buff, "%d", tab[j].val);
647 }
648 printf(_(usage[i].desc), buff);
649 printf("\n");
650 }
651}
652
653#ifdef HAVE_DHCP
654static void display_opts(void)
655{
656 int i;
657
658 printf(_("Known DHCP options:\n"));
659
660 for (i = 0; opttab[i].name; i++)
661 if (!(opttab[i].size & OT_INTERNAL))
662 printf("%3d %s\n", opttab[i].val, opttab[i].name);
663}
664
665/* This is too insanely large to keep in-line in the switch */
666static char *parse_dhcp_opt(char *arg, int flags)
667{
668 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
669 char lenchar = 0, *cp;
670 int i, addrs, digs, is_addr, is_hex, is_dec, is_string, dots;
671 char *comma = NULL, *problem = NULL;
672 struct dhcp_netid *np = NULL;
673 unsigned char opt_len = 0;
674
675 new->len = 0;
676 new->flags = flags;
677 new->netid = NULL;
678 new->val = NULL;
679 new->opt = 0;
680
681 while (arg)
682 {
683 comma = split(arg);
684
685 for (cp = arg; *cp; cp++)
686 if (*cp < '0' || *cp > '9')
687 break;
688
689 if (!*cp)
690 {
691 new->opt = atoi(arg);
692 opt_len = 0;
693 break;
694 }
695
696 if (strstr(arg, "option:") == arg)
697 {
698 for (i = 0; opttab[i].name; i++)
699 if (!(opttab[i].size & OT_INTERNAL) &&
700 strcasecmp(opttab[i].name, arg+7) == 0)
701 {
702 new->opt = opttab[i].val;
703 opt_len = opttab[i].size;
704 break;
705 }
706 /* option:<optname> must follow tag and vendor string. */
707 break;
708 }
709 else if (strstr(arg, "vendor:") == arg)
710 {
711 new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7);
712 new->flags |= DHOPT_VENDOR;
713 }
714 else if (strstr(arg, "encap:") == arg)
715 {
716 new->u.encap = atoi(arg+6);
717 new->flags |= DHOPT_ENCAPSULATE;
718 }
719 else
720 {
721 new->netid = opt_malloc(sizeof (struct dhcp_netid));
722 /* allow optional "net:" for consistency */
723 if (strstr(arg, "net:") == arg)
724 new->netid->net = opt_string_alloc(arg+4);
725 else
726 new->netid->net = opt_string_alloc(arg);
727 new->netid->next = np;
728 np = new->netid;
729 }
730
731 arg = comma;
732 }
733
734 if (new->opt == 0)
735 problem = _("bad dhcp-option");
736 else if (comma)
737 {
738 /* characterise the value */
739 char c;
740 is_addr = is_hex = is_dec = is_string = 1;
741 addrs = digs = 1;
742 dots = 0;
743 for (cp = comma; (c = *cp); cp++)
744 if (c == ',')
745 {
746 addrs++;
747 is_dec = is_hex = 0;
748 }
749 else if (c == ':')
750 {
751 digs++;
752 is_dec = is_addr = 0;
753 }
754 else if (c == '/')
755 {
756 is_dec = is_hex = 0;
757 if (cp == comma) /* leading / means a pathname */
758 is_addr = 0;
759 }
760 else if (c == '.')
761 {
762 is_dec = is_hex = 0;
763 dots++;
764 }
765 else if (c == '-')
766 is_hex = is_addr = 0;
767 else if (c == ' ')
768 is_dec = is_hex = 0;
769 else if (!(c >='0' && c <= '9'))
770 {
771 is_addr = 0;
772 if (cp[1] == 0 && is_dec &&
773 (c == 'b' || c == 's' || c == 'i'))
774 {
775 lenchar = c;
776 *cp = 0;
777 }
778 else
779 is_dec = 0;
780 if (!((c >='A' && c <= 'F') ||
781 (c >='a' && c <= 'f') ||
782 (c == '*' && (flags & DHOPT_MATCH))))
783 is_hex = 0;
784 }
785
786 /* We know that some options take addresses */
787
788 if (opt_len & OT_ADDR_LIST)
789 {
790 is_string = is_dec = is_hex = 0;
791 if (!is_addr || dots == 0)
792 problem = _("bad IP address");
793 }
794
795 if (is_hex && digs > 1)
796 {
797 new->len = digs;
798 new->val = opt_malloc(new->len);
799 parse_hex(comma, new->val, digs, (flags & DHOPT_MATCH) ? &new->u.wildcard_mask : NULL, NULL);
800 new->flags |= DHOPT_HEX;
801 }
802 else if (is_dec)
803 {
804 int i, val = atoi(comma);
805 /* assume numeric arg is 1 byte except for
806 options where it is known otherwise.
807 For vendor class option, we have to hack. */
808 if (opt_len != 0)
809 new->len = opt_len;
810 else if (val & 0xffff0000)
811 new->len = 4;
812 else if (val & 0xff00)
813 new->len = 2;
814 else
815 new->len = 1;
816
817 if (lenchar == 'b')
818 new->len = 1;
819 else if (lenchar == 's')
820 new->len = 2;
821 else if (lenchar == 'i')
822 new->len = 4;
823
824 new->val = opt_malloc(new->len);
825 for (i=0; i<new->len; i++)
826 new->val[i] = val>>((new->len - i - 1)*8);
827 }
828 else if (is_addr)
829 {
830 struct in_addr in;
831 unsigned char *op;
832 char *slash;
833 /* max length of address/subnet descriptor is five bytes,
834 add one for the option 120 enc byte too */
835 new->val = op = opt_malloc((5 * addrs) + 1);
836 new->flags |= DHOPT_ADDR;
837
838 if (!(new->flags & DHOPT_ENCAPSULATE) && new->opt == 120)
839 {
840 *(op++) = 1; /* RFC 3361 "enc byte" */
841 new->flags &= ~DHOPT_ADDR;
842 }
843 while (addrs--)
844 {
845 cp = comma;
846 comma = split(cp);
847 slash = split_chr(cp, '/');
848 in.s_addr = inet_addr(cp);
849 if (!slash)
850 {
851 memcpy(op, &in, INADDRSZ);
852 op += INADDRSZ;
853 }
854 else
855 {
856 unsigned char *p = (unsigned char *)&in;
857 int netsize = atoi(slash);
858 *op++ = netsize;
859 if (netsize > 0)
860 *op++ = *p++;
861 if (netsize > 8)
862 *op++ = *p++;
863 if (netsize > 16)
864 *op++ = *p++;
865 if (netsize > 24)
866 *op++ = *p++;
867 new->flags &= ~DHOPT_ADDR; /* cannot re-write descriptor format */
868 }
869 }
870 new->len = op - new->val;
871 }
872 else if (is_string)
873 {
874 /* text arg */
875 if ((new->opt == 119 || new->opt == 120) && !(new->flags & DHOPT_ENCAPSULATE))
876 {
877 /* dns search, RFC 3397, or SIP, RFC 3361 */
878 unsigned char *q, *r, *tail;
879 unsigned char *p, *m = NULL, *newp;
880 size_t newlen, len = 0;
881 int header_size = (new->opt == 119) ? 0 : 1;
882
883 arg = comma;
884 comma = split(arg);
885
886 while (arg && *arg)
887 {
888 char *dom;
889 if (!(dom = arg = canonicalise_opt(arg)))
890 {
891 problem = _("bad domain in dhcp-option");
892 break;
893 }
894
895 newp = opt_malloc(len + strlen(arg) + 2 + header_size);
896 if (m)
897 memcpy(newp, m, header_size + len);
898 m = newp;
899 p = m + header_size;
900 q = p + len;
901
902 /* add string on the end in RFC1035 format */
903 while (*arg)
904 {
905 unsigned char *cp = q++;
906 int j;
907 for (j = 0; *arg && (*arg != '.'); arg++, j++)
908 *q++ = *arg;
909 *cp = j;
910 if (*arg)
911 arg++;
912 }
913 *q++ = 0;
914 free(dom);
915
916 /* Now tail-compress using earlier names. */
917 newlen = q - p;
918 for (tail = p + len; *tail; tail += (*tail) + 1)
919 for (r = p; r - p < (int)len; r += (*r) + 1)
920 if (strcmp((char *)r, (char *)tail) == 0)
921 {
922 PUTSHORT((r - p) | 0xc000, tail);
923 newlen = tail - p;
924 goto end;
925 }
926 end:
927 len = newlen;
928
929 arg = comma;
930 comma = split(arg);
931 }
932
933 /* RFC 3361, enc byte is zero for names */
934 if (new->opt == 120)
935 m[0] = 0;
936 new->len = (int) len + header_size;
937 new->val = m;
938 }
939 else
940 {
941 new->len = strlen(comma);
942 /* keep terminating zero on string */
943 new->val = (unsigned char *)opt_string_alloc(comma);
944 new->flags |= DHOPT_STRING;
945 }
946 }
947 }
948
949 if ((new->len > 255) || (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))))
950 problem = _("dhcp-option too long");
951
952 if (!problem)
953 {
954 if (flags == DHOPT_MATCH)
955 {
956 if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||
957 !new->netid ||
958 new->netid->next)
959 problem = _("illegal dhcp-match");
960 else
961 {
962 new->next = daemon->dhcp_match;
963 daemon->dhcp_match = new;
964 }
965 }
966 else
967 {
968 new->next = daemon->dhcp_opts;
969 daemon->dhcp_opts = new;
970 }
971 }
972
973 return problem;
974}
975
976#endif
977
978static char *one_opt(int option, char *arg, char *gen_prob, int nest)
979{
980 int i;
981 char *comma, *problem = NULL;;
982
983 if (option == '?')
984 return gen_prob;
985
986 for (i=0; usage[i].opt != 0; i++)
987 if (usage[i].opt == option)
988 {
989 int rept = usage[i].rept;
990
991 if (nest == 0)
992 {
993 /* command line */
994 if (rept == ARG_USED_CL)
995 return _("illegal repeated flag");
996 if (rept == ARG_ONE)
997 usage[i].rept = ARG_USED_CL;
998 }
999 else
1000 {
1001 /* allow file to override command line */
1002 if (rept == ARG_USED_FILE)
1003 return _("illegal repeated keyword");
1004 if (rept == ARG_USED_CL || rept == ARG_ONE)
1005 usage[i].rept = ARG_USED_FILE;
1006 }
1007
1008 if (rept != ARG_DUP && rept != ARG_ONE && rept != ARG_USED_CL)
1009 {
1010 daemon->options |= rept;
1011 return NULL;
1012 }
1013
1014 break;
1015 }
1016
1017 switch (option)
1018 {
1019 case 'C': /* --conf-file */
1020 {
1021 char *file = opt_string_alloc(arg);
1022 if (file)
1023 {
1024 one_file(file, nest, 0);
1025 free(file);
1026 }
1027 break;
1028 }
1029
1030 case '7': /* --conf-dir */
1031 {
1032 DIR *dir_stream;
1033 struct dirent *ent;
1034 char *directory, *path;
1035 struct list {
1036 char *suffix;
1037 struct list *next;
1038 } *ignore_suffix = NULL, *li;
1039
1040 comma = split(arg);
1041 if (!(directory = opt_string_alloc(arg)))
1042 break;
1043
1044 for (arg = comma; arg; arg = comma)
1045 {
1046 comma = split(arg);
1047 li = opt_malloc(sizeof(struct list));
1048 li->next = ignore_suffix;
1049 ignore_suffix = li;
1050 /* Have to copy: buffer is overwritten */
1051 li->suffix = opt_string_alloc(arg);
1052 };
1053
1054 if (!(dir_stream = opendir(directory)))
1055 die(_("cannot access directory %s: %s"), directory, EC_FILE);
1056
1057 while ((ent = readdir(dir_stream)))
1058 {
1059 size_t len = strlen(ent->d_name);
1060 struct stat buf;
1061
1062 /* ignore emacs backups and dotfiles */
1063 if (len == 0 ||
1064 ent->d_name[len - 1] == '~' ||
1065 (ent->d_name[0] == '#' && ent->d_name[len - 1] == '#') ||
1066 ent->d_name[0] == '.')
1067 continue;
1068
1069 for (li = ignore_suffix; li; li = li->next)
1070 {
1071 /* check for proscribed suffices */
1072 size_t ls = strlen(li->suffix);
1073 if (len > ls &&
1074 strcmp(li->suffix, &ent->d_name[len - ls]) == 0)
1075 break;
1076 }
1077 if (li)
1078 continue;
1079
1080 path = opt_malloc(strlen(directory) + len + 2);
1081 strcpy(path, directory);
1082 strcat(path, "/");
1083 strcat(path, ent->d_name);
1084
1085 if (stat(path, &buf) == -1)
1086 die(_("cannot access %s: %s"), path, EC_FILE);
1087 /* only reg files allowed. */
1088 if (!S_ISREG(buf.st_mode))
1089 continue;
1090
1091 /* dir is one level, so files must be readable */
1092 one_file(path, nest + 1, 0);
1093 free(path);
1094 }
1095
1096 closedir(dir_stream);
1097 free(directory);
1098 for(; ignore_suffix; ignore_suffix = li)
1099 {
1100 li = ignore_suffix->next;
1101 free(ignore_suffix->suffix);
1102 free(ignore_suffix);
1103 }
1104
1105 break;
1106 }
1107
1108 case '8': /* --log-facility */
1109 /* may be a filename */
1110 if (strchr(arg, '/'))
1111 daemon->log_file = opt_string_alloc(arg);
1112 else
San Mehat5658bcb2010-01-20 10:16:30 -08001113 {
1114#ifdef __ANDROID__
1115 problem = "Android does not support log facilities";
1116#else
San Mehatffd68722010-01-20 09:56:15 -08001117 for (i = 0; facilitynames[i].c_name; i++)
1118 if (hostname_isequal((char *)facilitynames[i].c_name, arg))
1119 break;
1120
1121 if (facilitynames[i].c_name)
1122 daemon->log_fac = facilitynames[i].c_val;
1123 else
1124 problem = "bad log facility";
San Mehat5658bcb2010-01-20 10:16:30 -08001125#endif
San Mehatffd68722010-01-20 09:56:15 -08001126 }
1127 break;
1128
1129 case 'x': /* --pid-file */
1130 daemon->runfile = opt_string_alloc(arg);
1131 break;
1132
1133 case LOPT_DHCP_HOST: /* --dhcp-hostfile */
1134 if (daemon->dhcp_hosts_file)
1135 problem = _("only one dhcp-hostsfile allowed");
1136 else
1137 daemon->dhcp_hosts_file = opt_string_alloc(arg);
1138 break;
1139
1140 case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
1141 if (daemon->dhcp_opts_file)
1142 problem = _("only one dhcp-optsfile allowed");
1143 else
1144 daemon->dhcp_opts_file = opt_string_alloc(arg);
1145 break;
1146
1147 case 'r': /* --resolv-file */
1148 {
1149 char *name = opt_string_alloc(arg);
1150 struct resolvc *new, *list = daemon->resolv_files;
1151
1152 if (list && list->is_default)
1153 {
1154 /* replace default resolv file - possibly with nothing */
1155 if (name)
1156 {
1157 list->is_default = 0;
1158 list->name = name;
1159 }
1160 else
1161 list = NULL;
1162 }
1163 else if (name)
1164 {
1165 new = opt_malloc(sizeof(struct resolvc));
1166 new->next = list;
1167 new->name = name;
1168 new->is_default = 0;
1169 new->mtime = 0;
1170 new->logged = 0;
1171 list = new;
1172 }
1173 daemon->resolv_files = list;
1174 break;
1175 }
1176
1177 case 'm': /* --mx-host */
1178 {
1179 int pref = 1;
1180 struct mx_srv_record *new;
1181 char *name, *target = NULL;
1182
1183 if ((comma = split(arg)))
1184 {
1185 char *prefstr;
1186 if ((prefstr = split(comma)) && !atoi_check16(prefstr, &pref))
1187 problem = _("bad MX preference");
1188 }
1189
1190 if (!(name = canonicalise_opt(arg)) ||
1191 (comma && !(target = canonicalise_opt(comma))))
1192 problem = _("bad MX name");
1193
1194 new = opt_malloc(sizeof(struct mx_srv_record));
1195 new->next = daemon->mxnames;
1196 daemon->mxnames = new;
1197 new->issrv = 0;
1198 new->name = name;
1199 new->target = target; /* may be NULL */
1200 new->weight = pref;
1201 break;
1202 }
1203
1204 case 't': /* --mx-target */
1205 if (!(daemon->mxtarget = canonicalise_opt(arg)))
1206 problem = _("bad MX target");
1207 break;
1208
1209#ifdef HAVE_DHCP
1210 case 'l': /* --dhcp-leasefile */
1211 daemon->lease_file = opt_string_alloc(arg);
1212 break;
1213
1214 case '6': /* --dhcp-script */
1215# if defined(NO_FORK)
1216 problem = _("cannot run scripts under uClinux");
1217# elif !defined(HAVE_SCRIPT)
1218 problem = _("recompile with HAVE_SCRIPT defined to enable lease-change scripts");
1219# else
1220 daemon->lease_change_command = opt_string_alloc(arg);
1221# endif
1222 break;
1223#endif
1224
1225 case 'H': /* --addn-hosts */
1226 {
1227 struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
1228 static int hosts_index = 1;
1229 new->fname = opt_string_alloc(arg);
1230 new->index = hosts_index++;
1231 new->flags = 0;
1232 new->next = daemon->addn_hosts;
1233 daemon->addn_hosts = new;
1234 break;
1235 }
1236
1237 case 's': /* --domain */
1238 if (strcmp (arg, "#") == 0)
1239 daemon->options |= OPT_RESOLV_DOMAIN;
1240 else
1241 {
1242 char *d;
1243 comma = split(arg);
1244 if (!(d = canonicalise_opt(arg)))
1245 option = '?';
1246 else
1247 {
1248 if (comma)
1249 {
1250 struct cond_domain *new = safe_malloc(sizeof(struct cond_domain));
1251 unhide_metas(comma);
1252 if ((arg = split_chr(comma, '/')))
1253 {
1254 int mask;
1255 if ((new->start.s_addr = inet_addr(comma)) == (in_addr_t)-1 ||
1256 !atoi_check(arg, &mask))
1257 option = '?';
1258 else
1259 {
1260 mask = (1 << (32 - mask)) - 1;
1261 new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask);
1262 new->end.s_addr = new->start.s_addr | htonl(mask);
1263 }
1264 }
1265 else if ((arg = split(comma)))
1266 {
1267 if ((new->start.s_addr = inet_addr(comma)) == (in_addr_t)-1 ||
1268 (new->end.s_addr = inet_addr(arg)) == (in_addr_t)-1)
1269 option = '?';
1270 }
1271 else if ((new->start.s_addr = new->end.s_addr = inet_addr(comma)) == (in_addr_t)-1)
1272 option = '?';
1273
1274 new->domain = d;
1275 new->next = daemon->cond_domain;
1276 daemon->cond_domain = new;
1277 }
1278 else
1279 daemon->domain_suffix = d;
1280 }
1281 }
1282 break;
1283
1284 case 'u': /* --user */
1285 daemon->username = opt_string_alloc(arg);
1286 break;
1287
1288 case 'g': /* --group */
1289 daemon->groupname = opt_string_alloc(arg);
1290 daemon->group_set = 1;
1291 break;
1292
1293#ifdef HAVE_DHCP
1294 case LOPT_SCRIPTUSR: /* --scriptuser */
1295 daemon->scriptuser = opt_string_alloc(arg);
1296 break;
1297#endif
1298
1299 case 'i': /* --interface */
1300 do {
1301 struct iname *new = opt_malloc(sizeof(struct iname));
1302 comma = split(arg);
1303 new->next = daemon->if_names;
1304 daemon->if_names = new;
1305 /* new->name may be NULL if someone does
1306 "interface=" to disable all interfaces except loop. */
1307 new->name = opt_string_alloc(arg);
1308 new->isloop = new->used = 0;
1309 arg = comma;
1310 } while (arg);
1311 break;
1312
1313 case 'I': /* --except-interface */
1314 case '2': /* --no-dhcp-interface */
1315 do {
1316 struct iname *new = opt_malloc(sizeof(struct iname));
1317 comma = split(arg);
1318 new->name = opt_string_alloc(arg);
1319 if (option == 'I')
1320 {
1321 new->next = daemon->if_except;
1322 daemon->if_except = new;
1323 }
1324 else
1325 {
1326 new->next = daemon->dhcp_except;
1327 daemon->dhcp_except = new;
1328 }
1329 arg = comma;
1330 } while (arg);
1331 break;
1332
1333 case 'B': /* --bogus-nxdomain */
1334 {
1335 struct in_addr addr;
1336 unhide_metas(arg);
1337 if (arg && (addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
1338 {
1339 struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
1340 baddr->next = daemon->bogus_addr;
1341 daemon->bogus_addr = baddr;
1342 baddr->addr = addr;
1343 }
1344 else
1345 option = '?'; /* error */
1346 break;
1347 }
1348
1349 case 'a': /* --listen-address */
1350 do {
1351 struct iname *new = opt_malloc(sizeof(struct iname));
1352 comma = split(arg);
1353 unhide_metas(arg);
1354 new->next = daemon->if_addrs;
1355 if (arg && (new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
1356 {
1357 new->addr.sa.sa_family = AF_INET;
1358#ifdef HAVE_SOCKADDR_SA_LEN
1359 new->addr.in.sin_len = sizeof(new->addr.in);
1360#endif
1361 }
1362#ifdef HAVE_IPV6
1363 else if (arg && inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
1364 {
1365 new->addr.sa.sa_family = AF_INET6;
1366 new->addr.in6.sin6_flowinfo = 0;
1367 new->addr.in6.sin6_scope_id = 0;
1368#ifdef HAVE_SOCKADDR_SA_LEN
1369 new->addr.in6.sin6_len = sizeof(new->addr.in6);
1370#endif
1371 }
1372#endif
1373 else
1374 {
1375 option = '?'; /* error */
1376 break;
1377 }
1378
1379 daemon->if_addrs = new;
1380 arg = comma;
1381 } while (arg);
1382 break;
1383
1384 case 'S': /* --server */
1385 case LOPT_LOCAL: /* --local */
1386 case 'A': /* --address */
1387 {
1388 struct server *serv, *newlist = NULL;
1389
1390 unhide_metas(arg);
1391
1392 if (arg && *arg == '/')
1393 {
1394 char *end;
1395 arg++;
1396 while ((end = split_chr(arg, '/')))
1397 {
1398 char *domain = NULL;
1399 /* # matches everything and becomes a zero length domain string */
1400 if (strcmp(arg, "#") == 0)
1401 domain = "";
1402 else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
1403 option = '?';
1404 serv = opt_malloc(sizeof(struct server));
1405 memset(serv, 0, sizeof(struct server));
1406 serv->next = newlist;
1407 newlist = serv;
1408 serv->domain = domain;
1409 serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
1410 arg = end;
1411 }
1412 if (!newlist)
1413 {
1414 option = '?';
1415 break;
1416 }
1417
1418 }
1419 else
1420 {
1421 newlist = opt_malloc(sizeof(struct server));
1422 memset(newlist, 0, sizeof(struct server));
1423 }
1424
1425 if (option == 'A')
1426 {
1427 newlist->flags |= SERV_LITERAL_ADDRESS;
1428 if (!(newlist->flags & SERV_TYPE))
1429 option = '?';
1430 }
1431
1432 if (!arg || !*arg)
1433 {
1434 newlist->flags |= SERV_NO_ADDR; /* no server */
1435 if (newlist->flags & SERV_LITERAL_ADDRESS)
1436 option = '?';
1437 }
1438 else
1439 {
1440 int source_port = 0, serv_port = NAMESERVER_PORT;
1441 char *portno, *source;
1442
1443 if ((source = split_chr(arg, '@')) && /* is there a source. */
1444 (portno = split_chr(source, '#')) &&
1445 !atoi_check16(portno, &source_port))
1446 problem = _("bad port");
1447
1448 if ((portno = split_chr(arg, '#')) && /* is there a port no. */
1449 !atoi_check16(portno, &serv_port))
1450 problem = _("bad port");
1451
1452 if ((newlist->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1)
1453 {
1454 newlist->addr.in.sin_port = htons(serv_port);
1455 newlist->source_addr.in.sin_port = htons(source_port);
1456 newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET;
1457#ifdef HAVE_SOCKADDR_SA_LEN
1458 newlist->source_addr.in.sin_len = newlist->addr.in.sin_len = sizeof(struct sockaddr_in);
1459#endif
1460 if (source)
1461 {
1462 newlist->flags |= SERV_HAS_SOURCE;
1463 if ((newlist->source_addr.in.sin_addr.s_addr = inet_addr(source)) == (in_addr_t) -1)
1464 {
1465#if defined(SO_BINDTODEVICE)
1466 newlist->source_addr.in.sin_addr.s_addr = INADDR_ANY;
1467 strncpy(newlist->interface, source, IF_NAMESIZE);
1468#else
1469 problem = _("interface binding not supported");
1470#endif
1471 }
1472 }
1473 else
1474 newlist->source_addr.in.sin_addr.s_addr = INADDR_ANY;
1475 }
1476#ifdef HAVE_IPV6
1477 else if (inet_pton(AF_INET6, arg, &newlist->addr.in6.sin6_addr) > 0)
1478 {
1479 newlist->addr.in6.sin6_port = htons(serv_port);
1480 newlist->source_addr.in6.sin6_port = htons(source_port);
1481 newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET6;
1482#ifdef HAVE_SOCKADDR_SA_LEN
1483 newlist->addr.in6.sin6_len = newlist->source_addr.in6.sin6_len = sizeof(newlist->addr.in6);
1484#endif
1485 if (source)
1486 {
1487 newlist->flags |= SERV_HAS_SOURCE;
1488 if (inet_pton(AF_INET6, source, &newlist->source_addr.in6.sin6_addr) == 0)
1489 {
1490#if defined(SO_BINDTODEVICE)
1491 newlist->source_addr.in6.sin6_addr = in6addr_any;
1492 strncpy(newlist->interface, source, IF_NAMESIZE);
1493#else
1494 problem = _("interface binding not supported");
1495#endif
1496 }
1497 }
1498 else
1499 newlist->source_addr.in6.sin6_addr = in6addr_any;
1500 }
1501#endif
1502 else
1503 option = '?'; /* error */
1504
1505 }
1506
1507 serv = newlist;
1508 while (serv->next)
1509 {
1510 serv->next->flags = serv->flags;
1511 serv->next->addr = serv->addr;
1512 serv->next->source_addr = serv->source_addr;
1513 serv = serv->next;
1514 }
1515 serv->next = daemon->servers;
1516 daemon->servers = newlist;
1517 break;
1518 }
1519
1520 case 'c': /* --cache-size */
1521 {
1522 int size;
1523
1524 if (!atoi_check(arg, &size))
1525 option = '?';
1526 else
1527 {
1528 /* zero is OK, and means no caching. */
1529
1530 if (size < 0)
1531 size = 0;
1532 else if (size > 10000)
1533 size = 10000;
1534
1535 daemon->cachesize = size;
1536 }
1537 break;
1538 }
1539
1540 case 'p': /* --port */
1541 if (!atoi_check16(arg, &daemon->port))
1542 option = '?';
1543 break;
1544
1545 case LOPT_MINPORT: /* --min-port */
1546 if (!atoi_check16(arg, &daemon->min_port))
1547 option = '?';
1548 break;
1549
1550 case '0': /* --dns-forward-max */
1551 if (!atoi_check(arg, &daemon->ftabsize))
1552 option = '?';
1553 break;
1554
1555 case LOPT_MAX_LOGS: /* --log-async */
1556 daemon->max_logs = LOG_MAX; /* default */
1557 if (arg && !atoi_check(arg, &daemon->max_logs))
1558 option = '?';
1559 else if (daemon->max_logs > 100)
1560 daemon->max_logs = 100;
1561 break;
1562
1563 case 'P': /* --edns-packet-max */
1564 {
1565 int i;
1566 if (!atoi_check(arg, &i))
1567 option = '?';
1568 daemon->edns_pktsz = (unsigned short)i;
1569 break;
1570 }
1571
1572 case 'Q': /* --query-port */
1573 if (!atoi_check16(arg, &daemon->query_port))
1574 option = '?';
1575 /* if explicitly set to zero, use single OS ephemeral port
1576 and disable random ports */
1577 if (daemon->query_port == 0)
1578 daemon->osport = 1;
1579 break;
1580
1581 case 'T': /* --local-ttl */
1582 case LOPT_NEGTTL: /* --neg-ttl */
1583 {
1584 int ttl;
1585 if (!atoi_check(arg, &ttl))
1586 option = '?';
1587 else if (option == LOPT_NEGTTL)
1588 daemon->neg_ttl = (unsigned long)ttl;
1589 else
1590 daemon->local_ttl = (unsigned long)ttl;
1591 break;
1592 }
1593
1594#ifdef HAVE_DHCP
1595 case 'X': /* --dhcp-lease-max */
1596 if (!atoi_check(arg, &daemon->dhcp_max))
1597 option = '?';
1598 break;
1599#endif
1600
1601#ifdef HAVE_TFTP
1602 case LOPT_TFTP_MAX: /* --tftp-max */
1603 if (!atoi_check(arg, &daemon->tftp_max))
1604 option = '?';
1605 break;
1606
1607 case LOPT_PREFIX: /* --tftp-prefix */
1608 daemon->tftp_prefix = opt_string_alloc(arg);
1609 break;
1610
1611 case LOPT_TFTPPORTS: /* --tftp-port-range */
1612 if (!(comma = split(arg)) ||
1613 !atoi_check16(arg, &daemon->start_tftp_port) ||
1614 !atoi_check16(comma, &daemon->end_tftp_port))
1615 problem = _("bad port range");
1616
1617 if (daemon->start_tftp_port > daemon->end_tftp_port)
1618 {
1619 int tmp = daemon->start_tftp_port;
1620 daemon->start_tftp_port = daemon->end_tftp_port;
1621 daemon->end_tftp_port = tmp;
1622 }
1623
1624 break;
1625#endif
1626
1627 case LOPT_BRIDGE: /* --bridge-interface */
1628 {
1629 struct dhcp_bridge *new = opt_malloc(sizeof(struct dhcp_bridge));
1630 if (!(comma = split(arg)))
1631 {
1632 problem = _("bad bridge-interface");
1633 break;
1634 }
1635
1636 strncpy(new->iface, arg, IF_NAMESIZE);
1637 new->alias = NULL;
1638 new->next = daemon->bridges;
1639 daemon->bridges = new;
1640
1641 do {
1642 arg = comma;
1643 comma = split(arg);
1644 if (strlen(arg) != 0)
1645 {
1646 struct dhcp_bridge *b = opt_malloc(sizeof(struct dhcp_bridge));
1647 b->next = new->alias;
1648 new->alias = b;
1649 strncpy(b->iface, arg, IF_NAMESIZE);
1650 }
1651 } while (comma);
1652
1653 break;
1654 }
1655
1656#ifdef HAVE_DHCP
1657 case 'F': /* --dhcp-range */
1658 {
1659 int k, leasepos = 2;
1660 char *cp, *a[5] = { NULL, NULL, NULL, NULL, NULL };
1661 struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
1662
1663 new->next = daemon->dhcp;
1664 new->lease_time = DEFLEASE;
1665 new->addr_epoch = 0;
1666 new->netmask.s_addr = 0;
1667 new->broadcast.s_addr = 0;
1668 new->router.s_addr = 0;
1669 new->netid.net = NULL;
1670 new->filter = NULL;
1671 new->flags = 0;
1672
1673 gen_prob = _("bad dhcp-range");
1674
1675 if (!arg)
1676 {
1677 option = '?';
1678 break;
1679 }
1680
1681 while(1)
1682 {
1683 for (cp = arg; *cp; cp++)
1684 if (!(*cp == ' ' || *cp == '.' || (*cp >='0' && *cp <= '9')))
1685 break;
1686
1687 if (*cp != ',' && (comma = split(arg)))
1688 {
1689 if (strstr(arg, "net:") == arg)
1690 {
1691 struct dhcp_netid *tt = opt_malloc(sizeof (struct dhcp_netid));
1692 tt->net = opt_string_alloc(arg+4);
1693 tt->next = new->filter;
1694 new->filter = tt;
1695 }
1696 else
1697 {
1698 if (new->netid.net)
1699 problem = _("only one netid tag allowed");
1700 else
1701 new->netid.net = opt_string_alloc(arg);
1702 }
1703 arg = comma;
1704 }
1705 else
1706 {
1707 a[0] = arg;
1708 break;
1709 }
1710 }
1711
1712 for (k = 1; k < 5; k++)
1713 if (!(a[k] = split(a[k-1])))
1714 break;
1715
1716 if ((k < 2) || ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1))
1717 option = '?';
1718 else if (strcmp(a[1], "static") == 0)
1719 {
1720 new->end = new->start;
1721 new->flags |= CONTEXT_STATIC;
1722 }
1723 else if (strcmp(a[1], "proxy") == 0)
1724 {
1725 new->end = new->start;
1726 new->flags |= CONTEXT_PROXY;
1727 }
1728 else if ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1)
1729 option = '?';
1730
1731 if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
1732 {
1733 struct in_addr tmp = new->start;
1734 new->start = new->end;
1735 new->end = tmp;
1736 }
1737
1738 if (option != '?' && k >= 3 && strchr(a[2], '.') &&
1739 ((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
1740 {
1741 new->flags |= CONTEXT_NETMASK;
1742 leasepos = 3;
1743 if (!is_same_net(new->start, new->end, new->netmask))
1744 problem = _("inconsistent DHCP range");
1745 }
1746 daemon->dhcp = new;
1747
1748 if (k >= 4 && strchr(a[3], '.') &&
1749 ((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1))
1750 {
1751 new->flags |= CONTEXT_BRDCAST;
1752 leasepos = 4;
1753 }
1754
1755 if (k >= leasepos+1)
1756 {
1757 if (strcmp(a[leasepos], "infinite") == 0)
1758 new->lease_time = 0xffffffff;
1759 else
1760 {
1761 int fac = 1;
1762 if (strlen(a[leasepos]) > 0)
1763 {
1764 switch (a[leasepos][strlen(a[leasepos]) - 1])
1765 {
1766 case 'd':
1767 case 'D':
1768 fac *= 24;
1769 /* fall though */
1770 case 'h':
1771 case 'H':
1772 fac *= 60;
1773 /* fall through */
1774 case 'm':
1775 case 'M':
1776 fac *= 60;
1777 /* fall through */
1778 case 's':
1779 case 'S':
1780 a[leasepos][strlen(a[leasepos]) - 1] = 0;
1781 }
1782
1783 new->lease_time = atoi(a[leasepos]) * fac;
1784 /* Leases of a minute or less confuse
1785 some clients, notably Apple's */
1786 if (new->lease_time < 120)
1787 new->lease_time = 120;
1788 }
1789 }
1790 }
1791 break;
1792 }
1793
1794 case LOPT_BANK:
1795 case 'G': /* --dhcp-host */
1796 {
1797 int j, k = 0;
1798 char *a[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
1799 struct dhcp_config *new;
1800 struct in_addr in;
1801
1802 new = opt_malloc(sizeof(struct dhcp_config));
1803
1804 new->next = daemon->dhcp_conf;
1805 new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
1806 new->hwaddr = NULL;
1807
1808 if ((a[0] = arg))
1809 for (k = 1; k < 6; k++)
1810 if (!(a[k] = split(a[k-1])))
1811 break;
1812
1813 for (j = 0; j < k; j++)
1814 if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
1815 {
1816 char *arg = a[j];
1817
1818 if ((arg[0] == 'i' || arg[0] == 'I') &&
1819 (arg[1] == 'd' || arg[1] == 'D') &&
1820 arg[2] == ':')
1821 {
1822 if (arg[3] == '*')
1823 new->flags |= CONFIG_NOCLID;
1824 else
1825 {
1826 int len;
1827 arg += 3; /* dump id: */
1828 if (strchr(arg, ':'))
1829 len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
1830 else
1831 {
1832 unhide_metas(arg);
1833 len = (int) strlen(arg);
1834 }
1835
1836 if ((new->clid = opt_malloc(len)))
1837 {
1838 new->flags |= CONFIG_CLID;
1839 new->clid_len = len;
1840 memcpy(new->clid, arg, len);
1841 }
1842 }
1843 }
1844 else if (strstr(arg, "net:") == arg)
1845 {
1846 int len = strlen(arg + 4) + 1;
1847 if ((new->netid.net = opt_malloc(len)))
1848 {
1849 new->flags |= CONFIG_NETID;
1850 strcpy(new->netid.net, arg+4);
1851 unhide_metas(new->netid.net);
1852 }
1853 }
1854 else
1855 {
1856 struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
1857 newhw->next = new->hwaddr;
1858 new->hwaddr = newhw;
1859 newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
1860 &newhw->wildcard_mask, &newhw->hwaddr_type);
1861 }
1862 }
1863 else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1)
1864 {
1865 new->addr = in;
1866 new->flags |= CONFIG_ADDR;
1867 }
1868 else
1869 {
1870 char *cp, *lastp = NULL, last = 0;
1871 int fac = 1;
1872
1873 if (strlen(a[j]) > 1)
1874 {
1875 lastp = a[j] + strlen(a[j]) - 1;
1876 last = *lastp;
1877 switch (last)
1878 {
1879 case 'd':
1880 case 'D':
1881 fac *= 24;
1882 /* fall through */
1883 case 'h':
1884 case 'H':
1885 fac *= 60;
1886 /* fall through */
1887 case 'm':
1888 case 'M':
1889 fac *= 60;
1890 /* fall through */
1891 case 's':
1892 case 'S':
1893 *lastp = 0;
1894 }
1895 }
1896
1897 for (cp = a[j]; *cp; cp++)
1898 if (!isdigit((int)*cp) && *cp != ' ')
1899 break;
1900
1901 if (*cp)
1902 {
1903 if (lastp)
1904 *lastp = last;
1905 if (strcmp(a[j], "infinite") == 0)
1906 {
1907 new->lease_time = 0xffffffff;
1908 new->flags |= CONFIG_TIME;
1909 }
1910 else if (strcmp(a[j], "ignore") == 0)
1911 new->flags |= CONFIG_DISABLE;
1912 else
1913 {
1914 if (!(new->hostname = canonicalise_opt(a[j])) ||
1915 !legal_hostname(new->hostname))
1916 problem = _("bad DHCP host name");
1917 else
1918 new->flags |= CONFIG_NAME;
1919 new->domain = NULL;
1920 }
1921 }
1922 else
1923 {
1924 new->lease_time = atoi(a[j]) * fac;
1925 /* Leases of a minute or less confuse
1926 some clients, notably Apple's */
1927 if (new->lease_time < 120)
1928 new->lease_time = 120;
1929 new->flags |= CONFIG_TIME;
1930 }
1931 }
1932
1933 daemon->dhcp_conf = new;
1934 break;
1935 }
1936
1937 case 'O': /* --dhcp-option */
1938 case LOPT_FORCE: /* --dhcp-option-force */
1939 case LOPT_OPTS:
1940 case LOPT_MATCH: /* --dhcp-match */
1941 problem = parse_dhcp_opt(arg,
1942 option == LOPT_FORCE ? DHOPT_FORCE :
1943 (option == LOPT_MATCH ? DHOPT_MATCH :
1944 (option == LOPT_OPTS ? DHOPT_BANK : 0)));
1945 break;
1946
1947 case 'M': /* --dhcp-boot */
1948 {
1949 struct dhcp_netid *id = NULL;
1950 while (arg && strstr(arg, "net:") == arg)
1951 {
1952 struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
1953 newid->next = id;
1954 id = newid;
1955 comma = split(arg);
1956 newid->net = opt_string_alloc(arg+4);
1957 arg = comma;
1958 };
1959
1960 if (!arg)
1961 option = '?';
1962 else
1963 {
1964 char *dhcp_file, *dhcp_sname = NULL;
1965 struct in_addr dhcp_next_server;
1966 comma = split(arg);
1967 dhcp_file = opt_string_alloc(arg);
1968 dhcp_next_server.s_addr = 0;
1969 if (comma)
1970 {
1971 arg = comma;
1972 comma = split(arg);
1973 dhcp_sname = opt_string_alloc(arg);
1974 if (comma)
1975 {
1976 unhide_metas(comma);
1977 if ((dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
1978 option = '?';
1979 }
1980 }
1981 if (option != '?')
1982 {
1983 struct dhcp_boot *new = opt_malloc(sizeof(struct dhcp_boot));
1984 new->file = dhcp_file;
1985 new->sname = dhcp_sname;
1986 new->next_server = dhcp_next_server;
1987 new->netid = id;
1988 new->next = daemon->boot_config;
1989 daemon->boot_config = new;
1990 }
1991 }
1992
1993 break;
1994 }
1995
1996 case LOPT_PXE_PROMT: /* --pxe-prompt */
1997 {
1998 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
1999 int timeout;
2000
2001 new->netid = NULL;
2002 new->opt = 10; /* PXE_MENU_PROMPT */
2003
2004 while (arg && strstr(arg, "net:") == arg)
2005 {
2006 struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
2007 comma = split(arg);
2008 nn->next = new->netid;
2009 new->netid = nn;
2010 nn->net = opt_string_alloc(arg+4);
2011 arg = comma;
2012 }
2013
2014 if (!arg)
2015 option = '?';
2016 else
2017 {
2018 comma = split(arg);
2019 unhide_metas(arg);
2020 new->len = strlen(arg) + 1;
2021 new->val = opt_malloc(new->len);
2022 memcpy(new->val + 1, arg, new->len - 1);
2023
2024 new->u.vendor_class = (unsigned char *)"PXEClient";
2025 new->flags = DHOPT_VENDOR;
2026
2027 if (comma && atoi_check(comma, &timeout))
2028 *(new->val) = timeout;
2029 else
2030 *(new->val) = 255;
2031
2032 new->next = daemon->dhcp_opts;
2033 daemon->dhcp_opts = new;
2034 daemon->enable_pxe = 1;
2035 }
2036
2037 break;
2038 }
2039
2040 case LOPT_PXE_SERV: /* --pxe-service */
2041 {
2042 struct pxe_service *new = opt_malloc(sizeof(struct pxe_service));
2043 char *CSA[] = { "x86PC", "PC98", "IA64_EFI", "Alpha", "Arc_x86", "Intel_Lean_Client",
2044 "IA32_EFI", "BC_EFI", "Xscale_EFI", "x86-64_EFI", NULL };
2045 static int boottype = 32768;
2046
2047 new->netid = NULL;
2048 new->server.s_addr = 0;
2049
2050 while (arg && strstr(arg, "net:") == arg)
2051 {
2052 struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
2053 comma = split(arg);
2054 nn->next = new->netid;
2055 new->netid = nn;
2056 nn->net = opt_string_alloc(arg+4);
2057 arg = comma;
2058 }
2059
2060 if (arg && (comma = split(arg)))
2061 {
2062 for (i = 0; CSA[i]; i++)
2063 if (strcasecmp(CSA[i], arg) == 0)
2064 break;
2065
2066 if (CSA[i] || atoi_check(arg, &i))
2067 {
2068 arg = comma;
2069 comma = split(arg);
2070
2071 new->CSA = i;
2072 new->menu = opt_string_alloc(arg);
2073
2074 if (comma)
2075 {
2076 arg = comma;
2077 comma = split(arg);
2078 if (atoi_check(arg, &i))
2079 {
2080 new->type = i;
2081 new->basename = NULL;
2082 }
2083 else
2084 {
2085 new->type = boottype++;
2086 new->basename = opt_string_alloc(arg);
2087 }
2088
2089 if (comma && (new->server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
2090 option = '?';
2091
2092 /* Order matters */
2093 new->next = NULL;
2094 if (!daemon->pxe_services)
2095 daemon->pxe_services = new;
2096 else
2097 {
2098 struct pxe_service *s;
2099 for (s = daemon->pxe_services; s->next; s = s->next);
2100 s->next = new;
2101 }
2102
2103 daemon->enable_pxe = 1;
2104 break;
2105 }
2106 }
2107 }
2108
2109 option = '?';
2110 break;
2111 }
2112
2113 case '4': /* --dhcp-mac */
2114 {
2115 if (!(comma = split(arg)))
2116 option = '?';
2117 else
2118 {
2119 struct dhcp_mac *new = opt_malloc(sizeof(struct dhcp_mac));
2120 if (strstr(arg, "net:") == arg)
2121 new->netid.net = opt_string_alloc(arg+4);
2122 else
2123 new->netid.net = opt_string_alloc(arg);
2124 unhide_metas(comma);
2125 new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
2126 new->next = daemon->dhcp_macs;
2127 daemon->dhcp_macs = new;
2128 }
2129 }
2130 break;
2131
2132 case 'U': /* --dhcp-vendorclass */
2133 case 'j': /* --dhcp-userclass */
2134 case LOPT_CIRCUIT: /* --dhcp-circuitid */
2135 case LOPT_REMOTE: /* --dhcp-remoteid */
2136 case LOPT_SUBSCR: /* --dhcp-subscrid */
2137 {
2138 if (!(comma = split(arg)))
2139 option = '?';
2140 else
2141 {
2142 char *p;
2143 int dig = 0;
2144 struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
2145 if (strstr(arg, "net:") == arg)
2146 new->netid.net = opt_string_alloc(arg+4);
2147 else
2148 new->netid.net = opt_string_alloc(arg);
2149 /* check for hex string - must digits may include : must not have nothing else,
2150 only allowed for agent-options. */
2151 for (p = comma; *p; p++)
2152 if (isxdigit((int)*p))
2153 dig = 1;
2154 else if (*p != ':')
2155 break;
2156 unhide_metas(comma);
2157 if (option == 'U' || option == 'j' || *p || !dig)
2158 {
2159 new->len = strlen(comma);
2160 new->data = opt_malloc(new->len);
2161 memcpy(new->data, comma, new->len);
2162 }
2163 else
2164 {
2165 new->len = parse_hex(comma, (unsigned char *)comma, strlen(comma), NULL, NULL);
2166 new->data = opt_malloc(new->len);
2167 memcpy(new->data, comma, new->len);
2168 }
2169
2170 switch (option)
2171 {
2172 case 'j':
2173 new->match_type = MATCH_USER;
2174 break;
2175 case 'U':
2176 new->match_type = MATCH_VENDOR;
2177 break;
2178 case LOPT_CIRCUIT:
2179 new->match_type = MATCH_CIRCUIT;
2180 break;
2181 case LOPT_REMOTE:
2182 new->match_type = MATCH_REMOTE;
2183 break;
2184 case LOPT_SUBSCR:
2185 new->match_type = MATCH_SUBSCRIBER;
2186 break;
2187 }
2188 new->next = daemon->dhcp_vendors;
2189 daemon->dhcp_vendors = new;
2190 }
2191 break;
2192 }
2193
2194 case LOPT_ALTPORT: /* --dhcp-alternate-port */
2195 if (!arg)
2196 {
2197 daemon->dhcp_server_port = DHCP_SERVER_ALTPORT;
2198 daemon->dhcp_client_port = DHCP_CLIENT_ALTPORT;
2199 }
2200 else
2201 {
2202 comma = split(arg);
2203 if (!atoi_check16(arg, &daemon->dhcp_server_port) ||
2204 (comma && !atoi_check16(comma, &daemon->dhcp_client_port)))
2205 problem = _("invalid port number");
2206 if (!comma)
2207 daemon->dhcp_client_port = daemon->dhcp_server_port+1;
2208 }
2209 break;
2210
2211 case 'J': /* --dhcp-ignore */
2212 case LOPT_NO_NAMES: /* --dhcp-ignore-names */
2213 case LOPT_BROADCAST: /* --dhcp-broadcast */
2214 case '3': /* --bootp-dynamic */
2215 {
2216 struct dhcp_netid_list *new = opt_malloc(sizeof(struct dhcp_netid_list));
2217 struct dhcp_netid *list = NULL;
2218 if (option == 'J')
2219 {
2220 new->next = daemon->dhcp_ignore;
2221 daemon->dhcp_ignore = new;
2222 }
2223 else if (option == LOPT_BROADCAST)
2224 {
2225 new->next = daemon->force_broadcast;
2226 daemon->force_broadcast = new;
2227 }
2228 else if (option == '3')
2229 {
2230 new->next = daemon->bootp_dynamic;
2231 daemon->bootp_dynamic = new;
2232 }
2233 else
2234 {
2235 new->next = daemon->dhcp_ignore_names;
2236 daemon->dhcp_ignore_names = new;
2237 }
2238
2239 while (arg) {
2240 struct dhcp_netid *member = opt_malloc(sizeof(struct dhcp_netid));
2241 comma = split(arg);
2242 member->next = list;
2243 list = member;
2244 if (strstr(arg, "net:") == arg)
2245 member->net = opt_string_alloc(arg+4);
2246 else
2247 member->net = opt_string_alloc(arg);
2248 arg = comma;
2249 }
2250
2251 new->list = list;
2252 break;
2253 }
2254#endif
2255
2256 case 'V': /* --alias */
2257 {
2258 char *dash, *a[3] = { NULL, NULL, NULL };
2259 int k = 0;
2260 struct doctor *new = opt_malloc(sizeof(struct doctor));
2261 new->next = daemon->doctors;
2262 daemon->doctors = new;
2263 new->mask.s_addr = 0xffffffff;
2264 new->end.s_addr = 0;
2265
2266 if ((a[0] = arg))
2267 for (k = 1; k < 3; k++)
2268 {
2269 if (!(a[k] = split(a[k-1])))
2270 break;
2271 unhide_metas(a[k]);
2272 }
2273
2274 dash = split_chr(a[0], '-');
2275
2276 if ((k < 2) ||
2277 ((new->in.s_addr = inet_addr(a[0])) == (in_addr_t)-1) ||
2278 ((new->out.s_addr = inet_addr(a[1])) == (in_addr_t)-1))
2279 option = '?';
2280
2281 if (k == 3)
2282 new->mask.s_addr = inet_addr(a[2]);
2283
2284 if (dash &&
2285 ((new->end.s_addr = inet_addr(dash)) == (in_addr_t)-1 ||
2286 !is_same_net(new->in, new->end, new->mask) ||
2287 ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
2288 problem = _("invalid alias range");
2289
2290 break;
2291 }
2292
2293 case LOPT_INTNAME: /* --interface-name */
2294 {
2295 struct interface_name *new, **up;
2296 char *domain = NULL;
2297
2298 comma = split(arg);
2299
2300 if (!comma || !(domain = canonicalise_opt(arg)))
2301 problem = _("bad interface name");
2302
2303 new = opt_malloc(sizeof(struct interface_name));
2304 new->next = NULL;
2305 /* Add to the end of the list, so that first name
2306 of an interface is used for PTR lookups. */
2307 for (up = &daemon->int_names; *up; up = &((*up)->next));
2308 *up = new;
2309 new->name = domain;
2310 new->intr = opt_string_alloc(comma);
2311 break;
2312 }
2313
2314 case LOPT_CNAME: /* --cname */
2315 {
2316 struct cname *new;
2317
2318 if (!(comma = split(arg)))
2319 option = '?';
2320 else
2321 {
2322 char *alias = canonicalise_opt(arg);
2323 char *target = canonicalise_opt(comma);
2324
2325 if (!alias || !target)
2326 problem = _("bad CNAME");
2327 else
2328 {
2329 for (new = daemon->cnames; new; new = new->next)
2330 if (hostname_isequal(new->alias, arg))
2331 problem = _("duplicate CNAME");
2332 new = opt_malloc(sizeof(struct cname));
2333 new->next = daemon->cnames;
2334 daemon->cnames = new;
2335 new->alias = alias;
2336 new->target = target;
2337 }
2338 }
2339 break;
2340 }
2341
2342 case LOPT_PTR: /* --ptr-record */
2343 {
2344 struct ptr_record *new;
2345 char *dom, *target = NULL;
2346
2347 comma = split(arg);
2348
2349 if (!(dom = canonicalise_opt(arg)) ||
2350 (comma && !(target = canonicalise_opt(comma))))
2351 problem = _("bad PTR record");
2352 else
2353 {
2354 new = opt_malloc(sizeof(struct ptr_record));
2355 new->next = daemon->ptr;
2356 daemon->ptr = new;
2357 new->name = dom;
2358 new->ptr = target;
2359 }
2360 break;
2361 }
2362
2363 case LOPT_NAPTR: /* --naptr-record */
2364 {
2365 char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
2366 int k = 0;
2367 struct naptr *new;
2368 int order, pref;
2369 char *name, *replace = NULL;
2370
2371 if ((a[0] = arg))
2372 for (k = 1; k < 7; k++)
2373 if (!(a[k] = split(a[k-1])))
2374 break;
2375
2376
2377 if (k < 6 ||
2378 !(name = canonicalise_opt(a[0])) ||
2379 !atoi_check16(a[1], &order) ||
2380 !atoi_check16(a[2], &pref) ||
2381 (k == 7 && !(replace = canonicalise_opt(a[6]))))
2382 problem = _("bad NAPTR record");
2383 else
2384 {
2385 new = opt_malloc(sizeof(struct naptr));
2386 new->next = daemon->naptr;
2387 daemon->naptr = new;
2388 new->name = name;
2389 new->flags = opt_string_alloc(a[3]);
2390 new->services = opt_string_alloc(a[4]);
2391 new->regexp = opt_string_alloc(a[5]);
2392 new->replace = replace;
2393 new->order = order;
2394 new->pref = pref;
2395 }
2396 break;
2397 }
2398
2399 case 'Y': /* --txt-record */
2400 {
2401 struct txt_record *new;
2402 unsigned char *p, *q;
2403
2404 if ((comma = split(arg)))
2405 comma--;
2406
2407 gen_prob = _("TXT record string too long");
2408
2409 if ((q = (unsigned char *)comma))
2410 while (1)
2411 {
2412 size_t len;
2413 if ((p = (unsigned char *)strchr((char*)q+1, ',')))
2414 {
2415 if ((len = p - q - 1) > 255)
2416 option = '?';
2417 *q = len;
2418 for (q = q+1; q < p; q++)
2419 *q = unhide_meta(*q);
2420 }
2421 else
2422 {
2423 if ((len = strlen((char *)q+1)) > 255)
2424 option = '?';
2425 *q = len;
2426 for (q = q+1; *q; q++)
2427 *q = unhide_meta(*q);
2428 break;
2429 }
2430 }
2431
2432 new = opt_malloc(sizeof(struct txt_record));
2433 new->next = daemon->txt;
2434 daemon->txt = new;
2435 new->class = C_IN;
2436 if (comma)
2437 {
2438 new->len = q - ((unsigned char *)comma);
2439 new->txt = opt_malloc(new->len);
2440 memcpy(new->txt, comma, new->len);
2441 }
2442 else
2443 {
2444 static char empty[] = "";
2445 new->len = 1;
2446 new->txt = empty;
2447 }
2448
2449 /* ensure arg is terminated */
2450 if (comma)
2451 *comma = 0;
2452
2453 if (!(new->name = canonicalise_opt(arg)))
2454 {
2455 problem = _("bad TXT record");
2456 break;
2457 }
2458
2459 break;
2460 }
2461
2462 case 'W': /* --srv-host */
2463 {
2464 int port = 1, priority = 0, weight = 0;
2465 char *name, *target = NULL;
2466 struct mx_srv_record *new;
2467
2468 comma = split(arg);
2469
2470 if (!(name = canonicalise_opt(arg)))
2471 problem = _("bad SRV record");
2472
2473 if (comma)
2474 {
2475 arg = comma;
2476 comma = split(arg);
2477 if (!(target = canonicalise_opt(arg))
2478) problem = _("bad SRV target");
2479
2480 if (comma)
2481 {
2482 arg = comma;
2483 comma = split(arg);
2484 if (!atoi_check16(arg, &port))
2485 problem = _("invalid port number");
2486
2487 if (comma)
2488 {
2489 arg = comma;
2490 comma = split(arg);
2491 if (!atoi_check16(arg, &priority))
2492 problem = _("invalid priority");
2493
2494 if (comma)
2495 {
2496 arg = comma;
2497 comma = split(arg);
2498 if (!atoi_check16(arg, &weight))
2499 problem = _("invalid weight");
2500 }
2501 }
2502 }
2503 }
2504
2505 new = opt_malloc(sizeof(struct mx_srv_record));
2506 new->next = daemon->mxnames;
2507 daemon->mxnames = new;
2508 new->issrv = 1;
2509 new->name = name;
2510 new->target = target;
2511 new->srvport = port;
2512 new->priority = priority;
2513 new->weight = weight;
2514 break;
2515 }
2516
2517 default:
2518 return _("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DBus support)");
2519
2520 }
2521
2522 if (problem)
2523 return problem;
2524
2525 if (option == '?')
2526 return gen_prob;
2527
2528 return NULL;
2529}
2530
2531static void one_file(char *file, int nest, int hard_opt)
2532{
2533 volatile int lineno = 0;
2534 int i, option;
2535 FILE *f;
2536 char *p, *arg, *start, *buff = daemon->namebuff;
2537 static struct fileread {
2538 dev_t dev;
2539 ino_t ino;
2540 struct fileread *next;
2541 } *filesread = NULL;
2542 struct stat statbuf;
2543
2544 /* ignore repeated files. */
2545 if (hard_opt == 0 && stat(file, &statbuf) == 0)
2546 {
2547 struct fileread *r;
2548
2549 for (r = filesread; r; r = r->next)
2550 if (r->dev == statbuf.st_dev && r->ino == statbuf.st_ino)
2551 return;
2552
2553 r = safe_malloc(sizeof(struct fileread));
2554 r->next = filesread;
2555 filesread = r;
2556 r->dev = statbuf.st_dev;
2557 r->ino = statbuf.st_ino;
2558 }
2559
2560 if (nest > 20)
2561 die(_("files nested too deep in %s"), file, EC_BADCONF);
2562
2563 if (!(f = fopen(file, "r")))
2564 {
2565 if (errno == ENOENT && nest == 0)
2566 return; /* No conffile, all done. */
2567 else
2568 {
2569 char *str = _("cannot read %s: %s");
2570 if (hard_opt != 0)
2571 {
2572 my_syslog(LOG_ERR, str, file, strerror(errno));
2573 return;
2574 }
2575 else
2576 die(str, file, EC_FILE);
2577 }
2578 }
2579
2580 while (fgets(buff, MAXDNAME, f))
2581 {
2582 int white;
2583 unsigned int lastquote;
2584 char *errmess;
2585
2586 /* Memory allocation failure longjmps here if mem_recover == 1 */
2587 if (hard_opt)
2588 {
2589 if (setjmp(mem_jmp))
2590 continue;
2591 mem_recover = 1;
2592 }
2593
2594 lineno++;
2595 errmess = NULL;
2596
2597 /* Implement quotes, inside quotes we allow \\ \" \n and \t
2598 metacharacters get hidden also strip comments */
2599
2600 for (white = 1, lastquote = 0, p = buff; *p; p++)
2601 {
2602 if (*p == '"')
2603 {
2604 memmove(p, p+1, strlen(p+1)+1);
2605 for(; *p && *p != '"'; p++)
2606 {
2607 if (*p == '\\' && strchr("\"tnebr\\", p[1]))
2608 {
2609 if (p[1] == 't')
2610 p[1] = '\t';
2611 else if (p[1] == 'n')
2612 p[1] = '\n';
2613 else if (p[1] == 'b')
2614 p[1] = '\b';
2615 else if (p[1] == 'r')
2616 p[1] = '\r';
2617 else if (p[1] == 'e') /* escape */
2618 p[1] = '\033';
2619 memmove(p, p+1, strlen(p+1)+1);
2620 }
2621 *p = hide_meta(*p);
2622 }
2623 if (*p == '"')
2624 {
2625 memmove(p, p+1, strlen(p+1)+1);
2626 lastquote = p - buff;
2627 }
2628 else
2629 {
2630 errmess = _("missing \"");
2631 goto oops;
2632 }
2633 }
2634
2635 if (white && *p == '#')
2636 {
2637 *p = 0;
2638 break;
2639 }
2640 white = isspace((int)unhide_meta(*p));
2641 }
2642
2643 /* fgets gets end of line char too. */
2644 while (strlen(buff) > lastquote && isspace((int)unhide_meta(buff[strlen(buff)-1])))
2645 buff[strlen(buff)-1] = 0;
2646
2647 if (*buff == 0)
2648 continue;
2649
2650 if (hard_opt != 0)
2651 arg = buff;
2652 else if ((p=strchr(buff, '=')))
2653 {
2654 /* allow spaces around "=" */
2655 arg = p+1;
2656 for (; p >= buff && (isspace((int)*p) || *p == '='); p--)
2657 *p = 0;
2658 }
2659 else
2660 arg = NULL;
2661
2662 if (hard_opt != 0)
2663 option = hard_opt;
2664 else
2665 {
2666 /* skip leading space */
2667 for (start = buff; *start && isspace((int)*start); start++);
2668
2669 for (option = 0, i = 0; opts[i].name; i++)
2670 if (strcmp(opts[i].name, start) == 0)
2671 {
2672 option = opts[i].val;
2673 break;
2674 }
2675
2676 if (!option)
2677 errmess = _("bad option");
2678 else if (opts[i].has_arg == 0 && arg)
2679 errmess = _("extraneous parameter");
2680 else if (opts[i].has_arg == 1 && !arg)
2681 errmess = _("missing parameter");
2682 }
2683
2684 if (!errmess)
2685 {
2686 if (arg)
2687 for (; isspace((int)*arg); arg++);
2688
2689 errmess = one_opt(option, arg, _("error"), nest + 1);
2690 }
2691
2692 if (errmess)
2693 {
2694 oops:
2695 sprintf(buff, _("%s at line %d of %%s"), errmess, lineno);
2696 if (hard_opt != 0)
2697 my_syslog(LOG_ERR, buff, file);
2698 else
2699 die(buff, file, EC_BADCONF);
2700 }
2701 }
2702
2703 mem_recover = 1;
2704 fclose(f);
2705}
2706
2707#ifdef HAVE_DHCP
2708void reread_dhcp(void)
2709{
2710 if (daemon->dhcp_hosts_file)
2711 {
2712 struct dhcp_config *configs, *cp, **up;
2713
2714 /* remove existing... */
2715 for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
2716 {
2717 cp = configs->next;
2718
2719 if (configs->flags & CONFIG_BANK)
2720 {
2721 struct hwaddr_config *mac, *tmp;
2722
2723 for (mac = configs->hwaddr; mac; mac = tmp)
2724 {
2725 tmp = mac->next;
2726 free(mac);
2727 }
2728 if (configs->flags & CONFIG_CLID)
2729 free(configs->clid);
2730 if (configs->flags & CONFIG_NETID)
2731 free(configs->netid.net);
2732 if (configs->flags & CONFIG_NAME)
2733 free(configs->hostname);
2734
2735
2736 *up = configs->next;
2737 free(configs);
2738 }
2739 else
2740 up = &configs->next;
2741 }
2742
2743 one_file(daemon->dhcp_hosts_file, 1, LOPT_BANK);
2744 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), daemon->dhcp_hosts_file);
2745 }
2746
2747 if (daemon->dhcp_opts_file)
2748 {
2749 struct dhcp_opt *opts, *cp, **up;
2750 struct dhcp_netid *id, *next;
2751
2752 for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
2753 {
2754 cp = opts->next;
2755
2756 if (opts->flags & DHOPT_BANK)
2757 {
2758 if ((opts->flags & DHOPT_VENDOR))
2759 free(opts->u.vendor_class);
2760 free(opts->val);
2761 for (id = opts->netid; id; id = next)
2762 {
2763 next = id->next;
2764 free(id->net);
2765 free(id);
2766 }
2767 *up = opts->next;
2768 free(opts);
2769 }
2770 else
2771 up = &opts->next;
2772 }
2773
2774 one_file(daemon->dhcp_opts_file, 1, LOPT_OPTS);
2775 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), daemon->dhcp_opts_file);
2776 }
2777}
2778#endif
2779
2780void read_opts(int argc, char **argv, char *compile_opts)
2781{
2782 char *buff = opt_malloc(MAXDNAME);
2783 int option, nest = 0, testmode = 0;
2784 char *errmess, *arg, *conffile = CONFFILE;
2785
2786 opterr = 0;
2787
2788 daemon = opt_malloc(sizeof(struct daemon));
2789 memset(daemon, 0, sizeof(struct daemon));
2790 daemon->namebuff = buff;
2791
2792 /* Set defaults - everything else is zero or NULL */
2793 daemon->cachesize = CACHESIZ;
2794 daemon->ftabsize = FTABSIZ;
2795 daemon->port = NAMESERVER_PORT;
2796 daemon->dhcp_client_port = DHCP_CLIENT_PORT;
2797 daemon->dhcp_server_port = DHCP_SERVER_PORT;
2798 daemon->default_resolv.is_default = 1;
2799 daemon->default_resolv.name = RESOLVFILE;
2800 daemon->resolv_files = &daemon->default_resolv;
2801 daemon->username = CHUSER;
2802 daemon->runfile = RUNFILE;
2803 daemon->dhcp_max = MAXLEASES;
2804 daemon->tftp_max = TFTP_MAX_CONNECTIONS;
2805 daemon->edns_pktsz = EDNS_PKTSZ;
2806 daemon->log_fac = -1;
2807 add_txt("version.bind", "dnsmasq-" VERSION );
2808 add_txt("authors.bind", "Simon Kelley");
2809 add_txt("copyright.bind", COPYRIGHT);
2810
2811 while (1)
2812 {
2813#ifdef HAVE_GETOPT_LONG
2814 option = getopt_long(argc, argv, OPTSTRING, opts, NULL);
2815#else
2816 option = getopt(argc, argv, OPTSTRING);
2817#endif
2818
2819 if (option == -1)
2820 break;
2821
2822 /* Copy optarg so that argv doesn't get changed */
2823 if (optarg)
2824 {
2825 strncpy(buff, optarg, MAXDNAME);
2826 buff[MAXDNAME-1] = 0;
2827 arg = buff;
2828 }
2829 else
2830 arg = NULL;
2831
2832 /* command-line only stuff */
2833 if (option == LOPT_TEST)
2834 testmode = 1;
2835 else if (option == 'w')
2836 {
2837 if (argc != 3 || strcmp(argv[2], "dhcp") != 0)
2838 do_usage();
2839#ifdef HAVE_DHCP
2840 else
2841 display_opts();
2842#endif
2843 exit(0);
2844 }
2845 else if (option == 'v')
2846 {
2847 printf(_("Dnsmasq version %s %s\n"), VERSION, COPYRIGHT);
2848 printf(_("Compile time options %s\n\n"), compile_opts);
2849 printf(_("This software comes with ABSOLUTELY NO WARRANTY.\n"));
2850 printf(_("Dnsmasq is free software, and you are welcome to redistribute it\n"));
2851 printf(_("under the terms of the GNU General Public License, version 2 or 3.\n"));
2852 exit(0);
2853 }
2854 else if (option == 'C')
2855 {
2856 conffile = opt_string_alloc(arg);
2857 nest++;
2858 }
2859 else
2860 {
2861#ifdef HAVE_GETOPT_LONG
2862 errmess = one_opt(option, arg, _("try --help"), 0);
2863#else
2864 errmess = one_opt(option, arg, _("try -w"), 0);
2865#endif
2866 if (errmess)
2867 die(_("bad command line options: %s"), errmess, EC_BADCONF);
2868 }
2869 }
2870
2871 if (conffile)
2872 one_file(conffile, nest, 0);
2873
2874 /* port might not be known when the address is parsed - fill in here */
2875 if (daemon->servers)
2876 {
2877 struct server *tmp;
2878 for (tmp = daemon->servers; tmp; tmp = tmp->next)
2879 if (!(tmp->flags & SERV_HAS_SOURCE))
2880 {
2881 if (tmp->source_addr.sa.sa_family == AF_INET)
2882 tmp->source_addr.in.sin_port = htons(daemon->query_port);
2883#ifdef HAVE_IPV6
2884 else if (tmp->source_addr.sa.sa_family == AF_INET6)
2885 tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
2886#endif
2887 }
2888 }
2889
2890 if (daemon->if_addrs)
2891 {
2892 struct iname *tmp;
2893 for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)
2894 if (tmp->addr.sa.sa_family == AF_INET)
2895 tmp->addr.in.sin_port = htons(daemon->port);
2896#ifdef HAVE_IPV6
2897 else if (tmp->addr.sa.sa_family == AF_INET6)
2898 tmp->addr.in6.sin6_port = htons(daemon->port);
2899#endif /* IPv6 */
2900 }
2901
2902 /* only one of these need be specified: the other defaults to the host-name */
2903 if ((daemon->options & OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
2904 {
2905 struct mx_srv_record *mx;
2906
2907 if (gethostname(buff, MAXDNAME) == -1)
2908 die(_("cannot get host-name: %s"), NULL, EC_MISC);
2909
2910 for (mx = daemon->mxnames; mx; mx = mx->next)
2911 if (!mx->issrv && hostname_isequal(mx->name, buff))
2912 break;
2913
2914 if ((daemon->mxtarget || (daemon->options & OPT_LOCALMX)) && !mx)
2915 {
2916 mx = opt_malloc(sizeof(struct mx_srv_record));
2917 mx->next = daemon->mxnames;
2918 mx->issrv = 0;
2919 mx->target = NULL;
2920 mx->name = opt_string_alloc(buff);
2921 daemon->mxnames = mx;
2922 }
2923
2924 if (!daemon->mxtarget)
2925 daemon->mxtarget = opt_string_alloc(buff);
2926
2927 for (mx = daemon->mxnames; mx; mx = mx->next)
2928 if (!mx->issrv && !mx->target)
2929 mx->target = daemon->mxtarget;
2930 }
2931
2932 if (!(daemon->options & OPT_NO_RESOLV) &&
2933 daemon->resolv_files &&
2934 daemon->resolv_files->next &&
2935 (daemon->options & OPT_NO_POLL))
2936 die(_("only one resolv.conf file allowed in no-poll mode."), NULL, EC_BADCONF);
2937
2938 if (daemon->options & OPT_RESOLV_DOMAIN)
2939 {
2940 char *line;
2941 FILE *f;
2942
2943 if ((daemon->options & OPT_NO_RESOLV) ||
2944 !daemon->resolv_files ||
2945 (daemon->resolv_files)->next)
2946 die(_("must have exactly one resolv.conf to read domain from."), NULL, EC_BADCONF);
2947
2948 if (!(f = fopen((daemon->resolv_files)->name, "r")))
2949 die(_("failed to read %s: %s"), (daemon->resolv_files)->name, EC_FILE);
2950
2951 while ((line = fgets(buff, MAXDNAME, f)))
2952 {
2953 char *token = strtok(line, " \t\n\r");
2954
2955 if (!token || strcmp(token, "search") != 0)
2956 continue;
2957
2958 if ((token = strtok(NULL, " \t\n\r")) &&
2959 (daemon->domain_suffix = canonicalise_opt(token)))
2960 break;
2961 }
2962
2963 fclose(f);
2964
2965 if (!daemon->domain_suffix)
2966 die(_("no search directive found in %s"), (daemon->resolv_files)->name, EC_MISC);
2967 }
2968
2969 if (daemon->domain_suffix)
2970 {
2971 /* add domain for any srv record without one. */
2972 struct mx_srv_record *srv;
2973
2974 for (srv = daemon->mxnames; srv; srv = srv->next)
2975 if (srv->issrv &&
2976 strchr(srv->name, '.') &&
2977 strchr(srv->name, '.') == strrchr(srv->name, '.'))
2978 {
2979 strcpy(buff, srv->name);
2980 strcat(buff, ".");
2981 strcat(buff, daemon->domain_suffix);
2982 free(srv->name);
2983 srv->name = opt_string_alloc(buff);
2984 }
2985 }
2986 else if (daemon->options & OPT_DHCP_FQDN)
2987 die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
2988
2989 if (testmode)
2990 {
2991 fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
2992 exit(0);
2993 }
2994}