blob: ed015b616e6fc6224c68e8c6be1b5e122c551721 [file] [log] [blame]
Simon Kelley61744352013-01-31 14:34:40 +00001/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
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
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 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.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 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/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
Simon Kelley849a8352006-06-09 21:02:31 +010017/* define this to get facilitynames */
18#define SYSLOG_NAMES
Simon Kelley9e4abcb2004-01-22 19:47:41 +000019#include "dnsmasq.h"
Simon Kelley824af852008-02-12 20:43:05 +000020#include <setjmp.h>
21
Simon Kelley7622fc02009-06-04 20:32:05 +010022static volatile int mem_recover = 0;
23static jmp_buf mem_jmp;
Simon Kelley395eb712012-07-06 22:07:05 +010024static int one_file(char *file, int hard_opt);
Simon Kelley7622fc02009-06-04 20:32:05 +010025
Simon Kelley824af852008-02-12 20:43:05 +000026/* Solaris headers don't have facility names. */
27#ifdef HAVE_SOLARIS_NETWORK
28static 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 },
Simon Kelley824af852008-02-12 20:43:05 +000041 { "audit", LOG_AUDIT },
Simon Kelley824af852008-02-12 20:43:05 +000042 { "cron", LOG_CRON },
43 { "local0", LOG_LOCAL0 },
44 { "local1", LOG_LOCAL1 },
45 { "local2", LOG_LOCAL2 },
46 { "local3", LOG_LOCAL3 },
47 { "local4", LOG_LOCAL4 },
48 { "local5", LOG_LOCAL5 },
49 { "local6", LOG_LOCAL6 },
50 { "local7", LOG_LOCAL7 },
51 { NULL, 0 }
52};
53#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +000054
Simon Kelley849a8352006-06-09 21:02:31 +010055#ifndef HAVE_GETOPT_LONG
Simon Kelley9e4abcb2004-01-22 19:47:41 +000056struct myoption {
57 const char *name;
58 int has_arg;
59 int *flag;
60 int val;
61};
Simon Kelley849a8352006-06-09 21:02:31 +010062#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +000063
Simon Kelley9009d742008-11-14 20:04:27 +000064#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:"
Simon Kelley9e4abcb2004-01-22 19:47:41 +000065
Simon Kelley16972692006-10-16 20:04:18 +010066/* options which don't have a one-char version */
Simon Kelley832af0b2007-01-21 20:01:28 +000067#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
Simon Kelley6b010842007-02-12 20:32:07 +000075#define LOPT_FORCE 264
76#define LOPT_NOBLOCK 265
Simon Kelleyf2621c72007-04-29 19:47:21 +010077#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
Simon Kelley5aabfc72007-08-29 11:24:47 +010083#define LOPT_BANK 272
84#define LOPT_DHCP_HOST 273
85#define LOPT_APREF 274
Simon Kelley824af852008-02-12 20:43:05 +000086#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
Simon Kelley9e038942008-05-30 20:06:34 +010095#define LOPT_ALTPORT 284
96#define LOPT_SCRIPTUSR 285
Simon Kelley1a6bca82008-07-11 11:11:42 +010097#define LOPT_LOCAL 286
98#define LOPT_NAPTR 287
99#define LOPT_MINPORT 288
Simon Kelley9009d742008-11-14 20:04:27 +0000100#define LOPT_DHCP_FQDN 289
101#define LOPT_CNAME 290
Simon Kelley7622fc02009-06-04 20:32:05 +0100102#define LOPT_PXE_PROMT 291
103#define LOPT_PXE_SERV 292
104#define LOPT_TEST 293
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100105#define LOPT_TAG_IF 294
106#define LOPT_PROXY 295
107#define LOPT_GEN_NAMES 296
108#define LOPT_MAXTTL 297
109#define LOPT_NO_REBIND 298
110#define LOPT_LOC_REBND 299
Simon Kelley28866e92011-02-14 20:19:14 +0000111#define LOPT_ADD_MAC 300
Giovanni Bajo237724c2012-04-05 02:46:52 +0200112#define LOPT_SEC_PROXY 301
Simon Kelley7de060b2011-08-26 17:24:52 +0100113#define LOPT_INCR_ADDR 302
114#define LOPT_CONNTRACK 303
Simon Kelleyc72daea2012-01-05 21:33:27 +0000115#define LOPT_FQDN 304
116#define LOPT_LUASCRIPT 305
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000117#define LOPT_RA 306
Simon Kelley8b372702012-03-09 17:45:10 +0000118#define LOPT_DUID 307
Simon Kelleye759d422012-03-16 13:18:57 +0000119#define LOPT_HOST_REC 308
Simon Kelley61ce6002012-04-20 21:28:49 +0100120#define LOPT_TFTP_LC 309
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100121#define LOPT_RR 310
Simon Kelley54dd3932012-06-20 11:23:38 +0100122#define LOPT_CLVERBIND 311
Simon Kelley1d860412012-09-20 20:48:04 +0100123#define LOPT_MAXCTTL 312
Simon Kelley4f7b3042012-11-28 21:27:02 +0000124#define LOPT_AUTHZONE 313
125#define LOPT_AUTHSERV 314
Simon Kelleye1ff4192012-12-09 17:08:47 +0000126#define LOPT_AUTHTTL 315
Simon Kelley4f7b3042012-11-28 21:27:02 +0000127#define LOPT_AUTHSOA 316
Simon Kelleye1ff4192012-12-09 17:08:47 +0000128#define LOPT_AUTHSFS 317
Simon Kelley49678762012-12-09 18:24:58 +0000129#define LOPT_AUTHPEER 318
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000130#define LOPT_IPSET 319
Simon Kelley2bb73af2013-04-24 17:38:19 +0100131#define LOPT_SYNTH 320
Giovanni Bajo7dbe1932012-04-05 02:50:13 +0200132#define LOPT_SEC_VALID 321
Simon Kelleyc6309242013-03-07 20:59:28 +0000133#ifdef OPTION6_PREFIX_CLASS
Giovanni Bajo7dbe1932012-04-05 02:50:13 +0200134#define LOPT_PREF_CLSS 322
Simon Kelleyc6309242013-03-07 20:59:28 +0000135#endif
Simon Kelley8d030462013-07-29 15:41:26 +0100136#define LOPT_FAST_RA 322
Simon Kelley16972692006-10-16 20:04:18 +0100137
Giovanni Bajo7dbe1932012-04-05 02:50:13 +0200138
Simon Kelley849a8352006-06-09 21:02:31 +0100139#ifdef HAVE_GETOPT_LONG
140static const struct option opts[] =
141#else
142static const struct myoption opts[] =
143#endif
144 {
Simon Kelley7622fc02009-06-04 20:32:05 +0100145 { "version", 0, 0, 'v' },
146 { "no-hosts", 0, 0, 'h' },
147 { "no-poll", 0, 0, 'n' },
148 { "help", 0, 0, 'w' },
149 { "no-daemon", 0, 0, 'd' },
150 { "log-queries", 0, 0, 'q' },
151 { "user", 2, 0, 'u' },
152 { "group", 2, 0, 'g' },
153 { "resolv-file", 2, 0, 'r' },
154 { "mx-host", 1, 0, 'm' },
155 { "mx-target", 1, 0, 't' },
156 { "cache-size", 2, 0, 'c' },
157 { "port", 1, 0, 'p' },
158 { "dhcp-leasefile", 2, 0, 'l' },
159 { "dhcp-lease", 1, 0, 'l' },
160 { "dhcp-host", 1, 0, 'G' },
161 { "dhcp-range", 1, 0, 'F' },
162 { "dhcp-option", 1, 0, 'O' },
163 { "dhcp-boot", 1, 0, 'M' },
164 { "domain", 1, 0, 's' },
165 { "domain-suffix", 1, 0, 's' },
166 { "interface", 1, 0, 'i' },
167 { "listen-address", 1, 0, 'a' },
168 { "bogus-priv", 0, 0, 'b' },
169 { "bogus-nxdomain", 1, 0, 'B' },
170 { "selfmx", 0, 0, 'e' },
171 { "filterwin2k", 0, 0, 'f' },
172 { "pid-file", 2, 0, 'x' },
173 { "strict-order", 0, 0, 'o' },
174 { "server", 1, 0, 'S' },
175 { "local", 1, 0, LOPT_LOCAL },
176 { "address", 1, 0, 'A' },
177 { "conf-file", 2, 0, 'C' },
178 { "no-resolv", 0, 0, 'R' },
179 { "expand-hosts", 0, 0, 'E' },
180 { "localmx", 0, 0, 'L' },
181 { "local-ttl", 1, 0, 'T' },
182 { "no-negcache", 0, 0, 'N' },
183 { "addn-hosts", 1, 0, 'H' },
184 { "query-port", 1, 0, 'Q' },
185 { "except-interface", 1, 0, 'I' },
186 { "no-dhcp-interface", 1, 0, '2' },
187 { "domain-needed", 0, 0, 'D' },
188 { "dhcp-lease-max", 1, 0, 'X' },
189 { "bind-interfaces", 0, 0, 'z' },
190 { "read-ethers", 0, 0, 'Z' },
191 { "alias", 1, 0, 'V' },
192 { "dhcp-vendorclass", 1, 0, 'U' },
193 { "dhcp-userclass", 1, 0, 'j' },
194 { "dhcp-ignore", 1, 0, 'J' },
195 { "edns-packet-max", 1, 0, 'P' },
196 { "keep-in-foreground", 0, 0, 'k' },
197 { "dhcp-authoritative", 0, 0, 'K' },
198 { "srv-host", 1, 0, 'W' },
199 { "localise-queries", 0, 0, 'y' },
200 { "txt-record", 1, 0, 'Y' },
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100201 { "dns-rr", 1, 0, LOPT_RR },
Simon Kelleyad094272012-08-10 17:10:54 +0100202 { "enable-dbus", 2, 0, '1' },
Simon Kelley7622fc02009-06-04 20:32:05 +0100203 { "bootp-dynamic", 2, 0, '3' },
204 { "dhcp-mac", 1, 0, '4' },
205 { "no-ping", 0, 0, '5' },
206 { "dhcp-script", 1, 0, '6' },
207 { "conf-dir", 1, 0, '7' },
208 { "log-facility", 1, 0 ,'8' },
209 { "leasefile-ro", 0, 0, '9' },
210 { "dns-forward-max", 1, 0, '0' },
211 { "clear-on-reload", 0, 0, LOPT_RELOAD },
212 { "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
Simon Kelley2937f8a2013-07-29 19:49:07 +0100213 { "enable-tftp", 2, 0, LOPT_TFTP },
Simon Kelley7622fc02009-06-04 20:32:05 +0100214 { "tftp-secure", 0, 0, LOPT_SECURE },
215 { "tftp-unique-root", 0, 0, LOPT_APREF },
216 { "tftp-root", 1, 0, LOPT_PREFIX },
217 { "tftp-max", 1, 0, LOPT_TFTP_MAX },
Simon Kelley61ce6002012-04-20 21:28:49 +0100218 { "tftp-lowercase", 0, 0, LOPT_TFTP_LC },
Simon Kelley7622fc02009-06-04 20:32:05 +0100219 { "ptr-record", 1, 0, LOPT_PTR },
220 { "naptr-record", 1, 0, LOPT_NAPTR },
221 { "bridge-interface", 1, 0 , LOPT_BRIDGE },
222 { "dhcp-option-force", 1, 0, LOPT_FORCE },
223 { "tftp-no-blocksize", 0, 0, LOPT_NOBLOCK },
224 { "log-dhcp", 0, 0, LOPT_LOG_OPTS },
225 { "log-async", 2, 0, LOPT_MAX_LOGS },
226 { "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
227 { "dhcp-remoteid", 1, 0, LOPT_REMOTE },
228 { "dhcp-subscrid", 1, 0, LOPT_SUBSCR },
229 { "interface-name", 1, 0, LOPT_INTNAME },
230 { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
231 { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
232 { "dhcp-no-override", 0, 0, LOPT_OVERRIDE },
233 { "tftp-port-range", 1, 0, LOPT_TFTPPORTS },
234 { "stop-dns-rebind", 0, 0, LOPT_REBIND },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100235 { "rebind-domain-ok", 1, 0, LOPT_NO_REBIND },
Simon Kelley7622fc02009-06-04 20:32:05 +0100236 { "all-servers", 0, 0, LOPT_NOLAST },
237 { "dhcp-match", 1, 0, LOPT_MATCH },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100238 { "dhcp-broadcast", 2, 0, LOPT_BROADCAST },
Simon Kelley7622fc02009-06-04 20:32:05 +0100239 { "neg-ttl", 1, 0, LOPT_NEGTTL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100240 { "max-ttl", 1, 0, LOPT_MAXTTL },
Simon Kelley1d860412012-09-20 20:48:04 +0100241 { "max-cache-ttl", 1, 0, LOPT_MAXCTTL },
Simon Kelley7622fc02009-06-04 20:32:05 +0100242 { "dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
243 { "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
244 { "min-port", 1, 0, LOPT_MINPORT },
245 { "dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN },
246 { "cname", 1, 0, LOPT_CNAME },
247 { "pxe-prompt", 1, 0, LOPT_PXE_PROMT },
248 { "pxe-service", 1, 0, LOPT_PXE_SERV },
249 { "test", 0, 0, LOPT_TEST },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100250 { "tag-if", 1, 0, LOPT_TAG_IF },
251 { "dhcp-proxy", 2, 0, LOPT_PROXY },
252 { "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES },
253 { "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
Simon Kelley28866e92011-02-14 20:19:14 +0000254 { "add-mac", 0, 0, LOPT_ADD_MAC },
Giovanni Bajo237724c2012-04-05 02:46:52 +0200255 { "proxy-dnssec", 0, 0, LOPT_SEC_PROXY },
Simon Kelley7de060b2011-08-26 17:24:52 +0100256 { "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR },
257 { "conntrack", 0, 0, LOPT_CONNTRACK },
Simon Kelleyc72daea2012-01-05 21:33:27 +0000258 { "dhcp-client-update", 0, 0, LOPT_FQDN },
259 { "dhcp-luascript", 1, 0, LOPT_LUASCRIPT },
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000260 { "enable-ra", 0, 0, LOPT_RA },
Simon Kelley8b372702012-03-09 17:45:10 +0000261 { "dhcp-duid", 1, 0, LOPT_DUID },
Simon Kelleye759d422012-03-16 13:18:57 +0000262 { "host-record", 1, 0, LOPT_HOST_REC },
Simon Kelley54dd3932012-06-20 11:23:38 +0100263 { "bind-dynamic", 0, 0, LOPT_CLVERBIND },
Simon Kelley4f7b3042012-11-28 21:27:02 +0000264 { "auth-zone", 1, 0, LOPT_AUTHZONE },
265 { "auth-server", 1, 0, LOPT_AUTHSERV },
266 { "auth-ttl", 1, 0, LOPT_AUTHTTL },
267 { "auth-soa", 1, 0, LOPT_AUTHSOA },
Simon Kelleye1ff4192012-12-09 17:08:47 +0000268 { "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
Simon Kelley49678762012-12-09 18:24:58 +0000269 { "auth-peer", 1, 0, LOPT_AUTHPEER },
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000270 { "ipset", 1, 0, LOPT_IPSET },
Simon Kelley2bb73af2013-04-24 17:38:19 +0100271 { "synth-domain", 1, 0, LOPT_SYNTH },
Giovanni Bajo7dbe1932012-04-05 02:50:13 +0200272 { "dnssec", 0, 0, LOPT_SEC_VALID },
Simon Kelleyc6309242013-03-07 20:59:28 +0000273#ifdef OPTION6_PREFIX_CLASS
274 { "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
275#endif
Simon Kelley8d030462013-07-29 15:41:26 +0100276 { "force-fast-ra", 0, 0, LOPT_FAST_RA },
Simon Kelley849a8352006-06-09 21:02:31 +0100277 { NULL, 0, 0, 0 }
278 };
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000279
Simon Kelley28866e92011-02-14 20:19:14 +0000280
281#define ARG_DUP OPT_LAST
282#define ARG_ONE OPT_LAST + 1
283#define ARG_USED_CL OPT_LAST + 2
284#define ARG_USED_FILE OPT_LAST + 3
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000285
Simon Kelley1a6bca82008-07-11 11:11:42 +0100286static struct {
287 int opt;
288 unsigned int rept;
289 char * const flagdesc;
Simon Kelleyb8187c82005-11-26 21:46:27 +0000290 char * const desc;
291 char * const arg;
292} usage[] = {
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000293 { 'a', ARG_DUP, "<ipaddr>", gettext_noop("Specify local address(es) to listen on."), NULL },
294 { 'A', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Return ipaddr for all hosts in specified domains."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100295 { 'b', OPT_BOGUSPRIV, NULL, gettext_noop("Fake reverse lookups for RFC1918 private address ranges."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000296 { 'B', ARG_DUP, "<ipaddr>", gettext_noop("Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."), NULL },
297 { 'c', ARG_ONE, "<integer>", gettext_noop("Specify the size of the cache in entries (defaults to %s)."), "$" },
298 { 'C', ARG_DUP, "<path>", gettext_noop("Specify configuration file (defaults to %s)."), CONFFILE },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100299 { 'd', OPT_DEBUG, NULL, gettext_noop("Do NOT fork into the background: run in debug mode."), NULL },
300 { 'D', OPT_NODOTS_LOCAL, NULL, gettext_noop("Do NOT forward queries with no domain part."), NULL },
301 { 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL },
302 { 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
303 { 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000304 { 'F', ARG_DUP, "<ipaddr>,...", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
305 { 'g', ARG_ONE, "<groupname>", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100306 { 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000307 { LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL },
308 { LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100309 { LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100310 { 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000311 { 'H', ARG_DUP, "<path>", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
312 { 'i', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) to listen on."), NULL },
313 { 'I', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100314 { 'j', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
315 { LOPT_CIRCUIT, ARG_DUP, "set:<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
316 { LOPT_REMOTE, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
317 { LOPT_SUBSCR, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
318 { 'J', ARG_DUP, "tag:<tag>...", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
319 { LOPT_BROADCAST, ARG_DUP, "[=tag:<tag>...]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100320 { 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
321 { 'K', OPT_AUTHORITATIVE, NULL, gettext_noop("Assume we are the only DHCP server on the local network."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000322 { 'l', ARG_ONE, "<path>", gettext_noop("Specify where to store DHCP leases (defaults to %s)."), LEASEFILE },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100323 { 'L', OPT_LOCALMX, NULL, gettext_noop("Return MX records for local hosts."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000324 { 'm', ARG_DUP, "<host_name>,<target>,<pref>", gettext_noop("Specify an MX record."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100325 { 'M', ARG_DUP, "<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL },
326 { 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE },
327 { 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL },
328 { 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE },
329 { 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL },
330 { LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000331 { 'p', ARG_ONE, "<integer>", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
332 { 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100333 { 'q', OPT_LOG, NULL, gettext_noop("Log DNS queries."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000334 { 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100335 { 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000336 { 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
337 { 'S', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
338 { LOPT_LOCAL, ARG_DUP, "/<domain>/", gettext_noop("Never forward queries to specified domains."), NULL },
Simon Kelley9009d742008-11-14 20:04:27 +0000339 { 's', ARG_DUP, "<domain>[,<range>]", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000340 { 't', ARG_ONE, "<host_name>", gettext_noop("Specify default target in an MX record."), NULL },
341 { 'T', ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
342 { LOPT_NEGTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
343 { LOPT_MAXTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL },
344 { 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100345 { 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100346 { 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000347 { 'V', ARG_DUP, "<ipaddr>,<ipaddr>,<netmask>", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },
348 { 'W', ARG_DUP, "<name>,<target>,...", gettext_noop("Specify a SRV record."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100349 { 'w', 0, NULL, gettext_noop("Display this message. Use --help dhcp for known DHCP options."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000350 { 'x', ARG_ONE, "<path>", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE },
351 { 'X', ARG_ONE, "<integer>", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100352 { 'y', OPT_LOCALISE, NULL, gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000353 { 'Y', ARG_DUP, "<name>,<txt>[,<txt]", gettext_noop("Specify TXT DNS record."), NULL },
354 { LOPT_PTR, ARG_DUP, "<name>,<target>", gettext_noop("Specify PTR DNS record."), NULL },
355 { LOPT_INTNAME, ARG_DUP, "<name>,<interface>", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100356 { 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
357 { 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
Simon Kelleyad094272012-08-10 17:10:54 +0100358 { '1', ARG_ONE, "[=<busname>]", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000359 { '2', ARG_DUP, "<interface>", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100360 { '3', ARG_DUP, "[=tag:<tag>]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
361 { '4', ARG_DUP, "set:<tag>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000362 { LOPT_BRIDGE, ARG_DUP, "<iface>,<alias>..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100363 { '5', OPT_NO_PING, NULL, gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000364 { '6', ARG_ONE, "<path>", gettext_noop("Shell script to run on DHCP lease creation and destruction."), NULL },
365 { LOPT_LUASCRIPT, ARG_DUP, "path", gettext_noop("Lua script to run on DHCP lease creation and destruction."), NULL },
366 { LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change scripts as this user."), NULL },
367 { '7', ARG_DUP, "<path>", gettext_noop("Read configuration from all the files in this directory."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100368 { '8', ARG_ONE, "<facilty>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL },
369 { '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000370 { '0', ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100371 { LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100372 { LOPT_NO_NAMES, ARG_DUP, "[=tag:<tag>]...", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100373 { LOPT_OVERRIDE, OPT_NO_OVERRIDE, NULL, gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL },
Simon Kelley2937f8a2013-07-29 19:49:07 +0100374 { LOPT_TFTP, ARG_DUP, "[=<intr>[,<intr>]]", gettext_noop("Enable integrated read-only TFTP server."), NULL },
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100375 { LOPT_PREFIX, ARG_DUP, "<dir>[,<iface>]", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100376 { LOPT_APREF, OPT_TFTP_APREF, NULL, gettext_noop("Add client IP address to tftp-root."), NULL },
377 { LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000378 { LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100379 { LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
Simon Kelley61ce6002012-04-20 21:28:49 +0100380 { LOPT_TFTP_LC, OPT_TFTP_LC, NULL, gettext_noop("Convert TFTP filenames to lowercase"), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100381 { LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
382 { LOPT_LOG_OPTS, OPT_LOG_OPTS, NULL, gettext_noop("Extra logging for DHCP."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000383 { LOPT_MAX_LOGS, ARG_ONE, "[=<integer>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100384 { LOPT_REBIND, OPT_NO_REBIND, NULL, gettext_noop("Stop DNS rebinding. Filter private IP ranges when resolving."), NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100385 { LOPT_LOC_REBND, OPT_LOCAL_REBIND, NULL, gettext_noop("Allow rebinding of 127.0.0.0/8, for RBL servers."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000386 { LOPT_NO_REBIND, ARG_DUP, "/<domain>/", gettext_noop("Inhibit DNS-rebind protection on this domain."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100387 { LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100388 { LOPT_MATCH, ARG_DUP, "set:<tag>,<optspec>", gettext_noop("Set tag if client includes matching option in request."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100389 { LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100390 { LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
391 { LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
Simon Kelley9009d742008-11-14 20:04:27 +0000392 { LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000393 { LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
394 { LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
Simon Kelley9009d742008-11-14 20:04:27 +0000395 { LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
Simon Kelley7622fc02009-06-04 20:32:05 +0100396 { LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
397 { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
398 { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
Simon Kelley7de060b2011-08-26 17:24:52 +0100399 { LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
Giovanni Bajo237724c2012-04-05 02:46:52 +0200400 { LOPT_SEC_PROXY, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
Simon Kelley7de060b2011-08-26 17:24:52 +0100401 { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
402 { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
Simon Kelleyc72daea2012-01-05 21:33:27 +0000403 { LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow DHCP clients to do their own DDNS updates."), NULL },
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000404 { LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
Simon Kelley8d030462013-07-29 15:41:26 +0100405 { LOPT_FAST_RA, OPT_FAST_RA, NULL, gettext_noop("Always send frequent router-advertisements"), NULL },
Simon Kelley8b372702012-03-09 17:45:10 +0000406 { LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
Simon Kelleye759d422012-03-16 13:18:57 +0000407 { LOPT_HOST_REC, ARG_DUP, "<name>,<address>", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
Giovanni Bajo7dbe1932012-04-05 02:50:13 +0200408<<<<<<< HEAD
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100409 { LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
Simon Kelley4f7b3042012-11-28 21:27:02 +0000410 { LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL },
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000411 { LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>", gettext_noop("Export local names to global DNS"), NULL },
Simon Kelley333b2ce2013-01-07 21:46:03 +0000412 { LOPT_AUTHZONE, ARG_DUP, "<domain>,[<subnet>...]", gettext_noop("Domain to export to global DNS"), NULL },
Simon Kelley4f7b3042012-11-28 21:27:02 +0000413 { LOPT_AUTHTTL, ARG_ONE, "<integer>", gettext_noop("Set TTL for authoritative replies"), NULL },
414 { LOPT_AUTHSOA, ARG_ONE, "<serial>[,...]", gettext_noop("Set authoritive zone information"), NULL },
Simon Kelley49678762012-12-09 18:24:58 +0000415 { LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
416 { LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL },
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000417 { LOPT_IPSET, ARG_DUP, "/<domain>/<ipset>[,<ipset>...]", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },
Simon Kelley48fd1c42013-04-25 09:49:38 +0100418 { LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for sythesised names"), NULL },
Giovanni Bajo7dbe1932012-04-05 02:50:13 +0200419 { LOPT_SEC_VALID, OPT_DNSSEC_VALIDATE, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
420#ifdef HAVE_DNSSEC
421 { LOPT_SEC_VALID, OPT_DNSSEC_VALIDATE, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
422#endif
Simon Kelleyc6309242013-03-07 20:59:28 +0000423#ifdef OPTION6_PREFIX_CLASS
424 { LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
425#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100426 { 0, 0, NULL, NULL, NULL }
Simon Kelleyb8187c82005-11-26 21:46:27 +0000427};
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000428
Simon Kelley3d8df262005-08-29 12:19:27 +0100429/* We hide metacharaters in quoted strings by mapping them into the ASCII control
Simon Kelleyf2621c72007-04-29 19:47:21 +0100430 character space. Note that the \0, \t \b \r \033 and \n characters are carefully placed in the
Simon Kelley3d8df262005-08-29 12:19:27 +0100431 following sequence so that they map to themselves: it is therefore possible to call
432 unhide_metas repeatedly on string without breaking things.
Simon Kelley824af852008-02-12 20:43:05 +0000433 The transformation gets undone by opt_canonicalise, atoi_check and opt_string_alloc, and a
Simon Kelleyf2621c72007-04-29 19:47:21 +0100434 couple of other places.
435 Note that space is included here so that
436 --dhcp-option=3, string
437 has five characters, whilst
438 --dhcp-option=3," string"
439 has six.
440*/
Simon Kelley3d8df262005-08-29 12:19:27 +0100441
Simon Kelleyf2621c72007-04-29 19:47:21 +0100442static const char meta[] = "\000123456 \b\t\n78\r90abcdefABCDE\033F:,.";
Simon Kelley3d8df262005-08-29 12:19:27 +0100443
444static char hide_meta(char c)
445{
446 unsigned int i;
447
448 for (i = 0; i < (sizeof(meta) - 1); i++)
449 if (c == meta[i])
450 return (char)i;
451
452 return c;
453}
454
455static char unhide_meta(char cr)
456{
457 unsigned int c = cr;
458
459 if (c < (sizeof(meta) - 1))
460 cr = meta[c];
461
462 return cr;
463}
464
465static void unhide_metas(char *cp)
466{
467 if (cp)
468 for(; *cp; cp++)
469 *cp = unhide_meta(*cp);
470}
471
Simon Kelley824af852008-02-12 20:43:05 +0000472static void *opt_malloc(size_t size)
473{
474 void *ret;
475
476 if (mem_recover)
477 {
478 ret = whine_malloc(size);
479 if (!ret)
480 longjmp(mem_jmp, 1);
481 }
482 else
483 ret = safe_malloc(size);
484
485 return ret;
486}
487
488static char *opt_string_alloc(char *cp)
Simon Kelley3d8df262005-08-29 12:19:27 +0100489{
490 char *ret = NULL;
491
492 if (cp && strlen(cp) != 0)
493 {
Simon Kelley824af852008-02-12 20:43:05 +0000494 ret = opt_malloc(strlen(cp)+1);
Simon Kelley3d8df262005-08-29 12:19:27 +0100495 strcpy(ret, cp);
496
497 /* restore hidden metachars */
498 unhide_metas(ret);
499 }
500
501 return ret;
502}
503
Simon Kelley3d8df262005-08-29 12:19:27 +0100504
Simon Kelleyf2621c72007-04-29 19:47:21 +0100505/* find next comma, split string with zero and eliminate spaces.
506 return start of string following comma */
Simon Kelley73a08a22009-02-05 20:28:08 +0000507
508static char *split_chr(char *s, char c)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100509{
510 char *comma, *p;
511
Simon Kelley73a08a22009-02-05 20:28:08 +0000512 if (!s || !(comma = strchr(s, c)))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100513 return NULL;
514
515 p = comma;
516 *comma = ' ';
517
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100518 for (; *comma == ' '; comma++);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100519
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100520 for (; (p >= s) && *p == ' '; p--)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100521 *p = 0;
522
523 return comma;
Simon Kelley3d8df262005-08-29 12:19:27 +0100524}
525
Simon Kelley73a08a22009-02-05 20:28:08 +0000526static char *split(char *s)
527{
528 return split_chr(s, ',');
529}
530
Simon Kelley1f15b812009-10-13 17:49:32 +0100531static char *canonicalise_opt(char *s)
Simon Kelley3d8df262005-08-29 12:19:27 +0100532{
Simon Kelley1f15b812009-10-13 17:49:32 +0100533 char *ret;
534 int nomem;
535
Simon Kelley3d8df262005-08-29 12:19:27 +0100536 if (!s)
537 return 0;
538
539 unhide_metas(s);
Simon Kelley1f15b812009-10-13 17:49:32 +0100540 if (!(ret = canonicalise(s, &nomem)) && nomem)
541 {
542 if (mem_recover)
543 longjmp(mem_jmp, 1);
544 else
545 die(_("could not get memory"), NULL, EC_NOMEM);
546 }
547
548 return ret;
Simon Kelley3d8df262005-08-29 12:19:27 +0100549}
550
551static int atoi_check(char *a, int *res)
552{
553 char *p;
554
555 if (!a)
556 return 0;
557
558 unhide_metas(a);
559
560 for (p = a; *p; p++)
561 if (*p < '0' || *p > '9')
562 return 0;
563
564 *res = atoi(a);
565 return 1;
566}
567
Simon Kelley1ad24ae2008-07-20 20:22:50 +0100568static int atoi_check16(char *a, int *res)
569{
570 if (!(atoi_check(a, res)) ||
571 *res < 0 ||
572 *res > 0xffff)
573 return 0;
574
575 return 1;
576}
577
Simon Kelley5aabfc72007-08-29 11:24:47 +0100578static void add_txt(char *name, char *txt)
Simon Kelley0a852542005-03-23 20:28:59 +0000579{
580 size_t len = strlen(txt);
Simon Kelley824af852008-02-12 20:43:05 +0000581 struct txt_record *r = opt_malloc(sizeof(struct txt_record));
Simon Kelley0a852542005-03-23 20:28:59 +0000582
Simon Kelley824af852008-02-12 20:43:05 +0000583 r->name = opt_string_alloc(name);
Simon Kelley0a852542005-03-23 20:28:59 +0000584 r->next = daemon->txt;
585 daemon->txt = r;
586 r->class = C_CHAOS;
Simon Kelley824af852008-02-12 20:43:05 +0000587 r->txt = opt_malloc(len+1);
Simon Kelley0a852542005-03-23 20:28:59 +0000588 r->len = len+1;
589 *(r->txt) = len;
590 memcpy((r->txt)+1, txt, len);
591}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000592
Simon Kelley849a8352006-06-09 21:02:31 +0100593static void do_usage(void)
594{
595 char buff[100];
Simon Kelley832af0b2007-01-21 20:01:28 +0000596 int i, j;
597
598 struct {
599 char handle;
600 int val;
601 } tab[] = {
602 { '$', CACHESIZ },
603 { '*', EDNS_PKTSZ },
604 { '&', MAXLEASES },
605 { '!', FTABSIZ },
606 { '#', TFTP_MAX_CONNECTIONS },
607 { '\0', 0 }
608 };
Simon Kelley849a8352006-06-09 21:02:31 +0100609
610 printf(_("Usage: dnsmasq [options]\n\n"));
611#ifndef HAVE_GETOPT_LONG
612 printf(_("Use short options only on the command line.\n"));
613#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100614 printf(_("Valid options are:\n"));
Simon Kelley849a8352006-06-09 21:02:31 +0100615
Simon Kelley1a6bca82008-07-11 11:11:42 +0100616 for (i = 0; usage[i].opt != 0; i++)
Simon Kelley849a8352006-06-09 21:02:31 +0100617 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100618 char *desc = usage[i].flagdesc;
619 char *eq = "=";
620
621 if (!desc || *desc == '[')
622 eq = "";
623
624 if (!desc)
625 desc = "";
626
627 for ( j = 0; opts[j].name; j++)
628 if (opts[j].val == usage[i].opt)
629 break;
630 if (usage[i].opt < 256)
631 sprintf(buff, "-%c, ", usage[i].opt);
632 else
633 sprintf(buff, " ");
634
635 sprintf(buff+4, "--%s%s%s", opts[j].name, eq, desc);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100636 printf("%-40.40s", buff);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100637
Simon Kelley849a8352006-06-09 21:02:31 +0100638 if (usage[i].arg)
639 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000640 strcpy(buff, usage[i].arg);
641 for (j = 0; tab[j].handle; j++)
642 if (tab[j].handle == *(usage[i].arg))
643 sprintf(buff, "%d", tab[j].val);
Simon Kelley849a8352006-06-09 21:02:31 +0100644 }
Simon Kelley849a8352006-06-09 21:02:31 +0100645 printf(_(usage[i].desc), buff);
646 printf("\n");
647 }
648}
649
Simon Kelleyc740e4f2012-08-09 16:19:01 +0100650#define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
651
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100652char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags)
653{
654 int source_port = 0, serv_port = NAMESERVER_PORT;
655 char *portno, *source;
656#ifdef HAVE_IPV6
657 int scope_index = 0;
658 char *scope_id;
659#endif
660
661 if ((source = split_chr(arg, '@')) && /* is there a source. */
662 (portno = split_chr(source, '#')) &&
663 !atoi_check16(portno, &source_port))
664 return _("bad port");
665
666 if ((portno = split_chr(arg, '#')) && /* is there a port no. */
667 !atoi_check16(portno, &serv_port))
668 return _("bad port");
669
670#ifdef HAVE_IPV6
671 scope_id = split_chr(arg, '%');
672#endif
673
Simon Kelleyddd9a6b2013-04-29 17:00:21 +0100674 if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100675 {
676 addr->in.sin_port = htons(serv_port);
677 addr->sa.sa_family = source_addr->sa.sa_family = AF_INET;
678#ifdef HAVE_SOCKADDR_SA_LEN
679 source_addr->in.sin_len = addr->in.sin_len = sizeof(struct sockaddr_in);
680#endif
681 source_addr->in.sin_addr.s_addr = INADDR_ANY;
682 source_addr->in.sin_port = htons(daemon->query_port);
683
684 if (source)
685 {
686 if (flags)
687 *flags |= SERV_HAS_SOURCE;
688 source_addr->in.sin_port = htons(source_port);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +0100689 if (!(inet_pton(AF_INET, source, &source_addr->in.sin_addr) > 0))
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100690 {
691#if defined(SO_BINDTODEVICE)
692 source_addr->in.sin_addr.s_addr = INADDR_ANY;
693 strncpy(interface, source, IF_NAMESIZE - 1);
694#else
695 return _("interface binding not supported");
696#endif
697 }
698 }
699 }
700#ifdef HAVE_IPV6
701 else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
702 {
703 if (scope_id && (scope_index = if_nametoindex(scope_id)) == 0)
704 return _("bad interface name");
705
706 addr->in6.sin6_port = htons(serv_port);
707 addr->in6.sin6_scope_id = scope_index;
708 source_addr->in6.sin6_addr = in6addr_any;
709 source_addr->in6.sin6_port = htons(daemon->query_port);
710 source_addr->in6.sin6_scope_id = 0;
711 addr->sa.sa_family = source_addr->sa.sa_family = AF_INET6;
712 addr->in6.sin6_flowinfo = source_addr->in6.sin6_flowinfo = 0;
713#ifdef HAVE_SOCKADDR_SA_LEN
714 addr->in6.sin6_len = source_addr->in6.sin6_len = sizeof(addr->in6);
715#endif
716 if (source)
717 {
718 if (flags)
719 *flags |= SERV_HAS_SOURCE;
720 source_addr->in6.sin6_port = htons(source_port);
721 if (inet_pton(AF_INET6, source, &source_addr->in6.sin6_addr) == 0)
722 {
723#if defined(SO_BINDTODEVICE)
724 source_addr->in6.sin6_addr = in6addr_any;
725 strncpy(interface, source, IF_NAMESIZE - 1);
726#else
727 return _("interface binding not supported");
728#endif
729 }
730 }
731 }
732#endif
733 else
734 return _("bad address");
735
736 return NULL;
737}
738
Simon Kelleyb5a8dd12012-12-10 11:37:25 +0000739#ifdef HAVE_DHCP
740
741static int is_tag_prefix(char *arg)
742{
743 if (arg && (strstr(arg, "net:") == arg || strstr(arg, "tag:") == arg))
744 return 1;
745
746 return 0;
747}
748
749static char *set_prefix(char *arg)
750{
751 if (strstr(arg, "set:") == arg)
752 return arg+4;
753
754 return arg;
755}
756
Simon Kelley832af0b2007-01-21 20:01:28 +0000757/* This is too insanely large to keep in-line in the switch */
Simon Kelleyc4a7f902012-07-12 20:52:12 +0100758static int parse_dhcp_opt(char *errstr, char *arg, int flags)
Simon Kelley832af0b2007-01-21 20:01:28 +0000759{
Simon Kelley824af852008-02-12 20:43:05 +0000760 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
Simon Kelley832af0b2007-01-21 20:01:28 +0000761 char lenchar = 0, *cp;
Simon Kelley40ef23b2012-03-13 21:59:28 +0000762 int addrs, digs, is_addr, is_addr6, is_hex, is_dec, is_string, dots;
Simon Kelleyc4a7f902012-07-12 20:52:12 +0100763 char *comma = NULL;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100764 struct dhcp_netid *np = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000765 u16 opt_len = 0;
766 int is6 = 0;
Simon Kelleybd08ae62013-04-19 10:22:06 +0100767 int option_ok = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000768
769 new->len = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000770 new->flags = flags;
Simon Kelley832af0b2007-01-21 20:01:28 +0000771 new->netid = NULL;
772 new->val = NULL;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100773 new->opt = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000774
Simon Kelleyf2621c72007-04-29 19:47:21 +0100775 while (arg)
Simon Kelley832af0b2007-01-21 20:01:28 +0000776 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100777 comma = split(arg);
778
779 for (cp = arg; *cp; cp++)
780 if (*cp < '0' || *cp > '9')
Simon Kelley832af0b2007-01-21 20:01:28 +0000781 break;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100782
783 if (!*cp)
784 {
785 new->opt = atoi(arg);
786 opt_len = 0;
Simon Kelleybd08ae62013-04-19 10:22:06 +0100787 option_ok = 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100788 break;
789 }
790
791 if (strstr(arg, "option:") == arg)
792 {
Simon Kelleybd08ae62013-04-19 10:22:06 +0100793 if ((new->opt = lookup_dhcp_opt(AF_INET, arg+7)) != -1)
794 {
795 opt_len = lookup_dhcp_len(AF_INET, new->opt);
796 /* option:<optname> must follow tag and vendor string. */
797 if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
798 option_ok = 1;
799 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100800 break;
801 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000802#ifdef HAVE_DHCP6
803 else if (strstr(arg, "option6:") == arg)
804 {
805 for (cp = arg+8; *cp; cp++)
806 if (*cp < '0' || *cp > '9')
807 break;
808
809 if (!*cp)
810 {
811 new->opt = atoi(arg+8);
812 opt_len = 0;
Simon Kelleybd08ae62013-04-19 10:22:06 +0100813 option_ok = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000814 }
815 else
Simon Kelley40ef23b2012-03-13 21:59:28 +0000816 {
Simon Kelleybd08ae62013-04-19 10:22:06 +0100817 if ((new->opt = lookup_dhcp_opt(AF_INET6, arg+8)) != -1)
818 {
819 opt_len = lookup_dhcp_len(AF_INET6, new->opt);
820 if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
821 option_ok = 1;
822 }
Simon Kelley40ef23b2012-03-13 21:59:28 +0000823 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000824 /* option6:<opt>|<optname> must follow tag and vendor string. */
825 is6 = 1;
826 break;
827 }
828#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +0100829 else if (strstr(arg, "vendor:") == arg)
830 {
Simon Kelley73a08a22009-02-05 20:28:08 +0000831 new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7);
832 new->flags |= DHOPT_VENDOR;
833 }
834 else if (strstr(arg, "encap:") == arg)
835 {
836 new->u.encap = atoi(arg+6);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100837 new->flags |= DHOPT_ENCAPSULATE;
838 }
Simon Kelley316e2732010-01-22 20:16:09 +0000839 else if (strstr(arg, "vi-encap:") == arg)
840 {
841 new->u.encap = atoi(arg+9);
842 new->flags |= DHOPT_RFC3925;
843 if (flags == DHOPT_MATCH)
844 {
Simon Kelleybd08ae62013-04-19 10:22:06 +0100845 option_ok = 1;
Simon Kelley316e2732010-01-22 20:16:09 +0000846 break;
847 }
848 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100849 else
850 {
Simon Kelley824af852008-02-12 20:43:05 +0000851 new->netid = opt_malloc(sizeof (struct dhcp_netid));
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100852 /* allow optional "net:" or "tag:" for consistency */
853 if (is_tag_prefix(arg))
Simon Kelley824af852008-02-12 20:43:05 +0000854 new->netid->net = opt_string_alloc(arg+4);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100855 else
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100856 new->netid->net = opt_string_alloc(set_prefix(arg));
Simon Kelleyf2621c72007-04-29 19:47:21 +0100857 new->netid->next = np;
858 np = new->netid;
859 }
860
861 arg = comma;
Simon Kelley832af0b2007-01-21 20:01:28 +0000862 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000863
864#ifdef HAVE_DHCP6
865 if (is6)
866 {
867 if (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))
Simon Kelleyc4a7f902012-07-12 20:52:12 +0100868 ret_err(_("unsupported encapsulation for IPv6 option"));
Simon Kelley4cb1b322012-02-06 14:30:41 +0000869
870 if (opt_len == 0 &&
871 !(new->flags & DHOPT_RFC3925))
Simon Kelleybd08ae62013-04-19 10:22:06 +0100872 opt_len = lookup_dhcp_len(AF_INET6, new->opt);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000873 }
874 else
875#endif
876 if (opt_len == 0 &&
877 !(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
Simon Kelleybd08ae62013-04-19 10:22:06 +0100878 opt_len = lookup_dhcp_len(AF_INET, new->opt);
Simon Kelley40ef23b2012-03-13 21:59:28 +0000879
Simon Kelley316e2732010-01-22 20:16:09 +0000880 /* option may be missing with rfc3925 match */
Simon Kelleybd08ae62013-04-19 10:22:06 +0100881 if (!option_ok)
Simon Kelleyc4a7f902012-07-12 20:52:12 +0100882 ret_err(_("bad dhcp-option"));
883
884 if (comma)
Simon Kelley832af0b2007-01-21 20:01:28 +0000885 {
886 /* characterise the value */
Simon Kelleyf2621c72007-04-29 19:47:21 +0100887 char c;
Simon Kelley28866e92011-02-14 20:19:14 +0000888 int found_dig = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000889 is_addr = is_addr6 = is_hex = is_dec = is_string = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000890 addrs = digs = 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100891 dots = 0;
892 for (cp = comma; (c = *cp); cp++)
893 if (c == ',')
Simon Kelley832af0b2007-01-21 20:01:28 +0000894 {
895 addrs++;
896 is_dec = is_hex = 0;
897 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100898 else if (c == ':')
Simon Kelley832af0b2007-01-21 20:01:28 +0000899 {
900 digs++;
901 is_dec = is_addr = 0;
902 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100903 else if (c == '/')
Simon Kelley832af0b2007-01-21 20:01:28 +0000904 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000905 is_addr6 = is_dec = is_hex = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000906 if (cp == comma) /* leading / means a pathname */
907 is_addr = 0;
908 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100909 else if (c == '.')
910 {
Simon Kelley23245c02012-07-18 16:21:11 +0100911 is_addr6 = is_dec = is_hex = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100912 dots++;
913 }
914 else if (c == '-')
Simon Kelley4cb1b322012-02-06 14:30:41 +0000915 is_hex = is_addr = is_addr6 = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100916 else if (c == ' ')
Simon Kelley832af0b2007-01-21 20:01:28 +0000917 is_dec = is_hex = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100918 else if (!(c >='0' && c <= '9'))
Simon Kelley832af0b2007-01-21 20:01:28 +0000919 {
920 is_addr = 0;
921 if (cp[1] == 0 && is_dec &&
Simon Kelleyf2621c72007-04-29 19:47:21 +0100922 (c == 'b' || c == 's' || c == 'i'))
Simon Kelley832af0b2007-01-21 20:01:28 +0000923 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100924 lenchar = c;
Simon Kelley832af0b2007-01-21 20:01:28 +0000925 *cp = 0;
926 }
927 else
928 is_dec = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100929 if (!((c >='A' && c <= 'F') ||
Simon Kelley73a08a22009-02-05 20:28:08 +0000930 (c >='a' && c <= 'f') ||
931 (c == '*' && (flags & DHOPT_MATCH))))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000932 {
933 is_hex = 0;
934 if (c != '[' && c != ']')
935 is_addr6 = 0;
936 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000937 }
Simon Kelley28866e92011-02-14 20:19:14 +0000938 else
939 found_dig = 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100940
Simon Kelley28866e92011-02-14 20:19:14 +0000941 if (!found_dig)
942 is_dec = is_addr = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000943
Simon Kelleyf2621c72007-04-29 19:47:21 +0100944 /* We know that some options take addresses */
Simon Kelley7622fc02009-06-04 20:32:05 +0100945 if (opt_len & OT_ADDR_LIST)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100946 {
947 is_string = is_dec = is_hex = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000948
949 if (!is6 && (!is_addr || dots == 0))
Simon Kelleyc4a7f902012-07-12 20:52:12 +0100950 ret_err(_("bad IP address"));
Simon Kelley4cb1b322012-02-06 14:30:41 +0000951
952 if (is6 && !is_addr6)
Simon Kelleyc4a7f902012-07-12 20:52:12 +0100953 ret_err(_("bad IPv6 address"));
Simon Kelleyf2621c72007-04-29 19:47:21 +0100954 }
Simon Kelley28866e92011-02-14 20:19:14 +0000955 /* or names */
Simon Kelley4cb1b322012-02-06 14:30:41 +0000956 else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING))
957 is_addr6 = is_addr = is_dec = is_hex = 0;
Simon Kelley23245c02012-07-18 16:21:11 +0100958
959 if (found_dig && (opt_len & OT_TIME) && strlen(comma) > 0)
960 {
961 int val, fac = 1;
962
963 switch (comma[strlen(comma) - 1])
964 {
Simon Kelley42243212012-07-20 15:19:18 +0100965 case 'w':
966 case 'W':
967 fac *= 7;
968 /* fall through */
Simon Kelley23245c02012-07-18 16:21:11 +0100969 case 'd':
970 case 'D':
971 fac *= 24;
972 /* fall though */
973 case 'h':
974 case 'H':
975 fac *= 60;
976 /* fall through */
977 case 'm':
978 case 'M':
979 fac *= 60;
980 /* fall through */
981 case 's':
982 case 'S':
983 comma[strlen(comma) - 1] = 0;
984 }
985
986 new->len = 4;
987 new->val = opt_malloc(4);
988 val = atoi(comma);
989 *((int *)new->val) = htonl(val * fac);
990 }
991 else if (is_hex && digs > 1)
Simon Kelley832af0b2007-01-21 20:01:28 +0000992 {
993 new->len = digs;
Simon Kelley824af852008-02-12 20:43:05 +0000994 new->val = opt_malloc(new->len);
Simon Kelley73a08a22009-02-05 20:28:08 +0000995 parse_hex(comma, new->val, digs, (flags & DHOPT_MATCH) ? &new->u.wildcard_mask : NULL, NULL);
996 new->flags |= DHOPT_HEX;
Simon Kelley832af0b2007-01-21 20:01:28 +0000997 }
998 else if (is_dec)
999 {
1000 int i, val = atoi(comma);
1001 /* assume numeric arg is 1 byte except for
1002 options where it is known otherwise.
1003 For vendor class option, we have to hack. */
Simon Kelleyf2621c72007-04-29 19:47:21 +01001004 if (opt_len != 0)
1005 new->len = opt_len;
1006 else if (val & 0xffff0000)
1007 new->len = 4;
1008 else if (val & 0xff00)
1009 new->len = 2;
1010 else
1011 new->len = 1;
1012
Simon Kelley832af0b2007-01-21 20:01:28 +00001013 if (lenchar == 'b')
1014 new->len = 1;
1015 else if (lenchar == 's')
1016 new->len = 2;
1017 else if (lenchar == 'i')
1018 new->len = 4;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001019
Simon Kelley824af852008-02-12 20:43:05 +00001020 new->val = opt_malloc(new->len);
Simon Kelley832af0b2007-01-21 20:01:28 +00001021 for (i=0; i<new->len; i++)
1022 new->val[i] = val>>((new->len - i - 1)*8);
1023 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001024 else if (is_addr && !is6)
Simon Kelley832af0b2007-01-21 20:01:28 +00001025 {
1026 struct in_addr in;
1027 unsigned char *op;
1028 char *slash;
1029 /* max length of address/subnet descriptor is five bytes,
1030 add one for the option 120 enc byte too */
Simon Kelley824af852008-02-12 20:43:05 +00001031 new->val = op = opt_malloc((5 * addrs) + 1);
Simon Kelley6b010842007-02-12 20:32:07 +00001032 new->flags |= DHOPT_ADDR;
1033
Simon Kelley572b41e2011-02-18 18:11:18 +00001034 if (!(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
1035 new->opt == OPTION_SIP_SERVER)
Simon Kelley832af0b2007-01-21 20:01:28 +00001036 {
Simon Kelley6b010842007-02-12 20:32:07 +00001037 *(op++) = 1; /* RFC 3361 "enc byte" */
1038 new->flags &= ~DHOPT_ADDR;
Simon Kelley832af0b2007-01-21 20:01:28 +00001039 }
1040 while (addrs--)
1041 {
1042 cp = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001043 comma = split(cp);
Simon Kelley73a08a22009-02-05 20:28:08 +00001044 slash = split_chr(cp, '/');
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01001045 inet_pton(AF_INET, cp, &in);
Simon Kelley832af0b2007-01-21 20:01:28 +00001046 if (!slash)
1047 {
1048 memcpy(op, &in, INADDRSZ);
1049 op += INADDRSZ;
1050 }
1051 else
1052 {
1053 unsigned char *p = (unsigned char *)&in;
1054 int netsize = atoi(slash);
1055 *op++ = netsize;
1056 if (netsize > 0)
1057 *op++ = *p++;
1058 if (netsize > 8)
1059 *op++ = *p++;
1060 if (netsize > 16)
1061 *op++ = *p++;
1062 if (netsize > 24)
1063 *op++ = *p++;
1064 new->flags &= ~DHOPT_ADDR; /* cannot re-write descriptor format */
1065 }
1066 }
1067 new->len = op - new->val;
1068 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001069 else if (is_addr6 && is6)
1070 {
1071 unsigned char *op;
1072 new->val = op = opt_malloc(16 * addrs);
1073 new->flags |= DHOPT_ADDR6;
1074 while (addrs--)
1075 {
1076 cp = comma;
1077 comma = split(cp);
1078
1079 /* check for [1234::7] */
1080 if (*cp == '[')
1081 cp++;
1082 if (strlen(cp) > 1 && cp[strlen(cp)-1] == ']')
1083 cp[strlen(cp)-1] = 0;
1084
1085 if (inet_pton(AF_INET6, cp, op))
1086 {
1087 op += IN6ADDRSZ;
1088 continue;
1089 }
1090
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001091 ret_err(_("bad IPv6 address"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001092 }
1093 new->len = op - new->val;
1094 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001095 else if (is_string)
Simon Kelley832af0b2007-01-21 20:01:28 +00001096 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001097 /* text arg */
Simon Kelley572b41e2011-02-18 18:11:18 +00001098 if ((new->opt == OPTION_DOMAIN_SEARCH || new->opt == OPTION_SIP_SERVER) &&
Simon Kelley4cb1b322012-02-06 14:30:41 +00001099 !is6 && !(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
Simon Kelley832af0b2007-01-21 20:01:28 +00001100 {
1101 /* dns search, RFC 3397, or SIP, RFC 3361 */
1102 unsigned char *q, *r, *tail;
Simon Kelley824af852008-02-12 20:43:05 +00001103 unsigned char *p, *m = NULL, *newp;
Simon Kelley832af0b2007-01-21 20:01:28 +00001104 size_t newlen, len = 0;
Simon Kelley572b41e2011-02-18 18:11:18 +00001105 int header_size = (new->opt == OPTION_DOMAIN_SEARCH) ? 0 : 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001106
1107 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001108 comma = split(arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00001109
1110 while (arg && *arg)
1111 {
Simon Kelleyc52e1892010-06-07 22:01:39 +01001112 char *in, *dom = NULL;
1113 size_t domlen = 1;
1114 /* Allow "." as an empty domain */
1115 if (strcmp (arg, ".") != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001116 {
Simon Kelleyc52e1892010-06-07 22:01:39 +01001117 if (!(dom = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001118 ret_err(_("bad domain in dhcp-option"));
1119
Simon Kelleyc52e1892010-06-07 22:01:39 +01001120 domlen = strlen(dom) + 2;
Simon Kelley832af0b2007-01-21 20:01:28 +00001121 }
Simon Kelleyc52e1892010-06-07 22:01:39 +01001122
1123 newp = opt_malloc(len + domlen + header_size);
Simon Kelley824af852008-02-12 20:43:05 +00001124 if (m)
Simon Kelleyc52e1892010-06-07 22:01:39 +01001125 {
1126 memcpy(newp, m, header_size + len);
1127 free(m);
1128 }
Simon Kelley824af852008-02-12 20:43:05 +00001129 m = newp;
Simon Kelley832af0b2007-01-21 20:01:28 +00001130 p = m + header_size;
1131 q = p + len;
1132
1133 /* add string on the end in RFC1035 format */
Simon Kelleyc52e1892010-06-07 22:01:39 +01001134 for (in = dom; in && *in;)
Simon Kelley832af0b2007-01-21 20:01:28 +00001135 {
1136 unsigned char *cp = q++;
1137 int j;
Simon Kelleyc52e1892010-06-07 22:01:39 +01001138 for (j = 0; *in && (*in != '.'); in++, j++)
1139 *q++ = *in;
Simon Kelley832af0b2007-01-21 20:01:28 +00001140 *cp = j;
Simon Kelleyc52e1892010-06-07 22:01:39 +01001141 if (*in)
1142 in++;
Simon Kelley832af0b2007-01-21 20:01:28 +00001143 }
1144 *q++ = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +01001145 free(dom);
Simon Kelleyc52e1892010-06-07 22:01:39 +01001146
Simon Kelley832af0b2007-01-21 20:01:28 +00001147 /* Now tail-compress using earlier names. */
1148 newlen = q - p;
1149 for (tail = p + len; *tail; tail += (*tail) + 1)
1150 for (r = p; r - p < (int)len; r += (*r) + 1)
1151 if (strcmp((char *)r, (char *)tail) == 0)
1152 {
1153 PUTSHORT((r - p) | 0xc000, tail);
1154 newlen = tail - p;
1155 goto end;
1156 }
1157 end:
1158 len = newlen;
1159
1160 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001161 comma = split(arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00001162 }
1163
1164 /* RFC 3361, enc byte is zero for names */
Simon Kelley572b41e2011-02-18 18:11:18 +00001165 if (new->opt == OPTION_SIP_SERVER)
Simon Kelley832af0b2007-01-21 20:01:28 +00001166 m[0] = 0;
1167 new->len = (int) len + header_size;
1168 new->val = m;
1169 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001170#ifdef HAVE_DHCP6
1171 else if (comma && (opt_len & OT_CSTRING))
1172 {
1173 /* length fields are two bytes so need 16 bits for each string */
Simon Kelley40ef23b2012-03-13 21:59:28 +00001174 int i, commas = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001175 unsigned char *p, *newp;
1176
Simon Kelley40ef23b2012-03-13 21:59:28 +00001177 for (i = 0; comma[i]; i++)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001178 if (comma[i] == ',')
1179 commas++;
1180
1181 newp = opt_malloc(strlen(comma)+(2*commas));
1182 p = newp;
1183 arg = comma;
1184 comma = split(arg);
1185
1186 while (arg && *arg)
1187 {
1188 u16 len = strlen(arg);
Simon Kelley18f0fb02012-03-31 21:18:55 +01001189 unhide_metas(arg);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001190 PUTSHORT(len, p);
1191 memcpy(p, arg, len);
1192 p += len;
1193
1194 arg = comma;
1195 comma = split(arg);
1196 }
1197
1198 new->val = newp;
1199 new->len = p - newp;
1200 }
1201 else if (comma && (opt_len & OT_RFC1035_NAME))
1202 {
Simon Kelley18f0fb02012-03-31 21:18:55 +01001203 unsigned char *p = NULL, *newp, *end;
1204 int len = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001205 arg = comma;
1206 comma = split(arg);
1207
1208 while (arg && *arg)
1209 {
Simon Kelley18f0fb02012-03-31 21:18:55 +01001210 char *dom = canonicalise_opt(arg);
1211 if (!dom)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001212 ret_err(_("bad domain in dhcp-option"));
1213
Simon Kelley18f0fb02012-03-31 21:18:55 +01001214 newp = opt_malloc(len + strlen(dom) + 2);
1215
1216 if (p)
1217 {
1218 memcpy(newp, p, len);
1219 free(p);
1220 }
1221
1222 p = newp;
1223 end = do_rfc1035_name(p + len, dom);
1224 *end++ = 0;
1225 len = end - p;
1226 free(dom);
1227
Simon Kelley4cb1b322012-02-06 14:30:41 +00001228 arg = comma;
1229 comma = split(arg);
1230 }
1231
Simon Kelley18f0fb02012-03-31 21:18:55 +01001232 new->val = p;
1233 new->len = len;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001234 }
1235#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001236 else
1237 {
1238 new->len = strlen(comma);
1239 /* keep terminating zero on string */
Simon Kelley824af852008-02-12 20:43:05 +00001240 new->val = (unsigned char *)opt_string_alloc(comma);
Simon Kelley832af0b2007-01-21 20:01:28 +00001241 new->flags |= DHOPT_STRING;
1242 }
1243 }
1244 }
1245
Simon Kelley4cb1b322012-02-06 14:30:41 +00001246 if (!is6 &&
1247 ((new->len > 255) ||
Simon Kelley316e2732010-01-22 20:16:09 +00001248 (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) ||
Simon Kelley4cb1b322012-02-06 14:30:41 +00001249 (new->len > 250 && (new->flags & DHOPT_RFC3925))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001250 ret_err(_("dhcp-option too long"));
Simon Kelley832af0b2007-01-21 20:01:28 +00001251
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001252 if (flags == DHOPT_MATCH)
Simon Kelley824af852008-02-12 20:43:05 +00001253 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001254 if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||
1255 !new->netid ||
1256 new->netid->next)
1257 ret_err(_("illegal dhcp-match"));
1258
1259 if (is6)
Simon Kelley73a08a22009-02-05 20:28:08 +00001260 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001261 new->next = daemon->dhcp_match6;
1262 daemon->dhcp_match6 = new;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001263 }
1264 else
Simon Kelley73a08a22009-02-05 20:28:08 +00001265 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001266 new->next = daemon->dhcp_match;
1267 daemon->dhcp_match = new;
Simon Kelley73a08a22009-02-05 20:28:08 +00001268 }
Simon Kelley824af852008-02-12 20:43:05 +00001269 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001270 else if (is6)
1271 {
1272 new->next = daemon->dhcp_opts6;
1273 daemon->dhcp_opts6 = new;
1274 }
1275 else
1276 {
1277 new->next = daemon->dhcp_opts;
1278 daemon->dhcp_opts = new;
1279 }
1280
1281 return 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001282}
1283
Simon Kelley7622fc02009-06-04 20:32:05 +01001284#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001285
Simon Kelley28866e92011-02-14 20:19:14 +00001286void set_option_bool(unsigned int opt)
1287{
1288 if (opt < 32)
1289 daemon->options |= 1u << opt;
1290 else
1291 daemon->options2 |= 1u << (opt - 32);
1292}
1293
Simon Kelley2b5bae92012-06-26 16:55:23 +01001294void reset_option_bool(unsigned int opt)
1295{
1296 if (opt < 32)
1297 daemon->options &= ~(1u << opt);
1298 else
1299 daemon->options2 &= ~(1u << (opt - 32));
1300}
1301
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001302static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line)
Simon Kelley849a8352006-06-09 21:02:31 +01001303{
1304 int i;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001305 char *comma;
Simon Kelley849a8352006-06-09 21:02:31 +01001306
Simon Kelley832af0b2007-01-21 20:01:28 +00001307 if (option == '?')
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001308 ret_err(gen_err);
Simon Kelley832af0b2007-01-21 20:01:28 +00001309
Simon Kelley1a6bca82008-07-11 11:11:42 +01001310 for (i=0; usage[i].opt != 0; i++)
1311 if (usage[i].opt == option)
Simon Kelley849a8352006-06-09 21:02:31 +01001312 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001313 int rept = usage[i].rept;
1314
Simon Kelley28866e92011-02-14 20:19:14 +00001315 if (command_line)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001316 {
1317 /* command line */
1318 if (rept == ARG_USED_CL)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001319 ret_err(_("illegal repeated flag"));
Simon Kelley1a6bca82008-07-11 11:11:42 +01001320 if (rept == ARG_ONE)
1321 usage[i].rept = ARG_USED_CL;
1322 }
1323 else
1324 {
1325 /* allow file to override command line */
1326 if (rept == ARG_USED_FILE)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001327 ret_err(_("illegal repeated keyword"));
Simon Kelley1a6bca82008-07-11 11:11:42 +01001328 if (rept == ARG_USED_CL || rept == ARG_ONE)
1329 usage[i].rept = ARG_USED_FILE;
1330 }
1331
1332 if (rept != ARG_DUP && rept != ARG_ONE && rept != ARG_USED_CL)
1333 {
Simon Kelley28866e92011-02-14 20:19:14 +00001334 set_option_bool(rept);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001335 return 1;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001336 }
1337
1338 break;
Simon Kelley849a8352006-06-09 21:02:31 +01001339 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001340
Simon Kelley849a8352006-06-09 21:02:31 +01001341 switch (option)
1342 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001343 case 'C': /* --conf-file */
Simon Kelley849a8352006-06-09 21:02:31 +01001344 {
Simon Kelley824af852008-02-12 20:43:05 +00001345 char *file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001346 if (file)
Simon Kelley9009d742008-11-14 20:04:27 +00001347 {
Simon Kelley28866e92011-02-14 20:19:14 +00001348 one_file(file, 0);
Simon Kelley9009d742008-11-14 20:04:27 +00001349 free(file);
1350 }
Simon Kelley849a8352006-06-09 21:02:31 +01001351 break;
1352 }
1353
Simon Kelleyf2621c72007-04-29 19:47:21 +01001354 case '7': /* --conf-dir */
Simon Kelley849a8352006-06-09 21:02:31 +01001355 {
1356 DIR *dir_stream;
1357 struct dirent *ent;
1358 char *directory, *path;
Simon Kelley1f15b812009-10-13 17:49:32 +01001359 struct list {
1360 char *suffix;
1361 struct list *next;
1362 } *ignore_suffix = NULL, *li;
Simon Kelley849a8352006-06-09 21:02:31 +01001363
Simon Kelley1f15b812009-10-13 17:49:32 +01001364 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00001365 if (!(directory = opt_string_alloc(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01001366 break;
1367
Simon Kelley1f15b812009-10-13 17:49:32 +01001368 for (arg = comma; arg; arg = comma)
1369 {
1370 comma = split(arg);
1371 li = opt_malloc(sizeof(struct list));
1372 li->next = ignore_suffix;
1373 ignore_suffix = li;
1374 /* Have to copy: buffer is overwritten */
1375 li->suffix = opt_string_alloc(arg);
1376 };
1377
Simon Kelley849a8352006-06-09 21:02:31 +01001378 if (!(dir_stream = opendir(directory)))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001379 die(_("cannot access directory %s: %s"), directory, EC_FILE);
Simon Kelley1f15b812009-10-13 17:49:32 +01001380
Simon Kelley849a8352006-06-09 21:02:31 +01001381 while ((ent = readdir(dir_stream)))
1382 {
Simon Kelley7622fc02009-06-04 20:32:05 +01001383 size_t len = strlen(ent->d_name);
Simon Kelley849a8352006-06-09 21:02:31 +01001384 struct stat buf;
Simon Kelley1f15b812009-10-13 17:49:32 +01001385
1386 /* ignore emacs backups and dotfiles */
Simon Kelley7622fc02009-06-04 20:32:05 +01001387 if (len == 0 ||
1388 ent->d_name[len - 1] == '~' ||
Simon Kelley849a8352006-06-09 21:02:31 +01001389 (ent->d_name[0] == '#' && ent->d_name[len - 1] == '#') ||
1390 ent->d_name[0] == '.')
1391 continue;
Simon Kelley7622fc02009-06-04 20:32:05 +01001392
Simon Kelley1f15b812009-10-13 17:49:32 +01001393 for (li = ignore_suffix; li; li = li->next)
1394 {
1395 /* check for proscribed suffices */
1396 size_t ls = strlen(li->suffix);
1397 if (len > ls &&
1398 strcmp(li->suffix, &ent->d_name[len - ls]) == 0)
1399 break;
1400 }
1401 if (li)
1402 continue;
1403
Simon Kelley824af852008-02-12 20:43:05 +00001404 path = opt_malloc(strlen(directory) + len + 2);
Simon Kelley849a8352006-06-09 21:02:31 +01001405 strcpy(path, directory);
1406 strcat(path, "/");
1407 strcat(path, ent->d_name);
Simon Kelley7622fc02009-06-04 20:32:05 +01001408
Simon Kelley39595cf2013-02-04 21:40:07 +00001409 /* files must be readable */
Simon Kelley849a8352006-06-09 21:02:31 +01001410 if (stat(path, &buf) == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001411 die(_("cannot access %s: %s"), path, EC_FILE);
Simon Kelley849a8352006-06-09 21:02:31 +01001412
Simon Kelley39595cf2013-02-04 21:40:07 +00001413 /* only reg files allowed. */
1414 if (S_ISREG(buf.st_mode))
1415 one_file(path, 0);
1416
Simon Kelley849a8352006-06-09 21:02:31 +01001417 free(path);
1418 }
1419
1420 closedir(dir_stream);
Simon Kelley9009d742008-11-14 20:04:27 +00001421 free(directory);
Simon Kelley1f15b812009-10-13 17:49:32 +01001422 for(; ignore_suffix; ignore_suffix = li)
1423 {
1424 li = ignore_suffix->next;
1425 free(ignore_suffix->suffix);
1426 free(ignore_suffix);
1427 }
1428
Simon Kelley849a8352006-06-09 21:02:31 +01001429 break;
1430 }
1431
Simon Kelleyad094272012-08-10 17:10:54 +01001432 case '1': /* --enable-dbus */
1433 set_option_bool(OPT_DBUS);
1434 if (arg)
1435 daemon->dbus_name = opt_string_alloc(arg);
1436 else
1437 daemon->dbus_name = DNSMASQ_SERVICE;
1438 break;
1439
Simon Kelleyf2621c72007-04-29 19:47:21 +01001440 case '8': /* --log-facility */
1441 /* may be a filename */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001442 if (strchr(arg, '/') || strcmp (arg, "-") == 0)
Simon Kelley824af852008-02-12 20:43:05 +00001443 daemon->log_file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001444 else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001445 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001446#ifdef __ANDROID__
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001447 ret_err(_("setting log facility is not possible under Android"));
Simon Kelley572b41e2011-02-18 18:11:18 +00001448#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001449 for (i = 0; facilitynames[i].c_name; i++)
1450 if (hostname_isequal((char *)facilitynames[i].c_name, arg))
1451 break;
1452
1453 if (facilitynames[i].c_name)
1454 daemon->log_fac = facilitynames[i].c_val;
1455 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001456 ret_err(_("bad log facility"));
Simon Kelley572b41e2011-02-18 18:11:18 +00001457#endif
Simon Kelley849a8352006-06-09 21:02:31 +01001458 }
1459 break;
1460
Simon Kelleyf2621c72007-04-29 19:47:21 +01001461 case 'x': /* --pid-file */
Simon Kelley824af852008-02-12 20:43:05 +00001462 daemon->runfile = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001463 break;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001464
Simon Kelleyf2621c72007-04-29 19:47:21 +01001465 case 'r': /* --resolv-file */
Simon Kelley849a8352006-06-09 21:02:31 +01001466 {
Simon Kelley824af852008-02-12 20:43:05 +00001467 char *name = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001468 struct resolvc *new, *list = daemon->resolv_files;
1469
1470 if (list && list->is_default)
1471 {
1472 /* replace default resolv file - possibly with nothing */
1473 if (name)
1474 {
1475 list->is_default = 0;
1476 list->name = name;
1477 }
1478 else
1479 list = NULL;
1480 }
1481 else if (name)
1482 {
Simon Kelley824af852008-02-12 20:43:05 +00001483 new = opt_malloc(sizeof(struct resolvc));
Simon Kelley849a8352006-06-09 21:02:31 +01001484 new->next = list;
1485 new->name = name;
1486 new->is_default = 0;
1487 new->mtime = 0;
1488 new->logged = 0;
1489 list = new;
1490 }
1491 daemon->resolv_files = list;
1492 break;
1493 }
1494
Simon Kelleyf2621c72007-04-29 19:47:21 +01001495 case 'm': /* --mx-host */
Simon Kelley849a8352006-06-09 21:02:31 +01001496 {
1497 int pref = 1;
1498 struct mx_srv_record *new;
Simon Kelley1f15b812009-10-13 17:49:32 +01001499 char *name, *target = NULL;
1500
Simon Kelleyf2621c72007-04-29 19:47:21 +01001501 if ((comma = split(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01001502 {
1503 char *prefstr;
Simon Kelley1f15b812009-10-13 17:49:32 +01001504 if ((prefstr = split(comma)) && !atoi_check16(prefstr, &pref))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001505 ret_err(_("bad MX preference"));
Simon Kelley849a8352006-06-09 21:02:31 +01001506 }
1507
Simon Kelley1f15b812009-10-13 17:49:32 +01001508 if (!(name = canonicalise_opt(arg)) ||
1509 (comma && !(target = canonicalise_opt(comma))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001510 ret_err(_("bad MX name"));
Simon Kelley1f15b812009-10-13 17:49:32 +01001511
Simon Kelley824af852008-02-12 20:43:05 +00001512 new = opt_malloc(sizeof(struct mx_srv_record));
Simon Kelley849a8352006-06-09 21:02:31 +01001513 new->next = daemon->mxnames;
1514 daemon->mxnames = new;
1515 new->issrv = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +01001516 new->name = name;
1517 new->target = target; /* may be NULL */
Simon Kelley849a8352006-06-09 21:02:31 +01001518 new->weight = pref;
1519 break;
1520 }
1521
Simon Kelleyf2621c72007-04-29 19:47:21 +01001522 case 't': /* --mx-target */
Simon Kelley1f15b812009-10-13 17:49:32 +01001523 if (!(daemon->mxtarget = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001524 ret_err(_("bad MX target"));
Simon Kelley849a8352006-06-09 21:02:31 +01001525 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01001526
1527#ifdef HAVE_DHCP
Simon Kelleyf2621c72007-04-29 19:47:21 +01001528 case 'l': /* --dhcp-leasefile */
Simon Kelley824af852008-02-12 20:43:05 +00001529 daemon->lease_file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001530 break;
1531
Simon Kelleyc72daea2012-01-05 21:33:27 +00001532 /* Sorry about the gross pre-processor abuse */
1533 case '6': /* --dhcp-script */
1534 case LOPT_LUASCRIPT: /* --dhcp-luascript */
Simon Kelley1f15b812009-10-13 17:49:32 +01001535# if defined(NO_FORK)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001536 ret_err(_("cannot run scripts under uClinux"));
Simon Kelley1f15b812009-10-13 17:49:32 +01001537# elif !defined(HAVE_SCRIPT)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001538 ret_err(_("recompile with HAVE_SCRIPT defined to enable lease-change scripts"));
Simon Kelley7622fc02009-06-04 20:32:05 +01001539# else
Simon Kelleyc72daea2012-01-05 21:33:27 +00001540 if (option == LOPT_LUASCRIPT)
1541# if !defined(HAVE_LUASCRIPT)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001542 ret_err(_("recompile with HAVE_LUASCRIPT defined to enable Lua scripts"));
Simon Kelleyc72daea2012-01-05 21:33:27 +00001543# else
1544 daemon->luascript = opt_string_alloc(arg);
1545# endif
1546 else
1547 daemon->lease_change_command = opt_string_alloc(arg);
Simon Kelley7622fc02009-06-04 20:32:05 +01001548# endif
Simon Kelley849a8352006-06-09 21:02:31 +01001549 break;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001550#endif /* HAVE_DHCP */
Simon Kelley7622fc02009-06-04 20:32:05 +01001551
Simon Kelley28866e92011-02-14 20:19:14 +00001552 case LOPT_DHCP_HOST: /* --dhcp-hostfile */
1553 case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
Simon Kelleyf2621c72007-04-29 19:47:21 +01001554 case 'H': /* --addn-hosts */
Simon Kelley849a8352006-06-09 21:02:31 +01001555 {
Simon Kelley824af852008-02-12 20:43:05 +00001556 struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
Simon Kelley849a8352006-06-09 21:02:31 +01001557 static int hosts_index = 1;
Simon Kelley824af852008-02-12 20:43:05 +00001558 new->fname = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001559 new->index = hosts_index++;
Simon Kelley7622fc02009-06-04 20:32:05 +01001560 new->flags = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00001561 if (option == 'H')
1562 {
1563 new->next = daemon->addn_hosts;
1564 daemon->addn_hosts = new;
1565 }
1566 else if (option == LOPT_DHCP_HOST)
1567 {
1568 new->next = daemon->dhcp_hosts_file;
1569 daemon->dhcp_hosts_file = new;
1570 }
Simon Kelleye1ff4192012-12-09 17:08:47 +00001571 else if (option == LOPT_DHCP_OPTS)
Simon Kelley28866e92011-02-14 20:19:14 +00001572 {
1573 new->next = daemon->dhcp_opts_file;
1574 daemon->dhcp_opts_file = new;
1575 }
Simon Kelley849a8352006-06-09 21:02:31 +01001576 break;
1577 }
1578
Simon Kelley4f7b3042012-11-28 21:27:02 +00001579 case LOPT_AUTHSERV: /* --auth-server */
Simon Kelley86e3b9a2012-11-30 13:46:48 +00001580 if (!(comma = split(arg)))
Simon Kelley4f7b3042012-11-28 21:27:02 +00001581 ret_err(gen_err);
1582
Simon Kelley4f7b3042012-11-28 21:27:02 +00001583 daemon->authserver = opt_string_alloc(arg);
Simon Kelley429798f2012-12-10 20:45:53 +00001584 arg = comma;
1585 do {
1586 struct iname *new = opt_malloc(sizeof(struct iname));
1587 comma = split(arg);
1588 new->name = NULL;
1589 unhide_metas(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01001590 if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0)
Simon Kelley429798f2012-12-10 20:45:53 +00001591 new->addr.sa.sa_family = AF_INET;
1592#ifdef HAVE_IPV6
1593 else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
1594 new->addr.sa.sa_family = AF_INET6;
1595#endif
1596 else
1597 new->name = opt_string_alloc(arg);
1598
1599 new->next = daemon->authinterface;
1600 daemon->authinterface = new;
1601
1602 arg = comma;
1603 } while (arg);
1604
Simon Kelley4f7b3042012-11-28 21:27:02 +00001605 break;
Simon Kelleye1ff4192012-12-09 17:08:47 +00001606
1607 case LOPT_AUTHSFS: /* --auth-sec-servers */
1608 {
1609 struct name_list *new;
1610
1611 do {
1612 comma = split(arg);
Simon Kelley429798f2012-12-10 20:45:53 +00001613 new = opt_malloc(sizeof(struct name_list));
Simon Kelleye1ff4192012-12-09 17:08:47 +00001614 new->name = opt_string_alloc(arg);
1615 new->next = daemon->secondary_forward_server;
1616 daemon->secondary_forward_server = new;
1617 arg = comma;
1618 } while (arg);
1619 break;
1620 }
1621
Simon Kelley4f7b3042012-11-28 21:27:02 +00001622 case LOPT_AUTHZONE: /* --auth-zone */
1623 {
1624 struct auth_zone *new;
1625
1626 comma = split(arg);
Simon Kelley1e14cc02012-12-29 17:27:59 +00001627
Simon Kelley429798f2012-12-10 20:45:53 +00001628 new = opt_malloc(sizeof(struct auth_zone));
Simon Kelley4f7b3042012-11-28 21:27:02 +00001629 new->domain = opt_string_alloc(arg);
1630 new->subnet = NULL;
1631 new->next = daemon->auth_zones;
1632 daemon->auth_zones = new;
1633
1634 while ((arg = comma))
1635 {
1636 int prefixlen = 0;
1637 char *prefix;
Simon Kelley429798f2012-12-10 20:45:53 +00001638 struct subnet *subnet = opt_malloc(sizeof(struct subnet));
Simon Kelley4f7b3042012-11-28 21:27:02 +00001639
1640 subnet->next = new->subnet;
1641 new->subnet = subnet;
1642
1643 comma = split(arg);
1644 prefix = split_chr(arg, '/');
1645
1646 if (prefix && !atoi_check(prefix, &prefixlen))
1647 ret_err(gen_err);
1648
1649 if (inet_pton(AF_INET, arg, &subnet->addr4))
1650 {
1651 subnet->prefixlen = (prefixlen == 0) ? 24 : prefixlen;
1652 subnet->is6 = 0;
1653 }
1654#ifdef HAVE_IPV6
1655 else if (inet_pton(AF_INET6, arg, &subnet->addr6))
1656 {
1657 subnet->prefixlen = (prefixlen == 0) ? 64 : prefixlen;
1658 subnet->is6 = 1;
1659 }
1660#endif
1661 else
1662 ret_err(gen_err);
1663 }
1664 break;
1665 }
1666
1667 case LOPT_AUTHSOA: /* --auth-soa */
1668 comma = split(arg);
Simon Kelley5c72bb92013-08-19 14:12:59 +01001669 daemon->soa_sn = (u32)atoi(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001670 if (comma)
1671 {
Simon Kelley86e3b9a2012-11-30 13:46:48 +00001672 char *cp;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001673 arg = comma;
1674 comma = split(arg);
1675 daemon->hostmaster = opt_string_alloc(arg);
Simon Kelley86e3b9a2012-11-30 13:46:48 +00001676 for (cp = daemon->hostmaster; *cp; cp++)
1677 if (*cp == '@')
1678 *cp = '.';
1679
Simon Kelley4f7b3042012-11-28 21:27:02 +00001680 if (comma)
1681 {
1682 arg = comma;
1683 comma = split(arg);
Simon Kelley5c72bb92013-08-19 14:12:59 +01001684 daemon->soa_refresh = (u32)atoi(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001685 if (comma)
1686 {
1687 arg = comma;
1688 comma = split(arg);
Simon Kelley5c72bb92013-08-19 14:12:59 +01001689 daemon->soa_retry = (u32)atoi(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001690 if (comma)
1691 {
1692 arg = comma;
1693 comma = split(arg);
Simon Kelley5c72bb92013-08-19 14:12:59 +01001694 daemon->soa_expiry = (u32)atoi(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001695 }
1696 }
1697 }
1698 }
1699
1700 break;
1701
Simon Kelley2bb73af2013-04-24 17:38:19 +01001702 case 's': /* --domain */
1703 case LOPT_SYNTH: /* --synth-domain */
Simon Kelley849a8352006-06-09 21:02:31 +01001704 if (strcmp (arg, "#") == 0)
Simon Kelley28866e92011-02-14 20:19:14 +00001705 set_option_bool(OPT_RESOLV_DOMAIN);
Simon Kelley849a8352006-06-09 21:02:31 +01001706 else
Simon Kelley9009d742008-11-14 20:04:27 +00001707 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001708 char *d;
Simon Kelley9009d742008-11-14 20:04:27 +00001709 comma = split(arg);
Simon Kelley1f15b812009-10-13 17:49:32 +01001710 if (!(d = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001711 ret_err(gen_err);
Simon Kelley9009d742008-11-14 20:04:27 +00001712 else
1713 {
Simon Kelley9009d742008-11-14 20:04:27 +00001714 if (comma)
1715 {
Simon Kelley429798f2012-12-10 20:45:53 +00001716 struct cond_domain *new = opt_malloc(sizeof(struct cond_domain));
Simon Kelley28866e92011-02-14 20:19:14 +00001717 char *netpart;
Simon Kelley2bb73af2013-04-24 17:38:19 +01001718
Simon Kelley48fd1c42013-04-25 09:49:38 +01001719 new->prefix = NULL;
1720
Simon Kelley9009d742008-11-14 20:04:27 +00001721 unhide_metas(comma);
Simon Kelley28866e92011-02-14 20:19:14 +00001722 if ((netpart = split_chr(comma, '/')))
Simon Kelley9009d742008-11-14 20:04:27 +00001723 {
Simon Kelleyd74942a2012-02-07 20:51:56 +00001724 int msize;
1725
Simon Kelley28866e92011-02-14 20:19:14 +00001726 arg = split(netpart);
Simon Kelleyd74942a2012-02-07 20:51:56 +00001727 if (!atoi_check(netpart, &msize))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001728 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00001729 else if (inet_pton(AF_INET, comma, &new->start))
Simon Kelley9009d742008-11-14 20:04:27 +00001730 {
Simon Kelleyd74942a2012-02-07 20:51:56 +00001731 int mask = (1 << (32 - msize)) - 1;
1732 new->is6 = 0;
Simon Kelley9009d742008-11-14 20:04:27 +00001733 new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask);
1734 new->end.s_addr = new->start.s_addr | htonl(mask);
Simon Kelley28866e92011-02-14 20:19:14 +00001735 if (arg)
1736 {
Simon Kelley48fd1c42013-04-25 09:49:38 +01001737 if (option != 's')
Simon Kelleyb5a7ff42013-04-25 11:03:47 +01001738 {
1739 if (!(new->prefix = canonicalise_opt(arg)) ||
1740 strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
1741 ret_err(_("bad prefix"));
1742 }
Simon Kelley48fd1c42013-04-25 09:49:38 +01001743 else if (strcmp(arg, "local") != 0 ||
1744 (msize != 8 && msize != 16 && msize != 24))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001745 ret_err(gen_err);
Simon Kelley28866e92011-02-14 20:19:14 +00001746 else
1747 {
Simon Kelley48fd1c42013-04-25 09:49:38 +01001748 /* generate the equivalent of
1749 local=/<domain>/
1750 local=/xxx.yyy.zzz.in-addr.arpa/ */
Simon Kelley28866e92011-02-14 20:19:14 +00001751 struct server *serv = opt_malloc(sizeof(struct server));
1752 in_addr_t a = ntohl(new->start.s_addr) >> 8;
1753 char *p;
Simon Kelley48fd1c42013-04-25 09:49:38 +01001754
Simon Kelley28866e92011-02-14 20:19:14 +00001755 memset(serv, 0, sizeof(struct server));
1756 serv->domain = d;
1757 serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
1758 serv->next = daemon->servers;
1759 daemon->servers = serv;
Simon Kelley48fd1c42013-04-25 09:49:38 +01001760
Simon Kelley28866e92011-02-14 20:19:14 +00001761 serv = opt_malloc(sizeof(struct server));
1762 memset(serv, 0, sizeof(struct server));
1763 p = serv->domain = opt_malloc(25); /* strlen("xxx.yyy.zzz.in-addr.arpa")+1 */
1764
1765 if (msize == 24)
1766 p += sprintf(p, "%d.", a & 0xff);
1767 a = a >> 8;
1768 if (msize != 8)
1769 p += sprintf(p, "%d.", a & 0xff);
1770 a = a >> 8;
1771 p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
Simon Kelley48fd1c42013-04-25 09:49:38 +01001772
Simon Kelley28866e92011-02-14 20:19:14 +00001773 serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
1774 serv->next = daemon->servers;
1775 daemon->servers = serv;
1776 }
1777 }
Simon Kelley9009d742008-11-14 20:04:27 +00001778 }
Simon Kelleyd74942a2012-02-07 20:51:56 +00001779#ifdef HAVE_IPV6
1780 else if (inet_pton(AF_INET6, comma, &new->start6))
1781 {
1782 u64 mask = (1LLU << (128 - msize)) - 1LLU;
1783 u64 addrpart = addr6part(&new->start6);
1784 new->is6 = 1;
Simon Kelley48fd1c42013-04-25 09:49:38 +01001785
Simon Kelleyd74942a2012-02-07 20:51:56 +00001786 /* prefix==64 overflows the mask calculation above */
1787 if (msize == 64)
1788 mask = (u64)-1LL;
Simon Kelley48fd1c42013-04-25 09:49:38 +01001789
Simon Kelleyd74942a2012-02-07 20:51:56 +00001790 new->end6 = new->start6;
1791 setaddr6part(&new->start6, addrpart & ~mask);
1792 setaddr6part(&new->end6, addrpart | mask);
1793
1794 if (msize < 64)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001795 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00001796 else if (arg)
1797 {
Simon Kelley48fd1c42013-04-25 09:49:38 +01001798 if (option != 's')
Simon Kelleyb5a7ff42013-04-25 11:03:47 +01001799 {
1800 if (!(new->prefix = canonicalise_opt(arg)) ||
1801 strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
1802 ret_err(_("bad prefix"));
1803 }
Simon Kelley48fd1c42013-04-25 09:49:38 +01001804 else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001805 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00001806 else
1807 {
Simon Kelley48fd1c42013-04-25 09:49:38 +01001808 /* generate the equivalent of
1809 local=/<domain>/
1810 local=/xxx.yyy.zzz.ip6.arpa/ */
Simon Kelleyd74942a2012-02-07 20:51:56 +00001811 struct server *serv = opt_malloc(sizeof(struct server));
Simon Kelleyd74942a2012-02-07 20:51:56 +00001812 char *p;
Simon Kelleyceae00d2012-02-09 21:28:14 +00001813
Simon Kelleyd74942a2012-02-07 20:51:56 +00001814 memset(serv, 0, sizeof(struct server));
1815 serv->domain = d;
1816 serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
1817 serv->next = daemon->servers;
1818 daemon->servers = serv;
1819
1820 serv = opt_malloc(sizeof(struct server));
1821 memset(serv, 0, sizeof(struct server));
1822 p = serv->domain = opt_malloc(73); /* strlen("32*<n.>ip6.arpa")+1 */
1823
1824 for (i = msize-1; i >= 0; i -= 4)
1825 {
1826 int dig = ((unsigned char *)&new->start6)[i>>3];
1827 p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
1828 }
1829 p += sprintf(p, "ip6.arpa");
1830
1831 serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
1832 serv->next = daemon->servers;
1833 daemon->servers = serv;
1834 }
1835 }
1836 }
1837#endif
1838 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001839 ret_err(gen_err);
Simon Kelley9009d742008-11-14 20:04:27 +00001840 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001841 else
Simon Kelleyd74942a2012-02-07 20:51:56 +00001842 {
1843 arg = split(comma);
1844 if (inet_pton(AF_INET, comma, &new->start))
1845 {
1846 new->is6 = 0;
1847 if (!arg)
1848 new->end.s_addr = new->start.s_addr;
1849 else if (!inet_pton(AF_INET, arg, &new->end))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001850 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00001851 }
1852#ifdef HAVE_IPV6
1853 else if (inet_pton(AF_INET6, comma, &new->start6))
1854 {
1855 new->is6 = 1;
1856 if (!arg)
1857 memcpy(&new->end6, &new->start6, IN6ADDRSZ);
1858 else if (!inet_pton(AF_INET6, arg, &new->end6))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001859 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00001860 }
1861#endif
1862 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001863 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00001864 }
Simon Kelley2307eac2012-02-13 10:13:13 +00001865
1866 new->domain = d;
Simon Kelley2bb73af2013-04-24 17:38:19 +01001867 if (option == 's')
1868 {
1869 new->next = daemon->cond_domain;
1870 daemon->cond_domain = new;
1871 }
1872 else
1873 {
1874 new->next = daemon->synth_domains;
1875 daemon->synth_domains = new;
1876 }
Simon Kelley9009d742008-11-14 20:04:27 +00001877 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001878 else if (option == 's')
Simon Kelley9009d742008-11-14 20:04:27 +00001879 daemon->domain_suffix = d;
Simon Kelley2bb73af2013-04-24 17:38:19 +01001880 else
1881 ret_err(gen_err);
Simon Kelley9009d742008-11-14 20:04:27 +00001882 }
1883 }
Simon Kelley849a8352006-06-09 21:02:31 +01001884 break;
1885
Simon Kelleyf2621c72007-04-29 19:47:21 +01001886 case 'u': /* --user */
Simon Kelley824af852008-02-12 20:43:05 +00001887 daemon->username = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001888 break;
1889
Simon Kelleyf2621c72007-04-29 19:47:21 +01001890 case 'g': /* --group */
Simon Kelley824af852008-02-12 20:43:05 +00001891 daemon->groupname = opt_string_alloc(arg);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001892 daemon->group_set = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01001893 break;
Simon Kelley9e038942008-05-30 20:06:34 +01001894
Simon Kelley7622fc02009-06-04 20:32:05 +01001895#ifdef HAVE_DHCP
Simon Kelley9e038942008-05-30 20:06:34 +01001896 case LOPT_SCRIPTUSR: /* --scriptuser */
1897 daemon->scriptuser = opt_string_alloc(arg);
1898 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01001899#endif
Simon Kelley849a8352006-06-09 21:02:31 +01001900
Simon Kelleyf2621c72007-04-29 19:47:21 +01001901 case 'i': /* --interface */
Simon Kelley849a8352006-06-09 21:02:31 +01001902 do {
Simon Kelley824af852008-02-12 20:43:05 +00001903 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01001904 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001905 new->next = daemon->if_names;
1906 daemon->if_names = new;
1907 /* new->name may be NULL if someone does
1908 "interface=" to disable all interfaces except loop. */
Simon Kelley824af852008-02-12 20:43:05 +00001909 new->name = opt_string_alloc(arg);
Simon Kelley4ce4f372012-06-14 11:50:45 +01001910 new->used = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01001911 arg = comma;
1912 } while (arg);
1913 break;
1914
Simon Kelley2937f8a2013-07-29 19:49:07 +01001915 case LOPT_TFTP: /* --enable-tftp */
1916 set_option_bool(OPT_TFTP);
1917 if (!arg)
1918 break;
1919 /* fall through */
1920
Simon Kelleyf2621c72007-04-29 19:47:21 +01001921 case 'I': /* --except-interface */
1922 case '2': /* --no-dhcp-interface */
Simon Kelley849a8352006-06-09 21:02:31 +01001923 do {
Simon Kelley824af852008-02-12 20:43:05 +00001924 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01001925 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00001926 new->name = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001927 if (option == 'I')
1928 {
1929 new->next = daemon->if_except;
1930 daemon->if_except = new;
1931 }
Simon Kelley2937f8a2013-07-29 19:49:07 +01001932 else if (option == LOPT_TFTP)
1933 {
1934 new->next = daemon->tftp_interfaces;
1935 daemon->tftp_interfaces = new;
1936 }
Simon Kelley849a8352006-06-09 21:02:31 +01001937 else
1938 {
1939 new->next = daemon->dhcp_except;
1940 daemon->dhcp_except = new;
1941 }
1942 arg = comma;
1943 } while (arg);
1944 break;
1945
Simon Kelleyf2621c72007-04-29 19:47:21 +01001946 case 'B': /* --bogus-nxdomain */
Simon Kelley849a8352006-06-09 21:02:31 +01001947 {
1948 struct in_addr addr;
1949 unhide_metas(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01001950 if (arg && (inet_pton(AF_INET, arg, &addr) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01001951 {
Simon Kelley824af852008-02-12 20:43:05 +00001952 struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
Simon Kelley849a8352006-06-09 21:02:31 +01001953 baddr->next = daemon->bogus_addr;
1954 daemon->bogus_addr = baddr;
1955 baddr->addr = addr;
1956 }
1957 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001958 ret_err(gen_err); /* error */
Simon Kelley849a8352006-06-09 21:02:31 +01001959 break;
1960 }
1961
Simon Kelleyf2621c72007-04-29 19:47:21 +01001962 case 'a': /* --listen-address */
Simon Kelley49678762012-12-09 18:24:58 +00001963 case LOPT_AUTHPEER: /* --auth-peer */
Simon Kelley849a8352006-06-09 21:02:31 +01001964 do {
Simon Kelley824af852008-02-12 20:43:05 +00001965 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01001966 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001967 unhide_metas(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01001968 if (arg && (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01001969 {
1970 new->addr.sa.sa_family = AF_INET;
Simon Kelley49678762012-12-09 18:24:58 +00001971 new->addr.in.sin_port = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01001972#ifdef HAVE_SOCKADDR_SA_LEN
1973 new->addr.in.sin_len = sizeof(new->addr.in);
1974#endif
1975 }
1976#ifdef HAVE_IPV6
1977 else if (arg && inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
1978 {
1979 new->addr.sa.sa_family = AF_INET6;
1980 new->addr.in6.sin6_flowinfo = 0;
1981 new->addr.in6.sin6_scope_id = 0;
Simon Kelley49678762012-12-09 18:24:58 +00001982 new->addr.in6.sin6_port = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01001983#ifdef HAVE_SOCKADDR_SA_LEN
1984 new->addr.in6.sin6_len = sizeof(new->addr.in6);
1985#endif
1986 }
1987#endif
1988 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001989 ret_err(gen_err);
Simon Kelley4ce4f372012-06-14 11:50:45 +01001990
1991 new->used = 0;
Simon Kelley49678762012-12-09 18:24:58 +00001992 if (option == 'a')
1993 {
1994 new->next = daemon->if_addrs;
1995 daemon->if_addrs = new;
1996 }
1997 else
1998 {
1999 new->next = daemon->auth_peers;
2000 daemon->auth_peers = new;
2001 }
Simon Kelley849a8352006-06-09 21:02:31 +01002002 arg = comma;
2003 } while (arg);
2004 break;
2005
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002006 case 'S': /* --server */
2007 case LOPT_LOCAL: /* --local */
2008 case 'A': /* --address */
2009 case LOPT_NO_REBIND: /* --rebind-domain-ok */
Simon Kelley849a8352006-06-09 21:02:31 +01002010 {
2011 struct server *serv, *newlist = NULL;
2012
2013 unhide_metas(arg);
2014
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002015 if (arg && (*arg == '/' || option == LOPT_NO_REBIND))
Simon Kelley849a8352006-06-09 21:02:31 +01002016 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002017 int rebind = !(*arg == '/');
2018 char *end = NULL;
2019 if (!rebind)
2020 arg++;
2021 while (rebind || (end = split_chr(arg, '/')))
Simon Kelley849a8352006-06-09 21:02:31 +01002022 {
2023 char *domain = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002024 /* elide leading dots - they are implied in the search algorithm */
2025 while (*arg == '.') arg++;
Simon Kelley849a8352006-06-09 21:02:31 +01002026 /* # matches everything and becomes a zero length domain string */
2027 if (strcmp(arg, "#") == 0)
2028 domain = "";
Simon Kelley1f15b812009-10-13 17:49:32 +01002029 else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01002030 option = '?';
Simon Kelley824af852008-02-12 20:43:05 +00002031 serv = opt_malloc(sizeof(struct server));
2032 memset(serv, 0, sizeof(struct server));
Simon Kelley849a8352006-06-09 21:02:31 +01002033 serv->next = newlist;
2034 newlist = serv;
Simon Kelley849a8352006-06-09 21:02:31 +01002035 serv->domain = domain;
2036 serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
Simon Kelley73a08a22009-02-05 20:28:08 +00002037 arg = end;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002038 if (rebind)
2039 break;
Simon Kelley849a8352006-06-09 21:02:31 +01002040 }
2041 if (!newlist)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002042 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002043 }
2044 else
2045 {
Simon Kelley824af852008-02-12 20:43:05 +00002046 newlist = opt_malloc(sizeof(struct server));
2047 memset(newlist, 0, sizeof(struct server));
Simon Kelley849a8352006-06-09 21:02:31 +01002048 }
2049
2050 if (option == 'A')
2051 {
2052 newlist->flags |= SERV_LITERAL_ADDRESS;
2053 if (!(newlist->flags & SERV_TYPE))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002054 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002055 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002056 else if (option == LOPT_NO_REBIND)
2057 newlist->flags |= SERV_NO_REBIND;
Simon Kelley849a8352006-06-09 21:02:31 +01002058
2059 if (!arg || !*arg)
2060 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002061 if (!(newlist->flags & SERV_NO_REBIND))
2062 newlist->flags |= SERV_NO_ADDR; /* no server */
2063 if (newlist->flags & SERV_LITERAL_ADDRESS)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002064 ret_err(gen_err);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002065 }
2066
2067 else if (strcmp(arg, "#") == 0)
2068 {
2069 newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
Simon Kelley849a8352006-06-09 21:02:31 +01002070 if (newlist->flags & SERV_LITERAL_ADDRESS)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002071 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002072 }
2073 else
2074 {
Simon Kelleyfaafb3f2012-09-20 14:17:39 +01002075 char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
2076 if (err)
2077 ret_err(err);
Simon Kelley849a8352006-06-09 21:02:31 +01002078 }
2079
Simon Kelleyf2621c72007-04-29 19:47:21 +01002080 serv = newlist;
2081 while (serv->next)
Simon Kelley849a8352006-06-09 21:02:31 +01002082 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01002083 serv->next->flags = serv->flags;
2084 serv->next->addr = serv->addr;
2085 serv->next->source_addr = serv->source_addr;
Simon Kelleyfaafb3f2012-09-20 14:17:39 +01002086 strcpy(serv->next->interface, serv->interface);
Simon Kelleyf2621c72007-04-29 19:47:21 +01002087 serv = serv->next;
Simon Kelley849a8352006-06-09 21:02:31 +01002088 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01002089 serv->next = daemon->servers;
2090 daemon->servers = newlist;
Simon Kelley849a8352006-06-09 21:02:31 +01002091 break;
2092 }
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002093
2094 case LOPT_IPSET: /* --ipset */
2095#ifndef HAVE_IPSET
2096 ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
2097 break;
2098#else
2099 {
2100 struct ipsets ipsets_head;
2101 struct ipsets *ipsets = &ipsets_head;
2102 int size;
2103 char *end;
2104 char **sets, **sets_pos;
2105 memset(ipsets, 0, sizeof(struct ipsets));
2106 unhide_metas(arg);
2107 if (arg && *arg == '/')
2108 {
2109 arg++;
2110 while ((end = split_chr(arg, '/')))
2111 {
2112 char *domain = NULL;
2113 /* elide leading dots - they are implied in the search algorithm */
2114 while (*arg == '.')
2115 arg++;
2116 /* # matches everything and becomes a zero length domain string */
2117 if (strcmp(arg, "#") == 0 || !*arg)
2118 domain = "";
2119 else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg)))
2120 option = '?';
2121 ipsets->next = opt_malloc(sizeof(struct ipsets));
2122 ipsets = ipsets->next;
2123 memset(ipsets, 0, sizeof(struct ipsets));
2124 ipsets->domain = domain;
2125 arg = end;
2126 }
2127 }
2128 else
2129 {
2130 ipsets->next = opt_malloc(sizeof(struct ipsets));
2131 ipsets = ipsets->next;
2132 memset(ipsets, 0, sizeof(struct ipsets));
2133 ipsets->domain = "";
2134 }
2135 if (!arg || !*arg)
2136 {
2137 option = '?';
2138 break;
2139 }
2140 size = 2;
2141 for (end = arg; *end; ++end)
2142 if (*end == ',')
2143 ++size;
2144
2145 sets = sets_pos = opt_malloc(sizeof(char *) * size);
2146
2147 do {
2148 end = split(arg);
2149 *sets_pos++ = opt_string_alloc(arg);
2150 arg = end;
2151 } while (end);
2152 *sets_pos = 0;
2153 for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next)
2154 ipsets->next->sets = sets;
2155 ipsets->next = daemon->ipsets;
2156 daemon->ipsets = ipsets_head.next;
2157
2158 break;
2159 }
2160#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002161
Simon Kelleyf2621c72007-04-29 19:47:21 +01002162 case 'c': /* --cache-size */
Simon Kelley849a8352006-06-09 21:02:31 +01002163 {
2164 int size;
2165
2166 if (!atoi_check(arg, &size))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002167 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002168 else
2169 {
2170 /* zero is OK, and means no caching. */
2171
2172 if (size < 0)
2173 size = 0;
2174 else if (size > 10000)
2175 size = 10000;
2176
2177 daemon->cachesize = size;
2178 }
2179 break;
2180 }
2181
Simon Kelleyf2621c72007-04-29 19:47:21 +01002182 case 'p': /* --port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002183 if (!atoi_check16(arg, &daemon->port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002184 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002185 break;
Simon Kelley208b65c2006-08-05 21:41:37 +01002186
Simon Kelley1a6bca82008-07-11 11:11:42 +01002187 case LOPT_MINPORT: /* --min-port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002188 if (!atoi_check16(arg, &daemon->min_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002189 ret_err(gen_err);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002190 break;
2191
Simon Kelleyf2621c72007-04-29 19:47:21 +01002192 case '0': /* --dns-forward-max */
Simon Kelley208b65c2006-08-05 21:41:37 +01002193 if (!atoi_check(arg, &daemon->ftabsize))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002194 ret_err(gen_err);
Simon Kelley208b65c2006-08-05 21:41:37 +01002195 break;
2196
Simon Kelleyf2621c72007-04-29 19:47:21 +01002197 case LOPT_MAX_LOGS: /* --log-async */
2198 daemon->max_logs = LOG_MAX; /* default */
2199 if (arg && !atoi_check(arg, &daemon->max_logs))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002200 ret_err(gen_err);
Simon Kelleyf2621c72007-04-29 19:47:21 +01002201 else if (daemon->max_logs > 100)
2202 daemon->max_logs = 100;
2203 break;
2204
2205 case 'P': /* --edns-packet-max */
Simon Kelley849a8352006-06-09 21:02:31 +01002206 {
2207 int i;
2208 if (!atoi_check(arg, &i))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002209 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002210 daemon->edns_pktsz = (unsigned short)i;
2211 break;
2212 }
2213
Simon Kelleyf2621c72007-04-29 19:47:21 +01002214 case 'Q': /* --query-port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002215 if (!atoi_check16(arg, &daemon->query_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002216 ret_err(gen_err);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002217 /* if explicitly set to zero, use single OS ephemeral port
2218 and disable random ports */
2219 if (daemon->query_port == 0)
2220 daemon->osport = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01002221 break;
2222
Simon Kelley824af852008-02-12 20:43:05 +00002223 case 'T': /* --local-ttl */
2224 case LOPT_NEGTTL: /* --neg-ttl */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002225 case LOPT_MAXTTL: /* --max-ttl */
Simon Kelley1d860412012-09-20 20:48:04 +01002226 case LOPT_MAXCTTL: /* --max-cache-ttl */
Simon Kelley4f7b3042012-11-28 21:27:02 +00002227 case LOPT_AUTHTTL: /* --auth-ttl */
Simon Kelley849a8352006-06-09 21:02:31 +01002228 {
2229 int ttl;
2230 if (!atoi_check(arg, &ttl))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002231 ret_err(gen_err);
Simon Kelley824af852008-02-12 20:43:05 +00002232 else if (option == LOPT_NEGTTL)
2233 daemon->neg_ttl = (unsigned long)ttl;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002234 else if (option == LOPT_MAXTTL)
2235 daemon->max_ttl = (unsigned long)ttl;
Simon Kelley1d860412012-09-20 20:48:04 +01002236 else if (option == LOPT_MAXCTTL)
2237 daemon->max_cache_ttl = (unsigned long)ttl;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002238 else if (option == LOPT_AUTHTTL)
2239 daemon->auth_ttl = (unsigned long)ttl;
Simon Kelley849a8352006-06-09 21:02:31 +01002240 else
2241 daemon->local_ttl = (unsigned long)ttl;
2242 break;
2243 }
2244
Simon Kelley7622fc02009-06-04 20:32:05 +01002245#ifdef HAVE_DHCP
Simon Kelleyf2621c72007-04-29 19:47:21 +01002246 case 'X': /* --dhcp-lease-max */
Simon Kelley849a8352006-06-09 21:02:31 +01002247 if (!atoi_check(arg, &daemon->dhcp_max))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002248 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002249 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01002250#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002251
Simon Kelley7622fc02009-06-04 20:32:05 +01002252#ifdef HAVE_TFTP
Simon Kelleyf2621c72007-04-29 19:47:21 +01002253 case LOPT_TFTP_MAX: /* --tftp-max */
Simon Kelley832af0b2007-01-21 20:01:28 +00002254 if (!atoi_check(arg, &daemon->tftp_max))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002255 ret_err(gen_err);
Simon Kelley832af0b2007-01-21 20:01:28 +00002256 break;
2257
Simon Kelley824af852008-02-12 20:43:05 +00002258 case LOPT_PREFIX: /* --tftp-prefix */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002259 comma = split(arg);
2260 if (comma)
2261 {
2262 struct tftp_prefix *new = opt_malloc(sizeof(struct tftp_prefix));
2263 new->interface = opt_string_alloc(comma);
2264 new->prefix = opt_string_alloc(arg);
2265 new->next = daemon->if_prefix;
2266 daemon->if_prefix = new;
2267 }
2268 else
2269 daemon->tftp_prefix = opt_string_alloc(arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00002270 break;
2271
Simon Kelley824af852008-02-12 20:43:05 +00002272 case LOPT_TFTPPORTS: /* --tftp-port-range */
2273 if (!(comma = split(arg)) ||
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002274 !atoi_check16(arg, &daemon->start_tftp_port) ||
2275 !atoi_check16(comma, &daemon->end_tftp_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002276 ret_err(_("bad port range"));
Simon Kelley824af852008-02-12 20:43:05 +00002277
2278 if (daemon->start_tftp_port > daemon->end_tftp_port)
2279 {
2280 int tmp = daemon->start_tftp_port;
2281 daemon->start_tftp_port = daemon->end_tftp_port;
2282 daemon->end_tftp_port = tmp;
2283 }
2284
2285 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01002286#endif
Simon Kelley824af852008-02-12 20:43:05 +00002287
Simon Kelleyf2621c72007-04-29 19:47:21 +01002288 case LOPT_BRIDGE: /* --bridge-interface */
Simon Kelley832af0b2007-01-21 20:01:28 +00002289 {
Simon Kelley824af852008-02-12 20:43:05 +00002290 struct dhcp_bridge *new = opt_malloc(sizeof(struct dhcp_bridge));
Simon Kelley316e2732010-01-22 20:16:09 +00002291 if (!(comma = split(arg)) || strlen(arg) > IF_NAMESIZE - 1 )
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002292 ret_err(_("bad bridge-interface"));
Simon Kelley832af0b2007-01-21 20:01:28 +00002293
Simon Kelley316e2732010-01-22 20:16:09 +00002294 strcpy(new->iface, arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00002295 new->alias = NULL;
2296 new->next = daemon->bridges;
2297 daemon->bridges = new;
2298
2299 do {
Simon Kelleyf2621c72007-04-29 19:47:21 +01002300 arg = comma;
2301 comma = split(arg);
Simon Kelley316e2732010-01-22 20:16:09 +00002302 if (strlen(arg) != 0 && strlen(arg) <= IF_NAMESIZE - 1)
Simon Kelley832af0b2007-01-21 20:01:28 +00002303 {
Simon Kelley824af852008-02-12 20:43:05 +00002304 struct dhcp_bridge *b = opt_malloc(sizeof(struct dhcp_bridge));
Simon Kelley832af0b2007-01-21 20:01:28 +00002305 b->next = new->alias;
2306 new->alias = b;
Simon Kelley316e2732010-01-22 20:16:09 +00002307 strcpy(b->iface, arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00002308 }
2309 } while (comma);
2310
2311 break;
2312 }
Simon Kelley832af0b2007-01-21 20:01:28 +00002313
Simon Kelley7622fc02009-06-04 20:32:05 +01002314#ifdef HAVE_DHCP
Simon Kelleyf2621c72007-04-29 19:47:21 +01002315 case 'F': /* --dhcp-range */
Simon Kelley849a8352006-06-09 21:02:31 +01002316 {
2317 int k, leasepos = 2;
Simon Kelley8445f5d2012-12-17 21:54:08 +00002318 char *cp, *a[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
Simon Kelley824af852008-02-12 20:43:05 +00002319 struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
Simon Kelley849a8352006-06-09 21:02:31 +01002320
Simon Kelley52b92f42012-01-22 16:05:15 +00002321 memset (new, 0, sizeof(*new));
Simon Kelley849a8352006-06-09 21:02:31 +01002322 new->lease_time = DEFLEASE;
Simon Kelley52b92f42012-01-22 16:05:15 +00002323
Simon Kelley849a8352006-06-09 21:02:31 +01002324 if (!arg)
2325 {
2326 option = '?';
2327 break;
2328 }
2329
2330 while(1)
2331 {
2332 for (cp = arg; *cp; cp++)
Simon Kelley52b92f42012-01-22 16:05:15 +00002333 if (!(*cp == ' ' || *cp == '.' || *cp == ':' ||
2334 (*cp >= 'a' && *cp <= 'f') || (*cp >= 'A' && *cp <= 'F') ||
2335 (*cp >='0' && *cp <= '9')))
Simon Kelley849a8352006-06-09 21:02:31 +01002336 break;
2337
Simon Kelleyf2621c72007-04-29 19:47:21 +01002338 if (*cp != ',' && (comma = split(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01002339 {
Simon Kelley8bc4cec2012-07-03 21:04:11 +01002340 if (is_tag_prefix(arg))
Simon Kelley849a8352006-06-09 21:02:31 +01002341 {
Simon Kelley824af852008-02-12 20:43:05 +00002342 struct dhcp_netid *tt = opt_malloc(sizeof (struct dhcp_netid));
2343 tt->net = opt_string_alloc(arg+4);
Simon Kelley849a8352006-06-09 21:02:31 +01002344 tt->next = new->filter;
2345 new->filter = tt;
2346 }
2347 else
2348 {
2349 if (new->netid.net)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002350 ret_err(_("only one tag allowed"));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002351 else if (strstr(arg, "set:") == arg)
2352 new->netid.net = opt_string_alloc(arg+4);
Simon Kelley849a8352006-06-09 21:02:31 +01002353 else
Simon Kelley824af852008-02-12 20:43:05 +00002354 new->netid.net = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002355 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01002356 arg = comma;
Simon Kelley849a8352006-06-09 21:02:31 +01002357 }
2358 else
2359 {
2360 a[0] = arg;
2361 break;
2362 }
2363 }
2364
Simon Kelley1f776932012-12-16 19:46:08 +00002365 for (k = 1; k < 8; k++)
Simon Kelleyf2621c72007-04-29 19:47:21 +01002366 if (!(a[k] = split(a[k-1])))
2367 break;
Simon Kelley849a8352006-06-09 21:02:31 +01002368
Simon Kelley52b92f42012-01-22 16:05:15 +00002369 if (k < 2)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002370 ret_err(_("bad dhcp-range"));
2371
2372 if (inet_pton(AF_INET, a[0], &new->start))
Simon Kelley849a8352006-06-09 21:02:31 +01002373 {
Simon Kelley52b92f42012-01-22 16:05:15 +00002374 new->next = daemon->dhcp;
2375 daemon->dhcp = new;
Simon Kelley30cd9662012-03-25 20:44:38 +01002376 new->end = new->start;
Simon Kelley52b92f42012-01-22 16:05:15 +00002377 if (strcmp(a[1], "static") == 0)
Simon Kelley30cd9662012-03-25 20:44:38 +01002378 new->flags |= CONTEXT_STATIC;
Simon Kelley52b92f42012-01-22 16:05:15 +00002379 else if (strcmp(a[1], "proxy") == 0)
Simon Kelley30cd9662012-03-25 20:44:38 +01002380 new->flags |= CONTEXT_PROXY;
2381 else if (!inet_pton(AF_INET, a[1], &new->end))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002382 ret_err(_("bad dhcp-range"));
Simon Kelley52b92f42012-01-22 16:05:15 +00002383
2384 if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
2385 {
2386 struct in_addr tmp = new->start;
2387 new->start = new->end;
2388 new->end = tmp;
2389 }
2390
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002391 if (k >= 3 && strchr(a[2], '.') &&
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002392 (inet_pton(AF_INET, a[2], &new->netmask) > 0))
Simon Kelley52b92f42012-01-22 16:05:15 +00002393 {
2394 new->flags |= CONTEXT_NETMASK;
2395 leasepos = 3;
2396 if (!is_same_net(new->start, new->end, new->netmask))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002397 ret_err(_("inconsistent DHCP range"));
Simon Kelley52b92f42012-01-22 16:05:15 +00002398 }
2399
2400 if (k >= 4 && strchr(a[3], '.') &&
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002401 (inet_pton(AF_INET, a[3], &new->broadcast) > 0))
Simon Kelley52b92f42012-01-22 16:05:15 +00002402 {
2403 new->flags |= CONTEXT_BRDCAST;
2404 leasepos = 4;
2405 }
Simon Kelley849a8352006-06-09 21:02:31 +01002406 }
Simon Kelley52b92f42012-01-22 16:05:15 +00002407#ifdef HAVE_DHCP6
2408 else if (inet_pton(AF_INET6, a[0], &new->start6))
Simon Kelley7622fc02009-06-04 20:32:05 +01002409 {
Simon Kelley52b92f42012-01-22 16:05:15 +00002410 new->prefix = 64; /* default */
Simon Kelley30cd9662012-03-25 20:44:38 +01002411 new->end6 = new->start6;
Simon Kelley6692a1a2013-08-20 14:41:31 +01002412 new->next = daemon->dhcp6;
2413 daemon->dhcp6 = new;
2414
Simon Kelley30cd9662012-03-25 20:44:38 +01002415 for (leasepos = 1; leasepos < k; leasepos++)
2416 {
2417 if (strcmp(a[leasepos], "static") == 0)
2418 new->flags |= CONTEXT_STATIC | CONTEXT_DHCP;
2419 else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 )
Simon Kelley1f776932012-12-16 19:46:08 +00002420 new->flags |= CONTEXT_RA_ONLY | CONTEXT_RA;
Simon Kelley30cd9662012-03-25 20:44:38 +01002421 else if (strcmp(a[leasepos], "ra-names") == 0)
Simon Kelley1f776932012-12-16 19:46:08 +00002422 new->flags |= CONTEXT_RA_NAME | CONTEXT_RA;
Simon Kelley30cd9662012-03-25 20:44:38 +01002423 else if (strcmp(a[leasepos], "ra-stateless") == 0)
Simon Kelley1f776932012-12-16 19:46:08 +00002424 new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA;
Simon Kelley30cd9662012-03-25 20:44:38 +01002425 else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6))
2426 new->flags |= CONTEXT_DHCP;
Simon Kelley1f776932012-12-16 19:46:08 +00002427 else if (strstr(a[leasepos], "constructor:") == a[leasepos])
2428 {
2429 new->template_interface = opt_string_alloc(a[leasepos] + 12);
2430 new->flags |= CONTEXT_TEMPLATE;
2431 }
Simon Kelley921360c2013-05-31 14:07:22 +01002432 else if (strstr(a[leasepos], "constructor-noauth:") == a[leasepos])
2433 {
2434 new->template_interface = opt_string_alloc(a[leasepos] + 19);
2435 new->flags |= CONTEXT_TEMPLATE | CONTEXT_NOAUTH;
2436 }
Simon Kelley30cd9662012-03-25 20:44:38 +01002437 else
2438 break;
2439 }
Simon Kelley6692a1a2013-08-20 14:41:31 +01002440
Simon Kelley52b92f42012-01-22 16:05:15 +00002441 /* bare integer < 128 is prefix value */
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002442 if (leasepos < k)
Simon Kelley52b92f42012-01-22 16:05:15 +00002443 {
2444 int pref;
Simon Kelley30cd9662012-03-25 20:44:38 +01002445 for (cp = a[leasepos]; *cp; cp++)
Simon Kelley52b92f42012-01-22 16:05:15 +00002446 if (!(*cp >= '0' && *cp <= '9'))
2447 break;
Simon Kelley30cd9662012-03-25 20:44:38 +01002448 if (!*cp && (pref = atoi(a[leasepos])) <= 128)
Simon Kelley52b92f42012-01-22 16:05:15 +00002449 {
2450 new->prefix = pref;
Simon Kelley30cd9662012-03-25 20:44:38 +01002451 leasepos++;
Simon Kelley52b92f42012-01-22 16:05:15 +00002452 }
2453 }
Simon Kelley30cd9662012-03-25 20:44:38 +01002454
Simon Kelley6692a1a2013-08-20 14:41:31 +01002455 if (new->prefix != 64)
2456 {
2457 if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
2458 ret_err(_("prefix length must be exactly 64 for RA subnets"));
2459 else if (new->flags & CONTEXT_TEMPLATE)
2460 ret_err(_("prefix length must be exactly 64 for subnet constructors"));
2461 }
2462
2463 if (new->prefix < 64)
2464 ret_err(_("prefix length must be at least 64"));
2465
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002466 if (!is_same_net6(&new->start6, &new->end6, new->prefix))
2467 ret_err(_("inconsistent DHCPv6 range"));
Simon Kelley6692a1a2013-08-20 14:41:31 +01002468
2469 /* dhcp-range=:: enables DHCP stateless on any interface */
2470 if (IN6_IS_ADDR_UNSPECIFIED(&new->start6) && !(new->flags & CONTEXT_TEMPLATE))
2471 new->prefix = 0;
Simon Kelley66409192013-08-01 20:19:32 +01002472
2473 if (new->flags & CONTEXT_TEMPLATE)
2474 {
2475 struct in6_addr zero;
2476 memset(&zero, 0, sizeof(zero));
2477 if (!is_same_net6(&zero, &new->start6, new->prefix))
2478 ret_err(_("prefix must be zero with \"constructor:\" argument"));
2479 }
2480
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002481 if (addr6part(&new->start6) > addr6part(&new->end6))
Simon Kelley52b92f42012-01-22 16:05:15 +00002482 {
2483 struct in6_addr tmp = new->start6;
2484 new->start6 = new->end6;
2485 new->end6 = tmp;
2486 }
Simon Kelley849a8352006-06-09 21:02:31 +01002487 }
Simon Kelley52b92f42012-01-22 16:05:15 +00002488#endif
Simon Kelleyd9ee9c02013-04-12 11:17:55 +01002489 else
2490 ret_err(_("bad dhcp-range"));
Simon Kelley849a8352006-06-09 21:02:31 +01002491
Simon Kelley30cd9662012-03-25 20:44:38 +01002492 if (leasepos < k)
Simon Kelley849a8352006-06-09 21:02:31 +01002493 {
2494 if (strcmp(a[leasepos], "infinite") == 0)
2495 new->lease_time = 0xffffffff;
Simon Kelleyc8257542012-03-28 21:15:41 +01002496 else if (strcmp(a[leasepos], "deprecated") == 0)
2497 new->flags |= CONTEXT_DEPRECATE;
Simon Kelley849a8352006-06-09 21:02:31 +01002498 else
2499 {
2500 int fac = 1;
2501 if (strlen(a[leasepos]) > 0)
2502 {
2503 switch (a[leasepos][strlen(a[leasepos]) - 1])
2504 {
Simon Kelley42243212012-07-20 15:19:18 +01002505 case 'w':
2506 case 'W':
2507 fac *= 7;
2508 /* fall through */
Simon Kelley849a8352006-06-09 21:02:31 +01002509 case 'd':
2510 case 'D':
2511 fac *= 24;
2512 /* fall though */
2513 case 'h':
2514 case 'H':
2515 fac *= 60;
2516 /* fall through */
2517 case 'm':
2518 case 'M':
2519 fac *= 60;
2520 /* fall through */
2521 case 's':
2522 case 'S':
Simon Kelleyf2621c72007-04-29 19:47:21 +01002523 a[leasepos][strlen(a[leasepos]) - 1] = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002524 }
2525
Simon Kelleybe379862012-12-23 12:01:39 +00002526 for (cp = a[leasepos]; *cp; cp++)
2527 if (!(*cp >= '0' && *cp <= '9'))
2528 break;
2529
Simon Kelley54dae552013-02-05 17:55:10 +00002530 if (*cp || (leasepos+1 < k))
Simon Kelleybe379862012-12-23 12:01:39 +00002531 ret_err(_("bad dhcp-range"));
2532
Simon Kelley849a8352006-06-09 21:02:31 +01002533 new->lease_time = atoi(a[leasepos]) * fac;
2534 /* Leases of a minute or less confuse
2535 some clients, notably Apple's */
2536 if (new->lease_time < 120)
2537 new->lease_time = 120;
2538 }
2539 }
2540 }
2541 break;
2542 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01002543
Simon Kelley5aabfc72007-08-29 11:24:47 +01002544 case LOPT_BANK:
Simon Kelleyf2621c72007-04-29 19:47:21 +01002545 case 'G': /* --dhcp-host */
Simon Kelley849a8352006-06-09 21:02:31 +01002546 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01002547 int j, k = 0;
Simon Kelley3e8ed782013-05-29 14:31:33 +01002548 char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
Simon Kelley5aabfc72007-08-29 11:24:47 +01002549 struct dhcp_config *new;
Simon Kelley849a8352006-06-09 21:02:31 +01002550 struct in_addr in;
2551
Simon Kelley824af852008-02-12 20:43:05 +00002552 new = opt_malloc(sizeof(struct dhcp_config));
2553
Simon Kelley849a8352006-06-09 21:02:31 +01002554 new->next = daemon->dhcp_conf;
Simon Kelley9009d742008-11-14 20:04:27 +00002555 new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
2556 new->hwaddr = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002557 new->netid = NULL;
2558
Simon Kelley849a8352006-06-09 21:02:31 +01002559 if ((a[0] = arg))
Simon Kelley3e8ed782013-05-29 14:31:33 +01002560 for (k = 1; k < 7; k++)
Simon Kelleyf2621c72007-04-29 19:47:21 +01002561 if (!(a[k] = split(a[k-1])))
2562 break;
Simon Kelley849a8352006-06-09 21:02:31 +01002563
2564 for (j = 0; j < k; j++)
2565 if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
2566 {
2567 char *arg = a[j];
2568
2569 if ((arg[0] == 'i' || arg[0] == 'I') &&
2570 (arg[1] == 'd' || arg[1] == 'D') &&
2571 arg[2] == ':')
2572 {
2573 if (arg[3] == '*')
2574 new->flags |= CONFIG_NOCLID;
2575 else
2576 {
2577 int len;
2578 arg += 3; /* dump id: */
2579 if (strchr(arg, ':'))
2580 len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
2581 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01002582 {
2583 unhide_metas(arg);
2584 len = (int) strlen(arg);
2585 }
2586
Simon Kelley28866e92011-02-14 20:19:14 +00002587 if (len == -1)
Simon Kelley9f7f3b12012-05-28 21:39:57 +01002588
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002589 ret_err(_("bad hex constant"));
Simon Kelley28866e92011-02-14 20:19:14 +00002590 else if ((new->clid = opt_malloc(len)))
Simon Kelley5aabfc72007-08-29 11:24:47 +01002591 {
2592 new->flags |= CONFIG_CLID;
2593 new->clid_len = len;
2594 memcpy(new->clid, arg, len);
2595 }
Simon Kelley849a8352006-06-09 21:02:31 +01002596 }
2597 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002598 /* dhcp-host has strange backwards-compat needs. */
2599 else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg)
Simon Kelley849a8352006-06-09 21:02:31 +01002600 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002601 struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
2602 struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
2603 newtag->net = opt_malloc(strlen(arg + 4) + 1);
2604 newlist->next = new->netid;
2605 new->netid = newlist;
2606 newlist->list = newtag;
2607 strcpy(newtag->net, arg+4);
2608 unhide_metas(newtag->net);
Simon Kelley849a8352006-06-09 21:02:31 +01002609 }
Simon Kelley7de060b2011-08-26 17:24:52 +01002610 else if (strstr(arg, "tag:") == arg)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002611 ret_err(_("cannot match tags in --dhcp-host"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00002612#ifdef HAVE_DHCP6
2613 else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
2614 {
2615 arg[strlen(arg)-1] = 0;
2616 arg++;
2617
2618 if (!inet_pton(AF_INET6, arg, &new->addr6))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002619 ret_err(_("bad IPv6 address"));
Simon Kelley30393102013-01-17 16:34:16 +00002620
2621 for (i= 0; i < 8; i++)
2622 if (new->addr6.s6_addr[i] != 0)
2623 break;
2624
2625 /* set WILDCARD if network part all zeros */
2626 if (i == 8)
2627 new->flags |= CONFIG_WILDCARD;
Simon Kelley4cb1b322012-02-06 14:30:41 +00002628
2629 new->flags |= CONFIG_ADDR6;
2630 }
2631#endif
Simon Kelley7de060b2011-08-26 17:24:52 +01002632 else
Simon Kelley849a8352006-06-09 21:02:31 +01002633 {
Simon Kelley9009d742008-11-14 20:04:27 +00002634 struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
Simon Kelley28866e92011-02-14 20:19:14 +00002635 if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
2636 &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002637 ret_err(_("bad hex constant"));
Simon Kelley28866e92011-02-14 20:19:14 +00002638 else
2639 {
2640
2641 newhw->next = new->hwaddr;
2642 new->hwaddr = newhw;
2643 }
Simon Kelley849a8352006-06-09 21:02:31 +01002644 }
2645 }
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002646 else if (strchr(a[j], '.') && (inet_pton(AF_INET, a[j], &in) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01002647 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002648 struct dhcp_config *configs;
2649
Simon Kelley849a8352006-06-09 21:02:31 +01002650 new->addr = in;
2651 new->flags |= CONFIG_ADDR;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002652
2653 /* If the same IP appears in more than one host config, then DISCOVER
2654 for one of the hosts will get the address, but REQUEST will be NAKed,
2655 since the address is reserved by the other one -> protocol loop. */
2656 for (configs = daemon->dhcp_conf; configs; configs = configs->next)
2657 if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr)
2658 {
2659 sprintf(errstr, _("duplicate dhcp-host IP address %s"), inet_ntoa(in));
2660 return 0;
2661 }
Simon Kelley849a8352006-06-09 21:02:31 +01002662 }
2663 else
2664 {
2665 char *cp, *lastp = NULL, last = 0;
2666 int fac = 1;
2667
2668 if (strlen(a[j]) > 1)
2669 {
2670 lastp = a[j] + strlen(a[j]) - 1;
2671 last = *lastp;
2672 switch (last)
2673 {
Simon Kelley42243212012-07-20 15:19:18 +01002674 case 'w':
2675 case 'W':
2676 fac *= 7;
2677 /* fall through */
Simon Kelley849a8352006-06-09 21:02:31 +01002678 case 'd':
2679 case 'D':
2680 fac *= 24;
2681 /* fall through */
2682 case 'h':
2683 case 'H':
2684 fac *= 60;
2685 /* fall through */
2686 case 'm':
2687 case 'M':
2688 fac *= 60;
2689 /* fall through */
2690 case 's':
2691 case 'S':
2692 *lastp = 0;
2693 }
2694 }
2695
2696 for (cp = a[j]; *cp; cp++)
Simon Kelley572b41e2011-02-18 18:11:18 +00002697 if (!isdigit((unsigned char)*cp) && *cp != ' ')
Simon Kelley849a8352006-06-09 21:02:31 +01002698 break;
2699
2700 if (*cp)
2701 {
2702 if (lastp)
2703 *lastp = last;
2704 if (strcmp(a[j], "infinite") == 0)
2705 {
2706 new->lease_time = 0xffffffff;
2707 new->flags |= CONFIG_TIME;
2708 }
2709 else if (strcmp(a[j], "ignore") == 0)
2710 new->flags |= CONFIG_DISABLE;
2711 else
2712 {
Simon Kelley1f15b812009-10-13 17:49:32 +01002713 if (!(new->hostname = canonicalise_opt(a[j])) ||
2714 !legal_hostname(new->hostname))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002715 ret_err(_("bad DHCP host name"));
2716
2717 new->flags |= CONFIG_NAME;
2718 new->domain = strip_hostname(new->hostname);
Simon Kelley849a8352006-06-09 21:02:31 +01002719 }
2720 }
2721 else
2722 {
2723 new->lease_time = atoi(a[j]) * fac;
2724 /* Leases of a minute or less confuse
2725 some clients, notably Apple's */
2726 if (new->lease_time < 120)
2727 new->lease_time = 120;
2728 new->flags |= CONFIG_TIME;
2729 }
2730 }
2731
Simon Kelley5aabfc72007-08-29 11:24:47 +01002732 daemon->dhcp_conf = new;
Simon Kelley849a8352006-06-09 21:02:31 +01002733 break;
2734 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002735
2736 case LOPT_TAG_IF: /* --tag-if */
2737 {
2738 struct tag_if *new = opt_malloc(sizeof(struct tag_if));
2739
2740 new->tag = NULL;
2741 new->set = NULL;
2742 new->next = NULL;
2743
2744 /* preserve order */
2745 if (!daemon->tag_if)
2746 daemon->tag_if = new;
2747 else
2748 {
2749 struct tag_if *tmp;
2750 for (tmp = daemon->tag_if; tmp->next; tmp = tmp->next);
2751 tmp->next = new;
2752 }
2753
2754 while (arg)
2755 {
2756 size_t len;
2757
2758 comma = split(arg);
2759 len = strlen(arg);
2760
2761 if (len < 5)
2762 {
2763 new->set = NULL;
2764 break;
2765 }
2766 else
2767 {
2768 struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
2769 newtag->net = opt_malloc(len - 3);
2770 strcpy(newtag->net, arg+4);
2771 unhide_metas(newtag->net);
2772
2773 if (strstr(arg, "set:") == arg)
2774 {
2775 struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
2776 newlist->next = new->set;
2777 new->set = newlist;
2778 newlist->list = newtag;
2779 }
2780 else if (strstr(arg, "tag:") == arg)
2781 {
2782 newtag->next = new->tag;
2783 new->tag = newtag;
2784 }
2785 else
2786 {
2787 new->set = NULL;
Simon Kelley4dc9c652013-02-04 21:43:52 +00002788 free(newtag);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002789 break;
2790 }
2791 }
2792
2793 arg = comma;
2794 }
2795
2796 if (!new->set)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002797 ret_err(_("bad tag-if"));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002798
2799 break;
2800 }
2801
Simon Kelley849a8352006-06-09 21:02:31 +01002802
Simon Kelley73a08a22009-02-05 20:28:08 +00002803 case 'O': /* --dhcp-option */
2804 case LOPT_FORCE: /* --dhcp-option-force */
Simon Kelley824af852008-02-12 20:43:05 +00002805 case LOPT_OPTS:
Simon Kelley73a08a22009-02-05 20:28:08 +00002806 case LOPT_MATCH: /* --dhcp-match */
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002807 return parse_dhcp_opt(errstr, arg,
2808 option == LOPT_FORCE ? DHOPT_FORCE :
2809 (option == LOPT_MATCH ? DHOPT_MATCH :
2810 (option == LOPT_OPTS ? DHOPT_BANK : 0)));
2811
Simon Kelleyf2621c72007-04-29 19:47:21 +01002812 case 'M': /* --dhcp-boot */
Simon Kelley849a8352006-06-09 21:02:31 +01002813 {
2814 struct dhcp_netid *id = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002815 while (is_tag_prefix(arg))
Simon Kelley849a8352006-06-09 21:02:31 +01002816 {
Simon Kelley824af852008-02-12 20:43:05 +00002817 struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
Simon Kelley849a8352006-06-09 21:02:31 +01002818 newid->next = id;
2819 id = newid;
Simon Kelleyf2621c72007-04-29 19:47:21 +01002820 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00002821 newid->net = opt_string_alloc(arg+4);
Simon Kelley849a8352006-06-09 21:02:31 +01002822 arg = comma;
2823 };
2824
2825 if (!arg)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002826 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002827 else
2828 {
Simon Kelley7de060b2011-08-26 17:24:52 +01002829 char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +01002830 struct in_addr dhcp_next_server;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002831 struct dhcp_boot *new;
Simon Kelleyf2621c72007-04-29 19:47:21 +01002832 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00002833 dhcp_file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002834 dhcp_next_server.s_addr = 0;
2835 if (comma)
2836 {
2837 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01002838 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00002839 dhcp_sname = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002840 if (comma)
2841 {
2842 unhide_metas(comma);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002843 if (!(inet_pton(AF_INET, comma, &dhcp_next_server) > 0))
2844 {
2845 /*
2846 * The user may have specified the tftp hostname here.
2847 * save it so that it can be resolved/looked up during
2848 * actual dhcp_reply().
2849 */
2850
2851 tftp_sname = opt_string_alloc(comma);
2852 dhcp_next_server.s_addr = 0;
2853 }
Simon Kelley849a8352006-06-09 21:02:31 +01002854 }
2855 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002856
2857 new = opt_malloc(sizeof(struct dhcp_boot));
2858 new->file = dhcp_file;
2859 new->sname = dhcp_sname;
2860 new->tftp_sname = tftp_sname;
2861 new->next_server = dhcp_next_server;
2862 new->netid = id;
2863 new->next = daemon->boot_config;
2864 daemon->boot_config = new;
Simon Kelley849a8352006-06-09 21:02:31 +01002865 }
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002866
Simon Kelley849a8352006-06-09 21:02:31 +01002867 break;
2868 }
Simon Kelley7622fc02009-06-04 20:32:05 +01002869
2870 case LOPT_PXE_PROMT: /* --pxe-prompt */
2871 {
2872 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
2873 int timeout;
2874
2875 new->netid = NULL;
2876 new->opt = 10; /* PXE_MENU_PROMPT */
2877
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002878 while (is_tag_prefix(arg))
2879 {
Simon Kelley7622fc02009-06-04 20:32:05 +01002880 struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
2881 comma = split(arg);
2882 nn->next = new->netid;
2883 new->netid = nn;
2884 nn->net = opt_string_alloc(arg+4);
2885 arg = comma;
2886 }
2887
2888 if (!arg)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002889 ret_err(gen_err);
Simon Kelley7622fc02009-06-04 20:32:05 +01002890 else
2891 {
2892 comma = split(arg);
2893 unhide_metas(arg);
2894 new->len = strlen(arg) + 1;
2895 new->val = opt_malloc(new->len);
2896 memcpy(new->val + 1, arg, new->len - 1);
2897
2898 new->u.vendor_class = (unsigned char *)"PXEClient";
2899 new->flags = DHOPT_VENDOR;
2900
2901 if (comma && atoi_check(comma, &timeout))
2902 *(new->val) = timeout;
2903 else
2904 *(new->val) = 255;
2905
2906 new->next = daemon->dhcp_opts;
2907 daemon->dhcp_opts = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01002908 daemon->enable_pxe = 1;
Simon Kelley7622fc02009-06-04 20:32:05 +01002909 }
2910
2911 break;
2912 }
2913
2914 case LOPT_PXE_SERV: /* --pxe-service */
2915 {
2916 struct pxe_service *new = opt_malloc(sizeof(struct pxe_service));
2917 char *CSA[] = { "x86PC", "PC98", "IA64_EFI", "Alpha", "Arc_x86", "Intel_Lean_Client",
2918 "IA32_EFI", "BC_EFI", "Xscale_EFI", "x86-64_EFI", NULL };
2919 static int boottype = 32768;
2920
2921 new->netid = NULL;
Simon Kelley751d6f42012-02-10 15:24:51 +00002922 new->sname = NULL;
Simon Kelley7622fc02009-06-04 20:32:05 +01002923 new->server.s_addr = 0;
2924
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002925 while (is_tag_prefix(arg))
Simon Kelley7622fc02009-06-04 20:32:05 +01002926 {
2927 struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
2928 comma = split(arg);
2929 nn->next = new->netid;
2930 new->netid = nn;
2931 nn->net = opt_string_alloc(arg+4);
2932 arg = comma;
2933 }
2934
2935 if (arg && (comma = split(arg)))
2936 {
2937 for (i = 0; CSA[i]; i++)
2938 if (strcasecmp(CSA[i], arg) == 0)
2939 break;
2940
2941 if (CSA[i] || atoi_check(arg, &i))
2942 {
2943 arg = comma;
2944 comma = split(arg);
2945
2946 new->CSA = i;
2947 new->menu = opt_string_alloc(arg);
2948
Simon Kelley316e2732010-01-22 20:16:09 +00002949 if (!comma)
2950 {
2951 new->type = 0; /* local boot */
2952 new->basename = NULL;
2953 }
2954 else
Simon Kelley7622fc02009-06-04 20:32:05 +01002955 {
2956 arg = comma;
2957 comma = split(arg);
2958 if (atoi_check(arg, &i))
2959 {
2960 new->type = i;
2961 new->basename = NULL;
2962 }
2963 else
2964 {
2965 new->type = boottype++;
2966 new->basename = opt_string_alloc(arg);
2967 }
2968
Simon Kelley751d6f42012-02-10 15:24:51 +00002969 if (comma)
2970 {
2971 if (!inet_pton(AF_INET, comma, &new->server))
2972 {
2973 new->server.s_addr = 0;
2974 new->sname = opt_string_alloc(comma);
2975 }
2976
2977 }
Simon Kelley7622fc02009-06-04 20:32:05 +01002978 }
Simon Kelley751d6f42012-02-10 15:24:51 +00002979
Simon Kelley316e2732010-01-22 20:16:09 +00002980 /* Order matters */
2981 new->next = NULL;
2982 if (!daemon->pxe_services)
2983 daemon->pxe_services = new;
2984 else
2985 {
2986 struct pxe_service *s;
2987 for (s = daemon->pxe_services; s->next; s = s->next);
2988 s->next = new;
2989 }
2990
2991 daemon->enable_pxe = 1;
2992 break;
2993
Simon Kelley7622fc02009-06-04 20:32:05 +01002994 }
2995 }
2996
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002997 ret_err(gen_err);
Simon Kelley7622fc02009-06-04 20:32:05 +01002998 }
2999
Simon Kelleyf2621c72007-04-29 19:47:21 +01003000 case '4': /* --dhcp-mac */
Simon Kelley849a8352006-06-09 21:02:31 +01003001 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01003002 if (!(comma = split(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003003 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01003004 else
3005 {
Simon Kelley824af852008-02-12 20:43:05 +00003006 struct dhcp_mac *new = opt_malloc(sizeof(struct dhcp_mac));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003007 new->netid.net = opt_string_alloc(set_prefix(arg));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003008 unhide_metas(comma);
3009 new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
Simon Kelley28866e92011-02-14 20:19:14 +00003010 if (new->hwaddr_len == -1)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003011 ret_err(gen_err);
Simon Kelley28866e92011-02-14 20:19:14 +00003012 else
3013 {
3014 new->next = daemon->dhcp_macs;
3015 daemon->dhcp_macs = new;
3016 }
Simon Kelley849a8352006-06-09 21:02:31 +01003017 }
3018 }
3019 break;
Simon Kelleyc6309242013-03-07 20:59:28 +00003020
3021#ifdef OPTION6_PREFIX_CLASS
3022 case LOPT_PREF_CLSS: /* --dhcp-prefix-class */
3023 {
3024 struct prefix_class *new = opt_malloc(sizeof(struct prefix_class));
3025
3026 if (!(comma = split(arg)) ||
3027 !atoi_check16(comma, &new->class))
3028 ret_err(gen_err);
3029
3030 new->tag.net = opt_string_alloc(set_prefix(arg));
3031 new->next = daemon->prefix_classes;
3032 daemon->prefix_classes = new;
3033
3034 break;
3035 }
3036#endif
3037
3038
Simon Kelleyf2621c72007-04-29 19:47:21 +01003039 case 'U': /* --dhcp-vendorclass */
3040 case 'j': /* --dhcp-userclass */
3041 case LOPT_CIRCUIT: /* --dhcp-circuitid */
3042 case LOPT_REMOTE: /* --dhcp-remoteid */
3043 case LOPT_SUBSCR: /* --dhcp-subscrid */
Simon Kelley849a8352006-06-09 21:02:31 +01003044 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003045 unsigned char *p;
3046 int dig = 0;
3047 struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
3048
3049 if (!(comma = split(arg)))
3050 ret_err(gen_err);
3051
3052 new->netid.net = opt_string_alloc(set_prefix(arg));
3053 /* check for hex string - must digits may include : must not have nothing else,
3054 only allowed for agent-options. */
3055
3056 arg = comma;
3057 if ((comma = split(arg)))
3058 {
3059 if (option != 'U' || strstr(arg, "enterprise:") != arg)
3060 ret_err(gen_err);
3061 else
3062 new->enterprise = atoi(arg+11);
3063 }
3064 else
3065 comma = arg;
3066
3067 for (p = (unsigned char *)comma; *p; p++)
3068 if (isxdigit(*p))
3069 dig = 1;
3070 else if (*p != ':')
3071 break;
3072 unhide_metas(comma);
3073 if (option == 'U' || option == 'j' || *p || !dig)
3074 {
3075 new->len = strlen(comma);
3076 new->data = opt_malloc(new->len);
3077 memcpy(new->data, comma, new->len);
3078 }
3079 else
3080 {
3081 new->len = parse_hex(comma, (unsigned char *)comma, strlen(comma), NULL, NULL);
3082 new->data = opt_malloc(new->len);
3083 memcpy(new->data, comma, new->len);
3084 }
3085
3086 switch (option)
3087 {
3088 case 'j':
3089 new->match_type = MATCH_USER;
3090 break;
3091 case 'U':
3092 new->match_type = MATCH_VENDOR;
3093 break;
3094 case LOPT_CIRCUIT:
3095 new->match_type = MATCH_CIRCUIT;
3096 break;
3097 case LOPT_REMOTE:
3098 new->match_type = MATCH_REMOTE;
3099 break;
3100 case LOPT_SUBSCR:
3101 new->match_type = MATCH_SUBSCRIBER;
3102 break;
3103 }
3104 new->next = daemon->dhcp_vendors;
3105 daemon->dhcp_vendors = new;
Simon Kelleya5c72ab2012-02-10 13:42:47 +00003106
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003107 break;
Simon Kelley849a8352006-06-09 21:02:31 +01003108 }
3109
Simon Kelley9e038942008-05-30 20:06:34 +01003110 case LOPT_ALTPORT: /* --dhcp-alternate-port */
3111 if (!arg)
3112 {
3113 daemon->dhcp_server_port = DHCP_SERVER_ALTPORT;
3114 daemon->dhcp_client_port = DHCP_CLIENT_ALTPORT;
3115 }
3116 else
3117 {
3118 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01003119 if (!atoi_check16(arg, &daemon->dhcp_server_port) ||
3120 (comma && !atoi_check16(comma, &daemon->dhcp_client_port)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003121 ret_err(_("invalid port number"));
Simon Kelley9e038942008-05-30 20:06:34 +01003122 if (!comma)
3123 daemon->dhcp_client_port = daemon->dhcp_server_port+1;
3124 }
3125 break;
3126
Simon Kelley824af852008-02-12 20:43:05 +00003127 case 'J': /* --dhcp-ignore */
3128 case LOPT_NO_NAMES: /* --dhcp-ignore-names */
3129 case LOPT_BROADCAST: /* --dhcp-broadcast */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003130 case '3': /* --bootp-dynamic */
3131 case LOPT_GEN_NAMES: /* --dhcp-generate-names */
Simon Kelley849a8352006-06-09 21:02:31 +01003132 {
Simon Kelley824af852008-02-12 20:43:05 +00003133 struct dhcp_netid_list *new = opt_malloc(sizeof(struct dhcp_netid_list));
Simon Kelley849a8352006-06-09 21:02:31 +01003134 struct dhcp_netid *list = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00003135 if (option == 'J')
3136 {
3137 new->next = daemon->dhcp_ignore;
3138 daemon->dhcp_ignore = new;
3139 }
Simon Kelley824af852008-02-12 20:43:05 +00003140 else if (option == LOPT_BROADCAST)
3141 {
3142 new->next = daemon->force_broadcast;
3143 daemon->force_broadcast = new;
3144 }
Simon Kelley9009d742008-11-14 20:04:27 +00003145 else if (option == '3')
3146 {
3147 new->next = daemon->bootp_dynamic;
3148 daemon->bootp_dynamic = new;
3149 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003150 else if (option == LOPT_GEN_NAMES)
3151 {
3152 new->next = daemon->dhcp_gen_names;
3153 daemon->dhcp_gen_names = new;
3154 }
Simon Kelley832af0b2007-01-21 20:01:28 +00003155 else
3156 {
3157 new->next = daemon->dhcp_ignore_names;
3158 daemon->dhcp_ignore_names = new;
3159 }
3160
3161 while (arg) {
Simon Kelley824af852008-02-12 20:43:05 +00003162 struct dhcp_netid *member = opt_malloc(sizeof(struct dhcp_netid));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003163 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003164 member->next = list;
3165 list = member;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003166 if (is_tag_prefix(arg))
Simon Kelley9009d742008-11-14 20:04:27 +00003167 member->net = opt_string_alloc(arg+4);
3168 else
3169 member->net = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003170 arg = comma;
Simon Kelley832af0b2007-01-21 20:01:28 +00003171 }
Simon Kelley849a8352006-06-09 21:02:31 +01003172
3173 new->list = list;
3174 break;
3175 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003176
3177 case LOPT_PROXY: /* --dhcp-proxy */
3178 daemon->override = 1;
3179 while (arg) {
3180 struct addr_list *new = opt_malloc(sizeof(struct addr_list));
3181 comma = split(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003182 if (!(inet_pton(AF_INET, arg, &new->addr) > 0))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003183 ret_err(_("bad dhcp-proxy address"));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003184 new->next = daemon->override_relays;
3185 daemon->override_relays = new;
3186 arg = comma;
3187 }
3188 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01003189#endif
Simon Kelley849a8352006-06-09 21:02:31 +01003190
Simon Kelley8b372702012-03-09 17:45:10 +00003191#ifdef HAVE_DHCP6
3192 case LOPT_DUID: /* --dhcp-duid */
3193 if (!(comma = split(arg)) || !atoi_check(arg, (int *)&daemon->duid_enterprise))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003194 ret_err(_("bad DUID"));
Simon Kelley8b372702012-03-09 17:45:10 +00003195 else
3196 {
3197 daemon->duid_config_len = parse_hex(comma,(unsigned char *)comma, strlen(comma), NULL, NULL);
3198 daemon->duid_config = opt_malloc(daemon->duid_config_len);
3199 memcpy(daemon->duid_config, comma, daemon->duid_config_len);
3200 }
3201 break;
3202#endif
3203
Simon Kelleyf2621c72007-04-29 19:47:21 +01003204 case 'V': /* --alias */
Simon Kelley849a8352006-06-09 21:02:31 +01003205 {
Simon Kelley73a08a22009-02-05 20:28:08 +00003206 char *dash, *a[3] = { NULL, NULL, NULL };
Simon Kelleyf2621c72007-04-29 19:47:21 +01003207 int k = 0;
Simon Kelley73a08a22009-02-05 20:28:08 +00003208 struct doctor *new = opt_malloc(sizeof(struct doctor));
3209 new->next = daemon->doctors;
3210 daemon->doctors = new;
3211 new->mask.s_addr = 0xffffffff;
3212 new->end.s_addr = 0;
3213
Simon Kelley849a8352006-06-09 21:02:31 +01003214 if ((a[0] = arg))
3215 for (k = 1; k < 3; k++)
3216 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01003217 if (!(a[k] = split(a[k-1])))
Simon Kelley849a8352006-06-09 21:02:31 +01003218 break;
Simon Kelley849a8352006-06-09 21:02:31 +01003219 unhide_metas(a[k]);
3220 }
Simon Kelley849a8352006-06-09 21:02:31 +01003221
Simon Kelley73a08a22009-02-05 20:28:08 +00003222 dash = split_chr(a[0], '-');
3223
Simon Kelley849a8352006-06-09 21:02:31 +01003224 if ((k < 2) ||
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003225 (!(inet_pton(AF_INET, a[0], &new->in) > 0)) ||
3226 (!(inet_pton(AF_INET, a[1], &new->out) > 0)))
Simon Kelley73a08a22009-02-05 20:28:08 +00003227 option = '?';
Simon Kelley849a8352006-06-09 21:02:31 +01003228
3229 if (k == 3)
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003230 inet_pton(AF_INET, a[2], &new->mask);
Simon Kelley849a8352006-06-09 21:02:31 +01003231
Simon Kelley73a08a22009-02-05 20:28:08 +00003232 if (dash &&
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003233 (!(inet_pton(AF_INET, dash, &new->end) > 0) ||
Simon Kelley73a08a22009-02-05 20:28:08 +00003234 !is_same_net(new->in, new->end, new->mask) ||
3235 ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003236 ret_err(_("invalid alias range"));
Simon Kelley849a8352006-06-09 21:02:31 +01003237
3238 break;
3239 }
3240
Simon Kelleyf2621c72007-04-29 19:47:21 +01003241 case LOPT_INTNAME: /* --interface-name */
3242 {
3243 struct interface_name *new, **up;
Simon Kelley1f15b812009-10-13 17:49:32 +01003244 char *domain = NULL;
3245
Simon Kelleyf2621c72007-04-29 19:47:21 +01003246 comma = split(arg);
3247
Simon Kelley1f15b812009-10-13 17:49:32 +01003248 if (!comma || !(domain = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003249 ret_err(_("bad interface name"));
Simon Kelley1f15b812009-10-13 17:49:32 +01003250
Simon Kelley824af852008-02-12 20:43:05 +00003251 new = opt_malloc(sizeof(struct interface_name));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003252 new->next = NULL;
Simon Kelley115ac3e2013-05-20 11:28:32 +01003253 new->addr4 = NULL;
3254#ifdef HAVE_IPV6
3255 new->addr6 = NULL;
3256#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +01003257 /* Add to the end of the list, so that first name
3258 of an interface is used for PTR lookups. */
Simon Kelley824af852008-02-12 20:43:05 +00003259 for (up = &daemon->int_names; *up; up = &((*up)->next));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003260 *up = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003261 new->name = domain;
Simon Kelley824af852008-02-12 20:43:05 +00003262 new->intr = opt_string_alloc(comma);
Simon Kelleyf2621c72007-04-29 19:47:21 +01003263 break;
3264 }
Simon Kelley9009d742008-11-14 20:04:27 +00003265
3266 case LOPT_CNAME: /* --cname */
3267 {
3268 struct cname *new;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003269 char *alias;
3270 char *target;
3271
Simon Kelley9009d742008-11-14 20:04:27 +00003272 if (!(comma = split(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003273 ret_err(gen_err);
3274
3275 alias = canonicalise_opt(arg);
3276 target = canonicalise_opt(comma);
3277
3278 if (!alias || !target)
3279 ret_err(_("bad CNAME"));
Simon Kelley9009d742008-11-14 20:04:27 +00003280 else
3281 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003282 for (new = daemon->cnames; new; new = new->next)
3283 if (hostname_isequal(new->alias, arg))
3284 ret_err(_("duplicate CNAME"));
3285 new = opt_malloc(sizeof(struct cname));
3286 new->next = daemon->cnames;
3287 daemon->cnames = new;
3288 new->alias = alias;
3289 new->target = target;
Simon Kelley9009d742008-11-14 20:04:27 +00003290 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003291
Simon Kelley9009d742008-11-14 20:04:27 +00003292 break;
3293 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01003294
3295 case LOPT_PTR: /* --ptr-record */
Simon Kelley832af0b2007-01-21 20:01:28 +00003296 {
3297 struct ptr_record *new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003298 char *dom, *target = NULL;
3299
Simon Kelleyf2621c72007-04-29 19:47:21 +01003300 comma = split(arg);
3301
Simon Kelley1f15b812009-10-13 17:49:32 +01003302 if (!(dom = canonicalise_opt(arg)) ||
3303 (comma && !(target = canonicalise_opt(comma))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003304 ret_err(_("bad PTR record"));
Simon Kelley1f15b812009-10-13 17:49:32 +01003305 else
3306 {
3307 new = opt_malloc(sizeof(struct ptr_record));
3308 new->next = daemon->ptr;
3309 daemon->ptr = new;
3310 new->name = dom;
3311 new->ptr = target;
3312 }
Simon Kelley832af0b2007-01-21 20:01:28 +00003313 break;
3314 }
3315
Simon Kelley1a6bca82008-07-11 11:11:42 +01003316 case LOPT_NAPTR: /* --naptr-record */
3317 {
3318 char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
3319 int k = 0;
3320 struct naptr *new;
3321 int order, pref;
Simon Kelley1f15b812009-10-13 17:49:32 +01003322 char *name, *replace = NULL;
Simon Kelley1a6bca82008-07-11 11:11:42 +01003323
3324 if ((a[0] = arg))
3325 for (k = 1; k < 7; k++)
3326 if (!(a[k] = split(a[k-1])))
3327 break;
3328
3329
3330 if (k < 6 ||
Simon Kelley1f15b812009-10-13 17:49:32 +01003331 !(name = canonicalise_opt(a[0])) ||
Simon Kelley1ad24ae2008-07-20 20:22:50 +01003332 !atoi_check16(a[1], &order) ||
3333 !atoi_check16(a[2], &pref) ||
Simon Kelley1f15b812009-10-13 17:49:32 +01003334 (k == 7 && !(replace = canonicalise_opt(a[6]))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003335 ret_err(_("bad NAPTR record"));
Simon Kelley1a6bca82008-07-11 11:11:42 +01003336 else
3337 {
3338 new = opt_malloc(sizeof(struct naptr));
3339 new->next = daemon->naptr;
3340 daemon->naptr = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003341 new->name = name;
Simon Kelley1a6bca82008-07-11 11:11:42 +01003342 new->flags = opt_string_alloc(a[3]);
3343 new->services = opt_string_alloc(a[4]);
3344 new->regexp = opt_string_alloc(a[5]);
Simon Kelley1f15b812009-10-13 17:49:32 +01003345 new->replace = replace;
Simon Kelley1a6bca82008-07-11 11:11:42 +01003346 new->order = order;
3347 new->pref = pref;
3348 }
3349 break;
3350 }
Simon Kelley9f7f3b12012-05-28 21:39:57 +01003351
3352 case LOPT_RR: /* dns-rr */
3353 {
3354 struct txt_record *new;
3355 size_t len;
3356 char *data;
3357 int val;
3358
3359 comma = split(arg);
3360 data = split(comma);
3361
3362 new = opt_malloc(sizeof(struct txt_record));
3363 new->next = daemon->rr;
3364 daemon->rr = new;
3365
3366 if (!atoi_check(comma, &val) ||
3367 !(new->name = canonicalise_opt(arg)) ||
Simon Kelley51931b82012-05-29 17:06:02 +01003368 (data && (len = parse_hex(data, (unsigned char *)data, -1, NULL, NULL)) == -1U))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003369 ret_err(_("bad RR record"));
3370
Simon Kelley9f7f3b12012-05-28 21:39:57 +01003371 new->class = val;
3372 new->len = 0;
3373
3374 if (data)
3375 {
3376 new->txt=opt_malloc(len);
3377 new->len = len;
3378 memcpy(new->txt, data, len);
3379 }
3380
3381 break;
3382 }
3383
Simon Kelleyf2621c72007-04-29 19:47:21 +01003384 case 'Y': /* --txt-record */
Simon Kelley849a8352006-06-09 21:02:31 +01003385 {
3386 struct txt_record *new;
Simon Kelley28866e92011-02-14 20:19:14 +00003387 unsigned char *p, *cnt;
3388 size_t len;
3389
3390 comma = split(arg);
3391
Simon Kelley824af852008-02-12 20:43:05 +00003392 new = opt_malloc(sizeof(struct txt_record));
Simon Kelley849a8352006-06-09 21:02:31 +01003393 new->next = daemon->txt;
3394 daemon->txt = new;
3395 new->class = C_IN;
Simon Kelley849a8352006-06-09 21:02:31 +01003396
Simon Kelley1f15b812009-10-13 17:49:32 +01003397 if (!(new->name = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003398 ret_err(_("bad TXT record"));
3399
Simon Kelley28866e92011-02-14 20:19:14 +00003400 len = comma ? strlen(comma) : 0;
3401 len += (len/255) + 1; /* room for extra counts */
3402 new->txt = p = opt_malloc(len);
3403
3404 cnt = p++;
3405 *cnt = 0;
3406
3407 while (comma && *comma)
3408 {
3409 unsigned char c = (unsigned char)*comma++;
3410
3411 if (c == ',' || *cnt == 255)
3412 {
3413 if (c != ',')
3414 comma--;
3415 cnt = p++;
3416 *cnt = 0;
3417 }
3418 else
3419 {
3420 *p++ = unhide_meta(c);
3421 (*cnt)++;
3422 }
3423 }
3424
3425 new->len = p - new->txt;
3426
Simon Kelley849a8352006-06-09 21:02:31 +01003427 break;
3428 }
3429
Simon Kelleyf2621c72007-04-29 19:47:21 +01003430 case 'W': /* --srv-host */
Simon Kelley849a8352006-06-09 21:02:31 +01003431 {
3432 int port = 1, priority = 0, weight = 0;
3433 char *name, *target = NULL;
3434 struct mx_srv_record *new;
3435
Simon Kelleyf2621c72007-04-29 19:47:21 +01003436 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003437
Simon Kelley1f15b812009-10-13 17:49:32 +01003438 if (!(name = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003439 ret_err(_("bad SRV record"));
3440
Simon Kelley849a8352006-06-09 21:02:31 +01003441 if (comma)
3442 {
3443 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003444 comma = split(arg);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003445 if (!(target = canonicalise_opt(arg)))
3446 ret_err(_("bad SRV target"));
Simon Kelley824af852008-02-12 20:43:05 +00003447
Simon Kelley849a8352006-06-09 21:02:31 +01003448 if (comma)
3449 {
3450 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003451 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01003452 if (!atoi_check16(arg, &port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003453 ret_err(_("invalid port number"));
Simon Kelley824af852008-02-12 20:43:05 +00003454
Simon Kelley849a8352006-06-09 21:02:31 +01003455 if (comma)
3456 {
3457 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003458 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01003459 if (!atoi_check16(arg, &priority))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003460 ret_err(_("invalid priority"));
Simon Kelley824af852008-02-12 20:43:05 +00003461
Simon Kelley849a8352006-06-09 21:02:31 +01003462 if (comma)
3463 {
3464 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003465 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01003466 if (!atoi_check16(arg, &weight))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003467 ret_err(_("invalid weight"));
Simon Kelley849a8352006-06-09 21:02:31 +01003468 }
3469 }
3470 }
3471 }
3472
Simon Kelley824af852008-02-12 20:43:05 +00003473 new = opt_malloc(sizeof(struct mx_srv_record));
Simon Kelley849a8352006-06-09 21:02:31 +01003474 new->next = daemon->mxnames;
3475 daemon->mxnames = new;
3476 new->issrv = 1;
3477 new->name = name;
3478 new->target = target;
3479 new->srvport = port;
3480 new->priority = priority;
3481 new->weight = weight;
3482 break;
3483 }
Simon Kelley7622fc02009-06-04 20:32:05 +01003484
Simon Kelleye759d422012-03-16 13:18:57 +00003485 case LOPT_HOST_REC: /* --host-record */
3486 {
3487 struct host_record *new = opt_malloc(sizeof(struct host_record));
3488 memset(new, 0, sizeof(struct host_record));
3489
3490 if (!arg || !(comma = split(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003491 ret_err(_("Bad host-record"));
3492
3493 while (arg)
3494 {
3495 struct all_addr addr;
3496 if (inet_pton(AF_INET, arg, &addr))
3497 new->addr = addr.addr.addr4;
Simon Kelleye759d422012-03-16 13:18:57 +00003498#ifdef HAVE_IPV6
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003499 else if (inet_pton(AF_INET6, arg, &addr))
3500 new->addr6 = addr.addr.addr6;
Simon Kelleye759d422012-03-16 13:18:57 +00003501#endif
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003502 else
3503 {
3504 int nomem;
3505 char *canon = canonicalise(arg, &nomem);
3506 struct name_list *nl = opt_malloc(sizeof(struct name_list));
3507 if (!canon)
3508 ret_err(_("Bad name in host-record"));
3509
3510 nl->name = canon;
3511 /* keep order, so that PTR record goes to first name */
3512 nl->next = NULL;
3513 if (!new->names)
3514 new->names = nl;
3515 else
3516 {
3517 struct name_list *tmp;
3518 for (tmp = new->names; tmp->next; tmp = tmp->next);
3519 tmp->next = nl;
3520 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003521 }
Simon Kelleye4807d82012-09-27 21:52:26 +01003522
3523 arg = comma;
3524 comma = split(arg);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003525 }
Simon Kelleye759d422012-03-16 13:18:57 +00003526
3527 /* Keep list order */
3528 if (!daemon->host_records_tail)
3529 daemon->host_records = new;
3530 else
3531 daemon->host_records_tail->next = new;
3532 new->next = NULL;
3533 daemon->host_records_tail = new;
3534 break;
3535 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003536
Simon Kelley7622fc02009-06-04 20:32:05 +01003537 default:
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003538 ret_err(_("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DBus support)"));
3539
Simon Kelley849a8352006-06-09 21:02:31 +01003540 }
Simon Kelley824af852008-02-12 20:43:05 +00003541
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003542 return 1;
Simon Kelley849a8352006-06-09 21:02:31 +01003543}
3544
Simon Kelley28866e92011-02-14 20:19:14 +00003545static void read_file(char *file, FILE *f, int hard_opt)
Simon Kelley849a8352006-06-09 21:02:31 +01003546{
Simon Kelley824af852008-02-12 20:43:05 +00003547 volatile int lineno = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003548 char *buff = daemon->namebuff;
Simon Kelley849a8352006-06-09 21:02:31 +01003549
3550 while (fgets(buff, MAXDNAME, f))
3551 {
Simon Kelley611ebc52012-07-16 16:23:46 +01003552 int white, i, option = hard_opt;
3553 char *errmess, *p, *arg = NULL, *start;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003554 size_t len;
Simon Kelley832af0b2007-01-21 20:01:28 +00003555
Simon Kelley824af852008-02-12 20:43:05 +00003556 /* Memory allocation failure longjmps here if mem_recover == 1 */
Simon Kelley611ebc52012-07-16 16:23:46 +01003557 if (option != 0)
Simon Kelley824af852008-02-12 20:43:05 +00003558 {
3559 if (setjmp(mem_jmp))
3560 continue;
3561 mem_recover = 1;
3562 }
3563
Simon Kelley849a8352006-06-09 21:02:31 +01003564 lineno++;
Simon Kelley824af852008-02-12 20:43:05 +00003565 errmess = NULL;
3566
Simon Kelley849a8352006-06-09 21:02:31 +01003567 /* Implement quotes, inside quotes we allow \\ \" \n and \t
3568 metacharacters get hidden also strip comments */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003569 for (white = 1, p = buff; *p; p++)
Simon Kelley849a8352006-06-09 21:02:31 +01003570 {
3571 if (*p == '"')
3572 {
3573 memmove(p, p+1, strlen(p+1)+1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003574
Simon Kelley849a8352006-06-09 21:02:31 +01003575 for(; *p && *p != '"'; p++)
3576 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01003577 if (*p == '\\' && strchr("\"tnebr\\", p[1]))
Simon Kelley849a8352006-06-09 21:02:31 +01003578 {
3579 if (p[1] == 't')
3580 p[1] = '\t';
3581 else if (p[1] == 'n')
3582 p[1] = '\n';
Simon Kelley849a8352006-06-09 21:02:31 +01003583 else if (p[1] == 'b')
3584 p[1] = '\b';
3585 else if (p[1] == 'r')
3586 p[1] = '\r';
Simon Kelley6b010842007-02-12 20:32:07 +00003587 else if (p[1] == 'e') /* escape */
3588 p[1] = '\033';
Simon Kelley849a8352006-06-09 21:02:31 +01003589 memmove(p, p+1, strlen(p+1)+1);
3590 }
3591 *p = hide_meta(*p);
3592 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003593
3594 if (*p == 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +01003595 {
3596 errmess = _("missing \"");
3597 goto oops;
3598 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003599
3600 memmove(p, p+1, strlen(p+1)+1);
Simon Kelley849a8352006-06-09 21:02:31 +01003601 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01003602
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003603 if (isspace(*p))
3604 {
3605 *p = ' ';
3606 white = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01003607 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003608 else
3609 {
3610 if (white && *p == '#')
3611 {
3612 *p = 0;
3613 break;
3614 }
3615 white = 0;
3616 }
Simon Kelley849a8352006-06-09 21:02:31 +01003617 }
3618
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003619
3620 /* strip leading spaces */
3621 for (start = buff; *start && *start == ' '; start++);
3622
3623 /* strip trailing spaces */
3624 for (len = strlen(start); (len != 0) && (start[len-1] == ' '); len--);
3625
3626 if (len == 0)
Simon Kelley849a8352006-06-09 21:02:31 +01003627 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003628 else
3629 start[len] = 0;
3630
Simon Kelley611ebc52012-07-16 16:23:46 +01003631 if (option != 0)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003632 arg = start;
3633 else if ((p=strchr(start, '=')))
Simon Kelley849a8352006-06-09 21:02:31 +01003634 {
3635 /* allow spaces around "=" */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003636 for (arg = p+1; *arg == ' '; arg++);
3637 for (; p >= start && (*p == ' ' || *p == '='); p--)
Simon Kelley849a8352006-06-09 21:02:31 +01003638 *p = 0;
3639 }
3640 else
3641 arg = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00003642
Simon Kelley611ebc52012-07-16 16:23:46 +01003643 if (option == 0)
Simon Kelley5aabfc72007-08-29 11:24:47 +01003644 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01003645 for (option = 0, i = 0; opts[i].name; i++)
3646 if (strcmp(opts[i].name, start) == 0)
3647 {
3648 option = opts[i].val;
3649 break;
3650 }
3651
3652 if (!option)
3653 errmess = _("bad option");
3654 else if (opts[i].has_arg == 0 && arg)
3655 errmess = _("extraneous parameter");
3656 else if (opts[i].has_arg == 1 && !arg)
3657 errmess = _("missing parameter");
3658 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003659
3660 oops:
Simon Kelley832af0b2007-01-21 20:01:28 +00003661 if (errmess)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003662 strcpy(daemon->namebuff, errmess);
3663
3664 if (errmess || !one_opt(option, arg, buff, _("error"), 0))
Simon Kelleyf2621c72007-04-29 19:47:21 +01003665 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003666 sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file);
Simon Kelley824af852008-02-12 20:43:05 +00003667 if (hard_opt != 0)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003668 my_syslog(LOG_ERR, "%s", daemon->namebuff);
Simon Kelley5aabfc72007-08-29 11:24:47 +01003669 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003670 die("%s", daemon->namebuff, EC_BADCONF);
Simon Kelleyf2621c72007-04-29 19:47:21 +01003671 }
Simon Kelley849a8352006-06-09 21:02:31 +01003672 }
3673
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003674 mem_recover = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01003675 fclose(f);
3676}
3677
Simon Kelley395eb712012-07-06 22:07:05 +01003678static int one_file(char *file, int hard_opt)
Simon Kelley28866e92011-02-14 20:19:14 +00003679{
3680 FILE *f;
3681 int nofile_ok = 0;
3682 static int read_stdin = 0;
3683 static struct fileread {
3684 dev_t dev;
3685 ino_t ino;
3686 struct fileread *next;
3687 } *filesread = NULL;
3688
3689 if (hard_opt == '7')
3690 {
3691 /* default conf-file reading */
3692 hard_opt = 0;
3693 nofile_ok = 1;
3694 }
3695
3696 if (hard_opt == 0 && strcmp(file, "-") == 0)
3697 {
3698 if (read_stdin == 1)
Simon Kelley395eb712012-07-06 22:07:05 +01003699 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00003700 read_stdin = 1;
3701 file = "stdin";
3702 f = stdin;
3703 }
3704 else
3705 {
3706 /* ignore repeated files. */
3707 struct stat statbuf;
3708
3709 if (hard_opt == 0 && stat(file, &statbuf) == 0)
3710 {
3711 struct fileread *r;
3712
3713 for (r = filesread; r; r = r->next)
3714 if (r->dev == statbuf.st_dev && r->ino == statbuf.st_ino)
Simon Kelley395eb712012-07-06 22:07:05 +01003715 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00003716
3717 r = safe_malloc(sizeof(struct fileread));
3718 r->next = filesread;
3719 filesread = r;
3720 r->dev = statbuf.st_dev;
3721 r->ino = statbuf.st_ino;
3722 }
3723
3724 if (!(f = fopen(file, "r")))
3725 {
3726 if (errno == ENOENT && nofile_ok)
Simon Kelley395eb712012-07-06 22:07:05 +01003727 return 1; /* No conffile, all done. */
Simon Kelley28866e92011-02-14 20:19:14 +00003728 else
3729 {
3730 char *str = _("cannot read %s: %s");
3731 if (hard_opt != 0)
3732 {
3733 my_syslog(LOG_ERR, str, file, strerror(errno));
Simon Kelley395eb712012-07-06 22:07:05 +01003734 return 0;
Simon Kelley28866e92011-02-14 20:19:14 +00003735 }
3736 else
3737 die(str, file, EC_FILE);
3738 }
3739 }
3740 }
3741
3742 read_file(file, f, hard_opt);
Simon Kelley395eb712012-07-06 22:07:05 +01003743 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00003744}
3745
3746/* expand any name which is a directory */
3747struct hostsfile *expand_filelist(struct hostsfile *list)
3748{
3749 int i;
3750 struct hostsfile *ah;
3751
3752 for (i = 0, ah = list; ah; ah = ah->next)
3753 {
3754 if (i <= ah->index)
3755 i = ah->index + 1;
3756
3757 if (ah->flags & AH_DIR)
3758 ah->flags |= AH_INACTIVE;
3759 else
3760 ah->flags &= ~AH_INACTIVE;
3761 }
3762
3763 for (ah = list; ah; ah = ah->next)
3764 if (!(ah->flags & AH_INACTIVE))
3765 {
3766 struct stat buf;
3767 if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode))
3768 {
3769 DIR *dir_stream;
3770 struct dirent *ent;
3771
3772 /* don't read this as a file */
3773 ah->flags |= AH_INACTIVE;
3774
3775 if (!(dir_stream = opendir(ah->fname)))
3776 my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
3777 ah->fname, strerror(errno));
3778 else
3779 {
3780 while ((ent = readdir(dir_stream)))
3781 {
3782 size_t lendir = strlen(ah->fname);
3783 size_t lenfile = strlen(ent->d_name);
3784 struct hostsfile *ah1;
3785 char *path;
3786
3787 /* ignore emacs backups and dotfiles */
3788 if (lenfile == 0 ||
3789 ent->d_name[lenfile - 1] == '~' ||
3790 (ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
3791 ent->d_name[0] == '.')
3792 continue;
3793
3794 /* see if we have an existing record.
3795 dir is ah->fname
3796 file is ent->d_name
3797 path to match is ah1->fname */
3798
3799 for (ah1 = list; ah1; ah1 = ah1->next)
3800 {
3801 if (lendir < strlen(ah1->fname) &&
3802 strstr(ah1->fname, ah->fname) == ah1->fname &&
3803 ah1->fname[lendir] == '/' &&
3804 strcmp(ah1->fname + lendir + 1, ent->d_name) == 0)
3805 {
3806 ah1->flags &= ~AH_INACTIVE;
3807 break;
3808 }
3809 }
3810
3811 /* make new record */
3812 if (!ah1)
3813 {
3814 if (!(ah1 = whine_malloc(sizeof(struct hostsfile))))
3815 continue;
3816
3817 if (!(path = whine_malloc(lendir + lenfile + 2)))
3818 {
3819 free(ah1);
3820 continue;
3821 }
3822
3823 strcpy(path, ah->fname);
3824 strcat(path, "/");
3825 strcat(path, ent->d_name);
3826 ah1->fname = path;
3827 ah1->index = i++;
3828 ah1->flags = AH_DIR;
3829 ah1->next = list;
3830 list = ah1;
3831 }
3832
3833 /* inactivate record if not regular file */
3834 if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode))
3835 ah1->flags |= AH_INACTIVE;
3836
3837 }
3838 closedir(dir_stream);
3839 }
3840 }
3841 }
3842
3843 return list;
3844}
3845
3846
Simon Kelley7622fc02009-06-04 20:32:05 +01003847#ifdef HAVE_DHCP
Simon Kelley824af852008-02-12 20:43:05 +00003848void reread_dhcp(void)
3849{
Simon Kelley28866e92011-02-14 20:19:14 +00003850 struct hostsfile *hf;
3851
Simon Kelley824af852008-02-12 20:43:05 +00003852 if (daemon->dhcp_hosts_file)
3853 {
3854 struct dhcp_config *configs, *cp, **up;
Simon Kelley28866e92011-02-14 20:19:14 +00003855
Simon Kelley824af852008-02-12 20:43:05 +00003856 /* remove existing... */
3857 for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
3858 {
3859 cp = configs->next;
3860
3861 if (configs->flags & CONFIG_BANK)
3862 {
Simon Kelley9009d742008-11-14 20:04:27 +00003863 struct hwaddr_config *mac, *tmp;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003864 struct dhcp_netid_list *list, *tmplist;
Simon Kelley9009d742008-11-14 20:04:27 +00003865
3866 for (mac = configs->hwaddr; mac; mac = tmp)
3867 {
3868 tmp = mac->next;
3869 free(mac);
3870 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003871
Simon Kelley824af852008-02-12 20:43:05 +00003872 if (configs->flags & CONFIG_CLID)
3873 free(configs->clid);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003874
3875 for (list = configs->netid; list; list = tmplist)
3876 {
3877 free(list->list);
3878 tmplist = list->next;
3879 free(list);
3880 }
3881
Simon Kelley824af852008-02-12 20:43:05 +00003882 if (configs->flags & CONFIG_NAME)
3883 free(configs->hostname);
3884
3885 *up = configs->next;
3886 free(configs);
3887 }
3888 else
3889 up = &configs->next;
3890 }
3891
Simon Kelley28866e92011-02-14 20:19:14 +00003892 daemon->dhcp_hosts_file = expand_filelist(daemon->dhcp_hosts_file);
3893 for (hf = daemon->dhcp_hosts_file; hf; hf = hf->next)
3894 if (!(hf->flags & AH_INACTIVE))
3895 {
Simon Kelley395eb712012-07-06 22:07:05 +01003896 if (one_file(hf->fname, LOPT_BANK))
3897 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
Simon Kelley28866e92011-02-14 20:19:14 +00003898 }
Simon Kelley824af852008-02-12 20:43:05 +00003899 }
3900
3901 if (daemon->dhcp_opts_file)
3902 {
3903 struct dhcp_opt *opts, *cp, **up;
3904 struct dhcp_netid *id, *next;
3905
3906 for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
3907 {
3908 cp = opts->next;
3909
3910 if (opts->flags & DHOPT_BANK)
3911 {
Simon Kelley73a08a22009-02-05 20:28:08 +00003912 if ((opts->flags & DHOPT_VENDOR))
3913 free(opts->u.vendor_class);
Simon Kelley824af852008-02-12 20:43:05 +00003914 free(opts->val);
3915 for (id = opts->netid; id; id = next)
3916 {
3917 next = id->next;
3918 free(id->net);
3919 free(id);
3920 }
3921 *up = opts->next;
3922 free(opts);
3923 }
3924 else
3925 up = &opts->next;
3926 }
3927
Simon Kelley28866e92011-02-14 20:19:14 +00003928 daemon->dhcp_opts_file = expand_filelist(daemon->dhcp_opts_file);
3929 for (hf = daemon->dhcp_opts_file; hf; hf = hf->next)
3930 if (!(hf->flags & AH_INACTIVE))
3931 {
Simon Kelley395eb712012-07-06 22:07:05 +01003932 if (one_file(hf->fname, LOPT_OPTS))
3933 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
Simon Kelley28866e92011-02-14 20:19:14 +00003934 }
Simon Kelley824af852008-02-12 20:43:05 +00003935 }
3936}
Simon Kelley7622fc02009-06-04 20:32:05 +01003937#endif
Simon Kelley824af852008-02-12 20:43:05 +00003938
Simon Kelley5aabfc72007-08-29 11:24:47 +01003939void read_opts(int argc, char **argv, char *compile_opts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00003940{
Simon Kelley824af852008-02-12 20:43:05 +00003941 char *buff = opt_malloc(MAXDNAME);
Simon Kelley28866e92011-02-14 20:19:14 +00003942 int option, conffile_opt = '7', testmode = 0;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003943 char *arg, *conffile = CONFFILE;
Simon Kelley849a8352006-06-09 21:02:31 +01003944
Simon Kelley9e4abcb2004-01-22 19:47:41 +00003945 opterr = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +01003946
Simon Kelley824af852008-02-12 20:43:05 +00003947 daemon = opt_malloc(sizeof(struct daemon));
Simon Kelley3be34542004-09-11 19:12:13 +01003948 memset(daemon, 0, sizeof(struct daemon));
3949 daemon->namebuff = buff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00003950
Simon Kelley3be34542004-09-11 19:12:13 +01003951 /* Set defaults - everything else is zero or NULL */
Simon Kelley3be34542004-09-11 19:12:13 +01003952 daemon->cachesize = CACHESIZ;
Simon Kelley208b65c2006-08-05 21:41:37 +01003953 daemon->ftabsize = FTABSIZ;
Simon Kelley3be34542004-09-11 19:12:13 +01003954 daemon->port = NAMESERVER_PORT;
Simon Kelley9e038942008-05-30 20:06:34 +01003955 daemon->dhcp_client_port = DHCP_CLIENT_PORT;
3956 daemon->dhcp_server_port = DHCP_SERVER_PORT;
Simon Kelley3be34542004-09-11 19:12:13 +01003957 daemon->default_resolv.is_default = 1;
3958 daemon->default_resolv.name = RESOLVFILE;
3959 daemon->resolv_files = &daemon->default_resolv;
3960 daemon->username = CHUSER;
Simon Kelley3be34542004-09-11 19:12:13 +01003961 daemon->runfile = RUNFILE;
3962 daemon->dhcp_max = MAXLEASES;
Simon Kelley832af0b2007-01-21 20:01:28 +00003963 daemon->tftp_max = TFTP_MAX_CONNECTIONS;
Simon Kelley3be34542004-09-11 19:12:13 +01003964 daemon->edns_pktsz = EDNS_PKTSZ;
Simon Kelley849a8352006-06-09 21:02:31 +01003965 daemon->log_fac = -1;
Simon Kelley4f7b3042012-11-28 21:27:02 +00003966 daemon->auth_ttl = AUTH_TTL;
3967 daemon->soa_refresh = SOA_REFRESH;
3968 daemon->soa_retry = SOA_RETRY;
3969 daemon->soa_expiry = SOA_EXPIRY;
Simon Kelley5aabfc72007-08-29 11:24:47 +01003970 add_txt("version.bind", "dnsmasq-" VERSION );
3971 add_txt("authors.bind", "Simon Kelley");
3972 add_txt("copyright.bind", COPYRIGHT);
Simon Kelley0a852542005-03-23 20:28:59 +00003973
Simon Kelley849a8352006-06-09 21:02:31 +01003974 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00003975 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00003976#ifdef HAVE_GETOPT_LONG
Simon Kelley849a8352006-06-09 21:02:31 +01003977 option = getopt_long(argc, argv, OPTSTRING, opts, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00003978#else
Simon Kelley849a8352006-06-09 21:02:31 +01003979 option = getopt(argc, argv, OPTSTRING);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00003980#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00003981
3982 if (option == -1)
Simon Kelley28866e92011-02-14 20:19:14 +00003983 {
Simon Kelley572b41e2011-02-18 18:11:18 +00003984 for (; optind < argc; optind++)
3985 {
3986 unsigned char *c = (unsigned char *)argv[optind];
3987 for (; *c != 0; c++)
3988 if (!isspace(*c))
3989 die(_("junk found in command line"), NULL, EC_BADCONF);
3990 }
Simon Kelley28866e92011-02-14 20:19:14 +00003991 break;
3992 }
3993
Simon Kelley849a8352006-06-09 21:02:31 +01003994 /* Copy optarg so that argv doesn't get changed */
3995 if (optarg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00003996 {
Simon Kelley849a8352006-06-09 21:02:31 +01003997 strncpy(buff, optarg, MAXDNAME);
3998 buff[MAXDNAME-1] = 0;
3999 arg = buff;
4000 }
4001 else
4002 arg = NULL;
4003
4004 /* command-line only stuff */
Simon Kelley7622fc02009-06-04 20:32:05 +01004005 if (option == LOPT_TEST)
4006 testmode = 1;
4007 else if (option == 'w')
Simon Kelley849a8352006-06-09 21:02:31 +01004008 {
Simon Kelley7622fc02009-06-04 20:32:05 +01004009#ifdef HAVE_DHCP
Simon Kelley4cb1b322012-02-06 14:30:41 +00004010 if (argc == 3 && strcmp(argv[2], "dhcp") == 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01004011 display_opts();
Simon Kelley4cb1b322012-02-06 14:30:41 +00004012#ifdef HAVE_DHCP6
4013 else if (argc == 3 && strcmp(argv[2], "dhcp6") == 0)
4014 display_opts6();
Simon Kelley7622fc02009-06-04 20:32:05 +01004015#endif
Simon Kelley4cb1b322012-02-06 14:30:41 +00004016 else
4017#endif
4018 do_usage();
4019
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004020 exit(0);
4021 }
Simon Kelley849a8352006-06-09 21:02:31 +01004022 else if (option == 'v')
4023 {
4024 printf(_("Dnsmasq version %s %s\n"), VERSION, COPYRIGHT);
Simon Kelleyc72daea2012-01-05 21:33:27 +00004025 printf(_("Compile time options: %s\n\n"), compile_opts);
Simon Kelleyb8187c82005-11-26 21:46:27 +00004026 printf(_("This software comes with ABSOLUTELY NO WARRANTY.\n"));
4027 printf(_("Dnsmasq is free software, and you are welcome to redistribute it\n"));
Simon Kelley824af852008-02-12 20:43:05 +00004028 printf(_("under the terms of the GNU General Public License, version 2 or 3.\n"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004029 exit(0);
4030 }
Simon Kelley849a8352006-06-09 21:02:31 +01004031 else if (option == 'C')
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004032 {
Simon Kelley28866e92011-02-14 20:19:14 +00004033 conffile_opt = 0; /* file must exist */
Simon Kelley824af852008-02-12 20:43:05 +00004034 conffile = opt_string_alloc(arg);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004035 }
Simon Kelley849a8352006-06-09 21:02:31 +01004036 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004037 {
Simon Kelley26128d22004-11-14 16:43:54 +00004038#ifdef HAVE_GETOPT_LONG
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004039 if (!one_opt(option, arg, daemon->namebuff, _("try --help"), 1))
Simon Kelley849a8352006-06-09 21:02:31 +01004040#else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004041 if (!one_opt(option, arg, daemon->namebuff, _("try -w"), 1))
Simon Kelley849a8352006-06-09 21:02:31 +01004042#endif
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004043 die(_("bad command line options: %s"), daemon->namebuff, EC_BADCONF);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004044 }
4045 }
Simon Kelley849a8352006-06-09 21:02:31 +01004046
4047 if (conffile)
Simon Kelley28866e92011-02-14 20:19:14 +00004048 one_file(conffile, conffile_opt);
Simon Kelley849a8352006-06-09 21:02:31 +01004049
Simon Kelley1a6bca82008-07-11 11:11:42 +01004050 /* port might not be known when the address is parsed - fill in here */
Simon Kelley3be34542004-09-11 19:12:13 +01004051 if (daemon->servers)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004052 {
4053 struct server *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +01004054 for (tmp = daemon->servers; tmp; tmp = tmp->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004055 if (!(tmp->flags & SERV_HAS_SOURCE))
4056 {
4057 if (tmp->source_addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +01004058 tmp->source_addr.in.sin_port = htons(daemon->query_port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004059#ifdef HAVE_IPV6
4060 else if (tmp->source_addr.sa.sa_family == AF_INET6)
Simon Kelley3be34542004-09-11 19:12:13 +01004061 tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
Simon Kelley5aabfc72007-08-29 11:24:47 +01004062#endif
4063 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004064 }
4065
Simon Kelley3be34542004-09-11 19:12:13 +01004066 if (daemon->if_addrs)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004067 {
4068 struct iname *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +01004069 for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004070 if (tmp->addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +01004071 tmp->addr.in.sin_port = htons(daemon->port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004072#ifdef HAVE_IPV6
4073 else if (tmp->addr.sa.sa_family == AF_INET6)
Simon Kelley3be34542004-09-11 19:12:13 +01004074 tmp->addr.in6.sin6_port = htons(daemon->port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004075#endif /* IPv6 */
4076 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00004077
4078 /* create default, if not specified */
4079 if (daemon->authserver && !daemon->hostmaster)
4080 {
4081 strcpy(buff, "hostmaster.");
4082 strcat(buff, daemon->authserver);
4083 daemon->hostmaster = opt_string_alloc(buff);
4084 }
4085
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004086 /* only one of these need be specified: the other defaults to the host-name */
Simon Kelley28866e92011-02-14 20:19:14 +00004087 if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004088 {
Simon Kelley0a852542005-03-23 20:28:59 +00004089 struct mx_srv_record *mx;
4090
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004091 if (gethostname(buff, MAXDNAME) == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004092 die(_("cannot get host-name: %s"), NULL, EC_MISC);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004093
Simon Kelley0a852542005-03-23 20:28:59 +00004094 for (mx = daemon->mxnames; mx; mx = mx->next)
4095 if (!mx->issrv && hostname_isequal(mx->name, buff))
4096 break;
4097
Simon Kelley28866e92011-02-14 20:19:14 +00004098 if ((daemon->mxtarget || option_bool(OPT_LOCALMX)) && !mx)
Simon Kelleyde379512004-06-22 20:23:33 +01004099 {
Simon Kelley824af852008-02-12 20:43:05 +00004100 mx = opt_malloc(sizeof(struct mx_srv_record));
Simon Kelley91dccd02005-03-31 17:48:32 +01004101 mx->next = daemon->mxnames;
4102 mx->issrv = 0;
4103 mx->target = NULL;
Simon Kelley824af852008-02-12 20:43:05 +00004104 mx->name = opt_string_alloc(buff);
Simon Kelley91dccd02005-03-31 17:48:32 +01004105 daemon->mxnames = mx;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004106 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004107
Simon Kelley3be34542004-09-11 19:12:13 +01004108 if (!daemon->mxtarget)
Simon Kelley824af852008-02-12 20:43:05 +00004109 daemon->mxtarget = opt_string_alloc(buff);
Simon Kelley0a852542005-03-23 20:28:59 +00004110
4111 for (mx = daemon->mxnames; mx; mx = mx->next)
4112 if (!mx->issrv && !mx->target)
4113 mx->target = daemon->mxtarget;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004114 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004115
Simon Kelley28866e92011-02-14 20:19:14 +00004116 if (!option_bool(OPT_NO_RESOLV) &&
Simon Kelley208b65c2006-08-05 21:41:37 +01004117 daemon->resolv_files &&
4118 daemon->resolv_files->next &&
Simon Kelley28866e92011-02-14 20:19:14 +00004119 option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +01004120 die(_("only one resolv.conf file allowed in no-poll mode."), NULL, EC_BADCONF);
Simon Kelleyde379512004-06-22 20:23:33 +01004121
Simon Kelley28866e92011-02-14 20:19:14 +00004122 if (option_bool(OPT_RESOLV_DOMAIN))
Simon Kelleyde379512004-06-22 20:23:33 +01004123 {
4124 char *line;
Simon Kelley849a8352006-06-09 21:02:31 +01004125 FILE *f;
4126
Simon Kelley28866e92011-02-14 20:19:14 +00004127 if (option_bool(OPT_NO_RESOLV) ||
Simon Kelley208b65c2006-08-05 21:41:37 +01004128 !daemon->resolv_files ||
4129 (daemon->resolv_files)->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004130 die(_("must have exactly one resolv.conf to read domain from."), NULL, EC_BADCONF);
Simon Kelleyde379512004-06-22 20:23:33 +01004131
Simon Kelley3be34542004-09-11 19:12:13 +01004132 if (!(f = fopen((daemon->resolv_files)->name, "r")))
Simon Kelley5aabfc72007-08-29 11:24:47 +01004133 die(_("failed to read %s: %s"), (daemon->resolv_files)->name, EC_FILE);
Simon Kelleyde379512004-06-22 20:23:33 +01004134
4135 while ((line = fgets(buff, MAXDNAME, f)))
4136 {
4137 char *token = strtok(line, " \t\n\r");
4138
4139 if (!token || strcmp(token, "search") != 0)
4140 continue;
4141
4142 if ((token = strtok(NULL, " \t\n\r")) &&
Simon Kelley1f15b812009-10-13 17:49:32 +01004143 (daemon->domain_suffix = canonicalise_opt(token)))
Simon Kelleyde379512004-06-22 20:23:33 +01004144 break;
4145 }
Simon Kelley3be34542004-09-11 19:12:13 +01004146
Simon Kelleyde379512004-06-22 20:23:33 +01004147 fclose(f);
Simon Kelley8a911cc2004-03-16 18:35:52 +00004148
Simon Kelley3be34542004-09-11 19:12:13 +01004149 if (!daemon->domain_suffix)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004150 die(_("no search directive found in %s"), (daemon->resolv_files)->name, EC_MISC);
Simon Kelleyde379512004-06-22 20:23:33 +01004151 }
Simon Kelley3d8df262005-08-29 12:19:27 +01004152
4153 if (daemon->domain_suffix)
4154 {
4155 /* add domain for any srv record without one. */
4156 struct mx_srv_record *srv;
Simon Kelleyde379512004-06-22 20:23:33 +01004157
Simon Kelley3d8df262005-08-29 12:19:27 +01004158 for (srv = daemon->mxnames; srv; srv = srv->next)
4159 if (srv->issrv &&
4160 strchr(srv->name, '.') &&
4161 strchr(srv->name, '.') == strrchr(srv->name, '.'))
4162 {
4163 strcpy(buff, srv->name);
4164 strcat(buff, ".");
4165 strcat(buff, daemon->domain_suffix);
4166 free(srv->name);
Simon Kelley824af852008-02-12 20:43:05 +00004167 srv->name = opt_string_alloc(buff);
Simon Kelley3d8df262005-08-29 12:19:27 +01004168 }
4169 }
Simon Kelley28866e92011-02-14 20:19:14 +00004170 else if (option_bool(OPT_DHCP_FQDN))
Simon Kelley9009d742008-11-14 20:04:27 +00004171 die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
Simon Kelley7622fc02009-06-04 20:32:05 +01004172
4173 if (testmode)
4174 {
4175 fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
4176 exit(0);
4177 }
Simon Kelley849a8352006-06-09 21:02:31 +01004178}