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