Tomato 1.26 beta(1766)
[tomato.git] / release / src / router / dnsmasq / src / option.c
blobfe04b6f330310eb5c50ebcc217064190b17a0ed1
1 /* dnsmasq is Copyright (c) 2000-2009 Simon Kelley
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.
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.
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/>.
17 /* define this to get facilitynames */
18 #define SYSLOG_NAMES
19 #include "dnsmasq.h"
20 #include <setjmp.h>
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);
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 }
53 #endif
55 #ifndef HAVE_GETOPT_LONG
56 struct myoption {
57 const char *name;
58 int has_arg;
59 int *flag;
60 int val;
62 #endif
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:"
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
106 #ifdef HAVE_GETOPT_LONG
107 static const struct option opts[] =
108 #else
109 static const struct myoption opts[] =
110 #endif
112 { "version", 0, 0, 'v' },
113 { "no-hosts", 0, 0, 'h' },
114 { "no-poll", 0, 0, 'n' },
115 { "help", 0, 0, 'w' },
116 { "no-daemon", 0, 0, 'd' },
117 { "log-queries", 0, 0, 'q' },
118 { "user", 2, 0, 'u' },
119 { "group", 2, 0, 'g' },
120 { "resolv-file", 2, 0, 'r' },
121 { "mx-host", 1, 0, 'm' },
122 { "mx-target", 1, 0, 't' },
123 { "cache-size", 2, 0, 'c' },
124 { "port", 1, 0, 'p' },
125 { "dhcp-leasefile", 2, 0, 'l' },
126 { "dhcp-lease", 1, 0, 'l' },
127 { "dhcp-host", 1, 0, 'G' },
128 { "dhcp-range", 1, 0, 'F' },
129 { "dhcp-option", 1, 0, 'O' },
130 { "dhcp-boot", 1, 0, 'M' },
131 { "domain", 1, 0, 's' },
132 { "domain-suffix", 1, 0, 's' },
133 { "interface", 1, 0, 'i' },
134 { "listen-address", 1, 0, 'a' },
135 { "bogus-priv", 0, 0, 'b' },
136 { "bogus-nxdomain", 1, 0, 'B' },
137 { "selfmx", 0, 0, 'e' },
138 { "filterwin2k", 0, 0, 'f' },
139 { "pid-file", 2, 0, 'x' },
140 { "strict-order", 0, 0, 'o' },
141 { "server", 1, 0, 'S' },
142 { "local", 1, 0, LOPT_LOCAL },
143 { "address", 1, 0, 'A' },
144 { "conf-file", 2, 0, 'C' },
145 { "no-resolv", 0, 0, 'R' },
146 { "expand-hosts", 0, 0, 'E' },
147 { "localmx", 0, 0, 'L' },
148 { "local-ttl", 1, 0, 'T' },
149 { "no-negcache", 0, 0, 'N' },
150 { "addn-hosts", 1, 0, 'H' },
151 { "query-port", 1, 0, 'Q' },
152 { "except-interface", 1, 0, 'I' },
153 { "no-dhcp-interface", 1, 0, '2' },
154 { "domain-needed", 0, 0, 'D' },
155 { "dhcp-lease-max", 1, 0, 'X' },
156 { "bind-interfaces", 0, 0, 'z' },
157 { "read-ethers", 0, 0, 'Z' },
158 { "alias", 1, 0, 'V' },
159 { "dhcp-vendorclass", 1, 0, 'U' },
160 { "dhcp-userclass", 1, 0, 'j' },
161 { "dhcp-ignore", 1, 0, 'J' },
162 { "edns-packet-max", 1, 0, 'P' },
163 { "keep-in-foreground", 0, 0, 'k' },
164 { "dhcp-authoritative", 0, 0, 'K' },
165 { "srv-host", 1, 0, 'W' },
166 { "localise-queries", 0, 0, 'y' },
167 { "txt-record", 1, 0, 'Y' },
168 { "enable-dbus", 0, 0, '1' },
169 { "bootp-dynamic", 2, 0, '3' },
170 { "dhcp-mac", 1, 0, '4' },
171 { "no-ping", 0, 0, '5' },
172 { "dhcp-script", 1, 0, '6' },
173 { "conf-dir", 1, 0, '7' },
174 { "log-facility", 1, 0 ,'8' },
175 { "leasefile-ro", 0, 0, '9' },
176 { "dns-forward-max", 1, 0, '0' },
177 { "clear-on-reload", 0, 0, LOPT_RELOAD },
178 { "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
179 { "enable-tftp", 0, 0, LOPT_TFTP },
180 { "tftp-secure", 0, 0, LOPT_SECURE },
181 { "tftp-unique-root", 0, 0, LOPT_APREF },
182 { "tftp-root", 1, 0, LOPT_PREFIX },
183 { "tftp-max", 1, 0, LOPT_TFTP_MAX },
184 { "ptr-record", 1, 0, LOPT_PTR },
185 { "naptr-record", 1, 0, LOPT_NAPTR },
186 { "bridge-interface", 1, 0 , LOPT_BRIDGE },
187 { "dhcp-option-force", 1, 0, LOPT_FORCE },
188 { "tftp-no-blocksize", 0, 0, LOPT_NOBLOCK },
189 { "log-dhcp", 0, 0, LOPT_LOG_OPTS },
190 { "log-async", 2, 0, LOPT_MAX_LOGS },
191 { "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
192 { "dhcp-remoteid", 1, 0, LOPT_REMOTE },
193 { "dhcp-subscrid", 1, 0, LOPT_SUBSCR },
194 { "interface-name", 1, 0, LOPT_INTNAME },
195 { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
196 { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
197 { "dhcp-no-override", 0, 0, LOPT_OVERRIDE },
198 { "tftp-port-range", 1, 0, LOPT_TFTPPORTS },
199 { "stop-dns-rebind", 0, 0, LOPT_REBIND },
200 { "all-servers", 0, 0, LOPT_NOLAST },
201 { "dhcp-match", 1, 0, LOPT_MATCH },
202 { "dhcp-broadcast", 1, 0, LOPT_BROADCAST },
203 { "neg-ttl", 1, 0, LOPT_NEGTTL },
204 { "dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
205 { "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
206 { "min-port", 1, 0, LOPT_MINPORT },
207 { "dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN },
208 { "cname", 1, 0, LOPT_CNAME },
209 { "pxe-prompt", 1, 0, LOPT_PXE_PROMT },
210 { "pxe-service", 1, 0, LOPT_PXE_SERV },
211 { "test", 0, 0, LOPT_TEST },
212 { NULL, 0, 0, 0 }
215 /* These must have more the one '1' bit */
216 #define ARG_DUP 3
217 #define ARG_ONE 5
218 #define ARG_USED_CL 7
219 #define ARG_USED_FILE 9
221 static struct {
222 int opt;
223 unsigned int rept;
224 char * const flagdesc;
225 char * const desc;
226 char * const arg;
227 } usage[] = {
228 { 'a', ARG_DUP, "ipaddr", gettext_noop("Specify local address(es) to listen on."), NULL },
229 { 'A', ARG_DUP, "/domain/ipaddr", gettext_noop("Return ipaddr for all hosts in specified domains."), NULL },
230 { 'b', OPT_BOGUSPRIV, NULL, gettext_noop("Fake reverse lookups for RFC1918 private address ranges."), NULL },
231 { 'B', ARG_DUP, "ipaddr", gettext_noop("Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."), NULL },
232 { 'c', ARG_ONE, "cachesize", gettext_noop("Specify the size of the cache in entries (defaults to %s)."), "$" },
233 { 'C', ARG_DUP, "path", gettext_noop("Specify configuration file (defaults to %s)."), CONFFILE },
234 { 'd', OPT_DEBUG, NULL, gettext_noop("Do NOT fork into the background: run in debug mode."), NULL },
235 { 'D', OPT_NODOTS_LOCAL, NULL, gettext_noop("Do NOT forward queries with no domain part."), NULL },
236 { 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL },
237 { 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
238 { 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
239 { 'F', ARG_DUP, "ipaddr,ipaddr,time", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
240 { 'g', ARG_ONE, "groupname", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
241 { 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
242 { LOPT_DHCP_HOST, ARG_ONE, "<filename>", gettext_noop("Read DHCP host specs from file"), NULL },
243 { LOPT_DHCP_OPTS, ARG_ONE, "<filename>", gettext_noop("Read DHCP option specs from file"), NULL },
244 { 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
245 { 'H', ARG_DUP, "path", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
246 { 'i', ARG_DUP, "interface", gettext_noop("Specify interface(s) to listen on."), NULL },
247 { 'I', ARG_DUP, "int", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
248 { 'j', ARG_DUP, "<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
249 { LOPT_CIRCUIT, ARG_DUP, "<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
250 { LOPT_REMOTE, ARG_DUP, "<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
251 { LOPT_SUBSCR, ARG_DUP, "<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
252 { 'J', ARG_DUP, "=<id>[,<id>]", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
253 { LOPT_BROADCAST, ARG_DUP, "=<id>[,<id>]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
254 { 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
255 { 'K', OPT_AUTHORITATIVE, NULL, gettext_noop("Assume we are the only DHCP server on the local network."), NULL },
256 { 'l', ARG_ONE, "path", gettext_noop("Specify where to store DHCP leases (defaults to %s)."), LEASEFILE },
257 { 'L', OPT_LOCALMX, NULL, gettext_noop("Return MX records for local hosts."), NULL },
258 { 'm', ARG_DUP, "host_name,target,pref", gettext_noop("Specify an MX record."), NULL },
259 { 'M', ARG_DUP, "<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL },
260 { 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE },
261 { 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL },
262 { 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE },
263 { 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL },
264 { LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},
265 { 'p', ARG_ONE, "number", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
266 { 'P', ARG_ONE, "<size>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
267 { 'q', OPT_LOG, NULL, gettext_noop("Log DNS queries."), NULL },
268 { 'Q', ARG_ONE, "number", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
269 { 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
270 { 'r', ARG_DUP, "path", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
271 { 'S', ARG_DUP, "/domain/ipaddr", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
272 { LOPT_LOCAL, ARG_DUP, "/domain/", gettext_noop("Never forward queries to specified domains."), NULL },
273 { 's', ARG_DUP, "<domain>[,<range>]", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
274 { 't', ARG_ONE, "host_name", gettext_noop("Specify default target in an MX record."), NULL },
275 { 'T', ARG_ONE, "time", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
276 { LOPT_NEGTTL, ARG_ONE, "time", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
277 { 'u', ARG_ONE, "username", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
278 { 'U', ARG_DUP, "<id>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
279 { 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
280 { 'V', ARG_DUP, "addr,addr,mask", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },
281 { 'W', ARG_DUP, "name,target,...", gettext_noop("Specify a SRV record."), NULL },
282 { 'w', 0, NULL, gettext_noop("Display this message. Use --help dhcp for known DHCP options."), NULL },
283 { 'x', ARG_ONE, "path", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE },
284 { 'X', ARG_ONE, "number", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },
285 { 'y', OPT_LOCALISE, NULL, gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL },
286 { 'Y', ARG_DUP, "name,txt....", gettext_noop("Specify TXT DNS record."), NULL },
287 { LOPT_PTR, ARG_DUP, "name,target", gettext_noop("Specify PTR DNS record."), NULL },
288 { LOPT_INTNAME, ARG_DUP, "name,interface", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
289 { 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
290 { 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
291 { '1', OPT_DBUS, NULL, gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
292 { '2', ARG_DUP, "interface", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
293 { '3', ARG_DUP, "[=<id>[,<id>]]", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
294 { '4', ARG_DUP, "<id>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
295 { LOPT_BRIDGE, ARG_DUP, "iface,alias,..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL },
296 { '5', OPT_NO_PING, NULL, gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
297 { '6', ARG_ONE, "path", gettext_noop("Script to run on DHCP lease creation and destruction."), NULL },
298 { '7', ARG_DUP, "path", gettext_noop("Read configuration from all the files in this directory."), NULL },
299 { '8', ARG_ONE, "<facilty>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL },
300 { '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL },
301 { '0', ARG_ONE, "<queries>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" },
302 { LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
303 { LOPT_NO_NAMES, ARG_DUP, "[=<id>[,<id>]]", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
304 { LOPT_OVERRIDE, OPT_NO_OVERRIDE, NULL, gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL },
305 { LOPT_TFTP, OPT_TFTP, NULL, gettext_noop("Enable integrated read-only TFTP server."), NULL },
306 { LOPT_PREFIX, ARG_ONE, "<directory>", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
307 { LOPT_APREF, OPT_TFTP_APREF, NULL, gettext_noop("Add client IP address to tftp-root."), NULL },
308 { LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
309 { LOPT_TFTP_MAX, ARG_ONE, "<connections>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },
310 { LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
311 { LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
312 { LOPT_LOG_OPTS, OPT_LOG_OPTS, NULL, gettext_noop("Extra logging for DHCP."), NULL },
313 { LOPT_MAX_LOGS, ARG_ONE, "[=<log lines>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL },
314 { LOPT_REBIND, OPT_NO_REBIND, NULL, gettext_noop("Stop DNS rebinding. Filter private IP ranges when resolving."), NULL },
315 { LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL },
316 { LOPT_MATCH, ARG_DUP, "<netid>,<optspec>", gettext_noop("Set tag if client includes matching option in request."), NULL },
317 { LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
318 { LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change script as this user."), NULL },
319 { LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
320 { LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
321 { LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL },
322 { LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
323 { LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
324 { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
325 { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
326 { 0, 0, NULL, NULL, NULL }
329 #ifdef HAVE_DHCP
330 /* makes options which take a list of addresses */
331 #define OT_ADDR_LIST 0x80
332 /* DHCP-internal options, for logging. not valid in config file */
333 #define OT_INTERNAL 0x40
334 #define OT_NAME 0x20
336 static const struct {
337 char *name;
338 unsigned char val, size;
339 } opttab[] = {
340 { "netmask", 1, OT_ADDR_LIST },
341 { "time-offset", 2, 4 },
342 { "router", 3, OT_ADDR_LIST },
343 { "dns-server", 6, OT_ADDR_LIST },
344 { "log-server", 7, OT_ADDR_LIST },
345 { "lpr-server", 9, OT_ADDR_LIST },
346 { "hostname", 12, OT_INTERNAL | OT_NAME },
347 { "boot-file-size", 13, 2 },
348 { "domain-name", 15, OT_NAME },
349 { "swap-server", 16, OT_ADDR_LIST },
350 { "root-path", 17, 0 },
351 { "extension-path", 18, 0 },
352 { "ip-forward-enable", 19, 1 },
353 { "non-local-source-routing", 20, 1 },
354 { "policy-filter", 21, OT_ADDR_LIST },
355 { "max-datagram-reassembly", 22, 2 },
356 { "default-ttl", 23, 1 },
357 { "mtu", 26, 2 },
358 { "all-subnets-local", 27, 1 },
359 { "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
360 { "router-discovery", 31, 1 },
361 { "router-solicitation", 32, OT_ADDR_LIST },
362 { "static-route", 33, OT_ADDR_LIST },
363 { "trailer-encapsulation", 34, 1 },
364 { "arp-timeout", 35, 4 },
365 { "ethernet-encap", 36, 1 },
366 { "tcp-ttl", 37, 1 },
367 { "tcp-keepalive", 38, 4 },
368 { "nis-domain", 40, 0 },
369 { "nis-server", 41, OT_ADDR_LIST },
370 { "ntp-server", 42, OT_ADDR_LIST },
371 { "vendor-encap", 43, OT_INTERNAL },
372 { "netbios-ns", 44, OT_ADDR_LIST },
373 { "netbios-dd", 45, OT_ADDR_LIST },
374 { "netbios-nodetype", 46, 1 },
375 { "netbios-scope", 47, 0 },
376 { "x-windows-fs", 48, OT_ADDR_LIST },
377 { "x-windows-dm", 49, OT_ADDR_LIST },
378 { "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
379 { "lease-time", 51, OT_INTERNAL },
380 { "option-overload", 52, OT_INTERNAL },
381 { "message-type", 53, OT_INTERNAL, },
382 { "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
383 { "parameter-request", 55, OT_INTERNAL },
384 { "message", 56, OT_INTERNAL },
385 { "max-message-size", 57, OT_INTERNAL },
386 { "T1", 58, OT_INTERNAL },
387 { "T2", 59, OT_INTERNAL },
388 { "vendor-class", 60, 0 },
389 { "client-id", 61,OT_INTERNAL },
390 { "nis+-domain", 64, 0 },
391 { "nis+-server", 65, OT_ADDR_LIST },
392 { "tftp-server", 66, 0 },
393 { "bootfile-name", 67, 0 },
394 { "mobile-ip-home", 68, OT_ADDR_LIST },
395 { "smtp-server", 69, OT_ADDR_LIST },
396 { "pop3-server", 70, OT_ADDR_LIST },
397 { "nntp-server", 71, OT_ADDR_LIST },
398 { "irc-server", 74, OT_ADDR_LIST },
399 { "user-class", 77, 0 },
400 { "FQDN", 81, OT_INTERNAL },
401 { "agent-id", 82, OT_INTERNAL },
402 { "client-arch", 93, 2 },
403 { "client-interface-id", 94, 0 },
404 { "client-machine-id", 97, 0 },
405 { "subnet-select", 118, OT_INTERNAL },
406 { "domain-search", 119, 0 },
407 { "sip-server", 120, 0 },
408 { "classless-static-route", 121, 0 },
409 { NULL, 0, 0 }
412 char *option_string(unsigned char opt, int *is_ip, int *is_name)
414 int i;
416 for (i = 0; opttab[i].name; i++)
417 if (opttab[i].val == opt)
419 if (is_ip)
420 *is_ip = !!(opttab[i].size & OT_ADDR_LIST);
421 if (is_name)
422 *is_name = !!(opttab[i].size & OT_NAME);
423 return opttab[i].name;
426 return NULL;
429 #endif
431 /* We hide metacharaters in quoted strings by mapping them into the ASCII control
432 character space. Note that the \0, \t \b \r \033 and \n characters are carefully placed in the
433 following sequence so that they map to themselves: it is therefore possible to call
434 unhide_metas repeatedly on string without breaking things.
435 The transformation gets undone by opt_canonicalise, atoi_check and opt_string_alloc, and a
436 couple of other places.
437 Note that space is included here so that
438 --dhcp-option=3, string
439 has five characters, whilst
440 --dhcp-option=3," string"
441 has six.
444 static const char meta[] = "\000123456 \b\t\n78\r90abcdefABCDE\033F:,.";
446 static char hide_meta(char c)
448 unsigned int i;
450 for (i = 0; i < (sizeof(meta) - 1); i++)
451 if (c == meta[i])
452 return (char)i;
454 return c;
457 static char unhide_meta(char cr)
459 unsigned int c = cr;
461 if (c < (sizeof(meta) - 1))
462 cr = meta[c];
464 return cr;
467 static void unhide_metas(char *cp)
469 if (cp)
470 for(; *cp; cp++)
471 *cp = unhide_meta(*cp);
474 static void *opt_malloc(size_t size)
476 void *ret;
478 if (mem_recover)
480 ret = whine_malloc(size);
481 if (!ret)
482 longjmp(mem_jmp, 1);
484 else
485 ret = safe_malloc(size);
487 return ret;
490 static char *opt_string_alloc(char *cp)
492 char *ret = NULL;
494 if (cp && strlen(cp) != 0)
496 ret = opt_malloc(strlen(cp)+1);
497 strcpy(ret, cp);
499 /* restore hidden metachars */
500 unhide_metas(ret);
503 return ret;
507 /* find next comma, split string with zero and eliminate spaces.
508 return start of string following comma */
510 static char *split_chr(char *s, char c)
512 char *comma, *p;
514 if (!s || !(comma = strchr(s, c)))
515 return NULL;
517 p = comma;
518 *comma = ' ';
520 for (; isspace((int)*comma); comma++);
522 for (; (p >= s) && isspace((int)*p); p--)
523 *p = 0;
525 return comma;
528 static char *split(char *s)
530 return split_chr(s, ',');
533 static int canonicalise_opt(char *s)
535 if (!s)
536 return 0;
538 unhide_metas(s);
539 return canonicalise(s);
542 static int atoi_check(char *a, int *res)
544 char *p;
546 if (!a)
547 return 0;
549 unhide_metas(a);
551 for (p = a; *p; p++)
552 if (*p < '0' || *p > '9')
553 return 0;
555 *res = atoi(a);
556 return 1;
559 static int atoi_check16(char *a, int *res)
561 if (!(atoi_check(a, res)) ||
562 *res < 0 ||
563 *res > 0xffff)
564 return 0;
566 return 1;
569 static void add_txt(char *name, char *txt)
571 size_t len = strlen(txt);
572 struct txt_record *r = opt_malloc(sizeof(struct txt_record));
574 r->name = opt_string_alloc(name);
575 r->next = daemon->txt;
576 daemon->txt = r;
577 r->class = C_CHAOS;
578 r->txt = opt_malloc(len+1);
579 r->len = len+1;
580 *(r->txt) = len;
581 memcpy((r->txt)+1, txt, len);
584 static void do_usage(void)
586 char buff[100];
587 int i, j;
589 struct {
590 char handle;
591 int val;
592 } tab[] = {
593 { '$', CACHESIZ },
594 { '*', EDNS_PKTSZ },
595 { '&', MAXLEASES },
596 { '!', FTABSIZ },
597 { '#', TFTP_MAX_CONNECTIONS },
598 { '\0', 0 }
601 printf(_("Usage: dnsmasq [options]\n\n"));
602 #ifndef HAVE_GETOPT_LONG
603 printf(_("Use short options only on the command line.\n"));
604 #endif
605 printf(_("Valid options are:\n"));
607 for (i = 0; usage[i].opt != 0; i++)
609 char *desc = usage[i].flagdesc;
610 char *eq = "=";
612 if (!desc || *desc == '[')
613 eq = "";
615 if (!desc)
616 desc = "";
618 for ( j = 0; opts[j].name; j++)
619 if (opts[j].val == usage[i].opt)
620 break;
621 if (usage[i].opt < 256)
622 sprintf(buff, "-%c, ", usage[i].opt);
623 else
624 sprintf(buff, " ");
626 sprintf(buff+4, "--%s%s%s", opts[j].name, eq, desc);
627 printf("%-36.36s", buff);
629 if (usage[i].arg)
631 strcpy(buff, usage[i].arg);
632 for (j = 0; tab[j].handle; j++)
633 if (tab[j].handle == *(usage[i].arg))
634 sprintf(buff, "%d", tab[j].val);
636 printf(_(usage[i].desc), buff);
637 printf("\n");
641 #ifdef HAVE_DHCP
642 static void display_opts(void)
644 int i;
646 printf(_("Known DHCP options:\n"));
648 for (i = 0; opttab[i].name; i++)
649 if (opttab[i].size != OT_INTERNAL)
650 printf("%3d %s\n", opttab[i].val, opttab[i].name);
653 /* This is too insanely large to keep in-line in the switch */
654 static char *parse_dhcp_opt(char *arg, int flags)
656 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
657 char lenchar = 0, *cp;
658 int i, addrs, digs, is_addr, is_hex, is_dec, is_string, dots;
659 char *comma = NULL, *problem = NULL;
660 struct dhcp_netid *np = NULL;
661 unsigned char opt_len = 0;
663 new->len = 0;
664 new->flags = flags;
665 new->netid = NULL;
666 new->val = NULL;
667 new->opt = 0;
669 while (arg)
671 comma = split(arg);
673 for (cp = arg; *cp; cp++)
674 if (*cp < '0' || *cp > '9')
675 break;
677 if (!*cp)
679 new->opt = atoi(arg);
680 opt_len = 0;
681 break;
684 if (strstr(arg, "option:") == arg)
686 for (i = 0; opttab[i].name; i++)
687 if (opttab[i].size != OT_INTERNAL &&
688 strcasecmp(opttab[i].name, arg+7) == 0)
690 new->opt = opttab[i].val;
691 opt_len = opttab[i].size;
692 break;
694 /* option:<optname> must follow tag and vendor string. */
695 break;
697 else if (strstr(arg, "vendor:") == arg)
699 new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7);
700 new->flags |= DHOPT_VENDOR;
702 else if (strstr(arg, "encap:") == arg)
704 new->u.encap = atoi(arg+6);
705 new->flags |= DHOPT_ENCAPSULATE;
707 else
709 new->netid = opt_malloc(sizeof (struct dhcp_netid));
710 /* allow optional "net:" for consistency */
711 if (strstr(arg, "net:") == arg)
712 new->netid->net = opt_string_alloc(arg+4);
713 else
714 new->netid->net = opt_string_alloc(arg);
715 new->netid->next = np;
716 np = new->netid;
719 arg = comma;
722 if (new->opt == 0)
723 problem = _("bad dhcp-option");
724 else if (comma)
726 /* characterise the value */
727 char c;
728 is_addr = is_hex = is_dec = is_string = 1;
729 addrs = digs = 1;
730 dots = 0;
731 for (cp = comma; (c = *cp); cp++)
732 if (c == ',')
734 addrs++;
735 is_dec = is_hex = 0;
737 else if (c == ':')
739 digs++;
740 is_dec = is_addr = 0;
742 else if (c == '/')
744 is_dec = is_hex = 0;
745 if (cp == comma) /* leading / means a pathname */
746 is_addr = 0;
748 else if (c == '.')
750 is_dec = is_hex = 0;
751 dots++;
753 else if (c == '-')
754 is_hex = is_addr = 0;
755 else if (c == ' ')
756 is_dec = is_hex = 0;
757 else if (!(c >='0' && c <= '9'))
759 is_addr = 0;
760 if (cp[1] == 0 && is_dec &&
761 (c == 'b' || c == 's' || c == 'i'))
763 lenchar = c;
764 *cp = 0;
766 else
767 is_dec = 0;
768 if (!((c >='A' && c <= 'F') ||
769 (c >='a' && c <= 'f') ||
770 (c == '*' && (flags & DHOPT_MATCH))))
771 is_hex = 0;
774 /* We know that some options take addresses */
776 if (opt_len & OT_ADDR_LIST)
778 is_string = is_dec = is_hex = 0;
779 if (!is_addr || dots == 0)
780 problem = _("bad IP address");
783 if (is_hex && digs > 1)
785 new->len = digs;
786 new->val = opt_malloc(new->len);
787 parse_hex(comma, new->val, digs, (flags & DHOPT_MATCH) ? &new->u.wildcard_mask : NULL, NULL);
788 new->flags |= DHOPT_HEX;
790 else if (is_dec)
792 int i, val = atoi(comma);
793 /* assume numeric arg is 1 byte except for
794 options where it is known otherwise.
795 For vendor class option, we have to hack. */
796 if (opt_len != 0)
797 new->len = opt_len;
798 else if (val & 0xffff0000)
799 new->len = 4;
800 else if (val & 0xff00)
801 new->len = 2;
802 else
803 new->len = 1;
805 if (lenchar == 'b')
806 new->len = 1;
807 else if (lenchar == 's')
808 new->len = 2;
809 else if (lenchar == 'i')
810 new->len = 4;
812 new->val = opt_malloc(new->len);
813 for (i=0; i<new->len; i++)
814 new->val[i] = val>>((new->len - i - 1)*8);
816 else if (is_addr)
818 struct in_addr in;
819 unsigned char *op;
820 char *slash;
821 /* max length of address/subnet descriptor is five bytes,
822 add one for the option 120 enc byte too */
823 new->val = op = opt_malloc((5 * addrs) + 1);
824 new->flags |= DHOPT_ADDR;
826 if (!(new->flags & DHOPT_ENCAPSULATE) && new->opt == 120)
828 *(op++) = 1; /* RFC 3361 "enc byte" */
829 new->flags &= ~DHOPT_ADDR;
831 while (addrs--)
833 cp = comma;
834 comma = split(cp);
835 slash = split_chr(cp, '/');
836 in.s_addr = inet_addr(cp);
837 if (!slash)
839 memcpy(op, &in, INADDRSZ);
840 op += INADDRSZ;
842 else
844 unsigned char *p = (unsigned char *)&in;
845 int netsize = atoi(slash);
846 *op++ = netsize;
847 if (netsize > 0)
848 *op++ = *p++;
849 if (netsize > 8)
850 *op++ = *p++;
851 if (netsize > 16)
852 *op++ = *p++;
853 if (netsize > 24)
854 *op++ = *p++;
855 new->flags &= ~DHOPT_ADDR; /* cannot re-write descriptor format */
858 new->len = op - new->val;
860 else if (is_string)
862 /* text arg */
863 if ((new->opt == 119 || new->opt == 120) && !(new->flags & DHOPT_ENCAPSULATE))
865 /* dns search, RFC 3397, or SIP, RFC 3361 */
866 unsigned char *q, *r, *tail;
867 unsigned char *p, *m = NULL, *newp;
868 size_t newlen, len = 0;
869 int header_size = (new->opt == 119) ? 0 : 1;
871 arg = comma;
872 comma = split(arg);
874 while (arg && *arg)
876 if (!canonicalise_opt(arg))
878 problem = _("bad domain in dhcp-option");
879 break;
882 newp = opt_malloc(len + strlen(arg) + 2 + header_size);
883 if (m)
884 memcpy(newp, m, header_size + len);
885 m = newp;
886 p = m + header_size;
887 q = p + len;
889 /* add string on the end in RFC1035 format */
890 while (*arg)
892 unsigned char *cp = q++;
893 int j;
894 for (j = 0; *arg && (*arg != '.'); arg++, j++)
895 *q++ = *arg;
896 *cp = j;
897 if (*arg)
898 arg++;
900 *q++ = 0;
902 /* Now tail-compress using earlier names. */
903 newlen = q - p;
904 for (tail = p + len; *tail; tail += (*tail) + 1)
905 for (r = p; r - p < (int)len; r += (*r) + 1)
906 if (strcmp((char *)r, (char *)tail) == 0)
908 PUTSHORT((r - p) | 0xc000, tail);
909 newlen = tail - p;
910 goto end;
912 end:
913 len = newlen;
915 arg = comma;
916 comma = split(arg);
919 /* RFC 3361, enc byte is zero for names */
920 if (new->opt == 120)
921 m[0] = 0;
922 new->len = (int) len + header_size;
923 new->val = m;
925 else
927 new->len = strlen(comma);
928 /* keep terminating zero on string */
929 new->val = (unsigned char *)opt_string_alloc(comma);
930 new->flags |= DHOPT_STRING;
935 if ((new->len > 255) || (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))))
936 problem = _("dhcp-option too long");
938 if (!problem)
940 if (flags == DHOPT_MATCH)
942 if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||
943 !new->netid ||
944 new->netid->next)
945 problem = _("illegal dhcp-match");
946 else
948 new->next = daemon->dhcp_match;
949 daemon->dhcp_match = new;
952 else
954 new->next = daemon->dhcp_opts;
955 daemon->dhcp_opts = new;
959 return problem;
962 #endif
964 static char *one_opt(int option, char *arg, char *gen_prob, int nest)
966 int i;
967 char *comma, *problem = NULL;;
969 if (option == '?')
970 return gen_prob;
972 for (i=0; usage[i].opt != 0; i++)
973 if (usage[i].opt == option)
975 int rept = usage[i].rept;
977 if (nest == 0)
979 /* command line */
980 if (rept == ARG_USED_CL)
981 return _("illegal repeated flag");
982 if (rept == ARG_ONE)
983 usage[i].rept = ARG_USED_CL;
985 else
987 /* allow file to override command line */
988 if (rept == ARG_USED_FILE)
989 return _("illegal repeated keyword");
990 if (rept == ARG_USED_CL || rept == ARG_ONE)
991 usage[i].rept = ARG_USED_FILE;
994 if (rept != ARG_DUP && rept != ARG_ONE && rept != ARG_USED_CL)
996 daemon->options |= rept;
997 return NULL;
1000 break;
1003 switch (option)
1005 case 'C': /* --conf-file */
1007 char *file = opt_string_alloc(arg);
1008 if (file)
1010 one_file(file, nest, 0);
1011 free(file);
1013 break;
1016 case '7': /* --conf-dir */
1018 DIR *dir_stream;
1019 struct dirent *ent;
1020 char *directory, *path;
1022 if (!(directory = opt_string_alloc(arg)))
1023 break;
1025 if (!(dir_stream = opendir(directory)))
1026 die(_("cannot access directory %s: %s"), directory, EC_FILE);
1028 while ((ent = readdir(dir_stream)))
1030 size_t len = strlen(ent->d_name);
1031 struct stat buf;
1033 /* ignore emacs backups and dotfiles */
1034 if (len == 0 ||
1035 ent->d_name[len - 1] == '~' ||
1036 (ent->d_name[0] == '#' && ent->d_name[len - 1] == '#') ||
1037 ent->d_name[0] == '.')
1038 continue;
1040 path = opt_malloc(strlen(directory) + len + 2);
1041 strcpy(path, directory);
1042 strcat(path, "/");
1043 strcat(path, ent->d_name);
1045 if (stat(path, &buf) == -1)
1046 die(_("cannot access %s: %s"), path, EC_FILE);
1047 /* only reg files allowed. */
1048 if (!S_ISREG(buf.st_mode))
1049 continue;
1051 /* dir is one level, so files must be readable */
1052 one_file(path, nest + 1, 0);
1053 free(path);
1056 closedir(dir_stream);
1057 free(directory);
1058 break;
1061 case '8': /* --log-facility */
1062 /* may be a filename */
1063 if (strchr(arg, '/'))
1064 daemon->log_file = opt_string_alloc(arg);
1065 else
1067 for (i = 0; facilitynames[i].c_name; i++)
1068 if (hostname_isequal((char *)facilitynames[i].c_name, arg))
1069 break;
1071 if (facilitynames[i].c_name)
1072 daemon->log_fac = facilitynames[i].c_val;
1073 else
1074 problem = "bad log facility";
1076 break;
1078 case 'x': /* --pid-file */
1079 daemon->runfile = opt_string_alloc(arg);
1080 break;
1082 case LOPT_DHCP_HOST: /* --dhcp-hostfile */
1083 if (daemon->dhcp_hosts_file)
1084 problem = _("only one dhcp-hostsfile allowed");
1085 else
1086 daemon->dhcp_hosts_file = opt_string_alloc(arg);
1087 break;
1089 case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
1090 if (daemon->dhcp_opts_file)
1091 problem = _("only one dhcp-optsfile allowed");
1092 else
1093 daemon->dhcp_opts_file = opt_string_alloc(arg);
1094 break;
1096 case 'r': /* --resolv-file */
1098 char *name = opt_string_alloc(arg);
1099 struct resolvc *new, *list = daemon->resolv_files;
1101 if (list && list->is_default)
1103 /* replace default resolv file - possibly with nothing */
1104 if (name)
1106 list->is_default = 0;
1107 list->name = name;
1109 else
1110 list = NULL;
1112 else if (name)
1114 new = opt_malloc(sizeof(struct resolvc));
1115 new->next = list;
1116 new->name = name;
1117 new->is_default = 0;
1118 new->mtime = 0;
1119 new->logged = 0;
1120 list = new;
1122 daemon->resolv_files = list;
1123 break;
1126 case 'm': /* --mx-host */
1128 int pref = 1;
1129 struct mx_srv_record *new;
1131 if ((comma = split(arg)))
1133 char *prefstr;
1134 if ((prefstr=split(comma)) && !atoi_check16(prefstr, &pref))
1135 problem = _("bad MX preference");
1138 if (!canonicalise_opt(arg) || (comma && !canonicalise_opt(comma)))
1139 problem = _("bad MX name");
1141 new = opt_malloc(sizeof(struct mx_srv_record));
1142 new->next = daemon->mxnames;
1143 daemon->mxnames = new;
1144 new->issrv = 0;
1145 new->name = opt_string_alloc(arg);
1146 new->target = opt_string_alloc(comma); /* may be NULL */
1147 new->weight = pref;
1148 break;
1151 case 't': /* --mx-target */
1152 if (!canonicalise_opt(arg))
1153 problem = _("bad MX target");
1154 else
1155 daemon->mxtarget = opt_string_alloc(arg);
1156 break;
1158 #ifdef HAVE_DHCP
1159 case 'l': /* --dhcp-leasefile */
1160 daemon->lease_file = opt_string_alloc(arg);
1161 break;
1163 case '6': /* --dhcp-script */
1164 # ifdef NO_FORK
1165 problem = _("cannot run scripts under uClinux");
1166 # else
1167 daemon->lease_change_command = opt_string_alloc(arg);
1168 # endif
1169 break;
1170 #endif
1172 case 'H': /* --addn-hosts */
1174 struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
1175 static int hosts_index = 1;
1176 new->fname = opt_string_alloc(arg);
1177 new->index = hosts_index++;
1178 new->flags = 0;
1179 new->next = daemon->addn_hosts;
1180 daemon->addn_hosts = new;
1181 break;
1184 case 's': /* --domain */
1185 if (strcmp (arg, "#") == 0)
1186 daemon->options |= OPT_RESOLV_DOMAIN;
1187 else
1189 comma = split(arg);
1190 if (!canonicalise_opt(arg))
1191 option = '?';
1192 else
1194 char *d = opt_string_alloc(arg);
1195 if (comma)
1197 struct cond_domain *new = safe_malloc(sizeof(struct cond_domain));
1198 unhide_metas(comma);
1199 if ((arg = split_chr(comma, '/')))
1201 int mask;
1202 if ((new->start.s_addr = inet_addr(comma)) == (in_addr_t)-1 ||
1203 !atoi_check(arg, &mask))
1204 option = '?';
1205 else
1207 mask = (1 << (32 - mask)) - 1;
1208 new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask);
1209 new->end.s_addr = new->start.s_addr | htonl(mask);
1212 else if ((arg = split(comma)))
1214 if ((new->start.s_addr = inet_addr(comma)) == (in_addr_t)-1 ||
1215 (new->end.s_addr = inet_addr(arg)) == (in_addr_t)-1)
1216 option = '?';
1218 else if ((new->start.s_addr = new->end.s_addr = inet_addr(comma)) == (in_addr_t)-1)
1219 option = '?';
1221 new->domain = d;
1222 new->next = daemon->cond_domain;
1223 daemon->cond_domain = new;
1225 else
1226 daemon->domain_suffix = d;
1229 break;
1231 case 'u': /* --user */
1232 daemon->username = opt_string_alloc(arg);
1233 break;
1235 case 'g': /* --group */
1236 daemon->groupname = opt_string_alloc(arg);
1237 daemon->group_set = 1;
1238 break;
1240 #ifdef HAVE_DHCP
1241 case LOPT_SCRIPTUSR: /* --scriptuser */
1242 daemon->scriptuser = opt_string_alloc(arg);
1243 break;
1244 #endif
1246 case 'i': /* --interface */
1247 do {
1248 struct iname *new = opt_malloc(sizeof(struct iname));
1249 comma = split(arg);
1250 new->next = daemon->if_names;
1251 daemon->if_names = new;
1252 /* new->name may be NULL if someone does
1253 "interface=" to disable all interfaces except loop. */
1254 new->name = opt_string_alloc(arg);
1255 new->isloop = new->used = 0;
1256 arg = comma;
1257 } while (arg);
1258 break;
1260 case 'I': /* --except-interface */
1261 case '2': /* --no-dhcp-interface */
1262 do {
1263 struct iname *new = opt_malloc(sizeof(struct iname));
1264 comma = split(arg);
1265 new->name = opt_string_alloc(arg);
1266 if (option == 'I')
1268 new->next = daemon->if_except;
1269 daemon->if_except = new;
1271 else
1273 new->next = daemon->dhcp_except;
1274 daemon->dhcp_except = new;
1276 arg = comma;
1277 } while (arg);
1278 break;
1280 case 'B': /* --bogus-nxdomain */
1282 struct in_addr addr;
1283 unhide_metas(arg);
1284 if (arg && (addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
1286 struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
1287 baddr->next = daemon->bogus_addr;
1288 daemon->bogus_addr = baddr;
1289 baddr->addr = addr;
1291 else
1292 option = '?'; /* error */
1293 break;
1296 case 'a': /* --listen-address */
1297 do {
1298 struct iname *new = opt_malloc(sizeof(struct iname));
1299 comma = split(arg);
1300 unhide_metas(arg);
1301 new->next = daemon->if_addrs;
1302 if (arg && (new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
1304 new->addr.sa.sa_family = AF_INET;
1305 #ifdef HAVE_SOCKADDR_SA_LEN
1306 new->addr.in.sin_len = sizeof(new->addr.in);
1307 #endif
1309 #ifdef HAVE_IPV6
1310 else if (arg && inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
1312 new->addr.sa.sa_family = AF_INET6;
1313 new->addr.in6.sin6_flowinfo = 0;
1314 new->addr.in6.sin6_scope_id = 0;
1315 #ifdef HAVE_SOCKADDR_SA_LEN
1316 new->addr.in6.sin6_len = sizeof(new->addr.in6);
1317 #endif
1319 #endif
1320 else
1322 option = '?'; /* error */
1323 break;
1326 daemon->if_addrs = new;
1327 arg = comma;
1328 } while (arg);
1329 break;
1331 case 'S': /* --server */
1332 case LOPT_LOCAL: /* --local */
1333 case 'A': /* --address */
1335 struct server *serv, *newlist = NULL;
1337 unhide_metas(arg);
1339 if (arg && *arg == '/')
1341 char *end;
1342 arg++;
1343 while ((end = split_chr(arg, '/')))
1345 char *domain = NULL;
1346 /* # matches everything and becomes a zero length domain string */
1347 if (strcmp(arg, "#") == 0)
1348 domain = "";
1349 else if (!canonicalise_opt(arg) && strlen(arg) != 0)
1350 option = '?';
1351 else
1352 domain = opt_string_alloc(arg); /* NULL if strlen is zero */
1353 serv = opt_malloc(sizeof(struct server));
1354 memset(serv, 0, sizeof(struct server));
1355 serv->next = newlist;
1356 newlist = serv;
1357 serv->domain = domain;
1358 serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
1359 arg = end;
1361 if (!newlist)
1363 option = '?';
1364 break;
1368 else
1370 newlist = opt_malloc(sizeof(struct server));
1371 memset(newlist, 0, sizeof(struct server));
1374 if (option == 'A')
1376 newlist->flags |= SERV_LITERAL_ADDRESS;
1377 if (!(newlist->flags & SERV_TYPE))
1378 option = '?';
1381 if (!arg || !*arg)
1383 newlist->flags |= SERV_NO_ADDR; /* no server */
1384 if (newlist->flags & SERV_LITERAL_ADDRESS)
1385 option = '?';
1387 else
1389 int source_port = 0, serv_port = NAMESERVER_PORT;
1390 char *portno, *source;
1392 if ((source = split_chr(arg, '@')) && /* is there a source. */
1393 (portno = split_chr(source, '#')) &&
1394 !atoi_check16(portno, &source_port))
1395 problem = _("bad port");
1397 if ((portno = split_chr(arg, '#')) && /* is there a port no. */
1398 !atoi_check16(portno, &serv_port))
1399 problem = _("bad port");
1401 if ((newlist->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1)
1403 newlist->addr.in.sin_port = htons(serv_port);
1404 newlist->source_addr.in.sin_port = htons(source_port);
1405 newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET;
1406 #ifdef HAVE_SOCKADDR_SA_LEN
1407 newlist->source_addr.in.sin_len = newlist->addr.in.sin_len = sizeof(struct sockaddr_in);
1408 #endif
1409 if (source)
1411 newlist->flags |= SERV_HAS_SOURCE;
1412 if ((newlist->source_addr.in.sin_addr.s_addr = inet_addr(source)) == (in_addr_t) -1)
1414 #if defined(SO_BINDTODEVICE)
1415 newlist->source_addr.in.sin_addr.s_addr = INADDR_ANY;
1416 strncpy(newlist->interface, source, IF_NAMESIZE);
1417 #else
1418 problem = _("interface binding not supported");
1419 #endif
1422 else
1423 newlist->source_addr.in.sin_addr.s_addr = INADDR_ANY;
1425 #ifdef HAVE_IPV6
1426 else if (inet_pton(AF_INET6, arg, &newlist->addr.in6.sin6_addr) > 0)
1428 newlist->addr.in6.sin6_port = htons(serv_port);
1429 newlist->source_addr.in6.sin6_port = htons(source_port);
1430 newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET6;
1431 #ifdef HAVE_SOCKADDR_SA_LEN
1432 newlist->addr.in6.sin6_len = newlist->source_addr.in6.sin6_len = sizeof(newlist->addr.in6);
1433 #endif
1434 if (source)
1436 newlist->flags |= SERV_HAS_SOURCE;
1437 if (inet_pton(AF_INET6, source, &newlist->source_addr.in6.sin6_addr) == 0)
1439 #if defined(SO_BINDTODEVICE)
1440 newlist->source_addr.in6.sin6_addr = in6addr_any;
1441 strncpy(newlist->interface, source, IF_NAMESIZE);
1442 #else
1443 problem = _("interface binding not supported");
1444 #endif
1447 else
1448 newlist->source_addr.in6.sin6_addr = in6addr_any;
1450 #endif
1451 else
1452 option = '?'; /* error */
1456 serv = newlist;
1457 while (serv->next)
1459 serv->next->flags = serv->flags;
1460 serv->next->addr = serv->addr;
1461 serv->next->source_addr = serv->source_addr;
1462 serv = serv->next;
1464 serv->next = daemon->servers;
1465 daemon->servers = newlist;
1466 break;
1469 case 'c': /* --cache-size */
1471 int size;
1473 if (!atoi_check(arg, &size))
1474 option = '?';
1475 else
1477 /* zero is OK, and means no caching. */
1479 if (size < 0)
1480 size = 0;
1481 else if (size > 10000)
1482 size = 10000;
1484 daemon->cachesize = size;
1486 break;
1489 case 'p': /* --port */
1490 if (!atoi_check16(arg, &daemon->port))
1491 option = '?';
1492 break;
1494 case LOPT_MINPORT: /* --min-port */
1495 if (!atoi_check16(arg, &daemon->min_port))
1496 option = '?';
1497 break;
1499 case '0': /* --dns-forward-max */
1500 if (!atoi_check(arg, &daemon->ftabsize))
1501 option = '?';
1502 break;
1504 case LOPT_MAX_LOGS: /* --log-async */
1505 daemon->max_logs = LOG_MAX; /* default */
1506 if (arg && !atoi_check(arg, &daemon->max_logs))
1507 option = '?';
1508 else if (daemon->max_logs > 100)
1509 daemon->max_logs = 100;
1510 break;
1512 case 'P': /* --edns-packet-max */
1514 int i;
1515 if (!atoi_check(arg, &i))
1516 option = '?';
1517 daemon->edns_pktsz = (unsigned short)i;
1518 break;
1521 case 'Q': /* --query-port */
1522 if (!atoi_check16(arg, &daemon->query_port))
1523 option = '?';
1524 /* if explicitly set to zero, use single OS ephemeral port
1525 and disable random ports */
1526 if (daemon->query_port == 0)
1527 daemon->osport = 1;
1528 break;
1530 case 'T': /* --local-ttl */
1531 case LOPT_NEGTTL: /* --neg-ttl */
1533 int ttl;
1534 if (!atoi_check(arg, &ttl))
1535 option = '?';
1536 else if (option == LOPT_NEGTTL)
1537 daemon->neg_ttl = (unsigned long)ttl;
1538 else
1539 daemon->local_ttl = (unsigned long)ttl;
1540 break;
1543 #ifdef HAVE_DHCP
1544 case 'X': /* --dhcp-lease-max */
1545 if (!atoi_check(arg, &daemon->dhcp_max))
1546 option = '?';
1547 break;
1548 #endif
1550 #ifdef HAVE_TFTP
1551 case LOPT_TFTP_MAX: /* --tftp-max */
1552 if (!atoi_check(arg, &daemon->tftp_max))
1553 option = '?';
1554 break;
1556 case LOPT_PREFIX: /* --tftp-prefix */
1557 daemon->tftp_prefix = opt_string_alloc(arg);
1558 break;
1560 case LOPT_TFTPPORTS: /* --tftp-port-range */
1561 if (!(comma = split(arg)) ||
1562 !atoi_check16(arg, &daemon->start_tftp_port) ||
1563 !atoi_check16(comma, &daemon->end_tftp_port))
1564 problem = _("bad port range");
1566 if (daemon->start_tftp_port > daemon->end_tftp_port)
1568 int tmp = daemon->start_tftp_port;
1569 daemon->start_tftp_port = daemon->end_tftp_port;
1570 daemon->end_tftp_port = tmp;
1573 break;
1574 #endif
1576 case LOPT_BRIDGE: /* --bridge-interface */
1578 struct dhcp_bridge *new = opt_malloc(sizeof(struct dhcp_bridge));
1579 if (!(comma = split(arg)))
1581 problem = _("bad bridge-interface");
1582 break;
1585 strncpy(new->iface, arg, IF_NAMESIZE);
1586 new->alias = NULL;
1587 new->next = daemon->bridges;
1588 daemon->bridges = new;
1590 do {
1591 arg = comma;
1592 comma = split(arg);
1593 if (strlen(arg) != 0)
1595 struct dhcp_bridge *b = opt_malloc(sizeof(struct dhcp_bridge));
1596 b->next = new->alias;
1597 new->alias = b;
1598 strncpy(b->iface, arg, IF_NAMESIZE);
1600 } while (comma);
1602 break;
1605 #ifdef HAVE_DHCP
1606 case 'F': /* --dhcp-range */
1608 int k, leasepos = 2;
1609 char *cp, *a[5] = { NULL, NULL, NULL, NULL, NULL };
1610 struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
1612 new->next = daemon->dhcp;
1613 new->lease_time = DEFLEASE;
1614 new->addr_epoch = 0;
1615 new->netmask.s_addr = 0;
1616 new->broadcast.s_addr = 0;
1617 new->router.s_addr = 0;
1618 new->netid.net = NULL;
1619 new->filter = NULL;
1620 new->flags = 0;
1622 gen_prob = _("bad dhcp-range");
1624 if (!arg)
1626 option = '?';
1627 break;
1630 while(1)
1632 for (cp = arg; *cp; cp++)
1633 if (!(*cp == ' ' || *cp == '.' || (*cp >='0' && *cp <= '9')))
1634 break;
1636 if (*cp != ',' && (comma = split(arg)))
1638 if (strstr(arg, "net:") == arg)
1640 struct dhcp_netid *tt = opt_malloc(sizeof (struct dhcp_netid));
1641 tt->net = opt_string_alloc(arg+4);
1642 tt->next = new->filter;
1643 new->filter = tt;
1645 else
1647 if (new->netid.net)
1648 problem = _("only one netid tag allowed");
1649 else
1650 new->netid.net = opt_string_alloc(arg);
1652 arg = comma;
1654 else
1656 a[0] = arg;
1657 break;
1661 for (k = 1; k < 5; k++)
1662 if (!(a[k] = split(a[k-1])))
1663 break;
1665 if (option == '?' || (k < 2) || ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1))
1666 option = '?';
1667 else if (strcmp(a[1], "static") == 0)
1669 new->end = new->start;
1670 new->flags |= CONTEXT_STATIC;
1672 else if (strcmp(a[1], "proxy") == 0)
1674 new->end = new->start;
1675 new->flags |= CONTEXT_PROXY;
1677 else if ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1)
1678 option = '?';
1680 if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
1682 struct in_addr tmp = new->start;
1683 new->start = new->end;
1684 new->end = tmp;
1687 if (option != '?' && k >= 3 && strchr(a[2], '.') &&
1688 ((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
1690 new->flags |= CONTEXT_NETMASK;
1691 leasepos = 3;
1692 if (!is_same_net(new->start, new->end, new->netmask))
1693 problem = _("inconsistent DHCP range");
1695 daemon->dhcp = new;
1697 if (k >= 4 && strchr(a[3], '.') &&
1698 ((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1))
1700 new->flags |= CONTEXT_BRDCAST;
1701 leasepos = 4;
1704 if (k >= leasepos+1)
1706 if (strcmp(a[leasepos], "infinite") == 0)
1707 new->lease_time = 0xffffffff;
1708 else
1710 int fac = 1;
1711 if (strlen(a[leasepos]) > 0)
1713 switch (a[leasepos][strlen(a[leasepos]) - 1])
1715 case 'd':
1716 case 'D':
1717 fac *= 24;
1718 /* fall though */
1719 case 'h':
1720 case 'H':
1721 fac *= 60;
1722 /* fall through */
1723 case 'm':
1724 case 'M':
1725 fac *= 60;
1726 /* fall through */
1727 case 's':
1728 case 'S':
1729 a[leasepos][strlen(a[leasepos]) - 1] = 0;
1732 new->lease_time = atoi(a[leasepos]) * fac;
1733 /* Leases of a minute or less confuse
1734 some clients, notably Apple's */
1735 if (new->lease_time < 120)
1736 new->lease_time = 120;
1740 break;
1743 case LOPT_BANK:
1744 case 'G': /* --dhcp-host */
1746 int j, k = 0;
1747 char *a[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
1748 struct dhcp_config *new;
1749 struct in_addr in;
1751 new = opt_malloc(sizeof(struct dhcp_config));
1753 new->next = daemon->dhcp_conf;
1754 new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
1755 new->hwaddr = NULL;
1757 if ((a[0] = arg))
1758 for (k = 1; k < 6; k++)
1759 if (!(a[k] = split(a[k-1])))
1760 break;
1762 for (j = 0; j < k; j++)
1763 if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
1765 char *arg = a[j];
1767 if ((arg[0] == 'i' || arg[0] == 'I') &&
1768 (arg[1] == 'd' || arg[1] == 'D') &&
1769 arg[2] == ':')
1771 if (arg[3] == '*')
1772 new->flags |= CONFIG_NOCLID;
1773 else
1775 int len;
1776 arg += 3; /* dump id: */
1777 if (strchr(arg, ':'))
1778 len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
1779 else
1781 unhide_metas(arg);
1782 len = (int) strlen(arg);
1785 if ((new->clid = opt_malloc(len)))
1787 new->flags |= CONFIG_CLID;
1788 new->clid_len = len;
1789 memcpy(new->clid, arg, len);
1793 else if (strstr(arg, "net:") == arg)
1795 int len = strlen(arg + 4) + 1;
1796 if ((new->netid.net = opt_malloc(len)))
1798 new->flags |= CONFIG_NETID;
1799 strcpy(new->netid.net, arg+4);
1800 unhide_metas(new->netid.net);
1803 else
1805 struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
1806 newhw->next = new->hwaddr;
1807 new->hwaddr = newhw;
1808 newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
1809 &newhw->wildcard_mask, &newhw->hwaddr_type);
1812 else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1)
1814 new->addr = in;
1815 new->flags |= CONFIG_ADDR;
1817 else
1819 char *cp, *lastp = NULL, last = 0;
1820 int fac = 1;
1822 if (strlen(a[j]) > 1)
1824 lastp = a[j] + strlen(a[j]) - 1;
1825 last = *lastp;
1826 switch (last)
1828 case 'd':
1829 case 'D':
1830 fac *= 24;
1831 /* fall through */
1832 case 'h':
1833 case 'H':
1834 fac *= 60;
1835 /* fall through */
1836 case 'm':
1837 case 'M':
1838 fac *= 60;
1839 /* fall through */
1840 case 's':
1841 case 'S':
1842 *lastp = 0;
1846 for (cp = a[j]; *cp; cp++)
1847 if (!isdigit((int)*cp) && *cp != ' ')
1848 break;
1850 if (*cp)
1852 if (lastp)
1853 *lastp = last;
1854 if (strcmp(a[j], "infinite") == 0)
1856 new->lease_time = 0xffffffff;
1857 new->flags |= CONFIG_TIME;
1859 else if (strcmp(a[j], "ignore") == 0)
1860 new->flags |= CONFIG_DISABLE;
1861 else
1863 int len = strlen(a[j]) + 1;
1864 if (!canonicalise_opt(a[j]))
1865 problem = _("bad DHCP host name");
1866 else if ((new->hostname = opt_malloc(len)))
1868 new->flags |= CONFIG_NAME;
1869 strcpy(new->hostname, a[j]);
1870 new->domain = NULL;
1874 else
1876 new->lease_time = atoi(a[j]) * fac;
1877 /* Leases of a minute or less confuse
1878 some clients, notably Apple's */
1879 if (new->lease_time < 120)
1880 new->lease_time = 120;
1881 new->flags |= CONFIG_TIME;
1885 daemon->dhcp_conf = new;
1886 break;
1889 case 'O': /* --dhcp-option */
1890 case LOPT_FORCE: /* --dhcp-option-force */
1891 case LOPT_OPTS:
1892 case LOPT_MATCH: /* --dhcp-match */
1893 problem = parse_dhcp_opt(arg,
1894 option == LOPT_FORCE ? DHOPT_FORCE :
1895 (option == LOPT_MATCH ? DHOPT_MATCH :
1896 (option == LOPT_OPTS ? DHOPT_BANK : 0)));
1897 break;
1899 case 'M': /* --dhcp-boot */
1901 struct dhcp_netid *id = NULL;
1902 while (arg && strstr(arg, "net:") == arg)
1904 struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
1905 newid->next = id;
1906 id = newid;
1907 comma = split(arg);
1908 newid->net = opt_string_alloc(arg+4);
1909 arg = comma;
1912 if (!arg)
1913 option = '?';
1914 else
1916 char *dhcp_file, *dhcp_sname = NULL;
1917 struct in_addr dhcp_next_server;
1918 comma = split(arg);
1919 dhcp_file = opt_string_alloc(arg);
1920 dhcp_next_server.s_addr = 0;
1921 if (comma)
1923 arg = comma;
1924 comma = split(arg);
1925 dhcp_sname = opt_string_alloc(arg);
1926 if (comma)
1928 unhide_metas(comma);
1929 if ((dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
1930 option = '?';
1933 if (option != '?')
1935 struct dhcp_boot *new = opt_malloc(sizeof(struct dhcp_boot));
1936 new->file = dhcp_file;
1937 new->sname = dhcp_sname;
1938 new->next_server = dhcp_next_server;
1939 new->netid = id;
1940 new->next = daemon->boot_config;
1941 daemon->boot_config = new;
1945 break;
1948 case LOPT_PXE_PROMT: /* --pxe-prompt */
1950 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
1951 int timeout;
1953 new->netid = NULL;
1954 new->opt = 10; /* PXE_MENU_PROMPT */
1956 while (arg && strstr(arg, "net:") == arg)
1958 struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
1959 comma = split(arg);
1960 nn->next = new->netid;
1961 new->netid = nn;
1962 nn->net = opt_string_alloc(arg+4);
1963 arg = comma;
1966 if (!arg)
1967 option = '?';
1968 else
1970 comma = split(arg);
1971 unhide_metas(arg);
1972 new->len = strlen(arg) + 1;
1973 new->val = opt_malloc(new->len);
1974 memcpy(new->val + 1, arg, new->len - 1);
1976 new->u.vendor_class = (unsigned char *)"PXEClient";
1977 new->flags = DHOPT_VENDOR;
1979 if (comma && atoi_check(comma, &timeout))
1980 *(new->val) = timeout;
1981 else
1982 *(new->val) = 255;
1984 new->next = daemon->dhcp_opts;
1985 daemon->dhcp_opts = new;
1988 break;
1991 case LOPT_PXE_SERV: /* --pxe-service */
1993 struct pxe_service *new = opt_malloc(sizeof(struct pxe_service));
1994 char *CSA[] = { "x86PC", "PC98", "IA64_EFI", "Alpha", "Arc_x86", "Intel_Lean_Client",
1995 "IA32_EFI", "BC_EFI", "Xscale_EFI", "x86-64_EFI", NULL };
1996 static int boottype = 32768;
1998 new->netid = NULL;
1999 new->server.s_addr = 0;
2001 while (arg && strstr(arg, "net:") == arg)
2003 struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
2004 comma = split(arg);
2005 nn->next = new->netid;
2006 new->netid = nn;
2007 nn->net = opt_string_alloc(arg+4);
2008 arg = comma;
2011 if (arg && (comma = split(arg)))
2013 for (i = 0; CSA[i]; i++)
2014 if (strcasecmp(CSA[i], arg) == 0)
2015 break;
2017 if (CSA[i] || atoi_check(arg, &i))
2019 arg = comma;
2020 comma = split(arg);
2022 new->CSA = i;
2023 new->menu = opt_string_alloc(arg);
2025 if (comma)
2027 arg = comma;
2028 comma = split(arg);
2029 if (atoi_check(arg, &i))
2031 new->type = i;
2032 new->basename = NULL;
2034 else
2036 new->type = boottype++;
2037 new->basename = opt_string_alloc(arg);
2040 if (comma && (new->server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
2041 option = '?';
2043 /* Order matters */
2044 new->next = NULL;
2045 if (!daemon->pxe_services)
2046 daemon->pxe_services = new;
2047 else
2049 struct pxe_service *s;
2050 for (s = daemon->pxe_services; s->next; s = s->next);
2051 s->next = new;
2054 break;
2059 option = '?';
2060 break;
2063 case '4': /* --dhcp-mac */
2065 if (!(comma = split(arg)))
2066 option = '?';
2067 else
2069 struct dhcp_mac *new = opt_malloc(sizeof(struct dhcp_mac));
2070 if (strstr(arg, "net:") == arg)
2071 new->netid.net = opt_string_alloc(arg+4);
2072 else
2073 new->netid.net = opt_string_alloc(arg);
2074 unhide_metas(comma);
2075 new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
2076 new->next = daemon->dhcp_macs;
2077 daemon->dhcp_macs = new;
2080 break;
2082 case 'U': /* --dhcp-vendorclass */
2083 case 'j': /* --dhcp-userclass */
2084 case LOPT_CIRCUIT: /* --dhcp-circuitid */
2085 case LOPT_REMOTE: /* --dhcp-remoteid */
2086 case LOPT_SUBSCR: /* --dhcp-subscrid */
2088 if (!(comma = split(arg)))
2089 option = '?';
2090 else
2092 char *p;
2093 int dig = 0;
2094 struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
2095 if (strstr(arg, "net:") == arg)
2096 new->netid.net = opt_string_alloc(arg+4);
2097 else
2098 new->netid.net = opt_string_alloc(arg);
2099 /* check for hex string - must digits may include : must not have nothing else,
2100 only allowed for agent-options. */
2101 for (p = comma; *p; p++)
2102 if (isxdigit((int)*p))
2103 dig = 1;
2104 else if (*p != ':')
2105 break;
2106 unhide_metas(comma);
2107 if (option == 'U' || option == 'j' || *p || !dig)
2109 new->len = strlen(comma);
2110 new->data = opt_malloc(new->len);
2111 memcpy(new->data, comma, new->len);
2113 else
2115 new->len = parse_hex(comma, (unsigned char *)comma, strlen(comma), NULL, NULL);
2116 new->data = opt_malloc(new->len);
2117 memcpy(new->data, comma, new->len);
2120 switch (option)
2122 case 'j':
2123 new->match_type = MATCH_USER;
2124 break;
2125 case 'U':
2126 new->match_type = MATCH_VENDOR;
2127 break;
2128 case LOPT_CIRCUIT:
2129 new->match_type = MATCH_CIRCUIT;
2130 break;
2131 case LOPT_REMOTE:
2132 new->match_type = MATCH_REMOTE;
2133 break;
2134 case LOPT_SUBSCR:
2135 new->match_type = MATCH_SUBSCRIBER;
2136 break;
2138 new->next = daemon->dhcp_vendors;
2139 daemon->dhcp_vendors = new;
2141 break;
2144 case LOPT_ALTPORT: /* --dhcp-alternate-port */
2145 if (!arg)
2147 daemon->dhcp_server_port = DHCP_SERVER_ALTPORT;
2148 daemon->dhcp_client_port = DHCP_CLIENT_ALTPORT;
2150 else
2152 comma = split(arg);
2153 if (!atoi_check16(arg, &daemon->dhcp_server_port) ||
2154 (comma && !atoi_check16(comma, &daemon->dhcp_client_port)))
2155 problem = _("invalid port number");
2156 if (!comma)
2157 daemon->dhcp_client_port = daemon->dhcp_server_port+1;
2159 break;
2161 case 'J': /* --dhcp-ignore */
2162 case LOPT_NO_NAMES: /* --dhcp-ignore-names */
2163 case LOPT_BROADCAST: /* --dhcp-broadcast */
2164 case '3': /* --bootp-dynamic */
2166 struct dhcp_netid_list *new = opt_malloc(sizeof(struct dhcp_netid_list));
2167 struct dhcp_netid *list = NULL;
2168 if (option == 'J')
2170 new->next = daemon->dhcp_ignore;
2171 daemon->dhcp_ignore = new;
2173 else if (option == LOPT_BROADCAST)
2175 new->next = daemon->force_broadcast;
2176 daemon->force_broadcast = new;
2178 else if (option == '3')
2180 new->next = daemon->bootp_dynamic;
2181 daemon->bootp_dynamic = new;
2183 else
2185 new->next = daemon->dhcp_ignore_names;
2186 daemon->dhcp_ignore_names = new;
2189 while (arg) {
2190 struct dhcp_netid *member = opt_malloc(sizeof(struct dhcp_netid));
2191 comma = split(arg);
2192 member->next = list;
2193 list = member;
2194 if (strstr(arg, "net:") == arg)
2195 member->net = opt_string_alloc(arg+4);
2196 else
2197 member->net = opt_string_alloc(arg);
2198 arg = comma;
2201 new->list = list;
2202 break;
2204 #endif
2206 case 'V': /* --alias */
2208 char *dash, *a[3] = { NULL, NULL, NULL };
2209 int k = 0;
2210 struct doctor *new = opt_malloc(sizeof(struct doctor));
2211 new->next = daemon->doctors;
2212 daemon->doctors = new;
2213 new->mask.s_addr = 0xffffffff;
2214 new->end.s_addr = 0;
2216 if ((a[0] = arg))
2217 for (k = 1; k < 3; k++)
2219 if (!(a[k] = split(a[k-1])))
2220 break;
2221 unhide_metas(a[k]);
2224 dash = split_chr(a[0], '-');
2226 if ((k < 2) ||
2227 ((new->in.s_addr = inet_addr(a[0])) == (in_addr_t)-1) ||
2228 ((new->out.s_addr = inet_addr(a[1])) == (in_addr_t)-1))
2229 option = '?';
2231 if (k == 3)
2232 new->mask.s_addr = inet_addr(a[2]);
2234 if (dash &&
2235 ((new->end.s_addr = inet_addr(dash)) == (in_addr_t)-1 ||
2236 !is_same_net(new->in, new->end, new->mask) ||
2237 ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
2238 problem = _("invalid alias range");
2240 break;
2243 case LOPT_INTNAME: /* --interface-name */
2245 struct interface_name *new, **up;
2247 comma = split(arg);
2249 if (!comma || !canonicalise_opt(arg))
2250 problem = _("bad interface name");
2252 new = opt_malloc(sizeof(struct interface_name));
2253 new->next = NULL;
2254 /* Add to the end of the list, so that first name
2255 of an interface is used for PTR lookups. */
2256 for (up = &daemon->int_names; *up; up = &((*up)->next));
2257 *up = new;
2258 new->name = opt_string_alloc(arg);
2259 new->intr = opt_string_alloc(comma);
2260 break;
2263 case LOPT_CNAME: /* --cname */
2265 struct cname *new;
2267 if (!(comma = split(arg)))
2268 option = '?';
2269 else
2271 for (new = daemon->cnames; new; new = new->next)
2272 if (hostname_isequal(new->alias, arg))
2273 problem = _("duplicate CNAME");
2274 new = opt_malloc(sizeof(struct cname));
2275 new->next = daemon->cnames;
2276 daemon->cnames = new;
2277 new->alias = opt_string_alloc(arg);
2278 new->target = opt_string_alloc(comma);
2280 break;
2283 case LOPT_PTR: /* --ptr-record */
2285 struct ptr_record *new;
2287 comma = split(arg);
2289 if (!canonicalise_opt(arg))
2290 problem = _("bad PTR record");
2292 new = opt_malloc(sizeof(struct ptr_record));
2293 new->next = daemon->ptr;
2294 daemon->ptr = new;
2295 new->name = opt_string_alloc(arg);
2296 new->ptr = NULL;
2297 if (comma)
2298 new->ptr = opt_string_alloc(comma);
2299 break;
2302 case LOPT_NAPTR: /* --naptr-record */
2304 char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
2305 int k = 0;
2306 struct naptr *new;
2307 int order, pref;
2309 if ((a[0] = arg))
2310 for (k = 1; k < 7; k++)
2311 if (!(a[k] = split(a[k-1])))
2312 break;
2315 if (k < 6 ||
2316 !canonicalise_opt(a[0]) ||
2317 !atoi_check16(a[1], &order) ||
2318 !atoi_check16(a[2], &pref) ||
2319 (k == 7 && !canonicalise_opt(a[6])))
2320 problem = _("bad NAPTR record");
2321 else
2323 new = opt_malloc(sizeof(struct naptr));
2324 new->next = daemon->naptr;
2325 daemon->naptr = new;
2326 new->name = opt_string_alloc(a[0]);
2327 new->flags = opt_string_alloc(a[3]);
2328 new->services = opt_string_alloc(a[4]);
2329 new->regexp = opt_string_alloc(a[5]);
2330 if (k == 7)
2331 new->replace = opt_string_alloc(a[6]);
2332 new->order = order;
2333 new->pref = pref;
2335 break;
2338 case 'Y': /* --txt-record */
2340 struct txt_record *new;
2341 unsigned char *p, *q;
2343 if ((comma = split(arg)))
2344 comma--;
2346 gen_prob = _("TXT record string too long");
2348 if (!canonicalise_opt(arg))
2350 problem = _("bad TXT record");
2351 break;
2354 if ((q = (unsigned char *)comma))
2355 while (1)
2357 size_t len;
2358 if ((p = (unsigned char *)strchr((char*)q+1, ',')))
2360 if ((len = p - q - 1) > 255)
2361 option = '?';
2362 *q = len;
2363 for (q = q+1; q < p; q++)
2364 *q = unhide_meta(*q);
2366 else
2368 if ((len = strlen((char *)q+1)) > 255)
2369 option = '?';
2370 *q = len;
2371 for (q = q+1; *q; q++)
2372 *q = unhide_meta(*q);
2373 break;
2377 new = opt_malloc(sizeof(struct txt_record));
2378 new->next = daemon->txt;
2379 daemon->txt = new;
2380 new->class = C_IN;
2381 if (comma)
2383 new->len = q - ((unsigned char *)comma);
2384 new->txt = opt_malloc(new->len);
2385 memcpy(new->txt, comma, new->len);
2387 else
2389 static char empty[] = "";
2390 new->len = 1;
2391 new->txt = empty;
2394 /* ensure arg is terminated */
2395 if (comma)
2396 *comma = 0;
2397 new->name = opt_string_alloc(arg);
2398 break;
2401 case 'W': /* --srv-host */
2403 int port = 1, priority = 0, weight = 0;
2404 char *name, *target = NULL;
2405 struct mx_srv_record *new;
2407 comma = split(arg);
2409 if (!canonicalise_opt(arg))
2410 problem = _("bad SRV record");
2412 name = opt_string_alloc(arg);
2414 if (comma)
2416 arg = comma;
2417 comma = split(arg);
2418 if (!canonicalise_opt(arg))
2419 problem = _("bad SRV target");
2421 target = opt_string_alloc(arg);
2422 if (comma)
2424 arg = comma;
2425 comma = split(arg);
2426 if (!atoi_check16(arg, &port))
2427 problem = _("invalid port number");
2429 if (comma)
2431 arg = comma;
2432 comma = split(arg);
2433 if (!atoi_check16(arg, &priority))
2434 problem = _("invalid priority");
2436 if (comma)
2438 arg = comma;
2439 comma = split(arg);
2440 if (!atoi_check16(arg, &weight))
2441 problem = _("invalid weight");
2447 new = opt_malloc(sizeof(struct mx_srv_record));
2448 new->next = daemon->mxnames;
2449 daemon->mxnames = new;
2450 new->issrv = 1;
2451 new->name = name;
2452 new->target = target;
2453 new->srvport = port;
2454 new->priority = priority;
2455 new->weight = weight;
2456 break;
2459 default:
2460 return _("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DBus support)");
2464 if (problem)
2465 return problem;
2467 if (option == '?')
2468 return gen_prob;
2470 return NULL;
2473 static void one_file(char *file, int nest, int hard_opt)
2475 volatile int lineno = 0;
2476 int i, option;
2477 FILE *f;
2478 char *p, *arg, *start, *buff = daemon->namebuff;
2479 static struct fileread {
2480 dev_t dev;
2481 ino_t ino;
2482 struct fileread *next;
2483 } *filesread = NULL;
2484 struct stat statbuf;
2486 /* ignore repeated files. */
2487 if (hard_opt == 0 && stat(file, &statbuf) == 0)
2489 struct fileread *r;
2491 for (r = filesread; r; r = r->next)
2492 if (r->dev == statbuf.st_dev && r->ino == statbuf.st_ino)
2493 return;
2495 r = safe_malloc(sizeof(struct fileread));
2496 r->next = filesread;
2497 filesread = r;
2498 r->dev = statbuf.st_dev;
2499 r->ino = statbuf.st_ino;
2502 if (nest > 20)
2503 die(_("files nested too deep in %s"), file, EC_BADCONF);
2505 if (!(f = fopen(file, "r")))
2507 if (errno == ENOENT && nest == 0)
2508 return; /* No conffile, all done. */
2509 else
2511 char *str = _("cannot read %s: %s");
2512 if (hard_opt != 0)
2514 my_syslog(LOG_ERR, str, file, strerror(errno));
2515 return;
2517 else
2518 die(str, file, EC_FILE);
2522 while (fgets(buff, MAXDNAME, f))
2524 int white;
2525 unsigned int lastquote;
2526 char *errmess;
2528 /* Memory allocation failure longjmps here if mem_recover == 1 */
2529 if (hard_opt)
2531 if (setjmp(mem_jmp))
2532 continue;
2533 mem_recover = 1;
2536 lineno++;
2537 errmess = NULL;
2539 /* Implement quotes, inside quotes we allow \\ \" \n and \t
2540 metacharacters get hidden also strip comments */
2542 for (white = 1, lastquote = 0, p = buff; *p; p++)
2544 if (*p == '"')
2546 memmove(p, p+1, strlen(p+1)+1);
2547 for(; *p && *p != '"'; p++)
2549 if (*p == '\\' && strchr("\"tnebr\\", p[1]))
2551 if (p[1] == 't')
2552 p[1] = '\t';
2553 else if (p[1] == 'n')
2554 p[1] = '\n';
2555 else if (p[1] == 'b')
2556 p[1] = '\b';
2557 else if (p[1] == 'r')
2558 p[1] = '\r';
2559 else if (p[1] == 'e') /* escape */
2560 p[1] = '\033';
2561 memmove(p, p+1, strlen(p+1)+1);
2563 *p = hide_meta(*p);
2565 if (*p == '"')
2567 memmove(p, p+1, strlen(p+1)+1);
2568 lastquote = p - buff;
2570 else
2572 errmess = _("missing \"");
2573 goto oops;
2577 if (white && *p == '#')
2579 *p = 0;
2580 break;
2582 white = isspace((int)unhide_meta(*p));
2585 /* fgets gets end of line char too. */
2586 while (strlen(buff) > lastquote && isspace((int)unhide_meta(buff[strlen(buff)-1])))
2587 buff[strlen(buff)-1] = 0;
2589 if (*buff == 0)
2590 continue;
2592 if (hard_opt != 0)
2593 arg = buff;
2594 else if ((p=strchr(buff, '=')))
2596 /* allow spaces around "=" */
2597 arg = p+1;
2598 for (; p >= buff && (isspace((int)*p) || *p == '='); p--)
2599 *p = 0;
2601 else
2602 arg = NULL;
2604 if (hard_opt != 0)
2605 option = hard_opt;
2606 else
2608 /* skip leading space */
2609 for (start = buff; *start && isspace((int)*start); start++);
2611 for (option = 0, i = 0; opts[i].name; i++)
2612 if (strcmp(opts[i].name, start) == 0)
2614 option = opts[i].val;
2615 break;
2618 if (!option)
2619 errmess = _("bad option");
2620 else if (opts[i].has_arg == 0 && arg)
2621 errmess = _("extraneous parameter");
2622 else if (opts[i].has_arg == 1 && !arg)
2623 errmess = _("missing parameter");
2626 if (!errmess)
2628 if (arg)
2629 for (; isspace((int)*arg); arg++);
2631 errmess = one_opt(option, arg, _("error"), nest + 1);
2634 if (errmess)
2636 oops:
2637 sprintf(buff, _("%s at line %d of %%s"), errmess, lineno);
2638 if (hard_opt != 0)
2639 my_syslog(LOG_ERR, buff, file);
2640 else
2641 die(buff, file, EC_BADCONF);
2645 mem_recover = 1;
2646 fclose(f);
2649 #ifdef HAVE_DHCP
2650 void reread_dhcp(void)
2652 if (daemon->dhcp_hosts_file)
2654 struct dhcp_config *configs, *cp, **up;
2656 /* remove existing... */
2657 for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
2659 cp = configs->next;
2661 if (configs->flags & CONFIG_BANK)
2663 struct hwaddr_config *mac, *tmp;
2665 for (mac = configs->hwaddr; mac; mac = tmp)
2667 tmp = mac->next;
2668 free(mac);
2670 if (configs->flags & CONFIG_CLID)
2671 free(configs->clid);
2672 if (configs->flags & CONFIG_NETID)
2673 free(configs->netid.net);
2674 if (configs->flags & CONFIG_NAME)
2675 free(configs->hostname);
2678 *up = configs->next;
2679 free(configs);
2681 else
2682 up = &configs->next;
2685 one_file(daemon->dhcp_hosts_file, 1, LOPT_BANK);
2686 my_syslog(LOG_INFO, _("read %s"), daemon->dhcp_hosts_file);
2689 if (daemon->dhcp_opts_file)
2691 struct dhcp_opt *opts, *cp, **up;
2692 struct dhcp_netid *id, *next;
2694 for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
2696 cp = opts->next;
2698 if (opts->flags & DHOPT_BANK)
2700 if ((opts->flags & DHOPT_VENDOR))
2701 free(opts->u.vendor_class);
2702 free(opts->val);
2703 for (id = opts->netid; id; id = next)
2705 next = id->next;
2706 free(id->net);
2707 free(id);
2709 *up = opts->next;
2710 free(opts);
2712 else
2713 up = &opts->next;
2716 one_file(daemon->dhcp_opts_file, 1, LOPT_OPTS);
2717 my_syslog(LOG_INFO, _("read %s"), daemon->dhcp_opts_file);
2720 #endif
2722 void read_opts(int argc, char **argv, char *compile_opts)
2724 char *buff = opt_malloc(MAXDNAME);
2725 int option, nest = 0, testmode = 0;
2726 char *errmess, *arg, *conffile = CONFFILE;
2728 opterr = 0;
2730 daemon = opt_malloc(sizeof(struct daemon));
2731 memset(daemon, 0, sizeof(struct daemon));
2732 daemon->namebuff = buff;
2734 /* Set defaults - everything else is zero or NULL */
2735 daemon->cachesize = CACHESIZ;
2736 daemon->ftabsize = FTABSIZ;
2737 daemon->port = NAMESERVER_PORT;
2738 daemon->dhcp_client_port = DHCP_CLIENT_PORT;
2739 daemon->dhcp_server_port = DHCP_SERVER_PORT;
2740 daemon->default_resolv.is_default = 1;
2741 daemon->default_resolv.name = RESOLVFILE;
2742 daemon->resolv_files = &daemon->default_resolv;
2743 daemon->username = CHUSER;
2744 daemon->runfile = RUNFILE;
2745 daemon->dhcp_max = MAXLEASES;
2746 daemon->tftp_max = TFTP_MAX_CONNECTIONS;
2747 daemon->edns_pktsz = EDNS_PKTSZ;
2748 daemon->log_fac = -1;
2749 add_txt("version.bind", "dnsmasq-" VERSION );
2750 add_txt("authors.bind", "Simon Kelley");
2751 add_txt("copyright.bind", COPYRIGHT);
2753 while (1)
2755 #ifdef HAVE_GETOPT_LONG
2756 option = getopt_long(argc, argv, OPTSTRING, opts, NULL);
2757 #else
2758 option = getopt(argc, argv, OPTSTRING);
2759 #endif
2761 if (option == -1)
2762 break;
2764 /* Copy optarg so that argv doesn't get changed */
2765 if (optarg)
2767 strncpy(buff, optarg, MAXDNAME);
2768 buff[MAXDNAME-1] = 0;
2769 arg = buff;
2771 else
2772 arg = NULL;
2774 /* command-line only stuff */
2775 if (option == LOPT_TEST)
2776 testmode = 1;
2777 else if (option == 'w')
2779 if (argc != 3 || strcmp(argv[2], "dhcp") != 0)
2780 do_usage();
2781 #ifdef HAVE_DHCP
2782 else
2783 display_opts();
2784 #endif
2785 exit(0);
2787 else if (option == 'v')
2789 printf(_("Dnsmasq version %s %s\n"), VERSION, COPYRIGHT);
2790 printf(_("Compile time options %s\n\n"), compile_opts);
2791 printf(_("This software comes with ABSOLUTELY NO WARRANTY.\n"));
2792 printf(_("Dnsmasq is free software, and you are welcome to redistribute it\n"));
2793 printf(_("under the terms of the GNU General Public License, version 2 or 3.\n"));
2794 exit(0);
2796 else if (option == 'C')
2798 conffile = opt_string_alloc(arg);
2799 nest++;
2801 else
2803 #ifdef HAVE_GETOPT_LONG
2804 errmess = one_opt(option, arg, _("try --help"), 0);
2805 #else
2806 errmess = one_opt(option, arg, _("try -w"), 0);
2807 #endif
2808 if (errmess)
2809 die(_("bad command line options: %s"), errmess, EC_BADCONF);
2813 if (conffile)
2814 one_file(conffile, nest, 0);
2816 /* port might not be known when the address is parsed - fill in here */
2817 if (daemon->servers)
2819 struct server *tmp;
2820 for (tmp = daemon->servers; tmp; tmp = tmp->next)
2821 if (!(tmp->flags & SERV_HAS_SOURCE))
2823 if (tmp->source_addr.sa.sa_family == AF_INET)
2824 tmp->source_addr.in.sin_port = htons(daemon->query_port);
2825 #ifdef HAVE_IPV6
2826 else if (tmp->source_addr.sa.sa_family == AF_INET6)
2827 tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
2828 #endif
2832 if (daemon->if_addrs)
2834 struct iname *tmp;
2835 for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)
2836 if (tmp->addr.sa.sa_family == AF_INET)
2837 tmp->addr.in.sin_port = htons(daemon->port);
2838 #ifdef HAVE_IPV6
2839 else if (tmp->addr.sa.sa_family == AF_INET6)
2840 tmp->addr.in6.sin6_port = htons(daemon->port);
2841 #endif /* IPv6 */
2844 /* only one of these need be specified: the other defaults to the host-name */
2845 if ((daemon->options & OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
2847 struct mx_srv_record *mx;
2849 if (gethostname(buff, MAXDNAME) == -1)
2850 die(_("cannot get host-name: %s"), NULL, EC_MISC);
2852 for (mx = daemon->mxnames; mx; mx = mx->next)
2853 if (!mx->issrv && hostname_isequal(mx->name, buff))
2854 break;
2856 if ((daemon->mxtarget || (daemon->options & OPT_LOCALMX)) && !mx)
2858 mx = opt_malloc(sizeof(struct mx_srv_record));
2859 mx->next = daemon->mxnames;
2860 mx->issrv = 0;
2861 mx->target = NULL;
2862 mx->name = opt_string_alloc(buff);
2863 daemon->mxnames = mx;
2866 if (!daemon->mxtarget)
2867 daemon->mxtarget = opt_string_alloc(buff);
2869 for (mx = daemon->mxnames; mx; mx = mx->next)
2870 if (!mx->issrv && !mx->target)
2871 mx->target = daemon->mxtarget;
2874 if (!(daemon->options & OPT_NO_RESOLV) &&
2875 daemon->resolv_files &&
2876 daemon->resolv_files->next &&
2877 (daemon->options & OPT_NO_POLL))
2878 die(_("only one resolv.conf file allowed in no-poll mode."), NULL, EC_BADCONF);
2880 if (daemon->options & OPT_RESOLV_DOMAIN)
2882 char *line;
2883 FILE *f;
2885 if ((daemon->options & OPT_NO_RESOLV) ||
2886 !daemon->resolv_files ||
2887 (daemon->resolv_files)->next)
2888 die(_("must have exactly one resolv.conf to read domain from."), NULL, EC_BADCONF);
2890 if (!(f = fopen((daemon->resolv_files)->name, "r")))
2891 die(_("failed to read %s: %s"), (daemon->resolv_files)->name, EC_FILE);
2893 while ((line = fgets(buff, MAXDNAME, f)))
2895 char *token = strtok(line, " \t\n\r");
2897 if (!token || strcmp(token, "search") != 0)
2898 continue;
2900 if ((token = strtok(NULL, " \t\n\r")) &&
2901 canonicalise_opt(token) &&
2902 (daemon->domain_suffix = opt_string_alloc(token)))
2903 break;
2906 fclose(f);
2908 if (!daemon->domain_suffix)
2909 die(_("no search directive found in %s"), (daemon->resolv_files)->name, EC_MISC);
2912 if (daemon->domain_suffix)
2914 /* add domain for any srv record without one. */
2915 struct mx_srv_record *srv;
2917 for (srv = daemon->mxnames; srv; srv = srv->next)
2918 if (srv->issrv &&
2919 strchr(srv->name, '.') &&
2920 strchr(srv->name, '.') == strrchr(srv->name, '.'))
2922 strcpy(buff, srv->name);
2923 strcat(buff, ".");
2924 strcat(buff, daemon->domain_suffix);
2925 free(srv->name);
2926 srv->name = opt_string_alloc(buff);
2929 else if (daemon->options & OPT_DHCP_FQDN)
2930 die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
2932 if (testmode)
2934 fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
2935 exit(0);