]>
git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/option.c
1 /* dnsmasq is Copyright (c) 2000-2007 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 */
22 /* Solaris headers don't have facility names. */
23 #ifdef HAVE_SOLARIS_NETWORK
31 { "daemon", LOG_DAEMON
},
33 { "syslog", LOG_SYSLOG
},
38 /* Not Solaris < 10 */
39 { "audit", LOG_AUDIT
},
42 { "local0", LOG_LOCAL0
},
43 { "local1", LOG_LOCAL1
},
44 { "local2", LOG_LOCAL2
},
45 { "local3", LOG_LOCAL3
},
46 { "local4", LOG_LOCAL4
},
47 { "local5", LOG_LOCAL5
},
48 { "local6", LOG_LOCAL6
},
49 { "local7", LOG_LOCAL7
},
54 #ifndef HAVE_GETOPT_LONG
63 #define OPTSTRING "9531yZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:W:Y:2:4:6:7:8:0:"
65 /* options which don't have a one-char version */
66 #define LOPT_RELOAD 256
67 #define LOPT_NO_NAMES 257
69 #define LOPT_SECURE 259
70 #define LOPT_PREFIX 260
72 #define LOPT_BRIDGE 262
73 #define LOPT_TFTP_MAX 263
74 #define LOPT_FORCE 264
75 #define LOPT_NOBLOCK 265
76 #define LOPT_LOG_OPTS 266
77 #define LOPT_MAX_LOGS 267
78 #define LOPT_CIRCUIT 268
79 #define LOPT_REMOTE 269
80 #define LOPT_SUBSCR 270
81 #define LOPT_INTNAME 271
83 #define LOPT_DHCP_HOST 273
84 #define LOPT_APREF 274
85 #define LOPT_OVERRIDE 275
86 #define LOPT_TFTPPORTS 276
87 #define LOPT_REBIND 277
88 #define LOPT_NOLAST 278
90 #define LOPT_DHCP_OPTS 280
91 #define LOPT_MATCH 281
92 #define LOPT_BROADCAST 282
93 #define LOPT_NEGTTL 283
94 #define LOPT_ALTPORT 284
95 #define LOPT_SCRIPTUSR 285
97 #ifdef HAVE_GETOPT_LONG
98 static const struct option opts
[] =
100 static const struct myoption opts
[] =
103 {"version", 0, 0, 'v'},
104 {"no-hosts", 0, 0, 'h'},
105 {"no-poll", 0, 0, 'n'},
107 {"no-daemon", 0, 0, 'd'},
108 {"log-queries", 0, 0, 'q'},
110 {"group", 2, 0, 'g'},
111 {"resolv-file", 2, 0, 'r'},
112 {"mx-host", 1, 0, 'm'},
113 {"mx-target", 1, 0, 't'},
114 {"cache-size", 2, 0, 'c'},
116 {"dhcp-leasefile", 2, 0, 'l'},
117 {"dhcp-lease", 1, 0, 'l' },
118 {"dhcp-host", 1, 0, 'G'},
119 {"dhcp-range", 1, 0, 'F'},
120 {"dhcp-option", 1, 0, 'O'},
121 {"dhcp-boot", 1, 0, 'M'},
122 {"domain", 1, 0, 's'},
123 {"domain-suffix", 1, 0, 's'},
124 {"interface", 1, 0, 'i'},
125 {"listen-address", 1, 0, 'a'},
126 {"bogus-priv", 0, 0, 'b'},
127 {"bogus-nxdomain", 1, 0, 'B'},
128 {"selfmx", 0, 0, 'e'},
129 {"filterwin2k", 0, 0, 'f'},
130 {"pid-file", 2, 0, 'x'},
131 {"strict-order", 0, 0, 'o'},
132 {"server", 1, 0, 'S'},
133 {"local", 1, 0, 'S' },
134 {"address", 1, 0, 'A' },
135 {"conf-file", 2, 0, 'C'},
136 {"no-resolv", 0, 0, 'R'},
137 {"expand-hosts", 0, 0, 'E'},
138 {"localmx", 0, 0, 'L'},
139 {"local-ttl", 1, 0, 'T'},
140 {"no-negcache", 0, 0, 'N'},
141 {"addn-hosts", 1, 0, 'H'},
142 {"query-port", 1, 0, 'Q'},
143 {"except-interface", 1, 0, 'I'},
144 {"no-dhcp-interface", 1, 0, '2'},
145 {"domain-needed", 0, 0, 'D'},
146 {"dhcp-lease-max", 1, 0, 'X' },
147 {"bind-interfaces", 0, 0, 'z'},
148 {"read-ethers", 0, 0, 'Z' },
149 {"alias", 1, 0, 'V' },
150 {"dhcp-vendorclass", 1, 0, 'U'},
151 {"dhcp-userclass", 1, 0, 'j'},
152 {"dhcp-ignore", 1, 0, 'J'},
153 {"edns-packet-max", 1, 0, 'P'},
154 {"keep-in-foreground", 0, 0, 'k'},
155 {"dhcp-authoritative", 0, 0, 'K'},
156 {"srv-host", 1, 0, 'W'},
157 {"localise-queries", 0, 0, 'y'},
158 {"txt-record", 1, 0, 'Y'},
159 {"enable-dbus", 0, 0, '1'},
160 {"bootp-dynamic", 0, 0, '3'},
161 {"dhcp-mac", 1, 0, '4'},
162 {"no-ping", 0, 0, '5'},
163 {"dhcp-script", 1, 0, '6'},
164 {"conf-dir", 1, 0, '7'},
165 {"log-facility", 1, 0 ,'8'},
166 {"leasefile-ro", 0, 0, '9'},
167 {"dns-forward-max", 1, 0, '0'},
168 {"clear-on-reload", 0, 0, LOPT_RELOAD
},
169 {"dhcp-ignore-names", 2, 0, LOPT_NO_NAMES
},
170 {"enable-tftp", 0, 0, LOPT_TFTP
},
171 {"tftp-secure", 0, 0, LOPT_SECURE
},
172 {"tftp-unique-root", 0, 0, LOPT_APREF
},
173 {"tftp-root", 1, 0, LOPT_PREFIX
},
174 {"tftp-max", 1, 0, LOPT_TFTP_MAX
},
175 {"ptr-record", 1, 0, LOPT_PTR
},
176 #ifdef HAVE_BSD_BRIDGE
177 {"bridge-interface", 1, 0 , LOPT_BRIDGE
},
179 {"dhcp-option-force", 1, 0, LOPT_FORCE
},
180 {"tftp-no-blocksize", 0, 0, LOPT_NOBLOCK
},
181 {"log-dhcp", 0, 0, LOPT_LOG_OPTS
},
182 {"log-async", 2, 0, LOPT_MAX_LOGS
},
183 {"dhcp-circuitid", 1, 0, LOPT_CIRCUIT
},
184 {"dhcp-remoteid", 1, 0, LOPT_REMOTE
},
185 {"dhcp-subscrid", 1, 0, LOPT_SUBSCR
},
186 {"interface-name", 1, 0, LOPT_INTNAME
},
187 {"dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST
},
188 {"dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS
},
189 {"dhcp-no-override", 0, 0, LOPT_OVERRIDE
},
190 {"tftp-port-range", 1, 0, LOPT_TFTPPORTS
},
191 {"stop-dns-rebind", 0, 0, LOPT_REBIND
},
192 {"all-servers", 0, 0, LOPT_NOLAST
},
193 {"dhcp-match", 1, 0, LOPT_MATCH
},
194 {"dhcp-broadcast", 1, 0, LOPT_BROADCAST
},
195 {"neg-ttl", 1, 0, LOPT_NEGTTL
},
196 {"dhcp-alternate-port", 2, 0, LOPT_ALTPORT
},
197 {"dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR
},
206 static const struct optflags optmap
[] = {
207 { 'b', OPT_BOGUSPRIV
},
211 { 'h', OPT_NO_HOSTS
},
212 { 'n', OPT_NO_POLL
},
214 { 'k', OPT_NO_FORK
},
215 { 'K', OPT_AUTHORITATIVE
},
217 { 'R', OPT_NO_RESOLV
},
219 { 'L', OPT_LOCALMX
},
221 { 'D', OPT_NODOTS_LOCAL
},
224 { 'y', OPT_LOCALISE
},
226 { '3', OPT_BOOTP_DYNAMIC
},
227 { '5', OPT_NO_PING
},
228 { '9', OPT_LEASE_RO
},
229 { LOPT_RELOAD
, OPT_RELOAD
},
230 { LOPT_TFTP
, OPT_TFTP
},
231 { LOPT_SECURE
, OPT_TFTP_SECURE
},
232 { LOPT_NOBLOCK
, OPT_TFTP_NOBLOCK
},
233 { LOPT_LOG_OPTS
, OPT_LOG_OPTS
},
234 { LOPT_APREF
, OPT_TFTP_APREF
},
235 { LOPT_OVERRIDE
, OPT_NO_OVERRIDE
},
236 { LOPT_REBIND
, OPT_NO_REBIND
},
237 { LOPT_NOLAST
, OPT_ALL_SERVERS
},
243 static const struct {
248 { "-a, --listen-address=ipaddr", gettext_noop("Specify local address(es) to listen on."), NULL
},
249 { "-A, --address=/domain/ipaddr", gettext_noop("Return ipaddr for all hosts in specified domains."), NULL
},
250 { "-b, --bogus-priv", gettext_noop("Fake reverse lookups for RFC1918 private address ranges."), NULL
},
251 { "-B, --bogus-nxdomain=ipaddr", gettext_noop("Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."), NULL
},
252 { "-c, --cache-size=cachesize", gettext_noop("Specify the size of the cache in entries (defaults to %s)."), "$" },
253 { "-C, --conf-file=path", gettext_noop("Specify configuration file (defaults to %s)."), CONFFILE
},
254 { "-d, --no-daemon", gettext_noop("Do NOT fork into the background: run in debug mode."), NULL
},
255 { "-D, --domain-needed", gettext_noop("Do NOT forward queries with no domain part."), NULL
},
256 { "-e, --selfmx", gettext_noop("Return self-pointing MX records for local hosts."), NULL
},
257 { "-E, --expand-hosts", gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL
},
258 { "-f, --filterwin2k", gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL
},
259 { "-F, --dhcp-range=ipaddr,ipaddr,time", gettext_noop("Enable DHCP in the range given with lease duration."), NULL
},
260 { "-g, --group=groupname", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP
},
261 { "-G, --dhcp-host=<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL
},
262 { " --dhcp-hostsfile=<filename>", gettext_noop("Read DHCP host specs from file"), NULL
},
263 { " --dhcp-optsfile=<filename>", gettext_noop("Read DHCP option specs from file"), NULL
},
264 { "-h, --no-hosts", gettext_noop("Do NOT load %s file."), HOSTSFILE
},
265 { "-H, --addn-hosts=path", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE
},
266 { "-i, --interface=interface", gettext_noop("Specify interface(s) to listen on."), NULL
},
267 { "-I, --except-interface=int", gettext_noop("Specify interface(s) NOT to listen on.") , NULL
},
268 { "-j, --dhcp-userclass=<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL
},
269 { " --dhcp-circuitid=<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL
},
270 { " --dhcp-remoteid=<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL
},
271 { " --dhcp-subscrid=<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL
},
272 { "-J, --dhcp-ignore=<tag>", gettext_noop("Don't do DHCP for hosts with tag set."), NULL
},
273 { " --dhcp-broadcast=<tag>", gettext_noop("Force broadcast replies for hosts with tag set."), NULL
},
274 { "-k, --keep-in-foreground", gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL
},
275 { "-K, --dhcp-authoritative", gettext_noop("Assume we are the only DHCP server on the local network."), NULL
},
276 { "-l, --dhcp-leasefile=path", gettext_noop("Specify where to store DHCP leases (defaults to %s)."), LEASEFILE
},
277 { "-L, --localmx", gettext_noop("Return MX records for local hosts."), NULL
},
278 { "-m, --mx-host=host_name,target,pref", gettext_noop("Specify an MX record."), NULL
},
279 { "-M, --dhcp-boot=<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL
},
280 { "-n, --no-poll", gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE
},
281 { "-N, --no-negcache", gettext_noop("Do NOT cache failed search results."), NULL
},
282 { "-o, --strict-order", gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE
},
283 { "-O, --dhcp-option=<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL
},
284 { " --dhcp-option-force=<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL
},
285 { "-p, --port=number", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL
},
286 { "-P, --edns-packet-max=<size>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
287 { "-q, --log-queries", gettext_noop("Log DNS queries."), NULL
},
288 { "-Q, --query-port=number", gettext_noop("Force the originating port for upstream DNS queries."), NULL
},
289 { "-R, --no-resolv", gettext_noop("Do NOT read resolv.conf."), NULL
},
290 { "-r, --resolv-file=path", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE
},
291 { "-S, --server=/domain/ipaddr", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL
},
292 { " --local=/domain/", gettext_noop("Never forward queries to specified domains."), NULL
},
293 { "-s, --domain=domain", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL
},
294 { "-t, --mx-target=host_name", gettext_noop("Specify default target in an MX record."), NULL
},
295 { "-T, --local-ttl=time", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL
},
296 { " --neg-ttl=time", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL
},
297 { "-u, --user=username", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER
},
298 { "-U, --dhcp-vendorclass=<id>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL
},
299 { "-v, --version", gettext_noop("Display dnsmasq version and copyright information."), NULL
},
300 { "-V, --alias=addr,addr,mask", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL
},
301 { "-W, --srv-host=name,target,...", gettext_noop("Specify a SRV record."), NULL
},
302 { "-w, --help", gettext_noop("Display this message. Use --help dhcp for known DHCP options."), NULL
},
303 { "-x, --pid-file=path", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE
},
304 { "-X, --dhcp-lease-max=number", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },
305 { "-y, --localise-queries", gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL
},
306 { "-Y --txt-record=name,txt....", gettext_noop("Specify TXT DNS record."), NULL
},
307 { " --ptr-record=name,target", gettext_noop("Specify PTR DNS record."), NULL
},
308 { " --interface-name=name,interface", gettext_noop("Give DNS name to IPv4 address of interface."), NULL
},
309 { "-z, --bind-interfaces", gettext_noop("Bind only to interfaces in use."), NULL
},
310 { "-Z, --read-ethers", gettext_noop("Read DHCP static host information from %s."), ETHERSFILE
},
311 { "-1, --enable-dbus", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL
},
312 { "-2, --no-dhcp-interface=interface", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL
},
313 { "-3, --bootp-dynamic", gettext_noop("Enable dynamic address allocation for bootp."), NULL
},
314 { "-4, --dhcp-mac=<id>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL
},
315 #ifdef HAVE_BSD_BRIDGE
316 { " --bridge-interface=iface,alias,..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL
},
318 { "-5, --no-ping", gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL
},
319 { "-6, --dhcp-script=path", gettext_noop("Script to run on DHCP lease creation and destruction."), NULL
},
320 { "-7, --conf-dir=path", gettext_noop("Read configuration from all the files in this directory."), NULL
},
321 { "-8, --log-facility=facilty|file", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL
},
322 { "-9, --leasefile-ro", gettext_noop("Read leases at startup, but never write the lease file."), NULL
},
323 { "-0, --dns-forward-max=<queries>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" },
324 { " --clear-on-reload", gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE
},
325 { " --dhcp-ignore-names[=<id>]", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL
},
326 { " --dhcp-no-override", gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL
},
327 { " --enable-tftp", gettext_noop("Enable integrated read-only TFTP server."), NULL
},
328 { " --tftp-root=<directory>", gettext_noop("Export files by TFTP only from the specified subtree."), NULL
},
329 { " --tftp-unique-root", gettext_noop("Add client IP address to tftp-root."), NULL
},
330 { " --tftp-secure", gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL
},
331 { " --tftp-max=<connections>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },
332 { " --tftp-no-blocksize", gettext_noop("Disable the TFTP blocksize extension."), NULL
},
333 { " --tftp-port-range=<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL
},
334 { " --log-dhcp", gettext_noop("Extra logging for DHCP."), NULL
},
335 { " --log-async[=<log lines>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL
},
336 { " --stop-dns-rebind", gettext_noop("Stop DNS rebinding. Filter private IP ranges when resolving."), NULL
},
337 { " --all-servers", gettext_noop("Always perform DNS queries to all servers."), NULL
},
338 { " --dhcp-match=<netid>,<opt-no>", gettext_noop("Set tag if client includes option in request."), NULL
},
339 { " --dhcp-alternate-port[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL
},
340 { " --dhcp-scriptuser=<username>", gettext_noop("Run lease-change script as this user."), NULL
},
344 /* makes options which take a list of addresses */
345 #define OT_ADDR_LIST 255
346 /* DHCP-internal options, for logging. not valid in config file */
347 #define OT_INTERNAL 254
349 static const struct {
351 unsigned char val
, size
;
353 { "netmask", 1, OT_ADDR_LIST
},
354 { "time-offset", 2, 4 },
355 { "router", 3, OT_ADDR_LIST
},
356 { "dns-server", 6, OT_ADDR_LIST
},
357 { "log-server", 7, OT_ADDR_LIST
},
358 { "lpr-server", 9, OT_ADDR_LIST
},
359 { "hostname", 12, OT_INTERNAL
},
360 { "boot-file-size", 13, 2 },
361 { "domain-name", 15, 0 },
362 { "swap-server", 16, OT_ADDR_LIST
},
363 { "root-path", 17, 0 },
364 { "extension-path", 18, 0 },
365 { "ip-forward-enable", 19, 1 },
366 { "non-local-source-routing", 20, 1 },
367 { "policy-filter", 21, OT_ADDR_LIST
},
368 { "max-datagram-reassembly", 22, 2 },
369 { "default-ttl", 23, 1 },
371 { "all-subnets-local", 27, 1 },
372 { "broadcast", 28, OT_INTERNAL
},
373 { "router-discovery", 31, 1 },
374 { "router-solicitation", 32, OT_ADDR_LIST
},
375 { "static-route", 33, OT_ADDR_LIST
},
376 { "trailer-encapsulation", 34, 1 },
377 { "arp-timeout", 35, 4 },
378 { "ethernet-encap", 36, 1 },
379 { "tcp-ttl", 37, 1 },
380 { "tcp-keepalive", 38, 4 },
381 { "nis-domain", 40, 0 },
382 { "nis-server", 41, OT_ADDR_LIST
},
383 { "ntp-server", 42, OT_ADDR_LIST
},
384 { "vendor-encap", 43, OT_INTERNAL
},
385 { "netbios-ns", 44, OT_ADDR_LIST
},
386 { "netbios-dd", 45, OT_ADDR_LIST
},
387 { "netbios-nodetype", 46, 1 },
388 { "netbios-scope", 47, 0 },
389 { "x-windows-fs", 48, OT_ADDR_LIST
},
390 { "x-windows-dm", 49, OT_ADDR_LIST
},
391 { "requested-address", 50, OT_INTERNAL
},
392 { "lease-time", 51, OT_INTERNAL
},
393 { "option-overload", 52, OT_INTERNAL
},
394 { "message-type", 53, OT_INTERNAL
, },
395 { "server-identifier", 54, OT_INTERNAL
},
396 { "parameter-request", 55, OT_INTERNAL
},
397 { "message", 56, OT_INTERNAL
},
398 { "max-message-size", 57, OT_INTERNAL
},
399 { "T1", 58, OT_INTERNAL
},
400 { "T2", 59, OT_INTERNAL
},
401 { "vendor-class", 60, 0 },
402 { "client-id", 61,OT_INTERNAL
},
403 { "nis-domain", 64, 0 },
404 { "nis-server", 65, OT_ADDR_LIST
},
405 { "tftp-server", 66, 0 },
406 { "bootfile-name", 67, 0 },
407 { "mobile-ip-home", 68, OT_ADDR_LIST
},
408 { "smtp-server", 69, OT_ADDR_LIST
},
409 { "pop3-server", 70, OT_ADDR_LIST
},
410 { "nntp-server", 71, OT_ADDR_LIST
},
411 { "irc-server", 74, OT_ADDR_LIST
},
412 { "user-class", 77, 0 },
413 { "FQDN", 81, OT_INTERNAL
},
414 { "agent-id", 82, OT_INTERNAL
},
415 { "subnet-select", 118, OT_INTERNAL
},
416 { "domain-search", 119, 0 },
417 { "sip-server", 120, 0 },
418 { "classless-static-route", 121, 0 },
422 static volatile int mem_recover
= 0;
423 static jmp_buf mem_jmp
;
424 static void one_file(char *file
, int nest
, int hard_opt
);
426 char *option_string(unsigned char opt
)
430 for (i
= 0; opttab
[i
].name
; i
++)
431 if (opttab
[i
].val
== opt
)
432 return opttab
[i
].name
;
437 /* We hide metacharaters in quoted strings by mapping them into the ASCII control
438 character space. Note that the \0, \t \b \r \033 and \n characters are carefully placed in the
439 following sequence so that they map to themselves: it is therefore possible to call
440 unhide_metas repeatedly on string without breaking things.
441 The transformation gets undone by opt_canonicalise, atoi_check and opt_string_alloc, and a
442 couple of other places.
443 Note that space is included here so that
444 --dhcp-option=3, string
445 has five characters, whilst
446 --dhcp-option=3," string"
450 static const char meta
[] = "\000123456 \b\t\n78\r90abcdefABCDE\033F:,.";
452 static char hide_meta(char c
)
456 for (i
= 0; i
< (sizeof(meta
) - 1); i
++)
463 static char unhide_meta(char cr
)
467 if (c
< (sizeof(meta
) - 1))
473 static void unhide_metas(char *cp
)
477 *cp
= unhide_meta(*cp
);
480 static void *opt_malloc(size_t size
)
486 ret
= whine_malloc(size
);
491 ret
= safe_malloc(size
);
496 static char *opt_string_alloc(char *cp
)
500 if (cp
&& strlen(cp
) != 0)
502 ret
= opt_malloc(strlen(cp
)+1);
505 /* restore hidden metachars */
513 /* find next comma, split string with zero and eliminate spaces.
514 return start of string following comma */
515 static char *split(char *s
)
519 if (!s
|| !(comma
= strchr(s
, ',')))
525 for (; isspace((int)*comma
); comma
++);
527 for (; (p
>= s
) && isspace((int)*p
); p
--)
533 static int canonicalise_opt(char *s
)
539 return canonicalise(s
);
542 static int atoi_check(char *a
, int *res
)
552 if (*p
< '0' || *p
> '9')
559 static void add_txt(char *name
, char *txt
)
561 size_t len
= strlen(txt
);
562 struct txt_record
*r
= opt_malloc(sizeof(struct txt_record
));
564 r
->name
= opt_string_alloc(name
);
565 r
->next
= daemon
->txt
;
568 r
->txt
= opt_malloc(len
+1);
571 memcpy((r
->txt
)+1, txt
, len
);
574 static void do_usage(void)
587 { '#', TFTP_MAX_CONNECTIONS
},
591 printf(_("Usage: dnsmasq [options]\n\n"));
592 #ifndef HAVE_GETOPT_LONG
593 printf(_("Use short options only on the command line.\n"));
595 printf(_("Valid options are :\n"));
597 for (i
= 0; usage
[i
].flag
; i
++)
601 strcpy(buff
, usage
[i
].arg
);
602 for (j
= 0; tab
[j
].handle
; j
++)
603 if (tab
[j
].handle
== *(usage
[i
].arg
))
604 sprintf(buff
, "%d", tab
[j
].val
);
606 printf("%-36.36s", usage
[i
].flag
);
607 printf(_(usage
[i
].desc
), buff
);
612 static void display_opts(void)
616 printf(_("Known DHCP options:\n"));
618 for (i
= 0; opttab
[i
].name
; i
++)
619 if (opttab
[i
].size
!= OT_INTERNAL
)
620 printf("%3d %s\n", opttab
[i
].val
, opttab
[i
].name
);
623 /* This is too insanely large to keep in-line in the switch */
624 static char *parse_dhcp_opt(char *arg
, int flags
)
626 struct dhcp_opt
*new = opt_malloc(sizeof(struct dhcp_opt
));
627 char lenchar
= 0, *cp
;
628 int i
, addrs
, digs
, is_addr
, is_hex
, is_dec
, is_string
, dots
;
629 char *comma
= NULL
, *problem
= NULL
;
630 struct dhcp_netid
*np
= NULL
;
631 unsigned char opt_len
= 0;
637 new->vendor_class
= NULL
;
644 for (cp
= arg
; *cp
; cp
++)
645 if (*cp
< '0' || *cp
> '9')
650 new->opt
= atoi(arg
);
655 if (strstr(arg
, "option:") == arg
)
657 for (i
= 0; opttab
[i
].name
; i
++)
658 if (opttab
[i
].size
!= OT_INTERNAL
&&
659 strcasecmp(opttab
[i
].name
, arg
+7) == 0)
661 new->opt
= opttab
[i
].val
;
662 opt_len
= opttab
[i
].size
;
665 /* option:<optname> must follow tag and vendor string. */
668 else if (strstr(arg
, "vendor:") == arg
)
670 new->vendor_class
= (unsigned char *)opt_string_alloc(arg
+7);
671 new->flags
|= DHOPT_ENCAPSULATE
;
675 new->netid
= opt_malloc(sizeof (struct dhcp_netid
));
676 /* allow optional "net:" for consistency */
677 if (strstr(arg
, "net:") == arg
)
678 new->netid
->net
= opt_string_alloc(arg
+4);
680 new->netid
->net
= opt_string_alloc(arg
);
681 new->netid
->next
= np
;
689 problem
= _("bad dhcp-option");
692 /* characterise the value */
694 is_addr
= is_hex
= is_dec
= is_string
= 1;
697 for (cp
= comma
; (c
= *cp
); cp
++)
706 is_dec
= is_addr
= 0;
711 if (cp
== comma
) /* leading / means a pathname */
720 is_hex
= is_addr
= 0;
723 else if (!(c
>='0' && c
<= '9'))
726 if (cp
[1] == 0 && is_dec
&&
727 (c
== 'b' || c
== 's' || c
== 'i'))
734 if (!((c
>='A' && c
<= 'F') ||
735 (c
>='a' && c
<= 'f')))
739 /* We know that some options take addresses */
741 if (opt_len
== OT_ADDR_LIST
)
743 is_string
= is_dec
= is_hex
= 0;
744 if (!is_addr
|| dots
== 0)
745 problem
= _("bad IP address");
748 if (is_hex
&& digs
> 1)
751 new->val
= opt_malloc(new->len
);
752 parse_hex(comma
, new->val
, digs
, NULL
, NULL
);
756 int i
, val
= atoi(comma
);
757 /* assume numeric arg is 1 byte except for
758 options where it is known otherwise.
759 For vendor class option, we have to hack. */
762 else if (val
& 0xffff0000)
764 else if (val
& 0xff00)
771 else if (lenchar
== 's')
773 else if (lenchar
== 'i')
776 new->val
= opt_malloc(new->len
);
777 for (i
=0; i
<new->len
; i
++)
778 new->val
[i
] = val
>>((new->len
- i
- 1)*8);
785 /* max length of address/subnet descriptor is five bytes,
786 add one for the option 120 enc byte too */
787 new->val
= op
= opt_malloc((5 * addrs
) + 1);
788 new->flags
|= DHOPT_ADDR
;
790 if (!(new->flags
& DHOPT_ENCAPSULATE
) && new->opt
== 120)
792 *(op
++) = 1; /* RFC 3361 "enc byte" */
793 new->flags
&= ~DHOPT_ADDR
;
799 if ((slash
= strchr(cp
, '/')))
801 in
.s_addr
= inet_addr(cp
);
804 memcpy(op
, &in
, INADDRSZ
);
809 unsigned char *p
= (unsigned char *)&in
;
810 int netsize
= atoi(slash
);
820 new->flags
&= ~DHOPT_ADDR
; /* cannot re-write descriptor format */
823 new->len
= op
- new->val
;
828 if ((new->opt
== 119 || new->opt
== 120) && !(new->flags
& DHOPT_ENCAPSULATE
))
830 /* dns search, RFC 3397, or SIP, RFC 3361 */
831 unsigned char *q
, *r
, *tail
;
832 unsigned char *p
, *m
= NULL
, *newp
;
833 size_t newlen
, len
= 0;
834 int header_size
= (new->opt
== 119) ? 0 : 1;
841 if (!canonicalise_opt(arg
))
843 problem
= _("bad domain in dhcp-option");
847 newp
= opt_malloc(len
+ strlen(arg
) + 2 + header_size
);
849 memcpy(newp
, m
, header_size
+ len
);
854 /* add string on the end in RFC1035 format */
857 unsigned char *cp
= q
++;
859 for (j
= 0; *arg
&& (*arg
!= '.'); arg
++, j
++)
867 /* Now tail-compress using earlier names. */
869 for (tail
= p
+ len
; *tail
; tail
+= (*tail
) + 1)
870 for (r
= p
; r
- p
< (int)len
; r
+= (*r
) + 1)
871 if (strcmp((char *)r
, (char *)tail
) == 0)
873 PUTSHORT((r
- p
) | 0xc000, tail
);
884 /* RFC 3361, enc byte is zero for names */
887 new->len
= (int) len
+ header_size
;
892 new->len
= strlen(comma
);
893 /* keep terminating zero on string */
894 new->val
= (unsigned char *)opt_string_alloc(comma
);
895 new->flags
|= DHOPT_STRING
;
901 problem
= _("dhcp-option too long");
905 new->next
= daemon
->dhcp_opts
;
906 daemon
->dhcp_opts
= new;
913 static char *one_opt(int option
, char *arg
, char *gen_prob
, int nest
)
916 char *comma
, *problem
= NULL
;;
921 for (i
=0; optmap
[i
].c
; i
++)
922 if (option
== optmap
[i
].c
)
924 daemon
->options
|= optmap
[i
].flag
;
930 case 'C': /* --conf-file */
932 char *file
= opt_string_alloc(arg
);
934 one_file(file
, nest
, 0);
938 case '7': /* --conf-dir */
942 char *directory
, *path
;
944 if (!(directory
= opt_string_alloc(arg
)))
947 if (!(dir_stream
= opendir(directory
)))
948 die(_("cannot access directory %s: %s"), directory
, EC_FILE
);
950 while ((ent
= readdir(dir_stream
)))
955 if ((len
= strlen(ent
->d_name
)) == 0)
957 /* ignore emacs backups and dotfiles */
958 if (ent
->d_name
[len
- 1] == '~' ||
959 (ent
->d_name
[0] == '#' && ent
->d_name
[len
- 1] == '#') ||
960 ent
->d_name
[0] == '.')
962 path
= opt_malloc(strlen(directory
) + len
+ 2);
963 strcpy(path
, directory
);
965 strcat(path
, ent
->d_name
);
966 if (stat(path
, &buf
) == -1)
967 die(_("cannot access %s: %s"), path
, EC_FILE
);
968 /* only reg files allowed. */
969 if (!S_ISREG(buf
.st_mode
))
972 /* dir is one level, so files must be readable */
973 one_file(path
, nest
+ 1, 0);
977 closedir(dir_stream
);
981 case '8': /* --log-facility */
982 /* may be a filename */
983 if (strchr(arg
, '/'))
984 daemon
->log_file
= opt_string_alloc(arg
);
987 for (i
= 0; facilitynames
[i
].c_name
; i
++)
988 if (hostname_isequal((char *)facilitynames
[i
].c_name
, arg
))
991 if (facilitynames
[i
].c_name
)
992 daemon
->log_fac
= facilitynames
[i
].c_val
;
994 problem
= "bad log facility";
998 case 'x': /* --pid-file */
999 daemon
->runfile
= opt_string_alloc(arg
);
1002 case LOPT_DHCP_HOST
: /* --dhcp-hostfile */
1003 if (daemon
->dhcp_hosts_file
)
1004 problem
= _("only one dhcp-hostsfile allowed");
1006 daemon
->dhcp_hosts_file
= opt_string_alloc(arg
);
1009 case LOPT_DHCP_OPTS
: /* --dhcp-optsfile */
1010 if (daemon
->dhcp_opts_file
)
1011 problem
= _("only one dhcp-optsfile allowed");
1013 daemon
->dhcp_opts_file
= opt_string_alloc(arg
);
1016 case 'r': /* --resolv-file */
1018 char *name
= opt_string_alloc(arg
);
1019 struct resolvc
*new, *list
= daemon
->resolv_files
;
1021 if (list
&& list
->is_default
)
1023 /* replace default resolv file - possibly with nothing */
1026 list
->is_default
= 0;
1034 new = opt_malloc(sizeof(struct resolvc
));
1037 new->is_default
= 0;
1042 daemon
->resolv_files
= list
;
1046 case 'm': /* --mx-host */
1049 struct mx_srv_record
*new;
1051 if ((comma
= split(arg
)))
1054 if ((prefstr
=split(comma
)) && !atoi_check(prefstr
, &pref
))
1055 problem
= _("bad MX preference");
1058 if (!canonicalise_opt(arg
) || (comma
&& !canonicalise_opt(comma
)))
1059 problem
= _("bad MX name");
1061 new = opt_malloc(sizeof(struct mx_srv_record
));
1062 new->next
= daemon
->mxnames
;
1063 daemon
->mxnames
= new;
1065 new->name
= opt_string_alloc(arg
);
1066 new->target
= opt_string_alloc(comma
); /* may be NULL */
1071 case 't': /* --mx-target */
1072 if (!canonicalise_opt(arg
))
1073 problem
= _("bad MX target");
1075 daemon
->mxtarget
= opt_string_alloc(arg
);
1078 case 'l': /* --dhcp-leasefile */
1079 daemon
->lease_file
= opt_string_alloc(arg
);
1082 case '6': /* --dhcp-script */
1084 problem
= _("cannot run scripts under uClinux");
1086 daemon
->lease_change_command
= opt_string_alloc(arg
);
1090 case 'H': /* --addn-hosts */
1092 struct hostsfile
*new = opt_malloc(sizeof(struct hostsfile
));
1093 static int hosts_index
= 1;
1094 new->fname
= opt_string_alloc(arg
);
1095 new->index
= hosts_index
++;
1096 new->next
= daemon
->addn_hosts
;
1097 daemon
->addn_hosts
= new;
1101 case 's': /* --domain */
1102 if (strcmp (arg
, "#") == 0)
1103 daemon
->options
|= OPT_RESOLV_DOMAIN
;
1104 else if (!canonicalise_opt(arg
))
1107 daemon
->domain_suffix
= opt_string_alloc(arg
);
1110 case 'u': /* --user */
1111 daemon
->username
= opt_string_alloc(arg
);
1114 case 'g': /* --group */
1115 daemon
->groupname
= opt_string_alloc(arg
);
1118 case LOPT_SCRIPTUSR
: /* --scriptuser */
1119 daemon
->scriptuser
= opt_string_alloc(arg
);
1122 case 'i': /* --interface */
1124 struct iname
*new = opt_malloc(sizeof(struct iname
));
1126 new->next
= daemon
->if_names
;
1127 daemon
->if_names
= new;
1128 /* new->name may be NULL if someone does
1129 "interface=" to disable all interfaces except loop. */
1130 new->name
= opt_string_alloc(arg
);
1131 new->isloop
= new->used
= 0;
1136 case 'I': /* --except-interface */
1137 case '2': /* --no-dhcp-interface */
1139 struct iname
*new = opt_malloc(sizeof(struct iname
));
1141 new->name
= opt_string_alloc(arg
);
1144 new->next
= daemon
->if_except
;
1145 daemon
->if_except
= new;
1149 new->next
= daemon
->dhcp_except
;
1150 daemon
->dhcp_except
= new;
1156 case 'B': /* --bogus-nxdomain */
1158 struct in_addr addr
;
1160 if (arg
&& (addr
.s_addr
= inet_addr(arg
)) != (in_addr_t
)-1)
1162 struct bogus_addr
*baddr
= opt_malloc(sizeof(struct bogus_addr
));
1163 baddr
->next
= daemon
->bogus_addr
;
1164 daemon
->bogus_addr
= baddr
;
1168 option
= '?'; /* error */
1172 case 'a': /* --listen-address */
1174 struct iname
*new = opt_malloc(sizeof(struct iname
));
1177 new->next
= daemon
->if_addrs
;
1178 if (arg
&& (new->addr
.in
.sin_addr
.s_addr
= inet_addr(arg
)) != (in_addr_t
)-1)
1180 new->addr
.sa
.sa_family
= AF_INET
;
1181 #ifdef HAVE_SOCKADDR_SA_LEN
1182 new->addr
.in
.sin_len
= sizeof(new->addr
.in
);
1186 else if (arg
&& inet_pton(AF_INET6
, arg
, &new->addr
.in6
.sin6_addr
) > 0)
1188 new->addr
.sa
.sa_family
= AF_INET6
;
1189 new->addr
.in6
.sin6_flowinfo
= 0;
1190 new->addr
.in6
.sin6_scope_id
= 0;
1191 #ifdef HAVE_SOCKADDR_SA_LEN
1192 new->addr
.in6
.sin6_len
= sizeof(new->addr
.in6
);
1198 option
= '?'; /* error */
1202 daemon
->if_addrs
= new;
1207 case 'S': /* --server */
1208 case 'A': /* --address */
1210 struct server
*serv
, *newlist
= NULL
;
1214 if (arg
&& *arg
== '/')
1218 while ((end
= strchr(arg
, '/')))
1220 char *domain
= NULL
;
1222 /* # matches everything and becomes a zero length domain string */
1223 if (strcmp(arg
, "#") == 0)
1225 else if (!canonicalise_opt(arg
) && strlen(arg
) != 0)
1228 domain
= opt_string_alloc(arg
); /* NULL if strlen is zero */
1229 serv
= opt_malloc(sizeof(struct server
));
1230 memset(serv
, 0, sizeof(struct server
));
1231 serv
->next
= newlist
;
1233 serv
->domain
= domain
;
1234 serv
->flags
= domain
? SERV_HAS_DOMAIN
: SERV_FOR_NODOTS
;
1246 newlist
= opt_malloc(sizeof(struct server
));
1247 memset(newlist
, 0, sizeof(struct server
));
1252 newlist
->flags
|= SERV_LITERAL_ADDRESS
;
1253 if (!(newlist
->flags
& SERV_TYPE
))
1259 newlist
->flags
|= SERV_NO_ADDR
; /* no server */
1260 if (newlist
->flags
& SERV_LITERAL_ADDRESS
)
1265 int source_port
= 0, serv_port
= NAMESERVER_PORT
;
1266 char *portno
, *source
;
1268 if ((source
= strchr(arg
, '@'))) /* is there a source. */
1271 if ((portno
= strchr(source
+1, '#')))
1274 if (!atoi_check(portno
+1, &source_port
))
1275 problem
= _("bad port");
1279 if ((portno
= strchr(arg
, '#'))) /* is there a port no. */
1282 if (!atoi_check(portno
+1, &serv_port
))
1283 problem
= _("bad port");
1286 if ((newlist
->addr
.in
.sin_addr
.s_addr
= inet_addr(arg
)) != (in_addr_t
) -1)
1288 newlist
->addr
.in
.sin_port
= htons(serv_port
);
1289 newlist
->source_addr
.in
.sin_port
= htons(source_port
);
1290 newlist
->addr
.sa
.sa_family
= newlist
->source_addr
.sa
.sa_family
= AF_INET
;
1291 #ifdef HAVE_SOCKADDR_SA_LEN
1292 newlist
->source_addr
.in
.sin_len
= newlist
->addr
.in
.sin_len
= sizeof(struct sockaddr_in
);
1296 newlist
->flags
|= SERV_HAS_SOURCE
;
1297 if ((newlist
->source_addr
.in
.sin_addr
.s_addr
= inet_addr(source
+1)) == (in_addr_t
) -1)
1299 #if defined(SO_BINDTODEVICE)
1300 newlist
->source_addr
.in
.sin_addr
.s_addr
= INADDR_ANY
;
1301 strncpy(newlist
->interface
, source
+1, IF_NAMESIZE
);
1303 problem
= _("interface binding not supported");
1308 newlist
->source_addr
.in
.sin_addr
.s_addr
= INADDR_ANY
;
1311 else if (inet_pton(AF_INET6
, arg
, &newlist
->addr
.in6
.sin6_addr
) > 0)
1313 newlist
->addr
.in6
.sin6_port
= htons(serv_port
);
1314 newlist
->source_addr
.in6
.sin6_port
= htons(source_port
);
1315 newlist
->addr
.sa
.sa_family
= newlist
->source_addr
.sa
.sa_family
= AF_INET6
;
1316 #ifdef HAVE_SOCKADDR_SA_LEN
1317 newlist
->addr
.in6
.sin6_len
= newlist
->source_addr
.in6
.sin6_len
= sizeof(newlist
->addr
.in6
);
1321 newlist
->flags
|= SERV_HAS_SOURCE
;
1322 if (inet_pton(AF_INET6
, source
+1, &newlist
->source_addr
.in6
.sin6_addr
) == 0)
1324 #if defined(SO_BINDTODEVICE) || defined(HAVE_SOLARIS_NETWORK)
1325 newlist
->source_addr
.in6
.sin6_addr
= in6addr_any
;
1326 strncpy(newlist
->interface
, source
+1, IF_NAMESIZE
);
1328 problem
= _("interface binding not supported");
1333 newlist
->source_addr
.in6
.sin6_addr
= in6addr_any
;
1337 option
= '?'; /* error */
1344 serv
->next
->flags
= serv
->flags
;
1345 serv
->next
->addr
= serv
->addr
;
1346 serv
->next
->source_addr
= serv
->source_addr
;
1349 serv
->next
= daemon
->servers
;
1350 daemon
->servers
= newlist
;
1354 case 'c': /* --cache-size */
1358 if (!atoi_check(arg
, &size
))
1362 /* zero is OK, and means no caching. */
1366 else if (size
> 10000)
1369 daemon
->cachesize
= size
;
1374 case 'p': /* --port */
1375 if (!atoi_check(arg
, &daemon
->port
))
1379 case '0': /* --dns-forward-max */
1380 if (!atoi_check(arg
, &daemon
->ftabsize
))
1384 case LOPT_MAX_LOGS
: /* --log-async */
1385 daemon
->max_logs
= LOG_MAX
; /* default */
1386 if (arg
&& !atoi_check(arg
, &daemon
->max_logs
))
1388 else if (daemon
->max_logs
> 100)
1389 daemon
->max_logs
= 100;
1392 case 'P': /* --edns-packet-max */
1395 if (!atoi_check(arg
, &i
))
1397 daemon
->edns_pktsz
= (unsigned short)i
;
1401 case 'Q': /* --query-port */
1402 if (!atoi_check(arg
, &daemon
->query_port
))
1406 case 'T': /* --local-ttl */
1407 case LOPT_NEGTTL
: /* --neg-ttl */
1410 if (!atoi_check(arg
, &ttl
))
1412 else if (option
== LOPT_NEGTTL
)
1413 daemon
->neg_ttl
= (unsigned long)ttl
;
1415 daemon
->local_ttl
= (unsigned long)ttl
;
1419 case 'X': /* --dhcp-lease-max */
1420 if (!atoi_check(arg
, &daemon
->dhcp_max
))
1424 case LOPT_TFTP_MAX
: /* --tftp-max */
1425 if (!atoi_check(arg
, &daemon
->tftp_max
))
1429 case LOPT_PREFIX
: /* --tftp-prefix */
1430 daemon
->tftp_prefix
= opt_string_alloc(arg
);
1433 case LOPT_TFTPPORTS
: /* --tftp-port-range */
1434 if (!(comma
= split(arg
)) ||
1435 !atoi_check(arg
, &daemon
->start_tftp_port
) ||
1436 !atoi_check(comma
, &daemon
->end_tftp_port
))
1437 problem
= _("bad port range");
1439 if (daemon
->start_tftp_port
> daemon
->end_tftp_port
)
1441 int tmp
= daemon
->start_tftp_port
;
1442 daemon
->start_tftp_port
= daemon
->end_tftp_port
;
1443 daemon
->end_tftp_port
= tmp
;
1448 #ifdef HAVE_BSD_BRIDGE
1449 case LOPT_BRIDGE
: /* --bridge-interface */
1451 struct dhcp_bridge
*new = opt_malloc(sizeof(struct dhcp_bridge
));
1452 if (!(comma
= split(arg
)))
1454 problem
= _("bad bridge-interface");
1458 strncpy(new->iface
, arg
, IF_NAMESIZE
);
1460 new->next
= daemon
->bridges
;
1461 daemon
->bridges
= new;
1466 if (strlen(arg
) != 0)
1468 struct dhcp_bridge
*b
= opt_malloc(sizeof(struct dhcp_bridge
));
1469 b
->next
= new->alias
;
1471 strncpy(b
->iface
, arg
, IF_NAMESIZE
);
1479 case 'F': /* --dhcp-range */
1481 int k
, leasepos
= 2;
1482 char *cp
, *a
[5] = { NULL
, NULL
, NULL
, NULL
, NULL
};
1483 struct dhcp_context
*new = opt_malloc(sizeof(struct dhcp_context
));
1485 new->next
= daemon
->dhcp
;
1486 new->lease_time
= DEFLEASE
;
1487 new->addr_epoch
= 0;
1488 new->netmask
.s_addr
= 0;
1489 new->broadcast
.s_addr
= 0;
1490 new->router
.s_addr
= 0;
1491 new->netid
.net
= NULL
;
1495 gen_prob
= _("bad dhcp-range");
1505 for (cp
= arg
; *cp
; cp
++)
1506 if (!(*cp
== ' ' || *cp
== '.' || (*cp
>='0' && *cp
<= '9')))
1509 if (*cp
!= ',' && (comma
= split(arg
)))
1511 if (strstr(arg
, "net:") == arg
)
1513 struct dhcp_netid
*tt
= opt_malloc(sizeof (struct dhcp_netid
));
1514 tt
->net
= opt_string_alloc(arg
+4);
1515 tt
->next
= new->filter
;
1521 problem
= _("only one netid tag allowed");
1523 new->netid
.net
= opt_string_alloc(arg
);
1534 for (k
= 1; k
< 5; k
++)
1535 if (!(a
[k
] = split(a
[k
-1])))
1538 if (option
== '?' || (k
< 2) || ((new->start
.s_addr
= inet_addr(a
[0])) == (in_addr_t
)-1))
1540 else if (strcmp(a
[1], "static") == 0)
1542 new->end
= new->start
;
1543 new->flags
|= CONTEXT_STATIC
;
1545 else if ((new->end
.s_addr
= inet_addr(a
[1])) == (in_addr_t
)-1)
1548 if (ntohl(new->start
.s_addr
) > ntohl(new->end
.s_addr
))
1550 struct in_addr tmp
= new->start
;
1551 new->start
= new->end
;
1555 if (option
!= '?' && k
>= 3 && strchr(a
[2], '.') &&
1556 ((new->netmask
.s_addr
= inet_addr(a
[2])) != (in_addr_t
)-1))
1558 new->flags
|= CONTEXT_NETMASK
;
1560 if (!is_same_net(new->start
, new->end
, new->netmask
))
1561 problem
= _("inconsistent DHCP range");
1565 if (k
>= 4 && strchr(a
[3], '.') &&
1566 ((new->broadcast
.s_addr
= inet_addr(a
[3])) != (in_addr_t
)-1))
1568 new->flags
|= CONTEXT_BRDCAST
;
1572 if (k
>= leasepos
+1)
1574 if (strcmp(a
[leasepos
], "infinite") == 0)
1575 new->lease_time
= 0xffffffff;
1579 if (strlen(a
[leasepos
]) > 0)
1581 switch (a
[leasepos
][strlen(a
[leasepos
]) - 1])
1597 a
[leasepos
][strlen(a
[leasepos
]) - 1] = 0;
1600 new->lease_time
= atoi(a
[leasepos
]) * fac
;
1601 /* Leases of a minute or less confuse
1602 some clients, notably Apple's */
1603 if (new->lease_time
< 120)
1604 new->lease_time
= 120;
1612 case 'G': /* --dhcp-host */
1615 char *a
[6] = { NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
1616 struct dhcp_config
*new;
1619 new = opt_malloc(sizeof(struct dhcp_config
));
1621 new->next
= daemon
->dhcp_conf
;
1622 new->flags
= (option
== LOPT_BANK
) ? CONFIG_BANK
: 0;
1625 for (k
= 1; k
< 6; k
++)
1626 if (!(a
[k
] = split(a
[k
-1])))
1629 for (j
= 0; j
< k
; j
++)
1630 if (strchr(a
[j
], ':')) /* ethernet address, netid or binary CLID */
1634 if ((arg
[0] == 'i' || arg
[0] == 'I') &&
1635 (arg
[1] == 'd' || arg
[1] == 'D') &&
1639 new->flags
|= CONFIG_NOCLID
;
1643 arg
+= 3; /* dump id: */
1644 if (strchr(arg
, ':'))
1645 len
= parse_hex(arg
, (unsigned char *)arg
, -1, NULL
, NULL
);
1649 len
= (int) strlen(arg
);
1652 if ((new->clid
= opt_malloc(len
)))
1654 new->flags
|= CONFIG_CLID
;
1655 new->clid_len
= len
;
1656 memcpy(new->clid
, arg
, len
);
1660 else if (strstr(arg
, "net:") == arg
)
1662 int len
= strlen(arg
+ 4) + 1;
1663 if ((new->netid
.net
= opt_malloc(len
)))
1665 new->flags
|= CONFIG_NETID
;
1666 strcpy(new->netid
.net
, arg
+4);
1667 unhide_metas(new->netid
.net
);
1672 new->hwaddr_len
= parse_hex(a
[j
], new->hwaddr
, DHCP_CHADDR_MAX
, &new->wildcard_mask
, &new->hwaddr_type
);
1673 new->flags
|= CONFIG_HWADDR
;
1676 else if (strchr(a
[j
], '.') && (in
.s_addr
= inet_addr(a
[j
])) != (in_addr_t
)-1)
1679 new->flags
|= CONFIG_ADDR
;
1683 char *cp
, *lastp
= NULL
, last
= 0;
1686 if (strlen(a
[j
]) > 1)
1688 lastp
= a
[j
] + strlen(a
[j
]) - 1;
1710 for (cp
= a
[j
]; *cp
; cp
++)
1711 if (!isdigit((int)*cp
) && *cp
!= ' ')
1718 if (strcmp(a
[j
], "infinite") == 0)
1720 new->lease_time
= 0xffffffff;
1721 new->flags
|= CONFIG_TIME
;
1723 else if (strcmp(a
[j
], "ignore") == 0)
1724 new->flags
|= CONFIG_DISABLE
;
1727 int len
= strlen(a
[j
]) + 1;
1728 if (!canonicalise_opt(a
[j
]))
1729 problem
= _("bad DHCP host name");
1730 else if ((new->hostname
= opt_malloc(len
)))
1732 new->flags
|= CONFIG_NAME
;
1733 strcpy(new->hostname
, a
[j
]);
1739 new->lease_time
= atoi(a
[j
]) * fac
;
1740 /* Leases of a minute or less confuse
1741 some clients, notably Apple's */
1742 if (new->lease_time
< 120)
1743 new->lease_time
= 120;
1744 new->flags
|= CONFIG_TIME
;
1748 daemon
->dhcp_conf
= new;
1755 problem
= parse_dhcp_opt(arg
,
1756 option
== LOPT_FORCE
? DHOPT_FORCE
:
1757 (option
== LOPT_OPTS
? DHOPT_BANK
: 0));
1760 case 'M': /* --dhcp-boot */
1762 struct dhcp_netid
*id
= NULL
;
1763 while (arg
&& strstr(arg
, "net:") == arg
)
1765 struct dhcp_netid
*newid
= opt_malloc(sizeof(struct dhcp_netid
));
1769 newid
->net
= opt_string_alloc(arg
+4);
1777 char *dhcp_file
, *dhcp_sname
= NULL
;
1778 struct in_addr dhcp_next_server
;
1780 dhcp_file
= opt_string_alloc(arg
);
1781 dhcp_next_server
.s_addr
= 0;
1786 dhcp_sname
= opt_string_alloc(arg
);
1789 unhide_metas(comma
);
1790 if ((dhcp_next_server
.s_addr
= inet_addr(comma
)) == (in_addr_t
)-1)
1796 struct dhcp_boot
*new = opt_malloc(sizeof(struct dhcp_boot
));
1797 new->file
= dhcp_file
;
1798 new->sname
= dhcp_sname
;
1799 new->next_server
= dhcp_next_server
;
1801 new->next
= daemon
->boot_config
;
1802 daemon
->boot_config
= new;
1809 case '4': /* --dhcp-mac */
1811 if (!(comma
= split(arg
)))
1815 struct dhcp_mac
*new = opt_malloc(sizeof(struct dhcp_mac
));
1816 new->netid
.net
= opt_string_alloc(arg
);
1817 unhide_metas(comma
);
1818 new->hwaddr_len
= parse_hex(comma
, new->hwaddr
, DHCP_CHADDR_MAX
, &new->mask
, &new->hwaddr_type
);
1819 new->next
= daemon
->dhcp_macs
;
1820 daemon
->dhcp_macs
= new;
1825 case 'U': /* --dhcp-vendorclass */
1826 case 'j': /* --dhcp-userclass */
1827 case LOPT_CIRCUIT
: /* --dhcp-circuitid */
1828 case LOPT_REMOTE
: /* --dhcp-remoteid */
1829 case LOPT_SUBSCR
: /* --dhcp-subscrid */
1830 case LOPT_MATCH
: /* --dhcp-match */
1832 if (!(comma
= split(arg
)))
1838 struct dhcp_vendor
*new = opt_malloc(sizeof(struct dhcp_vendor
));
1839 new->netid
.net
= opt_string_alloc(arg
);
1840 /* check for hex string - must digits may include : must not have nothing else,
1841 only allowed for agent-options. */
1842 for (p
= comma
; *p
; p
++)
1843 if (isxdigit((int)*p
))
1847 unhide_metas(comma
);
1848 if (option
== LOPT_MATCH
)
1849 new->option
= atoi(comma
);
1850 else if (option
== 'U' || option
== 'j' || *p
|| !dig
)
1852 new->len
= strlen(comma
);
1853 new->data
= opt_malloc(new->len
);
1854 memcpy(new->data
, comma
, new->len
);
1858 new->len
= parse_hex(comma
, (unsigned char *)comma
, strlen(comma
), NULL
, NULL
);
1859 new->data
= opt_malloc(new->len
);
1860 memcpy(new->data
, comma
, new->len
);
1866 new->match_type
= MATCH_USER
;
1869 new->match_type
= MATCH_VENDOR
;
1872 new->match_type
= MATCH_CIRCUIT
;
1875 new->match_type
= MATCH_REMOTE
;
1878 new->match_type
= MATCH_SUBSCRIBER
;
1881 new->match_type
= MATCH_OPTION
;
1883 new->next
= daemon
->dhcp_vendors
;
1884 daemon
->dhcp_vendors
= new;
1889 case LOPT_ALTPORT
: /* --dhcp-alternate-port */
1892 daemon
->dhcp_server_port
= DHCP_SERVER_ALTPORT
;
1893 daemon
->dhcp_client_port
= DHCP_CLIENT_ALTPORT
;
1898 if (!atoi_check(arg
, &daemon
->dhcp_server_port
) ||
1899 (comma
&& !atoi_check(comma
, &daemon
->dhcp_client_port
)))
1900 problem
= _("invalid port number");
1902 daemon
->dhcp_client_port
= daemon
->dhcp_server_port
+1;
1906 case 'J': /* --dhcp-ignore */
1907 case LOPT_NO_NAMES
: /* --dhcp-ignore-names */
1908 case LOPT_BROADCAST
: /* --dhcp-broadcast */
1910 struct dhcp_netid_list
*new = opt_malloc(sizeof(struct dhcp_netid_list
));
1911 struct dhcp_netid
*list
= NULL
;
1914 new->next
= daemon
->dhcp_ignore
;
1915 daemon
->dhcp_ignore
= new;
1917 else if (option
== LOPT_BROADCAST
)
1919 new->next
= daemon
->force_broadcast
;
1920 daemon
->force_broadcast
= new;
1924 new->next
= daemon
->dhcp_ignore_names
;
1925 daemon
->dhcp_ignore_names
= new;
1929 struct dhcp_netid
*member
= opt_malloc(sizeof(struct dhcp_netid
));
1931 member
->next
= list
;
1933 member
->net
= opt_string_alloc(arg
);
1941 case 'V': /* --alias */
1943 char *a
[3] = { NULL
, NULL
, NULL
};
1945 struct in_addr in
, out
, mask
;
1948 mask
.s_addr
= 0xffffffff;
1951 for (k
= 1; k
< 3; k
++)
1953 if (!(a
[k
] = split(a
[k
-1])))
1959 ((in
.s_addr
= inet_addr(a
[0])) == (in_addr_t
)-1) ||
1960 ((out
.s_addr
= inet_addr(a
[1])) == (in_addr_t
)-1))
1967 mask
.s_addr
= inet_addr(a
[2]);
1969 new = opt_malloc(sizeof(struct doctor
));
1973 new->next
= daemon
->doctors
;
1974 daemon
->doctors
= new;
1979 case LOPT_INTNAME
: /* --interface-name */
1981 struct interface_name
*new, **up
;
1985 if (!comma
|| !canonicalise_opt(arg
))
1986 problem
= _("bad interface name");
1988 new = opt_malloc(sizeof(struct interface_name
));
1990 /* Add to the end of the list, so that first name
1991 of an interface is used for PTR lookups. */
1992 for (up
= &daemon
->int_names
; *up
; up
= &((*up
)->next
));
1994 new->name
= opt_string_alloc(arg
);
1995 new->intr
= opt_string_alloc(comma
);
1999 case LOPT_PTR
: /* --ptr-record */
2001 struct ptr_record
*new;
2005 if (!canonicalise_opt(arg
))
2006 problem
= _("bad PTR record");
2008 new = opt_malloc(sizeof(struct ptr_record
));
2009 new->next
= daemon
->ptr
;
2011 new->name
= opt_string_alloc(arg
);
2014 new->ptr
= opt_string_alloc(comma
);
2018 case 'Y': /* --txt-record */
2020 struct txt_record
*new;
2021 unsigned char *p
, *q
;
2023 if ((comma
= split(arg
)))
2026 gen_prob
= _("TXT record string too long");
2028 if (!canonicalise_opt(arg
))
2030 problem
= _("bad TXT record");
2034 if ((q
= (unsigned char *)comma
))
2038 if ((p
= (unsigned char *)strchr((char*)q
+1, ',')))
2040 if ((len
= p
- q
- 1) > 255)
2043 for (q
= q
+1; q
< p
; q
++)
2044 *q
= unhide_meta(*q
);
2048 if ((len
= strlen((char *)q
+1)) > 255)
2051 for (q
= q
+1; *q
; q
++)
2052 *q
= unhide_meta(*q
);
2057 new = opt_malloc(sizeof(struct txt_record
));
2058 new->next
= daemon
->txt
;
2063 new->len
= q
- ((unsigned char *)comma
);
2064 new->txt
= opt_malloc(new->len
);
2065 memcpy(new->txt
, comma
, new->len
);
2069 static char empty
[] = "";
2074 /* ensure arg is terminated */
2077 new->name
= opt_string_alloc(arg
);
2081 case 'W': /* --srv-host */
2083 int port
= 1, priority
= 0, weight
= 0;
2084 char *name
, *target
= NULL
;
2085 struct mx_srv_record
*new;
2089 if (!canonicalise_opt(arg
))
2090 problem
= _("bad SRV record");
2092 name
= opt_string_alloc(arg
);
2098 if (!canonicalise_opt(arg
))
2099 problem
= _("bad SRV target");
2101 target
= opt_string_alloc(arg
);
2106 if (!atoi_check(arg
, &port
))
2107 problem
= _("invalid port number");
2113 if (!atoi_check(arg
, &priority
))
2114 problem
= _("invalid priority");
2120 if (!atoi_check(arg
, &weight
))
2121 problem
= _("invalid weight");
2127 new = opt_malloc(sizeof(struct mx_srv_record
));
2128 new->next
= daemon
->mxnames
;
2129 daemon
->mxnames
= new;
2132 new->target
= target
;
2133 new->srvport
= port
;
2134 new->priority
= priority
;
2135 new->weight
= weight
;
2149 static void one_file(char *file
, int nest
, int hard_opt
)
2151 volatile int lineno
= 0;
2154 char *p
, *arg
, *start
, *buff
= daemon
->namebuff
;
2157 die(_("files nested too deep in %s"), file
, EC_BADCONF
);
2159 if (!(f
= fopen(file
, "r")))
2161 if (errno
== ENOENT
&& nest
== 0)
2162 return; /* No conffile, all done. */
2165 char *str
= _("cannot read %s: %s");
2168 my_syslog(LOG_ERR
, str
, file
, strerror(errno
));
2172 die(str
, file
, EC_FILE
);
2176 while (fgets(buff
, MAXDNAME
, f
))
2179 unsigned int lastquote
;
2182 /* Memory allocation failure longjmps here if mem_recover == 1 */
2185 if (setjmp(mem_jmp
))
2193 /* Implement quotes, inside quotes we allow \\ \" \n and \t
2194 metacharacters get hidden also strip comments */
2196 for (white
= 1, lastquote
= 0, p
= buff
; *p
; p
++)
2200 memmove(p
, p
+1, strlen(p
+1)+1);
2201 for(; *p
&& *p
!= '"'; p
++)
2203 if (*p
== '\\' && strchr("\"tnebr\\", p
[1]))
2207 else if (p
[1] == 'n')
2209 else if (p
[1] == 'b')
2211 else if (p
[1] == 'r')
2213 else if (p
[1] == 'e') /* escape */
2215 memmove(p
, p
+1, strlen(p
+1)+1);
2221 memmove(p
, p
+1, strlen(p
+1)+1);
2222 lastquote
= p
- buff
;
2226 errmess
= _("missing \"");
2231 if (white
&& *p
== '#')
2236 white
= isspace((int)unhide_meta(*p
));
2239 /* fgets gets end of line char too. */
2240 while (strlen(buff
) > lastquote
&& isspace((int)unhide_meta(buff
[strlen(buff
)-1])))
2241 buff
[strlen(buff
)-1] = 0;
2248 else if ((p
=strchr(buff
, '=')))
2250 /* allow spaces around "=" */
2252 for (; p
>= buff
&& (isspace((int)*p
) || *p
== '='); p
--)
2262 /* skip leading space */
2263 for (start
= buff
; *start
&& isspace((int)*start
); start
++);
2265 for (option
= 0, i
= 0; opts
[i
].name
; i
++)
2266 if (strcmp(opts
[i
].name
, start
) == 0)
2268 option
= opts
[i
].val
;
2273 errmess
= _("bad option");
2274 else if (opts
[i
].has_arg
== 0 && arg
)
2275 errmess
= _("extraneous parameter");
2276 else if (opts
[i
].has_arg
== 1 && !arg
)
2277 errmess
= _("missing parameter");
2283 for (; isspace((int)*arg
); arg
++);
2285 errmess
= one_opt(option
, arg
, _("error"), nest
+ 1);
2291 sprintf(buff
, _("%s at line %d of %%s"), errmess
, lineno
);
2293 my_syslog(LOG_ERR
, buff
, file
);
2295 die(buff
, file
, EC_BADCONF
);
2303 void reread_dhcp(void)
2305 if (daemon
->dhcp_hosts_file
)
2307 struct dhcp_config
*configs
, *cp
, **up
;
2309 /* remove existing... */
2310 for (up
= &daemon
->dhcp_conf
, configs
= daemon
->dhcp_conf
; configs
; configs
= cp
)
2314 if (configs
->flags
& CONFIG_BANK
)
2316 if (configs
->flags
& CONFIG_CLID
)
2317 free(configs
->clid
);
2318 if (configs
->flags
& CONFIG_NETID
)
2319 free(configs
->netid
.net
);
2320 if (configs
->flags
& CONFIG_NAME
)
2321 free(configs
->hostname
);
2323 *up
= configs
->next
;
2327 up
= &configs
->next
;
2330 one_file(daemon
->dhcp_hosts_file
, 1, LOPT_BANK
);
2331 my_syslog(LOG_INFO
, _("read %s"), daemon
->dhcp_hosts_file
);
2334 if (daemon
->dhcp_opts_file
)
2336 struct dhcp_opt
*opts
, *cp
, **up
;
2337 struct dhcp_netid
*id
, *next
;
2339 for (up
= &daemon
->dhcp_opts
, opts
= daemon
->dhcp_opts
; opts
; opts
= cp
)
2343 if (opts
->flags
& DHOPT_BANK
)
2345 free(opts
->vendor_class
);
2347 for (id
= opts
->netid
; id
; id
= next
)
2360 one_file(daemon
->dhcp_opts_file
, 1, LOPT_OPTS
);
2361 my_syslog(LOG_INFO
, _("read %s"), daemon
->dhcp_opts_file
);
2365 void read_opts(int argc
, char **argv
, char *compile_opts
)
2367 char *buff
= opt_malloc(MAXDNAME
);
2368 int option
, nest
= 0;
2369 char *errmess
, *arg
, *conffile
= CONFFILE
;
2373 daemon
= opt_malloc(sizeof(struct daemon
));
2374 memset(daemon
, 0, sizeof(struct daemon
));
2375 daemon
->namebuff
= buff
;
2377 /* Set defaults - everything else is zero or NULL */
2378 daemon
->cachesize
= CACHESIZ
;
2379 daemon
->ftabsize
= FTABSIZ
;
2380 daemon
->port
= NAMESERVER_PORT
;
2381 daemon
->dhcp_client_port
= DHCP_CLIENT_PORT
;
2382 daemon
->dhcp_server_port
= DHCP_SERVER_PORT
;
2383 daemon
->default_resolv
.is_default
= 1;
2384 daemon
->default_resolv
.name
= RESOLVFILE
;
2385 daemon
->resolv_files
= &daemon
->default_resolv
;
2386 daemon
->username
= CHUSER
;
2387 daemon
->groupname
= CHGRP
;
2388 daemon
->runfile
= RUNFILE
;
2389 daemon
->dhcp_max
= MAXLEASES
;
2390 daemon
->tftp_max
= TFTP_MAX_CONNECTIONS
;
2391 daemon
->edns_pktsz
= EDNS_PKTSZ
;
2392 daemon
->log_fac
= -1;
2393 add_txt("version.bind", "dnsmasq-" VERSION
);
2394 add_txt("authors.bind", "Simon Kelley");
2395 add_txt("copyright.bind", COPYRIGHT
);
2399 #ifdef HAVE_GETOPT_LONG
2400 option
= getopt_long(argc
, argv
, OPTSTRING
, opts
, NULL
);
2402 option
= getopt(argc
, argv
, OPTSTRING
);
2408 /* Copy optarg so that argv doesn't get changed */
2411 strncpy(buff
, optarg
, MAXDNAME
);
2412 buff
[MAXDNAME
-1] = 0;
2418 /* command-line only stuff */
2421 if (argc
== 3 && strcmp(argv
[2], "dhcp") == 0)
2427 else if (option
== 'v')
2429 printf(_("Dnsmasq version %s %s\n"), VERSION
, COPYRIGHT
);
2430 printf(_("Compile time options %s\n\n"), compile_opts
);
2431 printf(_("This software comes with ABSOLUTELY NO WARRANTY.\n"));
2432 printf(_("Dnsmasq is free software, and you are welcome to redistribute it\n"));
2433 printf(_("under the terms of the GNU General Public License, version 2 or 3.\n"));
2436 else if (option
== 'C')
2438 conffile
= opt_string_alloc(arg
);
2443 #ifdef HAVE_GETOPT_LONG
2444 errmess
= one_opt(option
, arg
, _("try --help"), 0);
2446 errmess
= one_opt(option
, arg
, _("try -w"), 0);
2449 die(_("bad command line options: %s"), errmess
, EC_BADCONF
);
2454 one_file(conffile
, nest
, 0);
2456 /* port might no be known when the address is parsed - fill in here */
2457 if (daemon
->servers
)
2460 for (tmp
= daemon
->servers
; tmp
; tmp
= tmp
->next
)
2461 if (!(tmp
->flags
& SERV_HAS_SOURCE
))
2463 if (tmp
->source_addr
.sa
.sa_family
== AF_INET
)
2464 tmp
->source_addr
.in
.sin_port
= htons(daemon
->query_port
);
2466 else if (tmp
->source_addr
.sa
.sa_family
== AF_INET6
)
2467 tmp
->source_addr
.in6
.sin6_port
= htons(daemon
->query_port
);
2472 if (daemon
->if_addrs
)
2475 for(tmp
= daemon
->if_addrs
; tmp
; tmp
= tmp
->next
)
2476 if (tmp
->addr
.sa
.sa_family
== AF_INET
)
2477 tmp
->addr
.in
.sin_port
= htons(daemon
->port
);
2479 else if (tmp
->addr
.sa
.sa_family
== AF_INET6
)
2480 tmp
->addr
.in6
.sin6_port
= htons(daemon
->port
);
2484 /* only one of these need be specified: the other defaults to the host-name */
2485 if ((daemon
->options
& OPT_LOCALMX
) || daemon
->mxnames
|| daemon
->mxtarget
)
2487 struct mx_srv_record
*mx
;
2489 if (gethostname(buff
, MAXDNAME
) == -1)
2490 die(_("cannot get host-name: %s"), NULL
, EC_MISC
);
2492 for (mx
= daemon
->mxnames
; mx
; mx
= mx
->next
)
2493 if (!mx
->issrv
&& hostname_isequal(mx
->name
, buff
))
2496 if ((daemon
->mxtarget
|| (daemon
->options
& OPT_LOCALMX
)) && !mx
)
2498 mx
= opt_malloc(sizeof(struct mx_srv_record
));
2499 mx
->next
= daemon
->mxnames
;
2502 mx
->name
= opt_string_alloc(buff
);
2503 daemon
->mxnames
= mx
;
2506 if (!daemon
->mxtarget
)
2507 daemon
->mxtarget
= opt_string_alloc(buff
);
2509 for (mx
= daemon
->mxnames
; mx
; mx
= mx
->next
)
2510 if (!mx
->issrv
&& !mx
->target
)
2511 mx
->target
= daemon
->mxtarget
;
2514 if (!(daemon
->options
& OPT_NO_RESOLV
) &&
2515 daemon
->resolv_files
&&
2516 daemon
->resolv_files
->next
&&
2517 (daemon
->options
& OPT_NO_POLL
))
2518 die(_("only one resolv.conf file allowed in no-poll mode."), NULL
, EC_BADCONF
);
2520 if (daemon
->options
& OPT_RESOLV_DOMAIN
)
2525 if ((daemon
->options
& OPT_NO_RESOLV
) ||
2526 !daemon
->resolv_files
||
2527 (daemon
->resolv_files
)->next
)
2528 die(_("must have exactly one resolv.conf to read domain from."), NULL
, EC_BADCONF
);
2530 if (!(f
= fopen((daemon
->resolv_files
)->name
, "r")))
2531 die(_("failed to read %s: %s"), (daemon
->resolv_files
)->name
, EC_FILE
);
2533 while ((line
= fgets(buff
, MAXDNAME
, f
)))
2535 char *token
= strtok(line
, " \t\n\r");
2537 if (!token
|| strcmp(token
, "search") != 0)
2540 if ((token
= strtok(NULL
, " \t\n\r")) &&
2541 canonicalise_opt(token
) &&
2542 (daemon
->domain_suffix
= opt_string_alloc(token
)))
2548 if (!daemon
->domain_suffix
)
2549 die(_("no search directive found in %s"), (daemon
->resolv_files
)->name
, EC_MISC
);
2552 if (daemon
->domain_suffix
)
2554 /* add domain for any srv record without one. */
2555 struct mx_srv_record
*srv
;
2557 for (srv
= daemon
->mxnames
; srv
; srv
= srv
->next
)
2559 strchr(srv
->name
, '.') &&
2560 strchr(srv
->name
, '.') == strrchr(srv
->name
, '.'))
2562 strcpy(buff
, srv
->name
);
2564 strcat(buff
, daemon
->domain_suffix
);
2566 srv
->name
= opt_string_alloc(buff
);