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