Tomato 1.26 beta (1786)
[tomato.git] / release / src / router / dnsmasq / src / option.c
blobabea37ecf5385d83fb88d5b1d7aafc6ed0f134c3
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 { "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
410 { NULL, 0, 0 }
413 char *option_string(unsigned char opt, int *is_ip, int *is_name)
415 int i;
417 for (i = 0; opttab[i].name; i++)
418 if (opttab[i].val == opt)
420 if (is_ip)
421 *is_ip = !!(opttab[i].size & OT_ADDR_LIST);
422 if (is_name)
423 *is_name = !!(opttab[i].size & OT_NAME);
424 return opttab[i].name;
427 return NULL;
430 #endif
432 /* We hide metacharaters in quoted strings by mapping them into the ASCII control
433 character space. Note that the \0, \t \b \r \033 and \n characters are carefully placed in the
434 following sequence so that they map to themselves: it is therefore possible to call
435 unhide_metas repeatedly on string without breaking things.
436 The transformation gets undone by opt_canonicalise, atoi_check and opt_string_alloc, and a
437 couple of other places.
438 Note that space is included here so that
439 --dhcp-option=3, string
440 has five characters, whilst
441 --dhcp-option=3," string"
442 has six.
445 static const char meta[] = "\000123456 \b\t\n78\r90abcdefABCDE\033F:,.";
447 static char hide_meta(char c)
449 unsigned int i;
451 for (i = 0; i < (sizeof(meta) - 1); i++)
452 if (c == meta[i])
453 return (char)i;
455 return c;
458 static char unhide_meta(char cr)
460 unsigned int c = cr;
462 if (c < (sizeof(meta) - 1))
463 cr = meta[c];
465 return cr;
468 static void unhide_metas(char *cp)
470 if (cp)
471 for(; *cp; cp++)
472 *cp = unhide_meta(*cp);
475 static void *opt_malloc(size_t size)
477 void *ret;
479 if (mem_recover)
481 ret = whine_malloc(size);
482 if (!ret)
483 longjmp(mem_jmp, 1);
485 else
486 ret = safe_malloc(size);
488 return ret;
491 static char *opt_string_alloc(char *cp)
493 char *ret = NULL;
495 if (cp && strlen(cp) != 0)
497 ret = opt_malloc(strlen(cp)+1);
498 strcpy(ret, cp);
500 /* restore hidden metachars */
501 unhide_metas(ret);
504 return ret;
508 /* find next comma, split string with zero and eliminate spaces.
509 return start of string following comma */
511 static char *split_chr(char *s, char c)
513 char *comma, *p;
515 if (!s || !(comma = strchr(s, c)))
516 return NULL;
518 p = comma;
519 *comma = ' ';
521 for (; isspace((int)*comma); comma++);
523 for (; (p >= s) && isspace((int)*p); p--)
524 *p = 0;
526 return comma;
529 static char *split(char *s)
531 return split_chr(s, ',');
534 static char *canonicalise_opt(char *s)
536 char *ret;
537 int nomem;
539 if (!s)
540 return 0;
542 unhide_metas(s);
543 if (!(ret = canonicalise(s, &nomem)) && nomem)
545 if (mem_recover)
546 longjmp(mem_jmp, 1);
547 else
548 die(_("could not get memory"), NULL, EC_NOMEM);
551 return ret;
554 static int atoi_check(char *a, int *res)
556 char *p;
558 if (!a)
559 return 0;
561 unhide_metas(a);
563 for (p = a; *p; p++)
564 if (*p < '0' || *p > '9')
565 return 0;
567 *res = atoi(a);
568 return 1;
571 static int atoi_check16(char *a, int *res)
573 if (!(atoi_check(a, res)) ||
574 *res < 0 ||
575 *res > 0xffff)
576 return 0;
578 return 1;
581 static void add_txt(char *name, char *txt)
583 size_t len = strlen(txt);
584 struct txt_record *r = opt_malloc(sizeof(struct txt_record));
586 r->name = opt_string_alloc(name);
587 r->next = daemon->txt;
588 daemon->txt = r;
589 r->class = C_CHAOS;
590 r->txt = opt_malloc(len+1);
591 r->len = len+1;
592 *(r->txt) = len;
593 memcpy((r->txt)+1, txt, len);
596 static void do_usage(void)
598 char buff[100];
599 int i, j;
601 struct {
602 char handle;
603 int val;
604 } tab[] = {
605 { '$', CACHESIZ },
606 { '*', EDNS_PKTSZ },
607 { '&', MAXLEASES },
608 { '!', FTABSIZ },
609 { '#', TFTP_MAX_CONNECTIONS },
610 { '\0', 0 }
613 printf(_("Usage: dnsmasq [options]\n\n"));
614 #ifndef HAVE_GETOPT_LONG
615 printf(_("Use short options only on the command line.\n"));
616 #endif
617 printf(_("Valid options are:\n"));
619 for (i = 0; usage[i].opt != 0; i++)
621 char *desc = usage[i].flagdesc;
622 char *eq = "=";
624 if (!desc || *desc == '[')
625 eq = "";
627 if (!desc)
628 desc = "";
630 for ( j = 0; opts[j].name; j++)
631 if (opts[j].val == usage[i].opt)
632 break;
633 if (usage[i].opt < 256)
634 sprintf(buff, "-%c, ", usage[i].opt);
635 else
636 sprintf(buff, " ");
638 sprintf(buff+4, "--%s%s%s", opts[j].name, eq, desc);
639 printf("%-36.36s", buff);
641 if (usage[i].arg)
643 strcpy(buff, usage[i].arg);
644 for (j = 0; tab[j].handle; j++)
645 if (tab[j].handle == *(usage[i].arg))
646 sprintf(buff, "%d", tab[j].val);
648 printf(_(usage[i].desc), buff);
649 printf("\n");
653 #ifdef HAVE_DHCP
654 static void display_opts(void)
656 int i;
658 printf(_("Known DHCP options:\n"));
660 for (i = 0; opttab[i].name; i++)
661 if (!(opttab[i].size & OT_INTERNAL))
662 printf("%3d %s\n", opttab[i].val, opttab[i].name);
665 /* This is too insanely large to keep in-line in the switch */
666 static char *parse_dhcp_opt(char *arg, int flags)
668 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
669 char lenchar = 0, *cp;
670 int i, addrs, digs, is_addr, is_hex, is_dec, is_string, dots;
671 char *comma = NULL, *problem = NULL;
672 struct dhcp_netid *np = NULL;
673 unsigned char opt_len = 0;
675 new->len = 0;
676 new->flags = flags;
677 new->netid = NULL;
678 new->val = NULL;
679 new->opt = 0;
681 while (arg)
683 comma = split(arg);
685 for (cp = arg; *cp; cp++)
686 if (*cp < '0' || *cp > '9')
687 break;
689 if (!*cp)
691 new->opt = atoi(arg);
692 opt_len = 0;
693 break;
696 if (strstr(arg, "option:") == arg)
698 for (i = 0; opttab[i].name; i++)
699 if (!(opttab[i].size & OT_INTERNAL) &&
700 strcasecmp(opttab[i].name, arg+7) == 0)
702 new->opt = opttab[i].val;
703 opt_len = opttab[i].size;
704 break;
706 /* option:<optname> must follow tag and vendor string. */
707 break;
709 else if (strstr(arg, "vendor:") == arg)
711 new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7);
712 new->flags |= DHOPT_VENDOR;
714 else if (strstr(arg, "encap:") == arg)
716 new->u.encap = atoi(arg+6);
717 new->flags |= DHOPT_ENCAPSULATE;
719 else
721 new->netid = opt_malloc(sizeof (struct dhcp_netid));
722 /* allow optional "net:" for consistency */
723 if (strstr(arg, "net:") == arg)
724 new->netid->net = opt_string_alloc(arg+4);
725 else
726 new->netid->net = opt_string_alloc(arg);
727 new->netid->next = np;
728 np = new->netid;
731 arg = comma;
734 if (new->opt == 0)
735 problem = _("bad dhcp-option");
736 else if (comma)
738 /* characterise the value */
739 char c;
740 is_addr = is_hex = is_dec = is_string = 1;
741 addrs = digs = 1;
742 dots = 0;
743 for (cp = comma; (c = *cp); cp++)
744 if (c == ',')
746 addrs++;
747 is_dec = is_hex = 0;
749 else if (c == ':')
751 digs++;
752 is_dec = is_addr = 0;
754 else if (c == '/')
756 is_dec = is_hex = 0;
757 if (cp == comma) /* leading / means a pathname */
758 is_addr = 0;
760 else if (c == '.')
762 is_dec = is_hex = 0;
763 dots++;
765 else if (c == '-')
766 is_hex = is_addr = 0;
767 else if (c == ' ')
768 is_dec = is_hex = 0;
769 else if (!(c >='0' && c <= '9'))
771 is_addr = 0;
772 if (cp[1] == 0 && is_dec &&
773 (c == 'b' || c == 's' || c == 'i'))
775 lenchar = c;
776 *cp = 0;
778 else
779 is_dec = 0;
780 if (!((c >='A' && c <= 'F') ||
781 (c >='a' && c <= 'f') ||
782 (c == '*' && (flags & DHOPT_MATCH))))
783 is_hex = 0;
786 /* We know that some options take addresses */
788 if (opt_len & OT_ADDR_LIST)
790 is_string = is_dec = is_hex = 0;
791 if (!is_addr || dots == 0)
792 problem = _("bad IP address");
795 if (is_hex && digs > 1)
797 new->len = digs;
798 new->val = opt_malloc(new->len);
799 parse_hex(comma, new->val, digs, (flags & DHOPT_MATCH) ? &new->u.wildcard_mask : NULL, NULL);
800 new->flags |= DHOPT_HEX;
802 else if (is_dec)
804 int i, val = atoi(comma);
805 /* assume numeric arg is 1 byte except for
806 options where it is known otherwise.
807 For vendor class option, we have to hack. */
808 if (opt_len != 0)
809 new->len = opt_len;
810 else if (val & 0xffff0000)
811 new->len = 4;
812 else if (val & 0xff00)
813 new->len = 2;
814 else
815 new->len = 1;
817 if (lenchar == 'b')
818 new->len = 1;
819 else if (lenchar == 's')
820 new->len = 2;
821 else if (lenchar == 'i')
822 new->len = 4;
824 new->val = opt_malloc(new->len);
825 for (i=0; i<new->len; i++)
826 new->val[i] = val>>((new->len - i - 1)*8);
828 else if (is_addr)
830 struct in_addr in;
831 unsigned char *op;
832 char *slash;
833 /* max length of address/subnet descriptor is five bytes,
834 add one for the option 120 enc byte too */
835 new->val = op = opt_malloc((5 * addrs) + 1);
836 new->flags |= DHOPT_ADDR;
838 if (!(new->flags & DHOPT_ENCAPSULATE) && new->opt == 120)
840 *(op++) = 1; /* RFC 3361 "enc byte" */
841 new->flags &= ~DHOPT_ADDR;
843 while (addrs--)
845 cp = comma;
846 comma = split(cp);
847 slash = split_chr(cp, '/');
848 in.s_addr = inet_addr(cp);
849 if (!slash)
851 memcpy(op, &in, INADDRSZ);
852 op += INADDRSZ;
854 else
856 unsigned char *p = (unsigned char *)&in;
857 int netsize = atoi(slash);
858 *op++ = netsize;
859 if (netsize > 0)
860 *op++ = *p++;
861 if (netsize > 8)
862 *op++ = *p++;
863 if (netsize > 16)
864 *op++ = *p++;
865 if (netsize > 24)
866 *op++ = *p++;
867 new->flags &= ~DHOPT_ADDR; /* cannot re-write descriptor format */
870 new->len = op - new->val;
872 else if (is_string)
874 /* text arg */
875 if ((new->opt == 119 || new->opt == 120) && !(new->flags & DHOPT_ENCAPSULATE))
877 /* dns search, RFC 3397, or SIP, RFC 3361 */
878 unsigned char *q, *r, *tail;
879 unsigned char *p, *m = NULL, *newp;
880 size_t newlen, len = 0;
881 int header_size = (new->opt == 119) ? 0 : 1;
883 arg = comma;
884 comma = split(arg);
886 while (arg && *arg)
888 char *dom;
889 if (!(dom = arg = canonicalise_opt(arg)))
891 problem = _("bad domain in dhcp-option");
892 break;
895 newp = opt_malloc(len + strlen(arg) + 2 + header_size);
896 if (m)
897 memcpy(newp, m, header_size + len);
898 m = newp;
899 p = m + header_size;
900 q = p + len;
902 /* add string on the end in RFC1035 format */
903 while (*arg)
905 unsigned char *cp = q++;
906 int j;
907 for (j = 0; *arg && (*arg != '.'); arg++, j++)
908 *q++ = *arg;
909 *cp = j;
910 if (*arg)
911 arg++;
913 *q++ = 0;
914 free(dom);
916 /* Now tail-compress using earlier names. */
917 newlen = q - p;
918 for (tail = p + len; *tail; tail += (*tail) + 1)
919 for (r = p; r - p < (int)len; r += (*r) + 1)
920 if (strcmp((char *)r, (char *)tail) == 0)
922 PUTSHORT((r - p) | 0xc000, tail);
923 newlen = tail - p;
924 goto end;
926 end:
927 len = newlen;
929 arg = comma;
930 comma = split(arg);
933 /* RFC 3361, enc byte is zero for names */
934 if (new->opt == 120)
935 m[0] = 0;
936 new->len = (int) len + header_size;
937 new->val = m;
939 else
941 new->len = strlen(comma);
942 /* keep terminating zero on string */
943 new->val = (unsigned char *)opt_string_alloc(comma);
944 new->flags |= DHOPT_STRING;
949 if ((new->len > 255) || (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))))
950 problem = _("dhcp-option too long");
952 if (!problem)
954 if (flags == DHOPT_MATCH)
956 if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||
957 !new->netid ||
958 new->netid->next)
959 problem = _("illegal dhcp-match");
960 else
962 new->next = daemon->dhcp_match;
963 daemon->dhcp_match = new;
966 else
968 new->next = daemon->dhcp_opts;
969 daemon->dhcp_opts = new;
973 return problem;
976 #endif
978 static char *one_opt(int option, char *arg, char *gen_prob, int nest)
980 int i;
981 char *comma, *problem = NULL;;
983 if (option == '?')
984 return gen_prob;
986 for (i=0; usage[i].opt != 0; i++)
987 if (usage[i].opt == option)
989 int rept = usage[i].rept;
991 if (nest == 0)
993 /* command line */
994 if (rept == ARG_USED_CL)
995 return _("illegal repeated flag");
996 if (rept == ARG_ONE)
997 usage[i].rept = ARG_USED_CL;
999 else
1001 /* allow file to override command line */
1002 if (rept == ARG_USED_FILE)
1003 return _("illegal repeated keyword");
1004 if (rept == ARG_USED_CL || rept == ARG_ONE)
1005 usage[i].rept = ARG_USED_FILE;
1008 if (rept != ARG_DUP && rept != ARG_ONE && rept != ARG_USED_CL)
1010 daemon->options |= rept;
1011 return NULL;
1014 break;
1017 switch (option)
1019 case 'C': /* --conf-file */
1021 char *file = opt_string_alloc(arg);
1022 if (file)
1024 one_file(file, nest, 0);
1025 free(file);
1027 break;
1030 case '7': /* --conf-dir */
1032 DIR *dir_stream;
1033 struct dirent *ent;
1034 char *directory, *path;
1035 struct list {
1036 char *suffix;
1037 struct list *next;
1038 } *ignore_suffix = NULL, *li;
1040 comma = split(arg);
1041 if (!(directory = opt_string_alloc(arg)))
1042 break;
1044 for (arg = comma; arg; arg = comma)
1046 comma = split(arg);
1047 li = opt_malloc(sizeof(struct list));
1048 li->next = ignore_suffix;
1049 ignore_suffix = li;
1050 /* Have to copy: buffer is overwritten */
1051 li->suffix = opt_string_alloc(arg);
1054 if (!(dir_stream = opendir(directory)))
1055 die(_("cannot access directory %s: %s"), directory, EC_FILE);
1057 while ((ent = readdir(dir_stream)))
1059 size_t len = strlen(ent->d_name);
1060 struct stat buf;
1062 /* ignore emacs backups and dotfiles */
1063 if (len == 0 ||
1064 ent->d_name[len - 1] == '~' ||
1065 (ent->d_name[0] == '#' && ent->d_name[len - 1] == '#') ||
1066 ent->d_name[0] == '.')
1067 continue;
1069 for (li = ignore_suffix; li; li = li->next)
1071 /* check for proscribed suffices */
1072 size_t ls = strlen(li->suffix);
1073 if (len > ls &&
1074 strcmp(li->suffix, &ent->d_name[len - ls]) == 0)
1075 break;
1077 if (li)
1078 continue;
1080 path = opt_malloc(strlen(directory) + len + 2);
1081 strcpy(path, directory);
1082 strcat(path, "/");
1083 strcat(path, ent->d_name);
1085 if (stat(path, &buf) == -1)
1086 die(_("cannot access %s: %s"), path, EC_FILE);
1087 /* only reg files allowed. */
1088 if (!S_ISREG(buf.st_mode))
1089 continue;
1091 /* dir is one level, so files must be readable */
1092 one_file(path, nest + 1, 0);
1093 free(path);
1096 closedir(dir_stream);
1097 free(directory);
1098 for(; ignore_suffix; ignore_suffix = li)
1100 li = ignore_suffix->next;
1101 free(ignore_suffix->suffix);
1102 free(ignore_suffix);
1105 break;
1108 case '8': /* --log-facility */
1109 /* may be a filename */
1110 if (strchr(arg, '/'))
1111 daemon->log_file = opt_string_alloc(arg);
1112 else
1114 for (i = 0; facilitynames[i].c_name; i++)
1115 if (hostname_isequal((char *)facilitynames[i].c_name, arg))
1116 break;
1118 if (facilitynames[i].c_name)
1119 daemon->log_fac = facilitynames[i].c_val;
1120 else
1121 problem = "bad log facility";
1123 break;
1125 case 'x': /* --pid-file */
1126 daemon->runfile = opt_string_alloc(arg);
1127 break;
1129 case LOPT_DHCP_HOST: /* --dhcp-hostfile */
1130 if (daemon->dhcp_hosts_file)
1131 problem = _("only one dhcp-hostsfile allowed");
1132 else
1133 daemon->dhcp_hosts_file = opt_string_alloc(arg);
1134 break;
1136 case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
1137 if (daemon->dhcp_opts_file)
1138 problem = _("only one dhcp-optsfile allowed");
1139 else
1140 daemon->dhcp_opts_file = opt_string_alloc(arg);
1141 break;
1143 case 'r': /* --resolv-file */
1145 char *name = opt_string_alloc(arg);
1146 struct resolvc *new, *list = daemon->resolv_files;
1148 if (list && list->is_default)
1150 /* replace default resolv file - possibly with nothing */
1151 if (name)
1153 list->is_default = 0;
1154 list->name = name;
1156 else
1157 list = NULL;
1159 else if (name)
1161 new = opt_malloc(sizeof(struct resolvc));
1162 new->next = list;
1163 new->name = name;
1164 new->is_default = 0;
1165 new->mtime = 0;
1166 new->logged = 0;
1167 list = new;
1169 daemon->resolv_files = list;
1170 break;
1173 case 'm': /* --mx-host */
1175 int pref = 1;
1176 struct mx_srv_record *new;
1177 char *name, *target = NULL;
1179 if ((comma = split(arg)))
1181 char *prefstr;
1182 if ((prefstr = split(comma)) && !atoi_check16(prefstr, &pref))
1183 problem = _("bad MX preference");
1186 if (!(name = canonicalise_opt(arg)) ||
1187 (comma && !(target = canonicalise_opt(comma))))
1188 problem = _("bad MX name");
1190 new = opt_malloc(sizeof(struct mx_srv_record));
1191 new->next = daemon->mxnames;
1192 daemon->mxnames = new;
1193 new->issrv = 0;
1194 new->name = name;
1195 new->target = target; /* may be NULL */
1196 new->weight = pref;
1197 break;
1200 case 't': /* --mx-target */
1201 if (!(daemon->mxtarget = canonicalise_opt(arg)))
1202 problem = _("bad MX target");
1203 break;
1205 #ifdef HAVE_DHCP
1206 case 'l': /* --dhcp-leasefile */
1207 daemon->lease_file = opt_string_alloc(arg);
1208 break;
1210 case '6': /* --dhcp-script */
1211 # if defined(NO_FORK)
1212 problem = _("cannot run scripts under uClinux");
1213 # elif !defined(HAVE_SCRIPT)
1214 problem = _("recompile with HAVE_SCRIPT defined to enable lease-change scripts");
1215 # else
1216 daemon->lease_change_command = opt_string_alloc(arg);
1217 # endif
1218 break;
1219 #endif
1221 case 'H': /* --addn-hosts */
1223 struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
1224 static int hosts_index = 1;
1225 new->fname = opt_string_alloc(arg);
1226 new->index = hosts_index++;
1227 new->flags = 0;
1228 new->next = daemon->addn_hosts;
1229 daemon->addn_hosts = new;
1230 break;
1233 case 's': /* --domain */
1234 if (strcmp (arg, "#") == 0)
1235 daemon->options |= OPT_RESOLV_DOMAIN;
1236 else
1238 char *d;
1239 comma = split(arg);
1240 if (!(d = canonicalise_opt(arg)))
1241 option = '?';
1242 else
1244 if (comma)
1246 struct cond_domain *new = safe_malloc(sizeof(struct cond_domain));
1247 unhide_metas(comma);
1248 if ((arg = split_chr(comma, '/')))
1250 int mask;
1251 if ((new->start.s_addr = inet_addr(comma)) == (in_addr_t)-1 ||
1252 !atoi_check(arg, &mask))
1253 option = '?';
1254 else
1256 mask = (1 << (32 - mask)) - 1;
1257 new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask);
1258 new->end.s_addr = new->start.s_addr | htonl(mask);
1261 else if ((arg = split(comma)))
1263 if ((new->start.s_addr = inet_addr(comma)) == (in_addr_t)-1 ||
1264 (new->end.s_addr = inet_addr(arg)) == (in_addr_t)-1)
1265 option = '?';
1267 else if ((new->start.s_addr = new->end.s_addr = inet_addr(comma)) == (in_addr_t)-1)
1268 option = '?';
1270 new->domain = d;
1271 new->next = daemon->cond_domain;
1272 daemon->cond_domain = new;
1274 else
1275 daemon->domain_suffix = d;
1278 break;
1280 case 'u': /* --user */
1281 daemon->username = opt_string_alloc(arg);
1282 break;
1284 case 'g': /* --group */
1285 daemon->groupname = opt_string_alloc(arg);
1286 daemon->group_set = 1;
1287 break;
1289 #ifdef HAVE_DHCP
1290 case LOPT_SCRIPTUSR: /* --scriptuser */
1291 daemon->scriptuser = opt_string_alloc(arg);
1292 break;
1293 #endif
1295 case 'i': /* --interface */
1296 do {
1297 struct iname *new = opt_malloc(sizeof(struct iname));
1298 comma = split(arg);
1299 new->next = daemon->if_names;
1300 daemon->if_names = new;
1301 /* new->name may be NULL if someone does
1302 "interface=" to disable all interfaces except loop. */
1303 new->name = opt_string_alloc(arg);
1304 new->isloop = new->used = 0;
1305 arg = comma;
1306 } while (arg);
1307 break;
1309 case 'I': /* --except-interface */
1310 case '2': /* --no-dhcp-interface */
1311 do {
1312 struct iname *new = opt_malloc(sizeof(struct iname));
1313 comma = split(arg);
1314 new->name = opt_string_alloc(arg);
1315 if (option == 'I')
1317 new->next = daemon->if_except;
1318 daemon->if_except = new;
1320 else
1322 new->next = daemon->dhcp_except;
1323 daemon->dhcp_except = new;
1325 arg = comma;
1326 } while (arg);
1327 break;
1329 case 'B': /* --bogus-nxdomain */
1331 struct in_addr addr;
1332 unhide_metas(arg);
1333 if (arg && (addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
1335 struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
1336 baddr->next = daemon->bogus_addr;
1337 daemon->bogus_addr = baddr;
1338 baddr->addr = addr;
1340 else
1341 option = '?'; /* error */
1342 break;
1345 case 'a': /* --listen-address */
1346 do {
1347 struct iname *new = opt_malloc(sizeof(struct iname));
1348 comma = split(arg);
1349 unhide_metas(arg);
1350 new->next = daemon->if_addrs;
1351 if (arg && (new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
1353 new->addr.sa.sa_family = AF_INET;
1354 #ifdef HAVE_SOCKADDR_SA_LEN
1355 new->addr.in.sin_len = sizeof(new->addr.in);
1356 #endif
1358 #ifdef HAVE_IPV6
1359 else if (arg && inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
1361 new->addr.sa.sa_family = AF_INET6;
1362 new->addr.in6.sin6_flowinfo = 0;
1363 new->addr.in6.sin6_scope_id = 0;
1364 #ifdef HAVE_SOCKADDR_SA_LEN
1365 new->addr.in6.sin6_len = sizeof(new->addr.in6);
1366 #endif
1368 #endif
1369 else
1371 option = '?'; /* error */
1372 break;
1375 daemon->if_addrs = new;
1376 arg = comma;
1377 } while (arg);
1378 break;
1380 case 'S': /* --server */
1381 case LOPT_LOCAL: /* --local */
1382 case 'A': /* --address */
1384 struct server *serv, *newlist = NULL;
1386 unhide_metas(arg);
1388 if (arg && *arg == '/')
1390 char *end;
1391 arg++;
1392 while ((end = split_chr(arg, '/')))
1394 char *domain = NULL;
1395 /* # matches everything and becomes a zero length domain string */
1396 if (strcmp(arg, "#") == 0)
1397 domain = "";
1398 else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
1399 option = '?';
1400 serv = opt_malloc(sizeof(struct server));
1401 memset(serv, 0, sizeof(struct server));
1402 serv->next = newlist;
1403 newlist = serv;
1404 serv->domain = domain;
1405 serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
1406 arg = end;
1408 if (!newlist)
1410 option = '?';
1411 break;
1415 else
1417 newlist = opt_malloc(sizeof(struct server));
1418 memset(newlist, 0, sizeof(struct server));
1421 if (option == 'A')
1423 newlist->flags |= SERV_LITERAL_ADDRESS;
1424 if (!(newlist->flags & SERV_TYPE))
1425 option = '?';
1428 if (!arg || !*arg)
1430 newlist->flags |= SERV_NO_ADDR; /* no server */
1431 if (newlist->flags & SERV_LITERAL_ADDRESS)
1432 option = '?';
1434 else
1436 int source_port = 0, serv_port = NAMESERVER_PORT;
1437 char *portno, *source;
1439 if ((source = split_chr(arg, '@')) && /* is there a source. */
1440 (portno = split_chr(source, '#')) &&
1441 !atoi_check16(portno, &source_port))
1442 problem = _("bad port");
1444 if ((portno = split_chr(arg, '#')) && /* is there a port no. */
1445 !atoi_check16(portno, &serv_port))
1446 problem = _("bad port");
1448 if ((newlist->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1)
1450 newlist->addr.in.sin_port = htons(serv_port);
1451 newlist->source_addr.in.sin_port = htons(source_port);
1452 newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET;
1453 #ifdef HAVE_SOCKADDR_SA_LEN
1454 newlist->source_addr.in.sin_len = newlist->addr.in.sin_len = sizeof(struct sockaddr_in);
1455 #endif
1456 if (source)
1458 newlist->flags |= SERV_HAS_SOURCE;
1459 if ((newlist->source_addr.in.sin_addr.s_addr = inet_addr(source)) == (in_addr_t) -1)
1461 #if defined(SO_BINDTODEVICE)
1462 newlist->source_addr.in.sin_addr.s_addr = INADDR_ANY;
1463 strncpy(newlist->interface, source, IF_NAMESIZE);
1464 #else
1465 problem = _("interface binding not supported");
1466 #endif
1469 else
1470 newlist->source_addr.in.sin_addr.s_addr = INADDR_ANY;
1472 #ifdef HAVE_IPV6
1473 else if (inet_pton(AF_INET6, arg, &newlist->addr.in6.sin6_addr) > 0)
1475 newlist->addr.in6.sin6_port = htons(serv_port);
1476 newlist->source_addr.in6.sin6_port = htons(source_port);
1477 newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET6;
1478 #ifdef HAVE_SOCKADDR_SA_LEN
1479 newlist->addr.in6.sin6_len = newlist->source_addr.in6.sin6_len = sizeof(newlist->addr.in6);
1480 #endif
1481 if (source)
1483 newlist->flags |= SERV_HAS_SOURCE;
1484 if (inet_pton(AF_INET6, source, &newlist->source_addr.in6.sin6_addr) == 0)
1486 #if defined(SO_BINDTODEVICE)
1487 newlist->source_addr.in6.sin6_addr = in6addr_any;
1488 strncpy(newlist->interface, source, IF_NAMESIZE);
1489 #else
1490 problem = _("interface binding not supported");
1491 #endif
1494 else
1495 newlist->source_addr.in6.sin6_addr = in6addr_any;
1497 #endif
1498 else
1499 option = '?'; /* error */
1503 serv = newlist;
1504 while (serv->next)
1506 serv->next->flags = serv->flags;
1507 serv->next->addr = serv->addr;
1508 serv->next->source_addr = serv->source_addr;
1509 serv = serv->next;
1511 serv->next = daemon->servers;
1512 daemon->servers = newlist;
1513 break;
1516 case 'c': /* --cache-size */
1518 int size;
1520 if (!atoi_check(arg, &size))
1521 option = '?';
1522 else
1524 /* zero is OK, and means no caching. */
1526 if (size < 0)
1527 size = 0;
1528 else if (size > 10000)
1529 size = 10000;
1531 daemon->cachesize = size;
1533 break;
1536 case 'p': /* --port */
1537 if (!atoi_check16(arg, &daemon->port))
1538 option = '?';
1539 break;
1541 case LOPT_MINPORT: /* --min-port */
1542 if (!atoi_check16(arg, &daemon->min_port))
1543 option = '?';
1544 break;
1546 case '0': /* --dns-forward-max */
1547 if (!atoi_check(arg, &daemon->ftabsize))
1548 option = '?';
1549 break;
1551 case LOPT_MAX_LOGS: /* --log-async */
1552 daemon->max_logs = LOG_MAX; /* default */
1553 if (arg && !atoi_check(arg, &daemon->max_logs))
1554 option = '?';
1555 else if (daemon->max_logs > 100)
1556 daemon->max_logs = 100;
1557 break;
1559 case 'P': /* --edns-packet-max */
1561 int i;
1562 if (!atoi_check(arg, &i))
1563 option = '?';
1564 daemon->edns_pktsz = (unsigned short)i;
1565 break;
1568 case 'Q': /* --query-port */
1569 if (!atoi_check16(arg, &daemon->query_port))
1570 option = '?';
1571 /* if explicitly set to zero, use single OS ephemeral port
1572 and disable random ports */
1573 if (daemon->query_port == 0)
1574 daemon->osport = 1;
1575 break;
1577 case 'T': /* --local-ttl */
1578 case LOPT_NEGTTL: /* --neg-ttl */
1580 int ttl;
1581 if (!atoi_check(arg, &ttl))
1582 option = '?';
1583 else if (option == LOPT_NEGTTL)
1584 daemon->neg_ttl = (unsigned long)ttl;
1585 else
1586 daemon->local_ttl = (unsigned long)ttl;
1587 break;
1590 #ifdef HAVE_DHCP
1591 case 'X': /* --dhcp-lease-max */
1592 if (!atoi_check(arg, &daemon->dhcp_max))
1593 option = '?';
1594 break;
1595 #endif
1597 #ifdef HAVE_TFTP
1598 case LOPT_TFTP_MAX: /* --tftp-max */
1599 if (!atoi_check(arg, &daemon->tftp_max))
1600 option = '?';
1601 break;
1603 case LOPT_PREFIX: /* --tftp-prefix */
1604 daemon->tftp_prefix = opt_string_alloc(arg);
1605 break;
1607 case LOPT_TFTPPORTS: /* --tftp-port-range */
1608 if (!(comma = split(arg)) ||
1609 !atoi_check16(arg, &daemon->start_tftp_port) ||
1610 !atoi_check16(comma, &daemon->end_tftp_port))
1611 problem = _("bad port range");
1613 if (daemon->start_tftp_port > daemon->end_tftp_port)
1615 int tmp = daemon->start_tftp_port;
1616 daemon->start_tftp_port = daemon->end_tftp_port;
1617 daemon->end_tftp_port = tmp;
1620 break;
1621 #endif
1623 case LOPT_BRIDGE: /* --bridge-interface */
1625 struct dhcp_bridge *new = opt_malloc(sizeof(struct dhcp_bridge));
1626 if (!(comma = split(arg)))
1628 problem = _("bad bridge-interface");
1629 break;
1632 strncpy(new->iface, arg, IF_NAMESIZE);
1633 new->alias = NULL;
1634 new->next = daemon->bridges;
1635 daemon->bridges = new;
1637 do {
1638 arg = comma;
1639 comma = split(arg);
1640 if (strlen(arg) != 0)
1642 struct dhcp_bridge *b = opt_malloc(sizeof(struct dhcp_bridge));
1643 b->next = new->alias;
1644 new->alias = b;
1645 strncpy(b->iface, arg, IF_NAMESIZE);
1647 } while (comma);
1649 break;
1652 #ifdef HAVE_DHCP
1653 case 'F': /* --dhcp-range */
1655 int k, leasepos = 2;
1656 char *cp, *a[5] = { NULL, NULL, NULL, NULL, NULL };
1657 struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
1659 new->next = daemon->dhcp;
1660 new->lease_time = DEFLEASE;
1661 new->addr_epoch = 0;
1662 new->netmask.s_addr = 0;
1663 new->broadcast.s_addr = 0;
1664 new->router.s_addr = 0;
1665 new->netid.net = NULL;
1666 new->filter = NULL;
1667 new->flags = 0;
1669 gen_prob = _("bad dhcp-range");
1671 if (!arg)
1673 option = '?';
1674 break;
1677 while(1)
1679 for (cp = arg; *cp; cp++)
1680 if (!(*cp == ' ' || *cp == '.' || (*cp >='0' && *cp <= '9')))
1681 break;
1683 if (*cp != ',' && (comma = split(arg)))
1685 if (strstr(arg, "net:") == arg)
1687 struct dhcp_netid *tt = opt_malloc(sizeof (struct dhcp_netid));
1688 tt->net = opt_string_alloc(arg+4);
1689 tt->next = new->filter;
1690 new->filter = tt;
1692 else
1694 if (new->netid.net)
1695 problem = _("only one netid tag allowed");
1696 else
1697 new->netid.net = opt_string_alloc(arg);
1699 arg = comma;
1701 else
1703 a[0] = arg;
1704 break;
1708 for (k = 1; k < 5; k++)
1709 if (!(a[k] = split(a[k-1])))
1710 break;
1712 if ((k < 2) || ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1))
1713 option = '?';
1714 else if (strcmp(a[1], "static") == 0)
1716 new->end = new->start;
1717 new->flags |= CONTEXT_STATIC;
1719 else if (strcmp(a[1], "proxy") == 0)
1721 new->end = new->start;
1722 new->flags |= CONTEXT_PROXY;
1724 else if ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1)
1725 option = '?';
1727 if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
1729 struct in_addr tmp = new->start;
1730 new->start = new->end;
1731 new->end = tmp;
1734 if (option != '?' && k >= 3 && strchr(a[2], '.') &&
1735 ((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
1737 new->flags |= CONTEXT_NETMASK;
1738 leasepos = 3;
1739 if (!is_same_net(new->start, new->end, new->netmask))
1740 problem = _("inconsistent DHCP range");
1742 daemon->dhcp = new;
1744 if (k >= 4 && strchr(a[3], '.') &&
1745 ((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1))
1747 new->flags |= CONTEXT_BRDCAST;
1748 leasepos = 4;
1751 if (k >= leasepos+1)
1753 if (strcmp(a[leasepos], "infinite") == 0)
1754 new->lease_time = 0xffffffff;
1755 else
1757 int fac = 1;
1758 if (strlen(a[leasepos]) > 0)
1760 switch (a[leasepos][strlen(a[leasepos]) - 1])
1762 case 'd':
1763 case 'D':
1764 fac *= 24;
1765 /* fall though */
1766 case 'h':
1767 case 'H':
1768 fac *= 60;
1769 /* fall through */
1770 case 'm':
1771 case 'M':
1772 fac *= 60;
1773 /* fall through */
1774 case 's':
1775 case 'S':
1776 a[leasepos][strlen(a[leasepos]) - 1] = 0;
1779 new->lease_time = atoi(a[leasepos]) * fac;
1780 /* Leases of a minute or less confuse
1781 some clients, notably Apple's */
1782 if (new->lease_time < 120)
1783 new->lease_time = 120;
1787 break;
1790 case LOPT_BANK:
1791 case 'G': /* --dhcp-host */
1793 int j, k = 0;
1794 char *a[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
1795 struct dhcp_config *new;
1796 struct in_addr in;
1798 new = opt_malloc(sizeof(struct dhcp_config));
1800 new->next = daemon->dhcp_conf;
1801 new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
1802 new->hwaddr = NULL;
1804 if ((a[0] = arg))
1805 for (k = 1; k < 6; k++)
1806 if (!(a[k] = split(a[k-1])))
1807 break;
1809 for (j = 0; j < k; j++)
1810 if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
1812 char *arg = a[j];
1814 if ((arg[0] == 'i' || arg[0] == 'I') &&
1815 (arg[1] == 'd' || arg[1] == 'D') &&
1816 arg[2] == ':')
1818 if (arg[3] == '*')
1819 new->flags |= CONFIG_NOCLID;
1820 else
1822 int len;
1823 arg += 3; /* dump id: */
1824 if (strchr(arg, ':'))
1825 len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
1826 else
1828 unhide_metas(arg);
1829 len = (int) strlen(arg);
1832 if ((new->clid = opt_malloc(len)))
1834 new->flags |= CONFIG_CLID;
1835 new->clid_len = len;
1836 memcpy(new->clid, arg, len);
1840 else if (strstr(arg, "net:") == arg)
1842 int len = strlen(arg + 4) + 1;
1843 if ((new->netid.net = opt_malloc(len)))
1845 new->flags |= CONFIG_NETID;
1846 strcpy(new->netid.net, arg+4);
1847 unhide_metas(new->netid.net);
1850 else
1852 struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
1853 newhw->next = new->hwaddr;
1854 new->hwaddr = newhw;
1855 newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
1856 &newhw->wildcard_mask, &newhw->hwaddr_type);
1859 else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1)
1861 new->addr = in;
1862 new->flags |= CONFIG_ADDR;
1864 else
1866 char *cp, *lastp = NULL, last = 0;
1867 int fac = 1;
1869 if (strlen(a[j]) > 1)
1871 lastp = a[j] + strlen(a[j]) - 1;
1872 last = *lastp;
1873 switch (last)
1875 case 'd':
1876 case 'D':
1877 fac *= 24;
1878 /* fall through */
1879 case 'h':
1880 case 'H':
1881 fac *= 60;
1882 /* fall through */
1883 case 'm':
1884 case 'M':
1885 fac *= 60;
1886 /* fall through */
1887 case 's':
1888 case 'S':
1889 *lastp = 0;
1893 for (cp = a[j]; *cp; cp++)
1894 if (!isdigit((int)*cp) && *cp != ' ')
1895 break;
1897 if (*cp)
1899 if (lastp)
1900 *lastp = last;
1901 if (strcmp(a[j], "infinite") == 0)
1903 new->lease_time = 0xffffffff;
1904 new->flags |= CONFIG_TIME;
1906 else if (strcmp(a[j], "ignore") == 0)
1907 new->flags |= CONFIG_DISABLE;
1908 else
1910 if (!(new->hostname = canonicalise_opt(a[j])) ||
1911 !legal_hostname(new->hostname))
1912 problem = _("bad DHCP host name");
1913 else
1914 new->flags |= CONFIG_NAME;
1915 new->domain = NULL;
1918 else
1920 new->lease_time = atoi(a[j]) * fac;
1921 /* Leases of a minute or less confuse
1922 some clients, notably Apple's */
1923 if (new->lease_time < 120)
1924 new->lease_time = 120;
1925 new->flags |= CONFIG_TIME;
1929 daemon->dhcp_conf = new;
1930 break;
1933 case 'O': /* --dhcp-option */
1934 case LOPT_FORCE: /* --dhcp-option-force */
1935 case LOPT_OPTS:
1936 case LOPT_MATCH: /* --dhcp-match */
1937 problem = parse_dhcp_opt(arg,
1938 option == LOPT_FORCE ? DHOPT_FORCE :
1939 (option == LOPT_MATCH ? DHOPT_MATCH :
1940 (option == LOPT_OPTS ? DHOPT_BANK : 0)));
1941 break;
1943 case 'M': /* --dhcp-boot */
1945 struct dhcp_netid *id = NULL;
1946 while (arg && strstr(arg, "net:") == arg)
1948 struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
1949 newid->next = id;
1950 id = newid;
1951 comma = split(arg);
1952 newid->net = opt_string_alloc(arg+4);
1953 arg = comma;
1956 if (!arg)
1957 option = '?';
1958 else
1960 char *dhcp_file, *dhcp_sname = NULL;
1961 struct in_addr dhcp_next_server;
1962 comma = split(arg);
1963 dhcp_file = opt_string_alloc(arg);
1964 dhcp_next_server.s_addr = 0;
1965 if (comma)
1967 arg = comma;
1968 comma = split(arg);
1969 dhcp_sname = opt_string_alloc(arg);
1970 if (comma)
1972 unhide_metas(comma);
1973 if ((dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
1974 option = '?';
1977 if (option != '?')
1979 struct dhcp_boot *new = opt_malloc(sizeof(struct dhcp_boot));
1980 new->file = dhcp_file;
1981 new->sname = dhcp_sname;
1982 new->next_server = dhcp_next_server;
1983 new->netid = id;
1984 new->next = daemon->boot_config;
1985 daemon->boot_config = new;
1989 break;
1992 case LOPT_PXE_PROMT: /* --pxe-prompt */
1994 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
1995 int timeout;
1997 new->netid = NULL;
1998 new->opt = 10; /* PXE_MENU_PROMPT */
2000 while (arg && strstr(arg, "net:") == arg)
2002 struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
2003 comma = split(arg);
2004 nn->next = new->netid;
2005 new->netid = nn;
2006 nn->net = opt_string_alloc(arg+4);
2007 arg = comma;
2010 if (!arg)
2011 option = '?';
2012 else
2014 comma = split(arg);
2015 unhide_metas(arg);
2016 new->len = strlen(arg) + 1;
2017 new->val = opt_malloc(new->len);
2018 memcpy(new->val + 1, arg, new->len - 1);
2020 new->u.vendor_class = (unsigned char *)"PXEClient";
2021 new->flags = DHOPT_VENDOR;
2023 if (comma && atoi_check(comma, &timeout))
2024 *(new->val) = timeout;
2025 else
2026 *(new->val) = 255;
2028 new->next = daemon->dhcp_opts;
2029 daemon->dhcp_opts = new;
2030 daemon->enable_pxe = 1;
2033 break;
2036 case LOPT_PXE_SERV: /* --pxe-service */
2038 struct pxe_service *new = opt_malloc(sizeof(struct pxe_service));
2039 char *CSA[] = { "x86PC", "PC98", "IA64_EFI", "Alpha", "Arc_x86", "Intel_Lean_Client",
2040 "IA32_EFI", "BC_EFI", "Xscale_EFI", "x86-64_EFI", NULL };
2041 static int boottype = 32768;
2043 new->netid = NULL;
2044 new->server.s_addr = 0;
2046 while (arg && strstr(arg, "net:") == arg)
2048 struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
2049 comma = split(arg);
2050 nn->next = new->netid;
2051 new->netid = nn;
2052 nn->net = opt_string_alloc(arg+4);
2053 arg = comma;
2056 if (arg && (comma = split(arg)))
2058 for (i = 0; CSA[i]; i++)
2059 if (strcasecmp(CSA[i], arg) == 0)
2060 break;
2062 if (CSA[i] || atoi_check(arg, &i))
2064 arg = comma;
2065 comma = split(arg);
2067 new->CSA = i;
2068 new->menu = opt_string_alloc(arg);
2070 if (comma)
2072 arg = comma;
2073 comma = split(arg);
2074 if (atoi_check(arg, &i))
2076 new->type = i;
2077 new->basename = NULL;
2079 else
2081 new->type = boottype++;
2082 new->basename = opt_string_alloc(arg);
2085 if (comma && (new->server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
2086 option = '?';
2088 /* Order matters */
2089 new->next = NULL;
2090 if (!daemon->pxe_services)
2091 daemon->pxe_services = new;
2092 else
2094 struct pxe_service *s;
2095 for (s = daemon->pxe_services; s->next; s = s->next);
2096 s->next = new;
2099 daemon->enable_pxe = 1;
2100 break;
2105 option = '?';
2106 break;
2109 case '4': /* --dhcp-mac */
2111 if (!(comma = split(arg)))
2112 option = '?';
2113 else
2115 struct dhcp_mac *new = opt_malloc(sizeof(struct dhcp_mac));
2116 if (strstr(arg, "net:") == arg)
2117 new->netid.net = opt_string_alloc(arg+4);
2118 else
2119 new->netid.net = opt_string_alloc(arg);
2120 unhide_metas(comma);
2121 new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
2122 new->next = daemon->dhcp_macs;
2123 daemon->dhcp_macs = new;
2126 break;
2128 case 'U': /* --dhcp-vendorclass */
2129 case 'j': /* --dhcp-userclass */
2130 case LOPT_CIRCUIT: /* --dhcp-circuitid */
2131 case LOPT_REMOTE: /* --dhcp-remoteid */
2132 case LOPT_SUBSCR: /* --dhcp-subscrid */
2134 if (!(comma = split(arg)))
2135 option = '?';
2136 else
2138 char *p;
2139 int dig = 0;
2140 struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
2141 if (strstr(arg, "net:") == arg)
2142 new->netid.net = opt_string_alloc(arg+4);
2143 else
2144 new->netid.net = opt_string_alloc(arg);
2145 /* check for hex string - must digits may include : must not have nothing else,
2146 only allowed for agent-options. */
2147 for (p = comma; *p; p++)
2148 if (isxdigit((int)*p))
2149 dig = 1;
2150 else if (*p != ':')
2151 break;
2152 unhide_metas(comma);
2153 if (option == 'U' || option == 'j' || *p || !dig)
2155 new->len = strlen(comma);
2156 new->data = opt_malloc(new->len);
2157 memcpy(new->data, comma, new->len);
2159 else
2161 new->len = parse_hex(comma, (unsigned char *)comma, strlen(comma), NULL, NULL);
2162 new->data = opt_malloc(new->len);
2163 memcpy(new->data, comma, new->len);
2166 switch (option)
2168 case 'j':
2169 new->match_type = MATCH_USER;
2170 break;
2171 case 'U':
2172 new->match_type = MATCH_VENDOR;
2173 break;
2174 case LOPT_CIRCUIT:
2175 new->match_type = MATCH_CIRCUIT;
2176 break;
2177 case LOPT_REMOTE:
2178 new->match_type = MATCH_REMOTE;
2179 break;
2180 case LOPT_SUBSCR:
2181 new->match_type = MATCH_SUBSCRIBER;
2182 break;
2184 new->next = daemon->dhcp_vendors;
2185 daemon->dhcp_vendors = new;
2187 break;
2190 case LOPT_ALTPORT: /* --dhcp-alternate-port */
2191 if (!arg)
2193 daemon->dhcp_server_port = DHCP_SERVER_ALTPORT;
2194 daemon->dhcp_client_port = DHCP_CLIENT_ALTPORT;
2196 else
2198 comma = split(arg);
2199 if (!atoi_check16(arg, &daemon->dhcp_server_port) ||
2200 (comma && !atoi_check16(comma, &daemon->dhcp_client_port)))
2201 problem = _("invalid port number");
2202 if (!comma)
2203 daemon->dhcp_client_port = daemon->dhcp_server_port+1;
2205 break;
2207 case 'J': /* --dhcp-ignore */
2208 case LOPT_NO_NAMES: /* --dhcp-ignore-names */
2209 case LOPT_BROADCAST: /* --dhcp-broadcast */
2210 case '3': /* --bootp-dynamic */
2212 struct dhcp_netid_list *new = opt_malloc(sizeof(struct dhcp_netid_list));
2213 struct dhcp_netid *list = NULL;
2214 if (option == 'J')
2216 new->next = daemon->dhcp_ignore;
2217 daemon->dhcp_ignore = new;
2219 else if (option == LOPT_BROADCAST)
2221 new->next = daemon->force_broadcast;
2222 daemon->force_broadcast = new;
2224 else if (option == '3')
2226 new->next = daemon->bootp_dynamic;
2227 daemon->bootp_dynamic = new;
2229 else
2231 new->next = daemon->dhcp_ignore_names;
2232 daemon->dhcp_ignore_names = new;
2235 while (arg) {
2236 struct dhcp_netid *member = opt_malloc(sizeof(struct dhcp_netid));
2237 comma = split(arg);
2238 member->next = list;
2239 list = member;
2240 if (strstr(arg, "net:") == arg)
2241 member->net = opt_string_alloc(arg+4);
2242 else
2243 member->net = opt_string_alloc(arg);
2244 arg = comma;
2247 new->list = list;
2248 break;
2250 #endif
2252 case 'V': /* --alias */
2254 char *dash, *a[3] = { NULL, NULL, NULL };
2255 int k = 0;
2256 struct doctor *new = opt_malloc(sizeof(struct doctor));
2257 new->next = daemon->doctors;
2258 daemon->doctors = new;
2259 new->mask.s_addr = 0xffffffff;
2260 new->end.s_addr = 0;
2262 if ((a[0] = arg))
2263 for (k = 1; k < 3; k++)
2265 if (!(a[k] = split(a[k-1])))
2266 break;
2267 unhide_metas(a[k]);
2270 dash = split_chr(a[0], '-');
2272 if ((k < 2) ||
2273 ((new->in.s_addr = inet_addr(a[0])) == (in_addr_t)-1) ||
2274 ((new->out.s_addr = inet_addr(a[1])) == (in_addr_t)-1))
2275 option = '?';
2277 if (k == 3)
2278 new->mask.s_addr = inet_addr(a[2]);
2280 if (dash &&
2281 ((new->end.s_addr = inet_addr(dash)) == (in_addr_t)-1 ||
2282 !is_same_net(new->in, new->end, new->mask) ||
2283 ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
2284 problem = _("invalid alias range");
2286 break;
2289 case LOPT_INTNAME: /* --interface-name */
2291 struct interface_name *new, **up;
2292 char *domain = NULL;
2294 comma = split(arg);
2296 if (!comma || !(domain = canonicalise_opt(arg)))
2297 problem = _("bad interface name");
2299 new = opt_malloc(sizeof(struct interface_name));
2300 new->next = NULL;
2301 /* Add to the end of the list, so that first name
2302 of an interface is used for PTR lookups. */
2303 for (up = &daemon->int_names; *up; up = &((*up)->next));
2304 *up = new;
2305 new->name = domain;
2306 new->intr = opt_string_alloc(comma);
2307 break;
2310 case LOPT_CNAME: /* --cname */
2312 struct cname *new;
2314 if (!(comma = split(arg)))
2315 option = '?';
2316 else
2318 char *alias = canonicalise_opt(arg);
2319 char *target = canonicalise_opt(comma);
2321 if (!alias || !target)
2322 problem = _("bad CNAME");
2323 else
2325 for (new = daemon->cnames; new; new = new->next)
2326 if (hostname_isequal(new->alias, arg))
2327 problem = _("duplicate CNAME");
2328 new = opt_malloc(sizeof(struct cname));
2329 new->next = daemon->cnames;
2330 daemon->cnames = new;
2331 new->alias = alias;
2332 new->target = target;
2335 break;
2338 case LOPT_PTR: /* --ptr-record */
2340 struct ptr_record *new;
2341 char *dom, *target = NULL;
2343 comma = split(arg);
2345 if (!(dom = canonicalise_opt(arg)) ||
2346 (comma && !(target = canonicalise_opt(comma))))
2347 problem = _("bad PTR record");
2348 else
2350 new = opt_malloc(sizeof(struct ptr_record));
2351 new->next = daemon->ptr;
2352 daemon->ptr = new;
2353 new->name = dom;
2354 new->ptr = target;
2356 break;
2359 case LOPT_NAPTR: /* --naptr-record */
2361 char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
2362 int k = 0;
2363 struct naptr *new;
2364 int order, pref;
2365 char *name, *replace = NULL;
2367 if ((a[0] = arg))
2368 for (k = 1; k < 7; k++)
2369 if (!(a[k] = split(a[k-1])))
2370 break;
2373 if (k < 6 ||
2374 !(name = canonicalise_opt(a[0])) ||
2375 !atoi_check16(a[1], &order) ||
2376 !atoi_check16(a[2], &pref) ||
2377 (k == 7 && !(replace = canonicalise_opt(a[6]))))
2378 problem = _("bad NAPTR record");
2379 else
2381 new = opt_malloc(sizeof(struct naptr));
2382 new->next = daemon->naptr;
2383 daemon->naptr = new;
2384 new->name = name;
2385 new->flags = opt_string_alloc(a[3]);
2386 new->services = opt_string_alloc(a[4]);
2387 new->regexp = opt_string_alloc(a[5]);
2388 new->replace = replace;
2389 new->order = order;
2390 new->pref = pref;
2392 break;
2395 case 'Y': /* --txt-record */
2397 struct txt_record *new;
2398 unsigned char *p, *q;
2400 if ((comma = split(arg)))
2401 comma--;
2403 gen_prob = _("TXT record string too long");
2405 if ((q = (unsigned char *)comma))
2406 while (1)
2408 size_t len;
2409 if ((p = (unsigned char *)strchr((char*)q+1, ',')))
2411 if ((len = p - q - 1) > 255)
2412 option = '?';
2413 *q = len;
2414 for (q = q+1; q < p; q++)
2415 *q = unhide_meta(*q);
2417 else
2419 if ((len = strlen((char *)q+1)) > 255)
2420 option = '?';
2421 *q = len;
2422 for (q = q+1; *q; q++)
2423 *q = unhide_meta(*q);
2424 break;
2428 new = opt_malloc(sizeof(struct txt_record));
2429 new->next = daemon->txt;
2430 daemon->txt = new;
2431 new->class = C_IN;
2432 if (comma)
2434 new->len = q - ((unsigned char *)comma);
2435 new->txt = opt_malloc(new->len);
2436 memcpy(new->txt, comma, new->len);
2438 else
2440 static char empty[] = "";
2441 new->len = 1;
2442 new->txt = empty;
2445 /* ensure arg is terminated */
2446 if (comma)
2447 *comma = 0;
2449 if (!(new->name = canonicalise_opt(arg)))
2451 problem = _("bad TXT record");
2452 break;
2455 break;
2458 case 'W': /* --srv-host */
2460 int port = 1, priority = 0, weight = 0;
2461 char *name, *target = NULL;
2462 struct mx_srv_record *new;
2464 comma = split(arg);
2466 if (!(name = canonicalise_opt(arg)))
2467 problem = _("bad SRV record");
2469 if (comma)
2471 arg = comma;
2472 comma = split(arg);
2473 if (!(target = canonicalise_opt(arg))
2474 ) problem = _("bad SRV target");
2476 if (comma)
2478 arg = comma;
2479 comma = split(arg);
2480 if (!atoi_check16(arg, &port))
2481 problem = _("invalid port number");
2483 if (comma)
2485 arg = comma;
2486 comma = split(arg);
2487 if (!atoi_check16(arg, &priority))
2488 problem = _("invalid priority");
2490 if (comma)
2492 arg = comma;
2493 comma = split(arg);
2494 if (!atoi_check16(arg, &weight))
2495 problem = _("invalid weight");
2501 new = opt_malloc(sizeof(struct mx_srv_record));
2502 new->next = daemon->mxnames;
2503 daemon->mxnames = new;
2504 new->issrv = 1;
2505 new->name = name;
2506 new->target = target;
2507 new->srvport = port;
2508 new->priority = priority;
2509 new->weight = weight;
2510 break;
2513 default:
2514 return _("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DBus support)");
2518 if (problem)
2519 return problem;
2521 if (option == '?')
2522 return gen_prob;
2524 return NULL;
2527 static void one_file(char *file, int nest, int hard_opt)
2529 volatile int lineno = 0;
2530 int i, option;
2531 FILE *f;
2532 char *p, *arg, *start, *buff = daemon->namebuff;
2533 static struct fileread {
2534 dev_t dev;
2535 ino_t ino;
2536 struct fileread *next;
2537 } *filesread = NULL;
2538 struct stat statbuf;
2540 /* ignore repeated files. */
2541 if (hard_opt == 0 && stat(file, &statbuf) == 0)
2543 struct fileread *r;
2545 for (r = filesread; r; r = r->next)
2546 if (r->dev == statbuf.st_dev && r->ino == statbuf.st_ino)
2547 return;
2549 r = safe_malloc(sizeof(struct fileread));
2550 r->next = filesread;
2551 filesread = r;
2552 r->dev = statbuf.st_dev;
2553 r->ino = statbuf.st_ino;
2556 if (nest > 20)
2557 die(_("files nested too deep in %s"), file, EC_BADCONF);
2559 if (!(f = fopen(file, "r")))
2561 if (errno == ENOENT && nest == 0)
2562 return; /* No conffile, all done. */
2563 else
2565 char *str = _("cannot read %s: %s");
2566 if (hard_opt != 0)
2568 my_syslog(LOG_ERR, str, file, strerror(errno));
2569 return;
2571 else
2572 die(str, file, EC_FILE);
2576 while (fgets(buff, MAXDNAME, f))
2578 int white;
2579 unsigned int lastquote;
2580 char *errmess;
2582 /* Memory allocation failure longjmps here if mem_recover == 1 */
2583 if (hard_opt)
2585 if (setjmp(mem_jmp))
2586 continue;
2587 mem_recover = 1;
2590 lineno++;
2591 errmess = NULL;
2593 /* Implement quotes, inside quotes we allow \\ \" \n and \t
2594 metacharacters get hidden also strip comments */
2596 for (white = 1, lastquote = 0, p = buff; *p; p++)
2598 if (*p == '"')
2600 memmove(p, p+1, strlen(p+1)+1);
2601 for(; *p && *p != '"'; p++)
2603 if (*p == '\\' && strchr("\"tnebr\\", p[1]))
2605 if (p[1] == 't')
2606 p[1] = '\t';
2607 else if (p[1] == 'n')
2608 p[1] = '\n';
2609 else if (p[1] == 'b')
2610 p[1] = '\b';
2611 else if (p[1] == 'r')
2612 p[1] = '\r';
2613 else if (p[1] == 'e') /* escape */
2614 p[1] = '\033';
2615 memmove(p, p+1, strlen(p+1)+1);
2617 *p = hide_meta(*p);
2619 if (*p == '"')
2621 memmove(p, p+1, strlen(p+1)+1);
2622 lastquote = p - buff;
2624 else
2626 errmess = _("missing \"");
2627 goto oops;
2631 if (white && *p == '#')
2633 *p = 0;
2634 break;
2636 white = isspace((int)unhide_meta(*p));
2639 /* fgets gets end of line char too. */
2640 while (strlen(buff) > lastquote && isspace((int)unhide_meta(buff[strlen(buff)-1])))
2641 buff[strlen(buff)-1] = 0;
2643 if (*buff == 0)
2644 continue;
2646 if (hard_opt != 0)
2647 arg = buff;
2648 else if ((p=strchr(buff, '=')))
2650 /* allow spaces around "=" */
2651 arg = p+1;
2652 for (; p >= buff && (isspace((int)*p) || *p == '='); p--)
2653 *p = 0;
2655 else
2656 arg = NULL;
2658 if (hard_opt != 0)
2659 option = hard_opt;
2660 else
2662 /* skip leading space */
2663 for (start = buff; *start && isspace((int)*start); start++);
2665 for (option = 0, i = 0; opts[i].name; i++)
2666 if (strcmp(opts[i].name, start) == 0)
2668 option = opts[i].val;
2669 break;
2672 if (!option)
2673 errmess = _("bad option");
2674 else if (opts[i].has_arg == 0 && arg)
2675 errmess = _("extraneous parameter");
2676 else if (opts[i].has_arg == 1 && !arg)
2677 errmess = _("missing parameter");
2680 if (!errmess)
2682 if (arg)
2683 for (; isspace((int)*arg); arg++);
2685 errmess = one_opt(option, arg, _("error"), nest + 1);
2688 if (errmess)
2690 oops:
2691 sprintf(buff, _("%s at line %d of %%s"), errmess, lineno);
2692 if (hard_opt != 0)
2693 my_syslog(LOG_ERR, buff, file);
2694 else
2695 die(buff, file, EC_BADCONF);
2699 mem_recover = 1;
2700 fclose(f);
2703 #ifdef HAVE_DHCP
2704 void reread_dhcp(void)
2706 if (daemon->dhcp_hosts_file)
2708 struct dhcp_config *configs, *cp, **up;
2710 /* remove existing... */
2711 for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
2713 cp = configs->next;
2715 if (configs->flags & CONFIG_BANK)
2717 struct hwaddr_config *mac, *tmp;
2719 for (mac = configs->hwaddr; mac; mac = tmp)
2721 tmp = mac->next;
2722 free(mac);
2724 if (configs->flags & CONFIG_CLID)
2725 free(configs->clid);
2726 if (configs->flags & CONFIG_NETID)
2727 free(configs->netid.net);
2728 if (configs->flags & CONFIG_NAME)
2729 free(configs->hostname);
2732 *up = configs->next;
2733 free(configs);
2735 else
2736 up = &configs->next;
2739 one_file(daemon->dhcp_hosts_file, 1, LOPT_BANK);
2740 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), daemon->dhcp_hosts_file);
2743 if (daemon->dhcp_opts_file)
2745 struct dhcp_opt *opts, *cp, **up;
2746 struct dhcp_netid *id, *next;
2748 for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
2750 cp = opts->next;
2752 if (opts->flags & DHOPT_BANK)
2754 if ((opts->flags & DHOPT_VENDOR))
2755 free(opts->u.vendor_class);
2756 free(opts->val);
2757 for (id = opts->netid; id; id = next)
2759 next = id->next;
2760 free(id->net);
2761 free(id);
2763 *up = opts->next;
2764 free(opts);
2766 else
2767 up = &opts->next;
2770 one_file(daemon->dhcp_opts_file, 1, LOPT_OPTS);
2771 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), daemon->dhcp_opts_file);
2774 #endif
2776 void read_opts(int argc, char **argv, char *compile_opts)
2778 char *buff = opt_malloc(MAXDNAME);
2779 int option, nest = 0, testmode = 0;
2780 char *errmess, *arg, *conffile = CONFFILE;
2782 opterr = 0;
2784 daemon = opt_malloc(sizeof(struct daemon));
2785 memset(daemon, 0, sizeof(struct daemon));
2786 daemon->namebuff = buff;
2788 /* Set defaults - everything else is zero or NULL */
2789 daemon->cachesize = CACHESIZ;
2790 daemon->ftabsize = FTABSIZ;
2791 daemon->port = NAMESERVER_PORT;
2792 daemon->dhcp_client_port = DHCP_CLIENT_PORT;
2793 daemon->dhcp_server_port = DHCP_SERVER_PORT;
2794 daemon->default_resolv.is_default = 1;
2795 daemon->default_resolv.name = RESOLVFILE;
2796 daemon->resolv_files = &daemon->default_resolv;
2797 daemon->username = CHUSER;
2798 daemon->runfile = RUNFILE;
2799 daemon->dhcp_max = MAXLEASES;
2800 daemon->tftp_max = TFTP_MAX_CONNECTIONS;
2801 daemon->edns_pktsz = EDNS_PKTSZ;
2802 daemon->log_fac = -1;
2803 add_txt("version.bind", "dnsmasq-" VERSION );
2804 add_txt("authors.bind", "Simon Kelley");
2805 add_txt("copyright.bind", COPYRIGHT);
2807 while (1)
2809 #ifdef HAVE_GETOPT_LONG
2810 option = getopt_long(argc, argv, OPTSTRING, opts, NULL);
2811 #else
2812 option = getopt(argc, argv, OPTSTRING);
2813 #endif
2815 if (option == -1)
2816 break;
2818 /* Copy optarg so that argv doesn't get changed */
2819 if (optarg)
2821 strncpy(buff, optarg, MAXDNAME);
2822 buff[MAXDNAME-1] = 0;
2823 arg = buff;
2825 else
2826 arg = NULL;
2828 /* command-line only stuff */
2829 if (option == LOPT_TEST)
2830 testmode = 1;
2831 else if (option == 'w')
2833 if (argc != 3 || strcmp(argv[2], "dhcp") != 0)
2834 do_usage();
2835 #ifdef HAVE_DHCP
2836 else
2837 display_opts();
2838 #endif
2839 exit(0);
2841 else if (option == 'v')
2843 printf(_("Dnsmasq version %s %s\n"), VERSION, COPYRIGHT);
2844 printf(_("Compile time options %s\n\n"), compile_opts);
2845 printf(_("This software comes with ABSOLUTELY NO WARRANTY.\n"));
2846 printf(_("Dnsmasq is free software, and you are welcome to redistribute it\n"));
2847 printf(_("under the terms of the GNU General Public License, version 2 or 3.\n"));
2848 exit(0);
2850 else if (option == 'C')
2852 conffile = opt_string_alloc(arg);
2853 nest++;
2855 else
2857 #ifdef HAVE_GETOPT_LONG
2858 errmess = one_opt(option, arg, _("try --help"), 0);
2859 #else
2860 errmess = one_opt(option, arg, _("try -w"), 0);
2861 #endif
2862 if (errmess)
2863 die(_("bad command line options: %s"), errmess, EC_BADCONF);
2867 if (conffile)
2868 one_file(conffile, nest, 0);
2870 /* port might not be known when the address is parsed - fill in here */
2871 if (daemon->servers)
2873 struct server *tmp;
2874 for (tmp = daemon->servers; tmp; tmp = tmp->next)
2875 if (!(tmp->flags & SERV_HAS_SOURCE))
2877 if (tmp->source_addr.sa.sa_family == AF_INET)
2878 tmp->source_addr.in.sin_port = htons(daemon->query_port);
2879 #ifdef HAVE_IPV6
2880 else if (tmp->source_addr.sa.sa_family == AF_INET6)
2881 tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
2882 #endif
2886 if (daemon->if_addrs)
2888 struct iname *tmp;
2889 for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)
2890 if (tmp->addr.sa.sa_family == AF_INET)
2891 tmp->addr.in.sin_port = htons(daemon->port);
2892 #ifdef HAVE_IPV6
2893 else if (tmp->addr.sa.sa_family == AF_INET6)
2894 tmp->addr.in6.sin6_port = htons(daemon->port);
2895 #endif /* IPv6 */
2898 /* only one of these need be specified: the other defaults to the host-name */
2899 if ((daemon->options & OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
2901 struct mx_srv_record *mx;
2903 if (gethostname(buff, MAXDNAME) == -1)
2904 die(_("cannot get host-name: %s"), NULL, EC_MISC);
2906 for (mx = daemon->mxnames; mx; mx = mx->next)
2907 if (!mx->issrv && hostname_isequal(mx->name, buff))
2908 break;
2910 if ((daemon->mxtarget || (daemon->options & OPT_LOCALMX)) && !mx)
2912 mx = opt_malloc(sizeof(struct mx_srv_record));
2913 mx->next = daemon->mxnames;
2914 mx->issrv = 0;
2915 mx->target = NULL;
2916 mx->name = opt_string_alloc(buff);
2917 daemon->mxnames = mx;
2920 if (!daemon->mxtarget)
2921 daemon->mxtarget = opt_string_alloc(buff);
2923 for (mx = daemon->mxnames; mx; mx = mx->next)
2924 if (!mx->issrv && !mx->target)
2925 mx->target = daemon->mxtarget;
2928 if (!(daemon->options & OPT_NO_RESOLV) &&
2929 daemon->resolv_files &&
2930 daemon->resolv_files->next &&
2931 (daemon->options & OPT_NO_POLL))
2932 die(_("only one resolv.conf file allowed in no-poll mode."), NULL, EC_BADCONF);
2934 if (daemon->options & OPT_RESOLV_DOMAIN)
2936 char *line;
2937 FILE *f;
2939 if ((daemon->options & OPT_NO_RESOLV) ||
2940 !daemon->resolv_files ||
2941 (daemon->resolv_files)->next)
2942 die(_("must have exactly one resolv.conf to read domain from."), NULL, EC_BADCONF);
2944 if (!(f = fopen((daemon->resolv_files)->name, "r")))
2945 die(_("failed to read %s: %s"), (daemon->resolv_files)->name, EC_FILE);
2947 while ((line = fgets(buff, MAXDNAME, f)))
2949 char *token = strtok(line, " \t\n\r");
2951 if (!token || strcmp(token, "search") != 0)
2952 continue;
2954 if ((token = strtok(NULL, " \t\n\r")) &&
2955 (daemon->domain_suffix = canonicalise_opt(token)))
2956 break;
2959 fclose(f);
2961 if (!daemon->domain_suffix)
2962 die(_("no search directive found in %s"), (daemon->resolv_files)->name, EC_MISC);
2965 if (daemon->domain_suffix)
2967 /* add domain for any srv record without one. */
2968 struct mx_srv_record *srv;
2970 for (srv = daemon->mxnames; srv; srv = srv->next)
2971 if (srv->issrv &&
2972 strchr(srv->name, '.') &&
2973 strchr(srv->name, '.') == strrchr(srv->name, '.'))
2975 strcpy(buff, srv->name);
2976 strcat(buff, ".");
2977 strcat(buff, daemon->domain_suffix);
2978 free(srv->name);
2979 srv->name = opt_string_alloc(buff);
2982 else if (daemon->options & OPT_DHCP_FQDN)
2983 die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
2985 if (testmode)
2987 fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
2988 exit(0);