blob: e4885eec1757979714a921f67e13a106fc0e7d5b [file] [log] [blame]
Simon Kelleyc47e3ba2014-01-08 17:07:54 +00001/* dnsmasq is Copyright (c) 2000-2014 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 */
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +010067#define LOPT_RELOAD 256
68#define LOPT_NO_NAMES 257
69#define LOPT_TFTP 258
70#define LOPT_SECURE 259
71#define LOPT_PREFIX 260
72#define LOPT_PTR 261
73#define LOPT_BRIDGE 262
74#define LOPT_TFTP_MAX 263
75#define LOPT_FORCE 264
76#define LOPT_NOBLOCK 265
77#define LOPT_LOG_OPTS 266
78#define LOPT_MAX_LOGS 267
79#define LOPT_CIRCUIT 268
80#define LOPT_REMOTE 269
81#define LOPT_SUBSCR 270
82#define LOPT_INTNAME 271
83#define LOPT_BANK 272
84#define LOPT_DHCP_HOST 273
85#define LOPT_APREF 274
86#define LOPT_OVERRIDE 275
87#define LOPT_TFTPPORTS 276
88#define LOPT_REBIND 277
89#define LOPT_NOLAST 278
90#define LOPT_OPTS 279
91#define LOPT_DHCP_OPTS 280
92#define LOPT_MATCH 281
93#define LOPT_BROADCAST 282
94#define LOPT_NEGTTL 283
95#define LOPT_ALTPORT 284
96#define LOPT_SCRIPTUSR 285
97#define LOPT_LOCAL 286
98#define LOPT_NAPTR 287
99#define LOPT_MINPORT 288
100#define LOPT_DHCP_FQDN 289
101#define LOPT_CNAME 290
102#define LOPT_PXE_PROMT 291
103#define LOPT_PXE_SERV 292
104#define LOPT_TEST 293
105#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
111#define LOPT_ADD_MAC 300
112#define LOPT_DNSSEC 301
113#define LOPT_INCR_ADDR 302
114#define LOPT_CONNTRACK 303
115#define LOPT_FQDN 304
116#define LOPT_LUASCRIPT 305
117#define LOPT_RA 306
118#define LOPT_DUID 307
119#define LOPT_HOST_REC 308
120#define LOPT_TFTP_LC 309
121#define LOPT_RR 310
122#define LOPT_CLVERBIND 311
123#define LOPT_MAXCTTL 312
124#define LOPT_AUTHZONE 313
125#define LOPT_AUTHSERV 314
126#define LOPT_AUTHTTL 315
127#define LOPT_AUTHSOA 316
128#define LOPT_AUTHSFS 317
129#define LOPT_AUTHPEER 318
130#define LOPT_IPSET 319
131#define LOPT_SYNTH 320
Simon Kelleyc6309242013-03-07 20:59:28 +0000132#ifdef OPTION6_PREFIX_CLASS
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100133#define LOPT_PREF_CLSS 321
Simon Kelleyc6309242013-03-07 20:59:28 +0000134#endif
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100135#define LOPT_RELAY 323
136#define LOPT_RA_PARAM 324
137#define LOPT_ADD_SBNET 325
138#define LOPT_QUIET_DHCP 326
139#define LOPT_QUIET_DHCP6 327
140#define LOPT_QUIET_RA 328
Simon Kelley5a4120d2013-10-25 13:13:11 +0100141#define LOPT_SEC_VALID 329
Simon Kelley0fc2f312014-01-08 10:26:58 +0000142#define LOPT_DNSKEY 330
Simon Kelley16972692006-10-16 20:04:18 +0100143
Giovanni Bajo7dbe1932012-04-05 02:50:13 +0200144
Simon Kelley849a8352006-06-09 21:02:31 +0100145#ifdef HAVE_GETOPT_LONG
146static const struct option opts[] =
147#else
148static const struct myoption opts[] =
149#endif
150 {
Simon Kelley7622fc02009-06-04 20:32:05 +0100151 { "version", 0, 0, 'v' },
152 { "no-hosts", 0, 0, 'h' },
153 { "no-poll", 0, 0, 'n' },
154 { "help", 0, 0, 'w' },
155 { "no-daemon", 0, 0, 'd' },
156 { "log-queries", 0, 0, 'q' },
157 { "user", 2, 0, 'u' },
158 { "group", 2, 0, 'g' },
159 { "resolv-file", 2, 0, 'r' },
160 { "mx-host", 1, 0, 'm' },
161 { "mx-target", 1, 0, 't' },
162 { "cache-size", 2, 0, 'c' },
163 { "port", 1, 0, 'p' },
164 { "dhcp-leasefile", 2, 0, 'l' },
165 { "dhcp-lease", 1, 0, 'l' },
166 { "dhcp-host", 1, 0, 'G' },
167 { "dhcp-range", 1, 0, 'F' },
168 { "dhcp-option", 1, 0, 'O' },
169 { "dhcp-boot", 1, 0, 'M' },
170 { "domain", 1, 0, 's' },
171 { "domain-suffix", 1, 0, 's' },
172 { "interface", 1, 0, 'i' },
173 { "listen-address", 1, 0, 'a' },
174 { "bogus-priv", 0, 0, 'b' },
175 { "bogus-nxdomain", 1, 0, 'B' },
176 { "selfmx", 0, 0, 'e' },
177 { "filterwin2k", 0, 0, 'f' },
178 { "pid-file", 2, 0, 'x' },
179 { "strict-order", 0, 0, 'o' },
180 { "server", 1, 0, 'S' },
181 { "local", 1, 0, LOPT_LOCAL },
182 { "address", 1, 0, 'A' },
183 { "conf-file", 2, 0, 'C' },
184 { "no-resolv", 0, 0, 'R' },
185 { "expand-hosts", 0, 0, 'E' },
186 { "localmx", 0, 0, 'L' },
187 { "local-ttl", 1, 0, 'T' },
188 { "no-negcache", 0, 0, 'N' },
189 { "addn-hosts", 1, 0, 'H' },
190 { "query-port", 1, 0, 'Q' },
191 { "except-interface", 1, 0, 'I' },
192 { "no-dhcp-interface", 1, 0, '2' },
193 { "domain-needed", 0, 0, 'D' },
194 { "dhcp-lease-max", 1, 0, 'X' },
195 { "bind-interfaces", 0, 0, 'z' },
196 { "read-ethers", 0, 0, 'Z' },
197 { "alias", 1, 0, 'V' },
198 { "dhcp-vendorclass", 1, 0, 'U' },
199 { "dhcp-userclass", 1, 0, 'j' },
200 { "dhcp-ignore", 1, 0, 'J' },
201 { "edns-packet-max", 1, 0, 'P' },
202 { "keep-in-foreground", 0, 0, 'k' },
203 { "dhcp-authoritative", 0, 0, 'K' },
204 { "srv-host", 1, 0, 'W' },
205 { "localise-queries", 0, 0, 'y' },
206 { "txt-record", 1, 0, 'Y' },
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100207 { "dns-rr", 1, 0, LOPT_RR },
Simon Kelleyad094272012-08-10 17:10:54 +0100208 { "enable-dbus", 2, 0, '1' },
Simon Kelley7622fc02009-06-04 20:32:05 +0100209 { "bootp-dynamic", 2, 0, '3' },
210 { "dhcp-mac", 1, 0, '4' },
211 { "no-ping", 0, 0, '5' },
212 { "dhcp-script", 1, 0, '6' },
213 { "conf-dir", 1, 0, '7' },
214 { "log-facility", 1, 0 ,'8' },
215 { "leasefile-ro", 0, 0, '9' },
216 { "dns-forward-max", 1, 0, '0' },
217 { "clear-on-reload", 0, 0, LOPT_RELOAD },
218 { "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
Simon Kelley2937f8a2013-07-29 19:49:07 +0100219 { "enable-tftp", 2, 0, LOPT_TFTP },
Simon Kelley7622fc02009-06-04 20:32:05 +0100220 { "tftp-secure", 0, 0, LOPT_SECURE },
221 { "tftp-unique-root", 0, 0, LOPT_APREF },
222 { "tftp-root", 1, 0, LOPT_PREFIX },
223 { "tftp-max", 1, 0, LOPT_TFTP_MAX },
Simon Kelley61ce6002012-04-20 21:28:49 +0100224 { "tftp-lowercase", 0, 0, LOPT_TFTP_LC },
Simon Kelley7622fc02009-06-04 20:32:05 +0100225 { "ptr-record", 1, 0, LOPT_PTR },
226 { "naptr-record", 1, 0, LOPT_NAPTR },
227 { "bridge-interface", 1, 0 , LOPT_BRIDGE },
228 { "dhcp-option-force", 1, 0, LOPT_FORCE },
229 { "tftp-no-blocksize", 0, 0, LOPT_NOBLOCK },
230 { "log-dhcp", 0, 0, LOPT_LOG_OPTS },
231 { "log-async", 2, 0, LOPT_MAX_LOGS },
232 { "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
233 { "dhcp-remoteid", 1, 0, LOPT_REMOTE },
234 { "dhcp-subscrid", 1, 0, LOPT_SUBSCR },
235 { "interface-name", 1, 0, LOPT_INTNAME },
236 { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
237 { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
238 { "dhcp-no-override", 0, 0, LOPT_OVERRIDE },
239 { "tftp-port-range", 1, 0, LOPT_TFTPPORTS },
240 { "stop-dns-rebind", 0, 0, LOPT_REBIND },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100241 { "rebind-domain-ok", 1, 0, LOPT_NO_REBIND },
Simon Kelley7622fc02009-06-04 20:32:05 +0100242 { "all-servers", 0, 0, LOPT_NOLAST },
243 { "dhcp-match", 1, 0, LOPT_MATCH },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100244 { "dhcp-broadcast", 2, 0, LOPT_BROADCAST },
Simon Kelley7622fc02009-06-04 20:32:05 +0100245 { "neg-ttl", 1, 0, LOPT_NEGTTL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100246 { "max-ttl", 1, 0, LOPT_MAXTTL },
Simon Kelley1d860412012-09-20 20:48:04 +0100247 { "max-cache-ttl", 1, 0, LOPT_MAXCTTL },
Simon Kelley7622fc02009-06-04 20:32:05 +0100248 { "dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
249 { "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
250 { "min-port", 1, 0, LOPT_MINPORT },
251 { "dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN },
252 { "cname", 1, 0, LOPT_CNAME },
253 { "pxe-prompt", 1, 0, LOPT_PXE_PROMT },
254 { "pxe-service", 1, 0, LOPT_PXE_SERV },
255 { "test", 0, 0, LOPT_TEST },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100256 { "tag-if", 1, 0, LOPT_TAG_IF },
257 { "dhcp-proxy", 2, 0, LOPT_PROXY },
258 { "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES },
259 { "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
Simon Kelley28866e92011-02-14 20:19:14 +0000260 { "add-mac", 0, 0, LOPT_ADD_MAC },
Simon Kelleyed4c0762013-10-08 20:46:34 +0100261 { "add-subnet", 2, 0, LOPT_ADD_SBNET },
Simon Kelley28866e92011-02-14 20:19:14 +0000262 { "proxy-dnssec", 0, 0, LOPT_DNSSEC },
Simon Kelley7de060b2011-08-26 17:24:52 +0100263 { "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR },
264 { "conntrack", 0, 0, LOPT_CONNTRACK },
Simon Kelleyc72daea2012-01-05 21:33:27 +0000265 { "dhcp-client-update", 0, 0, LOPT_FQDN },
266 { "dhcp-luascript", 1, 0, LOPT_LUASCRIPT },
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000267 { "enable-ra", 0, 0, LOPT_RA },
Simon Kelley8b372702012-03-09 17:45:10 +0000268 { "dhcp-duid", 1, 0, LOPT_DUID },
Simon Kelleye759d422012-03-16 13:18:57 +0000269 { "host-record", 1, 0, LOPT_HOST_REC },
Simon Kelley54dd3932012-06-20 11:23:38 +0100270 { "bind-dynamic", 0, 0, LOPT_CLVERBIND },
Simon Kelley4f7b3042012-11-28 21:27:02 +0000271 { "auth-zone", 1, 0, LOPT_AUTHZONE },
272 { "auth-server", 1, 0, LOPT_AUTHSERV },
273 { "auth-ttl", 1, 0, LOPT_AUTHTTL },
274 { "auth-soa", 1, 0, LOPT_AUTHSOA },
Simon Kelleye1ff4192012-12-09 17:08:47 +0000275 { "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
Simon Kelley49678762012-12-09 18:24:58 +0000276 { "auth-peer", 1, 0, LOPT_AUTHPEER },
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000277 { "ipset", 1, 0, LOPT_IPSET },
Simon Kelley2bb73af2013-04-24 17:38:19 +0100278 { "synth-domain", 1, 0, LOPT_SYNTH },
Giovanni Bajo7dbe1932012-04-05 02:50:13 +0200279 { "dnssec", 0, 0, LOPT_SEC_VALID },
Simon Kelley0fc2f312014-01-08 10:26:58 +0000280 { "dnskey", 1, 0, LOPT_DNSKEY },
Simon Kelleyc6309242013-03-07 20:59:28 +0000281#ifdef OPTION6_PREFIX_CLASS
282 { "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
283#endif
Simon Kelleyff7eea22013-09-04 18:01:38 +0100284 { "dhcp-relay", 1, 0, LOPT_RELAY },
Simon Kelleyc4cd95d2013-10-10 20:58:11 +0100285 { "ra-param", 1, 0, LOPT_RA_PARAM },
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100286 { "quiet-dhcp", 0, 0, LOPT_QUIET_DHCP },
287 { "quiet-dhcp6", 0, 0, LOPT_QUIET_DHCP6 },
288 { "quiet-ra", 0, 0, LOPT_QUIET_RA },
Simon Kelley849a8352006-06-09 21:02:31 +0100289 { NULL, 0, 0, 0 }
290 };
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000291
Simon Kelley28866e92011-02-14 20:19:14 +0000292
293#define ARG_DUP OPT_LAST
294#define ARG_ONE OPT_LAST + 1
295#define ARG_USED_CL OPT_LAST + 2
296#define ARG_USED_FILE OPT_LAST + 3
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000297
Simon Kelley1a6bca82008-07-11 11:11:42 +0100298static struct {
299 int opt;
300 unsigned int rept;
301 char * const flagdesc;
Simon Kelleyb8187c82005-11-26 21:46:27 +0000302 char * const desc;
303 char * const arg;
304} usage[] = {
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000305 { 'a', ARG_DUP, "<ipaddr>", gettext_noop("Specify local address(es) to listen on."), NULL },
306 { 'A', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Return ipaddr for all hosts in specified domains."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100307 { 'b', OPT_BOGUSPRIV, NULL, gettext_noop("Fake reverse lookups for RFC1918 private address ranges."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000308 { 'B', ARG_DUP, "<ipaddr>", gettext_noop("Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."), NULL },
309 { 'c', ARG_ONE, "<integer>", gettext_noop("Specify the size of the cache in entries (defaults to %s)."), "$" },
310 { 'C', ARG_DUP, "<path>", gettext_noop("Specify configuration file (defaults to %s)."), CONFFILE },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100311 { 'd', OPT_DEBUG, NULL, gettext_noop("Do NOT fork into the background: run in debug mode."), NULL },
312 { 'D', OPT_NODOTS_LOCAL, NULL, gettext_noop("Do NOT forward queries with no domain part."), NULL },
313 { 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL },
314 { 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
315 { 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000316 { 'F', ARG_DUP, "<ipaddr>,...", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
317 { 'g', ARG_ONE, "<groupname>", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100318 { 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000319 { LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL },
320 { LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100321 { LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100322 { 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000323 { 'H', ARG_DUP, "<path>", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
324 { 'i', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) to listen on."), NULL },
325 { 'I', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100326 { 'j', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
327 { LOPT_CIRCUIT, ARG_DUP, "set:<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
328 { LOPT_REMOTE, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
329 { LOPT_SUBSCR, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
330 { 'J', ARG_DUP, "tag:<tag>...", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
331 { LOPT_BROADCAST, ARG_DUP, "[=tag:<tag>...]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100332 { 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
333 { '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 +0000334 { 'l', ARG_ONE, "<path>", gettext_noop("Specify where to store DHCP leases (defaults to %s)."), LEASEFILE },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100335 { 'L', OPT_LOCALMX, NULL, gettext_noop("Return MX records for local hosts."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000336 { 'm', ARG_DUP, "<host_name>,<target>,<pref>", gettext_noop("Specify an MX record."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100337 { 'M', ARG_DUP, "<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL },
338 { 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE },
339 { 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL },
340 { 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE },
341 { 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL },
342 { 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 +0000343 { 'p', ARG_ONE, "<integer>", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
344 { 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100345 { 'q', OPT_LOG, NULL, gettext_noop("Log DNS queries."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000346 { 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100347 { 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000348 { 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
349 { 'S', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
350 { LOPT_LOCAL, ARG_DUP, "/<domain>/", gettext_noop("Never forward queries to specified domains."), NULL },
Simon Kelley9009d742008-11-14 20:04:27 +0000351 { 's', ARG_DUP, "<domain>[,<range>]", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000352 { 't', ARG_ONE, "<host_name>", gettext_noop("Specify default target in an MX record."), NULL },
353 { 'T', ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
354 { LOPT_NEGTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
355 { LOPT_MAXTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL },
356 { 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100357 { 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100358 { 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000359 { 'V', ARG_DUP, "<ipaddr>,<ipaddr>,<netmask>", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },
360 { 'W', ARG_DUP, "<name>,<target>,...", gettext_noop("Specify a SRV record."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100361 { 'w', 0, NULL, gettext_noop("Display this message. Use --help dhcp for known DHCP options."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000362 { 'x', ARG_ONE, "<path>", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE },
363 { 'X', ARG_ONE, "<integer>", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100364 { '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 +0000365 { 'Y', ARG_DUP, "<name>,<txt>[,<txt]", gettext_noop("Specify TXT DNS record."), NULL },
366 { LOPT_PTR, ARG_DUP, "<name>,<target>", gettext_noop("Specify PTR DNS record."), NULL },
367 { LOPT_INTNAME, ARG_DUP, "<name>,<interface>", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100368 { 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
369 { 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
Simon Kelleyad094272012-08-10 17:10:54 +0100370 { '1', ARG_ONE, "[=<busname>]", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000371 { '2', ARG_DUP, "<interface>", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100372 { '3', ARG_DUP, "[=tag:<tag>]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
373 { '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 +0000374 { 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 +0100375 { '5', OPT_NO_PING, NULL, gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000376 { '6', ARG_ONE, "<path>", gettext_noop("Shell script to run on DHCP lease creation and destruction."), NULL },
377 { LOPT_LUASCRIPT, ARG_DUP, "path", gettext_noop("Lua script to run on DHCP lease creation and destruction."), NULL },
378 { LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change scripts as this user."), NULL },
379 { '7', ARG_DUP, "<path>", gettext_noop("Read configuration from all the files in this directory."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100380 { '8', ARG_ONE, "<facilty>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL },
381 { '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000382 { '0', ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100383 { LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100384 { LOPT_NO_NAMES, ARG_DUP, "[=tag:<tag>]...", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100385 { 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 +0100386 { LOPT_TFTP, ARG_DUP, "[=<intr>[,<intr>]]", gettext_noop("Enable integrated read-only TFTP server."), NULL },
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100387 { 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 +0100388 { LOPT_APREF, OPT_TFTP_APREF, NULL, gettext_noop("Add client IP address to tftp-root."), NULL },
389 { 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 +0000390 { LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100391 { LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
Simon Kelley61ce6002012-04-20 21:28:49 +0100392 { LOPT_TFTP_LC, OPT_TFTP_LC, NULL, gettext_noop("Convert TFTP filenames to lowercase"), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100393 { LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
394 { LOPT_LOG_OPTS, OPT_LOG_OPTS, NULL, gettext_noop("Extra logging for DHCP."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000395 { LOPT_MAX_LOGS, ARG_ONE, "[=<integer>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100396 { 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 +0100397 { 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 +0000398 { LOPT_NO_REBIND, ARG_DUP, "/<domain>/", gettext_noop("Inhibit DNS-rebind protection on this domain."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100399 { LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100400 { 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 +0100401 { LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100402 { LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
403 { LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
Simon Kelley9009d742008-11-14 20:04:27 +0000404 { 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 +0000405 { LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
406 { LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
Simon Kelleyff7eea22013-09-04 18:01:38 +0100407 { LOPT_RELAY, ARG_DUP, "<local-addr>,<server>[,<interface>]", gettext_noop("Relay DHCP requests to a remote server"), NULL},
Simon Kelley9009d742008-11-14 20:04:27 +0000408 { LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
Simon Kelley7622fc02009-06-04 20:32:05 +0100409 { LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
410 { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
411 { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
Simon Kelley7de060b2011-08-26 17:24:52 +0100412 { LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
Simon Kelleyed4c0762013-10-08 20:46:34 +0100413 { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add requestor's IP subnet to forwarded DNS queries."), NULL },
Simon Kelley5a4120d2013-10-25 13:13:11 +0100414 { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
Simon Kelley7de060b2011-08-26 17:24:52 +0100415 { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
416 { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
Simon Kelleyc72daea2012-01-05 21:33:27 +0000417 { 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 +0000418 { LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
Simon Kelley8b372702012-03-09 17:45:10 +0000419 { LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
Simon Kelleye759d422012-03-16 13:18:57 +0000420 { LOPT_HOST_REC, ARG_DUP, "<name>,<address>", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100421 { LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
Simon Kelley4f7b3042012-11-28 21:27:02 +0000422 { LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL },
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000423 { LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>", gettext_noop("Export local names to global DNS"), NULL },
Simon Kelley333b2ce2013-01-07 21:46:03 +0000424 { LOPT_AUTHZONE, ARG_DUP, "<domain>,[<subnet>...]", gettext_noop("Domain to export to global DNS"), NULL },
Simon Kelley4f7b3042012-11-28 21:27:02 +0000425 { LOPT_AUTHTTL, ARG_ONE, "<integer>", gettext_noop("Set TTL for authoritative replies"), NULL },
426 { LOPT_AUTHSOA, ARG_ONE, "<serial>[,...]", gettext_noop("Set authoritive zone information"), NULL },
Simon Kelley49678762012-12-09 18:24:58 +0000427 { LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
428 { 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 +0000429 { LOPT_IPSET, ARG_DUP, "/<domain>/<ipset>[,<ipset>...]", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },
Gildasa9bf81a2013-10-24 13:31:40 +0100430 { LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for synthesised names"), NULL },
Giovanni Bajo7dbe1932012-04-05 02:50:13 +0200431#ifdef HAVE_DNSSEC
Simon Kelley3a237152013-12-12 12:15:50 +0000432 { LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
Simon Kelley0fc2f312014-01-08 10:26:58 +0000433 { LOPT_DNSKEY, ARG_DUP, "<domain>,<algo>,<key>", gettext_noop("Specify trust anchor DNSKEY"), NULL },
Giovanni Bajo7dbe1932012-04-05 02:50:13 +0200434#endif
Simon Kelleyc6309242013-03-07 20:59:28 +0000435#ifdef OPTION6_PREFIX_CLASS
436 { LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
437#endif
Simon Kelleyc4cd95d2013-10-10 20:58:11 +0100438 { LOPT_RA_PARAM, ARG_DUP, "<interface>,[high,|low,]<interval>[,<lifetime>]", gettext_noop("Set priority, resend-interval and router-lifetime"), NULL },
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100439 { LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
440 { LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
441 { LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100442 { 0, 0, NULL, NULL, NULL }
Simon Kelleyb8187c82005-11-26 21:46:27 +0000443};
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000444
Simon Kelley3d8df262005-08-29 12:19:27 +0100445/* We hide metacharaters in quoted strings by mapping them into the ASCII control
Simon Kelleyf2621c72007-04-29 19:47:21 +0100446 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 +0100447 following sequence so that they map to themselves: it is therefore possible to call
448 unhide_metas repeatedly on string without breaking things.
Simon Kelley824af852008-02-12 20:43:05 +0000449 The transformation gets undone by opt_canonicalise, atoi_check and opt_string_alloc, and a
Simon Kelleyf2621c72007-04-29 19:47:21 +0100450 couple of other places.
451 Note that space is included here so that
452 --dhcp-option=3, string
453 has five characters, whilst
454 --dhcp-option=3," string"
455 has six.
456*/
Simon Kelley3d8df262005-08-29 12:19:27 +0100457
Simon Kelleyf2621c72007-04-29 19:47:21 +0100458static const char meta[] = "\000123456 \b\t\n78\r90abcdefABCDE\033F:,.";
Simon Kelley3d8df262005-08-29 12:19:27 +0100459
460static char hide_meta(char c)
461{
462 unsigned int i;
463
464 for (i = 0; i < (sizeof(meta) - 1); i++)
465 if (c == meta[i])
466 return (char)i;
467
468 return c;
469}
470
471static char unhide_meta(char cr)
472{
473 unsigned int c = cr;
474
475 if (c < (sizeof(meta) - 1))
476 cr = meta[c];
477
478 return cr;
479}
480
481static void unhide_metas(char *cp)
482{
483 if (cp)
484 for(; *cp; cp++)
485 *cp = unhide_meta(*cp);
486}
487
Simon Kelley824af852008-02-12 20:43:05 +0000488static void *opt_malloc(size_t size)
489{
490 void *ret;
491
492 if (mem_recover)
493 {
494 ret = whine_malloc(size);
495 if (!ret)
496 longjmp(mem_jmp, 1);
497 }
498 else
499 ret = safe_malloc(size);
500
501 return ret;
502}
503
504static char *opt_string_alloc(char *cp)
Simon Kelley3d8df262005-08-29 12:19:27 +0100505{
506 char *ret = NULL;
507
508 if (cp && strlen(cp) != 0)
509 {
Simon Kelley824af852008-02-12 20:43:05 +0000510 ret = opt_malloc(strlen(cp)+1);
Simon Kelley3d8df262005-08-29 12:19:27 +0100511 strcpy(ret, cp);
512
513 /* restore hidden metachars */
514 unhide_metas(ret);
515 }
516
517 return ret;
518}
519
Simon Kelley3d8df262005-08-29 12:19:27 +0100520
Simon Kelleyf2621c72007-04-29 19:47:21 +0100521/* find next comma, split string with zero and eliminate spaces.
522 return start of string following comma */
Simon Kelley73a08a22009-02-05 20:28:08 +0000523
524static char *split_chr(char *s, char c)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100525{
526 char *comma, *p;
527
Simon Kelley73a08a22009-02-05 20:28:08 +0000528 if (!s || !(comma = strchr(s, c)))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100529 return NULL;
530
531 p = comma;
532 *comma = ' ';
533
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100534 for (; *comma == ' '; comma++);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100535
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100536 for (; (p >= s) && *p == ' '; p--)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100537 *p = 0;
538
539 return comma;
Simon Kelley3d8df262005-08-29 12:19:27 +0100540}
541
Simon Kelley73a08a22009-02-05 20:28:08 +0000542static char *split(char *s)
543{
544 return split_chr(s, ',');
545}
546
Simon Kelley1f15b812009-10-13 17:49:32 +0100547static char *canonicalise_opt(char *s)
Simon Kelley3d8df262005-08-29 12:19:27 +0100548{
Simon Kelley1f15b812009-10-13 17:49:32 +0100549 char *ret;
550 int nomem;
551
Simon Kelley3d8df262005-08-29 12:19:27 +0100552 if (!s)
553 return 0;
554
555 unhide_metas(s);
Simon Kelley1f15b812009-10-13 17:49:32 +0100556 if (!(ret = canonicalise(s, &nomem)) && nomem)
557 {
558 if (mem_recover)
559 longjmp(mem_jmp, 1);
560 else
561 die(_("could not get memory"), NULL, EC_NOMEM);
562 }
563
564 return ret;
Simon Kelley3d8df262005-08-29 12:19:27 +0100565}
566
567static int atoi_check(char *a, int *res)
568{
569 char *p;
570
571 if (!a)
572 return 0;
573
574 unhide_metas(a);
575
576 for (p = a; *p; p++)
577 if (*p < '0' || *p > '9')
578 return 0;
579
580 *res = atoi(a);
581 return 1;
582}
583
Simon Kelley1ad24ae2008-07-20 20:22:50 +0100584static int atoi_check16(char *a, int *res)
585{
586 if (!(atoi_check(a, res)) ||
587 *res < 0 ||
588 *res > 0xffff)
589 return 0;
590
591 return 1;
592}
593
Simon Kelley5aabfc72007-08-29 11:24:47 +0100594static void add_txt(char *name, char *txt)
Simon Kelley0a852542005-03-23 20:28:59 +0000595{
596 size_t len = strlen(txt);
Simon Kelley824af852008-02-12 20:43:05 +0000597 struct txt_record *r = opt_malloc(sizeof(struct txt_record));
Simon Kelley0a852542005-03-23 20:28:59 +0000598
Simon Kelley824af852008-02-12 20:43:05 +0000599 r->name = opt_string_alloc(name);
Simon Kelley0a852542005-03-23 20:28:59 +0000600 r->next = daemon->txt;
601 daemon->txt = r;
602 r->class = C_CHAOS;
Simon Kelley824af852008-02-12 20:43:05 +0000603 r->txt = opt_malloc(len+1);
Simon Kelley0a852542005-03-23 20:28:59 +0000604 r->len = len+1;
605 *(r->txt) = len;
606 memcpy((r->txt)+1, txt, len);
607}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000608
Simon Kelley849a8352006-06-09 21:02:31 +0100609static void do_usage(void)
610{
611 char buff[100];
Simon Kelley832af0b2007-01-21 20:01:28 +0000612 int i, j;
613
614 struct {
615 char handle;
616 int val;
617 } tab[] = {
618 { '$', CACHESIZ },
619 { '*', EDNS_PKTSZ },
620 { '&', MAXLEASES },
621 { '!', FTABSIZ },
622 { '#', TFTP_MAX_CONNECTIONS },
623 { '\0', 0 }
624 };
Simon Kelley849a8352006-06-09 21:02:31 +0100625
626 printf(_("Usage: dnsmasq [options]\n\n"));
627#ifndef HAVE_GETOPT_LONG
628 printf(_("Use short options only on the command line.\n"));
629#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100630 printf(_("Valid options are:\n"));
Simon Kelley849a8352006-06-09 21:02:31 +0100631
Simon Kelley1a6bca82008-07-11 11:11:42 +0100632 for (i = 0; usage[i].opt != 0; i++)
Simon Kelley849a8352006-06-09 21:02:31 +0100633 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100634 char *desc = usage[i].flagdesc;
635 char *eq = "=";
636
637 if (!desc || *desc == '[')
638 eq = "";
639
640 if (!desc)
641 desc = "";
642
643 for ( j = 0; opts[j].name; j++)
644 if (opts[j].val == usage[i].opt)
645 break;
646 if (usage[i].opt < 256)
647 sprintf(buff, "-%c, ", usage[i].opt);
648 else
649 sprintf(buff, " ");
650
651 sprintf(buff+4, "--%s%s%s", opts[j].name, eq, desc);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100652 printf("%-40.40s", buff);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100653
Simon Kelley849a8352006-06-09 21:02:31 +0100654 if (usage[i].arg)
655 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000656 strcpy(buff, usage[i].arg);
657 for (j = 0; tab[j].handle; j++)
658 if (tab[j].handle == *(usage[i].arg))
659 sprintf(buff, "%d", tab[j].val);
Simon Kelley849a8352006-06-09 21:02:31 +0100660 }
Simon Kelley849a8352006-06-09 21:02:31 +0100661 printf(_(usage[i].desc), buff);
662 printf("\n");
663 }
664}
665
Simon Kelleyc740e4f2012-08-09 16:19:01 +0100666#define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
667
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100668char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags)
669{
670 int source_port = 0, serv_port = NAMESERVER_PORT;
671 char *portno, *source;
672#ifdef HAVE_IPV6
673 int scope_index = 0;
674 char *scope_id;
675#endif
676
677 if ((source = split_chr(arg, '@')) && /* is there a source. */
678 (portno = split_chr(source, '#')) &&
679 !atoi_check16(portno, &source_port))
680 return _("bad port");
681
682 if ((portno = split_chr(arg, '#')) && /* is there a port no. */
683 !atoi_check16(portno, &serv_port))
684 return _("bad port");
685
686#ifdef HAVE_IPV6
687 scope_id = split_chr(arg, '%');
688#endif
689
Simon Kelleyddd9a6b2013-04-29 17:00:21 +0100690 if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100691 {
692 addr->in.sin_port = htons(serv_port);
693 addr->sa.sa_family = source_addr->sa.sa_family = AF_INET;
694#ifdef HAVE_SOCKADDR_SA_LEN
695 source_addr->in.sin_len = addr->in.sin_len = sizeof(struct sockaddr_in);
696#endif
697 source_addr->in.sin_addr.s_addr = INADDR_ANY;
698 source_addr->in.sin_port = htons(daemon->query_port);
699
700 if (source)
701 {
702 if (flags)
703 *flags |= SERV_HAS_SOURCE;
704 source_addr->in.sin_port = htons(source_port);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +0100705 if (!(inet_pton(AF_INET, source, &source_addr->in.sin_addr) > 0))
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100706 {
707#if defined(SO_BINDTODEVICE)
708 source_addr->in.sin_addr.s_addr = INADDR_ANY;
709 strncpy(interface, source, IF_NAMESIZE - 1);
710#else
711 return _("interface binding not supported");
712#endif
713 }
714 }
715 }
716#ifdef HAVE_IPV6
717 else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
718 {
719 if (scope_id && (scope_index = if_nametoindex(scope_id)) == 0)
720 return _("bad interface name");
721
722 addr->in6.sin6_port = htons(serv_port);
723 addr->in6.sin6_scope_id = scope_index;
724 source_addr->in6.sin6_addr = in6addr_any;
725 source_addr->in6.sin6_port = htons(daemon->query_port);
726 source_addr->in6.sin6_scope_id = 0;
727 addr->sa.sa_family = source_addr->sa.sa_family = AF_INET6;
728 addr->in6.sin6_flowinfo = source_addr->in6.sin6_flowinfo = 0;
729#ifdef HAVE_SOCKADDR_SA_LEN
730 addr->in6.sin6_len = source_addr->in6.sin6_len = sizeof(addr->in6);
731#endif
732 if (source)
733 {
734 if (flags)
735 *flags |= SERV_HAS_SOURCE;
736 source_addr->in6.sin6_port = htons(source_port);
737 if (inet_pton(AF_INET6, source, &source_addr->in6.sin6_addr) == 0)
738 {
739#if defined(SO_BINDTODEVICE)
740 source_addr->in6.sin6_addr = in6addr_any;
741 strncpy(interface, source, IF_NAMESIZE - 1);
742#else
743 return _("interface binding not supported");
744#endif
745 }
746 }
747 }
748#endif
749 else
750 return _("bad address");
751
752 return NULL;
753}
754
Simon Kelleyb5a8dd12012-12-10 11:37:25 +0000755#ifdef HAVE_DHCP
756
757static int is_tag_prefix(char *arg)
758{
759 if (arg && (strstr(arg, "net:") == arg || strstr(arg, "tag:") == arg))
760 return 1;
761
762 return 0;
763}
764
765static char *set_prefix(char *arg)
766{
767 if (strstr(arg, "set:") == arg)
768 return arg+4;
769
770 return arg;
771}
772
Simon Kelley832af0b2007-01-21 20:01:28 +0000773/* This is too insanely large to keep in-line in the switch */
Simon Kelleyc4a7f902012-07-12 20:52:12 +0100774static int parse_dhcp_opt(char *errstr, char *arg, int flags)
Simon Kelley832af0b2007-01-21 20:01:28 +0000775{
Simon Kelley824af852008-02-12 20:43:05 +0000776 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
Simon Kelley832af0b2007-01-21 20:01:28 +0000777 char lenchar = 0, *cp;
Simon Kelley40ef23b2012-03-13 21:59:28 +0000778 int addrs, digs, is_addr, is_addr6, is_hex, is_dec, is_string, dots;
Simon Kelleyc4a7f902012-07-12 20:52:12 +0100779 char *comma = NULL;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100780 struct dhcp_netid *np = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000781 u16 opt_len = 0;
782 int is6 = 0;
Simon Kelleybd08ae62013-04-19 10:22:06 +0100783 int option_ok = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000784
785 new->len = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000786 new->flags = flags;
Simon Kelley832af0b2007-01-21 20:01:28 +0000787 new->netid = NULL;
788 new->val = NULL;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100789 new->opt = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000790
Simon Kelleyf2621c72007-04-29 19:47:21 +0100791 while (arg)
Simon Kelley832af0b2007-01-21 20:01:28 +0000792 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100793 comma = split(arg);
794
795 for (cp = arg; *cp; cp++)
796 if (*cp < '0' || *cp > '9')
Simon Kelley832af0b2007-01-21 20:01:28 +0000797 break;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100798
799 if (!*cp)
800 {
801 new->opt = atoi(arg);
802 opt_len = 0;
Simon Kelleybd08ae62013-04-19 10:22:06 +0100803 option_ok = 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100804 break;
805 }
806
807 if (strstr(arg, "option:") == arg)
808 {
Simon Kelleybd08ae62013-04-19 10:22:06 +0100809 if ((new->opt = lookup_dhcp_opt(AF_INET, arg+7)) != -1)
810 {
811 opt_len = lookup_dhcp_len(AF_INET, new->opt);
812 /* option:<optname> must follow tag and vendor string. */
813 if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
814 option_ok = 1;
815 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100816 break;
817 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000818#ifdef HAVE_DHCP6
819 else if (strstr(arg, "option6:") == arg)
820 {
821 for (cp = arg+8; *cp; cp++)
822 if (*cp < '0' || *cp > '9')
823 break;
824
825 if (!*cp)
826 {
827 new->opt = atoi(arg+8);
828 opt_len = 0;
Simon Kelleybd08ae62013-04-19 10:22:06 +0100829 option_ok = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000830 }
831 else
Simon Kelley40ef23b2012-03-13 21:59:28 +0000832 {
Simon Kelleybd08ae62013-04-19 10:22:06 +0100833 if ((new->opt = lookup_dhcp_opt(AF_INET6, arg+8)) != -1)
834 {
835 opt_len = lookup_dhcp_len(AF_INET6, new->opt);
836 if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
837 option_ok = 1;
838 }
Simon Kelley40ef23b2012-03-13 21:59:28 +0000839 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000840 /* option6:<opt>|<optname> must follow tag and vendor string. */
841 is6 = 1;
842 break;
843 }
844#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +0100845 else if (strstr(arg, "vendor:") == arg)
846 {
Simon Kelley73a08a22009-02-05 20:28:08 +0000847 new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7);
848 new->flags |= DHOPT_VENDOR;
849 }
850 else if (strstr(arg, "encap:") == arg)
851 {
852 new->u.encap = atoi(arg+6);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100853 new->flags |= DHOPT_ENCAPSULATE;
854 }
Simon Kelley316e2732010-01-22 20:16:09 +0000855 else if (strstr(arg, "vi-encap:") == arg)
856 {
857 new->u.encap = atoi(arg+9);
858 new->flags |= DHOPT_RFC3925;
859 if (flags == DHOPT_MATCH)
860 {
Simon Kelleybd08ae62013-04-19 10:22:06 +0100861 option_ok = 1;
Simon Kelley316e2732010-01-22 20:16:09 +0000862 break;
863 }
864 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100865 else
866 {
Simon Kelley824af852008-02-12 20:43:05 +0000867 new->netid = opt_malloc(sizeof (struct dhcp_netid));
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100868 /* allow optional "net:" or "tag:" for consistency */
869 if (is_tag_prefix(arg))
Simon Kelley824af852008-02-12 20:43:05 +0000870 new->netid->net = opt_string_alloc(arg+4);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100871 else
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100872 new->netid->net = opt_string_alloc(set_prefix(arg));
Simon Kelleyf2621c72007-04-29 19:47:21 +0100873 new->netid->next = np;
874 np = new->netid;
875 }
876
877 arg = comma;
Simon Kelley832af0b2007-01-21 20:01:28 +0000878 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000879
880#ifdef HAVE_DHCP6
881 if (is6)
882 {
883 if (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))
Simon Kelleyc4a7f902012-07-12 20:52:12 +0100884 ret_err(_("unsupported encapsulation for IPv6 option"));
Simon Kelley4cb1b322012-02-06 14:30:41 +0000885
886 if (opt_len == 0 &&
887 !(new->flags & DHOPT_RFC3925))
Simon Kelleybd08ae62013-04-19 10:22:06 +0100888 opt_len = lookup_dhcp_len(AF_INET6, new->opt);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000889 }
890 else
891#endif
892 if (opt_len == 0 &&
893 !(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
Simon Kelleybd08ae62013-04-19 10:22:06 +0100894 opt_len = lookup_dhcp_len(AF_INET, new->opt);
Simon Kelley40ef23b2012-03-13 21:59:28 +0000895
Simon Kelley316e2732010-01-22 20:16:09 +0000896 /* option may be missing with rfc3925 match */
Simon Kelleybd08ae62013-04-19 10:22:06 +0100897 if (!option_ok)
Simon Kelleyc4a7f902012-07-12 20:52:12 +0100898 ret_err(_("bad dhcp-option"));
899
900 if (comma)
Simon Kelley832af0b2007-01-21 20:01:28 +0000901 {
902 /* characterise the value */
Simon Kelleyf2621c72007-04-29 19:47:21 +0100903 char c;
Simon Kelley28866e92011-02-14 20:19:14 +0000904 int found_dig = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000905 is_addr = is_addr6 = is_hex = is_dec = is_string = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +0000906 addrs = digs = 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100907 dots = 0;
908 for (cp = comma; (c = *cp); cp++)
909 if (c == ',')
Simon Kelley832af0b2007-01-21 20:01:28 +0000910 {
911 addrs++;
912 is_dec = is_hex = 0;
913 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100914 else if (c == ':')
Simon Kelley832af0b2007-01-21 20:01:28 +0000915 {
916 digs++;
917 is_dec = is_addr = 0;
918 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100919 else if (c == '/')
Simon Kelley832af0b2007-01-21 20:01:28 +0000920 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000921 is_addr6 = is_dec = is_hex = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000922 if (cp == comma) /* leading / means a pathname */
923 is_addr = 0;
924 }
Simon Kelleyf2621c72007-04-29 19:47:21 +0100925 else if (c == '.')
926 {
Simon Kelley23245c02012-07-18 16:21:11 +0100927 is_addr6 = is_dec = is_hex = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100928 dots++;
929 }
930 else if (c == '-')
Simon Kelley4cb1b322012-02-06 14:30:41 +0000931 is_hex = is_addr = is_addr6 = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100932 else if (c == ' ')
Simon Kelley832af0b2007-01-21 20:01:28 +0000933 is_dec = is_hex = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100934 else if (!(c >='0' && c <= '9'))
Simon Kelley832af0b2007-01-21 20:01:28 +0000935 {
936 is_addr = 0;
937 if (cp[1] == 0 && is_dec &&
Simon Kelleyf2621c72007-04-29 19:47:21 +0100938 (c == 'b' || c == 's' || c == 'i'))
Simon Kelley832af0b2007-01-21 20:01:28 +0000939 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100940 lenchar = c;
Simon Kelley832af0b2007-01-21 20:01:28 +0000941 *cp = 0;
942 }
943 else
944 is_dec = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100945 if (!((c >='A' && c <= 'F') ||
Simon Kelley73a08a22009-02-05 20:28:08 +0000946 (c >='a' && c <= 'f') ||
947 (c == '*' && (flags & DHOPT_MATCH))))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000948 {
949 is_hex = 0;
950 if (c != '[' && c != ']')
951 is_addr6 = 0;
952 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000953 }
Simon Kelley28866e92011-02-14 20:19:14 +0000954 else
955 found_dig = 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100956
Simon Kelley28866e92011-02-14 20:19:14 +0000957 if (!found_dig)
958 is_dec = is_addr = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000959
Simon Kelleyf2621c72007-04-29 19:47:21 +0100960 /* We know that some options take addresses */
Simon Kelley7622fc02009-06-04 20:32:05 +0100961 if (opt_len & OT_ADDR_LIST)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100962 {
963 is_string = is_dec = is_hex = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000964
965 if (!is6 && (!is_addr || dots == 0))
Simon Kelleyc4a7f902012-07-12 20:52:12 +0100966 ret_err(_("bad IP address"));
Simon Kelley4cb1b322012-02-06 14:30:41 +0000967
968 if (is6 && !is_addr6)
Simon Kelleyc4a7f902012-07-12 20:52:12 +0100969 ret_err(_("bad IPv6 address"));
Simon Kelleyf2621c72007-04-29 19:47:21 +0100970 }
Simon Kelley28866e92011-02-14 20:19:14 +0000971 /* or names */
Simon Kelley4cb1b322012-02-06 14:30:41 +0000972 else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING))
973 is_addr6 = is_addr = is_dec = is_hex = 0;
Simon Kelley23245c02012-07-18 16:21:11 +0100974
975 if (found_dig && (opt_len & OT_TIME) && strlen(comma) > 0)
976 {
977 int val, fac = 1;
978
979 switch (comma[strlen(comma) - 1])
980 {
Simon Kelley42243212012-07-20 15:19:18 +0100981 case 'w':
982 case 'W':
983 fac *= 7;
984 /* fall through */
Simon Kelley23245c02012-07-18 16:21:11 +0100985 case 'd':
986 case 'D':
987 fac *= 24;
988 /* fall though */
989 case 'h':
990 case 'H':
991 fac *= 60;
992 /* fall through */
993 case 'm':
994 case 'M':
995 fac *= 60;
996 /* fall through */
997 case 's':
998 case 'S':
999 comma[strlen(comma) - 1] = 0;
1000 }
1001
1002 new->len = 4;
1003 new->val = opt_malloc(4);
1004 val = atoi(comma);
1005 *((int *)new->val) = htonl(val * fac);
1006 }
1007 else if (is_hex && digs > 1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001008 {
1009 new->len = digs;
Simon Kelley824af852008-02-12 20:43:05 +00001010 new->val = opt_malloc(new->len);
Simon Kelley73a08a22009-02-05 20:28:08 +00001011 parse_hex(comma, new->val, digs, (flags & DHOPT_MATCH) ? &new->u.wildcard_mask : NULL, NULL);
1012 new->flags |= DHOPT_HEX;
Simon Kelley832af0b2007-01-21 20:01:28 +00001013 }
1014 else if (is_dec)
1015 {
1016 int i, val = atoi(comma);
1017 /* assume numeric arg is 1 byte except for
1018 options where it is known otherwise.
1019 For vendor class option, we have to hack. */
Simon Kelleyf2621c72007-04-29 19:47:21 +01001020 if (opt_len != 0)
1021 new->len = opt_len;
1022 else if (val & 0xffff0000)
1023 new->len = 4;
1024 else if (val & 0xff00)
1025 new->len = 2;
1026 else
1027 new->len = 1;
1028
Simon Kelley832af0b2007-01-21 20:01:28 +00001029 if (lenchar == 'b')
1030 new->len = 1;
1031 else if (lenchar == 's')
1032 new->len = 2;
1033 else if (lenchar == 'i')
1034 new->len = 4;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001035
Simon Kelley824af852008-02-12 20:43:05 +00001036 new->val = opt_malloc(new->len);
Simon Kelley832af0b2007-01-21 20:01:28 +00001037 for (i=0; i<new->len; i++)
1038 new->val[i] = val>>((new->len - i - 1)*8);
1039 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001040 else if (is_addr && !is6)
Simon Kelley832af0b2007-01-21 20:01:28 +00001041 {
1042 struct in_addr in;
1043 unsigned char *op;
1044 char *slash;
1045 /* max length of address/subnet descriptor is five bytes,
1046 add one for the option 120 enc byte too */
Simon Kelley824af852008-02-12 20:43:05 +00001047 new->val = op = opt_malloc((5 * addrs) + 1);
Simon Kelley6b010842007-02-12 20:32:07 +00001048 new->flags |= DHOPT_ADDR;
1049
Simon Kelley572b41e2011-02-18 18:11:18 +00001050 if (!(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
1051 new->opt == OPTION_SIP_SERVER)
Simon Kelley832af0b2007-01-21 20:01:28 +00001052 {
Simon Kelley6b010842007-02-12 20:32:07 +00001053 *(op++) = 1; /* RFC 3361 "enc byte" */
1054 new->flags &= ~DHOPT_ADDR;
Simon Kelley832af0b2007-01-21 20:01:28 +00001055 }
1056 while (addrs--)
1057 {
1058 cp = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001059 comma = split(cp);
Simon Kelley73a08a22009-02-05 20:28:08 +00001060 slash = split_chr(cp, '/');
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01001061 inet_pton(AF_INET, cp, &in);
Simon Kelley832af0b2007-01-21 20:01:28 +00001062 if (!slash)
1063 {
1064 memcpy(op, &in, INADDRSZ);
1065 op += INADDRSZ;
1066 }
1067 else
1068 {
1069 unsigned char *p = (unsigned char *)&in;
1070 int netsize = atoi(slash);
1071 *op++ = netsize;
1072 if (netsize > 0)
1073 *op++ = *p++;
1074 if (netsize > 8)
1075 *op++ = *p++;
1076 if (netsize > 16)
1077 *op++ = *p++;
1078 if (netsize > 24)
1079 *op++ = *p++;
1080 new->flags &= ~DHOPT_ADDR; /* cannot re-write descriptor format */
1081 }
1082 }
1083 new->len = op - new->val;
1084 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001085 else if (is_addr6 && is6)
1086 {
1087 unsigned char *op;
1088 new->val = op = opt_malloc(16 * addrs);
1089 new->flags |= DHOPT_ADDR6;
1090 while (addrs--)
1091 {
1092 cp = comma;
1093 comma = split(cp);
1094
1095 /* check for [1234::7] */
1096 if (*cp == '[')
1097 cp++;
1098 if (strlen(cp) > 1 && cp[strlen(cp)-1] == ']')
1099 cp[strlen(cp)-1] = 0;
1100
1101 if (inet_pton(AF_INET6, cp, op))
1102 {
1103 op += IN6ADDRSZ;
1104 continue;
1105 }
1106
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001107 ret_err(_("bad IPv6 address"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001108 }
1109 new->len = op - new->val;
1110 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001111 else if (is_string)
Simon Kelley832af0b2007-01-21 20:01:28 +00001112 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001113 /* text arg */
Simon Kelley572b41e2011-02-18 18:11:18 +00001114 if ((new->opt == OPTION_DOMAIN_SEARCH || new->opt == OPTION_SIP_SERVER) &&
Simon Kelley4cb1b322012-02-06 14:30:41 +00001115 !is6 && !(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
Simon Kelley832af0b2007-01-21 20:01:28 +00001116 {
1117 /* dns search, RFC 3397, or SIP, RFC 3361 */
1118 unsigned char *q, *r, *tail;
Simon Kelley824af852008-02-12 20:43:05 +00001119 unsigned char *p, *m = NULL, *newp;
Simon Kelley832af0b2007-01-21 20:01:28 +00001120 size_t newlen, len = 0;
Simon Kelley572b41e2011-02-18 18:11:18 +00001121 int header_size = (new->opt == OPTION_DOMAIN_SEARCH) ? 0 : 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001122
1123 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001124 comma = split(arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00001125
1126 while (arg && *arg)
1127 {
Simon Kelleyc52e1892010-06-07 22:01:39 +01001128 char *in, *dom = NULL;
1129 size_t domlen = 1;
1130 /* Allow "." as an empty domain */
1131 if (strcmp (arg, ".") != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001132 {
Simon Kelleyc52e1892010-06-07 22:01:39 +01001133 if (!(dom = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001134 ret_err(_("bad domain in dhcp-option"));
1135
Simon Kelleyc52e1892010-06-07 22:01:39 +01001136 domlen = strlen(dom) + 2;
Simon Kelley832af0b2007-01-21 20:01:28 +00001137 }
Simon Kelleyc52e1892010-06-07 22:01:39 +01001138
1139 newp = opt_malloc(len + domlen + header_size);
Simon Kelley824af852008-02-12 20:43:05 +00001140 if (m)
Simon Kelleyc52e1892010-06-07 22:01:39 +01001141 {
1142 memcpy(newp, m, header_size + len);
1143 free(m);
1144 }
Simon Kelley824af852008-02-12 20:43:05 +00001145 m = newp;
Simon Kelley832af0b2007-01-21 20:01:28 +00001146 p = m + header_size;
1147 q = p + len;
1148
1149 /* add string on the end in RFC1035 format */
Simon Kelleyc52e1892010-06-07 22:01:39 +01001150 for (in = dom; in && *in;)
Simon Kelley832af0b2007-01-21 20:01:28 +00001151 {
1152 unsigned char *cp = q++;
1153 int j;
Simon Kelleyc52e1892010-06-07 22:01:39 +01001154 for (j = 0; *in && (*in != '.'); in++, j++)
1155 *q++ = *in;
Simon Kelley832af0b2007-01-21 20:01:28 +00001156 *cp = j;
Simon Kelleyc52e1892010-06-07 22:01:39 +01001157 if (*in)
1158 in++;
Simon Kelley832af0b2007-01-21 20:01:28 +00001159 }
1160 *q++ = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +01001161 free(dom);
Simon Kelleyc52e1892010-06-07 22:01:39 +01001162
Simon Kelley832af0b2007-01-21 20:01:28 +00001163 /* Now tail-compress using earlier names. */
1164 newlen = q - p;
1165 for (tail = p + len; *tail; tail += (*tail) + 1)
1166 for (r = p; r - p < (int)len; r += (*r) + 1)
1167 if (strcmp((char *)r, (char *)tail) == 0)
1168 {
1169 PUTSHORT((r - p) | 0xc000, tail);
1170 newlen = tail - p;
1171 goto end;
1172 }
1173 end:
1174 len = newlen;
1175
1176 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001177 comma = split(arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00001178 }
1179
1180 /* RFC 3361, enc byte is zero for names */
Simon Kelley572b41e2011-02-18 18:11:18 +00001181 if (new->opt == OPTION_SIP_SERVER)
Simon Kelley832af0b2007-01-21 20:01:28 +00001182 m[0] = 0;
1183 new->len = (int) len + header_size;
1184 new->val = m;
1185 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001186#ifdef HAVE_DHCP6
1187 else if (comma && (opt_len & OT_CSTRING))
1188 {
1189 /* length fields are two bytes so need 16 bits for each string */
Simon Kelley40ef23b2012-03-13 21:59:28 +00001190 int i, commas = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001191 unsigned char *p, *newp;
1192
Simon Kelley40ef23b2012-03-13 21:59:28 +00001193 for (i = 0; comma[i]; i++)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001194 if (comma[i] == ',')
1195 commas++;
1196
1197 newp = opt_malloc(strlen(comma)+(2*commas));
1198 p = newp;
1199 arg = comma;
1200 comma = split(arg);
1201
1202 while (arg && *arg)
1203 {
1204 u16 len = strlen(arg);
Simon Kelley18f0fb02012-03-31 21:18:55 +01001205 unhide_metas(arg);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001206 PUTSHORT(len, p);
1207 memcpy(p, arg, len);
1208 p += len;
1209
1210 arg = comma;
1211 comma = split(arg);
1212 }
1213
1214 new->val = newp;
1215 new->len = p - newp;
1216 }
1217 else if (comma && (opt_len & OT_RFC1035_NAME))
1218 {
Simon Kelley18f0fb02012-03-31 21:18:55 +01001219 unsigned char *p = NULL, *newp, *end;
1220 int len = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001221 arg = comma;
1222 comma = split(arg);
1223
1224 while (arg && *arg)
1225 {
Simon Kelley18f0fb02012-03-31 21:18:55 +01001226 char *dom = canonicalise_opt(arg);
1227 if (!dom)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001228 ret_err(_("bad domain in dhcp-option"));
1229
Simon Kelley18f0fb02012-03-31 21:18:55 +01001230 newp = opt_malloc(len + strlen(dom) + 2);
1231
1232 if (p)
1233 {
1234 memcpy(newp, p, len);
1235 free(p);
1236 }
1237
1238 p = newp;
1239 end = do_rfc1035_name(p + len, dom);
1240 *end++ = 0;
1241 len = end - p;
1242 free(dom);
1243
Simon Kelley4cb1b322012-02-06 14:30:41 +00001244 arg = comma;
1245 comma = split(arg);
1246 }
1247
Simon Kelley18f0fb02012-03-31 21:18:55 +01001248 new->val = p;
1249 new->len = len;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001250 }
1251#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001252 else
1253 {
1254 new->len = strlen(comma);
1255 /* keep terminating zero on string */
Simon Kelley824af852008-02-12 20:43:05 +00001256 new->val = (unsigned char *)opt_string_alloc(comma);
Simon Kelley832af0b2007-01-21 20:01:28 +00001257 new->flags |= DHOPT_STRING;
1258 }
1259 }
1260 }
1261
Simon Kelley4cb1b322012-02-06 14:30:41 +00001262 if (!is6 &&
1263 ((new->len > 255) ||
Simon Kelley316e2732010-01-22 20:16:09 +00001264 (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) ||
Simon Kelley4cb1b322012-02-06 14:30:41 +00001265 (new->len > 250 && (new->flags & DHOPT_RFC3925))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001266 ret_err(_("dhcp-option too long"));
Simon Kelley832af0b2007-01-21 20:01:28 +00001267
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001268 if (flags == DHOPT_MATCH)
Simon Kelley824af852008-02-12 20:43:05 +00001269 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001270 if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||
1271 !new->netid ||
1272 new->netid->next)
1273 ret_err(_("illegal dhcp-match"));
1274
1275 if (is6)
Simon Kelley73a08a22009-02-05 20:28:08 +00001276 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001277 new->next = daemon->dhcp_match6;
1278 daemon->dhcp_match6 = new;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001279 }
1280 else
Simon Kelley73a08a22009-02-05 20:28:08 +00001281 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001282 new->next = daemon->dhcp_match;
1283 daemon->dhcp_match = new;
Simon Kelley73a08a22009-02-05 20:28:08 +00001284 }
Simon Kelley824af852008-02-12 20:43:05 +00001285 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001286 else if (is6)
1287 {
1288 new->next = daemon->dhcp_opts6;
1289 daemon->dhcp_opts6 = new;
1290 }
1291 else
1292 {
1293 new->next = daemon->dhcp_opts;
1294 daemon->dhcp_opts = new;
1295 }
1296
1297 return 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001298}
1299
Simon Kelley7622fc02009-06-04 20:32:05 +01001300#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001301
Simon Kelley28866e92011-02-14 20:19:14 +00001302void set_option_bool(unsigned int opt)
1303{
1304 if (opt < 32)
1305 daemon->options |= 1u << opt;
1306 else
1307 daemon->options2 |= 1u << (opt - 32);
1308}
1309
Simon Kelley2b5bae92012-06-26 16:55:23 +01001310void reset_option_bool(unsigned int opt)
1311{
1312 if (opt < 32)
1313 daemon->options &= ~(1u << opt);
1314 else
1315 daemon->options2 &= ~(1u << (opt - 32));
1316}
1317
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001318static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line)
Simon Kelley849a8352006-06-09 21:02:31 +01001319{
1320 int i;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001321 char *comma;
Simon Kelley849a8352006-06-09 21:02:31 +01001322
Simon Kelley832af0b2007-01-21 20:01:28 +00001323 if (option == '?')
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001324 ret_err(gen_err);
Simon Kelley832af0b2007-01-21 20:01:28 +00001325
Simon Kelley1a6bca82008-07-11 11:11:42 +01001326 for (i=0; usage[i].opt != 0; i++)
1327 if (usage[i].opt == option)
Simon Kelley849a8352006-06-09 21:02:31 +01001328 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001329 int rept = usage[i].rept;
1330
Simon Kelley28866e92011-02-14 20:19:14 +00001331 if (command_line)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001332 {
1333 /* command line */
1334 if (rept == ARG_USED_CL)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001335 ret_err(_("illegal repeated flag"));
Simon Kelley1a6bca82008-07-11 11:11:42 +01001336 if (rept == ARG_ONE)
1337 usage[i].rept = ARG_USED_CL;
1338 }
1339 else
1340 {
1341 /* allow file to override command line */
1342 if (rept == ARG_USED_FILE)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001343 ret_err(_("illegal repeated keyword"));
Simon Kelley1a6bca82008-07-11 11:11:42 +01001344 if (rept == ARG_USED_CL || rept == ARG_ONE)
1345 usage[i].rept = ARG_USED_FILE;
1346 }
1347
1348 if (rept != ARG_DUP && rept != ARG_ONE && rept != ARG_USED_CL)
1349 {
Simon Kelley28866e92011-02-14 20:19:14 +00001350 set_option_bool(rept);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001351 return 1;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001352 }
1353
1354 break;
Simon Kelley849a8352006-06-09 21:02:31 +01001355 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001356
Simon Kelley849a8352006-06-09 21:02:31 +01001357 switch (option)
1358 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001359 case 'C': /* --conf-file */
Simon Kelley849a8352006-06-09 21:02:31 +01001360 {
Simon Kelley824af852008-02-12 20:43:05 +00001361 char *file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001362 if (file)
Simon Kelley9009d742008-11-14 20:04:27 +00001363 {
Simon Kelley28866e92011-02-14 20:19:14 +00001364 one_file(file, 0);
Simon Kelley9009d742008-11-14 20:04:27 +00001365 free(file);
1366 }
Simon Kelley849a8352006-06-09 21:02:31 +01001367 break;
1368 }
1369
Simon Kelleyf2621c72007-04-29 19:47:21 +01001370 case '7': /* --conf-dir */
Simon Kelley849a8352006-06-09 21:02:31 +01001371 {
1372 DIR *dir_stream;
1373 struct dirent *ent;
1374 char *directory, *path;
Simon Kelley1f15b812009-10-13 17:49:32 +01001375 struct list {
1376 char *suffix;
1377 struct list *next;
1378 } *ignore_suffix = NULL, *li;
Simon Kelley849a8352006-06-09 21:02:31 +01001379
Simon Kelley1f15b812009-10-13 17:49:32 +01001380 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00001381 if (!(directory = opt_string_alloc(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01001382 break;
1383
Simon Kelley1f15b812009-10-13 17:49:32 +01001384 for (arg = comma; arg; arg = comma)
1385 {
1386 comma = split(arg);
1387 li = opt_malloc(sizeof(struct list));
1388 li->next = ignore_suffix;
1389 ignore_suffix = li;
1390 /* Have to copy: buffer is overwritten */
1391 li->suffix = opt_string_alloc(arg);
1392 };
1393
Simon Kelley849a8352006-06-09 21:02:31 +01001394 if (!(dir_stream = opendir(directory)))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001395 die(_("cannot access directory %s: %s"), directory, EC_FILE);
Simon Kelley1f15b812009-10-13 17:49:32 +01001396
Simon Kelley849a8352006-06-09 21:02:31 +01001397 while ((ent = readdir(dir_stream)))
1398 {
Simon Kelley7622fc02009-06-04 20:32:05 +01001399 size_t len = strlen(ent->d_name);
Simon Kelley849a8352006-06-09 21:02:31 +01001400 struct stat buf;
Simon Kelley1f15b812009-10-13 17:49:32 +01001401
1402 /* ignore emacs backups and dotfiles */
Simon Kelley7622fc02009-06-04 20:32:05 +01001403 if (len == 0 ||
1404 ent->d_name[len - 1] == '~' ||
Simon Kelley849a8352006-06-09 21:02:31 +01001405 (ent->d_name[0] == '#' && ent->d_name[len - 1] == '#') ||
1406 ent->d_name[0] == '.')
1407 continue;
Simon Kelley7622fc02009-06-04 20:32:05 +01001408
Simon Kelley1f15b812009-10-13 17:49:32 +01001409 for (li = ignore_suffix; li; li = li->next)
1410 {
1411 /* check for proscribed suffices */
1412 size_t ls = strlen(li->suffix);
1413 if (len > ls &&
1414 strcmp(li->suffix, &ent->d_name[len - ls]) == 0)
1415 break;
1416 }
1417 if (li)
1418 continue;
1419
Simon Kelley824af852008-02-12 20:43:05 +00001420 path = opt_malloc(strlen(directory) + len + 2);
Simon Kelley849a8352006-06-09 21:02:31 +01001421 strcpy(path, directory);
1422 strcat(path, "/");
1423 strcat(path, ent->d_name);
Simon Kelley7622fc02009-06-04 20:32:05 +01001424
Simon Kelley39595cf2013-02-04 21:40:07 +00001425 /* files must be readable */
Simon Kelley849a8352006-06-09 21:02:31 +01001426 if (stat(path, &buf) == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001427 die(_("cannot access %s: %s"), path, EC_FILE);
Simon Kelley849a8352006-06-09 21:02:31 +01001428
Simon Kelley39595cf2013-02-04 21:40:07 +00001429 /* only reg files allowed. */
1430 if (S_ISREG(buf.st_mode))
1431 one_file(path, 0);
1432
Simon Kelley849a8352006-06-09 21:02:31 +01001433 free(path);
1434 }
1435
1436 closedir(dir_stream);
Simon Kelley9009d742008-11-14 20:04:27 +00001437 free(directory);
Simon Kelley1f15b812009-10-13 17:49:32 +01001438 for(; ignore_suffix; ignore_suffix = li)
1439 {
1440 li = ignore_suffix->next;
1441 free(ignore_suffix->suffix);
1442 free(ignore_suffix);
1443 }
1444
Simon Kelley849a8352006-06-09 21:02:31 +01001445 break;
1446 }
1447
Simon Kelleyed4c0762013-10-08 20:46:34 +01001448 case LOPT_ADD_SBNET: /* --add-subnet */
1449 set_option_bool(OPT_CLIENT_SUBNET);
1450 if (arg)
1451 {
1452 comma = split(arg);
1453 if (!atoi_check(arg, &daemon->addr4_netmask) ||
1454 (comma && !atoi_check(comma, &daemon->addr6_netmask)))
1455 ret_err(gen_err);
1456 }
1457 break;
1458
Simon Kelleyad094272012-08-10 17:10:54 +01001459 case '1': /* --enable-dbus */
1460 set_option_bool(OPT_DBUS);
1461 if (arg)
1462 daemon->dbus_name = opt_string_alloc(arg);
1463 else
1464 daemon->dbus_name = DNSMASQ_SERVICE;
1465 break;
1466
Simon Kelleyf2621c72007-04-29 19:47:21 +01001467 case '8': /* --log-facility */
1468 /* may be a filename */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001469 if (strchr(arg, '/') || strcmp (arg, "-") == 0)
Simon Kelley824af852008-02-12 20:43:05 +00001470 daemon->log_file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001471 else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001472 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001473#ifdef __ANDROID__
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001474 ret_err(_("setting log facility is not possible under Android"));
Simon Kelley572b41e2011-02-18 18:11:18 +00001475#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001476 for (i = 0; facilitynames[i].c_name; i++)
1477 if (hostname_isequal((char *)facilitynames[i].c_name, arg))
1478 break;
1479
1480 if (facilitynames[i].c_name)
1481 daemon->log_fac = facilitynames[i].c_val;
1482 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001483 ret_err(_("bad log facility"));
Simon Kelley572b41e2011-02-18 18:11:18 +00001484#endif
Simon Kelley849a8352006-06-09 21:02:31 +01001485 }
1486 break;
1487
Simon Kelleyf2621c72007-04-29 19:47:21 +01001488 case 'x': /* --pid-file */
Simon Kelley824af852008-02-12 20:43:05 +00001489 daemon->runfile = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001490 break;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001491
Simon Kelleyf2621c72007-04-29 19:47:21 +01001492 case 'r': /* --resolv-file */
Simon Kelley849a8352006-06-09 21:02:31 +01001493 {
Simon Kelley824af852008-02-12 20:43:05 +00001494 char *name = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001495 struct resolvc *new, *list = daemon->resolv_files;
1496
1497 if (list && list->is_default)
1498 {
1499 /* replace default resolv file - possibly with nothing */
1500 if (name)
1501 {
1502 list->is_default = 0;
1503 list->name = name;
1504 }
1505 else
1506 list = NULL;
1507 }
1508 else if (name)
1509 {
Simon Kelley824af852008-02-12 20:43:05 +00001510 new = opt_malloc(sizeof(struct resolvc));
Simon Kelley849a8352006-06-09 21:02:31 +01001511 new->next = list;
1512 new->name = name;
1513 new->is_default = 0;
1514 new->mtime = 0;
1515 new->logged = 0;
1516 list = new;
1517 }
1518 daemon->resolv_files = list;
1519 break;
1520 }
1521
Simon Kelleyf2621c72007-04-29 19:47:21 +01001522 case 'm': /* --mx-host */
Simon Kelley849a8352006-06-09 21:02:31 +01001523 {
1524 int pref = 1;
1525 struct mx_srv_record *new;
Simon Kelley1f15b812009-10-13 17:49:32 +01001526 char *name, *target = NULL;
1527
Simon Kelleyf2621c72007-04-29 19:47:21 +01001528 if ((comma = split(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01001529 {
1530 char *prefstr;
Simon Kelley1f15b812009-10-13 17:49:32 +01001531 if ((prefstr = split(comma)) && !atoi_check16(prefstr, &pref))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001532 ret_err(_("bad MX preference"));
Simon Kelley849a8352006-06-09 21:02:31 +01001533 }
1534
Simon Kelley1f15b812009-10-13 17:49:32 +01001535 if (!(name = canonicalise_opt(arg)) ||
1536 (comma && !(target = canonicalise_opt(comma))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001537 ret_err(_("bad MX name"));
Simon Kelley1f15b812009-10-13 17:49:32 +01001538
Simon Kelley824af852008-02-12 20:43:05 +00001539 new = opt_malloc(sizeof(struct mx_srv_record));
Simon Kelley849a8352006-06-09 21:02:31 +01001540 new->next = daemon->mxnames;
1541 daemon->mxnames = new;
1542 new->issrv = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +01001543 new->name = name;
1544 new->target = target; /* may be NULL */
Simon Kelley849a8352006-06-09 21:02:31 +01001545 new->weight = pref;
1546 break;
1547 }
1548
Simon Kelleyf2621c72007-04-29 19:47:21 +01001549 case 't': /* --mx-target */
Simon Kelley1f15b812009-10-13 17:49:32 +01001550 if (!(daemon->mxtarget = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001551 ret_err(_("bad MX target"));
Simon Kelley849a8352006-06-09 21:02:31 +01001552 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01001553
1554#ifdef HAVE_DHCP
Simon Kelleyf2621c72007-04-29 19:47:21 +01001555 case 'l': /* --dhcp-leasefile */
Simon Kelley824af852008-02-12 20:43:05 +00001556 daemon->lease_file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001557 break;
1558
Simon Kelleyc72daea2012-01-05 21:33:27 +00001559 /* Sorry about the gross pre-processor abuse */
1560 case '6': /* --dhcp-script */
1561 case LOPT_LUASCRIPT: /* --dhcp-luascript */
Simon Kelley1f15b812009-10-13 17:49:32 +01001562# if defined(NO_FORK)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001563 ret_err(_("cannot run scripts under uClinux"));
Simon Kelley1f15b812009-10-13 17:49:32 +01001564# elif !defined(HAVE_SCRIPT)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001565 ret_err(_("recompile with HAVE_SCRIPT defined to enable lease-change scripts"));
Simon Kelley7622fc02009-06-04 20:32:05 +01001566# else
Simon Kelleyc72daea2012-01-05 21:33:27 +00001567 if (option == LOPT_LUASCRIPT)
1568# if !defined(HAVE_LUASCRIPT)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001569 ret_err(_("recompile with HAVE_LUASCRIPT defined to enable Lua scripts"));
Simon Kelleyc72daea2012-01-05 21:33:27 +00001570# else
1571 daemon->luascript = opt_string_alloc(arg);
1572# endif
1573 else
1574 daemon->lease_change_command = opt_string_alloc(arg);
Simon Kelley7622fc02009-06-04 20:32:05 +01001575# endif
Simon Kelley849a8352006-06-09 21:02:31 +01001576 break;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001577#endif /* HAVE_DHCP */
Simon Kelley7622fc02009-06-04 20:32:05 +01001578
Simon Kelley28866e92011-02-14 20:19:14 +00001579 case LOPT_DHCP_HOST: /* --dhcp-hostfile */
1580 case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
Simon Kelleyf2621c72007-04-29 19:47:21 +01001581 case 'H': /* --addn-hosts */
Simon Kelley849a8352006-06-09 21:02:31 +01001582 {
Simon Kelley824af852008-02-12 20:43:05 +00001583 struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
Simon Kelley849a8352006-06-09 21:02:31 +01001584 static int hosts_index = 1;
Simon Kelley824af852008-02-12 20:43:05 +00001585 new->fname = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001586 new->index = hosts_index++;
Simon Kelley7622fc02009-06-04 20:32:05 +01001587 new->flags = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00001588 if (option == 'H')
1589 {
1590 new->next = daemon->addn_hosts;
1591 daemon->addn_hosts = new;
1592 }
1593 else if (option == LOPT_DHCP_HOST)
1594 {
1595 new->next = daemon->dhcp_hosts_file;
1596 daemon->dhcp_hosts_file = new;
1597 }
Simon Kelleye1ff4192012-12-09 17:08:47 +00001598 else if (option == LOPT_DHCP_OPTS)
Simon Kelley28866e92011-02-14 20:19:14 +00001599 {
1600 new->next = daemon->dhcp_opts_file;
1601 daemon->dhcp_opts_file = new;
1602 }
Simon Kelley849a8352006-06-09 21:02:31 +01001603 break;
1604 }
1605
Simon Kelleyf373a152013-09-23 12:47:47 +01001606
1607#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001608 case LOPT_AUTHSERV: /* --auth-server */
Simon Kelley86e3b9a2012-11-30 13:46:48 +00001609 if (!(comma = split(arg)))
Simon Kelley4f7b3042012-11-28 21:27:02 +00001610 ret_err(gen_err);
1611
Simon Kelley4f7b3042012-11-28 21:27:02 +00001612 daemon->authserver = opt_string_alloc(arg);
Simon Kelley429798f2012-12-10 20:45:53 +00001613 arg = comma;
1614 do {
1615 struct iname *new = opt_malloc(sizeof(struct iname));
1616 comma = split(arg);
1617 new->name = NULL;
1618 unhide_metas(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01001619 if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0)
Simon Kelley429798f2012-12-10 20:45:53 +00001620 new->addr.sa.sa_family = AF_INET;
1621#ifdef HAVE_IPV6
1622 else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
1623 new->addr.sa.sa_family = AF_INET6;
1624#endif
1625 else
Simon Kelleyf25e6c62013-11-17 12:23:42 +00001626 {
1627 char *fam = split_chr(arg, '/');
1628 new->name = opt_string_alloc(arg);
1629 new->addr.sa.sa_family = 0;
1630 if (fam)
1631 {
1632 if (strcmp(fam, "4") == 0)
1633 new->addr.sa.sa_family = AF_INET;
1634#ifdef HAVE_IPV6
1635 else if (strcmp(fam, "6") == 0)
1636 new->addr.sa.sa_family = AF_INET6;
1637#endif
1638 else
1639 ret_err(gen_err);
1640 }
1641 }
Simon Kelley429798f2012-12-10 20:45:53 +00001642 new->next = daemon->authinterface;
1643 daemon->authinterface = new;
1644
1645 arg = comma;
1646 } while (arg);
1647
Simon Kelley4f7b3042012-11-28 21:27:02 +00001648 break;
Simon Kelleye1ff4192012-12-09 17:08:47 +00001649
1650 case LOPT_AUTHSFS: /* --auth-sec-servers */
1651 {
1652 struct name_list *new;
1653
1654 do {
1655 comma = split(arg);
Simon Kelley429798f2012-12-10 20:45:53 +00001656 new = opt_malloc(sizeof(struct name_list));
Simon Kelleye1ff4192012-12-09 17:08:47 +00001657 new->name = opt_string_alloc(arg);
1658 new->next = daemon->secondary_forward_server;
1659 daemon->secondary_forward_server = new;
1660 arg = comma;
1661 } while (arg);
1662 break;
1663 }
1664
Simon Kelley4f7b3042012-11-28 21:27:02 +00001665 case LOPT_AUTHZONE: /* --auth-zone */
1666 {
1667 struct auth_zone *new;
1668
1669 comma = split(arg);
Simon Kelley1e14cc02012-12-29 17:27:59 +00001670
Simon Kelley429798f2012-12-10 20:45:53 +00001671 new = opt_malloc(sizeof(struct auth_zone));
Simon Kelley4f7b3042012-11-28 21:27:02 +00001672 new->domain = opt_string_alloc(arg);
1673 new->subnet = NULL;
Simon Kelley376d48c2013-11-13 13:04:30 +00001674 new->interface_names = NULL;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001675 new->next = daemon->auth_zones;
1676 daemon->auth_zones = new;
1677
1678 while ((arg = comma))
1679 {
1680 int prefixlen = 0;
1681 char *prefix;
Simon Kelley376d48c2013-11-13 13:04:30 +00001682 struct addrlist *subnet = NULL;
1683 struct all_addr addr;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001684
1685 comma = split(arg);
1686 prefix = split_chr(arg, '/');
1687
1688 if (prefix && !atoi_check(prefix, &prefixlen))
1689 ret_err(gen_err);
1690
Simon Kelley376d48c2013-11-13 13:04:30 +00001691 if (inet_pton(AF_INET, arg, &addr.addr.addr4))
Simon Kelley4f7b3042012-11-28 21:27:02 +00001692 {
Simon Kelley376d48c2013-11-13 13:04:30 +00001693 subnet = opt_malloc(sizeof(struct addrlist));
Simon Kelley4f7b3042012-11-28 21:27:02 +00001694 subnet->prefixlen = (prefixlen == 0) ? 24 : prefixlen;
Simon Kelley376d48c2013-11-13 13:04:30 +00001695 subnet->flags = ADDRLIST_LITERAL;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001696 }
1697#ifdef HAVE_IPV6
Simon Kelley376d48c2013-11-13 13:04:30 +00001698 else if (inet_pton(AF_INET6, arg, &addr.addr.addr6))
Simon Kelley4f7b3042012-11-28 21:27:02 +00001699 {
Simon Kelley376d48c2013-11-13 13:04:30 +00001700 subnet = opt_malloc(sizeof(struct addrlist));
Simon Kelley4f7b3042012-11-28 21:27:02 +00001701 subnet->prefixlen = (prefixlen == 0) ? 64 : prefixlen;
Simon Kelley376d48c2013-11-13 13:04:30 +00001702 subnet->flags = ADDRLIST_LITERAL | ADDRLIST_IPV6;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001703 }
1704#endif
Simon Kelley376d48c2013-11-13 13:04:30 +00001705 else
1706 {
1707 struct auth_name_list *name = opt_malloc(sizeof(struct auth_name_list));
1708 name->name = opt_string_alloc(arg);
1709 name->flags = AUTH4 | AUTH6;
1710 name->next = new->interface_names;
1711 new->interface_names = name;
1712 if (prefix)
1713 {
1714 if (prefixlen == 4)
1715 name->flags &= ~AUTH6;
1716#ifdef HAVE_IPV6
1717 else if (prefixlen == 6)
1718 name->flags &= ~AUTH4;
1719#endif
1720 else
1721 ret_err(gen_err);
1722 }
1723 }
1724
1725 if (subnet)
1726 {
1727 subnet->addr = addr;
1728 subnet->next = new->subnet;
1729 new->subnet = subnet;
1730 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001731 }
1732 break;
1733 }
Simon Kelley376d48c2013-11-13 13:04:30 +00001734
Simon Kelley4f7b3042012-11-28 21:27:02 +00001735 case LOPT_AUTHSOA: /* --auth-soa */
1736 comma = split(arg);
Simon Kelley5c72bb92013-08-19 14:12:59 +01001737 daemon->soa_sn = (u32)atoi(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001738 if (comma)
1739 {
Simon Kelley86e3b9a2012-11-30 13:46:48 +00001740 char *cp;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001741 arg = comma;
1742 comma = split(arg);
1743 daemon->hostmaster = opt_string_alloc(arg);
Simon Kelley86e3b9a2012-11-30 13:46:48 +00001744 for (cp = daemon->hostmaster; *cp; cp++)
1745 if (*cp == '@')
1746 *cp = '.';
1747
Simon Kelley4f7b3042012-11-28 21:27:02 +00001748 if (comma)
1749 {
1750 arg = comma;
1751 comma = split(arg);
Simon Kelley5c72bb92013-08-19 14:12:59 +01001752 daemon->soa_refresh = (u32)atoi(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001753 if (comma)
1754 {
1755 arg = comma;
1756 comma = split(arg);
Simon Kelley5c72bb92013-08-19 14:12:59 +01001757 daemon->soa_retry = (u32)atoi(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001758 if (comma)
1759 {
1760 arg = comma;
1761 comma = split(arg);
Simon Kelley5c72bb92013-08-19 14:12:59 +01001762 daemon->soa_expiry = (u32)atoi(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001763 }
1764 }
1765 }
1766 }
1767
1768 break;
Simon Kelleyf373a152013-09-23 12:47:47 +01001769#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001770
Simon Kelley2bb73af2013-04-24 17:38:19 +01001771 case 's': /* --domain */
1772 case LOPT_SYNTH: /* --synth-domain */
Simon Kelley849a8352006-06-09 21:02:31 +01001773 if (strcmp (arg, "#") == 0)
Simon Kelley28866e92011-02-14 20:19:14 +00001774 set_option_bool(OPT_RESOLV_DOMAIN);
Simon Kelley849a8352006-06-09 21:02:31 +01001775 else
Simon Kelley9009d742008-11-14 20:04:27 +00001776 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001777 char *d;
Simon Kelley9009d742008-11-14 20:04:27 +00001778 comma = split(arg);
Simon Kelley1f15b812009-10-13 17:49:32 +01001779 if (!(d = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001780 ret_err(gen_err);
Simon Kelley9009d742008-11-14 20:04:27 +00001781 else
1782 {
Simon Kelley9009d742008-11-14 20:04:27 +00001783 if (comma)
1784 {
Simon Kelley429798f2012-12-10 20:45:53 +00001785 struct cond_domain *new = opt_malloc(sizeof(struct cond_domain));
Simon Kelley28866e92011-02-14 20:19:14 +00001786 char *netpart;
Simon Kelley2bb73af2013-04-24 17:38:19 +01001787
Simon Kelley48fd1c42013-04-25 09:49:38 +01001788 new->prefix = NULL;
1789
Simon Kelley9009d742008-11-14 20:04:27 +00001790 unhide_metas(comma);
Simon Kelley28866e92011-02-14 20:19:14 +00001791 if ((netpart = split_chr(comma, '/')))
Simon Kelley9009d742008-11-14 20:04:27 +00001792 {
Simon Kelleyd74942a2012-02-07 20:51:56 +00001793 int msize;
1794
Simon Kelley28866e92011-02-14 20:19:14 +00001795 arg = split(netpart);
Simon Kelleyd74942a2012-02-07 20:51:56 +00001796 if (!atoi_check(netpart, &msize))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001797 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00001798 else if (inet_pton(AF_INET, comma, &new->start))
Simon Kelley9009d742008-11-14 20:04:27 +00001799 {
Simon Kelleyd74942a2012-02-07 20:51:56 +00001800 int mask = (1 << (32 - msize)) - 1;
1801 new->is6 = 0;
Simon Kelley9009d742008-11-14 20:04:27 +00001802 new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask);
1803 new->end.s_addr = new->start.s_addr | htonl(mask);
Simon Kelley28866e92011-02-14 20:19:14 +00001804 if (arg)
1805 {
Simon Kelley48fd1c42013-04-25 09:49:38 +01001806 if (option != 's')
Simon Kelleyb5a7ff42013-04-25 11:03:47 +01001807 {
1808 if (!(new->prefix = canonicalise_opt(arg)) ||
1809 strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
1810 ret_err(_("bad prefix"));
1811 }
Simon Kelley48fd1c42013-04-25 09:49:38 +01001812 else if (strcmp(arg, "local") != 0 ||
1813 (msize != 8 && msize != 16 && msize != 24))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001814 ret_err(gen_err);
Simon Kelley28866e92011-02-14 20:19:14 +00001815 else
1816 {
Simon Kelley48fd1c42013-04-25 09:49:38 +01001817 /* generate the equivalent of
1818 local=/<domain>/
1819 local=/xxx.yyy.zzz.in-addr.arpa/ */
Simon Kelley28866e92011-02-14 20:19:14 +00001820 struct server *serv = opt_malloc(sizeof(struct server));
1821 in_addr_t a = ntohl(new->start.s_addr) >> 8;
1822 char *p;
Simon Kelley48fd1c42013-04-25 09:49:38 +01001823
Simon Kelley28866e92011-02-14 20:19:14 +00001824 memset(serv, 0, sizeof(struct server));
1825 serv->domain = d;
1826 serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
1827 serv->next = daemon->servers;
1828 daemon->servers = serv;
Simon Kelley48fd1c42013-04-25 09:49:38 +01001829
Simon Kelley28866e92011-02-14 20:19:14 +00001830 serv = opt_malloc(sizeof(struct server));
1831 memset(serv, 0, sizeof(struct server));
1832 p = serv->domain = opt_malloc(25); /* strlen("xxx.yyy.zzz.in-addr.arpa")+1 */
1833
1834 if (msize == 24)
1835 p += sprintf(p, "%d.", a & 0xff);
1836 a = a >> 8;
1837 if (msize != 8)
1838 p += sprintf(p, "%d.", a & 0xff);
1839 a = a >> 8;
1840 p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
Simon Kelley48fd1c42013-04-25 09:49:38 +01001841
Simon Kelley28866e92011-02-14 20:19:14 +00001842 serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
1843 serv->next = daemon->servers;
1844 daemon->servers = serv;
1845 }
1846 }
Simon Kelley9009d742008-11-14 20:04:27 +00001847 }
Simon Kelleyd74942a2012-02-07 20:51:56 +00001848#ifdef HAVE_IPV6
1849 else if (inet_pton(AF_INET6, comma, &new->start6))
1850 {
1851 u64 mask = (1LLU << (128 - msize)) - 1LLU;
1852 u64 addrpart = addr6part(&new->start6);
1853 new->is6 = 1;
Simon Kelley48fd1c42013-04-25 09:49:38 +01001854
Simon Kelleyd74942a2012-02-07 20:51:56 +00001855 /* prefix==64 overflows the mask calculation above */
1856 if (msize == 64)
1857 mask = (u64)-1LL;
Simon Kelley48fd1c42013-04-25 09:49:38 +01001858
Simon Kelleyd74942a2012-02-07 20:51:56 +00001859 new->end6 = new->start6;
1860 setaddr6part(&new->start6, addrpart & ~mask);
1861 setaddr6part(&new->end6, addrpart | mask);
1862
1863 if (msize < 64)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001864 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00001865 else if (arg)
1866 {
Simon Kelley48fd1c42013-04-25 09:49:38 +01001867 if (option != 's')
Simon Kelleyb5a7ff42013-04-25 11:03:47 +01001868 {
1869 if (!(new->prefix = canonicalise_opt(arg)) ||
1870 strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
1871 ret_err(_("bad prefix"));
1872 }
Simon Kelley48fd1c42013-04-25 09:49:38 +01001873 else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001874 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00001875 else
1876 {
Simon Kelley48fd1c42013-04-25 09:49:38 +01001877 /* generate the equivalent of
1878 local=/<domain>/
1879 local=/xxx.yyy.zzz.ip6.arpa/ */
Simon Kelleyd74942a2012-02-07 20:51:56 +00001880 struct server *serv = opt_malloc(sizeof(struct server));
Simon Kelleyd74942a2012-02-07 20:51:56 +00001881 char *p;
Simon Kelleyceae00d2012-02-09 21:28:14 +00001882
Simon Kelleyd74942a2012-02-07 20:51:56 +00001883 memset(serv, 0, sizeof(struct server));
1884 serv->domain = d;
1885 serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
1886 serv->next = daemon->servers;
1887 daemon->servers = serv;
1888
1889 serv = opt_malloc(sizeof(struct server));
1890 memset(serv, 0, sizeof(struct server));
1891 p = serv->domain = opt_malloc(73); /* strlen("32*<n.>ip6.arpa")+1 */
1892
1893 for (i = msize-1; i >= 0; i -= 4)
1894 {
1895 int dig = ((unsigned char *)&new->start6)[i>>3];
1896 p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
1897 }
1898 p += sprintf(p, "ip6.arpa");
1899
1900 serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
1901 serv->next = daemon->servers;
1902 daemon->servers = serv;
1903 }
1904 }
1905 }
1906#endif
1907 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001908 ret_err(gen_err);
Simon Kelley9009d742008-11-14 20:04:27 +00001909 }
Simon Kelleyeec5c1e2013-10-25 10:37:30 +01001910 else
Simon Kelleyd74942a2012-02-07 20:51:56 +00001911 {
Simon Kelleyeec5c1e2013-10-25 10:37:30 +01001912 char *prefstr;
Simon Kelleyd74942a2012-02-07 20:51:56 +00001913 arg = split(comma);
Simon Kelleyeec5c1e2013-10-25 10:37:30 +01001914 prefstr = split(arg);
1915
Simon Kelleyd74942a2012-02-07 20:51:56 +00001916 if (inet_pton(AF_INET, comma, &new->start))
1917 {
1918 new->is6 = 0;
1919 if (!arg)
1920 new->end.s_addr = new->start.s_addr;
1921 else if (!inet_pton(AF_INET, arg, &new->end))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001922 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00001923 }
1924#ifdef HAVE_IPV6
1925 else if (inet_pton(AF_INET6, comma, &new->start6))
1926 {
1927 new->is6 = 1;
1928 if (!arg)
1929 memcpy(&new->end6, &new->start6, IN6ADDRSZ);
1930 else if (!inet_pton(AF_INET6, arg, &new->end6))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001931 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00001932 }
1933#endif
1934 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001935 ret_err(gen_err);
Simon Kelleyeec5c1e2013-10-25 10:37:30 +01001936
1937 if (option != 's' && prefstr)
1938 {
1939 if (!(new->prefix = canonicalise_opt(prefstr)) ||
1940 strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
1941 ret_err(_("bad prefix"));
1942 }
Simon Kelleyd74942a2012-02-07 20:51:56 +00001943 }
Simon Kelley2307eac2012-02-13 10:13:13 +00001944
1945 new->domain = d;
Simon Kelley2bb73af2013-04-24 17:38:19 +01001946 if (option == 's')
1947 {
1948 new->next = daemon->cond_domain;
1949 daemon->cond_domain = new;
1950 }
1951 else
1952 {
1953 new->next = daemon->synth_domains;
1954 daemon->synth_domains = new;
1955 }
Simon Kelley9009d742008-11-14 20:04:27 +00001956 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001957 else if (option == 's')
Simon Kelley9009d742008-11-14 20:04:27 +00001958 daemon->domain_suffix = d;
Simon Kelley2bb73af2013-04-24 17:38:19 +01001959 else
1960 ret_err(gen_err);
Simon Kelley9009d742008-11-14 20:04:27 +00001961 }
1962 }
Simon Kelley849a8352006-06-09 21:02:31 +01001963 break;
1964
Simon Kelleyf2621c72007-04-29 19:47:21 +01001965 case 'u': /* --user */
Simon Kelley824af852008-02-12 20:43:05 +00001966 daemon->username = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001967 break;
1968
Simon Kelleyf2621c72007-04-29 19:47:21 +01001969 case 'g': /* --group */
Simon Kelley824af852008-02-12 20:43:05 +00001970 daemon->groupname = opt_string_alloc(arg);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001971 daemon->group_set = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01001972 break;
Simon Kelley9e038942008-05-30 20:06:34 +01001973
Simon Kelley7622fc02009-06-04 20:32:05 +01001974#ifdef HAVE_DHCP
Simon Kelley9e038942008-05-30 20:06:34 +01001975 case LOPT_SCRIPTUSR: /* --scriptuser */
1976 daemon->scriptuser = opt_string_alloc(arg);
1977 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01001978#endif
Simon Kelley849a8352006-06-09 21:02:31 +01001979
Simon Kelleyf2621c72007-04-29 19:47:21 +01001980 case 'i': /* --interface */
Simon Kelley849a8352006-06-09 21:02:31 +01001981 do {
Simon Kelley824af852008-02-12 20:43:05 +00001982 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01001983 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001984 new->next = daemon->if_names;
1985 daemon->if_names = new;
1986 /* new->name may be NULL if someone does
1987 "interface=" to disable all interfaces except loop. */
Simon Kelley824af852008-02-12 20:43:05 +00001988 new->name = opt_string_alloc(arg);
Simon Kelley4ce4f372012-06-14 11:50:45 +01001989 new->used = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01001990 arg = comma;
1991 } while (arg);
1992 break;
1993
Simon Kelley2937f8a2013-07-29 19:49:07 +01001994 case LOPT_TFTP: /* --enable-tftp */
1995 set_option_bool(OPT_TFTP);
1996 if (!arg)
1997 break;
1998 /* fall through */
1999
Simon Kelleyf2621c72007-04-29 19:47:21 +01002000 case 'I': /* --except-interface */
2001 case '2': /* --no-dhcp-interface */
Simon Kelley849a8352006-06-09 21:02:31 +01002002 do {
Simon Kelley824af852008-02-12 20:43:05 +00002003 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01002004 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00002005 new->name = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002006 if (option == 'I')
2007 {
2008 new->next = daemon->if_except;
2009 daemon->if_except = new;
2010 }
Simon Kelley2937f8a2013-07-29 19:49:07 +01002011 else if (option == LOPT_TFTP)
2012 {
2013 new->next = daemon->tftp_interfaces;
2014 daemon->tftp_interfaces = new;
2015 }
Simon Kelley849a8352006-06-09 21:02:31 +01002016 else
2017 {
2018 new->next = daemon->dhcp_except;
2019 daemon->dhcp_except = new;
2020 }
2021 arg = comma;
2022 } while (arg);
2023 break;
2024
Simon Kelleyf2621c72007-04-29 19:47:21 +01002025 case 'B': /* --bogus-nxdomain */
Simon Kelley849a8352006-06-09 21:02:31 +01002026 {
2027 struct in_addr addr;
2028 unhide_metas(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002029 if (arg && (inet_pton(AF_INET, arg, &addr) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01002030 {
Simon Kelley824af852008-02-12 20:43:05 +00002031 struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
Simon Kelley849a8352006-06-09 21:02:31 +01002032 baddr->next = daemon->bogus_addr;
2033 daemon->bogus_addr = baddr;
2034 baddr->addr = addr;
2035 }
2036 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002037 ret_err(gen_err); /* error */
Simon Kelley849a8352006-06-09 21:02:31 +01002038 break;
2039 }
2040
Simon Kelleyf2621c72007-04-29 19:47:21 +01002041 case 'a': /* --listen-address */
Simon Kelley49678762012-12-09 18:24:58 +00002042 case LOPT_AUTHPEER: /* --auth-peer */
Simon Kelley849a8352006-06-09 21:02:31 +01002043 do {
Simon Kelley824af852008-02-12 20:43:05 +00002044 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01002045 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002046 unhide_metas(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002047 if (arg && (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01002048 {
2049 new->addr.sa.sa_family = AF_INET;
Simon Kelley49678762012-12-09 18:24:58 +00002050 new->addr.in.sin_port = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002051#ifdef HAVE_SOCKADDR_SA_LEN
2052 new->addr.in.sin_len = sizeof(new->addr.in);
2053#endif
2054 }
2055#ifdef HAVE_IPV6
2056 else if (arg && inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
2057 {
2058 new->addr.sa.sa_family = AF_INET6;
2059 new->addr.in6.sin6_flowinfo = 0;
2060 new->addr.in6.sin6_scope_id = 0;
Simon Kelley49678762012-12-09 18:24:58 +00002061 new->addr.in6.sin6_port = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002062#ifdef HAVE_SOCKADDR_SA_LEN
2063 new->addr.in6.sin6_len = sizeof(new->addr.in6);
2064#endif
2065 }
2066#endif
2067 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002068 ret_err(gen_err);
Simon Kelley4ce4f372012-06-14 11:50:45 +01002069
2070 new->used = 0;
Simon Kelley49678762012-12-09 18:24:58 +00002071 if (option == 'a')
2072 {
2073 new->next = daemon->if_addrs;
2074 daemon->if_addrs = new;
2075 }
2076 else
2077 {
2078 new->next = daemon->auth_peers;
2079 daemon->auth_peers = new;
2080 }
Simon Kelley849a8352006-06-09 21:02:31 +01002081 arg = comma;
2082 } while (arg);
2083 break;
2084
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002085 case 'S': /* --server */
2086 case LOPT_LOCAL: /* --local */
2087 case 'A': /* --address */
2088 case LOPT_NO_REBIND: /* --rebind-domain-ok */
Simon Kelley849a8352006-06-09 21:02:31 +01002089 {
2090 struct server *serv, *newlist = NULL;
2091
2092 unhide_metas(arg);
2093
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002094 if (arg && (*arg == '/' || option == LOPT_NO_REBIND))
Simon Kelley849a8352006-06-09 21:02:31 +01002095 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002096 int rebind = !(*arg == '/');
2097 char *end = NULL;
2098 if (!rebind)
2099 arg++;
2100 while (rebind || (end = split_chr(arg, '/')))
Simon Kelley849a8352006-06-09 21:02:31 +01002101 {
2102 char *domain = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002103 /* elide leading dots - they are implied in the search algorithm */
2104 while (*arg == '.') arg++;
Simon Kelley849a8352006-06-09 21:02:31 +01002105 /* # matches everything and becomes a zero length domain string */
2106 if (strcmp(arg, "#") == 0)
2107 domain = "";
Simon Kelley1f15b812009-10-13 17:49:32 +01002108 else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01002109 option = '?';
Simon Kelley824af852008-02-12 20:43:05 +00002110 serv = opt_malloc(sizeof(struct server));
2111 memset(serv, 0, sizeof(struct server));
Simon Kelley849a8352006-06-09 21:02:31 +01002112 serv->next = newlist;
2113 newlist = serv;
Simon Kelley849a8352006-06-09 21:02:31 +01002114 serv->domain = domain;
2115 serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
Simon Kelley73a08a22009-02-05 20:28:08 +00002116 arg = end;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002117 if (rebind)
2118 break;
Simon Kelley849a8352006-06-09 21:02:31 +01002119 }
2120 if (!newlist)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002121 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002122 }
2123 else
2124 {
Simon Kelley824af852008-02-12 20:43:05 +00002125 newlist = opt_malloc(sizeof(struct server));
2126 memset(newlist, 0, sizeof(struct server));
Simon Kelley849a8352006-06-09 21:02:31 +01002127 }
2128
2129 if (option == 'A')
2130 {
2131 newlist->flags |= SERV_LITERAL_ADDRESS;
2132 if (!(newlist->flags & SERV_TYPE))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002133 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002134 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002135 else if (option == LOPT_NO_REBIND)
2136 newlist->flags |= SERV_NO_REBIND;
Simon Kelley849a8352006-06-09 21:02:31 +01002137
2138 if (!arg || !*arg)
2139 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002140 if (!(newlist->flags & SERV_NO_REBIND))
2141 newlist->flags |= SERV_NO_ADDR; /* no server */
2142 if (newlist->flags & SERV_LITERAL_ADDRESS)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002143 ret_err(gen_err);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002144 }
2145
2146 else if (strcmp(arg, "#") == 0)
2147 {
2148 newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
Simon Kelley849a8352006-06-09 21:02:31 +01002149 if (newlist->flags & SERV_LITERAL_ADDRESS)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002150 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002151 }
2152 else
2153 {
Simon Kelleyfaafb3f2012-09-20 14:17:39 +01002154 char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
2155 if (err)
2156 ret_err(err);
Simon Kelley849a8352006-06-09 21:02:31 +01002157 }
2158
Simon Kelleyf2621c72007-04-29 19:47:21 +01002159 serv = newlist;
2160 while (serv->next)
Simon Kelley849a8352006-06-09 21:02:31 +01002161 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01002162 serv->next->flags = serv->flags;
2163 serv->next->addr = serv->addr;
2164 serv->next->source_addr = serv->source_addr;
Simon Kelleyfaafb3f2012-09-20 14:17:39 +01002165 strcpy(serv->next->interface, serv->interface);
Simon Kelleyf2621c72007-04-29 19:47:21 +01002166 serv = serv->next;
Simon Kelley849a8352006-06-09 21:02:31 +01002167 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01002168 serv->next = daemon->servers;
2169 daemon->servers = newlist;
Simon Kelley849a8352006-06-09 21:02:31 +01002170 break;
2171 }
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002172
2173 case LOPT_IPSET: /* --ipset */
2174#ifndef HAVE_IPSET
2175 ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
2176 break;
2177#else
2178 {
2179 struct ipsets ipsets_head;
2180 struct ipsets *ipsets = &ipsets_head;
2181 int size;
2182 char *end;
2183 char **sets, **sets_pos;
2184 memset(ipsets, 0, sizeof(struct ipsets));
2185 unhide_metas(arg);
2186 if (arg && *arg == '/')
2187 {
2188 arg++;
2189 while ((end = split_chr(arg, '/')))
2190 {
2191 char *domain = NULL;
2192 /* elide leading dots - they are implied in the search algorithm */
2193 while (*arg == '.')
2194 arg++;
2195 /* # matches everything and becomes a zero length domain string */
2196 if (strcmp(arg, "#") == 0 || !*arg)
2197 domain = "";
2198 else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg)))
2199 option = '?';
2200 ipsets->next = opt_malloc(sizeof(struct ipsets));
2201 ipsets = ipsets->next;
2202 memset(ipsets, 0, sizeof(struct ipsets));
2203 ipsets->domain = domain;
2204 arg = end;
2205 }
2206 }
2207 else
2208 {
2209 ipsets->next = opt_malloc(sizeof(struct ipsets));
2210 ipsets = ipsets->next;
2211 memset(ipsets, 0, sizeof(struct ipsets));
2212 ipsets->domain = "";
2213 }
2214 if (!arg || !*arg)
2215 {
2216 option = '?';
2217 break;
2218 }
2219 size = 2;
2220 for (end = arg; *end; ++end)
2221 if (*end == ',')
2222 ++size;
2223
2224 sets = sets_pos = opt_malloc(sizeof(char *) * size);
2225
2226 do {
2227 end = split(arg);
2228 *sets_pos++ = opt_string_alloc(arg);
2229 arg = end;
2230 } while (end);
2231 *sets_pos = 0;
2232 for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next)
2233 ipsets->next->sets = sets;
2234 ipsets->next = daemon->ipsets;
2235 daemon->ipsets = ipsets_head.next;
2236
2237 break;
2238 }
2239#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002240
Simon Kelleyf2621c72007-04-29 19:47:21 +01002241 case 'c': /* --cache-size */
Simon Kelley849a8352006-06-09 21:02:31 +01002242 {
2243 int size;
2244
2245 if (!atoi_check(arg, &size))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002246 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002247 else
2248 {
2249 /* zero is OK, and means no caching. */
2250
2251 if (size < 0)
2252 size = 0;
2253 else if (size > 10000)
2254 size = 10000;
2255
2256 daemon->cachesize = size;
2257 }
2258 break;
2259 }
2260
Simon Kelleyf2621c72007-04-29 19:47:21 +01002261 case 'p': /* --port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002262 if (!atoi_check16(arg, &daemon->port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002263 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002264 break;
Simon Kelley208b65c2006-08-05 21:41:37 +01002265
Simon Kelley1a6bca82008-07-11 11:11:42 +01002266 case LOPT_MINPORT: /* --min-port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002267 if (!atoi_check16(arg, &daemon->min_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002268 ret_err(gen_err);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002269 break;
2270
Simon Kelleyf2621c72007-04-29 19:47:21 +01002271 case '0': /* --dns-forward-max */
Simon Kelley208b65c2006-08-05 21:41:37 +01002272 if (!atoi_check(arg, &daemon->ftabsize))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002273 ret_err(gen_err);
Simon Kelley208b65c2006-08-05 21:41:37 +01002274 break;
2275
Simon Kelleyf2621c72007-04-29 19:47:21 +01002276 case LOPT_MAX_LOGS: /* --log-async */
2277 daemon->max_logs = LOG_MAX; /* default */
2278 if (arg && !atoi_check(arg, &daemon->max_logs))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002279 ret_err(gen_err);
Simon Kelleyf2621c72007-04-29 19:47:21 +01002280 else if (daemon->max_logs > 100)
2281 daemon->max_logs = 100;
2282 break;
2283
2284 case 'P': /* --edns-packet-max */
Simon Kelley849a8352006-06-09 21:02:31 +01002285 {
2286 int i;
2287 if (!atoi_check(arg, &i))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002288 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002289 daemon->edns_pktsz = (unsigned short)i;
2290 break;
2291 }
2292
Simon Kelleyf2621c72007-04-29 19:47:21 +01002293 case 'Q': /* --query-port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002294 if (!atoi_check16(arg, &daemon->query_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002295 ret_err(gen_err);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002296 /* if explicitly set to zero, use single OS ephemeral port
2297 and disable random ports */
2298 if (daemon->query_port == 0)
2299 daemon->osport = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01002300 break;
2301
Simon Kelley824af852008-02-12 20:43:05 +00002302 case 'T': /* --local-ttl */
2303 case LOPT_NEGTTL: /* --neg-ttl */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002304 case LOPT_MAXTTL: /* --max-ttl */
Simon Kelley1d860412012-09-20 20:48:04 +01002305 case LOPT_MAXCTTL: /* --max-cache-ttl */
Simon Kelley4f7b3042012-11-28 21:27:02 +00002306 case LOPT_AUTHTTL: /* --auth-ttl */
Simon Kelley849a8352006-06-09 21:02:31 +01002307 {
2308 int ttl;
2309 if (!atoi_check(arg, &ttl))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002310 ret_err(gen_err);
Simon Kelley824af852008-02-12 20:43:05 +00002311 else if (option == LOPT_NEGTTL)
2312 daemon->neg_ttl = (unsigned long)ttl;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002313 else if (option == LOPT_MAXTTL)
2314 daemon->max_ttl = (unsigned long)ttl;
Simon Kelley1d860412012-09-20 20:48:04 +01002315 else if (option == LOPT_MAXCTTL)
2316 daemon->max_cache_ttl = (unsigned long)ttl;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002317 else if (option == LOPT_AUTHTTL)
2318 daemon->auth_ttl = (unsigned long)ttl;
Simon Kelley849a8352006-06-09 21:02:31 +01002319 else
2320 daemon->local_ttl = (unsigned long)ttl;
2321 break;
2322 }
2323
Simon Kelley7622fc02009-06-04 20:32:05 +01002324#ifdef HAVE_DHCP
Simon Kelleyf2621c72007-04-29 19:47:21 +01002325 case 'X': /* --dhcp-lease-max */
Simon Kelley849a8352006-06-09 21:02:31 +01002326 if (!atoi_check(arg, &daemon->dhcp_max))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002327 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002328 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01002329#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002330
Simon Kelley7622fc02009-06-04 20:32:05 +01002331#ifdef HAVE_TFTP
Simon Kelleyf2621c72007-04-29 19:47:21 +01002332 case LOPT_TFTP_MAX: /* --tftp-max */
Simon Kelley832af0b2007-01-21 20:01:28 +00002333 if (!atoi_check(arg, &daemon->tftp_max))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002334 ret_err(gen_err);
Simon Kelley832af0b2007-01-21 20:01:28 +00002335 break;
2336
Simon Kelley824af852008-02-12 20:43:05 +00002337 case LOPT_PREFIX: /* --tftp-prefix */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002338 comma = split(arg);
2339 if (comma)
2340 {
2341 struct tftp_prefix *new = opt_malloc(sizeof(struct tftp_prefix));
2342 new->interface = opt_string_alloc(comma);
2343 new->prefix = opt_string_alloc(arg);
2344 new->next = daemon->if_prefix;
2345 daemon->if_prefix = new;
2346 }
2347 else
2348 daemon->tftp_prefix = opt_string_alloc(arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00002349 break;
2350
Simon Kelley824af852008-02-12 20:43:05 +00002351 case LOPT_TFTPPORTS: /* --tftp-port-range */
2352 if (!(comma = split(arg)) ||
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002353 !atoi_check16(arg, &daemon->start_tftp_port) ||
2354 !atoi_check16(comma, &daemon->end_tftp_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002355 ret_err(_("bad port range"));
Simon Kelley824af852008-02-12 20:43:05 +00002356
2357 if (daemon->start_tftp_port > daemon->end_tftp_port)
2358 {
2359 int tmp = daemon->start_tftp_port;
2360 daemon->start_tftp_port = daemon->end_tftp_port;
2361 daemon->end_tftp_port = tmp;
2362 }
2363
2364 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01002365#endif
Simon Kelley824af852008-02-12 20:43:05 +00002366
Simon Kelleyf2621c72007-04-29 19:47:21 +01002367 case LOPT_BRIDGE: /* --bridge-interface */
Simon Kelley832af0b2007-01-21 20:01:28 +00002368 {
Simon Kelley824af852008-02-12 20:43:05 +00002369 struct dhcp_bridge *new = opt_malloc(sizeof(struct dhcp_bridge));
Simon Kelley316e2732010-01-22 20:16:09 +00002370 if (!(comma = split(arg)) || strlen(arg) > IF_NAMESIZE - 1 )
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002371 ret_err(_("bad bridge-interface"));
Simon Kelley832af0b2007-01-21 20:01:28 +00002372
Simon Kelley316e2732010-01-22 20:16:09 +00002373 strcpy(new->iface, arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00002374 new->alias = NULL;
2375 new->next = daemon->bridges;
2376 daemon->bridges = new;
2377
2378 do {
Simon Kelleyf2621c72007-04-29 19:47:21 +01002379 arg = comma;
2380 comma = split(arg);
Simon Kelley316e2732010-01-22 20:16:09 +00002381 if (strlen(arg) != 0 && strlen(arg) <= IF_NAMESIZE - 1)
Simon Kelley832af0b2007-01-21 20:01:28 +00002382 {
Simon Kelley824af852008-02-12 20:43:05 +00002383 struct dhcp_bridge *b = opt_malloc(sizeof(struct dhcp_bridge));
Simon Kelley832af0b2007-01-21 20:01:28 +00002384 b->next = new->alias;
2385 new->alias = b;
Simon Kelley316e2732010-01-22 20:16:09 +00002386 strcpy(b->iface, arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00002387 }
2388 } while (comma);
2389
2390 break;
2391 }
Simon Kelley832af0b2007-01-21 20:01:28 +00002392
Simon Kelley7622fc02009-06-04 20:32:05 +01002393#ifdef HAVE_DHCP
Simon Kelleyf2621c72007-04-29 19:47:21 +01002394 case 'F': /* --dhcp-range */
Simon Kelley849a8352006-06-09 21:02:31 +01002395 {
2396 int k, leasepos = 2;
Simon Kelley8445f5d2012-12-17 21:54:08 +00002397 char *cp, *a[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
Simon Kelley824af852008-02-12 20:43:05 +00002398 struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
Simon Kelley849a8352006-06-09 21:02:31 +01002399
Simon Kelley52b92f42012-01-22 16:05:15 +00002400 memset (new, 0, sizeof(*new));
Simon Kelley849a8352006-06-09 21:02:31 +01002401 new->lease_time = DEFLEASE;
Simon Kelley52b92f42012-01-22 16:05:15 +00002402
Simon Kelley849a8352006-06-09 21:02:31 +01002403 if (!arg)
2404 {
2405 option = '?';
2406 break;
2407 }
2408
2409 while(1)
2410 {
2411 for (cp = arg; *cp; cp++)
Simon Kelley52b92f42012-01-22 16:05:15 +00002412 if (!(*cp == ' ' || *cp == '.' || *cp == ':' ||
2413 (*cp >= 'a' && *cp <= 'f') || (*cp >= 'A' && *cp <= 'F') ||
2414 (*cp >='0' && *cp <= '9')))
Simon Kelley849a8352006-06-09 21:02:31 +01002415 break;
2416
Simon Kelleyf2621c72007-04-29 19:47:21 +01002417 if (*cp != ',' && (comma = split(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01002418 {
Simon Kelley8bc4cec2012-07-03 21:04:11 +01002419 if (is_tag_prefix(arg))
Simon Kelley849a8352006-06-09 21:02:31 +01002420 {
Simon Kelley824af852008-02-12 20:43:05 +00002421 struct dhcp_netid *tt = opt_malloc(sizeof (struct dhcp_netid));
2422 tt->net = opt_string_alloc(arg+4);
Simon Kelley849a8352006-06-09 21:02:31 +01002423 tt->next = new->filter;
Simon Kelley0c387192013-09-05 10:21:12 +01002424 /* ignore empty tag */
2425 if (tt->net)
2426 new->filter = tt;
Simon Kelley849a8352006-06-09 21:02:31 +01002427 }
2428 else
2429 {
2430 if (new->netid.net)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002431 ret_err(_("only one tag allowed"));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002432 else if (strstr(arg, "set:") == arg)
2433 new->netid.net = opt_string_alloc(arg+4);
Simon Kelley849a8352006-06-09 21:02:31 +01002434 else
Simon Kelley824af852008-02-12 20:43:05 +00002435 new->netid.net = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002436 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01002437 arg = comma;
Simon Kelley849a8352006-06-09 21:02:31 +01002438 }
2439 else
2440 {
2441 a[0] = arg;
2442 break;
2443 }
2444 }
2445
Simon Kelley1f776932012-12-16 19:46:08 +00002446 for (k = 1; k < 8; k++)
Simon Kelleyf2621c72007-04-29 19:47:21 +01002447 if (!(a[k] = split(a[k-1])))
2448 break;
Simon Kelley849a8352006-06-09 21:02:31 +01002449
Simon Kelley52b92f42012-01-22 16:05:15 +00002450 if (k < 2)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002451 ret_err(_("bad dhcp-range"));
2452
2453 if (inet_pton(AF_INET, a[0], &new->start))
Simon Kelley849a8352006-06-09 21:02:31 +01002454 {
Simon Kelley52b92f42012-01-22 16:05:15 +00002455 new->next = daemon->dhcp;
2456 daemon->dhcp = new;
Simon Kelley30cd9662012-03-25 20:44:38 +01002457 new->end = new->start;
Simon Kelley52b92f42012-01-22 16:05:15 +00002458 if (strcmp(a[1], "static") == 0)
Simon Kelley30cd9662012-03-25 20:44:38 +01002459 new->flags |= CONTEXT_STATIC;
Simon Kelley52b92f42012-01-22 16:05:15 +00002460 else if (strcmp(a[1], "proxy") == 0)
Simon Kelley30cd9662012-03-25 20:44:38 +01002461 new->flags |= CONTEXT_PROXY;
2462 else if (!inet_pton(AF_INET, a[1], &new->end))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002463 ret_err(_("bad dhcp-range"));
Simon Kelley52b92f42012-01-22 16:05:15 +00002464
2465 if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
2466 {
2467 struct in_addr tmp = new->start;
2468 new->start = new->end;
2469 new->end = tmp;
2470 }
2471
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002472 if (k >= 3 && strchr(a[2], '.') &&
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002473 (inet_pton(AF_INET, a[2], &new->netmask) > 0))
Simon Kelley52b92f42012-01-22 16:05:15 +00002474 {
2475 new->flags |= CONTEXT_NETMASK;
2476 leasepos = 3;
2477 if (!is_same_net(new->start, new->end, new->netmask))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002478 ret_err(_("inconsistent DHCP range"));
Simon Kelley52b92f42012-01-22 16:05:15 +00002479 }
2480
2481 if (k >= 4 && strchr(a[3], '.') &&
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002482 (inet_pton(AF_INET, a[3], &new->broadcast) > 0))
Simon Kelley52b92f42012-01-22 16:05:15 +00002483 {
2484 new->flags |= CONTEXT_BRDCAST;
2485 leasepos = 4;
2486 }
Simon Kelley849a8352006-06-09 21:02:31 +01002487 }
Simon Kelley52b92f42012-01-22 16:05:15 +00002488#ifdef HAVE_DHCP6
2489 else if (inet_pton(AF_INET6, a[0], &new->start6))
Simon Kelley7622fc02009-06-04 20:32:05 +01002490 {
Simon Kelley89500e32013-09-20 16:29:20 +01002491 new->flags |= CONTEXT_V6;
Simon Kelley52b92f42012-01-22 16:05:15 +00002492 new->prefix = 64; /* default */
Simon Kelley30cd9662012-03-25 20:44:38 +01002493 new->end6 = new->start6;
Simon Kelley6692a1a2013-08-20 14:41:31 +01002494 new->next = daemon->dhcp6;
2495 daemon->dhcp6 = new;
2496
Simon Kelley30cd9662012-03-25 20:44:38 +01002497 for (leasepos = 1; leasepos < k; leasepos++)
2498 {
2499 if (strcmp(a[leasepos], "static") == 0)
2500 new->flags |= CONTEXT_STATIC | CONTEXT_DHCP;
2501 else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 )
Simon Kelley1f776932012-12-16 19:46:08 +00002502 new->flags |= CONTEXT_RA_ONLY | CONTEXT_RA;
Simon Kelley30cd9662012-03-25 20:44:38 +01002503 else if (strcmp(a[leasepos], "ra-names") == 0)
Simon Kelley1f776932012-12-16 19:46:08 +00002504 new->flags |= CONTEXT_RA_NAME | CONTEXT_RA;
Simon Kelley30cd9662012-03-25 20:44:38 +01002505 else if (strcmp(a[leasepos], "ra-stateless") == 0)
Simon Kelley1f776932012-12-16 19:46:08 +00002506 new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA;
Simon Kelley30cd9662012-03-25 20:44:38 +01002507 else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6))
2508 new->flags |= CONTEXT_DHCP;
Simon Kelley1f776932012-12-16 19:46:08 +00002509 else if (strstr(a[leasepos], "constructor:") == a[leasepos])
2510 {
2511 new->template_interface = opt_string_alloc(a[leasepos] + 12);
2512 new->flags |= CONTEXT_TEMPLATE;
2513 }
Simon Kelley30cd9662012-03-25 20:44:38 +01002514 else
2515 break;
2516 }
Simon Kelley6692a1a2013-08-20 14:41:31 +01002517
Simon Kelley52b92f42012-01-22 16:05:15 +00002518 /* bare integer < 128 is prefix value */
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002519 if (leasepos < k)
Simon Kelley52b92f42012-01-22 16:05:15 +00002520 {
2521 int pref;
Simon Kelley30cd9662012-03-25 20:44:38 +01002522 for (cp = a[leasepos]; *cp; cp++)
Simon Kelley52b92f42012-01-22 16:05:15 +00002523 if (!(*cp >= '0' && *cp <= '9'))
2524 break;
Simon Kelley30cd9662012-03-25 20:44:38 +01002525 if (!*cp && (pref = atoi(a[leasepos])) <= 128)
Simon Kelley52b92f42012-01-22 16:05:15 +00002526 {
2527 new->prefix = pref;
Simon Kelley30cd9662012-03-25 20:44:38 +01002528 leasepos++;
Simon Kelley52b92f42012-01-22 16:05:15 +00002529 }
2530 }
Simon Kelley30cd9662012-03-25 20:44:38 +01002531
Simon Kelley6692a1a2013-08-20 14:41:31 +01002532 if (new->prefix != 64)
2533 {
2534 if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
2535 ret_err(_("prefix length must be exactly 64 for RA subnets"));
2536 else if (new->flags & CONTEXT_TEMPLATE)
2537 ret_err(_("prefix length must be exactly 64 for subnet constructors"));
2538 }
2539
2540 if (new->prefix < 64)
2541 ret_err(_("prefix length must be at least 64"));
2542
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002543 if (!is_same_net6(&new->start6, &new->end6, new->prefix))
2544 ret_err(_("inconsistent DHCPv6 range"));
Simon Kelley6692a1a2013-08-20 14:41:31 +01002545
2546 /* dhcp-range=:: enables DHCP stateless on any interface */
2547 if (IN6_IS_ADDR_UNSPECIFIED(&new->start6) && !(new->flags & CONTEXT_TEMPLATE))
2548 new->prefix = 0;
Simon Kelley66409192013-08-01 20:19:32 +01002549
2550 if (new->flags & CONTEXT_TEMPLATE)
2551 {
2552 struct in6_addr zero;
2553 memset(&zero, 0, sizeof(zero));
2554 if (!is_same_net6(&zero, &new->start6, new->prefix))
2555 ret_err(_("prefix must be zero with \"constructor:\" argument"));
2556 }
2557
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002558 if (addr6part(&new->start6) > addr6part(&new->end6))
Simon Kelley52b92f42012-01-22 16:05:15 +00002559 {
2560 struct in6_addr tmp = new->start6;
2561 new->start6 = new->end6;
2562 new->end6 = tmp;
2563 }
Simon Kelley849a8352006-06-09 21:02:31 +01002564 }
Simon Kelley52b92f42012-01-22 16:05:15 +00002565#endif
Simon Kelleyd9ee9c02013-04-12 11:17:55 +01002566 else
2567 ret_err(_("bad dhcp-range"));
Simon Kelley849a8352006-06-09 21:02:31 +01002568
Simon Kelley30cd9662012-03-25 20:44:38 +01002569 if (leasepos < k)
Simon Kelley849a8352006-06-09 21:02:31 +01002570 {
2571 if (strcmp(a[leasepos], "infinite") == 0)
2572 new->lease_time = 0xffffffff;
Simon Kelleyc8257542012-03-28 21:15:41 +01002573 else if (strcmp(a[leasepos], "deprecated") == 0)
2574 new->flags |= CONTEXT_DEPRECATE;
Simon Kelley849a8352006-06-09 21:02:31 +01002575 else
2576 {
2577 int fac = 1;
2578 if (strlen(a[leasepos]) > 0)
2579 {
2580 switch (a[leasepos][strlen(a[leasepos]) - 1])
2581 {
Simon Kelley42243212012-07-20 15:19:18 +01002582 case 'w':
2583 case 'W':
2584 fac *= 7;
2585 /* fall through */
Simon Kelley849a8352006-06-09 21:02:31 +01002586 case 'd':
2587 case 'D':
2588 fac *= 24;
2589 /* fall though */
2590 case 'h':
2591 case 'H':
2592 fac *= 60;
2593 /* fall through */
2594 case 'm':
2595 case 'M':
2596 fac *= 60;
2597 /* fall through */
2598 case 's':
2599 case 'S':
Simon Kelleyf2621c72007-04-29 19:47:21 +01002600 a[leasepos][strlen(a[leasepos]) - 1] = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002601 }
2602
Simon Kelleybe379862012-12-23 12:01:39 +00002603 for (cp = a[leasepos]; *cp; cp++)
2604 if (!(*cp >= '0' && *cp <= '9'))
2605 break;
2606
Simon Kelley54dae552013-02-05 17:55:10 +00002607 if (*cp || (leasepos+1 < k))
Simon Kelleybe379862012-12-23 12:01:39 +00002608 ret_err(_("bad dhcp-range"));
2609
Simon Kelley849a8352006-06-09 21:02:31 +01002610 new->lease_time = atoi(a[leasepos]) * fac;
2611 /* Leases of a minute or less confuse
2612 some clients, notably Apple's */
2613 if (new->lease_time < 120)
2614 new->lease_time = 120;
2615 }
2616 }
2617 }
2618 break;
2619 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01002620
Simon Kelley5aabfc72007-08-29 11:24:47 +01002621 case LOPT_BANK:
Simon Kelleyf2621c72007-04-29 19:47:21 +01002622 case 'G': /* --dhcp-host */
Simon Kelley849a8352006-06-09 21:02:31 +01002623 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01002624 int j, k = 0;
Simon Kelley3e8ed782013-05-29 14:31:33 +01002625 char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
Simon Kelley5aabfc72007-08-29 11:24:47 +01002626 struct dhcp_config *new;
Simon Kelley849a8352006-06-09 21:02:31 +01002627 struct in_addr in;
2628
Simon Kelley824af852008-02-12 20:43:05 +00002629 new = opt_malloc(sizeof(struct dhcp_config));
2630
Simon Kelley849a8352006-06-09 21:02:31 +01002631 new->next = daemon->dhcp_conf;
Simon Kelley9009d742008-11-14 20:04:27 +00002632 new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
2633 new->hwaddr = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002634 new->netid = NULL;
2635
Simon Kelley849a8352006-06-09 21:02:31 +01002636 if ((a[0] = arg))
Simon Kelley3e8ed782013-05-29 14:31:33 +01002637 for (k = 1; k < 7; k++)
Simon Kelleyf2621c72007-04-29 19:47:21 +01002638 if (!(a[k] = split(a[k-1])))
2639 break;
Simon Kelley849a8352006-06-09 21:02:31 +01002640
2641 for (j = 0; j < k; j++)
2642 if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
2643 {
2644 char *arg = a[j];
2645
2646 if ((arg[0] == 'i' || arg[0] == 'I') &&
2647 (arg[1] == 'd' || arg[1] == 'D') &&
2648 arg[2] == ':')
2649 {
2650 if (arg[3] == '*')
2651 new->flags |= CONFIG_NOCLID;
2652 else
2653 {
2654 int len;
2655 arg += 3; /* dump id: */
2656 if (strchr(arg, ':'))
2657 len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
2658 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01002659 {
2660 unhide_metas(arg);
2661 len = (int) strlen(arg);
2662 }
2663
Simon Kelley28866e92011-02-14 20:19:14 +00002664 if (len == -1)
Simon Kelley9f7f3b12012-05-28 21:39:57 +01002665
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002666 ret_err(_("bad hex constant"));
Simon Kelley28866e92011-02-14 20:19:14 +00002667 else if ((new->clid = opt_malloc(len)))
Simon Kelley5aabfc72007-08-29 11:24:47 +01002668 {
2669 new->flags |= CONFIG_CLID;
2670 new->clid_len = len;
2671 memcpy(new->clid, arg, len);
2672 }
Simon Kelley849a8352006-06-09 21:02:31 +01002673 }
2674 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002675 /* dhcp-host has strange backwards-compat needs. */
2676 else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg)
Simon Kelley849a8352006-06-09 21:02:31 +01002677 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002678 struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
2679 struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
2680 newtag->net = opt_malloc(strlen(arg + 4) + 1);
2681 newlist->next = new->netid;
2682 new->netid = newlist;
2683 newlist->list = newtag;
2684 strcpy(newtag->net, arg+4);
2685 unhide_metas(newtag->net);
Simon Kelley849a8352006-06-09 21:02:31 +01002686 }
Simon Kelley7de060b2011-08-26 17:24:52 +01002687 else if (strstr(arg, "tag:") == arg)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002688 ret_err(_("cannot match tags in --dhcp-host"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00002689#ifdef HAVE_DHCP6
2690 else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
2691 {
2692 arg[strlen(arg)-1] = 0;
2693 arg++;
2694
2695 if (!inet_pton(AF_INET6, arg, &new->addr6))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002696 ret_err(_("bad IPv6 address"));
Simon Kelley30393102013-01-17 16:34:16 +00002697
2698 for (i= 0; i < 8; i++)
2699 if (new->addr6.s6_addr[i] != 0)
2700 break;
2701
2702 /* set WILDCARD if network part all zeros */
2703 if (i == 8)
2704 new->flags |= CONFIG_WILDCARD;
Simon Kelley4cb1b322012-02-06 14:30:41 +00002705
2706 new->flags |= CONFIG_ADDR6;
2707 }
2708#endif
Simon Kelley7de060b2011-08-26 17:24:52 +01002709 else
Simon Kelley849a8352006-06-09 21:02:31 +01002710 {
Simon Kelley9009d742008-11-14 20:04:27 +00002711 struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
Simon Kelley28866e92011-02-14 20:19:14 +00002712 if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
2713 &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002714 ret_err(_("bad hex constant"));
Simon Kelley28866e92011-02-14 20:19:14 +00002715 else
2716 {
2717
2718 newhw->next = new->hwaddr;
2719 new->hwaddr = newhw;
2720 }
Simon Kelley849a8352006-06-09 21:02:31 +01002721 }
2722 }
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002723 else if (strchr(a[j], '.') && (inet_pton(AF_INET, a[j], &in) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01002724 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002725 struct dhcp_config *configs;
2726
Simon Kelley849a8352006-06-09 21:02:31 +01002727 new->addr = in;
2728 new->flags |= CONFIG_ADDR;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002729
2730 /* If the same IP appears in more than one host config, then DISCOVER
2731 for one of the hosts will get the address, but REQUEST will be NAKed,
2732 since the address is reserved by the other one -> protocol loop. */
2733 for (configs = daemon->dhcp_conf; configs; configs = configs->next)
2734 if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr)
2735 {
2736 sprintf(errstr, _("duplicate dhcp-host IP address %s"), inet_ntoa(in));
2737 return 0;
2738 }
Simon Kelley849a8352006-06-09 21:02:31 +01002739 }
2740 else
2741 {
2742 char *cp, *lastp = NULL, last = 0;
Simon Kelley76ff4402013-12-17 16:29:14 +00002743 int fac = 1, isdig = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002744
2745 if (strlen(a[j]) > 1)
2746 {
2747 lastp = a[j] + strlen(a[j]) - 1;
2748 last = *lastp;
2749 switch (last)
2750 {
Simon Kelley42243212012-07-20 15:19:18 +01002751 case 'w':
2752 case 'W':
2753 fac *= 7;
2754 /* fall through */
Simon Kelley849a8352006-06-09 21:02:31 +01002755 case 'd':
2756 case 'D':
2757 fac *= 24;
2758 /* fall through */
2759 case 'h':
2760 case 'H':
2761 fac *= 60;
2762 /* fall through */
2763 case 'm':
2764 case 'M':
2765 fac *= 60;
2766 /* fall through */
2767 case 's':
2768 case 'S':
2769 *lastp = 0;
2770 }
2771 }
2772
2773 for (cp = a[j]; *cp; cp++)
Simon Kelley76ff4402013-12-17 16:29:14 +00002774 if (isdigit((unsigned char)*cp))
2775 isdig = 1;
2776 else if (*cp != ' ')
Simon Kelley849a8352006-06-09 21:02:31 +01002777 break;
Simon Kelley76ff4402013-12-17 16:29:14 +00002778
Simon Kelley849a8352006-06-09 21:02:31 +01002779 if (*cp)
2780 {
2781 if (lastp)
2782 *lastp = last;
2783 if (strcmp(a[j], "infinite") == 0)
2784 {
2785 new->lease_time = 0xffffffff;
2786 new->flags |= CONFIG_TIME;
2787 }
2788 else if (strcmp(a[j], "ignore") == 0)
2789 new->flags |= CONFIG_DISABLE;
2790 else
2791 {
Simon Kelley1f15b812009-10-13 17:49:32 +01002792 if (!(new->hostname = canonicalise_opt(a[j])) ||
2793 !legal_hostname(new->hostname))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002794 ret_err(_("bad DHCP host name"));
2795
2796 new->flags |= CONFIG_NAME;
2797 new->domain = strip_hostname(new->hostname);
Simon Kelley849a8352006-06-09 21:02:31 +01002798 }
2799 }
Simon Kelley76ff4402013-12-17 16:29:14 +00002800 else if (isdig)
Simon Kelley849a8352006-06-09 21:02:31 +01002801 {
2802 new->lease_time = atoi(a[j]) * fac;
2803 /* Leases of a minute or less confuse
2804 some clients, notably Apple's */
2805 if (new->lease_time < 120)
2806 new->lease_time = 120;
2807 new->flags |= CONFIG_TIME;
2808 }
2809 }
2810
Simon Kelley5aabfc72007-08-29 11:24:47 +01002811 daemon->dhcp_conf = new;
Simon Kelley849a8352006-06-09 21:02:31 +01002812 break;
2813 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002814
2815 case LOPT_TAG_IF: /* --tag-if */
2816 {
2817 struct tag_if *new = opt_malloc(sizeof(struct tag_if));
2818
2819 new->tag = NULL;
2820 new->set = NULL;
2821 new->next = NULL;
2822
2823 /* preserve order */
2824 if (!daemon->tag_if)
2825 daemon->tag_if = new;
2826 else
2827 {
2828 struct tag_if *tmp;
2829 for (tmp = daemon->tag_if; tmp->next; tmp = tmp->next);
2830 tmp->next = new;
2831 }
2832
2833 while (arg)
2834 {
2835 size_t len;
2836
2837 comma = split(arg);
2838 len = strlen(arg);
2839
2840 if (len < 5)
2841 {
2842 new->set = NULL;
2843 break;
2844 }
2845 else
2846 {
2847 struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
2848 newtag->net = opt_malloc(len - 3);
2849 strcpy(newtag->net, arg+4);
2850 unhide_metas(newtag->net);
2851
2852 if (strstr(arg, "set:") == arg)
2853 {
2854 struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
2855 newlist->next = new->set;
2856 new->set = newlist;
2857 newlist->list = newtag;
2858 }
2859 else if (strstr(arg, "tag:") == arg)
2860 {
2861 newtag->next = new->tag;
2862 new->tag = newtag;
2863 }
2864 else
2865 {
2866 new->set = NULL;
Simon Kelley4dc9c652013-02-04 21:43:52 +00002867 free(newtag);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002868 break;
2869 }
2870 }
2871
2872 arg = comma;
2873 }
2874
2875 if (!new->set)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002876 ret_err(_("bad tag-if"));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002877
2878 break;
2879 }
2880
Simon Kelley849a8352006-06-09 21:02:31 +01002881
Simon Kelley73a08a22009-02-05 20:28:08 +00002882 case 'O': /* --dhcp-option */
2883 case LOPT_FORCE: /* --dhcp-option-force */
Simon Kelley824af852008-02-12 20:43:05 +00002884 case LOPT_OPTS:
Simon Kelley73a08a22009-02-05 20:28:08 +00002885 case LOPT_MATCH: /* --dhcp-match */
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002886 return parse_dhcp_opt(errstr, arg,
2887 option == LOPT_FORCE ? DHOPT_FORCE :
2888 (option == LOPT_MATCH ? DHOPT_MATCH :
2889 (option == LOPT_OPTS ? DHOPT_BANK : 0)));
2890
Simon Kelleyf2621c72007-04-29 19:47:21 +01002891 case 'M': /* --dhcp-boot */
Simon Kelley849a8352006-06-09 21:02:31 +01002892 {
2893 struct dhcp_netid *id = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002894 while (is_tag_prefix(arg))
Simon Kelley849a8352006-06-09 21:02:31 +01002895 {
Simon Kelley824af852008-02-12 20:43:05 +00002896 struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
Simon Kelley849a8352006-06-09 21:02:31 +01002897 newid->next = id;
2898 id = newid;
Simon Kelleyf2621c72007-04-29 19:47:21 +01002899 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00002900 newid->net = opt_string_alloc(arg+4);
Simon Kelley849a8352006-06-09 21:02:31 +01002901 arg = comma;
2902 };
2903
2904 if (!arg)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002905 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002906 else
2907 {
Simon Kelley7de060b2011-08-26 17:24:52 +01002908 char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +01002909 struct in_addr dhcp_next_server;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002910 struct dhcp_boot *new;
Simon Kelleyf2621c72007-04-29 19:47:21 +01002911 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00002912 dhcp_file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002913 dhcp_next_server.s_addr = 0;
2914 if (comma)
2915 {
2916 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01002917 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00002918 dhcp_sname = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002919 if (comma)
2920 {
2921 unhide_metas(comma);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002922 if (!(inet_pton(AF_INET, comma, &dhcp_next_server) > 0))
2923 {
2924 /*
2925 * The user may have specified the tftp hostname here.
2926 * save it so that it can be resolved/looked up during
2927 * actual dhcp_reply().
2928 */
2929
2930 tftp_sname = opt_string_alloc(comma);
2931 dhcp_next_server.s_addr = 0;
2932 }
Simon Kelley849a8352006-06-09 21:02:31 +01002933 }
2934 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002935
2936 new = opt_malloc(sizeof(struct dhcp_boot));
2937 new->file = dhcp_file;
2938 new->sname = dhcp_sname;
2939 new->tftp_sname = tftp_sname;
2940 new->next_server = dhcp_next_server;
2941 new->netid = id;
2942 new->next = daemon->boot_config;
2943 daemon->boot_config = new;
Simon Kelley849a8352006-06-09 21:02:31 +01002944 }
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002945
Simon Kelley849a8352006-06-09 21:02:31 +01002946 break;
2947 }
Simon Kelley7622fc02009-06-04 20:32:05 +01002948
2949 case LOPT_PXE_PROMT: /* --pxe-prompt */
2950 {
2951 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
2952 int timeout;
2953
2954 new->netid = NULL;
2955 new->opt = 10; /* PXE_MENU_PROMPT */
2956
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002957 while (is_tag_prefix(arg))
2958 {
Simon Kelley7622fc02009-06-04 20:32:05 +01002959 struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
2960 comma = split(arg);
2961 nn->next = new->netid;
2962 new->netid = nn;
2963 nn->net = opt_string_alloc(arg+4);
2964 arg = comma;
2965 }
2966
2967 if (!arg)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002968 ret_err(gen_err);
Simon Kelley7622fc02009-06-04 20:32:05 +01002969 else
2970 {
2971 comma = split(arg);
2972 unhide_metas(arg);
2973 new->len = strlen(arg) + 1;
2974 new->val = opt_malloc(new->len);
2975 memcpy(new->val + 1, arg, new->len - 1);
2976
2977 new->u.vendor_class = (unsigned char *)"PXEClient";
2978 new->flags = DHOPT_VENDOR;
2979
2980 if (comma && atoi_check(comma, &timeout))
2981 *(new->val) = timeout;
2982 else
2983 *(new->val) = 255;
2984
2985 new->next = daemon->dhcp_opts;
2986 daemon->dhcp_opts = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01002987 daemon->enable_pxe = 1;
Simon Kelley7622fc02009-06-04 20:32:05 +01002988 }
2989
2990 break;
2991 }
2992
2993 case LOPT_PXE_SERV: /* --pxe-service */
2994 {
2995 struct pxe_service *new = opt_malloc(sizeof(struct pxe_service));
2996 char *CSA[] = { "x86PC", "PC98", "IA64_EFI", "Alpha", "Arc_x86", "Intel_Lean_Client",
2997 "IA32_EFI", "BC_EFI", "Xscale_EFI", "x86-64_EFI", NULL };
2998 static int boottype = 32768;
2999
3000 new->netid = NULL;
Simon Kelley751d6f42012-02-10 15:24:51 +00003001 new->sname = NULL;
Simon Kelley7622fc02009-06-04 20:32:05 +01003002 new->server.s_addr = 0;
3003
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003004 while (is_tag_prefix(arg))
Simon Kelley7622fc02009-06-04 20:32:05 +01003005 {
3006 struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
3007 comma = split(arg);
3008 nn->next = new->netid;
3009 new->netid = nn;
3010 nn->net = opt_string_alloc(arg+4);
3011 arg = comma;
3012 }
3013
3014 if (arg && (comma = split(arg)))
3015 {
3016 for (i = 0; CSA[i]; i++)
3017 if (strcasecmp(CSA[i], arg) == 0)
3018 break;
3019
3020 if (CSA[i] || atoi_check(arg, &i))
3021 {
3022 arg = comma;
3023 comma = split(arg);
3024
3025 new->CSA = i;
3026 new->menu = opt_string_alloc(arg);
3027
Simon Kelley316e2732010-01-22 20:16:09 +00003028 if (!comma)
3029 {
3030 new->type = 0; /* local boot */
3031 new->basename = NULL;
3032 }
3033 else
Simon Kelley7622fc02009-06-04 20:32:05 +01003034 {
3035 arg = comma;
3036 comma = split(arg);
3037 if (atoi_check(arg, &i))
3038 {
3039 new->type = i;
3040 new->basename = NULL;
3041 }
3042 else
3043 {
3044 new->type = boottype++;
3045 new->basename = opt_string_alloc(arg);
3046 }
3047
Simon Kelley751d6f42012-02-10 15:24:51 +00003048 if (comma)
3049 {
3050 if (!inet_pton(AF_INET, comma, &new->server))
3051 {
3052 new->server.s_addr = 0;
3053 new->sname = opt_string_alloc(comma);
3054 }
3055
3056 }
Simon Kelley7622fc02009-06-04 20:32:05 +01003057 }
Simon Kelley751d6f42012-02-10 15:24:51 +00003058
Simon Kelley316e2732010-01-22 20:16:09 +00003059 /* Order matters */
3060 new->next = NULL;
3061 if (!daemon->pxe_services)
3062 daemon->pxe_services = new;
3063 else
3064 {
3065 struct pxe_service *s;
3066 for (s = daemon->pxe_services; s->next; s = s->next);
3067 s->next = new;
3068 }
3069
3070 daemon->enable_pxe = 1;
3071 break;
3072
Simon Kelley7622fc02009-06-04 20:32:05 +01003073 }
3074 }
3075
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003076 ret_err(gen_err);
Simon Kelley7622fc02009-06-04 20:32:05 +01003077 }
3078
Simon Kelleyf2621c72007-04-29 19:47:21 +01003079 case '4': /* --dhcp-mac */
Simon Kelley849a8352006-06-09 21:02:31 +01003080 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01003081 if (!(comma = split(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003082 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01003083 else
3084 {
Simon Kelley824af852008-02-12 20:43:05 +00003085 struct dhcp_mac *new = opt_malloc(sizeof(struct dhcp_mac));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003086 new->netid.net = opt_string_alloc(set_prefix(arg));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003087 unhide_metas(comma);
3088 new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
Simon Kelley28866e92011-02-14 20:19:14 +00003089 if (new->hwaddr_len == -1)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003090 ret_err(gen_err);
Simon Kelley28866e92011-02-14 20:19:14 +00003091 else
3092 {
3093 new->next = daemon->dhcp_macs;
3094 daemon->dhcp_macs = new;
3095 }
Simon Kelley849a8352006-06-09 21:02:31 +01003096 }
3097 }
3098 break;
Simon Kelleyc6309242013-03-07 20:59:28 +00003099
3100#ifdef OPTION6_PREFIX_CLASS
3101 case LOPT_PREF_CLSS: /* --dhcp-prefix-class */
3102 {
3103 struct prefix_class *new = opt_malloc(sizeof(struct prefix_class));
3104
3105 if (!(comma = split(arg)) ||
3106 !atoi_check16(comma, &new->class))
3107 ret_err(gen_err);
3108
3109 new->tag.net = opt_string_alloc(set_prefix(arg));
3110 new->next = daemon->prefix_classes;
3111 daemon->prefix_classes = new;
3112
3113 break;
3114 }
3115#endif
3116
3117
Simon Kelleyf2621c72007-04-29 19:47:21 +01003118 case 'U': /* --dhcp-vendorclass */
3119 case 'j': /* --dhcp-userclass */
3120 case LOPT_CIRCUIT: /* --dhcp-circuitid */
3121 case LOPT_REMOTE: /* --dhcp-remoteid */
3122 case LOPT_SUBSCR: /* --dhcp-subscrid */
Simon Kelley849a8352006-06-09 21:02:31 +01003123 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003124 unsigned char *p;
3125 int dig = 0;
3126 struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
3127
3128 if (!(comma = split(arg)))
3129 ret_err(gen_err);
3130
3131 new->netid.net = opt_string_alloc(set_prefix(arg));
3132 /* check for hex string - must digits may include : must not have nothing else,
3133 only allowed for agent-options. */
3134
3135 arg = comma;
3136 if ((comma = split(arg)))
3137 {
3138 if (option != 'U' || strstr(arg, "enterprise:") != arg)
3139 ret_err(gen_err);
3140 else
3141 new->enterprise = atoi(arg+11);
3142 }
3143 else
3144 comma = arg;
3145
3146 for (p = (unsigned char *)comma; *p; p++)
3147 if (isxdigit(*p))
3148 dig = 1;
3149 else if (*p != ':')
3150 break;
3151 unhide_metas(comma);
3152 if (option == 'U' || option == 'j' || *p || !dig)
3153 {
3154 new->len = strlen(comma);
3155 new->data = opt_malloc(new->len);
3156 memcpy(new->data, comma, new->len);
3157 }
3158 else
3159 {
3160 new->len = parse_hex(comma, (unsigned char *)comma, strlen(comma), NULL, NULL);
3161 new->data = opt_malloc(new->len);
3162 memcpy(new->data, comma, new->len);
3163 }
3164
3165 switch (option)
3166 {
3167 case 'j':
3168 new->match_type = MATCH_USER;
3169 break;
3170 case 'U':
3171 new->match_type = MATCH_VENDOR;
3172 break;
3173 case LOPT_CIRCUIT:
3174 new->match_type = MATCH_CIRCUIT;
3175 break;
3176 case LOPT_REMOTE:
3177 new->match_type = MATCH_REMOTE;
3178 break;
3179 case LOPT_SUBSCR:
3180 new->match_type = MATCH_SUBSCRIBER;
3181 break;
3182 }
3183 new->next = daemon->dhcp_vendors;
3184 daemon->dhcp_vendors = new;
Simon Kelleya5c72ab2012-02-10 13:42:47 +00003185
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003186 break;
Simon Kelley849a8352006-06-09 21:02:31 +01003187 }
3188
Simon Kelley9e038942008-05-30 20:06:34 +01003189 case LOPT_ALTPORT: /* --dhcp-alternate-port */
3190 if (!arg)
3191 {
3192 daemon->dhcp_server_port = DHCP_SERVER_ALTPORT;
3193 daemon->dhcp_client_port = DHCP_CLIENT_ALTPORT;
3194 }
3195 else
3196 {
3197 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01003198 if (!atoi_check16(arg, &daemon->dhcp_server_port) ||
3199 (comma && !atoi_check16(comma, &daemon->dhcp_client_port)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003200 ret_err(_("invalid port number"));
Simon Kelley9e038942008-05-30 20:06:34 +01003201 if (!comma)
3202 daemon->dhcp_client_port = daemon->dhcp_server_port+1;
3203 }
3204 break;
3205
Simon Kelley824af852008-02-12 20:43:05 +00003206 case 'J': /* --dhcp-ignore */
3207 case LOPT_NO_NAMES: /* --dhcp-ignore-names */
3208 case LOPT_BROADCAST: /* --dhcp-broadcast */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003209 case '3': /* --bootp-dynamic */
3210 case LOPT_GEN_NAMES: /* --dhcp-generate-names */
Simon Kelley849a8352006-06-09 21:02:31 +01003211 {
Simon Kelley824af852008-02-12 20:43:05 +00003212 struct dhcp_netid_list *new = opt_malloc(sizeof(struct dhcp_netid_list));
Simon Kelley849a8352006-06-09 21:02:31 +01003213 struct dhcp_netid *list = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00003214 if (option == 'J')
3215 {
3216 new->next = daemon->dhcp_ignore;
3217 daemon->dhcp_ignore = new;
3218 }
Simon Kelley824af852008-02-12 20:43:05 +00003219 else if (option == LOPT_BROADCAST)
3220 {
3221 new->next = daemon->force_broadcast;
3222 daemon->force_broadcast = new;
3223 }
Simon Kelley9009d742008-11-14 20:04:27 +00003224 else if (option == '3')
3225 {
3226 new->next = daemon->bootp_dynamic;
3227 daemon->bootp_dynamic = new;
3228 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003229 else if (option == LOPT_GEN_NAMES)
3230 {
3231 new->next = daemon->dhcp_gen_names;
3232 daemon->dhcp_gen_names = new;
3233 }
Simon Kelley832af0b2007-01-21 20:01:28 +00003234 else
3235 {
3236 new->next = daemon->dhcp_ignore_names;
3237 daemon->dhcp_ignore_names = new;
3238 }
3239
3240 while (arg) {
Simon Kelley824af852008-02-12 20:43:05 +00003241 struct dhcp_netid *member = opt_malloc(sizeof(struct dhcp_netid));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003242 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003243 member->next = list;
3244 list = member;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003245 if (is_tag_prefix(arg))
Simon Kelley9009d742008-11-14 20:04:27 +00003246 member->net = opt_string_alloc(arg+4);
3247 else
3248 member->net = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003249 arg = comma;
Simon Kelley832af0b2007-01-21 20:01:28 +00003250 }
Simon Kelley849a8352006-06-09 21:02:31 +01003251
3252 new->list = list;
3253 break;
3254 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003255
3256 case LOPT_PROXY: /* --dhcp-proxy */
3257 daemon->override = 1;
3258 while (arg) {
3259 struct addr_list *new = opt_malloc(sizeof(struct addr_list));
3260 comma = split(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003261 if (!(inet_pton(AF_INET, arg, &new->addr) > 0))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003262 ret_err(_("bad dhcp-proxy address"));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003263 new->next = daemon->override_relays;
3264 daemon->override_relays = new;
3265 arg = comma;
3266 }
3267 break;
Simon Kelleyff7eea22013-09-04 18:01:38 +01003268
3269 case LOPT_RELAY: /* --dhcp-relay */
3270 {
3271 struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
3272 comma = split(arg);
3273 new->interface = opt_string_alloc(split(comma));
3274 new->iface_index = 0;
3275 if (inet_pton(AF_INET, arg, &new->local) && inet_pton(AF_INET, comma, &new->server))
3276 {
3277 new->next = daemon->relay4;
3278 daemon->relay4 = new;
3279 }
3280#ifdef HAVE_DHCP6
3281 else if (inet_pton(AF_INET6, arg, &new->local) && inet_pton(AF_INET6, comma, &new->server))
3282 {
3283 new->next = daemon->relay6;
3284 daemon->relay6 = new;
3285 }
3286#endif
3287 else
3288 ret_err(_("Bad dhcp-relay"));
3289
3290 break;
3291 }
3292
Simon Kelley7622fc02009-06-04 20:32:05 +01003293#endif
Simon Kelley849a8352006-06-09 21:02:31 +01003294
Simon Kelley8b372702012-03-09 17:45:10 +00003295#ifdef HAVE_DHCP6
Simon Kelleyc4cd95d2013-10-10 20:58:11 +01003296 case LOPT_RA_PARAM: /* --ra-param */
3297 if ((comma = split(arg)))
3298 {
3299 struct ra_interface *new = opt_malloc(sizeof(struct ra_interface));
3300 new->lifetime = -1;
3301 new->prio = 0;
3302 new->name = opt_string_alloc(arg);
3303 if (strcasestr(comma, "high") == comma || strcasestr(comma, "low") == comma)
3304 {
3305 if (*comma == 'l' || *comma == 'L')
3306 new->prio = 0x18;
3307 else
3308 new->prio = 0x08;
3309 comma = split(comma);
3310 }
3311 arg = split(comma);
3312 if (!atoi_check(comma, &new->interval) ||
3313 (arg && !atoi_check(arg, &new->lifetime)))
3314 ret_err(_("bad RA-params"));
3315
3316 new->next = daemon->ra_interfaces;
3317 daemon->ra_interfaces = new;
3318 }
3319 break;
3320
Simon Kelley8b372702012-03-09 17:45:10 +00003321 case LOPT_DUID: /* --dhcp-duid */
3322 if (!(comma = split(arg)) || !atoi_check(arg, (int *)&daemon->duid_enterprise))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003323 ret_err(_("bad DUID"));
Simon Kelley8b372702012-03-09 17:45:10 +00003324 else
3325 {
3326 daemon->duid_config_len = parse_hex(comma,(unsigned char *)comma, strlen(comma), NULL, NULL);
3327 daemon->duid_config = opt_malloc(daemon->duid_config_len);
3328 memcpy(daemon->duid_config, comma, daemon->duid_config_len);
3329 }
3330 break;
3331#endif
3332
Simon Kelleyf2621c72007-04-29 19:47:21 +01003333 case 'V': /* --alias */
Simon Kelley849a8352006-06-09 21:02:31 +01003334 {
Simon Kelley73a08a22009-02-05 20:28:08 +00003335 char *dash, *a[3] = { NULL, NULL, NULL };
Simon Kelleyf2621c72007-04-29 19:47:21 +01003336 int k = 0;
Simon Kelley73a08a22009-02-05 20:28:08 +00003337 struct doctor *new = opt_malloc(sizeof(struct doctor));
3338 new->next = daemon->doctors;
3339 daemon->doctors = new;
3340 new->mask.s_addr = 0xffffffff;
3341 new->end.s_addr = 0;
3342
Simon Kelley849a8352006-06-09 21:02:31 +01003343 if ((a[0] = arg))
3344 for (k = 1; k < 3; k++)
3345 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01003346 if (!(a[k] = split(a[k-1])))
Simon Kelley849a8352006-06-09 21:02:31 +01003347 break;
Simon Kelley849a8352006-06-09 21:02:31 +01003348 unhide_metas(a[k]);
3349 }
Simon Kelley849a8352006-06-09 21:02:31 +01003350
Simon Kelley73a08a22009-02-05 20:28:08 +00003351 dash = split_chr(a[0], '-');
3352
Simon Kelley849a8352006-06-09 21:02:31 +01003353 if ((k < 2) ||
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003354 (!(inet_pton(AF_INET, a[0], &new->in) > 0)) ||
3355 (!(inet_pton(AF_INET, a[1], &new->out) > 0)))
Simon Kelley73a08a22009-02-05 20:28:08 +00003356 option = '?';
Simon Kelley849a8352006-06-09 21:02:31 +01003357
3358 if (k == 3)
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003359 inet_pton(AF_INET, a[2], &new->mask);
Simon Kelley849a8352006-06-09 21:02:31 +01003360
Simon Kelley73a08a22009-02-05 20:28:08 +00003361 if (dash &&
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003362 (!(inet_pton(AF_INET, dash, &new->end) > 0) ||
Simon Kelley73a08a22009-02-05 20:28:08 +00003363 !is_same_net(new->in, new->end, new->mask) ||
3364 ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003365 ret_err(_("invalid alias range"));
Simon Kelley849a8352006-06-09 21:02:31 +01003366
3367 break;
3368 }
3369
Simon Kelleyf2621c72007-04-29 19:47:21 +01003370 case LOPT_INTNAME: /* --interface-name */
3371 {
3372 struct interface_name *new, **up;
Simon Kelley1f15b812009-10-13 17:49:32 +01003373 char *domain = NULL;
3374
Simon Kelleyf2621c72007-04-29 19:47:21 +01003375 comma = split(arg);
3376
Simon Kelley1f15b812009-10-13 17:49:32 +01003377 if (!comma || !(domain = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003378 ret_err(_("bad interface name"));
Simon Kelley1f15b812009-10-13 17:49:32 +01003379
Simon Kelley824af852008-02-12 20:43:05 +00003380 new = opt_malloc(sizeof(struct interface_name));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003381 new->next = NULL;
Simon Kelley376d48c2013-11-13 13:04:30 +00003382 new->addr = NULL;
3383
Simon Kelleyf2621c72007-04-29 19:47:21 +01003384 /* Add to the end of the list, so that first name
3385 of an interface is used for PTR lookups. */
Simon Kelley824af852008-02-12 20:43:05 +00003386 for (up = &daemon->int_names; *up; up = &((*up)->next));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003387 *up = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003388 new->name = domain;
Simon Kelleyf7029f52013-11-21 15:09:09 +00003389 new->family = 0;
3390 arg = split_chr(comma, '/');
3391 if (arg)
3392 {
3393 if (strcmp(arg, "4") == 0)
3394 new->family = AF_INET;
3395#ifdef HAVE_IPV6
3396 else if (strcmp(arg, "6") == 0)
3397 new->family = AF_INET6;
3398#endif
3399 else
3400 ret_err(gen_err);
3401 }
Simon Kelley824af852008-02-12 20:43:05 +00003402 new->intr = opt_string_alloc(comma);
Simon Kelleyf2621c72007-04-29 19:47:21 +01003403 break;
3404 }
Simon Kelley9009d742008-11-14 20:04:27 +00003405
3406 case LOPT_CNAME: /* --cname */
3407 {
3408 struct cname *new;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003409 char *alias;
3410 char *target;
3411
Simon Kelley9009d742008-11-14 20:04:27 +00003412 if (!(comma = split(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003413 ret_err(gen_err);
3414
3415 alias = canonicalise_opt(arg);
3416 target = canonicalise_opt(comma);
3417
3418 if (!alias || !target)
3419 ret_err(_("bad CNAME"));
Simon Kelley9009d742008-11-14 20:04:27 +00003420 else
3421 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003422 for (new = daemon->cnames; new; new = new->next)
3423 if (hostname_isequal(new->alias, arg))
3424 ret_err(_("duplicate CNAME"));
3425 new = opt_malloc(sizeof(struct cname));
3426 new->next = daemon->cnames;
3427 daemon->cnames = new;
3428 new->alias = alias;
3429 new->target = target;
Simon Kelley9009d742008-11-14 20:04:27 +00003430 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003431
Simon Kelley9009d742008-11-14 20:04:27 +00003432 break;
3433 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01003434
3435 case LOPT_PTR: /* --ptr-record */
Simon Kelley832af0b2007-01-21 20:01:28 +00003436 {
3437 struct ptr_record *new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003438 char *dom, *target = NULL;
3439
Simon Kelleyf2621c72007-04-29 19:47:21 +01003440 comma = split(arg);
3441
Simon Kelley1f15b812009-10-13 17:49:32 +01003442 if (!(dom = canonicalise_opt(arg)) ||
3443 (comma && !(target = canonicalise_opt(comma))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003444 ret_err(_("bad PTR record"));
Simon Kelley1f15b812009-10-13 17:49:32 +01003445 else
3446 {
3447 new = opt_malloc(sizeof(struct ptr_record));
3448 new->next = daemon->ptr;
3449 daemon->ptr = new;
3450 new->name = dom;
3451 new->ptr = target;
3452 }
Simon Kelley832af0b2007-01-21 20:01:28 +00003453 break;
3454 }
3455
Simon Kelley1a6bca82008-07-11 11:11:42 +01003456 case LOPT_NAPTR: /* --naptr-record */
3457 {
3458 char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
3459 int k = 0;
3460 struct naptr *new;
3461 int order, pref;
Simon Kelley1f15b812009-10-13 17:49:32 +01003462 char *name, *replace = NULL;
Simon Kelley1a6bca82008-07-11 11:11:42 +01003463
3464 if ((a[0] = arg))
3465 for (k = 1; k < 7; k++)
3466 if (!(a[k] = split(a[k-1])))
3467 break;
3468
3469
3470 if (k < 6 ||
Simon Kelley1f15b812009-10-13 17:49:32 +01003471 !(name = canonicalise_opt(a[0])) ||
Simon Kelley1ad24ae2008-07-20 20:22:50 +01003472 !atoi_check16(a[1], &order) ||
3473 !atoi_check16(a[2], &pref) ||
Simon Kelley1f15b812009-10-13 17:49:32 +01003474 (k == 7 && !(replace = canonicalise_opt(a[6]))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003475 ret_err(_("bad NAPTR record"));
Simon Kelley1a6bca82008-07-11 11:11:42 +01003476 else
3477 {
3478 new = opt_malloc(sizeof(struct naptr));
3479 new->next = daemon->naptr;
3480 daemon->naptr = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003481 new->name = name;
Simon Kelley1a6bca82008-07-11 11:11:42 +01003482 new->flags = opt_string_alloc(a[3]);
3483 new->services = opt_string_alloc(a[4]);
3484 new->regexp = opt_string_alloc(a[5]);
Simon Kelley1f15b812009-10-13 17:49:32 +01003485 new->replace = replace;
Simon Kelley1a6bca82008-07-11 11:11:42 +01003486 new->order = order;
3487 new->pref = pref;
3488 }
3489 break;
3490 }
Simon Kelley9f7f3b12012-05-28 21:39:57 +01003491
3492 case LOPT_RR: /* dns-rr */
3493 {
3494 struct txt_record *new;
Vladislav Grishenkod082faf2013-11-26 11:04:24 +00003495 size_t len = len;
Simon Kelley9f7f3b12012-05-28 21:39:57 +01003496 char *data;
3497 int val;
3498
3499 comma = split(arg);
3500 data = split(comma);
3501
3502 new = opt_malloc(sizeof(struct txt_record));
3503 new->next = daemon->rr;
3504 daemon->rr = new;
3505
3506 if (!atoi_check(comma, &val) ||
3507 !(new->name = canonicalise_opt(arg)) ||
Simon Kelley51931b82012-05-29 17:06:02 +01003508 (data && (len = parse_hex(data, (unsigned char *)data, -1, NULL, NULL)) == -1U))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003509 ret_err(_("bad RR record"));
3510
Simon Kelley9f7f3b12012-05-28 21:39:57 +01003511 new->class = val;
3512 new->len = 0;
3513
3514 if (data)
3515 {
3516 new->txt=opt_malloc(len);
3517 new->len = len;
3518 memcpy(new->txt, data, len);
3519 }
3520
3521 break;
3522 }
3523
Simon Kelleyf2621c72007-04-29 19:47:21 +01003524 case 'Y': /* --txt-record */
Simon Kelley849a8352006-06-09 21:02:31 +01003525 {
3526 struct txt_record *new;
Simon Kelley28866e92011-02-14 20:19:14 +00003527 unsigned char *p, *cnt;
3528 size_t len;
3529
3530 comma = split(arg);
3531
Simon Kelley824af852008-02-12 20:43:05 +00003532 new = opt_malloc(sizeof(struct txt_record));
Simon Kelley849a8352006-06-09 21:02:31 +01003533 new->next = daemon->txt;
3534 daemon->txt = new;
3535 new->class = C_IN;
Simon Kelley849a8352006-06-09 21:02:31 +01003536
Simon Kelley1f15b812009-10-13 17:49:32 +01003537 if (!(new->name = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003538 ret_err(_("bad TXT record"));
3539
Simon Kelley28866e92011-02-14 20:19:14 +00003540 len = comma ? strlen(comma) : 0;
3541 len += (len/255) + 1; /* room for extra counts */
3542 new->txt = p = opt_malloc(len);
3543
3544 cnt = p++;
3545 *cnt = 0;
3546
3547 while (comma && *comma)
3548 {
3549 unsigned char c = (unsigned char)*comma++;
3550
3551 if (c == ',' || *cnt == 255)
3552 {
3553 if (c != ',')
3554 comma--;
3555 cnt = p++;
3556 *cnt = 0;
3557 }
3558 else
3559 {
3560 *p++ = unhide_meta(c);
3561 (*cnt)++;
3562 }
3563 }
3564
3565 new->len = p - new->txt;
3566
Simon Kelley849a8352006-06-09 21:02:31 +01003567 break;
3568 }
3569
Simon Kelleyf2621c72007-04-29 19:47:21 +01003570 case 'W': /* --srv-host */
Simon Kelley849a8352006-06-09 21:02:31 +01003571 {
3572 int port = 1, priority = 0, weight = 0;
3573 char *name, *target = NULL;
3574 struct mx_srv_record *new;
3575
Simon Kelleyf2621c72007-04-29 19:47:21 +01003576 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003577
Simon Kelley1f15b812009-10-13 17:49:32 +01003578 if (!(name = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003579 ret_err(_("bad SRV record"));
3580
Simon Kelley849a8352006-06-09 21:02:31 +01003581 if (comma)
3582 {
3583 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003584 comma = split(arg);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003585 if (!(target = canonicalise_opt(arg)))
3586 ret_err(_("bad SRV target"));
Simon Kelley824af852008-02-12 20:43:05 +00003587
Simon Kelley849a8352006-06-09 21:02:31 +01003588 if (comma)
3589 {
3590 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003591 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01003592 if (!atoi_check16(arg, &port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003593 ret_err(_("invalid port number"));
Simon Kelley824af852008-02-12 20:43:05 +00003594
Simon Kelley849a8352006-06-09 21:02:31 +01003595 if (comma)
3596 {
3597 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003598 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01003599 if (!atoi_check16(arg, &priority))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003600 ret_err(_("invalid priority"));
Simon Kelley824af852008-02-12 20:43:05 +00003601
Simon Kelley849a8352006-06-09 21:02:31 +01003602 if (comma)
3603 {
3604 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003605 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01003606 if (!atoi_check16(arg, &weight))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003607 ret_err(_("invalid weight"));
Simon Kelley849a8352006-06-09 21:02:31 +01003608 }
3609 }
3610 }
3611 }
3612
Simon Kelley824af852008-02-12 20:43:05 +00003613 new = opt_malloc(sizeof(struct mx_srv_record));
Simon Kelley849a8352006-06-09 21:02:31 +01003614 new->next = daemon->mxnames;
3615 daemon->mxnames = new;
3616 new->issrv = 1;
3617 new->name = name;
3618 new->target = target;
3619 new->srvport = port;
3620 new->priority = priority;
3621 new->weight = weight;
3622 break;
3623 }
Simon Kelley7622fc02009-06-04 20:32:05 +01003624
Simon Kelleye759d422012-03-16 13:18:57 +00003625 case LOPT_HOST_REC: /* --host-record */
3626 {
3627 struct host_record *new = opt_malloc(sizeof(struct host_record));
3628 memset(new, 0, sizeof(struct host_record));
3629
3630 if (!arg || !(comma = split(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003631 ret_err(_("Bad host-record"));
3632
3633 while (arg)
3634 {
3635 struct all_addr addr;
3636 if (inet_pton(AF_INET, arg, &addr))
3637 new->addr = addr.addr.addr4;
Simon Kelleye759d422012-03-16 13:18:57 +00003638#ifdef HAVE_IPV6
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003639 else if (inet_pton(AF_INET6, arg, &addr))
3640 new->addr6 = addr.addr.addr6;
Simon Kelleye759d422012-03-16 13:18:57 +00003641#endif
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003642 else
3643 {
3644 int nomem;
3645 char *canon = canonicalise(arg, &nomem);
3646 struct name_list *nl = opt_malloc(sizeof(struct name_list));
3647 if (!canon)
3648 ret_err(_("Bad name in host-record"));
3649
3650 nl->name = canon;
3651 /* keep order, so that PTR record goes to first name */
3652 nl->next = NULL;
3653 if (!new->names)
3654 new->names = nl;
3655 else
3656 {
3657 struct name_list *tmp;
3658 for (tmp = new->names; tmp->next; tmp = tmp->next);
3659 tmp->next = nl;
3660 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003661 }
Simon Kelleye4807d82012-09-27 21:52:26 +01003662
3663 arg = comma;
3664 comma = split(arg);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003665 }
Simon Kelleye759d422012-03-16 13:18:57 +00003666
3667 /* Keep list order */
3668 if (!daemon->host_records_tail)
3669 daemon->host_records = new;
3670 else
3671 daemon->host_records_tail->next = new;
3672 new->next = NULL;
3673 daemon->host_records_tail = new;
3674 break;
3675 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00003676
3677#ifdef HAVE_DNSSEC
3678 case LOPT_DNSKEY:
3679 {
3680 struct dnskey *new = opt_malloc(sizeof(struct dnskey));
3681 char *key64, *algo;
3682
3683 if (!(comma = split(arg)) || !(algo = split(comma)) || !(key64 = split(algo)) ||
3684 !atoi_check16(comma, &new->flags) || !atoi_check16(algo, &new->algo) ||
3685 !(new->name = canonicalise_opt(arg)))
3686 ret_err(_("bad DNSKEY"));
3687
3688
3689 /* Upper bound on length */
3690 new->key = opt_malloc((3*strlen(key64)/4));
3691 unhide_metas(key64);
3692 if ((new->keylen = parse_base64(key64, new->key)) == -1)
3693 ret_err(_("bad base64 in DNSKEY"));
3694
3695 new->next = daemon->dnskeys;
3696 daemon->dnskeys = new;
3697
3698 break;
3699 }
3700#endif
3701
Simon Kelley7622fc02009-06-04 20:32:05 +01003702 default:
Simon Kelley0fc2f312014-01-08 10:26:58 +00003703 ret_err(_("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"));
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003704
Simon Kelley849a8352006-06-09 21:02:31 +01003705 }
Simon Kelley824af852008-02-12 20:43:05 +00003706
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003707 return 1;
Simon Kelley849a8352006-06-09 21:02:31 +01003708}
3709
Simon Kelley28866e92011-02-14 20:19:14 +00003710static void read_file(char *file, FILE *f, int hard_opt)
Simon Kelley849a8352006-06-09 21:02:31 +01003711{
Simon Kelley824af852008-02-12 20:43:05 +00003712 volatile int lineno = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003713 char *buff = daemon->namebuff;
Simon Kelley849a8352006-06-09 21:02:31 +01003714
3715 while (fgets(buff, MAXDNAME, f))
3716 {
Simon Kelley611ebc52012-07-16 16:23:46 +01003717 int white, i, option = hard_opt;
3718 char *errmess, *p, *arg = NULL, *start;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003719 size_t len;
Simon Kelley832af0b2007-01-21 20:01:28 +00003720
Simon Kelley824af852008-02-12 20:43:05 +00003721 /* Memory allocation failure longjmps here if mem_recover == 1 */
Simon Kelley611ebc52012-07-16 16:23:46 +01003722 if (option != 0)
Simon Kelley824af852008-02-12 20:43:05 +00003723 {
3724 if (setjmp(mem_jmp))
3725 continue;
3726 mem_recover = 1;
3727 }
3728
Simon Kelley849a8352006-06-09 21:02:31 +01003729 lineno++;
Simon Kelley824af852008-02-12 20:43:05 +00003730 errmess = NULL;
3731
Simon Kelley849a8352006-06-09 21:02:31 +01003732 /* Implement quotes, inside quotes we allow \\ \" \n and \t
3733 metacharacters get hidden also strip comments */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003734 for (white = 1, p = buff; *p; p++)
Simon Kelley849a8352006-06-09 21:02:31 +01003735 {
3736 if (*p == '"')
3737 {
3738 memmove(p, p+1, strlen(p+1)+1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003739
Simon Kelley849a8352006-06-09 21:02:31 +01003740 for(; *p && *p != '"'; p++)
3741 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01003742 if (*p == '\\' && strchr("\"tnebr\\", p[1]))
Simon Kelley849a8352006-06-09 21:02:31 +01003743 {
3744 if (p[1] == 't')
3745 p[1] = '\t';
3746 else if (p[1] == 'n')
3747 p[1] = '\n';
Simon Kelley849a8352006-06-09 21:02:31 +01003748 else if (p[1] == 'b')
3749 p[1] = '\b';
3750 else if (p[1] == 'r')
3751 p[1] = '\r';
Simon Kelley6b010842007-02-12 20:32:07 +00003752 else if (p[1] == 'e') /* escape */
3753 p[1] = '\033';
Simon Kelley849a8352006-06-09 21:02:31 +01003754 memmove(p, p+1, strlen(p+1)+1);
3755 }
3756 *p = hide_meta(*p);
3757 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003758
3759 if (*p == 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +01003760 {
3761 errmess = _("missing \"");
3762 goto oops;
3763 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003764
3765 memmove(p, p+1, strlen(p+1)+1);
Simon Kelley849a8352006-06-09 21:02:31 +01003766 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01003767
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003768 if (isspace(*p))
3769 {
3770 *p = ' ';
3771 white = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01003772 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003773 else
3774 {
3775 if (white && *p == '#')
3776 {
3777 *p = 0;
3778 break;
3779 }
3780 white = 0;
3781 }
Simon Kelley849a8352006-06-09 21:02:31 +01003782 }
3783
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003784
3785 /* strip leading spaces */
3786 for (start = buff; *start && *start == ' '; start++);
3787
3788 /* strip trailing spaces */
3789 for (len = strlen(start); (len != 0) && (start[len-1] == ' '); len--);
3790
3791 if (len == 0)
Simon Kelley849a8352006-06-09 21:02:31 +01003792 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003793 else
3794 start[len] = 0;
3795
Simon Kelley611ebc52012-07-16 16:23:46 +01003796 if (option != 0)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003797 arg = start;
3798 else if ((p=strchr(start, '=')))
Simon Kelley849a8352006-06-09 21:02:31 +01003799 {
3800 /* allow spaces around "=" */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003801 for (arg = p+1; *arg == ' '; arg++);
3802 for (; p >= start && (*p == ' ' || *p == '='); p--)
Simon Kelley849a8352006-06-09 21:02:31 +01003803 *p = 0;
3804 }
3805 else
3806 arg = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00003807
Simon Kelley611ebc52012-07-16 16:23:46 +01003808 if (option == 0)
Simon Kelley5aabfc72007-08-29 11:24:47 +01003809 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01003810 for (option = 0, i = 0; opts[i].name; i++)
3811 if (strcmp(opts[i].name, start) == 0)
3812 {
3813 option = opts[i].val;
3814 break;
3815 }
3816
3817 if (!option)
3818 errmess = _("bad option");
3819 else if (opts[i].has_arg == 0 && arg)
3820 errmess = _("extraneous parameter");
3821 else if (opts[i].has_arg == 1 && !arg)
3822 errmess = _("missing parameter");
3823 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003824
3825 oops:
Simon Kelley832af0b2007-01-21 20:01:28 +00003826 if (errmess)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003827 strcpy(daemon->namebuff, errmess);
3828
3829 if (errmess || !one_opt(option, arg, buff, _("error"), 0))
Simon Kelleyf2621c72007-04-29 19:47:21 +01003830 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003831 sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file);
Simon Kelley824af852008-02-12 20:43:05 +00003832 if (hard_opt != 0)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003833 my_syslog(LOG_ERR, "%s", daemon->namebuff);
Simon Kelley5aabfc72007-08-29 11:24:47 +01003834 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003835 die("%s", daemon->namebuff, EC_BADCONF);
Simon Kelleyf2621c72007-04-29 19:47:21 +01003836 }
Simon Kelley849a8352006-06-09 21:02:31 +01003837 }
3838
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003839 mem_recover = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01003840 fclose(f);
3841}
3842
Simon Kelley395eb712012-07-06 22:07:05 +01003843static int one_file(char *file, int hard_opt)
Simon Kelley28866e92011-02-14 20:19:14 +00003844{
3845 FILE *f;
3846 int nofile_ok = 0;
3847 static int read_stdin = 0;
3848 static struct fileread {
3849 dev_t dev;
3850 ino_t ino;
3851 struct fileread *next;
3852 } *filesread = NULL;
3853
3854 if (hard_opt == '7')
3855 {
3856 /* default conf-file reading */
3857 hard_opt = 0;
3858 nofile_ok = 1;
3859 }
3860
3861 if (hard_opt == 0 && strcmp(file, "-") == 0)
3862 {
3863 if (read_stdin == 1)
Simon Kelley395eb712012-07-06 22:07:05 +01003864 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00003865 read_stdin = 1;
3866 file = "stdin";
3867 f = stdin;
3868 }
3869 else
3870 {
3871 /* ignore repeated files. */
3872 struct stat statbuf;
3873
3874 if (hard_opt == 0 && stat(file, &statbuf) == 0)
3875 {
3876 struct fileread *r;
3877
3878 for (r = filesread; r; r = r->next)
3879 if (r->dev == statbuf.st_dev && r->ino == statbuf.st_ino)
Simon Kelley395eb712012-07-06 22:07:05 +01003880 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00003881
3882 r = safe_malloc(sizeof(struct fileread));
3883 r->next = filesread;
3884 filesread = r;
3885 r->dev = statbuf.st_dev;
3886 r->ino = statbuf.st_ino;
3887 }
3888
3889 if (!(f = fopen(file, "r")))
3890 {
3891 if (errno == ENOENT && nofile_ok)
Simon Kelley395eb712012-07-06 22:07:05 +01003892 return 1; /* No conffile, all done. */
Simon Kelley28866e92011-02-14 20:19:14 +00003893 else
3894 {
3895 char *str = _("cannot read %s: %s");
3896 if (hard_opt != 0)
3897 {
3898 my_syslog(LOG_ERR, str, file, strerror(errno));
Simon Kelley395eb712012-07-06 22:07:05 +01003899 return 0;
Simon Kelley28866e92011-02-14 20:19:14 +00003900 }
3901 else
3902 die(str, file, EC_FILE);
3903 }
3904 }
3905 }
3906
3907 read_file(file, f, hard_opt);
Simon Kelley395eb712012-07-06 22:07:05 +01003908 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00003909}
3910
3911/* expand any name which is a directory */
3912struct hostsfile *expand_filelist(struct hostsfile *list)
3913{
3914 int i;
3915 struct hostsfile *ah;
3916
3917 for (i = 0, ah = list; ah; ah = ah->next)
3918 {
3919 if (i <= ah->index)
3920 i = ah->index + 1;
3921
3922 if (ah->flags & AH_DIR)
3923 ah->flags |= AH_INACTIVE;
3924 else
3925 ah->flags &= ~AH_INACTIVE;
3926 }
3927
3928 for (ah = list; ah; ah = ah->next)
3929 if (!(ah->flags & AH_INACTIVE))
3930 {
3931 struct stat buf;
3932 if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode))
3933 {
3934 DIR *dir_stream;
3935 struct dirent *ent;
3936
3937 /* don't read this as a file */
3938 ah->flags |= AH_INACTIVE;
3939
3940 if (!(dir_stream = opendir(ah->fname)))
3941 my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
3942 ah->fname, strerror(errno));
3943 else
3944 {
3945 while ((ent = readdir(dir_stream)))
3946 {
3947 size_t lendir = strlen(ah->fname);
3948 size_t lenfile = strlen(ent->d_name);
3949 struct hostsfile *ah1;
3950 char *path;
3951
3952 /* ignore emacs backups and dotfiles */
3953 if (lenfile == 0 ||
3954 ent->d_name[lenfile - 1] == '~' ||
3955 (ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
3956 ent->d_name[0] == '.')
3957 continue;
3958
3959 /* see if we have an existing record.
3960 dir is ah->fname
3961 file is ent->d_name
3962 path to match is ah1->fname */
3963
3964 for (ah1 = list; ah1; ah1 = ah1->next)
3965 {
3966 if (lendir < strlen(ah1->fname) &&
3967 strstr(ah1->fname, ah->fname) == ah1->fname &&
3968 ah1->fname[lendir] == '/' &&
3969 strcmp(ah1->fname + lendir + 1, ent->d_name) == 0)
3970 {
3971 ah1->flags &= ~AH_INACTIVE;
3972 break;
3973 }
3974 }
3975
3976 /* make new record */
3977 if (!ah1)
3978 {
3979 if (!(ah1 = whine_malloc(sizeof(struct hostsfile))))
3980 continue;
3981
3982 if (!(path = whine_malloc(lendir + lenfile + 2)))
3983 {
3984 free(ah1);
3985 continue;
3986 }
3987
3988 strcpy(path, ah->fname);
3989 strcat(path, "/");
3990 strcat(path, ent->d_name);
3991 ah1->fname = path;
3992 ah1->index = i++;
3993 ah1->flags = AH_DIR;
3994 ah1->next = list;
3995 list = ah1;
3996 }
3997
3998 /* inactivate record if not regular file */
3999 if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode))
4000 ah1->flags |= AH_INACTIVE;
4001
4002 }
4003 closedir(dir_stream);
4004 }
4005 }
4006 }
4007
4008 return list;
4009}
4010
4011
Simon Kelley7622fc02009-06-04 20:32:05 +01004012#ifdef HAVE_DHCP
Simon Kelley824af852008-02-12 20:43:05 +00004013void reread_dhcp(void)
4014{
Simon Kelley28866e92011-02-14 20:19:14 +00004015 struct hostsfile *hf;
4016
Simon Kelley824af852008-02-12 20:43:05 +00004017 if (daemon->dhcp_hosts_file)
4018 {
4019 struct dhcp_config *configs, *cp, **up;
Simon Kelley28866e92011-02-14 20:19:14 +00004020
Simon Kelley824af852008-02-12 20:43:05 +00004021 /* remove existing... */
4022 for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
4023 {
4024 cp = configs->next;
4025
4026 if (configs->flags & CONFIG_BANK)
4027 {
Simon Kelley9009d742008-11-14 20:04:27 +00004028 struct hwaddr_config *mac, *tmp;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004029 struct dhcp_netid_list *list, *tmplist;
Simon Kelley9009d742008-11-14 20:04:27 +00004030
4031 for (mac = configs->hwaddr; mac; mac = tmp)
4032 {
4033 tmp = mac->next;
4034 free(mac);
4035 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004036
Simon Kelley824af852008-02-12 20:43:05 +00004037 if (configs->flags & CONFIG_CLID)
4038 free(configs->clid);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004039
4040 for (list = configs->netid; list; list = tmplist)
4041 {
4042 free(list->list);
4043 tmplist = list->next;
4044 free(list);
4045 }
4046
Simon Kelley824af852008-02-12 20:43:05 +00004047 if (configs->flags & CONFIG_NAME)
4048 free(configs->hostname);
4049
4050 *up = configs->next;
4051 free(configs);
4052 }
4053 else
4054 up = &configs->next;
4055 }
4056
Simon Kelley28866e92011-02-14 20:19:14 +00004057 daemon->dhcp_hosts_file = expand_filelist(daemon->dhcp_hosts_file);
4058 for (hf = daemon->dhcp_hosts_file; hf; hf = hf->next)
4059 if (!(hf->flags & AH_INACTIVE))
4060 {
Simon Kelley395eb712012-07-06 22:07:05 +01004061 if (one_file(hf->fname, LOPT_BANK))
4062 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
Simon Kelley28866e92011-02-14 20:19:14 +00004063 }
Simon Kelley824af852008-02-12 20:43:05 +00004064 }
4065
4066 if (daemon->dhcp_opts_file)
4067 {
4068 struct dhcp_opt *opts, *cp, **up;
4069 struct dhcp_netid *id, *next;
4070
4071 for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
4072 {
4073 cp = opts->next;
4074
4075 if (opts->flags & DHOPT_BANK)
4076 {
Simon Kelley73a08a22009-02-05 20:28:08 +00004077 if ((opts->flags & DHOPT_VENDOR))
4078 free(opts->u.vendor_class);
Simon Kelley824af852008-02-12 20:43:05 +00004079 free(opts->val);
4080 for (id = opts->netid; id; id = next)
4081 {
4082 next = id->next;
4083 free(id->net);
4084 free(id);
4085 }
4086 *up = opts->next;
4087 free(opts);
4088 }
4089 else
4090 up = &opts->next;
4091 }
4092
Simon Kelley28866e92011-02-14 20:19:14 +00004093 daemon->dhcp_opts_file = expand_filelist(daemon->dhcp_opts_file);
4094 for (hf = daemon->dhcp_opts_file; hf; hf = hf->next)
4095 if (!(hf->flags & AH_INACTIVE))
4096 {
Simon Kelley395eb712012-07-06 22:07:05 +01004097 if (one_file(hf->fname, LOPT_OPTS))
4098 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
Simon Kelley28866e92011-02-14 20:19:14 +00004099 }
Simon Kelley824af852008-02-12 20:43:05 +00004100 }
4101}
Simon Kelley7622fc02009-06-04 20:32:05 +01004102#endif
Simon Kelley824af852008-02-12 20:43:05 +00004103
Simon Kelley5aabfc72007-08-29 11:24:47 +01004104void read_opts(int argc, char **argv, char *compile_opts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004105{
Simon Kelley824af852008-02-12 20:43:05 +00004106 char *buff = opt_malloc(MAXDNAME);
Simon Kelley28866e92011-02-14 20:19:14 +00004107 int option, conffile_opt = '7', testmode = 0;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004108 char *arg, *conffile = CONFFILE;
Simon Kelley849a8352006-06-09 21:02:31 +01004109
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004110 opterr = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +01004111
Simon Kelley824af852008-02-12 20:43:05 +00004112 daemon = opt_malloc(sizeof(struct daemon));
Simon Kelley3be34542004-09-11 19:12:13 +01004113 memset(daemon, 0, sizeof(struct daemon));
4114 daemon->namebuff = buff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004115
Simon Kelley3be34542004-09-11 19:12:13 +01004116 /* Set defaults - everything else is zero or NULL */
Simon Kelley3be34542004-09-11 19:12:13 +01004117 daemon->cachesize = CACHESIZ;
Simon Kelley208b65c2006-08-05 21:41:37 +01004118 daemon->ftabsize = FTABSIZ;
Simon Kelley3be34542004-09-11 19:12:13 +01004119 daemon->port = NAMESERVER_PORT;
Simon Kelley9e038942008-05-30 20:06:34 +01004120 daemon->dhcp_client_port = DHCP_CLIENT_PORT;
4121 daemon->dhcp_server_port = DHCP_SERVER_PORT;
Simon Kelley3be34542004-09-11 19:12:13 +01004122 daemon->default_resolv.is_default = 1;
4123 daemon->default_resolv.name = RESOLVFILE;
4124 daemon->resolv_files = &daemon->default_resolv;
4125 daemon->username = CHUSER;
Simon Kelley3be34542004-09-11 19:12:13 +01004126 daemon->runfile = RUNFILE;
4127 daemon->dhcp_max = MAXLEASES;
Simon Kelley832af0b2007-01-21 20:01:28 +00004128 daemon->tftp_max = TFTP_MAX_CONNECTIONS;
Simon Kelley3be34542004-09-11 19:12:13 +01004129 daemon->edns_pktsz = EDNS_PKTSZ;
Simon Kelley849a8352006-06-09 21:02:31 +01004130 daemon->log_fac = -1;
Simon Kelley4f7b3042012-11-28 21:27:02 +00004131 daemon->auth_ttl = AUTH_TTL;
4132 daemon->soa_refresh = SOA_REFRESH;
4133 daemon->soa_retry = SOA_RETRY;
4134 daemon->soa_expiry = SOA_EXPIRY;
Simon Kelley5aabfc72007-08-29 11:24:47 +01004135 add_txt("version.bind", "dnsmasq-" VERSION );
4136 add_txt("authors.bind", "Simon Kelley");
4137 add_txt("copyright.bind", COPYRIGHT);
Simon Kelley0a852542005-03-23 20:28:59 +00004138
Simon Kelley849a8352006-06-09 21:02:31 +01004139 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004140 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004141#ifdef HAVE_GETOPT_LONG
Simon Kelley849a8352006-06-09 21:02:31 +01004142 option = getopt_long(argc, argv, OPTSTRING, opts, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004143#else
Simon Kelley849a8352006-06-09 21:02:31 +01004144 option = getopt(argc, argv, OPTSTRING);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004145#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004146
4147 if (option == -1)
Simon Kelley28866e92011-02-14 20:19:14 +00004148 {
Simon Kelley572b41e2011-02-18 18:11:18 +00004149 for (; optind < argc; optind++)
4150 {
4151 unsigned char *c = (unsigned char *)argv[optind];
4152 for (; *c != 0; c++)
4153 if (!isspace(*c))
4154 die(_("junk found in command line"), NULL, EC_BADCONF);
4155 }
Simon Kelley28866e92011-02-14 20:19:14 +00004156 break;
4157 }
4158
Simon Kelley849a8352006-06-09 21:02:31 +01004159 /* Copy optarg so that argv doesn't get changed */
4160 if (optarg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004161 {
Simon Kelley849a8352006-06-09 21:02:31 +01004162 strncpy(buff, optarg, MAXDNAME);
4163 buff[MAXDNAME-1] = 0;
4164 arg = buff;
4165 }
4166 else
4167 arg = NULL;
4168
4169 /* command-line only stuff */
Simon Kelley7622fc02009-06-04 20:32:05 +01004170 if (option == LOPT_TEST)
4171 testmode = 1;
4172 else if (option == 'w')
Simon Kelley849a8352006-06-09 21:02:31 +01004173 {
Simon Kelley7622fc02009-06-04 20:32:05 +01004174#ifdef HAVE_DHCP
Simon Kelley4cb1b322012-02-06 14:30:41 +00004175 if (argc == 3 && strcmp(argv[2], "dhcp") == 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01004176 display_opts();
Simon Kelley4cb1b322012-02-06 14:30:41 +00004177#ifdef HAVE_DHCP6
4178 else if (argc == 3 && strcmp(argv[2], "dhcp6") == 0)
4179 display_opts6();
Simon Kelley7622fc02009-06-04 20:32:05 +01004180#endif
Simon Kelley4cb1b322012-02-06 14:30:41 +00004181 else
4182#endif
4183 do_usage();
4184
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004185 exit(0);
4186 }
Simon Kelley849a8352006-06-09 21:02:31 +01004187 else if (option == 'v')
4188 {
4189 printf(_("Dnsmasq version %s %s\n"), VERSION, COPYRIGHT);
Simon Kelleyc72daea2012-01-05 21:33:27 +00004190 printf(_("Compile time options: %s\n\n"), compile_opts);
Simon Kelleyb8187c82005-11-26 21:46:27 +00004191 printf(_("This software comes with ABSOLUTELY NO WARRANTY.\n"));
4192 printf(_("Dnsmasq is free software, and you are welcome to redistribute it\n"));
Simon Kelley824af852008-02-12 20:43:05 +00004193 printf(_("under the terms of the GNU General Public License, version 2 or 3.\n"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004194 exit(0);
4195 }
Simon Kelley849a8352006-06-09 21:02:31 +01004196 else if (option == 'C')
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004197 {
Simon Kelley28866e92011-02-14 20:19:14 +00004198 conffile_opt = 0; /* file must exist */
Simon Kelley824af852008-02-12 20:43:05 +00004199 conffile = opt_string_alloc(arg);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004200 }
Simon Kelley849a8352006-06-09 21:02:31 +01004201 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004202 {
Simon Kelley26128d22004-11-14 16:43:54 +00004203#ifdef HAVE_GETOPT_LONG
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004204 if (!one_opt(option, arg, daemon->namebuff, _("try --help"), 1))
Simon Kelley849a8352006-06-09 21:02:31 +01004205#else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004206 if (!one_opt(option, arg, daemon->namebuff, _("try -w"), 1))
Simon Kelley849a8352006-06-09 21:02:31 +01004207#endif
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004208 die(_("bad command line options: %s"), daemon->namebuff, EC_BADCONF);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004209 }
4210 }
Simon Kelley849a8352006-06-09 21:02:31 +01004211
4212 if (conffile)
Simon Kelley28866e92011-02-14 20:19:14 +00004213 one_file(conffile, conffile_opt);
Simon Kelley849a8352006-06-09 21:02:31 +01004214
Simon Kelley1a6bca82008-07-11 11:11:42 +01004215 /* port might not be known when the address is parsed - fill in here */
Simon Kelley3be34542004-09-11 19:12:13 +01004216 if (daemon->servers)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004217 {
4218 struct server *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +01004219 for (tmp = daemon->servers; tmp; tmp = tmp->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004220 if (!(tmp->flags & SERV_HAS_SOURCE))
4221 {
4222 if (tmp->source_addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +01004223 tmp->source_addr.in.sin_port = htons(daemon->query_port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004224#ifdef HAVE_IPV6
4225 else if (tmp->source_addr.sa.sa_family == AF_INET6)
Simon Kelley3be34542004-09-11 19:12:13 +01004226 tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
Simon Kelley5aabfc72007-08-29 11:24:47 +01004227#endif
4228 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004229 }
4230
Simon Kelley3be34542004-09-11 19:12:13 +01004231 if (daemon->if_addrs)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004232 {
4233 struct iname *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +01004234 for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004235 if (tmp->addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +01004236 tmp->addr.in.sin_port = htons(daemon->port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004237#ifdef HAVE_IPV6
4238 else if (tmp->addr.sa.sa_family == AF_INET6)
Simon Kelley3be34542004-09-11 19:12:13 +01004239 tmp->addr.in6.sin6_port = htons(daemon->port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004240#endif /* IPv6 */
4241 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00004242
4243 /* create default, if not specified */
4244 if (daemon->authserver && !daemon->hostmaster)
4245 {
4246 strcpy(buff, "hostmaster.");
4247 strcat(buff, daemon->authserver);
4248 daemon->hostmaster = opt_string_alloc(buff);
4249 }
4250
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004251 /* only one of these need be specified: the other defaults to the host-name */
Simon Kelley28866e92011-02-14 20:19:14 +00004252 if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004253 {
Simon Kelley0a852542005-03-23 20:28:59 +00004254 struct mx_srv_record *mx;
4255
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004256 if (gethostname(buff, MAXDNAME) == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004257 die(_("cannot get host-name: %s"), NULL, EC_MISC);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004258
Simon Kelley0a852542005-03-23 20:28:59 +00004259 for (mx = daemon->mxnames; mx; mx = mx->next)
4260 if (!mx->issrv && hostname_isequal(mx->name, buff))
4261 break;
4262
Simon Kelley28866e92011-02-14 20:19:14 +00004263 if ((daemon->mxtarget || option_bool(OPT_LOCALMX)) && !mx)
Simon Kelleyde379512004-06-22 20:23:33 +01004264 {
Simon Kelley824af852008-02-12 20:43:05 +00004265 mx = opt_malloc(sizeof(struct mx_srv_record));
Simon Kelley91dccd02005-03-31 17:48:32 +01004266 mx->next = daemon->mxnames;
4267 mx->issrv = 0;
4268 mx->target = NULL;
Simon Kelley824af852008-02-12 20:43:05 +00004269 mx->name = opt_string_alloc(buff);
Simon Kelley91dccd02005-03-31 17:48:32 +01004270 daemon->mxnames = mx;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004271 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004272
Simon Kelley3be34542004-09-11 19:12:13 +01004273 if (!daemon->mxtarget)
Simon Kelley824af852008-02-12 20:43:05 +00004274 daemon->mxtarget = opt_string_alloc(buff);
Simon Kelley0a852542005-03-23 20:28:59 +00004275
4276 for (mx = daemon->mxnames; mx; mx = mx->next)
4277 if (!mx->issrv && !mx->target)
4278 mx->target = daemon->mxtarget;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004279 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004280
Simon Kelley28866e92011-02-14 20:19:14 +00004281 if (!option_bool(OPT_NO_RESOLV) &&
Simon Kelley208b65c2006-08-05 21:41:37 +01004282 daemon->resolv_files &&
4283 daemon->resolv_files->next &&
Simon Kelley28866e92011-02-14 20:19:14 +00004284 option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +01004285 die(_("only one resolv.conf file allowed in no-poll mode."), NULL, EC_BADCONF);
Simon Kelleyde379512004-06-22 20:23:33 +01004286
Simon Kelley28866e92011-02-14 20:19:14 +00004287 if (option_bool(OPT_RESOLV_DOMAIN))
Simon Kelleyde379512004-06-22 20:23:33 +01004288 {
4289 char *line;
Simon Kelley849a8352006-06-09 21:02:31 +01004290 FILE *f;
4291
Simon Kelley28866e92011-02-14 20:19:14 +00004292 if (option_bool(OPT_NO_RESOLV) ||
Simon Kelley208b65c2006-08-05 21:41:37 +01004293 !daemon->resolv_files ||
4294 (daemon->resolv_files)->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004295 die(_("must have exactly one resolv.conf to read domain from."), NULL, EC_BADCONF);
Simon Kelleyde379512004-06-22 20:23:33 +01004296
Simon Kelley3be34542004-09-11 19:12:13 +01004297 if (!(f = fopen((daemon->resolv_files)->name, "r")))
Simon Kelley5aabfc72007-08-29 11:24:47 +01004298 die(_("failed to read %s: %s"), (daemon->resolv_files)->name, EC_FILE);
Simon Kelleyde379512004-06-22 20:23:33 +01004299
4300 while ((line = fgets(buff, MAXDNAME, f)))
4301 {
4302 char *token = strtok(line, " \t\n\r");
4303
4304 if (!token || strcmp(token, "search") != 0)
4305 continue;
4306
4307 if ((token = strtok(NULL, " \t\n\r")) &&
Simon Kelley1f15b812009-10-13 17:49:32 +01004308 (daemon->domain_suffix = canonicalise_opt(token)))
Simon Kelleyde379512004-06-22 20:23:33 +01004309 break;
4310 }
Simon Kelley3be34542004-09-11 19:12:13 +01004311
Simon Kelleyde379512004-06-22 20:23:33 +01004312 fclose(f);
Simon Kelley8a911cc2004-03-16 18:35:52 +00004313
Simon Kelley3be34542004-09-11 19:12:13 +01004314 if (!daemon->domain_suffix)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004315 die(_("no search directive found in %s"), (daemon->resolv_files)->name, EC_MISC);
Simon Kelleyde379512004-06-22 20:23:33 +01004316 }
Simon Kelley3d8df262005-08-29 12:19:27 +01004317
4318 if (daemon->domain_suffix)
4319 {
4320 /* add domain for any srv record without one. */
4321 struct mx_srv_record *srv;
Simon Kelleyde379512004-06-22 20:23:33 +01004322
Simon Kelley3d8df262005-08-29 12:19:27 +01004323 for (srv = daemon->mxnames; srv; srv = srv->next)
4324 if (srv->issrv &&
4325 strchr(srv->name, '.') &&
4326 strchr(srv->name, '.') == strrchr(srv->name, '.'))
4327 {
4328 strcpy(buff, srv->name);
4329 strcat(buff, ".");
4330 strcat(buff, daemon->domain_suffix);
4331 free(srv->name);
Simon Kelley824af852008-02-12 20:43:05 +00004332 srv->name = opt_string_alloc(buff);
Simon Kelley3d8df262005-08-29 12:19:27 +01004333 }
4334 }
Simon Kelley28866e92011-02-14 20:19:14 +00004335 else if (option_bool(OPT_DHCP_FQDN))
Simon Kelley9009d742008-11-14 20:04:27 +00004336 die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
Simon Kelley7622fc02009-06-04 20:32:05 +01004337
4338 if (testmode)
4339 {
4340 fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
4341 exit(0);
4342 }
Simon Kelley849a8352006-06-09 21:02:31 +01004343}