blob: 9f1b84f81152b3723085e228b17b8f68646d9d3a [file] [log] [blame]
Simon Kelleyd1ced3a2018-01-01 22:18:03 +00001/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
Simon Kelley849a8352006-06-09 21:02:31 +010017/* define this to get facilitynames */
18#define SYSLOG_NAMES
Simon Kelley9e4abcb2004-01-22 19:47:41 +000019#include "dnsmasq.h"
Simon Kelley824af852008-02-12 20:43:05 +000020#include <setjmp.h>
21
Simon Kelley7622fc02009-06-04 20:32:05 +010022static volatile int mem_recover = 0;
23static jmp_buf mem_jmp;
Simon Kelley395eb712012-07-06 22:07:05 +010024static int one_file(char *file, int hard_opt);
Simon Kelley7622fc02009-06-04 20:32:05 +010025
Simon Kelley824af852008-02-12 20:43:05 +000026/* Solaris headers don't have facility names. */
27#ifdef HAVE_SOLARIS_NETWORK
28static const struct {
29 char *c_name;
30 unsigned int c_val;
31} facilitynames[] = {
32 { "kern", LOG_KERN },
33 { "user", LOG_USER },
34 { "mail", LOG_MAIL },
35 { "daemon", LOG_DAEMON },
36 { "auth", LOG_AUTH },
37 { "syslog", LOG_SYSLOG },
38 { "lpr", LOG_LPR },
39 { "news", LOG_NEWS },
40 { "uucp", LOG_UUCP },
Simon Kelley824af852008-02-12 20:43:05 +000041 { "audit", LOG_AUDIT },
Simon Kelley824af852008-02-12 20:43:05 +000042 { "cron", LOG_CRON },
43 { "local0", LOG_LOCAL0 },
44 { "local1", LOG_LOCAL1 },
45 { "local2", LOG_LOCAL2 },
46 { "local3", LOG_LOCAL3 },
47 { "local4", LOG_LOCAL4 },
48 { "local5", LOG_LOCAL5 },
49 { "local6", LOG_LOCAL6 },
50 { "local7", LOG_LOCAL7 },
51 { NULL, 0 }
52};
53#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +000054
Simon Kelley849a8352006-06-09 21:02:31 +010055#ifndef HAVE_GETOPT_LONG
Simon Kelley9e4abcb2004-01-22 19:47:41 +000056struct myoption {
57 const char *name;
58 int has_arg;
59 int *flag;
60 int val;
61};
Simon Kelley849a8352006-06-09 21:02:31 +010062#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +000063
Simon Kelley9009d742008-11-14 20:04:27 +000064#define OPTSTRING "951yZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:W:Y:2:4:6:7:8:0:3:"
Simon Kelley9e4abcb2004-01-22 19:47:41 +000065
Simon Kelley16972692006-10-16 20:04:18 +010066/* options which don't have a one-char version */
Simon Kelleye98bd522014-03-28 20:41:23 +000067#define LOPT_RELOAD 256
68#define LOPT_NO_NAMES 257
69#define LOPT_TFTP 258
70#define LOPT_SECURE 259
71#define LOPT_PREFIX 260
72#define LOPT_PTR 261
73#define LOPT_BRIDGE 262
74#define LOPT_TFTP_MAX 263
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
Simon Kelleye98bd522014-03-28 20:41:23 +0000133#define LOPT_PREF_CLSS 321
Simon Kelleyc6309242013-03-07 20:59:28 +0000134#endif
Simon Kelleye98bd522014-03-28 20:41:23 +0000135#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
141#define LOPT_SEC_VALID 329
142#define LOPT_TRUST_ANCHOR 330
143#define LOPT_DNSSEC_DEBUG 331
144#define LOPT_REV_SERV 332
145#define LOPT_SERVERS_FILE 333
146#define LOPT_DNSSEC_CHECK 334
Simon Kelleyc8a80482014-03-05 14:29:54 +0000147#define LOPT_LOCAL_SERVICE 335
Simon Kelleye98bd522014-03-28 20:41:23 +0000148#define LOPT_DNSSEC_TIME 336
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +0100149#define LOPT_LOOP_DETECT 337
Glen Huang32fc6db2014-12-27 15:28:12 +0000150#define LOPT_IGNORE_ADDR 338
RinSatsuki28de3872015-01-10 15:22:21 +0000151#define LOPT_MINCTTL 339
Simon Kelley5f4dc5c2015-01-20 20:51:02 +0000152#define LOPT_DHCP_INOTIFY 340
Simon Kelley70d18732015-01-31 19:59:29 +0000153#define LOPT_DHOPT_INOTIFY 341
154#define LOPT_HOST_INOTIFY 342
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000155#define LOPT_DNSSEC_STAMP 343
Stefan Tomanek30d08792015-03-31 22:32:11 +0100156#define LOPT_TFTP_NO_FAIL 344
Hans Dedecker926332a2016-01-23 10:48:12 +0000157#define LOPT_MAXPORT 345
Simon Kelley1e505122016-01-25 21:29:23 +0000158#define LOPT_CPE_ID 346
159#define LOPT_SCRIPT_ARP 347
Simon Kelley832e47b2016-02-24 21:24:45 +0000160#define LOPT_DHCPTTL 348
Simon Kelleybec366b2016-02-24 22:03:26 +0000161#define LOPT_TFTP_MTU 349
Floris Bos503c6092017-04-09 23:07:13 +0100162#define LOPT_REPLY_DELAY 350
Simon Kelley734d5312018-03-23 23:09:53 +0000163#define LOPT_RAPID_COMMIT 351
Simon Kelley6b173352018-05-08 18:32:14 +0100164#define LOPT_DUMPFILE 352
165#define LOPT_DUMPMASK 353
Julian Kornberger8dcdb332018-07-21 22:11:08 +0100166#define LOPT_UBUS 354
Simon Kelleybec366b2016-02-24 22:03:26 +0000167
Simon Kelley849a8352006-06-09 21:02:31 +0100168#ifdef HAVE_GETOPT_LONG
169static const struct option opts[] =
170#else
171static const struct myoption opts[] =
172#endif
173 {
Simon Kelley7622fc02009-06-04 20:32:05 +0100174 { "version", 0, 0, 'v' },
175 { "no-hosts", 0, 0, 'h' },
176 { "no-poll", 0, 0, 'n' },
177 { "help", 0, 0, 'w' },
178 { "no-daemon", 0, 0, 'd' },
Simon Kelley25cf5e32015-01-09 15:53:03 +0000179 { "log-queries", 2, 0, 'q' },
Simon Kelley7622fc02009-06-04 20:32:05 +0100180 { "user", 2, 0, 'u' },
181 { "group", 2, 0, 'g' },
182 { "resolv-file", 2, 0, 'r' },
Simon Kelley7b1eae42014-02-20 13:43:28 +0000183 { "servers-file", 1, 0, LOPT_SERVERS_FILE },
Simon Kelley7622fc02009-06-04 20:32:05 +0100184 { "mx-host", 1, 0, 'm' },
185 { "mx-target", 1, 0, 't' },
186 { "cache-size", 2, 0, 'c' },
187 { "port", 1, 0, 'p' },
188 { "dhcp-leasefile", 2, 0, 'l' },
189 { "dhcp-lease", 1, 0, 'l' },
190 { "dhcp-host", 1, 0, 'G' },
191 { "dhcp-range", 1, 0, 'F' },
192 { "dhcp-option", 1, 0, 'O' },
193 { "dhcp-boot", 1, 0, 'M' },
194 { "domain", 1, 0, 's' },
195 { "domain-suffix", 1, 0, 's' },
196 { "interface", 1, 0, 'i' },
197 { "listen-address", 1, 0, 'a' },
Simon Kelleyc8a80482014-03-05 14:29:54 +0000198 { "local-service", 0, 0, LOPT_LOCAL_SERVICE },
Simon Kelley7622fc02009-06-04 20:32:05 +0100199 { "bogus-priv", 0, 0, 'b' },
200 { "bogus-nxdomain", 1, 0, 'B' },
Glen Huang32fc6db2014-12-27 15:28:12 +0000201 { "ignore-address", 1, 0, LOPT_IGNORE_ADDR },
Simon Kelley7622fc02009-06-04 20:32:05 +0100202 { "selfmx", 0, 0, 'e' },
203 { "filterwin2k", 0, 0, 'f' },
204 { "pid-file", 2, 0, 'x' },
205 { "strict-order", 0, 0, 'o' },
206 { "server", 1, 0, 'S' },
Simon Kelleyde73a492014-02-17 21:43:27 +0000207 { "rev-server", 1, 0, LOPT_REV_SERV },
Simon Kelley7622fc02009-06-04 20:32:05 +0100208 { "local", 1, 0, LOPT_LOCAL },
209 { "address", 1, 0, 'A' },
210 { "conf-file", 2, 0, 'C' },
211 { "no-resolv", 0, 0, 'R' },
212 { "expand-hosts", 0, 0, 'E' },
213 { "localmx", 0, 0, 'L' },
214 { "local-ttl", 1, 0, 'T' },
215 { "no-negcache", 0, 0, 'N' },
216 { "addn-hosts", 1, 0, 'H' },
Simon Kelley70d18732015-01-31 19:59:29 +0000217 { "hostsdir", 1, 0, LOPT_HOST_INOTIFY },
Simon Kelley7622fc02009-06-04 20:32:05 +0100218 { "query-port", 1, 0, 'Q' },
219 { "except-interface", 1, 0, 'I' },
220 { "no-dhcp-interface", 1, 0, '2' },
221 { "domain-needed", 0, 0, 'D' },
222 { "dhcp-lease-max", 1, 0, 'X' },
223 { "bind-interfaces", 0, 0, 'z' },
224 { "read-ethers", 0, 0, 'Z' },
225 { "alias", 1, 0, 'V' },
226 { "dhcp-vendorclass", 1, 0, 'U' },
227 { "dhcp-userclass", 1, 0, 'j' },
228 { "dhcp-ignore", 1, 0, 'J' },
229 { "edns-packet-max", 1, 0, 'P' },
230 { "keep-in-foreground", 0, 0, 'k' },
231 { "dhcp-authoritative", 0, 0, 'K' },
232 { "srv-host", 1, 0, 'W' },
233 { "localise-queries", 0, 0, 'y' },
234 { "txt-record", 1, 0, 'Y' },
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100235 { "dns-rr", 1, 0, LOPT_RR },
Simon Kelleyad094272012-08-10 17:10:54 +0100236 { "enable-dbus", 2, 0, '1' },
Julian Kornberger8dcdb332018-07-21 22:11:08 +0100237 { "enable-ubus", 0, 0, LOPT_UBUS },
Simon Kelley7622fc02009-06-04 20:32:05 +0100238 { "bootp-dynamic", 2, 0, '3' },
239 { "dhcp-mac", 1, 0, '4' },
240 { "no-ping", 0, 0, '5' },
241 { "dhcp-script", 1, 0, '6' },
242 { "conf-dir", 1, 0, '7' },
243 { "log-facility", 1, 0 ,'8' },
244 { "leasefile-ro", 0, 0, '9' },
245 { "dns-forward-max", 1, 0, '0' },
246 { "clear-on-reload", 0, 0, LOPT_RELOAD },
247 { "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
Simon Kelley2937f8a2013-07-29 19:49:07 +0100248 { "enable-tftp", 2, 0, LOPT_TFTP },
Simon Kelley7622fc02009-06-04 20:32:05 +0100249 { "tftp-secure", 0, 0, LOPT_SECURE },
Stefan Tomanek30d08792015-03-31 22:32:11 +0100250 { "tftp-no-fail", 0, 0, LOPT_TFTP_NO_FAIL },
Floris Bos60704f52017-04-09 22:22:49 +0100251 { "tftp-unique-root", 2, 0, LOPT_APREF },
Simon Kelley7622fc02009-06-04 20:32:05 +0100252 { "tftp-root", 1, 0, LOPT_PREFIX },
253 { "tftp-max", 1, 0, LOPT_TFTP_MAX },
Simon Kelleybec366b2016-02-24 22:03:26 +0000254 { "tftp-mtu", 1, 0, LOPT_TFTP_MTU },
Simon Kelley61ce6002012-04-20 21:28:49 +0100255 { "tftp-lowercase", 0, 0, LOPT_TFTP_LC },
Simon Kelley7622fc02009-06-04 20:32:05 +0100256 { "ptr-record", 1, 0, LOPT_PTR },
257 { "naptr-record", 1, 0, LOPT_NAPTR },
258 { "bridge-interface", 1, 0 , LOPT_BRIDGE },
259 { "dhcp-option-force", 1, 0, LOPT_FORCE },
260 { "tftp-no-blocksize", 0, 0, LOPT_NOBLOCK },
261 { "log-dhcp", 0, 0, LOPT_LOG_OPTS },
262 { "log-async", 2, 0, LOPT_MAX_LOGS },
263 { "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
264 { "dhcp-remoteid", 1, 0, LOPT_REMOTE },
265 { "dhcp-subscrid", 1, 0, LOPT_SUBSCR },
266 { "interface-name", 1, 0, LOPT_INTNAME },
267 { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
268 { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
Simon Kelley5f4dc5c2015-01-20 20:51:02 +0000269 { "dhcp-hostsdir", 1, 0, LOPT_DHCP_INOTIFY },
Simon Kelley70d18732015-01-31 19:59:29 +0000270 { "dhcp-optsdir", 1, 0, LOPT_DHOPT_INOTIFY },
Simon Kelley7622fc02009-06-04 20:32:05 +0100271 { "dhcp-no-override", 0, 0, LOPT_OVERRIDE },
272 { "tftp-port-range", 1, 0, LOPT_TFTPPORTS },
273 { "stop-dns-rebind", 0, 0, LOPT_REBIND },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100274 { "rebind-domain-ok", 1, 0, LOPT_NO_REBIND },
Simon Kelley7622fc02009-06-04 20:32:05 +0100275 { "all-servers", 0, 0, LOPT_NOLAST },
276 { "dhcp-match", 1, 0, LOPT_MATCH },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100277 { "dhcp-broadcast", 2, 0, LOPT_BROADCAST },
Simon Kelley7622fc02009-06-04 20:32:05 +0100278 { "neg-ttl", 1, 0, LOPT_NEGTTL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100279 { "max-ttl", 1, 0, LOPT_MAXTTL },
RinSatsuki28de3872015-01-10 15:22:21 +0000280 { "min-cache-ttl", 1, 0, LOPT_MINCTTL },
Simon Kelley1d860412012-09-20 20:48:04 +0100281 { "max-cache-ttl", 1, 0, LOPT_MAXCTTL },
Simon Kelley7622fc02009-06-04 20:32:05 +0100282 { "dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
283 { "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
284 { "min-port", 1, 0, LOPT_MINPORT },
Hans Dedecker926332a2016-01-23 10:48:12 +0000285 { "max-port", 1, 0, LOPT_MAXPORT },
Simon Kelley7622fc02009-06-04 20:32:05 +0100286 { "dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN },
287 { "cname", 1, 0, LOPT_CNAME },
288 { "pxe-prompt", 1, 0, LOPT_PXE_PROMT },
289 { "pxe-service", 1, 0, LOPT_PXE_SERV },
290 { "test", 0, 0, LOPT_TEST },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100291 { "tag-if", 1, 0, LOPT_TAG_IF },
292 { "dhcp-proxy", 2, 0, LOPT_PROXY },
293 { "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES },
294 { "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
Simon Kelley1e505122016-01-25 21:29:23 +0000295 { "add-mac", 2, 0, LOPT_ADD_MAC },
Simon Kelleyed4c0762013-10-08 20:46:34 +0100296 { "add-subnet", 2, 0, LOPT_ADD_SBNET },
Simon Kelley1e505122016-01-25 21:29:23 +0000297 { "add-cpe-id", 1, 0 , LOPT_CPE_ID },
Simon Kelley28866e92011-02-14 20:19:14 +0000298 { "proxy-dnssec", 0, 0, LOPT_DNSSEC },
Simon Kelley7de060b2011-08-26 17:24:52 +0100299 { "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR },
300 { "conntrack", 0, 0, LOPT_CONNTRACK },
Simon Kelleyc72daea2012-01-05 21:33:27 +0000301 { "dhcp-client-update", 0, 0, LOPT_FQDN },
302 { "dhcp-luascript", 1, 0, LOPT_LUASCRIPT },
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000303 { "enable-ra", 0, 0, LOPT_RA },
Simon Kelley8b372702012-03-09 17:45:10 +0000304 { "dhcp-duid", 1, 0, LOPT_DUID },
Simon Kelleye759d422012-03-16 13:18:57 +0000305 { "host-record", 1, 0, LOPT_HOST_REC },
Simon Kelley54dd3932012-06-20 11:23:38 +0100306 { "bind-dynamic", 0, 0, LOPT_CLVERBIND },
Simon Kelley4f7b3042012-11-28 21:27:02 +0000307 { "auth-zone", 1, 0, LOPT_AUTHZONE },
308 { "auth-server", 1, 0, LOPT_AUTHSERV },
309 { "auth-ttl", 1, 0, LOPT_AUTHTTL },
310 { "auth-soa", 1, 0, LOPT_AUTHSOA },
Simon Kelleye1ff4192012-12-09 17:08:47 +0000311 { "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
Simon Kelley49678762012-12-09 18:24:58 +0000312 { "auth-peer", 1, 0, LOPT_AUTHPEER },
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000313 { "ipset", 1, 0, LOPT_IPSET },
Simon Kelley2bb73af2013-04-24 17:38:19 +0100314 { "synth-domain", 1, 0, LOPT_SYNTH },
Giovanni Bajo7dbe1932012-04-05 02:50:13 +0200315 { "dnssec", 0, 0, LOPT_SEC_VALID },
Simon Kelleyee415862014-02-11 11:07:22 +0000316 { "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR },
Simon Kelley5b3bf922014-01-25 17:03:07 +0000317 { "dnssec-debug", 0, 0, LOPT_DNSSEC_DEBUG },
Simon Kelleya6918532018-04-15 16:20:52 +0100318 { "dnssec-check-unsigned", 2, 0, LOPT_DNSSEC_CHECK },
Simon Kelleye98bd522014-03-28 20:41:23 +0000319 { "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME },
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000320 { "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP },
Simon Kelleyc6309242013-03-07 20:59:28 +0000321#ifdef OPTION6_PREFIX_CLASS
322 { "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
323#endif
Simon Kelleyff7eea22013-09-04 18:01:38 +0100324 { "dhcp-relay", 1, 0, LOPT_RELAY },
Simon Kelleyc4cd95d2013-10-10 20:58:11 +0100325 { "ra-param", 1, 0, LOPT_RA_PARAM },
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100326 { "quiet-dhcp", 0, 0, LOPT_QUIET_DHCP },
327 { "quiet-dhcp6", 0, 0, LOPT_QUIET_DHCP6 },
328 { "quiet-ra", 0, 0, LOPT_QUIET_RA },
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +0100329 { "dns-loop-detect", 0, 0, LOPT_LOOP_DETECT },
Simon Kelley1e505122016-01-25 21:29:23 +0000330 { "script-arp", 0, 0, LOPT_SCRIPT_ARP },
Simon Kelley832e47b2016-02-24 21:24:45 +0000331 { "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },
Floris Bos503c6092017-04-09 23:07:13 +0100332 { "dhcp-reply-delay", 1, 0, LOPT_REPLY_DELAY },
Simon Kelley734d5312018-03-23 23:09:53 +0000333 { "dhcp-rapid-commit", 0, 0, LOPT_RAPID_COMMIT },
Simon Kelley6b173352018-05-08 18:32:14 +0100334 { "dumpfile", 1, 0, LOPT_DUMPFILE },
335 { "dumpmask", 1, 0, LOPT_DUMPMASK },
Simon Kelley849a8352006-06-09 21:02:31 +0100336 { NULL, 0, 0, 0 }
337 };
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000338
Simon Kelley28866e92011-02-14 20:19:14 +0000339
340#define ARG_DUP OPT_LAST
341#define ARG_ONE OPT_LAST + 1
342#define ARG_USED_CL OPT_LAST + 2
343#define ARG_USED_FILE OPT_LAST + 3
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000344
Simon Kelley1a6bca82008-07-11 11:11:42 +0100345static struct {
346 int opt;
347 unsigned int rept;
348 char * const flagdesc;
Simon Kelleyb8187c82005-11-26 21:46:27 +0000349 char * const desc;
350 char * const arg;
351} usage[] = {
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000352 { 'a', ARG_DUP, "<ipaddr>", gettext_noop("Specify local address(es) to listen on."), NULL },
353 { 'A', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Return ipaddr for all hosts in specified domains."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100354 { 'b', OPT_BOGUSPRIV, NULL, gettext_noop("Fake reverse lookups for RFC1918 private address ranges."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000355 { 'B', ARG_DUP, "<ipaddr>", gettext_noop("Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."), NULL },
356 { 'c', ARG_ONE, "<integer>", gettext_noop("Specify the size of the cache in entries (defaults to %s)."), "$" },
357 { 'C', ARG_DUP, "<path>", gettext_noop("Specify configuration file (defaults to %s)."), CONFFILE },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100358 { 'd', OPT_DEBUG, NULL, gettext_noop("Do NOT fork into the background: run in debug mode."), NULL },
359 { 'D', OPT_NODOTS_LOCAL, NULL, gettext_noop("Do NOT forward queries with no domain part."), NULL },
360 { 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL },
361 { 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
362 { 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000363 { 'F', ARG_DUP, "<ipaddr>,...", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
364 { 'g', ARG_ONE, "<groupname>", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100365 { 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000366 { LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL },
367 { LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL },
Simon Kelley5f4dc5c2015-01-20 20:51:02 +0000368 { LOPT_DHCP_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from a directory."), NULL },
Simon Kelley70d18732015-01-31 19:59:29 +0000369 { LOPT_DHOPT_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP options from a directory."), NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100370 { LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100371 { 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000372 { 'H', ARG_DUP, "<path>", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
Simon Kelley70d18732015-01-31 19:59:29 +0000373 { LOPT_HOST_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read hosts files from a directory."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000374 { 'i', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) to listen on."), NULL },
375 { 'I', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100376 { 'j', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
377 { LOPT_CIRCUIT, ARG_DUP, "set:<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
378 { LOPT_REMOTE, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
379 { LOPT_SUBSCR, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
380 { 'J', ARG_DUP, "tag:<tag>...", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
381 { LOPT_BROADCAST, ARG_DUP, "[=tag:<tag>...]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100382 { 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
383 { '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 +0000384 { 'l', ARG_ONE, "<path>", gettext_noop("Specify where to store DHCP leases (defaults to %s)."), LEASEFILE },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100385 { 'L', OPT_LOCALMX, NULL, gettext_noop("Return MX records for local hosts."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000386 { 'm', ARG_DUP, "<host_name>,<target>,<pref>", gettext_noop("Specify an MX record."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100387 { 'M', ARG_DUP, "<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL },
388 { 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE },
389 { 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL },
390 { 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE },
391 { 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL },
392 { 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 +0000393 { 'p', ARG_ONE, "<integer>", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
394 { 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
Simon Kelley25cf5e32015-01-09 15:53:03 +0000395 { 'q', ARG_DUP, NULL, gettext_noop("Log DNS queries."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000396 { 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100397 { 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000398 { 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
Simon Kelley7b1eae42014-02-20 13:43:28 +0000399 { LOPT_SERVERS_FILE, ARG_ONE, "<path>", gettext_noop("Specify path to file with server= options"), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000400 { 'S', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
Simon Kelleyde73a492014-02-17 21:43:27 +0000401 { LOPT_REV_SERV, ARG_DUP, "<addr>/<prefix>,<ipaddr>", gettext_noop("Specify address of upstream servers for reverse address queries"), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000402 { LOPT_LOCAL, ARG_DUP, "/<domain>/", gettext_noop("Never forward queries to specified domains."), NULL },
Simon Kelley9009d742008-11-14 20:04:27 +0000403 { 's', ARG_DUP, "<domain>[,<range>]", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000404 { 't', ARG_ONE, "<host_name>", gettext_noop("Specify default target in an MX record."), NULL },
405 { 'T', ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
406 { LOPT_NEGTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
407 { LOPT_MAXTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL },
RinSatsuki28de3872015-01-10 15:22:21 +0000408 { LOPT_MAXCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live ceiling for cache."), NULL },
409 { LOPT_MINCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live floor for cache."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000410 { 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100411 { 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100412 { 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000413 { 'V', ARG_DUP, "<ipaddr>,<ipaddr>,<netmask>", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },
414 { 'W', ARG_DUP, "<name>,<target>,...", gettext_noop("Specify a SRV record."), NULL },
Simon Kelley09217a12016-05-03 17:04:35 +0100415 { 'w', 0, NULL, gettext_noop("Display this message. Use --help dhcp or --help dhcp6 for known DHCP options."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000416 { 'x', ARG_ONE, "<path>", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE },
417 { 'X', ARG_ONE, "<integer>", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100418 { '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 +0000419 { 'Y', ARG_DUP, "<name>,<txt>[,<txt]", gettext_noop("Specify TXT DNS record."), NULL },
420 { LOPT_PTR, ARG_DUP, "<name>,<target>", gettext_noop("Specify PTR DNS record."), NULL },
421 { LOPT_INTNAME, ARG_DUP, "<name>,<interface>", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100422 { 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
423 { 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
Simon Kelleyad094272012-08-10 17:10:54 +0100424 { '1', ARG_ONE, "[=<busname>]", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
Julian Kornberger8dcdb332018-07-21 22:11:08 +0100425 { LOPT_UBUS, OPT_UBUS, NULL, gettext_noop("Enable the UBus interface."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000426 { '2', ARG_DUP, "<interface>", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100427 { '3', ARG_DUP, "[=tag:<tag>]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
428 { '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 +0000429 { 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 +0100430 { '5', OPT_NO_PING, NULL, gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000431 { '6', ARG_ONE, "<path>", gettext_noop("Shell script to run on DHCP lease creation and destruction."), NULL },
432 { LOPT_LUASCRIPT, ARG_DUP, "path", gettext_noop("Lua script to run on DHCP lease creation and destruction."), NULL },
433 { LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change scripts as this user."), NULL },
Simon Kelley1e505122016-01-25 21:29:23 +0000434 { LOPT_SCRIPT_ARP, OPT_SCRIPT_ARP, NULL, gettext_noop("Call dhcp-script with changes to local ARP table."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000435 { '7', ARG_DUP, "<path>", gettext_noop("Read configuration from all the files in this directory."), NULL },
Josh Soref730c6742017-02-06 16:14:04 +0000436 { '8', ARG_ONE, "<facility>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100437 { '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000438 { '0', ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100439 { LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100440 { LOPT_NO_NAMES, ARG_DUP, "[=tag:<tag>]...", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100441 { 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 +0100442 { LOPT_TFTP, ARG_DUP, "[=<intr>[,<intr>]]", gettext_noop("Enable integrated read-only TFTP server."), NULL },
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100443 { LOPT_PREFIX, ARG_DUP, "<dir>[,<iface>]", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
Floris Bos60704f52017-04-09 22:22:49 +0100444 { LOPT_APREF, ARG_DUP, "[=ip|mac]", gettext_noop("Add client IP or hardware address to tftp-root."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100445 { LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
Stefan Tomanek30d08792015-03-31 22:32:11 +0100446 { LOPT_TFTP_NO_FAIL, OPT_TFTP_NO_FAIL, NULL, gettext_noop("Do not terminate the service if TFTP directories are inaccessible."), NULL },
Josh Soref730c6742017-02-06 16:14:04 +0000447 { LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent TFTP transfers (defaults to %s)."), "#" },
Simon Kelleybec366b2016-02-24 22:03:26 +0000448 { LOPT_TFTP_MTU, ARG_ONE, "<integer>", gettext_noop("Maximum MTU to use for TFTP transfers."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100449 { LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
Simon Kelley61ce6002012-04-20 21:28:49 +0100450 { LOPT_TFTP_LC, OPT_TFTP_LC, NULL, gettext_noop("Convert TFTP filenames to lowercase"), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100451 { LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
452 { LOPT_LOG_OPTS, OPT_LOG_OPTS, NULL, gettext_noop("Extra logging for DHCP."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000453 { LOPT_MAX_LOGS, ARG_ONE, "[=<integer>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100454 { 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 +0100455 { 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 +0000456 { LOPT_NO_REBIND, ARG_DUP, "/<domain>/", gettext_noop("Inhibit DNS-rebind protection on this domain."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100457 { LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100458 { 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 +0100459 { LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100460 { LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
461 { LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
Hans Dedecker926332a2016-01-23 10:48:12 +0000462 { LOPT_MAXPORT, ARG_ONE, "<port>", gettext_noop("Specify highest port available for DNS query transmission."), NULL },
Simon Kelley9009d742008-11-14 20:04:27 +0000463 { 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 +0000464 { LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
465 { LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
Peter Wu3c0c1112016-08-28 20:53:09 +0100466 { LOPT_RELAY, ARG_DUP, "<local-addr>,<server>[,<iface>]", gettext_noop("Relay DHCP requests to a remote server"), NULL},
Simon Kelleydf3d54f2016-02-24 21:03:38 +0000467 { LOPT_CNAME, ARG_DUP, "<alias>,<target>[,<ttl>]", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
Simon Kelley7622fc02009-06-04 20:32:05 +0100468 { LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
469 { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
470 { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
Simon Kelley22c0f4f2016-02-17 22:12:31 +0000471 { LOPT_ADD_MAC, ARG_DUP, "[=base64|text]", gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
Ed Bardsleya7369be2015-08-05 21:17:18 +0100472 { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL },
Simon Kelleydf3d54f2016-02-24 21:03:38 +0000473 { LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client identification to forwarded DNS queries."), NULL },
Simon Kelley5a4120d2013-10-25 13:13:11 +0100474 { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
Simon Kelley7de060b2011-08-26 17:24:52 +0100475 { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
476 { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
Simon Kelleyc72daea2012-01-05 21:33:27 +0000477 { 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 +0000478 { LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
Simon Kelley8b372702012-03-09 17:45:10 +0000479 { LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
Simon Kelleydf3d54f2016-02-24 21:03:38 +0000480 { LOPT_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100481 { LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
Simon Kelley4f7b3042012-11-28 21:27:02 +0000482 { LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL },
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000483 { LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>", gettext_noop("Export local names to global DNS"), NULL },
Simon Kelley333b2ce2013-01-07 21:46:03 +0000484 { LOPT_AUTHZONE, ARG_DUP, "<domain>,[<subnet>...]", gettext_noop("Domain to export to global DNS"), NULL },
Simon Kelley4f7b3042012-11-28 21:27:02 +0000485 { LOPT_AUTHTTL, ARG_ONE, "<integer>", gettext_noop("Set TTL for authoritative replies"), NULL },
Josh Soref730c6742017-02-06 16:14:04 +0000486 { LOPT_AUTHSOA, ARG_ONE, "<serial>[,...]", gettext_noop("Set authoritative zone information"), NULL },
Simon Kelley49678762012-12-09 18:24:58 +0000487 { LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
488 { LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL },
Peter Wu3c0c1112016-08-28 20:53:09 +0100489 { LOPT_IPSET, ARG_DUP, "/<domain>[/<domain>...]/<ipset>...", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },
Gildasa9bf81a2013-10-24 13:31:40 +0100490 { LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for synthesised names"), NULL },
Simon Kelley3a237152013-12-12 12:15:50 +0000491 { LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
Simon Kelleyee415862014-02-11 11:07:22 +0000492 { LOPT_TRUST_ANCHOR, ARG_DUP, "<domain>,[<class>],...", gettext_noop("Specify trust anchor key digest."), NULL },
Simon Kelley5b3bf922014-01-25 17:03:07 +0000493 { LOPT_DNSSEC_DEBUG, OPT_DNSSEC_DEBUG, NULL, gettext_noop("Disable upstream checking for DNSSEC debugging."), NULL },
Simon Kelleya6918532018-04-15 16:20:52 +0100494 { LOPT_DNSSEC_CHECK, ARG_DUP, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
Simon Kelleye98bd522014-03-28 20:41:23 +0000495 { LOPT_DNSSEC_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL },
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000496 { LOPT_DNSSEC_STAMP, ARG_ONE, "<path>", gettext_noop("Timestamp file to verify system clock for DNSSEC"), NULL },
Simon Kelleyc6309242013-03-07 20:59:28 +0000497#ifdef OPTION6_PREFIX_CLASS
498 { LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
499#endif
Vladislav Grishenko6ec5f5c2017-04-24 22:34:45 +0100500 { LOPT_RA_PARAM, ARG_DUP, "<iface>,[mtu:<value>|<interface>|off,][<prio>,]<intval>[,<lifetime>]", gettext_noop("Set MTU, priority, resend-interval and router-lifetime"), NULL },
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100501 { LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
502 { LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
503 { LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
Simon Kelley832e47b2016-02-24 21:24:45 +0000504 { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks."), NULL },
505 { LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops."), NULL },
Glen Huang32fc6db2014-12-27 15:28:12 +0000506 { LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL },
Simon Kelley832e47b2016-02-24 21:24:45 +0000507 { LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL },
Floris Bos503c6092017-04-09 23:07:13 +0100508 { LOPT_REPLY_DELAY, ARG_ONE, "<integer>", gettext_noop("Delay DHCP replies for at least number of seconds."), NULL },
Simon Kelley734d5312018-03-23 23:09:53 +0000509 { LOPT_RAPID_COMMIT, OPT_RAPID_COMMIT, NULL, gettext_noop("Enables DHCPv4 Rapid Commit option."), NULL },
Simon Kelley6b173352018-05-08 18:32:14 +0100510 { LOPT_DUMPFILE, ARG_ONE, "<path>", gettext_noop("Path to debug packet dump file"), NULL },
511 { LOPT_DUMPMASK, ARG_ONE, "<hex>", gettext_noop("Mask which packets to dump"), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100512 { 0, 0, NULL, NULL, NULL }
Simon Kelleyb8187c82005-11-26 21:46:27 +0000513};
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000514
Josh Soref730c6742017-02-06 16:14:04 +0000515/* We hide metacharacters in quoted strings by mapping them into the ASCII control
Simon Kelleyf2621c72007-04-29 19:47:21 +0100516 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 +0100517 following sequence so that they map to themselves: it is therefore possible to call
518 unhide_metas repeatedly on string without breaking things.
Simon Kelley824af852008-02-12 20:43:05 +0000519 The transformation gets undone by opt_canonicalise, atoi_check and opt_string_alloc, and a
Simon Kelleyf2621c72007-04-29 19:47:21 +0100520 couple of other places.
521 Note that space is included here so that
522 --dhcp-option=3, string
523 has five characters, whilst
524 --dhcp-option=3," string"
525 has six.
526*/
Simon Kelley3d8df262005-08-29 12:19:27 +0100527
Simon Kelleyf2621c72007-04-29 19:47:21 +0100528static const char meta[] = "\000123456 \b\t\n78\r90abcdefABCDE\033F:,.";
Simon Kelley3d8df262005-08-29 12:19:27 +0100529
530static char hide_meta(char c)
531{
532 unsigned int i;
533
534 for (i = 0; i < (sizeof(meta) - 1); i++)
535 if (c == meta[i])
536 return (char)i;
537
538 return c;
539}
540
541static char unhide_meta(char cr)
542{
543 unsigned int c = cr;
544
545 if (c < (sizeof(meta) - 1))
546 cr = meta[c];
547
548 return cr;
549}
550
551static void unhide_metas(char *cp)
552{
553 if (cp)
554 for(; *cp; cp++)
555 *cp = unhide_meta(*cp);
556}
557
Simon Kelley824af852008-02-12 20:43:05 +0000558static void *opt_malloc(size_t size)
559{
560 void *ret;
561
562 if (mem_recover)
563 {
564 ret = whine_malloc(size);
565 if (!ret)
566 longjmp(mem_jmp, 1);
567 }
568 else
569 ret = safe_malloc(size);
570
571 return ret;
572}
573
574static char *opt_string_alloc(char *cp)
Simon Kelley3d8df262005-08-29 12:19:27 +0100575{
576 char *ret = NULL;
577
578 if (cp && strlen(cp) != 0)
579 {
Simon Kelley824af852008-02-12 20:43:05 +0000580 ret = opt_malloc(strlen(cp)+1);
Simon Kelley3d8df262005-08-29 12:19:27 +0100581 strcpy(ret, cp);
582
583 /* restore hidden metachars */
584 unhide_metas(ret);
585 }
586
587 return ret;
588}
589
Simon Kelley3d8df262005-08-29 12:19:27 +0100590
Simon Kelleyf2621c72007-04-29 19:47:21 +0100591/* find next comma, split string with zero and eliminate spaces.
592 return start of string following comma */
Simon Kelley73a08a22009-02-05 20:28:08 +0000593
594static char *split_chr(char *s, char c)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100595{
596 char *comma, *p;
597
Simon Kelley73a08a22009-02-05 20:28:08 +0000598 if (!s || !(comma = strchr(s, c)))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100599 return NULL;
600
601 p = comma;
602 *comma = ' ';
603
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100604 for (; *comma == ' '; comma++);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100605
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100606 for (; (p >= s) && *p == ' '; p--)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100607 *p = 0;
608
609 return comma;
Simon Kelley3d8df262005-08-29 12:19:27 +0100610}
611
Simon Kelley73a08a22009-02-05 20:28:08 +0000612static char *split(char *s)
613{
614 return split_chr(s, ',');
615}
616
Simon Kelley1f15b812009-10-13 17:49:32 +0100617static char *canonicalise_opt(char *s)
Simon Kelley3d8df262005-08-29 12:19:27 +0100618{
Simon Kelley1f15b812009-10-13 17:49:32 +0100619 char *ret;
620 int nomem;
621
Simon Kelley3d8df262005-08-29 12:19:27 +0100622 if (!s)
623 return 0;
624
625 unhide_metas(s);
Simon Kelley1f15b812009-10-13 17:49:32 +0100626 if (!(ret = canonicalise(s, &nomem)) && nomem)
627 {
628 if (mem_recover)
629 longjmp(mem_jmp, 1);
630 else
631 die(_("could not get memory"), NULL, EC_NOMEM);
632 }
633
634 return ret;
Simon Kelley3d8df262005-08-29 12:19:27 +0100635}
636
637static int atoi_check(char *a, int *res)
638{
639 char *p;
640
641 if (!a)
642 return 0;
643
644 unhide_metas(a);
645
646 for (p = a; *p; p++)
647 if (*p < '0' || *p > '9')
648 return 0;
649
650 *res = atoi(a);
651 return 1;
652}
653
Simon Kelley1ad24ae2008-07-20 20:22:50 +0100654static int atoi_check16(char *a, int *res)
655{
656 if (!(atoi_check(a, res)) ||
657 *res < 0 ||
658 *res > 0xffff)
659 return 0;
660
661 return 1;
662}
Simon Kelleyee415862014-02-11 11:07:22 +0000663
Simon Kelleyde73a492014-02-17 21:43:27 +0000664#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +0000665static int atoi_check8(char *a, int *res)
666{
667 if (!(atoi_check(a, res)) ||
668 *res < 0 ||
669 *res > 0xff)
670 return 0;
671
672 return 1;
673}
Simon Kelleyde73a492014-02-17 21:43:27 +0000674#endif
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +0100675
676#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +0000677static void add_txt(char *name, char *txt, int stat)
Simon Kelley0a852542005-03-23 20:28:59 +0000678{
Simon Kelley824af852008-02-12 20:43:05 +0000679 struct txt_record *r = opt_malloc(sizeof(struct txt_record));
Simon Kelleyfec216d2014-03-27 20:54:34 +0000680
681 if (txt)
682 {
683 size_t len = strlen(txt);
684 r->txt = opt_malloc(len+1);
685 r->len = len+1;
686 *(r->txt) = len;
687 memcpy((r->txt)+1, txt, len);
688 }
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +0100689
Simon Kelleyfec216d2014-03-27 20:54:34 +0000690 r->stat = stat;
Simon Kelley824af852008-02-12 20:43:05 +0000691 r->name = opt_string_alloc(name);
Simon Kelley0a852542005-03-23 20:28:59 +0000692 r->next = daemon->txt;
693 daemon->txt = r;
694 r->class = C_CHAOS;
Simon Kelley0a852542005-03-23 20:28:59 +0000695}
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +0100696#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000697
Simon Kelley849a8352006-06-09 21:02:31 +0100698static void do_usage(void)
699{
700 char buff[100];
Simon Kelley832af0b2007-01-21 20:01:28 +0000701 int i, j;
702
703 struct {
704 char handle;
705 int val;
706 } tab[] = {
707 { '$', CACHESIZ },
708 { '*', EDNS_PKTSZ },
709 { '&', MAXLEASES },
710 { '!', FTABSIZ },
711 { '#', TFTP_MAX_CONNECTIONS },
712 { '\0', 0 }
713 };
Simon Kelley849a8352006-06-09 21:02:31 +0100714
715 printf(_("Usage: dnsmasq [options]\n\n"));
716#ifndef HAVE_GETOPT_LONG
717 printf(_("Use short options only on the command line.\n"));
718#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100719 printf(_("Valid options are:\n"));
Simon Kelley849a8352006-06-09 21:02:31 +0100720
Simon Kelley1a6bca82008-07-11 11:11:42 +0100721 for (i = 0; usage[i].opt != 0; i++)
Simon Kelley849a8352006-06-09 21:02:31 +0100722 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100723 char *desc = usage[i].flagdesc;
724 char *eq = "=";
725
726 if (!desc || *desc == '[')
727 eq = "";
728
729 if (!desc)
730 desc = "";
731
732 for ( j = 0; opts[j].name; j++)
733 if (opts[j].val == usage[i].opt)
734 break;
735 if (usage[i].opt < 256)
736 sprintf(buff, "-%c, ", usage[i].opt);
737 else
738 sprintf(buff, " ");
739
740 sprintf(buff+4, "--%s%s%s", opts[j].name, eq, desc);
Peter Wu3c0c1112016-08-28 20:53:09 +0100741 printf("%-55.55s", buff);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100742
Simon Kelley849a8352006-06-09 21:02:31 +0100743 if (usage[i].arg)
744 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000745 strcpy(buff, usage[i].arg);
746 for (j = 0; tab[j].handle; j++)
747 if (tab[j].handle == *(usage[i].arg))
748 sprintf(buff, "%d", tab[j].val);
Simon Kelley849a8352006-06-09 21:02:31 +0100749 }
Simon Kelley849a8352006-06-09 21:02:31 +0100750 printf(_(usage[i].desc), buff);
751 printf("\n");
752 }
753}
754
Simon Kelleyc740e4f2012-08-09 16:19:01 +0100755#define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
756
Ed Bardsleya7369be2015-08-05 21:17:18 +0100757static char *parse_mysockaddr(char *arg, union mysockaddr *addr)
758{
759 if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
760 addr->sa.sa_family = AF_INET;
761#ifdef HAVE_IPV6
762 else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
763 addr->sa.sa_family = AF_INET6;
764#endif
765 else
766 return _("bad address");
767
768 return NULL;
769}
770
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100771char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags)
772{
773 int source_port = 0, serv_port = NAMESERVER_PORT;
774 char *portno, *source;
Kristian Evensen4e7694d2017-03-22 21:32:50 +0000775 char *interface_opt = NULL;
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100776#ifdef HAVE_IPV6
777 int scope_index = 0;
778 char *scope_id;
779#endif
780
Simon Kelleyd68c2ca2014-02-18 22:30:30 +0000781 if (!arg || strlen(arg) == 0)
782 {
783 *flags |= SERV_NO_ADDR;
784 *interface = 0;
785 return NULL;
786 }
787
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100788 if ((source = split_chr(arg, '@')) && /* is there a source. */
789 (portno = split_chr(source, '#')) &&
790 !atoi_check16(portno, &source_port))
791 return _("bad port");
792
793 if ((portno = split_chr(arg, '#')) && /* is there a port no. */
794 !atoi_check16(portno, &serv_port))
795 return _("bad port");
796
797#ifdef HAVE_IPV6
798 scope_id = split_chr(arg, '%');
799#endif
800
Kristian Evensen4e7694d2017-03-22 21:32:50 +0000801 if (source) {
802 interface_opt = split_chr(source, '@');
803
804 if (interface_opt)
805 {
806#if defined(SO_BINDTODEVICE)
807 strncpy(interface, interface_opt, IF_NAMESIZE - 1);
808#else
809 return _("interface binding not supported");
810#endif
811 }
812 }
813
Simon Kelleyddd9a6b2013-04-29 17:00:21 +0100814 if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100815 {
816 addr->in.sin_port = htons(serv_port);
817 addr->sa.sa_family = source_addr->sa.sa_family = AF_INET;
818#ifdef HAVE_SOCKADDR_SA_LEN
819 source_addr->in.sin_len = addr->in.sin_len = sizeof(struct sockaddr_in);
820#endif
821 source_addr->in.sin_addr.s_addr = INADDR_ANY;
822 source_addr->in.sin_port = htons(daemon->query_port);
823
824 if (source)
825 {
826 if (flags)
827 *flags |= SERV_HAS_SOURCE;
828 source_addr->in.sin_port = htons(source_port);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +0100829 if (!(inet_pton(AF_INET, source, &source_addr->in.sin_addr) > 0))
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100830 {
831#if defined(SO_BINDTODEVICE)
Kristian Evensen4e7694d2017-03-22 21:32:50 +0000832 if (interface_opt)
833 return _("interface can only be specified once");
834
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100835 source_addr->in.sin_addr.s_addr = INADDR_ANY;
836 strncpy(interface, source, IF_NAMESIZE - 1);
837#else
838 return _("interface binding not supported");
839#endif
840 }
841 }
842 }
843#ifdef HAVE_IPV6
844 else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
845 {
846 if (scope_id && (scope_index = if_nametoindex(scope_id)) == 0)
847 return _("bad interface name");
848
849 addr->in6.sin6_port = htons(serv_port);
850 addr->in6.sin6_scope_id = scope_index;
851 source_addr->in6.sin6_addr = in6addr_any;
852 source_addr->in6.sin6_port = htons(daemon->query_port);
853 source_addr->in6.sin6_scope_id = 0;
854 addr->sa.sa_family = source_addr->sa.sa_family = AF_INET6;
855 addr->in6.sin6_flowinfo = source_addr->in6.sin6_flowinfo = 0;
856#ifdef HAVE_SOCKADDR_SA_LEN
857 addr->in6.sin6_len = source_addr->in6.sin6_len = sizeof(addr->in6);
858#endif
859 if (source)
860 {
861 if (flags)
862 *flags |= SERV_HAS_SOURCE;
863 source_addr->in6.sin6_port = htons(source_port);
864 if (inet_pton(AF_INET6, source, &source_addr->in6.sin6_addr) == 0)
865 {
866#if defined(SO_BINDTODEVICE)
Kristian Evensen4e7694d2017-03-22 21:32:50 +0000867 if (interface_opt)
868 return _("interface can only be specified once");
869
870 source_addr->in6.sin6_addr = in6addr_any;
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100871 strncpy(interface, source, IF_NAMESIZE - 1);
872#else
873 return _("interface binding not supported");
874#endif
875 }
876 }
877 }
878#endif
879 else
880 return _("bad address");
881
882 return NULL;
883}
884
Simon Kelleyde73a492014-02-17 21:43:27 +0000885static struct server *add_rev4(struct in_addr addr, int msize)
886{
887 struct server *serv = opt_malloc(sizeof(struct server));
Olivier Gayot916959c2017-03-06 22:14:50 +0000888 in_addr_t a = ntohl(addr.s_addr);
Simon Kelleyde73a492014-02-17 21:43:27 +0000889 char *p;
890
891 memset(serv, 0, sizeof(struct server));
Olivier Gayot916959c2017-03-06 22:14:50 +0000892 p = serv->domain = opt_malloc(29); /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */
893
894 switch (msize)
895 {
896 case 32:
Rosen Penevcbd29e52017-06-27 22:29:51 +0100897 p += sprintf(p, "%u.", a & 0xff);
Olivier Gayot916959c2017-03-06 22:14:50 +0000898 /* fall through */
899 case 24:
900 p += sprintf(p, "%d.", (a >> 8) & 0xff);
901 /* fall through */
Olivier Gayot916959c2017-03-06 22:14:50 +0000902 case 16:
903 p += sprintf(p, "%d.", (a >> 16) & 0xff);
904 /* fall through */
905 case 8:
906 p += sprintf(p, "%d.", (a >> 24) & 0xff);
907 break;
Olivier Gayotdc990582017-03-06 22:17:21 +0000908 default:
909 return NULL;
Olivier Gayot916959c2017-03-06 22:14:50 +0000910 }
911
912 p += sprintf(p, "in-addr.arpa");
Simon Kelleyde73a492014-02-17 21:43:27 +0000913
914 serv->flags = SERV_HAS_DOMAIN;
915 serv->next = daemon->servers;
916 daemon->servers = serv;
917
918 return serv;
919
920}
921
922static struct server *add_rev6(struct in6_addr *addr, int msize)
923{
924 struct server *serv = opt_malloc(sizeof(struct server));
925 char *p;
926 int i;
927
928 memset(serv, 0, sizeof(struct server));
929 p = serv->domain = opt_malloc(73); /* strlen("32*<n.>ip6.arpa")+1 */
930
931 for (i = msize-1; i >= 0; i -= 4)
932 {
933 int dig = ((unsigned char *)addr)[i>>3];
934 p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
935 }
936 p += sprintf(p, "ip6.arpa");
937
938 serv->flags = SERV_HAS_DOMAIN;
939 serv->next = daemon->servers;
940 daemon->servers = serv;
941
942 return serv;
943}
944
Simon Kelleyb5a8dd12012-12-10 11:37:25 +0000945#ifdef HAVE_DHCP
946
947static int is_tag_prefix(char *arg)
948{
949 if (arg && (strstr(arg, "net:") == arg || strstr(arg, "tag:") == arg))
950 return 1;
951
952 return 0;
953}
954
955static char *set_prefix(char *arg)
956{
957 if (strstr(arg, "set:") == arg)
958 return arg+4;
959
960 return arg;
961}
962
Simon Kelley832af0b2007-01-21 20:01:28 +0000963/* This is too insanely large to keep in-line in the switch */
Simon Kelleyc4a7f902012-07-12 20:52:12 +0100964static int parse_dhcp_opt(char *errstr, char *arg, int flags)
Simon Kelley832af0b2007-01-21 20:01:28 +0000965{
Simon Kelley824af852008-02-12 20:43:05 +0000966 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
Simon Kelley832af0b2007-01-21 20:01:28 +0000967 char lenchar = 0, *cp;
Simon Kelley40ef23b2012-03-13 21:59:28 +0000968 int addrs, digs, is_addr, is_addr6, is_hex, is_dec, is_string, dots;
Simon Kelleyc4a7f902012-07-12 20:52:12 +0100969 char *comma = NULL;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100970 struct dhcp_netid *np = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000971 u16 opt_len = 0;
972 int is6 = 0;
Simon Kelleybd08ae62013-04-19 10:22:06 +0100973 int option_ok = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000974
975 new->len = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000976 new->flags = flags;
Simon Kelley832af0b2007-01-21 20:01:28 +0000977 new->netid = NULL;
978 new->val = NULL;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100979 new->opt = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000980
Simon Kelleyf2621c72007-04-29 19:47:21 +0100981 while (arg)
Simon Kelley832af0b2007-01-21 20:01:28 +0000982 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100983 comma = split(arg);
984
985 for (cp = arg; *cp; cp++)
986 if (*cp < '0' || *cp > '9')
Simon Kelley832af0b2007-01-21 20:01:28 +0000987 break;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100988
989 if (!*cp)
990 {
991 new->opt = atoi(arg);
992 opt_len = 0;
Simon Kelleybd08ae62013-04-19 10:22:06 +0100993 option_ok = 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100994 break;
995 }
996
997 if (strstr(arg, "option:") == arg)
998 {
Simon Kelleybd08ae62013-04-19 10:22:06 +0100999 if ((new->opt = lookup_dhcp_opt(AF_INET, arg+7)) != -1)
1000 {
1001 opt_len = lookup_dhcp_len(AF_INET, new->opt);
1002 /* option:<optname> must follow tag and vendor string. */
1003 if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
1004 option_ok = 1;
1005 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001006 break;
1007 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001008#ifdef HAVE_DHCP6
1009 else if (strstr(arg, "option6:") == arg)
1010 {
1011 for (cp = arg+8; *cp; cp++)
1012 if (*cp < '0' || *cp > '9')
1013 break;
1014
1015 if (!*cp)
1016 {
1017 new->opt = atoi(arg+8);
1018 opt_len = 0;
Simon Kelleybd08ae62013-04-19 10:22:06 +01001019 option_ok = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001020 }
1021 else
Simon Kelley40ef23b2012-03-13 21:59:28 +00001022 {
Simon Kelleybd08ae62013-04-19 10:22:06 +01001023 if ((new->opt = lookup_dhcp_opt(AF_INET6, arg+8)) != -1)
1024 {
1025 opt_len = lookup_dhcp_len(AF_INET6, new->opt);
1026 if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
1027 option_ok = 1;
1028 }
Simon Kelley40ef23b2012-03-13 21:59:28 +00001029 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001030 /* option6:<opt>|<optname> must follow tag and vendor string. */
1031 is6 = 1;
1032 break;
1033 }
1034#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +01001035 else if (strstr(arg, "vendor:") == arg)
1036 {
Simon Kelley73a08a22009-02-05 20:28:08 +00001037 new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7);
1038 new->flags |= DHOPT_VENDOR;
1039 }
1040 else if (strstr(arg, "encap:") == arg)
1041 {
1042 new->u.encap = atoi(arg+6);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001043 new->flags |= DHOPT_ENCAPSULATE;
1044 }
Simon Kelley316e2732010-01-22 20:16:09 +00001045 else if (strstr(arg, "vi-encap:") == arg)
1046 {
1047 new->u.encap = atoi(arg+9);
1048 new->flags |= DHOPT_RFC3925;
1049 if (flags == DHOPT_MATCH)
1050 {
Simon Kelleybd08ae62013-04-19 10:22:06 +01001051 option_ok = 1;
Simon Kelley316e2732010-01-22 20:16:09 +00001052 break;
1053 }
1054 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001055 else
1056 {
Simon Kelley824af852008-02-12 20:43:05 +00001057 new->netid = opt_malloc(sizeof (struct dhcp_netid));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001058 /* allow optional "net:" or "tag:" for consistency */
1059 if (is_tag_prefix(arg))
Simon Kelley824af852008-02-12 20:43:05 +00001060 new->netid->net = opt_string_alloc(arg+4);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001061 else
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001062 new->netid->net = opt_string_alloc(set_prefix(arg));
Simon Kelleyf2621c72007-04-29 19:47:21 +01001063 new->netid->next = np;
1064 np = new->netid;
1065 }
1066
1067 arg = comma;
Simon Kelley832af0b2007-01-21 20:01:28 +00001068 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001069
1070#ifdef HAVE_DHCP6
1071 if (is6)
1072 {
1073 if (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001074 ret_err(_("unsupported encapsulation for IPv6 option"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001075
1076 if (opt_len == 0 &&
1077 !(new->flags & DHOPT_RFC3925))
Simon Kelleybd08ae62013-04-19 10:22:06 +01001078 opt_len = lookup_dhcp_len(AF_INET6, new->opt);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001079 }
1080 else
1081#endif
1082 if (opt_len == 0 &&
1083 !(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
Simon Kelleybd08ae62013-04-19 10:22:06 +01001084 opt_len = lookup_dhcp_len(AF_INET, new->opt);
Simon Kelley40ef23b2012-03-13 21:59:28 +00001085
Simon Kelley316e2732010-01-22 20:16:09 +00001086 /* option may be missing with rfc3925 match */
Simon Kelleybd08ae62013-04-19 10:22:06 +01001087 if (!option_ok)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001088 ret_err(_("bad dhcp-option"));
1089
1090 if (comma)
Simon Kelley832af0b2007-01-21 20:01:28 +00001091 {
1092 /* characterise the value */
Simon Kelleyf2621c72007-04-29 19:47:21 +01001093 char c;
Simon Kelley28866e92011-02-14 20:19:14 +00001094 int found_dig = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001095 is_addr = is_addr6 = is_hex = is_dec = is_string = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001096 addrs = digs = 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001097 dots = 0;
1098 for (cp = comma; (c = *cp); cp++)
1099 if (c == ',')
Simon Kelley832af0b2007-01-21 20:01:28 +00001100 {
1101 addrs++;
1102 is_dec = is_hex = 0;
1103 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001104 else if (c == ':')
Simon Kelley832af0b2007-01-21 20:01:28 +00001105 {
1106 digs++;
1107 is_dec = is_addr = 0;
1108 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001109 else if (c == '/')
Simon Kelley832af0b2007-01-21 20:01:28 +00001110 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001111 is_addr6 = is_dec = is_hex = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001112 if (cp == comma) /* leading / means a pathname */
1113 is_addr = 0;
1114 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001115 else if (c == '.')
1116 {
Simon Kelley23245c02012-07-18 16:21:11 +01001117 is_addr6 = is_dec = is_hex = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001118 dots++;
1119 }
1120 else if (c == '-')
Simon Kelley4cb1b322012-02-06 14:30:41 +00001121 is_hex = is_addr = is_addr6 = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001122 else if (c == ' ')
Simon Kelley832af0b2007-01-21 20:01:28 +00001123 is_dec = is_hex = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001124 else if (!(c >='0' && c <= '9'))
Simon Kelley832af0b2007-01-21 20:01:28 +00001125 {
1126 is_addr = 0;
1127 if (cp[1] == 0 && is_dec &&
Simon Kelleyf2621c72007-04-29 19:47:21 +01001128 (c == 'b' || c == 's' || c == 'i'))
Simon Kelley832af0b2007-01-21 20:01:28 +00001129 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001130 lenchar = c;
Simon Kelley832af0b2007-01-21 20:01:28 +00001131 *cp = 0;
1132 }
1133 else
1134 is_dec = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001135 if (!((c >='A' && c <= 'F') ||
Simon Kelley73a08a22009-02-05 20:28:08 +00001136 (c >='a' && c <= 'f') ||
1137 (c == '*' && (flags & DHOPT_MATCH))))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001138 {
1139 is_hex = 0;
1140 if (c != '[' && c != ']')
1141 is_addr6 = 0;
1142 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001143 }
Simon Kelley28866e92011-02-14 20:19:14 +00001144 else
1145 found_dig = 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001146
Simon Kelley28866e92011-02-14 20:19:14 +00001147 if (!found_dig)
1148 is_dec = is_addr = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001149
Simon Kelleyf2621c72007-04-29 19:47:21 +01001150 /* We know that some options take addresses */
Simon Kelley7622fc02009-06-04 20:32:05 +01001151 if (opt_len & OT_ADDR_LIST)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001152 {
1153 is_string = is_dec = is_hex = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001154
1155 if (!is6 && (!is_addr || dots == 0))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001156 ret_err(_("bad IP address"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001157
1158 if (is6 && !is_addr6)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001159 ret_err(_("bad IPv6 address"));
Simon Kelleyf2621c72007-04-29 19:47:21 +01001160 }
Simon Kelley28866e92011-02-14 20:19:14 +00001161 /* or names */
Simon Kelley4cb1b322012-02-06 14:30:41 +00001162 else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING))
1163 is_addr6 = is_addr = is_dec = is_hex = 0;
Simon Kelley23245c02012-07-18 16:21:11 +01001164
1165 if (found_dig && (opt_len & OT_TIME) && strlen(comma) > 0)
1166 {
1167 int val, fac = 1;
1168
1169 switch (comma[strlen(comma) - 1])
1170 {
Simon Kelley42243212012-07-20 15:19:18 +01001171 case 'w':
1172 case 'W':
1173 fac *= 7;
1174 /* fall through */
Simon Kelley23245c02012-07-18 16:21:11 +01001175 case 'd':
1176 case 'D':
1177 fac *= 24;
Simon Kelley87e00fe2018-02-16 21:27:35 +00001178 /* fall through */
Simon Kelley23245c02012-07-18 16:21:11 +01001179 case 'h':
1180 case 'H':
1181 fac *= 60;
1182 /* fall through */
1183 case 'm':
1184 case 'M':
1185 fac *= 60;
1186 /* fall through */
1187 case 's':
1188 case 'S':
1189 comma[strlen(comma) - 1] = 0;
1190 }
1191
1192 new->len = 4;
1193 new->val = opt_malloc(4);
1194 val = atoi(comma);
1195 *((int *)new->val) = htonl(val * fac);
1196 }
1197 else if (is_hex && digs > 1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001198 {
1199 new->len = digs;
Simon Kelley824af852008-02-12 20:43:05 +00001200 new->val = opt_malloc(new->len);
Simon Kelley73a08a22009-02-05 20:28:08 +00001201 parse_hex(comma, new->val, digs, (flags & DHOPT_MATCH) ? &new->u.wildcard_mask : NULL, NULL);
1202 new->flags |= DHOPT_HEX;
Simon Kelley832af0b2007-01-21 20:01:28 +00001203 }
1204 else if (is_dec)
1205 {
1206 int i, val = atoi(comma);
1207 /* assume numeric arg is 1 byte except for
1208 options where it is known otherwise.
1209 For vendor class option, we have to hack. */
Simon Kelleyf2621c72007-04-29 19:47:21 +01001210 if (opt_len != 0)
1211 new->len = opt_len;
1212 else if (val & 0xffff0000)
1213 new->len = 4;
1214 else if (val & 0xff00)
1215 new->len = 2;
1216 else
1217 new->len = 1;
1218
Simon Kelley832af0b2007-01-21 20:01:28 +00001219 if (lenchar == 'b')
1220 new->len = 1;
1221 else if (lenchar == 's')
1222 new->len = 2;
1223 else if (lenchar == 'i')
1224 new->len = 4;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001225
Simon Kelley824af852008-02-12 20:43:05 +00001226 new->val = opt_malloc(new->len);
Simon Kelley832af0b2007-01-21 20:01:28 +00001227 for (i=0; i<new->len; i++)
1228 new->val[i] = val>>((new->len - i - 1)*8);
1229 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001230 else if (is_addr && !is6)
Simon Kelley832af0b2007-01-21 20:01:28 +00001231 {
1232 struct in_addr in;
1233 unsigned char *op;
1234 char *slash;
1235 /* max length of address/subnet descriptor is five bytes,
1236 add one for the option 120 enc byte too */
Simon Kelley824af852008-02-12 20:43:05 +00001237 new->val = op = opt_malloc((5 * addrs) + 1);
Simon Kelley6b010842007-02-12 20:32:07 +00001238 new->flags |= DHOPT_ADDR;
1239
Simon Kelley572b41e2011-02-18 18:11:18 +00001240 if (!(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
1241 new->opt == OPTION_SIP_SERVER)
Simon Kelley832af0b2007-01-21 20:01:28 +00001242 {
Simon Kelley6b010842007-02-12 20:32:07 +00001243 *(op++) = 1; /* RFC 3361 "enc byte" */
1244 new->flags &= ~DHOPT_ADDR;
Simon Kelley832af0b2007-01-21 20:01:28 +00001245 }
1246 while (addrs--)
1247 {
1248 cp = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001249 comma = split(cp);
Simon Kelley73a08a22009-02-05 20:28:08 +00001250 slash = split_chr(cp, '/');
Simon Kelleya2bc2542016-04-21 22:34:22 +01001251 if (!inet_pton(AF_INET, cp, &in))
1252 ret_err(_("bad IPv4 address"));
Simon Kelley832af0b2007-01-21 20:01:28 +00001253 if (!slash)
1254 {
1255 memcpy(op, &in, INADDRSZ);
1256 op += INADDRSZ;
1257 }
1258 else
1259 {
1260 unsigned char *p = (unsigned char *)&in;
1261 int netsize = atoi(slash);
1262 *op++ = netsize;
1263 if (netsize > 0)
1264 *op++ = *p++;
1265 if (netsize > 8)
1266 *op++ = *p++;
1267 if (netsize > 16)
1268 *op++ = *p++;
1269 if (netsize > 24)
1270 *op++ = *p++;
1271 new->flags &= ~DHOPT_ADDR; /* cannot re-write descriptor format */
1272 }
1273 }
1274 new->len = op - new->val;
1275 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001276 else if (is_addr6 && is6)
1277 {
1278 unsigned char *op;
1279 new->val = op = opt_malloc(16 * addrs);
1280 new->flags |= DHOPT_ADDR6;
1281 while (addrs--)
1282 {
1283 cp = comma;
1284 comma = split(cp);
1285
1286 /* check for [1234::7] */
1287 if (*cp == '[')
1288 cp++;
1289 if (strlen(cp) > 1 && cp[strlen(cp)-1] == ']')
1290 cp[strlen(cp)-1] = 0;
1291
1292 if (inet_pton(AF_INET6, cp, op))
1293 {
1294 op += IN6ADDRSZ;
1295 continue;
1296 }
1297
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001298 ret_err(_("bad IPv6 address"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001299 }
1300 new->len = op - new->val;
1301 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001302 else if (is_string)
Simon Kelley832af0b2007-01-21 20:01:28 +00001303 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001304 /* text arg */
Simon Kelley572b41e2011-02-18 18:11:18 +00001305 if ((new->opt == OPTION_DOMAIN_SEARCH || new->opt == OPTION_SIP_SERVER) &&
Simon Kelley4cb1b322012-02-06 14:30:41 +00001306 !is6 && !(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
Simon Kelley832af0b2007-01-21 20:01:28 +00001307 {
1308 /* dns search, RFC 3397, or SIP, RFC 3361 */
1309 unsigned char *q, *r, *tail;
Simon Kelley824af852008-02-12 20:43:05 +00001310 unsigned char *p, *m = NULL, *newp;
Simon Kelley832af0b2007-01-21 20:01:28 +00001311 size_t newlen, len = 0;
Simon Kelley572b41e2011-02-18 18:11:18 +00001312 int header_size = (new->opt == OPTION_DOMAIN_SEARCH) ? 0 : 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001313
1314 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001315 comma = split(arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00001316
1317 while (arg && *arg)
1318 {
Simon Kelleyc52e1892010-06-07 22:01:39 +01001319 char *in, *dom = NULL;
1320 size_t domlen = 1;
1321 /* Allow "." as an empty domain */
1322 if (strcmp (arg, ".") != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001323 {
Simon Kelleyc52e1892010-06-07 22:01:39 +01001324 if (!(dom = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001325 ret_err(_("bad domain in dhcp-option"));
1326
Simon Kelleyc52e1892010-06-07 22:01:39 +01001327 domlen = strlen(dom) + 2;
Simon Kelley832af0b2007-01-21 20:01:28 +00001328 }
Simon Kelleyc52e1892010-06-07 22:01:39 +01001329
1330 newp = opt_malloc(len + domlen + header_size);
Simon Kelley824af852008-02-12 20:43:05 +00001331 if (m)
Simon Kelleyc52e1892010-06-07 22:01:39 +01001332 {
1333 memcpy(newp, m, header_size + len);
1334 free(m);
1335 }
Simon Kelley824af852008-02-12 20:43:05 +00001336 m = newp;
Simon Kelley832af0b2007-01-21 20:01:28 +00001337 p = m + header_size;
1338 q = p + len;
1339
1340 /* add string on the end in RFC1035 format */
Simon Kelleyc52e1892010-06-07 22:01:39 +01001341 for (in = dom; in && *in;)
Simon Kelley832af0b2007-01-21 20:01:28 +00001342 {
1343 unsigned char *cp = q++;
1344 int j;
Simon Kelleyc52e1892010-06-07 22:01:39 +01001345 for (j = 0; *in && (*in != '.'); in++, j++)
1346 *q++ = *in;
Simon Kelley832af0b2007-01-21 20:01:28 +00001347 *cp = j;
Simon Kelleyc52e1892010-06-07 22:01:39 +01001348 if (*in)
1349 in++;
Simon Kelley832af0b2007-01-21 20:01:28 +00001350 }
1351 *q++ = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +01001352 free(dom);
Simon Kelleyc52e1892010-06-07 22:01:39 +01001353
Simon Kelley832af0b2007-01-21 20:01:28 +00001354 /* Now tail-compress using earlier names. */
1355 newlen = q - p;
1356 for (tail = p + len; *tail; tail += (*tail) + 1)
1357 for (r = p; r - p < (int)len; r += (*r) + 1)
1358 if (strcmp((char *)r, (char *)tail) == 0)
1359 {
1360 PUTSHORT((r - p) | 0xc000, tail);
1361 newlen = tail - p;
1362 goto end;
1363 }
1364 end:
1365 len = newlen;
1366
1367 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001368 comma = split(arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00001369 }
1370
1371 /* RFC 3361, enc byte is zero for names */
Simon Kelley572b41e2011-02-18 18:11:18 +00001372 if (new->opt == OPTION_SIP_SERVER)
Simon Kelley832af0b2007-01-21 20:01:28 +00001373 m[0] = 0;
1374 new->len = (int) len + header_size;
1375 new->val = m;
1376 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001377#ifdef HAVE_DHCP6
1378 else if (comma && (opt_len & OT_CSTRING))
1379 {
1380 /* length fields are two bytes so need 16 bits for each string */
Simon Kelley40ef23b2012-03-13 21:59:28 +00001381 int i, commas = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001382 unsigned char *p, *newp;
1383
Simon Kelley40ef23b2012-03-13 21:59:28 +00001384 for (i = 0; comma[i]; i++)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001385 if (comma[i] == ',')
1386 commas++;
1387
1388 newp = opt_malloc(strlen(comma)+(2*commas));
1389 p = newp;
1390 arg = comma;
1391 comma = split(arg);
1392
1393 while (arg && *arg)
1394 {
1395 u16 len = strlen(arg);
Simon Kelley18f0fb02012-03-31 21:18:55 +01001396 unhide_metas(arg);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001397 PUTSHORT(len, p);
1398 memcpy(p, arg, len);
1399 p += len;
1400
1401 arg = comma;
1402 comma = split(arg);
1403 }
1404
1405 new->val = newp;
1406 new->len = p - newp;
1407 }
1408 else if (comma && (opt_len & OT_RFC1035_NAME))
1409 {
Simon Kelley18f0fb02012-03-31 21:18:55 +01001410 unsigned char *p = NULL, *newp, *end;
1411 int len = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001412 arg = comma;
1413 comma = split(arg);
1414
1415 while (arg && *arg)
1416 {
Simon Kelley18f0fb02012-03-31 21:18:55 +01001417 char *dom = canonicalise_opt(arg);
1418 if (!dom)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001419 ret_err(_("bad domain in dhcp-option"));
1420
Simon Kelley18f0fb02012-03-31 21:18:55 +01001421 newp = opt_malloc(len + strlen(dom) + 2);
1422
1423 if (p)
1424 {
1425 memcpy(newp, p, len);
1426 free(p);
1427 }
1428
1429 p = newp;
Simon Kelley0549c732017-09-25 18:17:11 +01001430 end = do_rfc1035_name(p + len, dom, NULL);
Simon Kelley18f0fb02012-03-31 21:18:55 +01001431 *end++ = 0;
1432 len = end - p;
1433 free(dom);
1434
Simon Kelley4cb1b322012-02-06 14:30:41 +00001435 arg = comma;
1436 comma = split(arg);
1437 }
1438
Simon Kelley18f0fb02012-03-31 21:18:55 +01001439 new->val = p;
1440 new->len = len;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001441 }
1442#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001443 else
1444 {
1445 new->len = strlen(comma);
1446 /* keep terminating zero on string */
Simon Kelley824af852008-02-12 20:43:05 +00001447 new->val = (unsigned char *)opt_string_alloc(comma);
Simon Kelley832af0b2007-01-21 20:01:28 +00001448 new->flags |= DHOPT_STRING;
1449 }
1450 }
1451 }
1452
Simon Kelley4cb1b322012-02-06 14:30:41 +00001453 if (!is6 &&
1454 ((new->len > 255) ||
Simon Kelley316e2732010-01-22 20:16:09 +00001455 (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) ||
Simon Kelley4cb1b322012-02-06 14:30:41 +00001456 (new->len > 250 && (new->flags & DHOPT_RFC3925))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001457 ret_err(_("dhcp-option too long"));
Simon Kelley832af0b2007-01-21 20:01:28 +00001458
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001459 if (flags == DHOPT_MATCH)
Simon Kelley824af852008-02-12 20:43:05 +00001460 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001461 if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||
1462 !new->netid ||
1463 new->netid->next)
1464 ret_err(_("illegal dhcp-match"));
1465
1466 if (is6)
Simon Kelley73a08a22009-02-05 20:28:08 +00001467 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001468 new->next = daemon->dhcp_match6;
1469 daemon->dhcp_match6 = new;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001470 }
1471 else
Simon Kelley73a08a22009-02-05 20:28:08 +00001472 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001473 new->next = daemon->dhcp_match;
1474 daemon->dhcp_match = new;
Simon Kelley73a08a22009-02-05 20:28:08 +00001475 }
Simon Kelley824af852008-02-12 20:43:05 +00001476 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001477 else if (is6)
1478 {
1479 new->next = daemon->dhcp_opts6;
1480 daemon->dhcp_opts6 = new;
1481 }
1482 else
1483 {
1484 new->next = daemon->dhcp_opts;
1485 daemon->dhcp_opts = new;
1486 }
1487
1488 return 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001489}
1490
Simon Kelley7622fc02009-06-04 20:32:05 +01001491#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001492
Simon Kelley28866e92011-02-14 20:19:14 +00001493void set_option_bool(unsigned int opt)
1494{
1495 if (opt < 32)
1496 daemon->options |= 1u << opt;
1497 else
1498 daemon->options2 |= 1u << (opt - 32);
1499}
1500
Simon Kelley2b5bae92012-06-26 16:55:23 +01001501void reset_option_bool(unsigned int opt)
1502{
1503 if (opt < 32)
1504 daemon->options &= ~(1u << opt);
1505 else
1506 daemon->options2 &= ~(1u << (opt - 32));
1507}
1508
Simon Kelley7b1eae42014-02-20 13:43:28 +00001509static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only)
Simon Kelley849a8352006-06-09 21:02:31 +01001510{
1511 int i;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001512 char *comma;
Simon Kelley849a8352006-06-09 21:02:31 +01001513
Simon Kelley832af0b2007-01-21 20:01:28 +00001514 if (option == '?')
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001515 ret_err(gen_err);
Simon Kelley832af0b2007-01-21 20:01:28 +00001516
Simon Kelley1a6bca82008-07-11 11:11:42 +01001517 for (i=0; usage[i].opt != 0; i++)
1518 if (usage[i].opt == option)
Simon Kelley849a8352006-06-09 21:02:31 +01001519 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001520 int rept = usage[i].rept;
1521
Simon Kelley28866e92011-02-14 20:19:14 +00001522 if (command_line)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001523 {
1524 /* command line */
1525 if (rept == ARG_USED_CL)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001526 ret_err(_("illegal repeated flag"));
Simon Kelley1a6bca82008-07-11 11:11:42 +01001527 if (rept == ARG_ONE)
1528 usage[i].rept = ARG_USED_CL;
1529 }
1530 else
1531 {
1532 /* allow file to override command line */
1533 if (rept == ARG_USED_FILE)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001534 ret_err(_("illegal repeated keyword"));
Simon Kelley1a6bca82008-07-11 11:11:42 +01001535 if (rept == ARG_USED_CL || rept == ARG_ONE)
1536 usage[i].rept = ARG_USED_FILE;
1537 }
1538
1539 if (rept != ARG_DUP && rept != ARG_ONE && rept != ARG_USED_CL)
1540 {
Simon Kelley28866e92011-02-14 20:19:14 +00001541 set_option_bool(rept);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001542 return 1;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001543 }
1544
1545 break;
Simon Kelley849a8352006-06-09 21:02:31 +01001546 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001547
Simon Kelley849a8352006-06-09 21:02:31 +01001548 switch (option)
1549 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001550 case 'C': /* --conf-file */
Simon Kelley849a8352006-06-09 21:02:31 +01001551 {
Simon Kelley824af852008-02-12 20:43:05 +00001552 char *file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001553 if (file)
Simon Kelley9009d742008-11-14 20:04:27 +00001554 {
Simon Kelley28866e92011-02-14 20:19:14 +00001555 one_file(file, 0);
Simon Kelley9009d742008-11-14 20:04:27 +00001556 free(file);
1557 }
Simon Kelley849a8352006-06-09 21:02:31 +01001558 break;
1559 }
1560
Simon Kelleyf2621c72007-04-29 19:47:21 +01001561 case '7': /* --conf-dir */
Simon Kelley849a8352006-06-09 21:02:31 +01001562 {
1563 DIR *dir_stream;
1564 struct dirent *ent;
1565 char *directory, *path;
Simon Kelley1f15b812009-10-13 17:49:32 +01001566 struct list {
1567 char *suffix;
1568 struct list *next;
Simon Kelley3e1551a2014-09-09 21:46:07 +01001569 } *ignore_suffix = NULL, *match_suffix = NULL, *li;
Simon Kelley849a8352006-06-09 21:02:31 +01001570
Simon Kelley1f15b812009-10-13 17:49:32 +01001571 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00001572 if (!(directory = opt_string_alloc(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01001573 break;
1574
Simon Kelley1f15b812009-10-13 17:49:32 +01001575 for (arg = comma; arg; arg = comma)
1576 {
1577 comma = split(arg);
Simon Kelley00cd9d52014-10-02 21:44:21 +01001578 if (strlen(arg) != 0)
Simon Kelley3e1551a2014-09-09 21:46:07 +01001579 {
Simon Kelley00cd9d52014-10-02 21:44:21 +01001580 li = opt_malloc(sizeof(struct list));
1581 if (*arg == '*')
1582 {
Simon Kelley0007ee92015-11-21 21:47:41 +00001583 /* "*" with no suffix is a no-op */
1584 if (arg[1] == 0)
1585 free(li);
1586 else
1587 {
1588 li->next = match_suffix;
1589 match_suffix = li;
1590 /* Have to copy: buffer is overwritten */
1591 li->suffix = opt_string_alloc(arg+1);
1592 }
Simon Kelley00cd9d52014-10-02 21:44:21 +01001593 }
1594 else
1595 {
1596 li->next = ignore_suffix;
1597 ignore_suffix = li;
1598 /* Have to copy: buffer is overwritten */
1599 li->suffix = opt_string_alloc(arg);
1600 }
Simon Kelley3e1551a2014-09-09 21:46:07 +01001601 }
Simon Kelley00cd9d52014-10-02 21:44:21 +01001602 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001603
Simon Kelley849a8352006-06-09 21:02:31 +01001604 if (!(dir_stream = opendir(directory)))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001605 die(_("cannot access directory %s: %s"), directory, EC_FILE);
Simon Kelley1f15b812009-10-13 17:49:32 +01001606
Simon Kelley849a8352006-06-09 21:02:31 +01001607 while ((ent = readdir(dir_stream)))
1608 {
Simon Kelley7622fc02009-06-04 20:32:05 +01001609 size_t len = strlen(ent->d_name);
Simon Kelley849a8352006-06-09 21:02:31 +01001610 struct stat buf;
Simon Kelley1f15b812009-10-13 17:49:32 +01001611
1612 /* ignore emacs backups and dotfiles */
Simon Kelley7622fc02009-06-04 20:32:05 +01001613 if (len == 0 ||
1614 ent->d_name[len - 1] == '~' ||
Simon Kelley849a8352006-06-09 21:02:31 +01001615 (ent->d_name[0] == '#' && ent->d_name[len - 1] == '#') ||
1616 ent->d_name[0] == '.')
1617 continue;
Simon Kelley7622fc02009-06-04 20:32:05 +01001618
Simon Kelley3e1551a2014-09-09 21:46:07 +01001619 if (match_suffix)
1620 {
1621 for (li = match_suffix; li; li = li->next)
1622 {
1623 /* check for required suffices */
1624 size_t ls = strlen(li->suffix);
1625 if (len > ls &&
1626 strcmp(li->suffix, &ent->d_name[len - ls]) == 0)
1627 break;
1628 }
1629 if (!li)
1630 continue;
1631 }
1632
Simon Kelley1f15b812009-10-13 17:49:32 +01001633 for (li = ignore_suffix; li; li = li->next)
1634 {
1635 /* check for proscribed suffices */
1636 size_t ls = strlen(li->suffix);
1637 if (len > ls &&
1638 strcmp(li->suffix, &ent->d_name[len - ls]) == 0)
1639 break;
1640 }
1641 if (li)
1642 continue;
1643
Simon Kelley824af852008-02-12 20:43:05 +00001644 path = opt_malloc(strlen(directory) + len + 2);
Simon Kelley849a8352006-06-09 21:02:31 +01001645 strcpy(path, directory);
1646 strcat(path, "/");
1647 strcat(path, ent->d_name);
Simon Kelley7622fc02009-06-04 20:32:05 +01001648
Simon Kelley39595cf2013-02-04 21:40:07 +00001649 /* files must be readable */
Simon Kelley849a8352006-06-09 21:02:31 +01001650 if (stat(path, &buf) == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001651 die(_("cannot access %s: %s"), path, EC_FILE);
Simon Kelley849a8352006-06-09 21:02:31 +01001652
Simon Kelley39595cf2013-02-04 21:40:07 +00001653 /* only reg files allowed. */
1654 if (S_ISREG(buf.st_mode))
1655 one_file(path, 0);
1656
Simon Kelley849a8352006-06-09 21:02:31 +01001657 free(path);
1658 }
1659
1660 closedir(dir_stream);
Simon Kelley9009d742008-11-14 20:04:27 +00001661 free(directory);
Simon Kelley1f15b812009-10-13 17:49:32 +01001662 for(; ignore_suffix; ignore_suffix = li)
1663 {
1664 li = ignore_suffix->next;
1665 free(ignore_suffix->suffix);
1666 free(ignore_suffix);
1667 }
Simon Kelley00cd9d52014-10-02 21:44:21 +01001668 for(; match_suffix; match_suffix = li)
1669 {
1670 li = match_suffix->next;
1671 free(match_suffix->suffix);
1672 free(match_suffix);
Ed Bardsleya7369be2015-08-05 21:17:18 +01001673 }
Simon Kelley849a8352006-06-09 21:02:31 +01001674 break;
1675 }
1676
Simon Kelleyed4c0762013-10-08 20:46:34 +01001677 case LOPT_ADD_SBNET: /* --add-subnet */
1678 set_option_bool(OPT_CLIENT_SUBNET);
1679 if (arg)
1680 {
Ed Bardsleya7369be2015-08-05 21:17:18 +01001681 char *err, *end;
Simon Kelleyed4c0762013-10-08 20:46:34 +01001682 comma = split(arg);
Ed Bardsleya7369be2015-08-05 21:17:18 +01001683
1684 struct mysubnet* new = opt_malloc(sizeof(struct mysubnet));
1685 if ((end = split_chr(arg, '/')))
1686 {
1687 /* has subnet+len */
1688 err = parse_mysockaddr(arg, &new->addr);
1689 if (err)
1690 ret_err(err);
1691 if (!atoi_check(end, &new->mask))
1692 ret_err(gen_err);
1693 new->addr_used = 1;
1694 }
1695 else if (!atoi_check(arg, &new->mask))
1696 ret_err(gen_err);
1697
1698 daemon->add_subnet4 = new;
1699
Ed Bardsleya7369be2015-08-05 21:17:18 +01001700 if (comma)
1701 {
Simon Kelley22fe2fd2016-02-28 17:07:10 +00001702 new = opt_malloc(sizeof(struct mysubnet));
1703 if ((end = split_chr(comma, '/')))
1704 {
1705 /* has subnet+len */
Ed Bardsleya7369be2015-08-05 21:17:18 +01001706 err = parse_mysockaddr(comma, &new->addr);
1707 if (err)
1708 ret_err(err);
1709 if (!atoi_check(end, &new->mask))
1710 ret_err(gen_err);
1711 new->addr_used = 1;
1712 }
1713 else
1714 {
1715 if (!atoi_check(comma, &new->mask))
1716 ret_err(gen_err);
1717 }
Simon Kelley22fe2fd2016-02-28 17:07:10 +00001718
1719 daemon->add_subnet6 = new;
1720 }
Simon Kelleyed4c0762013-10-08 20:46:34 +01001721 }
1722 break;
1723
Simon Kelleyad094272012-08-10 17:10:54 +01001724 case '1': /* --enable-dbus */
1725 set_option_bool(OPT_DBUS);
1726 if (arg)
1727 daemon->dbus_name = opt_string_alloc(arg);
1728 else
1729 daemon->dbus_name = DNSMASQ_SERVICE;
1730 break;
1731
Simon Kelleyf2621c72007-04-29 19:47:21 +01001732 case '8': /* --log-facility */
1733 /* may be a filename */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001734 if (strchr(arg, '/') || strcmp (arg, "-") == 0)
Simon Kelley824af852008-02-12 20:43:05 +00001735 daemon->log_file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001736 else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001737 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001738#ifdef __ANDROID__
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001739 ret_err(_("setting log facility is not possible under Android"));
Simon Kelley572b41e2011-02-18 18:11:18 +00001740#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001741 for (i = 0; facilitynames[i].c_name; i++)
1742 if (hostname_isequal((char *)facilitynames[i].c_name, arg))
1743 break;
1744
1745 if (facilitynames[i].c_name)
1746 daemon->log_fac = facilitynames[i].c_val;
1747 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001748 ret_err(_("bad log facility"));
Simon Kelley572b41e2011-02-18 18:11:18 +00001749#endif
Simon Kelley849a8352006-06-09 21:02:31 +01001750 }
1751 break;
Julian Kornberger8dcdb332018-07-21 22:11:08 +01001752
Simon Kelleyf2621c72007-04-29 19:47:21 +01001753 case 'x': /* --pid-file */
Simon Kelley824af852008-02-12 20:43:05 +00001754 daemon->runfile = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001755 break;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001756
Simon Kelleyf2621c72007-04-29 19:47:21 +01001757 case 'r': /* --resolv-file */
Simon Kelley849a8352006-06-09 21:02:31 +01001758 {
Simon Kelley824af852008-02-12 20:43:05 +00001759 char *name = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001760 struct resolvc *new, *list = daemon->resolv_files;
1761
1762 if (list && list->is_default)
1763 {
1764 /* replace default resolv file - possibly with nothing */
1765 if (name)
1766 {
1767 list->is_default = 0;
1768 list->name = name;
1769 }
1770 else
1771 list = NULL;
1772 }
1773 else if (name)
1774 {
Simon Kelley824af852008-02-12 20:43:05 +00001775 new = opt_malloc(sizeof(struct resolvc));
Simon Kelley849a8352006-06-09 21:02:31 +01001776 new->next = list;
1777 new->name = name;
1778 new->is_default = 0;
1779 new->mtime = 0;
1780 new->logged = 0;
1781 list = new;
1782 }
1783 daemon->resolv_files = list;
1784 break;
1785 }
Simon Kelley7b1eae42014-02-20 13:43:28 +00001786
1787 case LOPT_SERVERS_FILE:
1788 daemon->servers_file = opt_string_alloc(arg);
1789 break;
Simon Kelley849a8352006-06-09 21:02:31 +01001790
Simon Kelleyf2621c72007-04-29 19:47:21 +01001791 case 'm': /* --mx-host */
Simon Kelley849a8352006-06-09 21:02:31 +01001792 {
1793 int pref = 1;
1794 struct mx_srv_record *new;
Simon Kelley1f15b812009-10-13 17:49:32 +01001795 char *name, *target = NULL;
1796
Simon Kelleyf2621c72007-04-29 19:47:21 +01001797 if ((comma = split(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01001798 {
1799 char *prefstr;
Simon Kelley1f15b812009-10-13 17:49:32 +01001800 if ((prefstr = split(comma)) && !atoi_check16(prefstr, &pref))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001801 ret_err(_("bad MX preference"));
Simon Kelley849a8352006-06-09 21:02:31 +01001802 }
1803
Simon Kelley1f15b812009-10-13 17:49:32 +01001804 if (!(name = canonicalise_opt(arg)) ||
1805 (comma && !(target = canonicalise_opt(comma))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001806 ret_err(_("bad MX name"));
Simon Kelley1f15b812009-10-13 17:49:32 +01001807
Simon Kelley824af852008-02-12 20:43:05 +00001808 new = opt_malloc(sizeof(struct mx_srv_record));
Simon Kelley849a8352006-06-09 21:02:31 +01001809 new->next = daemon->mxnames;
1810 daemon->mxnames = new;
1811 new->issrv = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +01001812 new->name = name;
1813 new->target = target; /* may be NULL */
Simon Kelley849a8352006-06-09 21:02:31 +01001814 new->weight = pref;
1815 break;
1816 }
1817
Simon Kelleyf2621c72007-04-29 19:47:21 +01001818 case 't': /* --mx-target */
Simon Kelley1f15b812009-10-13 17:49:32 +01001819 if (!(daemon->mxtarget = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001820 ret_err(_("bad MX target"));
Simon Kelley849a8352006-06-09 21:02:31 +01001821 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01001822
Simon Kelley6b173352018-05-08 18:32:14 +01001823 case LOPT_DUMPFILE: /* --dumpfile */
1824 daemon->dump_file = opt_string_alloc(arg);
1825 break;
1826
1827 case LOPT_DUMPMASK: /* --dumpmask */
1828 daemon->dump_mask = strtol(arg, NULL, 0);
1829 break;
1830
Simon Kelley7622fc02009-06-04 20:32:05 +01001831#ifdef HAVE_DHCP
Simon Kelleyf2621c72007-04-29 19:47:21 +01001832 case 'l': /* --dhcp-leasefile */
Simon Kelley824af852008-02-12 20:43:05 +00001833 daemon->lease_file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001834 break;
1835
Simon Kelleyc72daea2012-01-05 21:33:27 +00001836 /* Sorry about the gross pre-processor abuse */
1837 case '6': /* --dhcp-script */
1838 case LOPT_LUASCRIPT: /* --dhcp-luascript */
Simon Kelley1f15b812009-10-13 17:49:32 +01001839# if defined(NO_FORK)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001840 ret_err(_("cannot run scripts under uClinux"));
Simon Kelley1f15b812009-10-13 17:49:32 +01001841# elif !defined(HAVE_SCRIPT)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001842 ret_err(_("recompile with HAVE_SCRIPT defined to enable lease-change scripts"));
Simon Kelley7622fc02009-06-04 20:32:05 +01001843# else
Simon Kelleyc72daea2012-01-05 21:33:27 +00001844 if (option == LOPT_LUASCRIPT)
1845# if !defined(HAVE_LUASCRIPT)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001846 ret_err(_("recompile with HAVE_LUASCRIPT defined to enable Lua scripts"));
Simon Kelleyc72daea2012-01-05 21:33:27 +00001847# else
1848 daemon->luascript = opt_string_alloc(arg);
1849# endif
1850 else
1851 daemon->lease_change_command = opt_string_alloc(arg);
Simon Kelley7622fc02009-06-04 20:32:05 +01001852# endif
Simon Kelley849a8352006-06-09 21:02:31 +01001853 break;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001854#endif /* HAVE_DHCP */
Simon Kelley7622fc02009-06-04 20:32:05 +01001855
Simon Kelley70d18732015-01-31 19:59:29 +00001856 case LOPT_DHCP_HOST: /* --dhcp-hostsfile */
1857 case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
1858 case LOPT_DHCP_INOTIFY: /* --dhcp-hostsdir */
1859 case LOPT_DHOPT_INOTIFY: /* --dhcp-optsdir */
1860 case LOPT_HOST_INOTIFY: /* --hostsdir */
1861 case 'H': /* --addn-hosts */
Simon Kelley849a8352006-06-09 21:02:31 +01001862 {
Simon Kelley824af852008-02-12 20:43:05 +00001863 struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
Simon Kelley19c51cf2014-03-18 22:38:30 +00001864 static unsigned int hosts_index = SRC_AH;
Simon Kelley824af852008-02-12 20:43:05 +00001865 new->fname = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001866 new->index = hosts_index++;
Simon Kelley7622fc02009-06-04 20:32:05 +01001867 new->flags = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00001868 if (option == 'H')
1869 {
1870 new->next = daemon->addn_hosts;
1871 daemon->addn_hosts = new;
1872 }
1873 else if (option == LOPT_DHCP_HOST)
1874 {
1875 new->next = daemon->dhcp_hosts_file;
1876 daemon->dhcp_hosts_file = new;
1877 }
Simon Kelleye1ff4192012-12-09 17:08:47 +00001878 else if (option == LOPT_DHCP_OPTS)
Simon Kelley28866e92011-02-14 20:19:14 +00001879 {
1880 new->next = daemon->dhcp_opts_file;
1881 daemon->dhcp_opts_file = new;
1882 }
Simon Kelley70d18732015-01-31 19:59:29 +00001883 else
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00001884 {
Simon Kelley70d18732015-01-31 19:59:29 +00001885 new->next = daemon->dynamic_dirs;
1886 daemon->dynamic_dirs = new;
1887 if (option == LOPT_DHCP_INOTIFY)
1888 new->flags |= AH_DHCP_HST;
1889 else if (option == LOPT_DHOPT_INOTIFY)
1890 new->flags |= AH_DHCP_OPT;
1891 else if (option == LOPT_HOST_INOTIFY)
1892 new->flags |= AH_HOSTS;
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00001893 }
1894
Simon Kelley849a8352006-06-09 21:02:31 +01001895 break;
1896 }
1897
Simon Kelleyf373a152013-09-23 12:47:47 +01001898
1899#ifdef HAVE_AUTH
Simon Kelley4f7b3042012-11-28 21:27:02 +00001900 case LOPT_AUTHSERV: /* --auth-server */
Simon Kelley86e3b9a2012-11-30 13:46:48 +00001901 if (!(comma = split(arg)))
Simon Kelley4f7b3042012-11-28 21:27:02 +00001902 ret_err(gen_err);
1903
Simon Kelley4f7b3042012-11-28 21:27:02 +00001904 daemon->authserver = opt_string_alloc(arg);
Simon Kelley429798f2012-12-10 20:45:53 +00001905 arg = comma;
1906 do {
1907 struct iname *new = opt_malloc(sizeof(struct iname));
1908 comma = split(arg);
1909 new->name = NULL;
1910 unhide_metas(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01001911 if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0)
Simon Kelley429798f2012-12-10 20:45:53 +00001912 new->addr.sa.sa_family = AF_INET;
1913#ifdef HAVE_IPV6
1914 else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
1915 new->addr.sa.sa_family = AF_INET6;
1916#endif
1917 else
Simon Kelleyf25e6c62013-11-17 12:23:42 +00001918 {
1919 char *fam = split_chr(arg, '/');
1920 new->name = opt_string_alloc(arg);
1921 new->addr.sa.sa_family = 0;
1922 if (fam)
1923 {
1924 if (strcmp(fam, "4") == 0)
1925 new->addr.sa.sa_family = AF_INET;
1926#ifdef HAVE_IPV6
1927 else if (strcmp(fam, "6") == 0)
1928 new->addr.sa.sa_family = AF_INET6;
1929#endif
1930 else
1931 ret_err(gen_err);
1932 }
1933 }
Simon Kelley429798f2012-12-10 20:45:53 +00001934 new->next = daemon->authinterface;
1935 daemon->authinterface = new;
1936
1937 arg = comma;
1938 } while (arg);
1939
Simon Kelley4f7b3042012-11-28 21:27:02 +00001940 break;
Simon Kelleye1ff4192012-12-09 17:08:47 +00001941
1942 case LOPT_AUTHSFS: /* --auth-sec-servers */
1943 {
1944 struct name_list *new;
1945
1946 do {
1947 comma = split(arg);
Simon Kelley429798f2012-12-10 20:45:53 +00001948 new = opt_malloc(sizeof(struct name_list));
Simon Kelleye1ff4192012-12-09 17:08:47 +00001949 new->name = opt_string_alloc(arg);
1950 new->next = daemon->secondary_forward_server;
1951 daemon->secondary_forward_server = new;
1952 arg = comma;
1953 } while (arg);
1954 break;
1955 }
1956
Simon Kelley4f7b3042012-11-28 21:27:02 +00001957 case LOPT_AUTHZONE: /* --auth-zone */
1958 {
1959 struct auth_zone *new;
1960
1961 comma = split(arg);
Simon Kelley1e14cc02012-12-29 17:27:59 +00001962
Simon Kelley429798f2012-12-10 20:45:53 +00001963 new = opt_malloc(sizeof(struct auth_zone));
Simon Kelley4f7b3042012-11-28 21:27:02 +00001964 new->domain = opt_string_alloc(arg);
1965 new->subnet = NULL;
Mathias Kresin094bfae2016-07-24 14:15:22 +01001966 new->exclude = NULL;
Simon Kelley376d48c2013-11-13 13:04:30 +00001967 new->interface_names = NULL;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001968 new->next = daemon->auth_zones;
1969 daemon->auth_zones = new;
1970
1971 while ((arg = comma))
1972 {
1973 int prefixlen = 0;
Mathias Kresin094bfae2016-07-24 14:15:22 +01001974 int is_exclude = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001975 char *prefix;
Simon Kelley376d48c2013-11-13 13:04:30 +00001976 struct addrlist *subnet = NULL;
1977 struct all_addr addr;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001978
1979 comma = split(arg);
1980 prefix = split_chr(arg, '/');
1981
1982 if (prefix && !atoi_check(prefix, &prefixlen))
1983 ret_err(gen_err);
1984
Mathias Kresin094bfae2016-07-24 14:15:22 +01001985 if (strstr(arg, "exclude:") == arg)
1986 {
1987 is_exclude = 1;
1988 arg = arg+8;
1989 }
1990
Simon Kelley376d48c2013-11-13 13:04:30 +00001991 if (inet_pton(AF_INET, arg, &addr.addr.addr4))
Simon Kelley4f7b3042012-11-28 21:27:02 +00001992 {
Simon Kelley376d48c2013-11-13 13:04:30 +00001993 subnet = opt_malloc(sizeof(struct addrlist));
Simon Kelley4f7b3042012-11-28 21:27:02 +00001994 subnet->prefixlen = (prefixlen == 0) ? 24 : prefixlen;
Simon Kelley376d48c2013-11-13 13:04:30 +00001995 subnet->flags = ADDRLIST_LITERAL;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001996 }
1997#ifdef HAVE_IPV6
Simon Kelley376d48c2013-11-13 13:04:30 +00001998 else if (inet_pton(AF_INET6, arg, &addr.addr.addr6))
Simon Kelley4f7b3042012-11-28 21:27:02 +00001999 {
Simon Kelley376d48c2013-11-13 13:04:30 +00002000 subnet = opt_malloc(sizeof(struct addrlist));
Simon Kelley4f7b3042012-11-28 21:27:02 +00002001 subnet->prefixlen = (prefixlen == 0) ? 64 : prefixlen;
Simon Kelley376d48c2013-11-13 13:04:30 +00002002 subnet->flags = ADDRLIST_LITERAL | ADDRLIST_IPV6;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002003 }
2004#endif
Simon Kelley376d48c2013-11-13 13:04:30 +00002005 else
2006 {
2007 struct auth_name_list *name = opt_malloc(sizeof(struct auth_name_list));
2008 name->name = opt_string_alloc(arg);
2009 name->flags = AUTH4 | AUTH6;
2010 name->next = new->interface_names;
2011 new->interface_names = name;
2012 if (prefix)
2013 {
2014 if (prefixlen == 4)
2015 name->flags &= ~AUTH6;
2016#ifdef HAVE_IPV6
2017 else if (prefixlen == 6)
2018 name->flags &= ~AUTH4;
2019#endif
2020 else
2021 ret_err(gen_err);
2022 }
2023 }
2024
2025 if (subnet)
2026 {
2027 subnet->addr = addr;
Mathias Kresin094bfae2016-07-24 14:15:22 +01002028
2029 if (is_exclude)
2030 {
2031 subnet->next = new->exclude;
2032 new->exclude = subnet;
2033 }
2034 else
2035 {
2036 subnet->next = new->subnet;
2037 new->subnet = subnet;
2038 }
Simon Kelley376d48c2013-11-13 13:04:30 +00002039 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002040 }
2041 break;
2042 }
Simon Kelley376d48c2013-11-13 13:04:30 +00002043
Simon Kelley4f7b3042012-11-28 21:27:02 +00002044 case LOPT_AUTHSOA: /* --auth-soa */
2045 comma = split(arg);
Simon Kelley5c72bb92013-08-19 14:12:59 +01002046 daemon->soa_sn = (u32)atoi(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002047 if (comma)
2048 {
Simon Kelley86e3b9a2012-11-30 13:46:48 +00002049 char *cp;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002050 arg = comma;
2051 comma = split(arg);
2052 daemon->hostmaster = opt_string_alloc(arg);
Simon Kelley86e3b9a2012-11-30 13:46:48 +00002053 for (cp = daemon->hostmaster; *cp; cp++)
2054 if (*cp == '@')
2055 *cp = '.';
2056
Simon Kelley4f7b3042012-11-28 21:27:02 +00002057 if (comma)
2058 {
2059 arg = comma;
2060 comma = split(arg);
Simon Kelley5c72bb92013-08-19 14:12:59 +01002061 daemon->soa_refresh = (u32)atoi(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002062 if (comma)
2063 {
2064 arg = comma;
2065 comma = split(arg);
Simon Kelley5c72bb92013-08-19 14:12:59 +01002066 daemon->soa_retry = (u32)atoi(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002067 if (comma)
Simon Kelley407a1f32016-03-01 17:06:07 +00002068 daemon->soa_expiry = (u32)atoi(comma);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002069 }
2070 }
2071 }
2072
2073 break;
Simon Kelleyf373a152013-09-23 12:47:47 +01002074#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00002075
Simon Kelley2bb73af2013-04-24 17:38:19 +01002076 case 's': /* --domain */
2077 case LOPT_SYNTH: /* --synth-domain */
Simon Kelley849a8352006-06-09 21:02:31 +01002078 if (strcmp (arg, "#") == 0)
Simon Kelley28866e92011-02-14 20:19:14 +00002079 set_option_bool(OPT_RESOLV_DOMAIN);
Simon Kelley849a8352006-06-09 21:02:31 +01002080 else
Simon Kelley9009d742008-11-14 20:04:27 +00002081 {
Simon Kelley1f15b812009-10-13 17:49:32 +01002082 char *d;
Simon Kelley9009d742008-11-14 20:04:27 +00002083 comma = split(arg);
Simon Kelley1f15b812009-10-13 17:49:32 +01002084 if (!(d = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002085 ret_err(gen_err);
Simon Kelley9009d742008-11-14 20:04:27 +00002086 else
2087 {
Simon Kelley9009d742008-11-14 20:04:27 +00002088 if (comma)
2089 {
Simon Kelley429798f2012-12-10 20:45:53 +00002090 struct cond_domain *new = opt_malloc(sizeof(struct cond_domain));
Simon Kelley28866e92011-02-14 20:19:14 +00002091 char *netpart;
Simon Kelley2bb73af2013-04-24 17:38:19 +01002092
Simon Kelley48fd1c42013-04-25 09:49:38 +01002093 new->prefix = NULL;
Simon Kelley6b2b5642018-03-10 18:12:04 +00002094 new->indexed = 0;
2095
Simon Kelley9009d742008-11-14 20:04:27 +00002096 unhide_metas(comma);
Simon Kelley28866e92011-02-14 20:19:14 +00002097 if ((netpart = split_chr(comma, '/')))
Simon Kelley9009d742008-11-14 20:04:27 +00002098 {
Simon Kelleyd74942a2012-02-07 20:51:56 +00002099 int msize;
2100
Simon Kelley28866e92011-02-14 20:19:14 +00002101 arg = split(netpart);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002102 if (!atoi_check(netpart, &msize))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002103 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002104 else if (inet_pton(AF_INET, comma, &new->start))
Simon Kelley9009d742008-11-14 20:04:27 +00002105 {
Simon Kelleyd74942a2012-02-07 20:51:56 +00002106 int mask = (1 << (32 - msize)) - 1;
2107 new->is6 = 0;
Simon Kelley9009d742008-11-14 20:04:27 +00002108 new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask);
2109 new->end.s_addr = new->start.s_addr | htonl(mask);
Simon Kelley28866e92011-02-14 20:19:14 +00002110 if (arg)
2111 {
Simon Kelley48fd1c42013-04-25 09:49:38 +01002112 if (option != 's')
Simon Kelleyb5a7ff42013-04-25 11:03:47 +01002113 {
2114 if (!(new->prefix = canonicalise_opt(arg)) ||
2115 strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
2116 ret_err(_("bad prefix"));
2117 }
Simon Kelley48fd1c42013-04-25 09:49:38 +01002118 else if (strcmp(arg, "local") != 0 ||
2119 (msize != 8 && msize != 16 && msize != 24))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002120 ret_err(gen_err);
Simon Kelley28866e92011-02-14 20:19:14 +00002121 else
2122 {
Simon Kelleyde73a492014-02-17 21:43:27 +00002123 /* generate the equivalent of
Simon Kelleyde73a492014-02-17 21:43:27 +00002124 local=/xxx.yyy.zzz.in-addr.arpa/ */
2125 struct server *serv = add_rev4(new->start, msize);
Olivier Gayotdc990582017-03-06 22:17:21 +00002126 if (!serv)
2127 ret_err(_("bad prefix"));
2128
Simon Kelleyde73a492014-02-17 21:43:27 +00002129 serv->flags |= SERV_NO_ADDR;
Simon Kelley3ad3f3b2014-12-16 18:25:17 +00002130
2131 /* local=/<domain>/ */
2132 serv = opt_malloc(sizeof(struct server));
2133 memset(serv, 0, sizeof(struct server));
2134 serv->domain = d;
2135 serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
2136 serv->next = daemon->servers;
2137 daemon->servers = serv;
Simon Kelley28866e92011-02-14 20:19:14 +00002138 }
2139 }
Simon Kelley9009d742008-11-14 20:04:27 +00002140 }
Simon Kelleyd74942a2012-02-07 20:51:56 +00002141#ifdef HAVE_IPV6
2142 else if (inet_pton(AF_INET6, comma, &new->start6))
2143 {
2144 u64 mask = (1LLU << (128 - msize)) - 1LLU;
2145 u64 addrpart = addr6part(&new->start6);
2146 new->is6 = 1;
Simon Kelley48fd1c42013-04-25 09:49:38 +01002147
Simon Kelleyd74942a2012-02-07 20:51:56 +00002148 /* prefix==64 overflows the mask calculation above */
2149 if (msize == 64)
2150 mask = (u64)-1LL;
Simon Kelley48fd1c42013-04-25 09:49:38 +01002151
Simon Kelleyd74942a2012-02-07 20:51:56 +00002152 new->end6 = new->start6;
2153 setaddr6part(&new->start6, addrpart & ~mask);
2154 setaddr6part(&new->end6, addrpart | mask);
2155
2156 if (msize < 64)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002157 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002158 else if (arg)
2159 {
Simon Kelley48fd1c42013-04-25 09:49:38 +01002160 if (option != 's')
Simon Kelleyb5a7ff42013-04-25 11:03:47 +01002161 {
2162 if (!(new->prefix = canonicalise_opt(arg)) ||
2163 strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
2164 ret_err(_("bad prefix"));
2165 }
Simon Kelley48fd1c42013-04-25 09:49:38 +01002166 else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002167 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002168 else
2169 {
Simon Kelley48fd1c42013-04-25 09:49:38 +01002170 /* generate the equivalent of
Simon Kelley48fd1c42013-04-25 09:49:38 +01002171 local=/xxx.yyy.zzz.ip6.arpa/ */
Simon Kelleyde73a492014-02-17 21:43:27 +00002172 struct server *serv = add_rev6(&new->start6, msize);
2173 serv->flags |= SERV_NO_ADDR;
Simon Kelley3ad3f3b2014-12-16 18:25:17 +00002174
2175 /* local=/<domain>/ */
2176 serv = opt_malloc(sizeof(struct server));
2177 memset(serv, 0, sizeof(struct server));
2178 serv->domain = d;
2179 serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
2180 serv->next = daemon->servers;
2181 daemon->servers = serv;
Simon Kelleyd74942a2012-02-07 20:51:56 +00002182 }
2183 }
2184 }
2185#endif
2186 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002187 ret_err(gen_err);
Simon Kelley9009d742008-11-14 20:04:27 +00002188 }
Simon Kelleyeec5c1e2013-10-25 10:37:30 +01002189 else
Simon Kelleyd74942a2012-02-07 20:51:56 +00002190 {
Simon Kelleyeec5c1e2013-10-25 10:37:30 +01002191 char *prefstr;
Simon Kelleyd74942a2012-02-07 20:51:56 +00002192 arg = split(comma);
Simon Kelleyeec5c1e2013-10-25 10:37:30 +01002193 prefstr = split(arg);
2194
Simon Kelleyd74942a2012-02-07 20:51:56 +00002195 if (inet_pton(AF_INET, comma, &new->start))
2196 {
2197 new->is6 = 0;
2198 if (!arg)
2199 new->end.s_addr = new->start.s_addr;
2200 else if (!inet_pton(AF_INET, arg, &new->end))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002201 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002202 }
2203#ifdef HAVE_IPV6
2204 else if (inet_pton(AF_INET6, comma, &new->start6))
2205 {
2206 new->is6 = 1;
2207 if (!arg)
2208 memcpy(&new->end6, &new->start6, IN6ADDRSZ);
2209 else if (!inet_pton(AF_INET6, arg, &new->end6))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002210 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002211 }
2212#endif
2213 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002214 ret_err(gen_err);
Simon Kelleyeec5c1e2013-10-25 10:37:30 +01002215
2216 if (option != 's' && prefstr)
2217 {
2218 if (!(new->prefix = canonicalise_opt(prefstr)) ||
2219 strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
2220 ret_err(_("bad prefix"));
2221 }
Simon Kelleyd74942a2012-02-07 20:51:56 +00002222 }
Simon Kelley2307eac2012-02-13 10:13:13 +00002223
2224 new->domain = d;
Simon Kelley2bb73af2013-04-24 17:38:19 +01002225 if (option == 's')
2226 {
2227 new->next = daemon->cond_domain;
2228 daemon->cond_domain = new;
2229 }
2230 else
2231 {
Simon Kelley6b2b5642018-03-10 18:12:04 +00002232 char *star;
Simon Kelley2bb73af2013-04-24 17:38:19 +01002233 new->next = daemon->synth_domains;
2234 daemon->synth_domains = new;
Simon Kelley6b2b5642018-03-10 18:12:04 +00002235 if ((star = strrchr(new->prefix, '*')) && *(star+1) == 0)
2236 {
2237 *star = 0;
2238 new->indexed = 1;
2239 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01002240 }
Simon Kelley9009d742008-11-14 20:04:27 +00002241 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01002242 else if (option == 's')
Simon Kelley9009d742008-11-14 20:04:27 +00002243 daemon->domain_suffix = d;
Simon Kelley2bb73af2013-04-24 17:38:19 +01002244 else
2245 ret_err(gen_err);
Simon Kelley9009d742008-11-14 20:04:27 +00002246 }
2247 }
Simon Kelley849a8352006-06-09 21:02:31 +01002248 break;
2249
Simon Kelley1e505122016-01-25 21:29:23 +00002250 case LOPT_CPE_ID: /* --add-dns-client */
2251 if (arg)
Simon Kelley33702ab2015-12-28 23:17:15 +00002252 daemon->dns_client_id = opt_string_alloc(arg);
2253 break;
2254
Simon Kelleyc7f3bd22016-02-28 21:48:34 +00002255 case LOPT_ADD_MAC: /* --add-mac */
Simon Kelley1e505122016-01-25 21:29:23 +00002256 if (!arg)
2257 set_option_bool(OPT_ADD_MAC);
2258 else
2259 {
2260 unhide_metas(arg);
2261 if (strcmp(arg, "base64") == 0)
2262 set_option_bool(OPT_MAC_B64);
Simon Kelley9e4cf472016-02-17 20:26:32 +00002263 else if (strcmp(arg, "text") == 0)
2264 set_option_bool(OPT_MAC_HEX);
Simon Kelley22c0f4f2016-02-17 22:12:31 +00002265 else
2266 ret_err(gen_err);
Simon Kelley1e505122016-01-25 21:29:23 +00002267 }
2268 break;
2269
Simon Kelleyf2621c72007-04-29 19:47:21 +01002270 case 'u': /* --user */
Simon Kelley824af852008-02-12 20:43:05 +00002271 daemon->username = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002272 break;
2273
Simon Kelleyf2621c72007-04-29 19:47:21 +01002274 case 'g': /* --group */
Simon Kelley824af852008-02-12 20:43:05 +00002275 daemon->groupname = opt_string_alloc(arg);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002276 daemon->group_set = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01002277 break;
Simon Kelley9e038942008-05-30 20:06:34 +01002278
Simon Kelley7622fc02009-06-04 20:32:05 +01002279#ifdef HAVE_DHCP
Simon Kelley9e038942008-05-30 20:06:34 +01002280 case LOPT_SCRIPTUSR: /* --scriptuser */
2281 daemon->scriptuser = opt_string_alloc(arg);
2282 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01002283#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002284
Simon Kelleyf2621c72007-04-29 19:47:21 +01002285 case 'i': /* --interface */
Simon Kelley849a8352006-06-09 21:02:31 +01002286 do {
Simon Kelley824af852008-02-12 20:43:05 +00002287 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01002288 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002289 new->next = daemon->if_names;
2290 daemon->if_names = new;
2291 /* new->name may be NULL if someone does
2292 "interface=" to disable all interfaces except loop. */
Simon Kelley824af852008-02-12 20:43:05 +00002293 new->name = opt_string_alloc(arg);
Simon Kelley4ce4f372012-06-14 11:50:45 +01002294 new->used = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002295 arg = comma;
2296 } while (arg);
2297 break;
2298
Simon Kelley2937f8a2013-07-29 19:49:07 +01002299 case LOPT_TFTP: /* --enable-tftp */
2300 set_option_bool(OPT_TFTP);
2301 if (!arg)
2302 break;
2303 /* fall through */
2304
Simon Kelleyf2621c72007-04-29 19:47:21 +01002305 case 'I': /* --except-interface */
2306 case '2': /* --no-dhcp-interface */
Simon Kelley849a8352006-06-09 21:02:31 +01002307 do {
Simon Kelley824af852008-02-12 20:43:05 +00002308 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01002309 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00002310 new->name = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002311 if (option == 'I')
2312 {
2313 new->next = daemon->if_except;
2314 daemon->if_except = new;
2315 }
Simon Kelley2937f8a2013-07-29 19:49:07 +01002316 else if (option == LOPT_TFTP)
2317 {
2318 new->next = daemon->tftp_interfaces;
2319 daemon->tftp_interfaces = new;
2320 }
Simon Kelley849a8352006-06-09 21:02:31 +01002321 else
2322 {
2323 new->next = daemon->dhcp_except;
2324 daemon->dhcp_except = new;
2325 }
2326 arg = comma;
2327 } while (arg);
2328 break;
2329
Simon Kelleyf2621c72007-04-29 19:47:21 +01002330 case 'B': /* --bogus-nxdomain */
Glen Huang32fc6db2014-12-27 15:28:12 +00002331 case LOPT_IGNORE_ADDR: /* --ignore-address */
2332 {
Simon Kelley849a8352006-06-09 21:02:31 +01002333 struct in_addr addr;
2334 unhide_metas(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002335 if (arg && (inet_pton(AF_INET, arg, &addr) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01002336 {
Simon Kelley824af852008-02-12 20:43:05 +00002337 struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
Glen Huang32fc6db2014-12-27 15:28:12 +00002338 if (option == 'B')
2339 {
2340 baddr->next = daemon->bogus_addr;
2341 daemon->bogus_addr = baddr;
2342 }
2343 else
2344 {
2345 baddr->next = daemon->ignore_addr;
2346 daemon->ignore_addr = baddr;
2347 }
Simon Kelley849a8352006-06-09 21:02:31 +01002348 baddr->addr = addr;
2349 }
2350 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002351 ret_err(gen_err); /* error */
Simon Kelley849a8352006-06-09 21:02:31 +01002352 break;
2353 }
2354
Simon Kelleyf2621c72007-04-29 19:47:21 +01002355 case 'a': /* --listen-address */
Simon Kelley49678762012-12-09 18:24:58 +00002356 case LOPT_AUTHPEER: /* --auth-peer */
Simon Kelley849a8352006-06-09 21:02:31 +01002357 do {
Simon Kelley824af852008-02-12 20:43:05 +00002358 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01002359 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002360 unhide_metas(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002361 if (arg && (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01002362 {
2363 new->addr.sa.sa_family = AF_INET;
Simon Kelley49678762012-12-09 18:24:58 +00002364 new->addr.in.sin_port = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002365#ifdef HAVE_SOCKADDR_SA_LEN
2366 new->addr.in.sin_len = sizeof(new->addr.in);
2367#endif
2368 }
2369#ifdef HAVE_IPV6
2370 else if (arg && inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
2371 {
2372 new->addr.sa.sa_family = AF_INET6;
2373 new->addr.in6.sin6_flowinfo = 0;
2374 new->addr.in6.sin6_scope_id = 0;
Simon Kelley49678762012-12-09 18:24:58 +00002375 new->addr.in6.sin6_port = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002376#ifdef HAVE_SOCKADDR_SA_LEN
2377 new->addr.in6.sin6_len = sizeof(new->addr.in6);
2378#endif
2379 }
2380#endif
2381 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002382 ret_err(gen_err);
Simon Kelley4ce4f372012-06-14 11:50:45 +01002383
2384 new->used = 0;
Simon Kelley49678762012-12-09 18:24:58 +00002385 if (option == 'a')
2386 {
2387 new->next = daemon->if_addrs;
2388 daemon->if_addrs = new;
2389 }
2390 else
2391 {
2392 new->next = daemon->auth_peers;
2393 daemon->auth_peers = new;
2394 }
Simon Kelley849a8352006-06-09 21:02:31 +01002395 arg = comma;
2396 } while (arg);
2397 break;
2398
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002399 case 'S': /* --server */
2400 case LOPT_LOCAL: /* --local */
2401 case 'A': /* --address */
2402 case LOPT_NO_REBIND: /* --rebind-domain-ok */
Simon Kelley849a8352006-06-09 21:02:31 +01002403 {
2404 struct server *serv, *newlist = NULL;
2405
2406 unhide_metas(arg);
2407
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002408 if (arg && (*arg == '/' || option == LOPT_NO_REBIND))
Simon Kelley849a8352006-06-09 21:02:31 +01002409 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002410 int rebind = !(*arg == '/');
2411 char *end = NULL;
2412 if (!rebind)
2413 arg++;
2414 while (rebind || (end = split_chr(arg, '/')))
Simon Kelley849a8352006-06-09 21:02:31 +01002415 {
2416 char *domain = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002417 /* elide leading dots - they are implied in the search algorithm */
2418 while (*arg == '.') arg++;
Simon Kelley849a8352006-06-09 21:02:31 +01002419 /* # matches everything and becomes a zero length domain string */
2420 if (strcmp(arg, "#") == 0)
2421 domain = "";
Simon Kelley1f15b812009-10-13 17:49:32 +01002422 else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
Simon Kelleya3bd7e72018-07-19 22:00:08 +01002423 ret_err(gen_err);
Simon Kelley824af852008-02-12 20:43:05 +00002424 serv = opt_malloc(sizeof(struct server));
2425 memset(serv, 0, sizeof(struct server));
Simon Kelley849a8352006-06-09 21:02:31 +01002426 serv->next = newlist;
2427 newlist = serv;
Simon Kelley849a8352006-06-09 21:02:31 +01002428 serv->domain = domain;
2429 serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
Simon Kelley73a08a22009-02-05 20:28:08 +00002430 arg = end;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002431 if (rebind)
2432 break;
Simon Kelley849a8352006-06-09 21:02:31 +01002433 }
2434 if (!newlist)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002435 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002436 }
2437 else
2438 {
Simon Kelley824af852008-02-12 20:43:05 +00002439 newlist = opt_malloc(sizeof(struct server));
2440 memset(newlist, 0, sizeof(struct server));
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002441#ifdef HAVE_LOOP
2442 newlist->uid = rand32();
2443#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002444 }
2445
Simon Kelley7b1eae42014-02-20 13:43:28 +00002446 if (servers_only && option == 'S')
2447 newlist->flags |= SERV_FROM_FILE;
2448
Simon Kelley849a8352006-06-09 21:02:31 +01002449 if (option == 'A')
2450 {
2451 newlist->flags |= SERV_LITERAL_ADDRESS;
2452 if (!(newlist->flags & SERV_TYPE))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002453 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002454 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002455 else if (option == LOPT_NO_REBIND)
2456 newlist->flags |= SERV_NO_REBIND;
Simon Kelley849a8352006-06-09 21:02:31 +01002457
2458 if (!arg || !*arg)
2459 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002460 if (!(newlist->flags & SERV_NO_REBIND))
2461 newlist->flags |= SERV_NO_ADDR; /* no server */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002462 }
2463
2464 else if (strcmp(arg, "#") == 0)
2465 {
2466 newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
Simon Kelley849a8352006-06-09 21:02:31 +01002467 if (newlist->flags & SERV_LITERAL_ADDRESS)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002468 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002469 }
2470 else
2471 {
Simon Kelleyfaafb3f2012-09-20 14:17:39 +01002472 char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
2473 if (err)
2474 ret_err(err);
Simon Kelley849a8352006-06-09 21:02:31 +01002475 }
2476
Simon Kelleyf2621c72007-04-29 19:47:21 +01002477 serv = newlist;
2478 while (serv->next)
Simon Kelley849a8352006-06-09 21:02:31 +01002479 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01002480 serv->next->flags = serv->flags;
2481 serv->next->addr = serv->addr;
2482 serv->next->source_addr = serv->source_addr;
Simon Kelleyfaafb3f2012-09-20 14:17:39 +01002483 strcpy(serv->next->interface, serv->interface);
Simon Kelleyf2621c72007-04-29 19:47:21 +01002484 serv = serv->next;
Simon Kelley849a8352006-06-09 21:02:31 +01002485 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01002486 serv->next = daemon->servers;
2487 daemon->servers = newlist;
Simon Kelley849a8352006-06-09 21:02:31 +01002488 break;
2489 }
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002490
Simon Kelleyde73a492014-02-17 21:43:27 +00002491 case LOPT_REV_SERV: /* --rev-server */
2492 {
2493 char *string;
2494 int size;
2495 struct server *serv;
2496 struct in_addr addr4;
2497#ifdef HAVE_IPV6
2498 struct in6_addr addr6;
2499#endif
2500
2501 unhide_metas(arg);
2502 if (!arg || !(comma=split(arg)) || !(string = split_chr(arg, '/')) || !atoi_check(string, &size))
2503 ret_err(gen_err);
2504
2505 if (inet_pton(AF_INET, arg, &addr4))
Olivier Gayotdc990582017-03-06 22:17:21 +00002506 {
2507 serv = add_rev4(addr4, size);
2508 if (!serv)
2509 ret_err(_("bad prefix"));
2510 }
Simon Kelleyde73a492014-02-17 21:43:27 +00002511#ifdef HAVE_IPV6
2512 else if (inet_pton(AF_INET6, arg, &addr6))
2513 serv = add_rev6(&addr6, size);
2514#endif
2515 else
2516 ret_err(gen_err);
2517
2518 string = parse_server(comma, &serv->addr, &serv->source_addr, serv->interface, &serv->flags);
2519
2520 if (string)
2521 ret_err(string);
Simon Kelley7b1eae42014-02-20 13:43:28 +00002522
2523 if (servers_only)
2524 serv->flags |= SERV_FROM_FILE;
2525
Simon Kelleyde73a492014-02-17 21:43:27 +00002526 break;
2527 }
2528
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002529 case LOPT_IPSET: /* --ipset */
2530#ifndef HAVE_IPSET
2531 ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
2532 break;
2533#else
2534 {
2535 struct ipsets ipsets_head;
2536 struct ipsets *ipsets = &ipsets_head;
2537 int size;
2538 char *end;
2539 char **sets, **sets_pos;
2540 memset(ipsets, 0, sizeof(struct ipsets));
2541 unhide_metas(arg);
2542 if (arg && *arg == '/')
2543 {
2544 arg++;
2545 while ((end = split_chr(arg, '/')))
2546 {
2547 char *domain = NULL;
2548 /* elide leading dots - they are implied in the search algorithm */
2549 while (*arg == '.')
2550 arg++;
2551 /* # matches everything and becomes a zero length domain string */
2552 if (strcmp(arg, "#") == 0 || !*arg)
2553 domain = "";
2554 else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg)))
Simon Kelleya3bd7e72018-07-19 22:00:08 +01002555 ret_err(gen_err);
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002556 ipsets->next = opt_malloc(sizeof(struct ipsets));
2557 ipsets = ipsets->next;
2558 memset(ipsets, 0, sizeof(struct ipsets));
2559 ipsets->domain = domain;
2560 arg = end;
2561 }
2562 }
2563 else
2564 {
2565 ipsets->next = opt_malloc(sizeof(struct ipsets));
2566 ipsets = ipsets->next;
2567 memset(ipsets, 0, sizeof(struct ipsets));
2568 ipsets->domain = "";
2569 }
Simon Kelleya3bd7e72018-07-19 22:00:08 +01002570
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002571 if (!arg || !*arg)
Simon Kelleya3bd7e72018-07-19 22:00:08 +01002572 ret_err(gen_err);
2573
2574 for (size = 2, end = arg; *end; ++end)
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002575 if (*end == ',')
2576 ++size;
2577
2578 sets = sets_pos = opt_malloc(sizeof(char *) * size);
2579
2580 do {
2581 end = split(arg);
2582 *sets_pos++ = opt_string_alloc(arg);
2583 arg = end;
2584 } while (end);
2585 *sets_pos = 0;
2586 for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next)
2587 ipsets->next->sets = sets;
2588 ipsets->next = daemon->ipsets;
2589 daemon->ipsets = ipsets_head.next;
2590
2591 break;
2592 }
2593#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002594
Simon Kelleyf2621c72007-04-29 19:47:21 +01002595 case 'c': /* --cache-size */
Simon Kelley849a8352006-06-09 21:02:31 +01002596 {
2597 int size;
2598
2599 if (!atoi_check(arg, &size))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002600 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002601 else
2602 {
2603 /* zero is OK, and means no caching. */
2604
2605 if (size < 0)
2606 size = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002607
2608 daemon->cachesize = size;
2609 }
2610 break;
2611 }
2612
Simon Kelleyf2621c72007-04-29 19:47:21 +01002613 case 'p': /* --port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002614 if (!atoi_check16(arg, &daemon->port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002615 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002616 break;
Simon Kelley208b65c2006-08-05 21:41:37 +01002617
Simon Kelley1a6bca82008-07-11 11:11:42 +01002618 case LOPT_MINPORT: /* --min-port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002619 if (!atoi_check16(arg, &daemon->min_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002620 ret_err(gen_err);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002621 break;
2622
Hans Dedecker926332a2016-01-23 10:48:12 +00002623 case LOPT_MAXPORT: /* --max-port */
2624 if (!atoi_check16(arg, &daemon->max_port))
2625 ret_err(gen_err);
2626 break;
2627
Simon Kelleyf2621c72007-04-29 19:47:21 +01002628 case '0': /* --dns-forward-max */
Simon Kelley208b65c2006-08-05 21:41:37 +01002629 if (!atoi_check(arg, &daemon->ftabsize))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002630 ret_err(gen_err);
Simon Kelley208b65c2006-08-05 21:41:37 +01002631 break;
2632
Simon Kelley25cf5e32015-01-09 15:53:03 +00002633 case 'q': /* --log-queries */
2634 set_option_bool(OPT_LOG);
2635 if (arg && strcmp(arg, "extra") == 0)
2636 set_option_bool(OPT_EXTRALOG);
2637 break;
2638
Simon Kelleyf2621c72007-04-29 19:47:21 +01002639 case LOPT_MAX_LOGS: /* --log-async */
2640 daemon->max_logs = LOG_MAX; /* default */
2641 if (arg && !atoi_check(arg, &daemon->max_logs))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002642 ret_err(gen_err);
Simon Kelleyf2621c72007-04-29 19:47:21 +01002643 else if (daemon->max_logs > 100)
2644 daemon->max_logs = 100;
2645 break;
2646
2647 case 'P': /* --edns-packet-max */
Simon Kelley849a8352006-06-09 21:02:31 +01002648 {
2649 int i;
2650 if (!atoi_check(arg, &i))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002651 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002652 daemon->edns_pktsz = (unsigned short)i;
2653 break;
2654 }
2655
Simon Kelleyf2621c72007-04-29 19:47:21 +01002656 case 'Q': /* --query-port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002657 if (!atoi_check16(arg, &daemon->query_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002658 ret_err(gen_err);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002659 /* if explicitly set to zero, use single OS ephemeral port
2660 and disable random ports */
2661 if (daemon->query_port == 0)
2662 daemon->osport = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01002663 break;
2664
Simon Kelley824af852008-02-12 20:43:05 +00002665 case 'T': /* --local-ttl */
2666 case LOPT_NEGTTL: /* --neg-ttl */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002667 case LOPT_MAXTTL: /* --max-ttl */
RinSatsuki28de3872015-01-10 15:22:21 +00002668 case LOPT_MINCTTL: /* --min-cache-ttl */
Simon Kelley1d860412012-09-20 20:48:04 +01002669 case LOPT_MAXCTTL: /* --max-cache-ttl */
Simon Kelley4f7b3042012-11-28 21:27:02 +00002670 case LOPT_AUTHTTL: /* --auth-ttl */
Simon Kelley832e47b2016-02-24 21:24:45 +00002671 case LOPT_DHCPTTL: /* --dhcp-ttl */
Simon Kelley849a8352006-06-09 21:02:31 +01002672 {
2673 int ttl;
2674 if (!atoi_check(arg, &ttl))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002675 ret_err(gen_err);
Simon Kelley824af852008-02-12 20:43:05 +00002676 else if (option == LOPT_NEGTTL)
2677 daemon->neg_ttl = (unsigned long)ttl;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002678 else if (option == LOPT_MAXTTL)
2679 daemon->max_ttl = (unsigned long)ttl;
RinSatsuki28de3872015-01-10 15:22:21 +00002680 else if (option == LOPT_MINCTTL)
2681 {
2682 if (ttl > TTL_FLOOR_LIMIT)
2683 ttl = TTL_FLOOR_LIMIT;
2684 daemon->min_cache_ttl = (unsigned long)ttl;
2685 }
Simon Kelley1d860412012-09-20 20:48:04 +01002686 else if (option == LOPT_MAXCTTL)
2687 daemon->max_cache_ttl = (unsigned long)ttl;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002688 else if (option == LOPT_AUTHTTL)
2689 daemon->auth_ttl = (unsigned long)ttl;
Simon Kelley832e47b2016-02-24 21:24:45 +00002690 else if (option == LOPT_DHCPTTL)
2691 {
2692 daemon->dhcp_ttl = (unsigned long)ttl;
2693 daemon->use_dhcp_ttl = 1;
2694 }
Simon Kelley849a8352006-06-09 21:02:31 +01002695 else
2696 daemon->local_ttl = (unsigned long)ttl;
2697 break;
2698 }
2699
Simon Kelley7622fc02009-06-04 20:32:05 +01002700#ifdef HAVE_DHCP
Simon Kelleyf2621c72007-04-29 19:47:21 +01002701 case 'X': /* --dhcp-lease-max */
Simon Kelley849a8352006-06-09 21:02:31 +01002702 if (!atoi_check(arg, &daemon->dhcp_max))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002703 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002704 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01002705#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002706
Simon Kelley7622fc02009-06-04 20:32:05 +01002707#ifdef HAVE_TFTP
Simon Kelleyf2621c72007-04-29 19:47:21 +01002708 case LOPT_TFTP_MAX: /* --tftp-max */
Simon Kelley832af0b2007-01-21 20:01:28 +00002709 if (!atoi_check(arg, &daemon->tftp_max))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002710 ret_err(gen_err);
Simon Kelley832af0b2007-01-21 20:01:28 +00002711 break;
2712
Simon Kelleybec366b2016-02-24 22:03:26 +00002713 case LOPT_TFTP_MTU: /* --tftp-mtu */
2714 if (!atoi_check(arg, &daemon->tftp_mtu))
2715 ret_err(gen_err);
2716 break;
2717
Simon Kelley824af852008-02-12 20:43:05 +00002718 case LOPT_PREFIX: /* --tftp-prefix */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002719 comma = split(arg);
2720 if (comma)
2721 {
2722 struct tftp_prefix *new = opt_malloc(sizeof(struct tftp_prefix));
2723 new->interface = opt_string_alloc(comma);
2724 new->prefix = opt_string_alloc(arg);
2725 new->next = daemon->if_prefix;
2726 daemon->if_prefix = new;
2727 }
2728 else
2729 daemon->tftp_prefix = opt_string_alloc(arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00002730 break;
2731
Simon Kelley824af852008-02-12 20:43:05 +00002732 case LOPT_TFTPPORTS: /* --tftp-port-range */
2733 if (!(comma = split(arg)) ||
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002734 !atoi_check16(arg, &daemon->start_tftp_port) ||
2735 !atoi_check16(comma, &daemon->end_tftp_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002736 ret_err(_("bad port range"));
Simon Kelley824af852008-02-12 20:43:05 +00002737
2738 if (daemon->start_tftp_port > daemon->end_tftp_port)
2739 {
2740 int tmp = daemon->start_tftp_port;
2741 daemon->start_tftp_port = daemon->end_tftp_port;
2742 daemon->end_tftp_port = tmp;
2743 }
2744
2745 break;
Floris Bos60704f52017-04-09 22:22:49 +01002746
2747 case LOPT_APREF: /* --tftp-unique-root */
2748 if (!arg || strcasecmp(arg, "ip") == 0)
2749 set_option_bool(OPT_TFTP_APREF_IP);
2750 else if (strcasecmp(arg, "mac") == 0)
2751 set_option_bool(OPT_TFTP_APREF_MAC);
2752 else
2753 ret_err(gen_err);
2754 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01002755#endif
Simon Kelley824af852008-02-12 20:43:05 +00002756
Simon Kelleyf2621c72007-04-29 19:47:21 +01002757 case LOPT_BRIDGE: /* --bridge-interface */
Simon Kelley832af0b2007-01-21 20:01:28 +00002758 {
Simon Kelley22cd8602018-01-14 22:57:14 +00002759 struct dhcp_bridge *new;
2760
Simon Kelley316e2732010-01-22 20:16:09 +00002761 if (!(comma = split(arg)) || strlen(arg) > IF_NAMESIZE - 1 )
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002762 ret_err(_("bad bridge-interface"));
Simon Kelley832af0b2007-01-21 20:01:28 +00002763
Simon Kelley22cd8602018-01-14 22:57:14 +00002764 for (new = daemon->bridges; new; new = new->next)
2765 if (strcmp(new->iface, arg) == 0)
2766 break;
2767
2768 if (!new)
2769 {
2770 new = opt_malloc(sizeof(struct dhcp_bridge));
2771 strcpy(new->iface, arg);
2772 new->alias = NULL;
2773 new->next = daemon->bridges;
2774 daemon->bridges = new;
2775 }
2776
Simon Kelley832af0b2007-01-21 20:01:28 +00002777 do {
Simon Kelleyf2621c72007-04-29 19:47:21 +01002778 arg = comma;
2779 comma = split(arg);
Simon Kelley316e2732010-01-22 20:16:09 +00002780 if (strlen(arg) != 0 && strlen(arg) <= IF_NAMESIZE - 1)
Simon Kelley832af0b2007-01-21 20:01:28 +00002781 {
Simon Kelley824af852008-02-12 20:43:05 +00002782 struct dhcp_bridge *b = opt_malloc(sizeof(struct dhcp_bridge));
Simon Kelley832af0b2007-01-21 20:01:28 +00002783 b->next = new->alias;
2784 new->alias = b;
Simon Kelley316e2732010-01-22 20:16:09 +00002785 strcpy(b->iface, arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00002786 }
2787 } while (comma);
2788
2789 break;
2790 }
Simon Kelley832af0b2007-01-21 20:01:28 +00002791
Simon Kelley7622fc02009-06-04 20:32:05 +01002792#ifdef HAVE_DHCP
Simon Kelleyf2621c72007-04-29 19:47:21 +01002793 case 'F': /* --dhcp-range */
Simon Kelley849a8352006-06-09 21:02:31 +01002794 {
2795 int k, leasepos = 2;
Simon Kelley8445f5d2012-12-17 21:54:08 +00002796 char *cp, *a[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
Simon Kelley824af852008-02-12 20:43:05 +00002797 struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
Simon Kelley849a8352006-06-09 21:02:31 +01002798
Simon Kelley52b92f42012-01-22 16:05:15 +00002799 memset (new, 0, sizeof(*new));
Simon Kelley849a8352006-06-09 21:02:31 +01002800 new->lease_time = DEFLEASE;
Simon Kelley52b92f42012-01-22 16:05:15 +00002801
Simon Kelley849a8352006-06-09 21:02:31 +01002802 while(1)
2803 {
2804 for (cp = arg; *cp; cp++)
Simon Kelley52b92f42012-01-22 16:05:15 +00002805 if (!(*cp == ' ' || *cp == '.' || *cp == ':' ||
2806 (*cp >= 'a' && *cp <= 'f') || (*cp >= 'A' && *cp <= 'F') ||
2807 (*cp >='0' && *cp <= '9')))
Simon Kelley849a8352006-06-09 21:02:31 +01002808 break;
2809
Simon Kelleyf2621c72007-04-29 19:47:21 +01002810 if (*cp != ',' && (comma = split(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01002811 {
Simon Kelley8bc4cec2012-07-03 21:04:11 +01002812 if (is_tag_prefix(arg))
Simon Kelley849a8352006-06-09 21:02:31 +01002813 {
Simon Kelley824af852008-02-12 20:43:05 +00002814 struct dhcp_netid *tt = opt_malloc(sizeof (struct dhcp_netid));
2815 tt->net = opt_string_alloc(arg+4);
Simon Kelley849a8352006-06-09 21:02:31 +01002816 tt->next = new->filter;
Simon Kelley0c387192013-09-05 10:21:12 +01002817 /* ignore empty tag */
2818 if (tt->net)
2819 new->filter = tt;
Simon Kelley849a8352006-06-09 21:02:31 +01002820 }
2821 else
2822 {
2823 if (new->netid.net)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002824 ret_err(_("only one tag allowed"));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002825 else if (strstr(arg, "set:") == arg)
2826 new->netid.net = opt_string_alloc(arg+4);
Simon Kelley849a8352006-06-09 21:02:31 +01002827 else
Simon Kelley824af852008-02-12 20:43:05 +00002828 new->netid.net = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002829 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01002830 arg = comma;
Simon Kelley849a8352006-06-09 21:02:31 +01002831 }
2832 else
2833 {
2834 a[0] = arg;
2835 break;
2836 }
2837 }
2838
Simon Kelley1f776932012-12-16 19:46:08 +00002839 for (k = 1; k < 8; k++)
Simon Kelleyf2621c72007-04-29 19:47:21 +01002840 if (!(a[k] = split(a[k-1])))
2841 break;
Simon Kelley849a8352006-06-09 21:02:31 +01002842
Simon Kelley52b92f42012-01-22 16:05:15 +00002843 if (k < 2)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002844 ret_err(_("bad dhcp-range"));
2845
2846 if (inet_pton(AF_INET, a[0], &new->start))
Simon Kelley849a8352006-06-09 21:02:31 +01002847 {
Simon Kelley52b92f42012-01-22 16:05:15 +00002848 new->next = daemon->dhcp;
2849 daemon->dhcp = new;
Simon Kelley30cd9662012-03-25 20:44:38 +01002850 new->end = new->start;
Simon Kelley52b92f42012-01-22 16:05:15 +00002851 if (strcmp(a[1], "static") == 0)
Simon Kelley30cd9662012-03-25 20:44:38 +01002852 new->flags |= CONTEXT_STATIC;
Simon Kelley52b92f42012-01-22 16:05:15 +00002853 else if (strcmp(a[1], "proxy") == 0)
Simon Kelley30cd9662012-03-25 20:44:38 +01002854 new->flags |= CONTEXT_PROXY;
2855 else if (!inet_pton(AF_INET, a[1], &new->end))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002856 ret_err(_("bad dhcp-range"));
Simon Kelley52b92f42012-01-22 16:05:15 +00002857
2858 if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
2859 {
2860 struct in_addr tmp = new->start;
2861 new->start = new->end;
2862 new->end = tmp;
2863 }
2864
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002865 if (k >= 3 && strchr(a[2], '.') &&
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002866 (inet_pton(AF_INET, a[2], &new->netmask) > 0))
Simon Kelley52b92f42012-01-22 16:05:15 +00002867 {
2868 new->flags |= CONTEXT_NETMASK;
2869 leasepos = 3;
2870 if (!is_same_net(new->start, new->end, new->netmask))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002871 ret_err(_("inconsistent DHCP range"));
Simon Kelleyfa794662016-03-03 20:33:54 +00002872
Simon Kelley52b92f42012-01-22 16:05:15 +00002873
Simon Kelleyfa794662016-03-03 20:33:54 +00002874 if (k >= 4 && strchr(a[3], '.') &&
2875 (inet_pton(AF_INET, a[3], &new->broadcast) > 0))
2876 {
2877 new->flags |= CONTEXT_BRDCAST;
2878 leasepos = 4;
2879 }
Simon Kelley52b92f42012-01-22 16:05:15 +00002880 }
Simon Kelley849a8352006-06-09 21:02:31 +01002881 }
Simon Kelley52b92f42012-01-22 16:05:15 +00002882#ifdef HAVE_DHCP6
2883 else if (inet_pton(AF_INET6, a[0], &new->start6))
Simon Kelley7622fc02009-06-04 20:32:05 +01002884 {
Simon Kelley89500e32013-09-20 16:29:20 +01002885 new->flags |= CONTEXT_V6;
Simon Kelley52b92f42012-01-22 16:05:15 +00002886 new->prefix = 64; /* default */
Simon Kelley30cd9662012-03-25 20:44:38 +01002887 new->end6 = new->start6;
Simon Kelley6692a1a2013-08-20 14:41:31 +01002888 new->next = daemon->dhcp6;
2889 daemon->dhcp6 = new;
2890
Simon Kelley30cd9662012-03-25 20:44:38 +01002891 for (leasepos = 1; leasepos < k; leasepos++)
2892 {
2893 if (strcmp(a[leasepos], "static") == 0)
2894 new->flags |= CONTEXT_STATIC | CONTEXT_DHCP;
2895 else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 )
Simon Kelley7ea3d3f2014-04-25 22:04:05 +01002896 new->flags |= CONTEXT_RA;
Simon Kelley30cd9662012-03-25 20:44:38 +01002897 else if (strcmp(a[leasepos], "ra-names") == 0)
Simon Kelley1f776932012-12-16 19:46:08 +00002898 new->flags |= CONTEXT_RA_NAME | CONTEXT_RA;
Simon Kelley7ea3d3f2014-04-25 22:04:05 +01002899 else if (strcmp(a[leasepos], "ra-advrouter") == 0)
2900 new->flags |= CONTEXT_RA_ROUTER | CONTEXT_RA;
Simon Kelley30cd9662012-03-25 20:44:38 +01002901 else if (strcmp(a[leasepos], "ra-stateless") == 0)
Simon Kelley1f776932012-12-16 19:46:08 +00002902 new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA;
Neil Jerram2fd5bc92015-06-10 22:13:06 +01002903 else if (strcmp(a[leasepos], "off-link") == 0)
2904 new->flags |= CONTEXT_RA_OFF_LINK;
Simon Kelley30cd9662012-03-25 20:44:38 +01002905 else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6))
2906 new->flags |= CONTEXT_DHCP;
Simon Kelley1f776932012-12-16 19:46:08 +00002907 else if (strstr(a[leasepos], "constructor:") == a[leasepos])
2908 {
2909 new->template_interface = opt_string_alloc(a[leasepos] + 12);
2910 new->flags |= CONTEXT_TEMPLATE;
2911 }
Simon Kelley30cd9662012-03-25 20:44:38 +01002912 else
2913 break;
2914 }
Simon Kelley6692a1a2013-08-20 14:41:31 +01002915
Simon Kelley52b92f42012-01-22 16:05:15 +00002916 /* bare integer < 128 is prefix value */
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002917 if (leasepos < k)
Simon Kelley52b92f42012-01-22 16:05:15 +00002918 {
2919 int pref;
Simon Kelley30cd9662012-03-25 20:44:38 +01002920 for (cp = a[leasepos]; *cp; cp++)
Simon Kelley52b92f42012-01-22 16:05:15 +00002921 if (!(*cp >= '0' && *cp <= '9'))
2922 break;
Simon Kelley30cd9662012-03-25 20:44:38 +01002923 if (!*cp && (pref = atoi(a[leasepos])) <= 128)
Simon Kelley52b92f42012-01-22 16:05:15 +00002924 {
2925 new->prefix = pref;
Simon Kelley30cd9662012-03-25 20:44:38 +01002926 leasepos++;
Simon Kelley52b92f42012-01-22 16:05:15 +00002927 }
2928 }
Simon Kelley30cd9662012-03-25 20:44:38 +01002929
Simon Kelley6692a1a2013-08-20 14:41:31 +01002930 if (new->prefix != 64)
2931 {
Simon Kelley7ea3d3f2014-04-25 22:04:05 +01002932 if (new->flags & CONTEXT_RA)
Simon Kelley6692a1a2013-08-20 14:41:31 +01002933 ret_err(_("prefix length must be exactly 64 for RA subnets"));
2934 else if (new->flags & CONTEXT_TEMPLATE)
2935 ret_err(_("prefix length must be exactly 64 for subnet constructors"));
2936 }
2937
2938 if (new->prefix < 64)
2939 ret_err(_("prefix length must be at least 64"));
2940
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002941 if (!is_same_net6(&new->start6, &new->end6, new->prefix))
2942 ret_err(_("inconsistent DHCPv6 range"));
Simon Kelley6692a1a2013-08-20 14:41:31 +01002943
2944 /* dhcp-range=:: enables DHCP stateless on any interface */
2945 if (IN6_IS_ADDR_UNSPECIFIED(&new->start6) && !(new->flags & CONTEXT_TEMPLATE))
2946 new->prefix = 0;
Simon Kelley66409192013-08-01 20:19:32 +01002947
2948 if (new->flags & CONTEXT_TEMPLATE)
2949 {
2950 struct in6_addr zero;
2951 memset(&zero, 0, sizeof(zero));
2952 if (!is_same_net6(&zero, &new->start6, new->prefix))
2953 ret_err(_("prefix must be zero with \"constructor:\" argument"));
2954 }
2955
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002956 if (addr6part(&new->start6) > addr6part(&new->end6))
Simon Kelley52b92f42012-01-22 16:05:15 +00002957 {
2958 struct in6_addr tmp = new->start6;
2959 new->start6 = new->end6;
2960 new->end6 = tmp;
2961 }
Simon Kelley849a8352006-06-09 21:02:31 +01002962 }
Simon Kelley52b92f42012-01-22 16:05:15 +00002963#endif
Simon Kelleyd9ee9c02013-04-12 11:17:55 +01002964 else
2965 ret_err(_("bad dhcp-range"));
Simon Kelley849a8352006-06-09 21:02:31 +01002966
Simon Kelley30cd9662012-03-25 20:44:38 +01002967 if (leasepos < k)
Simon Kelley849a8352006-06-09 21:02:31 +01002968 {
Simon Kelleyfa794662016-03-03 20:33:54 +00002969 if (leasepos != k-1)
2970 ret_err(_("bad dhcp-range"));
2971
Simon Kelley849a8352006-06-09 21:02:31 +01002972 if (strcmp(a[leasepos], "infinite") == 0)
2973 new->lease_time = 0xffffffff;
Simon Kelleyc8257542012-03-28 21:15:41 +01002974 else if (strcmp(a[leasepos], "deprecated") == 0)
2975 new->flags |= CONTEXT_DEPRECATE;
Simon Kelley849a8352006-06-09 21:02:31 +01002976 else
2977 {
2978 int fac = 1;
2979 if (strlen(a[leasepos]) > 0)
2980 {
2981 switch (a[leasepos][strlen(a[leasepos]) - 1])
2982 {
Simon Kelley42243212012-07-20 15:19:18 +01002983 case 'w':
2984 case 'W':
2985 fac *= 7;
2986 /* fall through */
Simon Kelley849a8352006-06-09 21:02:31 +01002987 case 'd':
2988 case 'D':
2989 fac *= 24;
Simon Kelley87e00fe2018-02-16 21:27:35 +00002990 /* fall through */
Simon Kelley849a8352006-06-09 21:02:31 +01002991 case 'h':
2992 case 'H':
2993 fac *= 60;
2994 /* fall through */
2995 case 'm':
2996 case 'M':
2997 fac *= 60;
2998 /* fall through */
2999 case 's':
3000 case 'S':
Simon Kelleyf2621c72007-04-29 19:47:21 +01003001 a[leasepos][strlen(a[leasepos]) - 1] = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01003002 }
3003
Simon Kelleybe379862012-12-23 12:01:39 +00003004 for (cp = a[leasepos]; *cp; cp++)
3005 if (!(*cp >= '0' && *cp <= '9'))
3006 break;
3007
Simon Kelley54dae552013-02-05 17:55:10 +00003008 if (*cp || (leasepos+1 < k))
Simon Kelleybe379862012-12-23 12:01:39 +00003009 ret_err(_("bad dhcp-range"));
3010
Simon Kelley849a8352006-06-09 21:02:31 +01003011 new->lease_time = atoi(a[leasepos]) * fac;
3012 /* Leases of a minute or less confuse
3013 some clients, notably Apple's */
3014 if (new->lease_time < 120)
3015 new->lease_time = 120;
3016 }
3017 }
3018 }
3019 break;
3020 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01003021
Simon Kelley5aabfc72007-08-29 11:24:47 +01003022 case LOPT_BANK:
Simon Kelleyf2621c72007-04-29 19:47:21 +01003023 case 'G': /* --dhcp-host */
Simon Kelley849a8352006-06-09 21:02:31 +01003024 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01003025 int j, k = 0;
Simon Kelley3e8ed782013-05-29 14:31:33 +01003026 char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
Simon Kelley5aabfc72007-08-29 11:24:47 +01003027 struct dhcp_config *new;
Simon Kelley849a8352006-06-09 21:02:31 +01003028 struct in_addr in;
3029
Simon Kelley824af852008-02-12 20:43:05 +00003030 new = opt_malloc(sizeof(struct dhcp_config));
3031
Simon Kelley849a8352006-06-09 21:02:31 +01003032 new->next = daemon->dhcp_conf;
Simon Kelley9009d742008-11-14 20:04:27 +00003033 new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
3034 new->hwaddr = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003035 new->netid = NULL;
3036
Simon Kelley849a8352006-06-09 21:02:31 +01003037 if ((a[0] = arg))
Simon Kelley3e8ed782013-05-29 14:31:33 +01003038 for (k = 1; k < 7; k++)
Simon Kelleyf2621c72007-04-29 19:47:21 +01003039 if (!(a[k] = split(a[k-1])))
3040 break;
Simon Kelley849a8352006-06-09 21:02:31 +01003041
3042 for (j = 0; j < k; j++)
3043 if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
3044 {
3045 char *arg = a[j];
3046
3047 if ((arg[0] == 'i' || arg[0] == 'I') &&
3048 (arg[1] == 'd' || arg[1] == 'D') &&
3049 arg[2] == ':')
3050 {
3051 if (arg[3] == '*')
3052 new->flags |= CONFIG_NOCLID;
3053 else
3054 {
3055 int len;
3056 arg += 3; /* dump id: */
3057 if (strchr(arg, ':'))
3058 len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
3059 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01003060 {
3061 unhide_metas(arg);
3062 len = (int) strlen(arg);
3063 }
3064
Simon Kelley28866e92011-02-14 20:19:14 +00003065 if (len == -1)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003066 ret_err(_("bad hex constant"));
Simon Kelley28866e92011-02-14 20:19:14 +00003067 else if ((new->clid = opt_malloc(len)))
Simon Kelley5aabfc72007-08-29 11:24:47 +01003068 {
3069 new->flags |= CONFIG_CLID;
3070 new->clid_len = len;
3071 memcpy(new->clid, arg, len);
3072 }
Simon Kelley849a8352006-06-09 21:02:31 +01003073 }
3074 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003075 /* dhcp-host has strange backwards-compat needs. */
3076 else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg)
Simon Kelley849a8352006-06-09 21:02:31 +01003077 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003078 struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
3079 struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
3080 newtag->net = opt_malloc(strlen(arg + 4) + 1);
3081 newlist->next = new->netid;
3082 new->netid = newlist;
3083 newlist->list = newtag;
3084 strcpy(newtag->net, arg+4);
3085 unhide_metas(newtag->net);
Simon Kelley849a8352006-06-09 21:02:31 +01003086 }
Simon Kelley7de060b2011-08-26 17:24:52 +01003087 else if (strstr(arg, "tag:") == arg)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003088 ret_err(_("cannot match tags in --dhcp-host"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00003089#ifdef HAVE_DHCP6
3090 else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
3091 {
3092 arg[strlen(arg)-1] = 0;
3093 arg++;
3094
3095 if (!inet_pton(AF_INET6, arg, &new->addr6))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003096 ret_err(_("bad IPv6 address"));
Simon Kelley30393102013-01-17 16:34:16 +00003097
3098 for (i= 0; i < 8; i++)
3099 if (new->addr6.s6_addr[i] != 0)
3100 break;
3101
3102 /* set WILDCARD if network part all zeros */
3103 if (i == 8)
3104 new->flags |= CONFIG_WILDCARD;
Simon Kelley4cb1b322012-02-06 14:30:41 +00003105
3106 new->flags |= CONFIG_ADDR6;
3107 }
3108#endif
Simon Kelley7de060b2011-08-26 17:24:52 +01003109 else
Simon Kelley849a8352006-06-09 21:02:31 +01003110 {
Simon Kelley9009d742008-11-14 20:04:27 +00003111 struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
Simon Kelley28866e92011-02-14 20:19:14 +00003112 if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
3113 &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003114 ret_err(_("bad hex constant"));
Simon Kelley28866e92011-02-14 20:19:14 +00003115 else
3116 {
3117
3118 newhw->next = new->hwaddr;
3119 new->hwaddr = newhw;
3120 }
Simon Kelley849a8352006-06-09 21:02:31 +01003121 }
3122 }
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003123 else if (strchr(a[j], '.') && (inet_pton(AF_INET, a[j], &in) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01003124 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003125 struct dhcp_config *configs;
3126
Simon Kelley849a8352006-06-09 21:02:31 +01003127 new->addr = in;
3128 new->flags |= CONFIG_ADDR;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003129
3130 /* If the same IP appears in more than one host config, then DISCOVER
3131 for one of the hosts will get the address, but REQUEST will be NAKed,
3132 since the address is reserved by the other one -> protocol loop. */
3133 for (configs = daemon->dhcp_conf; configs; configs = configs->next)
3134 if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr)
3135 {
3136 sprintf(errstr, _("duplicate dhcp-host IP address %s"), inet_ntoa(in));
3137 return 0;
3138 }
Simon Kelley849a8352006-06-09 21:02:31 +01003139 }
3140 else
3141 {
3142 char *cp, *lastp = NULL, last = 0;
Simon Kelley76ff4402013-12-17 16:29:14 +00003143 int fac = 1, isdig = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01003144
3145 if (strlen(a[j]) > 1)
3146 {
3147 lastp = a[j] + strlen(a[j]) - 1;
3148 last = *lastp;
3149 switch (last)
3150 {
Simon Kelley42243212012-07-20 15:19:18 +01003151 case 'w':
3152 case 'W':
3153 fac *= 7;
3154 /* fall through */
Simon Kelley849a8352006-06-09 21:02:31 +01003155 case 'd':
3156 case 'D':
3157 fac *= 24;
3158 /* fall through */
3159 case 'h':
3160 case 'H':
3161 fac *= 60;
3162 /* fall through */
3163 case 'm':
3164 case 'M':
3165 fac *= 60;
3166 /* fall through */
3167 case 's':
3168 case 'S':
3169 *lastp = 0;
3170 }
3171 }
3172
3173 for (cp = a[j]; *cp; cp++)
Simon Kelley76ff4402013-12-17 16:29:14 +00003174 if (isdigit((unsigned char)*cp))
3175 isdig = 1;
3176 else if (*cp != ' ')
Simon Kelley849a8352006-06-09 21:02:31 +01003177 break;
Simon Kelley76ff4402013-12-17 16:29:14 +00003178
Simon Kelley849a8352006-06-09 21:02:31 +01003179 if (*cp)
3180 {
3181 if (lastp)
3182 *lastp = last;
3183 if (strcmp(a[j], "infinite") == 0)
3184 {
3185 new->lease_time = 0xffffffff;
3186 new->flags |= CONFIG_TIME;
3187 }
3188 else if (strcmp(a[j], "ignore") == 0)
3189 new->flags |= CONFIG_DISABLE;
3190 else
3191 {
Simon Kelley1f15b812009-10-13 17:49:32 +01003192 if (!(new->hostname = canonicalise_opt(a[j])) ||
3193 !legal_hostname(new->hostname))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003194 ret_err(_("bad DHCP host name"));
3195
3196 new->flags |= CONFIG_NAME;
3197 new->domain = strip_hostname(new->hostname);
Simon Kelley849a8352006-06-09 21:02:31 +01003198 }
3199 }
Simon Kelley76ff4402013-12-17 16:29:14 +00003200 else if (isdig)
Simon Kelley849a8352006-06-09 21:02:31 +01003201 {
3202 new->lease_time = atoi(a[j]) * fac;
3203 /* Leases of a minute or less confuse
3204 some clients, notably Apple's */
3205 if (new->lease_time < 120)
3206 new->lease_time = 120;
3207 new->flags |= CONFIG_TIME;
3208 }
3209 }
3210
Simon Kelley5aabfc72007-08-29 11:24:47 +01003211 daemon->dhcp_conf = new;
Simon Kelley849a8352006-06-09 21:02:31 +01003212 break;
3213 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003214
3215 case LOPT_TAG_IF: /* --tag-if */
3216 {
3217 struct tag_if *new = opt_malloc(sizeof(struct tag_if));
3218
3219 new->tag = NULL;
3220 new->set = NULL;
3221 new->next = NULL;
3222
3223 /* preserve order */
3224 if (!daemon->tag_if)
3225 daemon->tag_if = new;
3226 else
3227 {
3228 struct tag_if *tmp;
3229 for (tmp = daemon->tag_if; tmp->next; tmp = tmp->next);
3230 tmp->next = new;
3231 }
3232
3233 while (arg)
3234 {
3235 size_t len;
3236
3237 comma = split(arg);
3238 len = strlen(arg);
3239
3240 if (len < 5)
3241 {
3242 new->set = NULL;
3243 break;
3244 }
3245 else
3246 {
3247 struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
3248 newtag->net = opt_malloc(len - 3);
3249 strcpy(newtag->net, arg+4);
3250 unhide_metas(newtag->net);
3251
3252 if (strstr(arg, "set:") == arg)
3253 {
3254 struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
3255 newlist->next = new->set;
3256 new->set = newlist;
3257 newlist->list = newtag;
3258 }
3259 else if (strstr(arg, "tag:") == arg)
3260 {
3261 newtag->next = new->tag;
3262 new->tag = newtag;
3263 }
3264 else
3265 {
3266 new->set = NULL;
Simon Kelley4dc9c652013-02-04 21:43:52 +00003267 free(newtag);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003268 break;
3269 }
3270 }
3271
3272 arg = comma;
3273 }
3274
3275 if (!new->set)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003276 ret_err(_("bad tag-if"));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003277
3278 break;
3279 }
3280
Simon Kelley849a8352006-06-09 21:02:31 +01003281
Simon Kelley73a08a22009-02-05 20:28:08 +00003282 case 'O': /* --dhcp-option */
3283 case LOPT_FORCE: /* --dhcp-option-force */
Simon Kelley824af852008-02-12 20:43:05 +00003284 case LOPT_OPTS:
Simon Kelley73a08a22009-02-05 20:28:08 +00003285 case LOPT_MATCH: /* --dhcp-match */
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003286 return parse_dhcp_opt(errstr, arg,
3287 option == LOPT_FORCE ? DHOPT_FORCE :
3288 (option == LOPT_MATCH ? DHOPT_MATCH :
3289 (option == LOPT_OPTS ? DHOPT_BANK : 0)));
3290
Simon Kelleyf2621c72007-04-29 19:47:21 +01003291 case 'M': /* --dhcp-boot */
Simon Kelley849a8352006-06-09 21:02:31 +01003292 {
3293 struct dhcp_netid *id = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003294 while (is_tag_prefix(arg))
Simon Kelley849a8352006-06-09 21:02:31 +01003295 {
Simon Kelley824af852008-02-12 20:43:05 +00003296 struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
Simon Kelley849a8352006-06-09 21:02:31 +01003297 newid->next = id;
3298 id = newid;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003299 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00003300 newid->net = opt_string_alloc(arg+4);
Simon Kelley849a8352006-06-09 21:02:31 +01003301 arg = comma;
3302 };
3303
3304 if (!arg)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003305 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01003306 else
3307 {
Simon Kelley7de060b2011-08-26 17:24:52 +01003308 char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +01003309 struct in_addr dhcp_next_server;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003310 struct dhcp_boot *new;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003311 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00003312 dhcp_file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003313 dhcp_next_server.s_addr = 0;
3314 if (comma)
3315 {
3316 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003317 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00003318 dhcp_sname = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003319 if (comma)
3320 {
3321 unhide_metas(comma);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003322 if (!(inet_pton(AF_INET, comma, &dhcp_next_server) > 0))
3323 {
3324 /*
3325 * The user may have specified the tftp hostname here.
3326 * save it so that it can be resolved/looked up during
3327 * actual dhcp_reply().
3328 */
3329
3330 tftp_sname = opt_string_alloc(comma);
3331 dhcp_next_server.s_addr = 0;
3332 }
Simon Kelley849a8352006-06-09 21:02:31 +01003333 }
3334 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003335
3336 new = opt_malloc(sizeof(struct dhcp_boot));
3337 new->file = dhcp_file;
3338 new->sname = dhcp_sname;
3339 new->tftp_sname = tftp_sname;
3340 new->next_server = dhcp_next_server;
3341 new->netid = id;
3342 new->next = daemon->boot_config;
3343 daemon->boot_config = new;
Simon Kelley849a8352006-06-09 21:02:31 +01003344 }
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003345
Simon Kelley849a8352006-06-09 21:02:31 +01003346 break;
3347 }
Simon Kelley7622fc02009-06-04 20:32:05 +01003348
Floris Bos503c6092017-04-09 23:07:13 +01003349 case LOPT_REPLY_DELAY: /* --dhcp-reply-delay */
3350 {
3351 struct dhcp_netid *id = NULL;
3352 while (is_tag_prefix(arg))
3353 {
3354 struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
3355 newid->next = id;
3356 id = newid;
3357 comma = split(arg);
3358 newid->net = opt_string_alloc(arg+4);
3359 arg = comma;
3360 };
3361
3362 if (!arg)
3363 ret_err(gen_err);
3364 else
3365 {
3366 struct delay_config *new;
3367 int delay;
3368 if (!atoi_check(arg, &delay))
3369 ret_err(gen_err);
3370
3371 new = opt_malloc(sizeof(struct delay_config));
3372 new->delay = delay;
3373 new->netid = id;
3374 new->next = daemon->delay_conf;
3375 daemon->delay_conf = new;
3376 }
3377
3378 break;
3379 }
3380
Simon Kelley7622fc02009-06-04 20:32:05 +01003381 case LOPT_PXE_PROMT: /* --pxe-prompt */
3382 {
3383 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
3384 int timeout;
Floris Bos503c6092017-04-09 23:07:13 +01003385
Simon Kelley7622fc02009-06-04 20:32:05 +01003386 new->netid = NULL;
3387 new->opt = 10; /* PXE_MENU_PROMPT */
3388
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003389 while (is_tag_prefix(arg))
3390 {
Simon Kelley7622fc02009-06-04 20:32:05 +01003391 struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
3392 comma = split(arg);
3393 nn->next = new->netid;
3394 new->netid = nn;
3395 nn->net = opt_string_alloc(arg+4);
3396 arg = comma;
3397 }
3398
3399 if (!arg)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003400 ret_err(gen_err);
Simon Kelley7622fc02009-06-04 20:32:05 +01003401 else
3402 {
3403 comma = split(arg);
3404 unhide_metas(arg);
3405 new->len = strlen(arg) + 1;
3406 new->val = opt_malloc(new->len);
3407 memcpy(new->val + 1, arg, new->len - 1);
3408
3409 new->u.vendor_class = (unsigned char *)"PXEClient";
3410 new->flags = DHOPT_VENDOR;
3411
3412 if (comma && atoi_check(comma, &timeout))
3413 *(new->val) = timeout;
3414 else
3415 *(new->val) = 255;
3416
3417 new->next = daemon->dhcp_opts;
3418 daemon->dhcp_opts = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003419 daemon->enable_pxe = 1;
Simon Kelley7622fc02009-06-04 20:32:05 +01003420 }
3421
3422 break;
3423 }
3424
3425 case LOPT_PXE_SERV: /* --pxe-service */
3426 {
3427 struct pxe_service *new = opt_malloc(sizeof(struct pxe_service));
3428 char *CSA[] = { "x86PC", "PC98", "IA64_EFI", "Alpha", "Arc_x86", "Intel_Lean_Client",
Simon Kelley68bea102016-05-11 22:15:06 +01003429 "IA32_EFI", "x86-64_EFI", "Xscale_EFI", "BC_EFI",
3430 "ARM32_EFI", "ARM64_EFI", NULL };
Simon Kelley7622fc02009-06-04 20:32:05 +01003431 static int boottype = 32768;
3432
3433 new->netid = NULL;
Simon Kelley751d6f42012-02-10 15:24:51 +00003434 new->sname = NULL;
Simon Kelley7622fc02009-06-04 20:32:05 +01003435 new->server.s_addr = 0;
3436
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003437 while (is_tag_prefix(arg))
Simon Kelley7622fc02009-06-04 20:32:05 +01003438 {
3439 struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
3440 comma = split(arg);
3441 nn->next = new->netid;
3442 new->netid = nn;
3443 nn->net = opt_string_alloc(arg+4);
3444 arg = comma;
3445 }
3446
3447 if (arg && (comma = split(arg)))
3448 {
3449 for (i = 0; CSA[i]; i++)
3450 if (strcasecmp(CSA[i], arg) == 0)
3451 break;
3452
3453 if (CSA[i] || atoi_check(arg, &i))
3454 {
3455 arg = comma;
3456 comma = split(arg);
3457
3458 new->CSA = i;
3459 new->menu = opt_string_alloc(arg);
3460
Simon Kelley316e2732010-01-22 20:16:09 +00003461 if (!comma)
3462 {
3463 new->type = 0; /* local boot */
3464 new->basename = NULL;
3465 }
3466 else
Simon Kelley7622fc02009-06-04 20:32:05 +01003467 {
3468 arg = comma;
3469 comma = split(arg);
3470 if (atoi_check(arg, &i))
3471 {
3472 new->type = i;
3473 new->basename = NULL;
3474 }
3475 else
3476 {
3477 new->type = boottype++;
3478 new->basename = opt_string_alloc(arg);
3479 }
3480
Simon Kelley751d6f42012-02-10 15:24:51 +00003481 if (comma)
3482 {
3483 if (!inet_pton(AF_INET, comma, &new->server))
3484 {
3485 new->server.s_addr = 0;
3486 new->sname = opt_string_alloc(comma);
3487 }
3488
3489 }
Simon Kelley7622fc02009-06-04 20:32:05 +01003490 }
Simon Kelley751d6f42012-02-10 15:24:51 +00003491
Simon Kelley316e2732010-01-22 20:16:09 +00003492 /* Order matters */
3493 new->next = NULL;
3494 if (!daemon->pxe_services)
3495 daemon->pxe_services = new;
3496 else
3497 {
3498 struct pxe_service *s;
3499 for (s = daemon->pxe_services; s->next; s = s->next);
3500 s->next = new;
3501 }
3502
3503 daemon->enable_pxe = 1;
3504 break;
3505
Simon Kelley7622fc02009-06-04 20:32:05 +01003506 }
3507 }
3508
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003509 ret_err(gen_err);
Simon Kelley7622fc02009-06-04 20:32:05 +01003510 }
3511
Simon Kelleyf2621c72007-04-29 19:47:21 +01003512 case '4': /* --dhcp-mac */
Simon Kelley849a8352006-06-09 21:02:31 +01003513 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01003514 if (!(comma = split(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003515 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01003516 else
3517 {
Simon Kelley824af852008-02-12 20:43:05 +00003518 struct dhcp_mac *new = opt_malloc(sizeof(struct dhcp_mac));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003519 new->netid.net = opt_string_alloc(set_prefix(arg));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003520 unhide_metas(comma);
3521 new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
Simon Kelley28866e92011-02-14 20:19:14 +00003522 if (new->hwaddr_len == -1)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003523 ret_err(gen_err);
Simon Kelley28866e92011-02-14 20:19:14 +00003524 else
3525 {
3526 new->next = daemon->dhcp_macs;
3527 daemon->dhcp_macs = new;
3528 }
Simon Kelley849a8352006-06-09 21:02:31 +01003529 }
3530 }
3531 break;
Simon Kelleyc6309242013-03-07 20:59:28 +00003532
3533#ifdef OPTION6_PREFIX_CLASS
3534 case LOPT_PREF_CLSS: /* --dhcp-prefix-class */
3535 {
3536 struct prefix_class *new = opt_malloc(sizeof(struct prefix_class));
3537
3538 if (!(comma = split(arg)) ||
3539 !atoi_check16(comma, &new->class))
3540 ret_err(gen_err);
3541
3542 new->tag.net = opt_string_alloc(set_prefix(arg));
3543 new->next = daemon->prefix_classes;
3544 daemon->prefix_classes = new;
3545
3546 break;
3547 }
3548#endif
3549
3550
Simon Kelleyf2621c72007-04-29 19:47:21 +01003551 case 'U': /* --dhcp-vendorclass */
3552 case 'j': /* --dhcp-userclass */
3553 case LOPT_CIRCUIT: /* --dhcp-circuitid */
3554 case LOPT_REMOTE: /* --dhcp-remoteid */
3555 case LOPT_SUBSCR: /* --dhcp-subscrid */
Simon Kelley849a8352006-06-09 21:02:31 +01003556 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003557 unsigned char *p;
3558 int dig = 0;
3559 struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
3560
3561 if (!(comma = split(arg)))
3562 ret_err(gen_err);
3563
3564 new->netid.net = opt_string_alloc(set_prefix(arg));
3565 /* check for hex string - must digits may include : must not have nothing else,
3566 only allowed for agent-options. */
3567
3568 arg = comma;
3569 if ((comma = split(arg)))
3570 {
3571 if (option != 'U' || strstr(arg, "enterprise:") != arg)
3572 ret_err(gen_err);
3573 else
3574 new->enterprise = atoi(arg+11);
3575 }
3576 else
3577 comma = arg;
3578
3579 for (p = (unsigned char *)comma; *p; p++)
3580 if (isxdigit(*p))
3581 dig = 1;
3582 else if (*p != ':')
3583 break;
3584 unhide_metas(comma);
3585 if (option == 'U' || option == 'j' || *p || !dig)
3586 {
3587 new->len = strlen(comma);
3588 new->data = opt_malloc(new->len);
3589 memcpy(new->data, comma, new->len);
3590 }
3591 else
3592 {
3593 new->len = parse_hex(comma, (unsigned char *)comma, strlen(comma), NULL, NULL);
3594 new->data = opt_malloc(new->len);
3595 memcpy(new->data, comma, new->len);
3596 }
3597
3598 switch (option)
3599 {
3600 case 'j':
3601 new->match_type = MATCH_USER;
3602 break;
3603 case 'U':
3604 new->match_type = MATCH_VENDOR;
3605 break;
3606 case LOPT_CIRCUIT:
3607 new->match_type = MATCH_CIRCUIT;
3608 break;
3609 case LOPT_REMOTE:
3610 new->match_type = MATCH_REMOTE;
3611 break;
3612 case LOPT_SUBSCR:
3613 new->match_type = MATCH_SUBSCRIBER;
3614 break;
3615 }
3616 new->next = daemon->dhcp_vendors;
3617 daemon->dhcp_vendors = new;
Simon Kelleya5c72ab2012-02-10 13:42:47 +00003618
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003619 break;
Simon Kelley849a8352006-06-09 21:02:31 +01003620 }
3621
Simon Kelley9e038942008-05-30 20:06:34 +01003622 case LOPT_ALTPORT: /* --dhcp-alternate-port */
3623 if (!arg)
3624 {
3625 daemon->dhcp_server_port = DHCP_SERVER_ALTPORT;
3626 daemon->dhcp_client_port = DHCP_CLIENT_ALTPORT;
3627 }
3628 else
3629 {
3630 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01003631 if (!atoi_check16(arg, &daemon->dhcp_server_port) ||
3632 (comma && !atoi_check16(comma, &daemon->dhcp_client_port)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003633 ret_err(_("invalid port number"));
Simon Kelley9e038942008-05-30 20:06:34 +01003634 if (!comma)
3635 daemon->dhcp_client_port = daemon->dhcp_server_port+1;
3636 }
3637 break;
3638
Simon Kelley824af852008-02-12 20:43:05 +00003639 case 'J': /* --dhcp-ignore */
3640 case LOPT_NO_NAMES: /* --dhcp-ignore-names */
3641 case LOPT_BROADCAST: /* --dhcp-broadcast */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003642 case '3': /* --bootp-dynamic */
3643 case LOPT_GEN_NAMES: /* --dhcp-generate-names */
Simon Kelley849a8352006-06-09 21:02:31 +01003644 {
Simon Kelley824af852008-02-12 20:43:05 +00003645 struct dhcp_netid_list *new = opt_malloc(sizeof(struct dhcp_netid_list));
Simon Kelley849a8352006-06-09 21:02:31 +01003646 struct dhcp_netid *list = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00003647 if (option == 'J')
3648 {
3649 new->next = daemon->dhcp_ignore;
3650 daemon->dhcp_ignore = new;
3651 }
Simon Kelley824af852008-02-12 20:43:05 +00003652 else if (option == LOPT_BROADCAST)
3653 {
3654 new->next = daemon->force_broadcast;
3655 daemon->force_broadcast = new;
3656 }
Simon Kelley9009d742008-11-14 20:04:27 +00003657 else if (option == '3')
3658 {
3659 new->next = daemon->bootp_dynamic;
3660 daemon->bootp_dynamic = new;
3661 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003662 else if (option == LOPT_GEN_NAMES)
3663 {
3664 new->next = daemon->dhcp_gen_names;
3665 daemon->dhcp_gen_names = new;
3666 }
Simon Kelley832af0b2007-01-21 20:01:28 +00003667 else
3668 {
3669 new->next = daemon->dhcp_ignore_names;
3670 daemon->dhcp_ignore_names = new;
3671 }
3672
3673 while (arg) {
Simon Kelley824af852008-02-12 20:43:05 +00003674 struct dhcp_netid *member = opt_malloc(sizeof(struct dhcp_netid));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003675 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003676 member->next = list;
3677 list = member;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003678 if (is_tag_prefix(arg))
Simon Kelley9009d742008-11-14 20:04:27 +00003679 member->net = opt_string_alloc(arg+4);
3680 else
3681 member->net = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003682 arg = comma;
Simon Kelley832af0b2007-01-21 20:01:28 +00003683 }
Simon Kelley849a8352006-06-09 21:02:31 +01003684
3685 new->list = list;
3686 break;
3687 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003688
3689 case LOPT_PROXY: /* --dhcp-proxy */
3690 daemon->override = 1;
3691 while (arg) {
3692 struct addr_list *new = opt_malloc(sizeof(struct addr_list));
3693 comma = split(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003694 if (!(inet_pton(AF_INET, arg, &new->addr) > 0))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003695 ret_err(_("bad dhcp-proxy address"));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003696 new->next = daemon->override_relays;
3697 daemon->override_relays = new;
3698 arg = comma;
3699 }
3700 break;
Simon Kelleyff7eea22013-09-04 18:01:38 +01003701
3702 case LOPT_RELAY: /* --dhcp-relay */
3703 {
3704 struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
3705 comma = split(arg);
3706 new->interface = opt_string_alloc(split(comma));
3707 new->iface_index = 0;
3708 if (inet_pton(AF_INET, arg, &new->local) && inet_pton(AF_INET, comma, &new->server))
3709 {
3710 new->next = daemon->relay4;
3711 daemon->relay4 = new;
3712 }
3713#ifdef HAVE_DHCP6
3714 else if (inet_pton(AF_INET6, arg, &new->local) && inet_pton(AF_INET6, comma, &new->server))
3715 {
3716 new->next = daemon->relay6;
3717 daemon->relay6 = new;
3718 }
3719#endif
3720 else
3721 ret_err(_("Bad dhcp-relay"));
3722
3723 break;
3724 }
3725
Simon Kelley7622fc02009-06-04 20:32:05 +01003726#endif
Simon Kelley849a8352006-06-09 21:02:31 +01003727
Simon Kelley8b372702012-03-09 17:45:10 +00003728#ifdef HAVE_DHCP6
Simon Kelleyc4cd95d2013-10-10 20:58:11 +01003729 case LOPT_RA_PARAM: /* --ra-param */
3730 if ((comma = split(arg)))
3731 {
3732 struct ra_interface *new = opt_malloc(sizeof(struct ra_interface));
3733 new->lifetime = -1;
3734 new->prio = 0;
David Flamand005c46d2017-04-11 11:49:54 +01003735 new->mtu = 0;
Vladislav Grishenko6ec5f5c2017-04-24 22:34:45 +01003736 new->mtu_name = NULL;
Simon Kelleyc4cd95d2013-10-10 20:58:11 +01003737 new->name = opt_string_alloc(arg);
David Flamand005c46d2017-04-11 11:49:54 +01003738 if (strcasestr(comma, "mtu:") == comma)
3739 {
3740 arg = comma + 4;
3741 if (!(comma = split(comma)))
3742 goto err;
3743 if (!strcasecmp(arg, "off"))
3744 new->mtu = -1;
Vladislav Grishenko6ec5f5c2017-04-24 22:34:45 +01003745 else if (!atoi_check(arg, &new->mtu))
3746 new->mtu_name = opt_string_alloc(arg);
3747 else if (new->mtu < 1280)
David Flamand005c46d2017-04-11 11:49:54 +01003748 goto err;
3749 }
Simon Kelleyc4cd95d2013-10-10 20:58:11 +01003750 if (strcasestr(comma, "high") == comma || strcasestr(comma, "low") == comma)
3751 {
3752 if (*comma == 'l' || *comma == 'L')
3753 new->prio = 0x18;
3754 else
3755 new->prio = 0x08;
3756 comma = split(comma);
3757 }
3758 arg = split(comma);
3759 if (!atoi_check(comma, &new->interval) ||
3760 (arg && !atoi_check(arg, &new->lifetime)))
David Flamand005c46d2017-04-11 11:49:54 +01003761err:
Simon Kelleyc4cd95d2013-10-10 20:58:11 +01003762 ret_err(_("bad RA-params"));
3763
3764 new->next = daemon->ra_interfaces;
3765 daemon->ra_interfaces = new;
3766 }
3767 break;
3768
Simon Kelley8b372702012-03-09 17:45:10 +00003769 case LOPT_DUID: /* --dhcp-duid */
3770 if (!(comma = split(arg)) || !atoi_check(arg, (int *)&daemon->duid_enterprise))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003771 ret_err(_("bad DUID"));
Simon Kelley8b372702012-03-09 17:45:10 +00003772 else
3773 {
3774 daemon->duid_config_len = parse_hex(comma,(unsigned char *)comma, strlen(comma), NULL, NULL);
3775 daemon->duid_config = opt_malloc(daemon->duid_config_len);
3776 memcpy(daemon->duid_config, comma, daemon->duid_config_len);
3777 }
3778 break;
3779#endif
3780
Simon Kelleyf2621c72007-04-29 19:47:21 +01003781 case 'V': /* --alias */
Simon Kelley849a8352006-06-09 21:02:31 +01003782 {
Simon Kelley73a08a22009-02-05 20:28:08 +00003783 char *dash, *a[3] = { NULL, NULL, NULL };
Simon Kelleyf2621c72007-04-29 19:47:21 +01003784 int k = 0;
Simon Kelley73a08a22009-02-05 20:28:08 +00003785 struct doctor *new = opt_malloc(sizeof(struct doctor));
3786 new->next = daemon->doctors;
3787 daemon->doctors = new;
3788 new->mask.s_addr = 0xffffffff;
3789 new->end.s_addr = 0;
3790
Simon Kelley849a8352006-06-09 21:02:31 +01003791 if ((a[0] = arg))
3792 for (k = 1; k < 3; k++)
3793 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01003794 if (!(a[k] = split(a[k-1])))
Simon Kelley849a8352006-06-09 21:02:31 +01003795 break;
Simon Kelley849a8352006-06-09 21:02:31 +01003796 unhide_metas(a[k]);
3797 }
Simon Kelley849a8352006-06-09 21:02:31 +01003798
Simon Kelley73a08a22009-02-05 20:28:08 +00003799 dash = split_chr(a[0], '-');
3800
Simon Kelley849a8352006-06-09 21:02:31 +01003801 if ((k < 2) ||
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003802 (!(inet_pton(AF_INET, a[0], &new->in) > 0)) ||
Simon Kelleya3bd7e72018-07-19 22:00:08 +01003803 (!(inet_pton(AF_INET, a[1], &new->out) > 0)) ||
3804 (k == 3 && !inet_pton(AF_INET, a[2], &new->mask)))
3805 ret_err(_("missing address in alias"));
Simon Kelley849a8352006-06-09 21:02:31 +01003806
Simon Kelley73a08a22009-02-05 20:28:08 +00003807 if (dash &&
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003808 (!(inet_pton(AF_INET, dash, &new->end) > 0) ||
Simon Kelley73a08a22009-02-05 20:28:08 +00003809 !is_same_net(new->in, new->end, new->mask) ||
3810 ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003811 ret_err(_("invalid alias range"));
Simon Kelley849a8352006-06-09 21:02:31 +01003812
3813 break;
3814 }
3815
Simon Kelleyf2621c72007-04-29 19:47:21 +01003816 case LOPT_INTNAME: /* --interface-name */
3817 {
3818 struct interface_name *new, **up;
Simon Kelley1f15b812009-10-13 17:49:32 +01003819 char *domain = NULL;
3820
Simon Kelleyf2621c72007-04-29 19:47:21 +01003821 comma = split(arg);
3822
Simon Kelley1f15b812009-10-13 17:49:32 +01003823 if (!comma || !(domain = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003824 ret_err(_("bad interface name"));
Simon Kelley1f15b812009-10-13 17:49:32 +01003825
Simon Kelley824af852008-02-12 20:43:05 +00003826 new = opt_malloc(sizeof(struct interface_name));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003827 new->next = NULL;
Simon Kelley376d48c2013-11-13 13:04:30 +00003828 new->addr = NULL;
3829
Simon Kelleyf2621c72007-04-29 19:47:21 +01003830 /* Add to the end of the list, so that first name
3831 of an interface is used for PTR lookups. */
Simon Kelley824af852008-02-12 20:43:05 +00003832 for (up = &daemon->int_names; *up; up = &((*up)->next));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003833 *up = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003834 new->name = domain;
Simon Kelleyf7029f52013-11-21 15:09:09 +00003835 new->family = 0;
3836 arg = split_chr(comma, '/');
3837 if (arg)
3838 {
3839 if (strcmp(arg, "4") == 0)
3840 new->family = AF_INET;
3841#ifdef HAVE_IPV6
3842 else if (strcmp(arg, "6") == 0)
3843 new->family = AF_INET6;
3844#endif
3845 else
3846 ret_err(gen_err);
3847 }
Simon Kelley824af852008-02-12 20:43:05 +00003848 new->intr = opt_string_alloc(comma);
Simon Kelleyf2621c72007-04-29 19:47:21 +01003849 break;
3850 }
Simon Kelley9009d742008-11-14 20:04:27 +00003851
3852 case LOPT_CNAME: /* --cname */
3853 {
3854 struct cname *new;
Simon Kelleya1d973f2016-12-22 22:09:50 +00003855 char *alias, *target, *last, *pen;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00003856 int ttl = -1;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003857
Simon Kelleya1d973f2016-12-22 22:09:50 +00003858 for (last = pen = NULL, comma = arg; comma; comma = split(comma))
Simon Kelley9009d742008-11-14 20:04:27 +00003859 {
Simon Kelleya1d973f2016-12-22 22:09:50 +00003860 pen = last;
3861 last = comma;
3862 }
3863
3864 if (!pen)
3865 ret_err(_("bad CNAME"));
3866
3867 if (pen != arg && atoi_check(last, &ttl))
3868 last = pen;
3869
3870 target = canonicalise_opt(last);
3871
3872 while (arg != last)
3873 {
Petr Menšík56f06232018-03-06 23:13:32 +00003874 int arglen = strlen(arg);
Simon Kelleya1d973f2016-12-22 22:09:50 +00003875 alias = canonicalise_opt(arg);
Simon Kelley56144132017-05-03 22:54:09 +01003876
3877 if (!alias || !target)
3878 ret_err(_("bad CNAME"));
Simon Kelleya1d973f2016-12-22 22:09:50 +00003879
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003880 for (new = daemon->cnames; new; new = new->next)
Simon Kelley56144132017-05-03 22:54:09 +01003881 if (hostname_isequal(new->alias, alias))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003882 ret_err(_("duplicate CNAME"));
3883 new = opt_malloc(sizeof(struct cname));
3884 new->next = daemon->cnames;
3885 daemon->cnames = new;
3886 new->alias = alias;
3887 new->target = target;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00003888 new->ttl = ttl;
Simon Kelleya1d973f2016-12-22 22:09:50 +00003889
Petr Menšík56f06232018-03-06 23:13:32 +00003890 for (arg += arglen+1; *arg && isspace(*arg); arg++);
Simon Kelley9009d742008-11-14 20:04:27 +00003891 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003892
Simon Kelley9009d742008-11-14 20:04:27 +00003893 break;
3894 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01003895
3896 case LOPT_PTR: /* --ptr-record */
Simon Kelley832af0b2007-01-21 20:01:28 +00003897 {
3898 struct ptr_record *new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003899 char *dom, *target = NULL;
3900
Simon Kelleyf2621c72007-04-29 19:47:21 +01003901 comma = split(arg);
3902
Simon Kelley1f15b812009-10-13 17:49:32 +01003903 if (!(dom = canonicalise_opt(arg)) ||
3904 (comma && !(target = canonicalise_opt(comma))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003905 ret_err(_("bad PTR record"));
Simon Kelley1f15b812009-10-13 17:49:32 +01003906 else
3907 {
3908 new = opt_malloc(sizeof(struct ptr_record));
3909 new->next = daemon->ptr;
3910 daemon->ptr = new;
3911 new->name = dom;
3912 new->ptr = target;
3913 }
Simon Kelley832af0b2007-01-21 20:01:28 +00003914 break;
3915 }
3916
Simon Kelley1a6bca82008-07-11 11:11:42 +01003917 case LOPT_NAPTR: /* --naptr-record */
3918 {
3919 char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
3920 int k = 0;
3921 struct naptr *new;
3922 int order, pref;
Simon Kelley1f15b812009-10-13 17:49:32 +01003923 char *name, *replace = NULL;
Simon Kelley1a6bca82008-07-11 11:11:42 +01003924
3925 if ((a[0] = arg))
3926 for (k = 1; k < 7; k++)
3927 if (!(a[k] = split(a[k-1])))
3928 break;
3929
3930
3931 if (k < 6 ||
Simon Kelley1f15b812009-10-13 17:49:32 +01003932 !(name = canonicalise_opt(a[0])) ||
Simon Kelley1ad24ae2008-07-20 20:22:50 +01003933 !atoi_check16(a[1], &order) ||
3934 !atoi_check16(a[2], &pref) ||
Simon Kelley1f15b812009-10-13 17:49:32 +01003935 (k == 7 && !(replace = canonicalise_opt(a[6]))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003936 ret_err(_("bad NAPTR record"));
Simon Kelley1a6bca82008-07-11 11:11:42 +01003937 else
3938 {
3939 new = opt_malloc(sizeof(struct naptr));
3940 new->next = daemon->naptr;
3941 daemon->naptr = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003942 new->name = name;
Simon Kelley1a6bca82008-07-11 11:11:42 +01003943 new->flags = opt_string_alloc(a[3]);
3944 new->services = opt_string_alloc(a[4]);
3945 new->regexp = opt_string_alloc(a[5]);
Simon Kelley1f15b812009-10-13 17:49:32 +01003946 new->replace = replace;
Simon Kelley1a6bca82008-07-11 11:11:42 +01003947 new->order = order;
3948 new->pref = pref;
3949 }
3950 break;
3951 }
Simon Kelley9f7f3b12012-05-28 21:39:57 +01003952
3953 case LOPT_RR: /* dns-rr */
3954 {
3955 struct txt_record *new;
Simon Kelley4caa86d2016-03-16 18:44:16 +00003956 size_t len = 0;
Simon Kelley9f7f3b12012-05-28 21:39:57 +01003957 char *data;
3958 int val;
3959
3960 comma = split(arg);
3961 data = split(comma);
3962
3963 new = opt_malloc(sizeof(struct txt_record));
3964 new->next = daemon->rr;
3965 daemon->rr = new;
3966
3967 if (!atoi_check(comma, &val) ||
3968 !(new->name = canonicalise_opt(arg)) ||
Simon Kelley51931b82012-05-29 17:06:02 +01003969 (data && (len = parse_hex(data, (unsigned char *)data, -1, NULL, NULL)) == -1U))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003970 ret_err(_("bad RR record"));
3971
Simon Kelley9f7f3b12012-05-28 21:39:57 +01003972 new->class = val;
3973 new->len = 0;
3974
3975 if (data)
3976 {
3977 new->txt=opt_malloc(len);
3978 new->len = len;
3979 memcpy(new->txt, data, len);
3980 }
3981
3982 break;
3983 }
3984
Simon Kelleyf2621c72007-04-29 19:47:21 +01003985 case 'Y': /* --txt-record */
Simon Kelley849a8352006-06-09 21:02:31 +01003986 {
3987 struct txt_record *new;
Simon Kelley28866e92011-02-14 20:19:14 +00003988 unsigned char *p, *cnt;
3989 size_t len;
3990
3991 comma = split(arg);
3992
Simon Kelley824af852008-02-12 20:43:05 +00003993 new = opt_malloc(sizeof(struct txt_record));
Simon Kelley849a8352006-06-09 21:02:31 +01003994 new->next = daemon->txt;
3995 daemon->txt = new;
3996 new->class = C_IN;
Simon Kelleyfec216d2014-03-27 20:54:34 +00003997 new->stat = 0;
3998
Simon Kelley1f15b812009-10-13 17:49:32 +01003999 if (!(new->name = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004000 ret_err(_("bad TXT record"));
4001
Simon Kelley28866e92011-02-14 20:19:14 +00004002 len = comma ? strlen(comma) : 0;
4003 len += (len/255) + 1; /* room for extra counts */
4004 new->txt = p = opt_malloc(len);
4005
4006 cnt = p++;
4007 *cnt = 0;
4008
4009 while (comma && *comma)
4010 {
4011 unsigned char c = (unsigned char)*comma++;
4012
4013 if (c == ',' || *cnt == 255)
4014 {
4015 if (c != ',')
4016 comma--;
4017 cnt = p++;
4018 *cnt = 0;
4019 }
4020 else
4021 {
4022 *p++ = unhide_meta(c);
4023 (*cnt)++;
4024 }
4025 }
4026
4027 new->len = p - new->txt;
4028
Simon Kelley849a8352006-06-09 21:02:31 +01004029 break;
4030 }
4031
Simon Kelleyf2621c72007-04-29 19:47:21 +01004032 case 'W': /* --srv-host */
Simon Kelley849a8352006-06-09 21:02:31 +01004033 {
4034 int port = 1, priority = 0, weight = 0;
4035 char *name, *target = NULL;
4036 struct mx_srv_record *new;
4037
Simon Kelleyf2621c72007-04-29 19:47:21 +01004038 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01004039
Simon Kelley1f15b812009-10-13 17:49:32 +01004040 if (!(name = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004041 ret_err(_("bad SRV record"));
4042
Simon Kelley849a8352006-06-09 21:02:31 +01004043 if (comma)
4044 {
4045 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01004046 comma = split(arg);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004047 if (!(target = canonicalise_opt(arg)))
4048 ret_err(_("bad SRV target"));
Simon Kelley824af852008-02-12 20:43:05 +00004049
Simon Kelley849a8352006-06-09 21:02:31 +01004050 if (comma)
4051 {
4052 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01004053 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01004054 if (!atoi_check16(arg, &port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004055 ret_err(_("invalid port number"));
Simon Kelley824af852008-02-12 20:43:05 +00004056
Simon Kelley849a8352006-06-09 21:02:31 +01004057 if (comma)
4058 {
4059 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01004060 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01004061 if (!atoi_check16(arg, &priority))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004062 ret_err(_("invalid priority"));
Simon Kelley824af852008-02-12 20:43:05 +00004063
Simon Kelley407a1f32016-03-01 17:06:07 +00004064 if (comma && !atoi_check16(comma, &weight))
4065 ret_err(_("invalid weight"));
Simon Kelley849a8352006-06-09 21:02:31 +01004066 }
4067 }
4068 }
4069
Simon Kelley824af852008-02-12 20:43:05 +00004070 new = opt_malloc(sizeof(struct mx_srv_record));
Simon Kelley849a8352006-06-09 21:02:31 +01004071 new->next = daemon->mxnames;
4072 daemon->mxnames = new;
4073 new->issrv = 1;
4074 new->name = name;
4075 new->target = target;
4076 new->srvport = port;
4077 new->priority = priority;
4078 new->weight = weight;
4079 break;
4080 }
Simon Kelley7622fc02009-06-04 20:32:05 +01004081
Simon Kelleye759d422012-03-16 13:18:57 +00004082 case LOPT_HOST_REC: /* --host-record */
4083 {
4084 struct host_record *new = opt_malloc(sizeof(struct host_record));
4085 memset(new, 0, sizeof(struct host_record));
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004086 new->ttl = -1;
4087
Simon Kelleye759d422012-03-16 13:18:57 +00004088 if (!arg || !(comma = split(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004089 ret_err(_("Bad host-record"));
4090
4091 while (arg)
4092 {
4093 struct all_addr addr;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004094 char *dig;
4095
4096 for (dig = arg; *dig != 0; dig++)
4097 if (*dig < '0' || *dig > '9')
4098 break;
4099 if (*dig == 0)
4100 new->ttl = atoi(arg);
4101 else if (inet_pton(AF_INET, arg, &addr))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004102 new->addr = addr.addr.addr4;
Simon Kelleye759d422012-03-16 13:18:57 +00004103#ifdef HAVE_IPV6
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004104 else if (inet_pton(AF_INET6, arg, &addr))
4105 new->addr6 = addr.addr.addr6;
Simon Kelleye759d422012-03-16 13:18:57 +00004106#endif
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004107 else
4108 {
4109 int nomem;
4110 char *canon = canonicalise(arg, &nomem);
4111 struct name_list *nl = opt_malloc(sizeof(struct name_list));
4112 if (!canon)
4113 ret_err(_("Bad name in host-record"));
4114
4115 nl->name = canon;
4116 /* keep order, so that PTR record goes to first name */
4117 nl->next = NULL;
4118 if (!new->names)
4119 new->names = nl;
4120 else
4121 {
4122 struct name_list *tmp;
4123 for (tmp = new->names; tmp->next; tmp = tmp->next);
4124 tmp->next = nl;
4125 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004126 }
Simon Kelleye4807d82012-09-27 21:52:26 +01004127
4128 arg = comma;
4129 comma = split(arg);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004130 }
Simon Kelleye759d422012-03-16 13:18:57 +00004131
4132 /* Keep list order */
4133 if (!daemon->host_records_tail)
4134 daemon->host_records = new;
4135 else
4136 daemon->host_records_tail->next = new;
4137 new->next = NULL;
4138 daemon->host_records_tail = new;
4139 break;
4140 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00004141
4142#ifdef HAVE_DNSSEC
Simon Kelleyf3e57872018-07-20 21:10:48 +01004143 case LOPT_DNSSEC_STAMP: /* --dnssec-timestamp */
Simon Kelleyf6e62e22015-03-01 18:17:54 +00004144 daemon->timestamp_file = opt_string_alloc(arg);
4145 break;
4146
Simon Kelleyf3e57872018-07-20 21:10:48 +01004147 case LOPT_DNSSEC_CHECK: /* --dnssec-check-unsigned */
Simon Kelleya6918532018-04-15 16:20:52 +01004148 if (arg)
4149 {
4150 if (strcmp(arg, "no") == 0)
4151 set_option_bool(OPT_DNSSEC_IGN_NS);
4152 else
4153 ret_err(_("bad value for dnssec-check-unsigned"));
4154 }
4155 break;
4156
Simon Kelleyf3e57872018-07-20 21:10:48 +01004157 case LOPT_TRUST_ANCHOR: /* --trust-anchor */
Simon Kelley0fc2f312014-01-08 10:26:58 +00004158 {
Simon Kelleyee415862014-02-11 11:07:22 +00004159 struct ds_config *new = opt_malloc(sizeof(struct ds_config));
4160 char *cp, *cp1, *keyhex, *digest, *algo = NULL;
4161 int len;
Simon Kelleycbf13a22014-01-25 17:59:14 +00004162
4163 new->class = C_IN;
Simon Kelley0fc2f312014-01-08 10:26:58 +00004164
Simon Kelleycbf13a22014-01-25 17:59:14 +00004165 if ((comma = split(arg)) && (algo = split(comma)))
4166 {
4167 int class = 0;
4168 if (strcmp(comma, "IN") == 0)
4169 class = C_IN;
4170 else if (strcmp(comma, "CH") == 0)
4171 class = C_CHAOS;
4172 else if (strcmp(comma, "HS") == 0)
4173 class = C_HESIOD;
4174
4175 if (class != 0)
4176 {
4177 new->class = class;
4178 comma = algo;
4179 algo = split(comma);
4180 }
4181 }
4182
Simon Kelleyee415862014-02-11 11:07:22 +00004183 if (!comma || !algo || !(digest = split(algo)) || !(keyhex = split(digest)) ||
4184 !atoi_check16(comma, &new->keytag) ||
4185 !atoi_check8(algo, &new->algo) ||
4186 !atoi_check8(digest, &new->digest_type) ||
Simon Kelleycbf13a22014-01-25 17:59:14 +00004187 !(new->name = canonicalise_opt(arg)))
Simon Kelleyee415862014-02-11 11:07:22 +00004188 ret_err(_("bad trust anchor"));
Simon Kelleycbf13a22014-01-25 17:59:14 +00004189
Simon Kelley0fc2f312014-01-08 10:26:58 +00004190 /* Upper bound on length */
Simon Kelleyee415862014-02-11 11:07:22 +00004191 len = (2*strlen(keyhex))+1;
4192 new->digest = opt_malloc(len);
4193 unhide_metas(keyhex);
4194 /* 4034: "Whitespace is allowed within digits" */
4195 for (cp = keyhex; *cp; )
4196 if (isspace(*cp))
4197 for (cp1 = cp; *cp1; cp1++)
4198 *cp1 = *(cp1+1);
4199 else
4200 cp++;
4201 if ((new->digestlen = parse_hex(keyhex, (unsigned char *)new->digest, len, NULL, NULL)) == -1)
4202 ret_err(_("bad HEX in trust anchor"));
Simon Kelley0fc2f312014-01-08 10:26:58 +00004203
Simon Kelleyee415862014-02-11 11:07:22 +00004204 new->next = daemon->ds;
4205 daemon->ds = new;
4206
Simon Kelley0fc2f312014-01-08 10:26:58 +00004207 break;
4208 }
4209#endif
4210
Simon Kelley7622fc02009-06-04 20:32:05 +01004211 default:
Simon Kelley0fc2f312014-01-08 10:26:58 +00004212 ret_err(_("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"));
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004213
Simon Kelley849a8352006-06-09 21:02:31 +01004214 }
Simon Kelley824af852008-02-12 20:43:05 +00004215
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004216 return 1;
Simon Kelley849a8352006-06-09 21:02:31 +01004217}
4218
Simon Kelley28866e92011-02-14 20:19:14 +00004219static void read_file(char *file, FILE *f, int hard_opt)
Simon Kelley849a8352006-06-09 21:02:31 +01004220{
Simon Kelley824af852008-02-12 20:43:05 +00004221 volatile int lineno = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004222 char *buff = daemon->namebuff;
Simon Kelley849a8352006-06-09 21:02:31 +01004223
4224 while (fgets(buff, MAXDNAME, f))
4225 {
Simon Kelley7b1eae42014-02-20 13:43:28 +00004226 int white, i;
4227 volatile int option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt;
Simon Kelley13dee6f2017-02-28 16:51:58 +00004228 char *errmess, *p, *arg, *start;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004229 size_t len;
Simon Kelley832af0b2007-01-21 20:01:28 +00004230
Simon Kelley824af852008-02-12 20:43:05 +00004231 /* Memory allocation failure longjmps here if mem_recover == 1 */
Simon Kelley7b1eae42014-02-20 13:43:28 +00004232 if (option != 0 || hard_opt == LOPT_REV_SERV)
Simon Kelley824af852008-02-12 20:43:05 +00004233 {
4234 if (setjmp(mem_jmp))
4235 continue;
4236 mem_recover = 1;
4237 }
4238
Simon Kelley13dee6f2017-02-28 16:51:58 +00004239 arg = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +01004240 lineno++;
Simon Kelley824af852008-02-12 20:43:05 +00004241 errmess = NULL;
4242
Simon Kelley849a8352006-06-09 21:02:31 +01004243 /* Implement quotes, inside quotes we allow \\ \" \n and \t
4244 metacharacters get hidden also strip comments */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004245 for (white = 1, p = buff; *p; p++)
Simon Kelley849a8352006-06-09 21:02:31 +01004246 {
4247 if (*p == '"')
4248 {
4249 memmove(p, p+1, strlen(p+1)+1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004250
Simon Kelley849a8352006-06-09 21:02:31 +01004251 for(; *p && *p != '"'; p++)
4252 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01004253 if (*p == '\\' && strchr("\"tnebr\\", p[1]))
Simon Kelley849a8352006-06-09 21:02:31 +01004254 {
4255 if (p[1] == 't')
4256 p[1] = '\t';
4257 else if (p[1] == 'n')
4258 p[1] = '\n';
Simon Kelley849a8352006-06-09 21:02:31 +01004259 else if (p[1] == 'b')
4260 p[1] = '\b';
4261 else if (p[1] == 'r')
4262 p[1] = '\r';
Simon Kelley6b010842007-02-12 20:32:07 +00004263 else if (p[1] == 'e') /* escape */
4264 p[1] = '\033';
Simon Kelley849a8352006-06-09 21:02:31 +01004265 memmove(p, p+1, strlen(p+1)+1);
4266 }
4267 *p = hide_meta(*p);
4268 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004269
4270 if (*p == 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +01004271 {
4272 errmess = _("missing \"");
4273 goto oops;
4274 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004275
4276 memmove(p, p+1, strlen(p+1)+1);
Simon Kelley849a8352006-06-09 21:02:31 +01004277 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01004278
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004279 if (isspace(*p))
4280 {
4281 *p = ' ';
4282 white = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01004283 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004284 else
4285 {
4286 if (white && *p == '#')
4287 {
4288 *p = 0;
4289 break;
4290 }
4291 white = 0;
4292 }
Simon Kelley849a8352006-06-09 21:02:31 +01004293 }
4294
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004295
4296 /* strip leading spaces */
4297 for (start = buff; *start && *start == ' '; start++);
4298
4299 /* strip trailing spaces */
4300 for (len = strlen(start); (len != 0) && (start[len-1] == ' '); len--);
4301
4302 if (len == 0)
Simon Kelley849a8352006-06-09 21:02:31 +01004303 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004304 else
4305 start[len] = 0;
4306
Simon Kelley611ebc52012-07-16 16:23:46 +01004307 if (option != 0)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004308 arg = start;
4309 else if ((p=strchr(start, '=')))
Simon Kelley849a8352006-06-09 21:02:31 +01004310 {
4311 /* allow spaces around "=" */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004312 for (arg = p+1; *arg == ' '; arg++);
4313 for (; p >= start && (*p == ' ' || *p == '='); p--)
Simon Kelley849a8352006-06-09 21:02:31 +01004314 *p = 0;
4315 }
4316 else
4317 arg = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00004318
Simon Kelley611ebc52012-07-16 16:23:46 +01004319 if (option == 0)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004320 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01004321 for (option = 0, i = 0; opts[i].name; i++)
4322 if (strcmp(opts[i].name, start) == 0)
4323 {
4324 option = opts[i].val;
4325 break;
4326 }
4327
4328 if (!option)
4329 errmess = _("bad option");
4330 else if (opts[i].has_arg == 0 && arg)
4331 errmess = _("extraneous parameter");
4332 else if (opts[i].has_arg == 1 && !arg)
4333 errmess = _("missing parameter");
Simon Kelley7b1eae42014-02-20 13:43:28 +00004334 else if (hard_opt == LOPT_REV_SERV && option != 'S' && option != LOPT_REV_SERV)
4335 errmess = _("illegal option");
Simon Kelley5aabfc72007-08-29 11:24:47 +01004336 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004337
4338 oops:
Simon Kelley832af0b2007-01-21 20:01:28 +00004339 if (errmess)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004340 strcpy(daemon->namebuff, errmess);
4341
Simon Kelley7b1eae42014-02-20 13:43:28 +00004342 if (errmess || !one_opt(option, arg, buff, _("error"), 0, hard_opt == LOPT_REV_SERV))
Simon Kelleyf2621c72007-04-29 19:47:21 +01004343 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004344 sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file);
Simon Kelley824af852008-02-12 20:43:05 +00004345 if (hard_opt != 0)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004346 my_syslog(LOG_ERR, "%s", daemon->namebuff);
Simon Kelley5aabfc72007-08-29 11:24:47 +01004347 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004348 die("%s", daemon->namebuff, EC_BADCONF);
Simon Kelleyf2621c72007-04-29 19:47:21 +01004349 }
Simon Kelley849a8352006-06-09 21:02:31 +01004350 }
4351
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004352 mem_recover = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01004353 fclose(f);
4354}
4355
Simon Kelley4f7bb572018-03-08 18:47:08 +00004356#if defined(HAVE_DHCP) && defined(HAVE_INOTIFY)
Simon Kelley70d18732015-01-31 19:59:29 +00004357int option_read_dynfile(char *file, int flags)
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00004358{
Simon Kelleyf9c86372015-02-03 21:52:48 +00004359 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), file);
4360
Simon Kelley70d18732015-01-31 19:59:29 +00004361 if (flags & AH_DHCP_HST)
4362 return one_file(file, LOPT_BANK);
4363 else if (flags & AH_DHCP_OPT)
4364 return one_file(file, LOPT_OPTS);
Simon Kelleyf9c86372015-02-03 21:52:48 +00004365
Simon Kelley70d18732015-01-31 19:59:29 +00004366 return 0;
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00004367}
4368#endif
4369
Simon Kelley395eb712012-07-06 22:07:05 +01004370static int one_file(char *file, int hard_opt)
Simon Kelley28866e92011-02-14 20:19:14 +00004371{
4372 FILE *f;
4373 int nofile_ok = 0;
4374 static int read_stdin = 0;
4375 static struct fileread {
4376 dev_t dev;
4377 ino_t ino;
4378 struct fileread *next;
4379 } *filesread = NULL;
4380
4381 if (hard_opt == '7')
4382 {
4383 /* default conf-file reading */
4384 hard_opt = 0;
4385 nofile_ok = 1;
4386 }
4387
4388 if (hard_opt == 0 && strcmp(file, "-") == 0)
4389 {
4390 if (read_stdin == 1)
Simon Kelley395eb712012-07-06 22:07:05 +01004391 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00004392 read_stdin = 1;
4393 file = "stdin";
4394 f = stdin;
4395 }
4396 else
4397 {
4398 /* ignore repeated files. */
4399 struct stat statbuf;
4400
4401 if (hard_opt == 0 && stat(file, &statbuf) == 0)
4402 {
4403 struct fileread *r;
4404
4405 for (r = filesread; r; r = r->next)
4406 if (r->dev == statbuf.st_dev && r->ino == statbuf.st_ino)
Simon Kelley395eb712012-07-06 22:07:05 +01004407 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00004408
4409 r = safe_malloc(sizeof(struct fileread));
4410 r->next = filesread;
4411 filesread = r;
4412 r->dev = statbuf.st_dev;
4413 r->ino = statbuf.st_ino;
4414 }
4415
4416 if (!(f = fopen(file, "r")))
4417 {
4418 if (errno == ENOENT && nofile_ok)
Simon Kelley395eb712012-07-06 22:07:05 +01004419 return 1; /* No conffile, all done. */
Simon Kelley28866e92011-02-14 20:19:14 +00004420 else
4421 {
4422 char *str = _("cannot read %s: %s");
4423 if (hard_opt != 0)
4424 {
4425 my_syslog(LOG_ERR, str, file, strerror(errno));
Simon Kelley395eb712012-07-06 22:07:05 +01004426 return 0;
Simon Kelley28866e92011-02-14 20:19:14 +00004427 }
4428 else
4429 die(str, file, EC_FILE);
4430 }
4431 }
4432 }
4433
4434 read_file(file, f, hard_opt);
Simon Kelley395eb712012-07-06 22:07:05 +01004435 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00004436}
4437
4438/* expand any name which is a directory */
4439struct hostsfile *expand_filelist(struct hostsfile *list)
4440{
Simon Kelley19c51cf2014-03-18 22:38:30 +00004441 unsigned int i;
Simon Kelley28866e92011-02-14 20:19:14 +00004442 struct hostsfile *ah;
4443
Simon Kelley19c51cf2014-03-18 22:38:30 +00004444 /* find largest used index */
4445 for (i = SRC_AH, ah = list; ah; ah = ah->next)
Simon Kelley28866e92011-02-14 20:19:14 +00004446 {
4447 if (i <= ah->index)
4448 i = ah->index + 1;
4449
4450 if (ah->flags & AH_DIR)
4451 ah->flags |= AH_INACTIVE;
4452 else
4453 ah->flags &= ~AH_INACTIVE;
4454 }
4455
4456 for (ah = list; ah; ah = ah->next)
4457 if (!(ah->flags & AH_INACTIVE))
4458 {
4459 struct stat buf;
4460 if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode))
4461 {
4462 DIR *dir_stream;
4463 struct dirent *ent;
4464
4465 /* don't read this as a file */
4466 ah->flags |= AH_INACTIVE;
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00004467
Simon Kelley28866e92011-02-14 20:19:14 +00004468 if (!(dir_stream = opendir(ah->fname)))
4469 my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
4470 ah->fname, strerror(errno));
4471 else
4472 {
4473 while ((ent = readdir(dir_stream)))
4474 {
4475 size_t lendir = strlen(ah->fname);
4476 size_t lenfile = strlen(ent->d_name);
4477 struct hostsfile *ah1;
4478 char *path;
4479
4480 /* ignore emacs backups and dotfiles */
4481 if (lenfile == 0 ||
4482 ent->d_name[lenfile - 1] == '~' ||
4483 (ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
4484 ent->d_name[0] == '.')
4485 continue;
4486
4487 /* see if we have an existing record.
4488 dir is ah->fname
4489 file is ent->d_name
4490 path to match is ah1->fname */
4491
4492 for (ah1 = list; ah1; ah1 = ah1->next)
4493 {
4494 if (lendir < strlen(ah1->fname) &&
4495 strstr(ah1->fname, ah->fname) == ah1->fname &&
4496 ah1->fname[lendir] == '/' &&
4497 strcmp(ah1->fname + lendir + 1, ent->d_name) == 0)
4498 {
4499 ah1->flags &= ~AH_INACTIVE;
4500 break;
4501 }
4502 }
4503
4504 /* make new record */
4505 if (!ah1)
4506 {
4507 if (!(ah1 = whine_malloc(sizeof(struct hostsfile))))
4508 continue;
4509
4510 if (!(path = whine_malloc(lendir + lenfile + 2)))
4511 {
4512 free(ah1);
4513 continue;
4514 }
4515
4516 strcpy(path, ah->fname);
4517 strcat(path, "/");
4518 strcat(path, ent->d_name);
4519 ah1->fname = path;
4520 ah1->index = i++;
4521 ah1->flags = AH_DIR;
4522 ah1->next = list;
4523 list = ah1;
4524 }
4525
4526 /* inactivate record if not regular file */
4527 if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode))
4528 ah1->flags |= AH_INACTIVE;
4529
4530 }
4531 closedir(dir_stream);
4532 }
4533 }
4534 }
4535
4536 return list;
4537}
4538
Simon Kelley7b1eae42014-02-20 13:43:28 +00004539void read_servers_file(void)
4540{
4541 FILE *f;
4542
4543 if (!(f = fopen(daemon->servers_file, "r")))
4544 {
4545 my_syslog(LOG_ERR, _("cannot read %s: %s"), daemon->servers_file, strerror(errno));
4546 return;
4547 }
4548
4549 mark_servers(SERV_FROM_FILE);
4550 cleanup_servers();
4551
4552 read_file(daemon->servers_file, f, LOPT_REV_SERV);
4553}
4554
Simon Kelley28866e92011-02-14 20:19:14 +00004555
Simon Kelley7622fc02009-06-04 20:32:05 +01004556#ifdef HAVE_DHCP
Simon Kelley4f7bb572018-03-08 18:47:08 +00004557static void clear_dynamic_conf(void)
4558{
4559 struct dhcp_config *configs, *cp, **up;
4560
4561 /* remove existing... */
4562 for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
4563 {
4564 cp = configs->next;
4565
4566 if (configs->flags & CONFIG_BANK)
4567 {
4568 struct hwaddr_config *mac, *tmp;
4569 struct dhcp_netid_list *list, *tmplist;
4570
4571 for (mac = configs->hwaddr; mac; mac = tmp)
4572 {
4573 tmp = mac->next;
4574 free(mac);
4575 }
4576
4577 if (configs->flags & CONFIG_CLID)
4578 free(configs->clid);
4579
4580 for (list = configs->netid; list; list = tmplist)
4581 {
4582 free(list->list);
4583 tmplist = list->next;
4584 free(list);
4585 }
4586
4587 if (configs->flags & CONFIG_NAME)
4588 free(configs->hostname);
4589
4590 *up = configs->next;
4591 free(configs);
4592 }
4593 else
4594 up = &configs->next;
4595 }
4596}
4597
4598static void clear_dynamic_opt(void)
4599{
4600 struct dhcp_opt *opts, *cp, **up;
4601 struct dhcp_netid *id, *next;
4602
4603 for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
4604 {
4605 cp = opts->next;
4606
4607 if (opts->flags & DHOPT_BANK)
4608 {
4609 if ((opts->flags & DHOPT_VENDOR))
4610 free(opts->u.vendor_class);
4611 free(opts->val);
4612 for (id = opts->netid; id; id = next)
4613 {
4614 next = id->next;
4615 free(id->net);
4616 free(id);
4617 }
4618 *up = opts->next;
4619 free(opts);
4620 }
4621 else
4622 up = &opts->next;
4623 }
4624}
4625
Simon Kelley824af852008-02-12 20:43:05 +00004626void reread_dhcp(void)
4627{
Simon Kelley4f7bb572018-03-08 18:47:08 +00004628 struct hostsfile *hf;
Simon Kelley28866e92011-02-14 20:19:14 +00004629
Simon Kelley4f7bb572018-03-08 18:47:08 +00004630 /* Do these even if there is no daemon->dhcp_hosts_file or
4631 daemon->dhcp_opts_file since entries may have been created by the
4632 inotify dynamic file reading system. */
4633
4634 clear_dynamic_conf();
4635 clear_dynamic_opt();
4636
4637 if (daemon->dhcp_hosts_file)
Simon Kelley824af852008-02-12 20:43:05 +00004638 {
Simon Kelley28866e92011-02-14 20:19:14 +00004639 daemon->dhcp_hosts_file = expand_filelist(daemon->dhcp_hosts_file);
4640 for (hf = daemon->dhcp_hosts_file; hf; hf = hf->next)
Simon Kelley4f7bb572018-03-08 18:47:08 +00004641 if (!(hf->flags & AH_INACTIVE))
4642 {
4643 if (one_file(hf->fname, LOPT_BANK))
4644 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
4645 }
Simon Kelley824af852008-02-12 20:43:05 +00004646 }
4647
4648 if (daemon->dhcp_opts_file)
4649 {
Simon Kelley28866e92011-02-14 20:19:14 +00004650 daemon->dhcp_opts_file = expand_filelist(daemon->dhcp_opts_file);
4651 for (hf = daemon->dhcp_opts_file; hf; hf = hf->next)
4652 if (!(hf->flags & AH_INACTIVE))
4653 {
Simon Kelley395eb712012-07-06 22:07:05 +01004654 if (one_file(hf->fname, LOPT_OPTS))
4655 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
Simon Kelley28866e92011-02-14 20:19:14 +00004656 }
Simon Kelley824af852008-02-12 20:43:05 +00004657 }
Simon Kelley4f7bb572018-03-08 18:47:08 +00004658
4659# ifdef HAVE_INOTIFY
4660 /* Setup notify and read pre-existing files. */
4661 set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
4662# endif
Simon Kelley824af852008-02-12 20:43:05 +00004663}
Simon Kelley7622fc02009-06-04 20:32:05 +01004664#endif
Simon Kelley4f7bb572018-03-08 18:47:08 +00004665
Simon Kelley5aabfc72007-08-29 11:24:47 +01004666void read_opts(int argc, char **argv, char *compile_opts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004667{
Neil Jerram3bd4c472018-01-18 22:49:38 +00004668 size_t argbuf_size = MAXDNAME;
4669 char *argbuf = opt_malloc(argbuf_size);
Simon Kelley824af852008-02-12 20:43:05 +00004670 char *buff = opt_malloc(MAXDNAME);
Simon Kelley28866e92011-02-14 20:19:14 +00004671 int option, conffile_opt = '7', testmode = 0;
Simon Kelley90cb2222015-07-05 21:59:10 +01004672 char *arg, *conffile = CONFFILE;
Simon Kelley849a8352006-06-09 21:02:31 +01004673
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004674 opterr = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +01004675
Simon Kelley824af852008-02-12 20:43:05 +00004676 daemon = opt_malloc(sizeof(struct daemon));
Simon Kelley3be34542004-09-11 19:12:13 +01004677 memset(daemon, 0, sizeof(struct daemon));
4678 daemon->namebuff = buff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004679
Simon Kelley3be34542004-09-11 19:12:13 +01004680 /* Set defaults - everything else is zero or NULL */
Simon Kelley3be34542004-09-11 19:12:13 +01004681 daemon->cachesize = CACHESIZ;
Simon Kelley208b65c2006-08-05 21:41:37 +01004682 daemon->ftabsize = FTABSIZ;
Simon Kelley3be34542004-09-11 19:12:13 +01004683 daemon->port = NAMESERVER_PORT;
Simon Kelley9e038942008-05-30 20:06:34 +01004684 daemon->dhcp_client_port = DHCP_CLIENT_PORT;
4685 daemon->dhcp_server_port = DHCP_SERVER_PORT;
Simon Kelley3be34542004-09-11 19:12:13 +01004686 daemon->default_resolv.is_default = 1;
4687 daemon->default_resolv.name = RESOLVFILE;
4688 daemon->resolv_files = &daemon->default_resolv;
4689 daemon->username = CHUSER;
Simon Kelley3be34542004-09-11 19:12:13 +01004690 daemon->runfile = RUNFILE;
4691 daemon->dhcp_max = MAXLEASES;
Simon Kelley832af0b2007-01-21 20:01:28 +00004692 daemon->tftp_max = TFTP_MAX_CONNECTIONS;
Simon Kelley3be34542004-09-11 19:12:13 +01004693 daemon->edns_pktsz = EDNS_PKTSZ;
Simon Kelley849a8352006-06-09 21:02:31 +01004694 daemon->log_fac = -1;
Simon Kelley4f7b3042012-11-28 21:27:02 +00004695 daemon->auth_ttl = AUTH_TTL;
4696 daemon->soa_refresh = SOA_REFRESH;
4697 daemon->soa_retry = SOA_RETRY;
4698 daemon->soa_expiry = SOA_EXPIRY;
Hans Dedecker926332a2016-01-23 10:48:12 +00004699 daemon->max_port = MAX_PORT;
Simon Kelleybaf553d2018-01-29 22:49:27 +00004700 daemon->min_port = MIN_PORT;
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01004701
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01004702#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +00004703 add_txt("version.bind", "dnsmasq-" VERSION, 0 );
4704 add_txt("authors.bind", "Simon Kelley", 0);
4705 add_txt("copyright.bind", COPYRIGHT, 0);
4706 add_txt("cachesize.bind", NULL, TXT_STAT_CACHESIZE);
4707 add_txt("insertions.bind", NULL, TXT_STAT_INSERTS);
4708 add_txt("evictions.bind", NULL, TXT_STAT_EVICTIONS);
4709 add_txt("misses.bind", NULL, TXT_STAT_MISSES);
4710 add_txt("hits.bind", NULL, TXT_STAT_HITS);
4711#ifdef HAVE_AUTH
4712 add_txt("auth.bind", NULL, TXT_STAT_AUTH);
4713#endif
4714 add_txt("servers.bind", NULL, TXT_STAT_SERVERS);
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01004715#endif
Simon Kelley0a852542005-03-23 20:28:59 +00004716
Simon Kelley849a8352006-06-09 21:02:31 +01004717 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004718 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004719#ifdef HAVE_GETOPT_LONG
Simon Kelley849a8352006-06-09 21:02:31 +01004720 option = getopt_long(argc, argv, OPTSTRING, opts, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004721#else
Simon Kelley849a8352006-06-09 21:02:31 +01004722 option = getopt(argc, argv, OPTSTRING);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004723#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004724
4725 if (option == -1)
Simon Kelley28866e92011-02-14 20:19:14 +00004726 {
Simon Kelley572b41e2011-02-18 18:11:18 +00004727 for (; optind < argc; optind++)
4728 {
4729 unsigned char *c = (unsigned char *)argv[optind];
4730 for (; *c != 0; c++)
4731 if (!isspace(*c))
4732 die(_("junk found in command line"), NULL, EC_BADCONF);
4733 }
Simon Kelley28866e92011-02-14 20:19:14 +00004734 break;
4735 }
4736
Simon Kelley849a8352006-06-09 21:02:31 +01004737 /* Copy optarg so that argv doesn't get changed */
4738 if (optarg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004739 {
Neil Jerram3bd4c472018-01-18 22:49:38 +00004740 if (strlen(optarg) >= argbuf_size)
4741 {
4742 free(argbuf);
4743 argbuf_size = strlen(optarg) + 1;
4744 argbuf = opt_malloc(argbuf_size);
4745 }
4746 strncpy(argbuf, optarg, argbuf_size);
4747 argbuf[argbuf_size-1] = 0;
4748 arg = argbuf;
Simon Kelley849a8352006-06-09 21:02:31 +01004749 }
4750 else
4751 arg = NULL;
4752
4753 /* command-line only stuff */
Simon Kelley7622fc02009-06-04 20:32:05 +01004754 if (option == LOPT_TEST)
4755 testmode = 1;
4756 else if (option == 'w')
Simon Kelley849a8352006-06-09 21:02:31 +01004757 {
Simon Kelley7622fc02009-06-04 20:32:05 +01004758#ifdef HAVE_DHCP
Simon Kelley4cb1b322012-02-06 14:30:41 +00004759 if (argc == 3 && strcmp(argv[2], "dhcp") == 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01004760 display_opts();
Simon Kelley4cb1b322012-02-06 14:30:41 +00004761#ifdef HAVE_DHCP6
4762 else if (argc == 3 && strcmp(argv[2], "dhcp6") == 0)
4763 display_opts6();
Simon Kelley7622fc02009-06-04 20:32:05 +01004764#endif
Simon Kelley4cb1b322012-02-06 14:30:41 +00004765 else
4766#endif
4767 do_usage();
4768
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004769 exit(0);
4770 }
Simon Kelley849a8352006-06-09 21:02:31 +01004771 else if (option == 'v')
4772 {
4773 printf(_("Dnsmasq version %s %s\n"), VERSION, COPYRIGHT);
Simon Kelleyc72daea2012-01-05 21:33:27 +00004774 printf(_("Compile time options: %s\n\n"), compile_opts);
Simon Kelleyb8187c82005-11-26 21:46:27 +00004775 printf(_("This software comes with ABSOLUTELY NO WARRANTY.\n"));
4776 printf(_("Dnsmasq is free software, and you are welcome to redistribute it\n"));
Simon Kelley824af852008-02-12 20:43:05 +00004777 printf(_("under the terms of the GNU General Public License, version 2 or 3.\n"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004778 exit(0);
4779 }
Simon Kelley849a8352006-06-09 21:02:31 +01004780 else if (option == 'C')
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004781 {
Simon Kelley28866e92011-02-14 20:19:14 +00004782 conffile_opt = 0; /* file must exist */
Simon Kelley824af852008-02-12 20:43:05 +00004783 conffile = opt_string_alloc(arg);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004784 }
Simon Kelley849a8352006-06-09 21:02:31 +01004785 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004786 {
Simon Kelley26128d22004-11-14 16:43:54 +00004787#ifdef HAVE_GETOPT_LONG
Simon Kelley7b1eae42014-02-20 13:43:28 +00004788 if (!one_opt(option, arg, daemon->namebuff, _("try --help"), 1, 0))
Simon Kelley849a8352006-06-09 21:02:31 +01004789#else
Simon Kelley7b1eae42014-02-20 13:43:28 +00004790 if (!one_opt(option, arg, daemon->namebuff, _("try -w"), 1, 0))
Simon Kelley849a8352006-06-09 21:02:31 +01004791#endif
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004792 die(_("bad command line options: %s"), daemon->namebuff, EC_BADCONF);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004793 }
4794 }
Simon Kelley849a8352006-06-09 21:02:31 +01004795
Neil Jerram3bd4c472018-01-18 22:49:38 +00004796 free(argbuf);
4797
Simon Kelley849a8352006-06-09 21:02:31 +01004798 if (conffile)
Chen Wei28b879a2015-02-17 22:07:35 +00004799 {
4800 one_file(conffile, conffile_opt);
Simon Kelley90cb2222015-07-05 21:59:10 +01004801 if (conffile_opt == 0)
4802 free(conffile);
Chen Wei28b879a2015-02-17 22:07:35 +00004803 }
Simon Kelley849a8352006-06-09 21:02:31 +01004804
Simon Kelley1a6bca82008-07-11 11:11:42 +01004805 /* port might not be known when the address is parsed - fill in here */
Simon Kelley3be34542004-09-11 19:12:13 +01004806 if (daemon->servers)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004807 {
4808 struct server *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +01004809 for (tmp = daemon->servers; tmp; tmp = tmp->next)
Simon Kelley14ffa072016-04-25 16:36:44 +01004810 if (!(tmp->flags & SERV_HAS_SOURCE))
4811 {
4812 if (tmp->source_addr.sa.sa_family == AF_INET)
4813 tmp->source_addr.in.sin_port = htons(daemon->query_port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004814#ifdef HAVE_IPV6
Simon Kelley14ffa072016-04-25 16:36:44 +01004815 else if (tmp->source_addr.sa.sa_family == AF_INET6)
4816 tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
Simon Kelley5aabfc72007-08-29 11:24:47 +01004817#endif
Simon Kelley14ffa072016-04-25 16:36:44 +01004818 }
4819 }
4820
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004821 if (daemon->host_records)
4822 {
4823 struct host_record *hr;
4824
4825 for (hr = daemon->host_records; hr; hr = hr->next)
4826 if (hr->ttl == -1)
4827 hr->ttl = daemon->local_ttl;
4828 }
4829
4830 if (daemon->cnames)
4831 {
Simon Kelley903df072017-01-19 17:22:00 +00004832 struct cname *cn, *cn2, *cn3;
4833
4834#define NOLOOP 1
4835#define TESTLOOP 2
4836
4837 /* Fill in TTL for CNAMES noe we have local_ttl.
4838 Also prepare to do loop detection. */
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004839 for (cn = daemon->cnames; cn; cn = cn->next)
Simon Kelley903df072017-01-19 17:22:00 +00004840 {
4841 if (cn->ttl == -1)
4842 cn->ttl = daemon->local_ttl;
4843 cn->flag = 0;
4844 cn->targetp = NULL;
4845 for (cn2 = daemon->cnames; cn2; cn2 = cn2->next)
4846 if (hostname_isequal(cn->target, cn2->alias))
4847 {
4848 cn->targetp = cn2;
4849 break;
4850 }
4851 }
4852
4853 /* Find any CNAME loops.*/
4854 for (cn = daemon->cnames; cn; cn = cn->next)
4855 {
4856 for (cn2 = cn->targetp; cn2; cn2 = cn2->targetp)
4857 {
4858 if (cn2->flag == NOLOOP)
4859 break;
4860
4861 if (cn2->flag == TESTLOOP)
4862 die(_("CNAME loop involving %s"), cn->alias, EC_BADCONF);
4863
4864 cn2->flag = TESTLOOP;
4865 }
4866
4867 for (cn3 = cn->targetp; cn3 != cn2; cn3 = cn3->targetp)
4868 cn3->flag = NOLOOP;
4869 }
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004870 }
4871
Simon Kelley3be34542004-09-11 19:12:13 +01004872 if (daemon->if_addrs)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004873 {
4874 struct iname *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +01004875 for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004876 if (tmp->addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +01004877 tmp->addr.in.sin_port = htons(daemon->port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004878#ifdef HAVE_IPV6
4879 else if (tmp->addr.sa.sa_family == AF_INET6)
Simon Kelley3be34542004-09-11 19:12:13 +01004880 tmp->addr.in6.sin6_port = htons(daemon->port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004881#endif /* IPv6 */
4882 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00004883
4884 /* create default, if not specified */
4885 if (daemon->authserver && !daemon->hostmaster)
4886 {
4887 strcpy(buff, "hostmaster.");
4888 strcat(buff, daemon->authserver);
4889 daemon->hostmaster = opt_string_alloc(buff);
4890 }
4891
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004892 /* only one of these need be specified: the other defaults to the host-name */
Simon Kelley28866e92011-02-14 20:19:14 +00004893 if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004894 {
Simon Kelley0a852542005-03-23 20:28:59 +00004895 struct mx_srv_record *mx;
4896
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004897 if (gethostname(buff, MAXDNAME) == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004898 die(_("cannot get host-name: %s"), NULL, EC_MISC);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004899
Simon Kelley0a852542005-03-23 20:28:59 +00004900 for (mx = daemon->mxnames; mx; mx = mx->next)
4901 if (!mx->issrv && hostname_isequal(mx->name, buff))
4902 break;
4903
Simon Kelley28866e92011-02-14 20:19:14 +00004904 if ((daemon->mxtarget || option_bool(OPT_LOCALMX)) && !mx)
Simon Kelleyde379512004-06-22 20:23:33 +01004905 {
Simon Kelley824af852008-02-12 20:43:05 +00004906 mx = opt_malloc(sizeof(struct mx_srv_record));
Simon Kelley91dccd02005-03-31 17:48:32 +01004907 mx->next = daemon->mxnames;
4908 mx->issrv = 0;
4909 mx->target = NULL;
Simon Kelley824af852008-02-12 20:43:05 +00004910 mx->name = opt_string_alloc(buff);
Simon Kelley91dccd02005-03-31 17:48:32 +01004911 daemon->mxnames = mx;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004912 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004913
Simon Kelley3be34542004-09-11 19:12:13 +01004914 if (!daemon->mxtarget)
Simon Kelley824af852008-02-12 20:43:05 +00004915 daemon->mxtarget = opt_string_alloc(buff);
Simon Kelley0a852542005-03-23 20:28:59 +00004916
4917 for (mx = daemon->mxnames; mx; mx = mx->next)
4918 if (!mx->issrv && !mx->target)
4919 mx->target = daemon->mxtarget;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004920 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004921
Simon Kelley28866e92011-02-14 20:19:14 +00004922 if (!option_bool(OPT_NO_RESOLV) &&
Simon Kelley208b65c2006-08-05 21:41:37 +01004923 daemon->resolv_files &&
4924 daemon->resolv_files->next &&
Simon Kelley28866e92011-02-14 20:19:14 +00004925 option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +01004926 die(_("only one resolv.conf file allowed in no-poll mode."), NULL, EC_BADCONF);
Simon Kelleyde379512004-06-22 20:23:33 +01004927
Simon Kelley28866e92011-02-14 20:19:14 +00004928 if (option_bool(OPT_RESOLV_DOMAIN))
Simon Kelleyde379512004-06-22 20:23:33 +01004929 {
4930 char *line;
Simon Kelley849a8352006-06-09 21:02:31 +01004931 FILE *f;
4932
Simon Kelley28866e92011-02-14 20:19:14 +00004933 if (option_bool(OPT_NO_RESOLV) ||
Simon Kelley208b65c2006-08-05 21:41:37 +01004934 !daemon->resolv_files ||
4935 (daemon->resolv_files)->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004936 die(_("must have exactly one resolv.conf to read domain from."), NULL, EC_BADCONF);
Simon Kelleyde379512004-06-22 20:23:33 +01004937
Simon Kelley3be34542004-09-11 19:12:13 +01004938 if (!(f = fopen((daemon->resolv_files)->name, "r")))
Simon Kelley5aabfc72007-08-29 11:24:47 +01004939 die(_("failed to read %s: %s"), (daemon->resolv_files)->name, EC_FILE);
Simon Kelleyde379512004-06-22 20:23:33 +01004940
4941 while ((line = fgets(buff, MAXDNAME, f)))
4942 {
4943 char *token = strtok(line, " \t\n\r");
4944
4945 if (!token || strcmp(token, "search") != 0)
4946 continue;
4947
4948 if ((token = strtok(NULL, " \t\n\r")) &&
Simon Kelley1f15b812009-10-13 17:49:32 +01004949 (daemon->domain_suffix = canonicalise_opt(token)))
Simon Kelleyde379512004-06-22 20:23:33 +01004950 break;
4951 }
Simon Kelley3be34542004-09-11 19:12:13 +01004952
Simon Kelleyde379512004-06-22 20:23:33 +01004953 fclose(f);
Simon Kelley8a911cc2004-03-16 18:35:52 +00004954
Simon Kelley3be34542004-09-11 19:12:13 +01004955 if (!daemon->domain_suffix)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004956 die(_("no search directive found in %s"), (daemon->resolv_files)->name, EC_MISC);
Simon Kelleyde379512004-06-22 20:23:33 +01004957 }
Simon Kelley3d8df262005-08-29 12:19:27 +01004958
4959 if (daemon->domain_suffix)
4960 {
4961 /* add domain for any srv record without one. */
4962 struct mx_srv_record *srv;
Simon Kelleyde379512004-06-22 20:23:33 +01004963
Simon Kelley3d8df262005-08-29 12:19:27 +01004964 for (srv = daemon->mxnames; srv; srv = srv->next)
4965 if (srv->issrv &&
4966 strchr(srv->name, '.') &&
4967 strchr(srv->name, '.') == strrchr(srv->name, '.'))
4968 {
4969 strcpy(buff, srv->name);
4970 strcat(buff, ".");
4971 strcat(buff, daemon->domain_suffix);
4972 free(srv->name);
Simon Kelley824af852008-02-12 20:43:05 +00004973 srv->name = opt_string_alloc(buff);
Simon Kelley3d8df262005-08-29 12:19:27 +01004974 }
4975 }
Simon Kelley28866e92011-02-14 20:19:14 +00004976 else if (option_bool(OPT_DHCP_FQDN))
Simon Kelley9009d742008-11-14 20:04:27 +00004977 die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
Simon Kelley7622fc02009-06-04 20:32:05 +01004978
Simon Kelleyc8a80482014-03-05 14:29:54 +00004979 /* If there's access-control config, then ignore --local-service, it's intended
4980 as a system default to keep otherwise unconfigured installations safe. */
4981 if (daemon->if_names || daemon->if_except || daemon->if_addrs || daemon->authserver)
4982 reset_option_bool(OPT_LOCAL_SERVICE);
4983
Simon Kelley7622fc02009-06-04 20:32:05 +01004984 if (testmode)
4985 {
4986 fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
4987 exit(0);
4988 }
Simon Kelley849a8352006-06-09 21:02:31 +01004989}