blob: c2038268b5a47e3b142d672a709b52efeed3510b [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 Kelleydd33e982018-07-30 14:55:39 +01002235 if (new->prefix &&
2236 (star = strrchr(new->prefix, '*'))
2237 && *(star+1) == 0)
Simon Kelley6b2b5642018-03-10 18:12:04 +00002238 {
2239 *star = 0;
2240 new->indexed = 1;
2241 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01002242 }
Simon Kelley9009d742008-11-14 20:04:27 +00002243 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01002244 else if (option == 's')
Simon Kelley9009d742008-11-14 20:04:27 +00002245 daemon->domain_suffix = d;
Simon Kelley2bb73af2013-04-24 17:38:19 +01002246 else
2247 ret_err(gen_err);
Simon Kelley9009d742008-11-14 20:04:27 +00002248 }
2249 }
Simon Kelley849a8352006-06-09 21:02:31 +01002250 break;
2251
Simon Kelley1e505122016-01-25 21:29:23 +00002252 case LOPT_CPE_ID: /* --add-dns-client */
2253 if (arg)
Simon Kelley33702ab2015-12-28 23:17:15 +00002254 daemon->dns_client_id = opt_string_alloc(arg);
2255 break;
2256
Simon Kelleyc7f3bd22016-02-28 21:48:34 +00002257 case LOPT_ADD_MAC: /* --add-mac */
Simon Kelley1e505122016-01-25 21:29:23 +00002258 if (!arg)
2259 set_option_bool(OPT_ADD_MAC);
2260 else
2261 {
2262 unhide_metas(arg);
2263 if (strcmp(arg, "base64") == 0)
2264 set_option_bool(OPT_MAC_B64);
Simon Kelley9e4cf472016-02-17 20:26:32 +00002265 else if (strcmp(arg, "text") == 0)
2266 set_option_bool(OPT_MAC_HEX);
Simon Kelley22c0f4f2016-02-17 22:12:31 +00002267 else
2268 ret_err(gen_err);
Simon Kelley1e505122016-01-25 21:29:23 +00002269 }
2270 break;
2271
Simon Kelleyf2621c72007-04-29 19:47:21 +01002272 case 'u': /* --user */
Simon Kelley824af852008-02-12 20:43:05 +00002273 daemon->username = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002274 break;
2275
Simon Kelleyf2621c72007-04-29 19:47:21 +01002276 case 'g': /* --group */
Simon Kelley824af852008-02-12 20:43:05 +00002277 daemon->groupname = opt_string_alloc(arg);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002278 daemon->group_set = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01002279 break;
Simon Kelley9e038942008-05-30 20:06:34 +01002280
Simon Kelley7622fc02009-06-04 20:32:05 +01002281#ifdef HAVE_DHCP
Simon Kelley9e038942008-05-30 20:06:34 +01002282 case LOPT_SCRIPTUSR: /* --scriptuser */
2283 daemon->scriptuser = opt_string_alloc(arg);
2284 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01002285#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002286
Simon Kelleyf2621c72007-04-29 19:47:21 +01002287 case 'i': /* --interface */
Simon Kelley849a8352006-06-09 21:02:31 +01002288 do {
Simon Kelley824af852008-02-12 20:43:05 +00002289 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01002290 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002291 new->next = daemon->if_names;
2292 daemon->if_names = new;
2293 /* new->name may be NULL if someone does
2294 "interface=" to disable all interfaces except loop. */
Simon Kelley824af852008-02-12 20:43:05 +00002295 new->name = opt_string_alloc(arg);
Simon Kelley4ce4f372012-06-14 11:50:45 +01002296 new->used = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002297 arg = comma;
2298 } while (arg);
2299 break;
2300
Simon Kelley2937f8a2013-07-29 19:49:07 +01002301 case LOPT_TFTP: /* --enable-tftp */
2302 set_option_bool(OPT_TFTP);
2303 if (!arg)
2304 break;
2305 /* fall through */
2306
Simon Kelleyf2621c72007-04-29 19:47:21 +01002307 case 'I': /* --except-interface */
2308 case '2': /* --no-dhcp-interface */
Simon Kelley849a8352006-06-09 21:02:31 +01002309 do {
Simon Kelley824af852008-02-12 20:43:05 +00002310 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01002311 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00002312 new->name = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002313 if (option == 'I')
2314 {
2315 new->next = daemon->if_except;
2316 daemon->if_except = new;
2317 }
Simon Kelley2937f8a2013-07-29 19:49:07 +01002318 else if (option == LOPT_TFTP)
2319 {
2320 new->next = daemon->tftp_interfaces;
2321 daemon->tftp_interfaces = new;
2322 }
Simon Kelley849a8352006-06-09 21:02:31 +01002323 else
2324 {
2325 new->next = daemon->dhcp_except;
2326 daemon->dhcp_except = new;
2327 }
2328 arg = comma;
2329 } while (arg);
2330 break;
2331
Simon Kelleyf2621c72007-04-29 19:47:21 +01002332 case 'B': /* --bogus-nxdomain */
Glen Huang32fc6db2014-12-27 15:28:12 +00002333 case LOPT_IGNORE_ADDR: /* --ignore-address */
2334 {
Simon Kelley849a8352006-06-09 21:02:31 +01002335 struct in_addr addr;
2336 unhide_metas(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002337 if (arg && (inet_pton(AF_INET, arg, &addr) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01002338 {
Simon Kelley824af852008-02-12 20:43:05 +00002339 struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
Glen Huang32fc6db2014-12-27 15:28:12 +00002340 if (option == 'B')
2341 {
2342 baddr->next = daemon->bogus_addr;
2343 daemon->bogus_addr = baddr;
2344 }
2345 else
2346 {
2347 baddr->next = daemon->ignore_addr;
2348 daemon->ignore_addr = baddr;
2349 }
Simon Kelley849a8352006-06-09 21:02:31 +01002350 baddr->addr = addr;
2351 }
2352 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002353 ret_err(gen_err); /* error */
Simon Kelley849a8352006-06-09 21:02:31 +01002354 break;
2355 }
2356
Simon Kelleyf2621c72007-04-29 19:47:21 +01002357 case 'a': /* --listen-address */
Simon Kelley49678762012-12-09 18:24:58 +00002358 case LOPT_AUTHPEER: /* --auth-peer */
Simon Kelley849a8352006-06-09 21:02:31 +01002359 do {
Simon Kelley824af852008-02-12 20:43:05 +00002360 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01002361 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002362 unhide_metas(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002363 if (arg && (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01002364 {
2365 new->addr.sa.sa_family = AF_INET;
Simon Kelley49678762012-12-09 18:24:58 +00002366 new->addr.in.sin_port = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002367#ifdef HAVE_SOCKADDR_SA_LEN
2368 new->addr.in.sin_len = sizeof(new->addr.in);
2369#endif
2370 }
2371#ifdef HAVE_IPV6
2372 else if (arg && inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
2373 {
2374 new->addr.sa.sa_family = AF_INET6;
2375 new->addr.in6.sin6_flowinfo = 0;
2376 new->addr.in6.sin6_scope_id = 0;
Simon Kelley49678762012-12-09 18:24:58 +00002377 new->addr.in6.sin6_port = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002378#ifdef HAVE_SOCKADDR_SA_LEN
2379 new->addr.in6.sin6_len = sizeof(new->addr.in6);
2380#endif
2381 }
2382#endif
2383 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002384 ret_err(gen_err);
Simon Kelley4ce4f372012-06-14 11:50:45 +01002385
2386 new->used = 0;
Simon Kelley49678762012-12-09 18:24:58 +00002387 if (option == 'a')
2388 {
2389 new->next = daemon->if_addrs;
2390 daemon->if_addrs = new;
2391 }
2392 else
2393 {
2394 new->next = daemon->auth_peers;
2395 daemon->auth_peers = new;
2396 }
Simon Kelley849a8352006-06-09 21:02:31 +01002397 arg = comma;
2398 } while (arg);
2399 break;
2400
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002401 case 'S': /* --server */
2402 case LOPT_LOCAL: /* --local */
2403 case 'A': /* --address */
2404 case LOPT_NO_REBIND: /* --rebind-domain-ok */
Simon Kelley849a8352006-06-09 21:02:31 +01002405 {
2406 struct server *serv, *newlist = NULL;
2407
2408 unhide_metas(arg);
2409
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002410 if (arg && (*arg == '/' || option == LOPT_NO_REBIND))
Simon Kelley849a8352006-06-09 21:02:31 +01002411 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002412 int rebind = !(*arg == '/');
2413 char *end = NULL;
2414 if (!rebind)
2415 arg++;
2416 while (rebind || (end = split_chr(arg, '/')))
Simon Kelley849a8352006-06-09 21:02:31 +01002417 {
2418 char *domain = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002419 /* elide leading dots - they are implied in the search algorithm */
2420 while (*arg == '.') arg++;
Simon Kelley849a8352006-06-09 21:02:31 +01002421 /* # matches everything and becomes a zero length domain string */
2422 if (strcmp(arg, "#") == 0)
2423 domain = "";
Simon Kelley1f15b812009-10-13 17:49:32 +01002424 else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
Simon Kelleya3bd7e72018-07-19 22:00:08 +01002425 ret_err(gen_err);
Simon Kelley824af852008-02-12 20:43:05 +00002426 serv = opt_malloc(sizeof(struct server));
2427 memset(serv, 0, sizeof(struct server));
Simon Kelley849a8352006-06-09 21:02:31 +01002428 serv->next = newlist;
2429 newlist = serv;
Simon Kelley849a8352006-06-09 21:02:31 +01002430 serv->domain = domain;
2431 serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
Simon Kelley73a08a22009-02-05 20:28:08 +00002432 arg = end;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002433 if (rebind)
2434 break;
Simon Kelley849a8352006-06-09 21:02:31 +01002435 }
2436 if (!newlist)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002437 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002438 }
2439 else
2440 {
Simon Kelley824af852008-02-12 20:43:05 +00002441 newlist = opt_malloc(sizeof(struct server));
2442 memset(newlist, 0, sizeof(struct server));
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002443#ifdef HAVE_LOOP
2444 newlist->uid = rand32();
2445#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002446 }
2447
Simon Kelley7b1eae42014-02-20 13:43:28 +00002448 if (servers_only && option == 'S')
2449 newlist->flags |= SERV_FROM_FILE;
2450
Simon Kelley849a8352006-06-09 21:02:31 +01002451 if (option == 'A')
2452 {
2453 newlist->flags |= SERV_LITERAL_ADDRESS;
2454 if (!(newlist->flags & SERV_TYPE))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002455 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002456 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002457 else if (option == LOPT_NO_REBIND)
2458 newlist->flags |= SERV_NO_REBIND;
Simon Kelley849a8352006-06-09 21:02:31 +01002459
2460 if (!arg || !*arg)
2461 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002462 if (!(newlist->flags & SERV_NO_REBIND))
2463 newlist->flags |= SERV_NO_ADDR; /* no server */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002464 }
2465
2466 else if (strcmp(arg, "#") == 0)
2467 {
2468 newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
Simon Kelley849a8352006-06-09 21:02:31 +01002469 if (newlist->flags & SERV_LITERAL_ADDRESS)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002470 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002471 }
2472 else
2473 {
Simon Kelleyfaafb3f2012-09-20 14:17:39 +01002474 char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
2475 if (err)
2476 ret_err(err);
Simon Kelley849a8352006-06-09 21:02:31 +01002477 }
2478
Simon Kelleyf2621c72007-04-29 19:47:21 +01002479 serv = newlist;
2480 while (serv->next)
Simon Kelley849a8352006-06-09 21:02:31 +01002481 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01002482 serv->next->flags = serv->flags;
2483 serv->next->addr = serv->addr;
2484 serv->next->source_addr = serv->source_addr;
Simon Kelleyfaafb3f2012-09-20 14:17:39 +01002485 strcpy(serv->next->interface, serv->interface);
Simon Kelleyf2621c72007-04-29 19:47:21 +01002486 serv = serv->next;
Simon Kelley849a8352006-06-09 21:02:31 +01002487 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01002488 serv->next = daemon->servers;
2489 daemon->servers = newlist;
Simon Kelley849a8352006-06-09 21:02:31 +01002490 break;
2491 }
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002492
Simon Kelleyde73a492014-02-17 21:43:27 +00002493 case LOPT_REV_SERV: /* --rev-server */
2494 {
2495 char *string;
2496 int size;
2497 struct server *serv;
2498 struct in_addr addr4;
2499#ifdef HAVE_IPV6
2500 struct in6_addr addr6;
2501#endif
2502
2503 unhide_metas(arg);
2504 if (!arg || !(comma=split(arg)) || !(string = split_chr(arg, '/')) || !atoi_check(string, &size))
2505 ret_err(gen_err);
2506
2507 if (inet_pton(AF_INET, arg, &addr4))
Olivier Gayotdc990582017-03-06 22:17:21 +00002508 {
2509 serv = add_rev4(addr4, size);
2510 if (!serv)
2511 ret_err(_("bad prefix"));
2512 }
Simon Kelleyde73a492014-02-17 21:43:27 +00002513#ifdef HAVE_IPV6
2514 else if (inet_pton(AF_INET6, arg, &addr6))
2515 serv = add_rev6(&addr6, size);
2516#endif
2517 else
2518 ret_err(gen_err);
2519
2520 string = parse_server(comma, &serv->addr, &serv->source_addr, serv->interface, &serv->flags);
2521
2522 if (string)
2523 ret_err(string);
Simon Kelley7b1eae42014-02-20 13:43:28 +00002524
2525 if (servers_only)
2526 serv->flags |= SERV_FROM_FILE;
2527
Simon Kelleyde73a492014-02-17 21:43:27 +00002528 break;
2529 }
2530
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002531 case LOPT_IPSET: /* --ipset */
2532#ifndef HAVE_IPSET
2533 ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
2534 break;
2535#else
2536 {
2537 struct ipsets ipsets_head;
2538 struct ipsets *ipsets = &ipsets_head;
2539 int size;
2540 char *end;
2541 char **sets, **sets_pos;
2542 memset(ipsets, 0, sizeof(struct ipsets));
2543 unhide_metas(arg);
2544 if (arg && *arg == '/')
2545 {
2546 arg++;
2547 while ((end = split_chr(arg, '/')))
2548 {
2549 char *domain = NULL;
2550 /* elide leading dots - they are implied in the search algorithm */
2551 while (*arg == '.')
2552 arg++;
2553 /* # matches everything and becomes a zero length domain string */
2554 if (strcmp(arg, "#") == 0 || !*arg)
2555 domain = "";
2556 else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg)))
Simon Kelleya3bd7e72018-07-19 22:00:08 +01002557 ret_err(gen_err);
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002558 ipsets->next = opt_malloc(sizeof(struct ipsets));
2559 ipsets = ipsets->next;
2560 memset(ipsets, 0, sizeof(struct ipsets));
2561 ipsets->domain = domain;
2562 arg = end;
2563 }
2564 }
2565 else
2566 {
2567 ipsets->next = opt_malloc(sizeof(struct ipsets));
2568 ipsets = ipsets->next;
2569 memset(ipsets, 0, sizeof(struct ipsets));
2570 ipsets->domain = "";
2571 }
Simon Kelleya3bd7e72018-07-19 22:00:08 +01002572
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002573 if (!arg || !*arg)
Simon Kelleya3bd7e72018-07-19 22:00:08 +01002574 ret_err(gen_err);
2575
2576 for (size = 2, end = arg; *end; ++end)
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002577 if (*end == ',')
2578 ++size;
2579
2580 sets = sets_pos = opt_malloc(sizeof(char *) * size);
2581
2582 do {
2583 end = split(arg);
2584 *sets_pos++ = opt_string_alloc(arg);
2585 arg = end;
2586 } while (end);
2587 *sets_pos = 0;
2588 for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next)
2589 ipsets->next->sets = sets;
2590 ipsets->next = daemon->ipsets;
2591 daemon->ipsets = ipsets_head.next;
2592
2593 break;
2594 }
2595#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002596
Simon Kelleyf2621c72007-04-29 19:47:21 +01002597 case 'c': /* --cache-size */
Simon Kelley849a8352006-06-09 21:02:31 +01002598 {
2599 int size;
2600
2601 if (!atoi_check(arg, &size))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002602 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002603 else
2604 {
2605 /* zero is OK, and means no caching. */
2606
2607 if (size < 0)
2608 size = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002609
2610 daemon->cachesize = size;
2611 }
2612 break;
2613 }
2614
Simon Kelleyf2621c72007-04-29 19:47:21 +01002615 case 'p': /* --port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002616 if (!atoi_check16(arg, &daemon->port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002617 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002618 break;
Simon Kelley208b65c2006-08-05 21:41:37 +01002619
Simon Kelley1a6bca82008-07-11 11:11:42 +01002620 case LOPT_MINPORT: /* --min-port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002621 if (!atoi_check16(arg, &daemon->min_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002622 ret_err(gen_err);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002623 break;
2624
Hans Dedecker926332a2016-01-23 10:48:12 +00002625 case LOPT_MAXPORT: /* --max-port */
2626 if (!atoi_check16(arg, &daemon->max_port))
2627 ret_err(gen_err);
2628 break;
2629
Simon Kelleyf2621c72007-04-29 19:47:21 +01002630 case '0': /* --dns-forward-max */
Simon Kelley208b65c2006-08-05 21:41:37 +01002631 if (!atoi_check(arg, &daemon->ftabsize))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002632 ret_err(gen_err);
Simon Kelley208b65c2006-08-05 21:41:37 +01002633 break;
2634
Simon Kelley25cf5e32015-01-09 15:53:03 +00002635 case 'q': /* --log-queries */
2636 set_option_bool(OPT_LOG);
2637 if (arg && strcmp(arg, "extra") == 0)
2638 set_option_bool(OPT_EXTRALOG);
2639 break;
2640
Simon Kelleyf2621c72007-04-29 19:47:21 +01002641 case LOPT_MAX_LOGS: /* --log-async */
2642 daemon->max_logs = LOG_MAX; /* default */
2643 if (arg && !atoi_check(arg, &daemon->max_logs))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002644 ret_err(gen_err);
Simon Kelleyf2621c72007-04-29 19:47:21 +01002645 else if (daemon->max_logs > 100)
2646 daemon->max_logs = 100;
2647 break;
2648
2649 case 'P': /* --edns-packet-max */
Simon Kelley849a8352006-06-09 21:02:31 +01002650 {
2651 int i;
2652 if (!atoi_check(arg, &i))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002653 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002654 daemon->edns_pktsz = (unsigned short)i;
2655 break;
2656 }
2657
Simon Kelleyf2621c72007-04-29 19:47:21 +01002658 case 'Q': /* --query-port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002659 if (!atoi_check16(arg, &daemon->query_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002660 ret_err(gen_err);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002661 /* if explicitly set to zero, use single OS ephemeral port
2662 and disable random ports */
2663 if (daemon->query_port == 0)
2664 daemon->osport = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01002665 break;
2666
Simon Kelley824af852008-02-12 20:43:05 +00002667 case 'T': /* --local-ttl */
2668 case LOPT_NEGTTL: /* --neg-ttl */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002669 case LOPT_MAXTTL: /* --max-ttl */
RinSatsuki28de3872015-01-10 15:22:21 +00002670 case LOPT_MINCTTL: /* --min-cache-ttl */
Simon Kelley1d860412012-09-20 20:48:04 +01002671 case LOPT_MAXCTTL: /* --max-cache-ttl */
Simon Kelley4f7b3042012-11-28 21:27:02 +00002672 case LOPT_AUTHTTL: /* --auth-ttl */
Simon Kelley832e47b2016-02-24 21:24:45 +00002673 case LOPT_DHCPTTL: /* --dhcp-ttl */
Simon Kelley849a8352006-06-09 21:02:31 +01002674 {
2675 int ttl;
2676 if (!atoi_check(arg, &ttl))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002677 ret_err(gen_err);
Simon Kelley824af852008-02-12 20:43:05 +00002678 else if (option == LOPT_NEGTTL)
2679 daemon->neg_ttl = (unsigned long)ttl;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002680 else if (option == LOPT_MAXTTL)
2681 daemon->max_ttl = (unsigned long)ttl;
RinSatsuki28de3872015-01-10 15:22:21 +00002682 else if (option == LOPT_MINCTTL)
2683 {
2684 if (ttl > TTL_FLOOR_LIMIT)
2685 ttl = TTL_FLOOR_LIMIT;
2686 daemon->min_cache_ttl = (unsigned long)ttl;
2687 }
Simon Kelley1d860412012-09-20 20:48:04 +01002688 else if (option == LOPT_MAXCTTL)
2689 daemon->max_cache_ttl = (unsigned long)ttl;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002690 else if (option == LOPT_AUTHTTL)
2691 daemon->auth_ttl = (unsigned long)ttl;
Simon Kelley832e47b2016-02-24 21:24:45 +00002692 else if (option == LOPT_DHCPTTL)
2693 {
2694 daemon->dhcp_ttl = (unsigned long)ttl;
2695 daemon->use_dhcp_ttl = 1;
2696 }
Simon Kelley849a8352006-06-09 21:02:31 +01002697 else
2698 daemon->local_ttl = (unsigned long)ttl;
2699 break;
2700 }
2701
Simon Kelley7622fc02009-06-04 20:32:05 +01002702#ifdef HAVE_DHCP
Simon Kelleyf2621c72007-04-29 19:47:21 +01002703 case 'X': /* --dhcp-lease-max */
Simon Kelley849a8352006-06-09 21:02:31 +01002704 if (!atoi_check(arg, &daemon->dhcp_max))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002705 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002706 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01002707#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002708
Simon Kelley7622fc02009-06-04 20:32:05 +01002709#ifdef HAVE_TFTP
Simon Kelleyf2621c72007-04-29 19:47:21 +01002710 case LOPT_TFTP_MAX: /* --tftp-max */
Simon Kelley832af0b2007-01-21 20:01:28 +00002711 if (!atoi_check(arg, &daemon->tftp_max))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002712 ret_err(gen_err);
Simon Kelley832af0b2007-01-21 20:01:28 +00002713 break;
2714
Simon Kelleybec366b2016-02-24 22:03:26 +00002715 case LOPT_TFTP_MTU: /* --tftp-mtu */
2716 if (!atoi_check(arg, &daemon->tftp_mtu))
2717 ret_err(gen_err);
2718 break;
2719
Simon Kelley824af852008-02-12 20:43:05 +00002720 case LOPT_PREFIX: /* --tftp-prefix */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002721 comma = split(arg);
2722 if (comma)
2723 {
2724 struct tftp_prefix *new = opt_malloc(sizeof(struct tftp_prefix));
2725 new->interface = opt_string_alloc(comma);
2726 new->prefix = opt_string_alloc(arg);
2727 new->next = daemon->if_prefix;
2728 daemon->if_prefix = new;
2729 }
2730 else
2731 daemon->tftp_prefix = opt_string_alloc(arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00002732 break;
2733
Simon Kelley824af852008-02-12 20:43:05 +00002734 case LOPT_TFTPPORTS: /* --tftp-port-range */
2735 if (!(comma = split(arg)) ||
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002736 !atoi_check16(arg, &daemon->start_tftp_port) ||
2737 !atoi_check16(comma, &daemon->end_tftp_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002738 ret_err(_("bad port range"));
Simon Kelley824af852008-02-12 20:43:05 +00002739
2740 if (daemon->start_tftp_port > daemon->end_tftp_port)
2741 {
2742 int tmp = daemon->start_tftp_port;
2743 daemon->start_tftp_port = daemon->end_tftp_port;
2744 daemon->end_tftp_port = tmp;
2745 }
2746
2747 break;
Floris Bos60704f52017-04-09 22:22:49 +01002748
2749 case LOPT_APREF: /* --tftp-unique-root */
2750 if (!arg || strcasecmp(arg, "ip") == 0)
2751 set_option_bool(OPT_TFTP_APREF_IP);
2752 else if (strcasecmp(arg, "mac") == 0)
2753 set_option_bool(OPT_TFTP_APREF_MAC);
2754 else
2755 ret_err(gen_err);
2756 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01002757#endif
Simon Kelley824af852008-02-12 20:43:05 +00002758
Simon Kelleyf2621c72007-04-29 19:47:21 +01002759 case LOPT_BRIDGE: /* --bridge-interface */
Simon Kelley832af0b2007-01-21 20:01:28 +00002760 {
Simon Kelley22cd8602018-01-14 22:57:14 +00002761 struct dhcp_bridge *new;
2762
Simon Kelley316e2732010-01-22 20:16:09 +00002763 if (!(comma = split(arg)) || strlen(arg) > IF_NAMESIZE - 1 )
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002764 ret_err(_("bad bridge-interface"));
Simon Kelley832af0b2007-01-21 20:01:28 +00002765
Simon Kelley22cd8602018-01-14 22:57:14 +00002766 for (new = daemon->bridges; new; new = new->next)
2767 if (strcmp(new->iface, arg) == 0)
2768 break;
2769
2770 if (!new)
2771 {
2772 new = opt_malloc(sizeof(struct dhcp_bridge));
2773 strcpy(new->iface, arg);
2774 new->alias = NULL;
2775 new->next = daemon->bridges;
2776 daemon->bridges = new;
2777 }
2778
Simon Kelley832af0b2007-01-21 20:01:28 +00002779 do {
Simon Kelleyf2621c72007-04-29 19:47:21 +01002780 arg = comma;
2781 comma = split(arg);
Simon Kelley316e2732010-01-22 20:16:09 +00002782 if (strlen(arg) != 0 && strlen(arg) <= IF_NAMESIZE - 1)
Simon Kelley832af0b2007-01-21 20:01:28 +00002783 {
Simon Kelley824af852008-02-12 20:43:05 +00002784 struct dhcp_bridge *b = opt_malloc(sizeof(struct dhcp_bridge));
Simon Kelley832af0b2007-01-21 20:01:28 +00002785 b->next = new->alias;
2786 new->alias = b;
Simon Kelley316e2732010-01-22 20:16:09 +00002787 strcpy(b->iface, arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00002788 }
2789 } while (comma);
2790
2791 break;
2792 }
Simon Kelley832af0b2007-01-21 20:01:28 +00002793
Simon Kelley7622fc02009-06-04 20:32:05 +01002794#ifdef HAVE_DHCP
Simon Kelleyf2621c72007-04-29 19:47:21 +01002795 case 'F': /* --dhcp-range */
Simon Kelley849a8352006-06-09 21:02:31 +01002796 {
2797 int k, leasepos = 2;
Simon Kelley8445f5d2012-12-17 21:54:08 +00002798 char *cp, *a[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
Simon Kelley824af852008-02-12 20:43:05 +00002799 struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
Simon Kelley849a8352006-06-09 21:02:31 +01002800
Simon Kelley52b92f42012-01-22 16:05:15 +00002801 memset (new, 0, sizeof(*new));
Simon Kelley849a8352006-06-09 21:02:31 +01002802 new->lease_time = DEFLEASE;
Simon Kelley52b92f42012-01-22 16:05:15 +00002803
Simon Kelley849a8352006-06-09 21:02:31 +01002804 while(1)
2805 {
2806 for (cp = arg; *cp; cp++)
Simon Kelley52b92f42012-01-22 16:05:15 +00002807 if (!(*cp == ' ' || *cp == '.' || *cp == ':' ||
2808 (*cp >= 'a' && *cp <= 'f') || (*cp >= 'A' && *cp <= 'F') ||
2809 (*cp >='0' && *cp <= '9')))
Simon Kelley849a8352006-06-09 21:02:31 +01002810 break;
2811
Simon Kelleyf2621c72007-04-29 19:47:21 +01002812 if (*cp != ',' && (comma = split(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01002813 {
Simon Kelley8bc4cec2012-07-03 21:04:11 +01002814 if (is_tag_prefix(arg))
Simon Kelley849a8352006-06-09 21:02:31 +01002815 {
Simon Kelley824af852008-02-12 20:43:05 +00002816 struct dhcp_netid *tt = opt_malloc(sizeof (struct dhcp_netid));
2817 tt->net = opt_string_alloc(arg+4);
Simon Kelley849a8352006-06-09 21:02:31 +01002818 tt->next = new->filter;
Simon Kelley0c387192013-09-05 10:21:12 +01002819 /* ignore empty tag */
2820 if (tt->net)
2821 new->filter = tt;
Simon Kelley849a8352006-06-09 21:02:31 +01002822 }
2823 else
2824 {
2825 if (new->netid.net)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002826 ret_err(_("only one tag allowed"));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002827 else if (strstr(arg, "set:") == arg)
2828 new->netid.net = opt_string_alloc(arg+4);
Simon Kelley849a8352006-06-09 21:02:31 +01002829 else
Simon Kelley824af852008-02-12 20:43:05 +00002830 new->netid.net = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002831 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01002832 arg = comma;
Simon Kelley849a8352006-06-09 21:02:31 +01002833 }
2834 else
2835 {
2836 a[0] = arg;
2837 break;
2838 }
2839 }
2840
Simon Kelley1f776932012-12-16 19:46:08 +00002841 for (k = 1; k < 8; k++)
Simon Kelleyf2621c72007-04-29 19:47:21 +01002842 if (!(a[k] = split(a[k-1])))
2843 break;
Simon Kelley849a8352006-06-09 21:02:31 +01002844
Simon Kelley52b92f42012-01-22 16:05:15 +00002845 if (k < 2)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002846 ret_err(_("bad dhcp-range"));
2847
2848 if (inet_pton(AF_INET, a[0], &new->start))
Simon Kelley849a8352006-06-09 21:02:31 +01002849 {
Simon Kelley52b92f42012-01-22 16:05:15 +00002850 new->next = daemon->dhcp;
2851 daemon->dhcp = new;
Simon Kelley30cd9662012-03-25 20:44:38 +01002852 new->end = new->start;
Simon Kelley52b92f42012-01-22 16:05:15 +00002853 if (strcmp(a[1], "static") == 0)
Simon Kelley30cd9662012-03-25 20:44:38 +01002854 new->flags |= CONTEXT_STATIC;
Simon Kelley52b92f42012-01-22 16:05:15 +00002855 else if (strcmp(a[1], "proxy") == 0)
Simon Kelley30cd9662012-03-25 20:44:38 +01002856 new->flags |= CONTEXT_PROXY;
2857 else if (!inet_pton(AF_INET, a[1], &new->end))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002858 ret_err(_("bad dhcp-range"));
Simon Kelley52b92f42012-01-22 16:05:15 +00002859
2860 if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
2861 {
2862 struct in_addr tmp = new->start;
2863 new->start = new->end;
2864 new->end = tmp;
2865 }
2866
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002867 if (k >= 3 && strchr(a[2], '.') &&
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002868 (inet_pton(AF_INET, a[2], &new->netmask) > 0))
Simon Kelley52b92f42012-01-22 16:05:15 +00002869 {
2870 new->flags |= CONTEXT_NETMASK;
2871 leasepos = 3;
2872 if (!is_same_net(new->start, new->end, new->netmask))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002873 ret_err(_("inconsistent DHCP range"));
Simon Kelleyfa794662016-03-03 20:33:54 +00002874
Simon Kelley52b92f42012-01-22 16:05:15 +00002875
Simon Kelleyfa794662016-03-03 20:33:54 +00002876 if (k >= 4 && strchr(a[3], '.') &&
2877 (inet_pton(AF_INET, a[3], &new->broadcast) > 0))
2878 {
2879 new->flags |= CONTEXT_BRDCAST;
2880 leasepos = 4;
2881 }
Simon Kelley52b92f42012-01-22 16:05:15 +00002882 }
Simon Kelley849a8352006-06-09 21:02:31 +01002883 }
Simon Kelley52b92f42012-01-22 16:05:15 +00002884#ifdef HAVE_DHCP6
2885 else if (inet_pton(AF_INET6, a[0], &new->start6))
Simon Kelley7622fc02009-06-04 20:32:05 +01002886 {
Simon Kelley89500e32013-09-20 16:29:20 +01002887 new->flags |= CONTEXT_V6;
Simon Kelley52b92f42012-01-22 16:05:15 +00002888 new->prefix = 64; /* default */
Simon Kelley30cd9662012-03-25 20:44:38 +01002889 new->end6 = new->start6;
Simon Kelley6692a1a2013-08-20 14:41:31 +01002890 new->next = daemon->dhcp6;
2891 daemon->dhcp6 = new;
2892
Simon Kelley30cd9662012-03-25 20:44:38 +01002893 for (leasepos = 1; leasepos < k; leasepos++)
2894 {
2895 if (strcmp(a[leasepos], "static") == 0)
2896 new->flags |= CONTEXT_STATIC | CONTEXT_DHCP;
2897 else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 )
Simon Kelley7ea3d3f2014-04-25 22:04:05 +01002898 new->flags |= CONTEXT_RA;
Simon Kelley30cd9662012-03-25 20:44:38 +01002899 else if (strcmp(a[leasepos], "ra-names") == 0)
Simon Kelley1f776932012-12-16 19:46:08 +00002900 new->flags |= CONTEXT_RA_NAME | CONTEXT_RA;
Simon Kelley7ea3d3f2014-04-25 22:04:05 +01002901 else if (strcmp(a[leasepos], "ra-advrouter") == 0)
2902 new->flags |= CONTEXT_RA_ROUTER | CONTEXT_RA;
Simon Kelley30cd9662012-03-25 20:44:38 +01002903 else if (strcmp(a[leasepos], "ra-stateless") == 0)
Simon Kelley1f776932012-12-16 19:46:08 +00002904 new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA;
Neil Jerram2fd5bc92015-06-10 22:13:06 +01002905 else if (strcmp(a[leasepos], "off-link") == 0)
2906 new->flags |= CONTEXT_RA_OFF_LINK;
Simon Kelley30cd9662012-03-25 20:44:38 +01002907 else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6))
2908 new->flags |= CONTEXT_DHCP;
Simon Kelley1f776932012-12-16 19:46:08 +00002909 else if (strstr(a[leasepos], "constructor:") == a[leasepos])
2910 {
2911 new->template_interface = opt_string_alloc(a[leasepos] + 12);
2912 new->flags |= CONTEXT_TEMPLATE;
2913 }
Simon Kelley30cd9662012-03-25 20:44:38 +01002914 else
2915 break;
2916 }
Simon Kelley6692a1a2013-08-20 14:41:31 +01002917
Simon Kelley52b92f42012-01-22 16:05:15 +00002918 /* bare integer < 128 is prefix value */
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002919 if (leasepos < k)
Simon Kelley52b92f42012-01-22 16:05:15 +00002920 {
2921 int pref;
Simon Kelley30cd9662012-03-25 20:44:38 +01002922 for (cp = a[leasepos]; *cp; cp++)
Simon Kelley52b92f42012-01-22 16:05:15 +00002923 if (!(*cp >= '0' && *cp <= '9'))
2924 break;
Simon Kelley30cd9662012-03-25 20:44:38 +01002925 if (!*cp && (pref = atoi(a[leasepos])) <= 128)
Simon Kelley52b92f42012-01-22 16:05:15 +00002926 {
2927 new->prefix = pref;
Simon Kelley30cd9662012-03-25 20:44:38 +01002928 leasepos++;
Simon Kelley52b92f42012-01-22 16:05:15 +00002929 }
2930 }
Simon Kelley30cd9662012-03-25 20:44:38 +01002931
Simon Kelley6692a1a2013-08-20 14:41:31 +01002932 if (new->prefix != 64)
2933 {
Simon Kelley7ea3d3f2014-04-25 22:04:05 +01002934 if (new->flags & CONTEXT_RA)
Simon Kelley6692a1a2013-08-20 14:41:31 +01002935 ret_err(_("prefix length must be exactly 64 for RA subnets"));
2936 else if (new->flags & CONTEXT_TEMPLATE)
2937 ret_err(_("prefix length must be exactly 64 for subnet constructors"));
2938 }
2939
2940 if (new->prefix < 64)
2941 ret_err(_("prefix length must be at least 64"));
2942
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002943 if (!is_same_net6(&new->start6, &new->end6, new->prefix))
2944 ret_err(_("inconsistent DHCPv6 range"));
Simon Kelley6692a1a2013-08-20 14:41:31 +01002945
2946 /* dhcp-range=:: enables DHCP stateless on any interface */
2947 if (IN6_IS_ADDR_UNSPECIFIED(&new->start6) && !(new->flags & CONTEXT_TEMPLATE))
2948 new->prefix = 0;
Simon Kelley66409192013-08-01 20:19:32 +01002949
2950 if (new->flags & CONTEXT_TEMPLATE)
2951 {
2952 struct in6_addr zero;
2953 memset(&zero, 0, sizeof(zero));
2954 if (!is_same_net6(&zero, &new->start6, new->prefix))
2955 ret_err(_("prefix must be zero with \"constructor:\" argument"));
2956 }
2957
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002958 if (addr6part(&new->start6) > addr6part(&new->end6))
Simon Kelley52b92f42012-01-22 16:05:15 +00002959 {
2960 struct in6_addr tmp = new->start6;
2961 new->start6 = new->end6;
2962 new->end6 = tmp;
2963 }
Simon Kelley849a8352006-06-09 21:02:31 +01002964 }
Simon Kelley52b92f42012-01-22 16:05:15 +00002965#endif
Simon Kelleyd9ee9c02013-04-12 11:17:55 +01002966 else
2967 ret_err(_("bad dhcp-range"));
Simon Kelley849a8352006-06-09 21:02:31 +01002968
Simon Kelley30cd9662012-03-25 20:44:38 +01002969 if (leasepos < k)
Simon Kelley849a8352006-06-09 21:02:31 +01002970 {
Simon Kelleyfa794662016-03-03 20:33:54 +00002971 if (leasepos != k-1)
2972 ret_err(_("bad dhcp-range"));
2973
Simon Kelley849a8352006-06-09 21:02:31 +01002974 if (strcmp(a[leasepos], "infinite") == 0)
2975 new->lease_time = 0xffffffff;
Simon Kelleyc8257542012-03-28 21:15:41 +01002976 else if (strcmp(a[leasepos], "deprecated") == 0)
2977 new->flags |= CONTEXT_DEPRECATE;
Simon Kelley849a8352006-06-09 21:02:31 +01002978 else
2979 {
2980 int fac = 1;
2981 if (strlen(a[leasepos]) > 0)
2982 {
2983 switch (a[leasepos][strlen(a[leasepos]) - 1])
2984 {
Simon Kelley42243212012-07-20 15:19:18 +01002985 case 'w':
2986 case 'W':
2987 fac *= 7;
2988 /* fall through */
Simon Kelley849a8352006-06-09 21:02:31 +01002989 case 'd':
2990 case 'D':
2991 fac *= 24;
Simon Kelley87e00fe2018-02-16 21:27:35 +00002992 /* fall through */
Simon Kelley849a8352006-06-09 21:02:31 +01002993 case 'h':
2994 case 'H':
2995 fac *= 60;
2996 /* fall through */
2997 case 'm':
2998 case 'M':
2999 fac *= 60;
3000 /* fall through */
3001 case 's':
3002 case 'S':
Simon Kelleyf2621c72007-04-29 19:47:21 +01003003 a[leasepos][strlen(a[leasepos]) - 1] = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01003004 }
3005
Simon Kelleybe379862012-12-23 12:01:39 +00003006 for (cp = a[leasepos]; *cp; cp++)
3007 if (!(*cp >= '0' && *cp <= '9'))
3008 break;
3009
Simon Kelley54dae552013-02-05 17:55:10 +00003010 if (*cp || (leasepos+1 < k))
Simon Kelleybe379862012-12-23 12:01:39 +00003011 ret_err(_("bad dhcp-range"));
3012
Simon Kelley849a8352006-06-09 21:02:31 +01003013 new->lease_time = atoi(a[leasepos]) * fac;
3014 /* Leases of a minute or less confuse
3015 some clients, notably Apple's */
3016 if (new->lease_time < 120)
3017 new->lease_time = 120;
3018 }
3019 }
3020 }
3021 break;
3022 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01003023
Simon Kelley5aabfc72007-08-29 11:24:47 +01003024 case LOPT_BANK:
Simon Kelleyf2621c72007-04-29 19:47:21 +01003025 case 'G': /* --dhcp-host */
Simon Kelley849a8352006-06-09 21:02:31 +01003026 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01003027 int j, k = 0;
Simon Kelley3e8ed782013-05-29 14:31:33 +01003028 char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
Simon Kelley5aabfc72007-08-29 11:24:47 +01003029 struct dhcp_config *new;
Simon Kelley849a8352006-06-09 21:02:31 +01003030 struct in_addr in;
3031
Simon Kelley824af852008-02-12 20:43:05 +00003032 new = opt_malloc(sizeof(struct dhcp_config));
3033
Simon Kelley849a8352006-06-09 21:02:31 +01003034 new->next = daemon->dhcp_conf;
Simon Kelley9009d742008-11-14 20:04:27 +00003035 new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
3036 new->hwaddr = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003037 new->netid = NULL;
3038
Simon Kelley849a8352006-06-09 21:02:31 +01003039 if ((a[0] = arg))
Simon Kelley3e8ed782013-05-29 14:31:33 +01003040 for (k = 1; k < 7; k++)
Simon Kelleyf2621c72007-04-29 19:47:21 +01003041 if (!(a[k] = split(a[k-1])))
3042 break;
Simon Kelley849a8352006-06-09 21:02:31 +01003043
3044 for (j = 0; j < k; j++)
3045 if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
3046 {
3047 char *arg = a[j];
3048
3049 if ((arg[0] == 'i' || arg[0] == 'I') &&
3050 (arg[1] == 'd' || arg[1] == 'D') &&
3051 arg[2] == ':')
3052 {
3053 if (arg[3] == '*')
3054 new->flags |= CONFIG_NOCLID;
3055 else
3056 {
3057 int len;
3058 arg += 3; /* dump id: */
3059 if (strchr(arg, ':'))
3060 len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
3061 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01003062 {
3063 unhide_metas(arg);
3064 len = (int) strlen(arg);
3065 }
3066
Simon Kelley28866e92011-02-14 20:19:14 +00003067 if (len == -1)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003068 ret_err(_("bad hex constant"));
Simon Kelley28866e92011-02-14 20:19:14 +00003069 else if ((new->clid = opt_malloc(len)))
Simon Kelley5aabfc72007-08-29 11:24:47 +01003070 {
3071 new->flags |= CONFIG_CLID;
3072 new->clid_len = len;
3073 memcpy(new->clid, arg, len);
3074 }
Simon Kelley849a8352006-06-09 21:02:31 +01003075 }
3076 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003077 /* dhcp-host has strange backwards-compat needs. */
3078 else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg)
Simon Kelley849a8352006-06-09 21:02:31 +01003079 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003080 struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
3081 struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
3082 newtag->net = opt_malloc(strlen(arg + 4) + 1);
3083 newlist->next = new->netid;
3084 new->netid = newlist;
3085 newlist->list = newtag;
3086 strcpy(newtag->net, arg+4);
3087 unhide_metas(newtag->net);
Simon Kelley849a8352006-06-09 21:02:31 +01003088 }
Simon Kelley7de060b2011-08-26 17:24:52 +01003089 else if (strstr(arg, "tag:") == arg)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003090 ret_err(_("cannot match tags in --dhcp-host"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00003091#ifdef HAVE_DHCP6
3092 else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
3093 {
3094 arg[strlen(arg)-1] = 0;
3095 arg++;
3096
3097 if (!inet_pton(AF_INET6, arg, &new->addr6))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003098 ret_err(_("bad IPv6 address"));
Simon Kelley30393102013-01-17 16:34:16 +00003099
3100 for (i= 0; i < 8; i++)
3101 if (new->addr6.s6_addr[i] != 0)
3102 break;
3103
3104 /* set WILDCARD if network part all zeros */
3105 if (i == 8)
3106 new->flags |= CONFIG_WILDCARD;
Simon Kelley4cb1b322012-02-06 14:30:41 +00003107
3108 new->flags |= CONFIG_ADDR6;
3109 }
3110#endif
Simon Kelley7de060b2011-08-26 17:24:52 +01003111 else
Simon Kelley849a8352006-06-09 21:02:31 +01003112 {
Simon Kelley9009d742008-11-14 20:04:27 +00003113 struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
Simon Kelley28866e92011-02-14 20:19:14 +00003114 if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
3115 &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003116 ret_err(_("bad hex constant"));
Simon Kelley28866e92011-02-14 20:19:14 +00003117 else
3118 {
3119
3120 newhw->next = new->hwaddr;
3121 new->hwaddr = newhw;
3122 }
Simon Kelley849a8352006-06-09 21:02:31 +01003123 }
3124 }
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003125 else if (strchr(a[j], '.') && (inet_pton(AF_INET, a[j], &in) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01003126 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003127 struct dhcp_config *configs;
3128
Simon Kelley849a8352006-06-09 21:02:31 +01003129 new->addr = in;
3130 new->flags |= CONFIG_ADDR;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003131
3132 /* If the same IP appears in more than one host config, then DISCOVER
3133 for one of the hosts will get the address, but REQUEST will be NAKed,
3134 since the address is reserved by the other one -> protocol loop. */
3135 for (configs = daemon->dhcp_conf; configs; configs = configs->next)
3136 if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr)
3137 {
3138 sprintf(errstr, _("duplicate dhcp-host IP address %s"), inet_ntoa(in));
3139 return 0;
3140 }
Simon Kelley849a8352006-06-09 21:02:31 +01003141 }
3142 else
3143 {
3144 char *cp, *lastp = NULL, last = 0;
Simon Kelley76ff4402013-12-17 16:29:14 +00003145 int fac = 1, isdig = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01003146
3147 if (strlen(a[j]) > 1)
3148 {
3149 lastp = a[j] + strlen(a[j]) - 1;
3150 last = *lastp;
3151 switch (last)
3152 {
Simon Kelley42243212012-07-20 15:19:18 +01003153 case 'w':
3154 case 'W':
3155 fac *= 7;
3156 /* fall through */
Simon Kelley849a8352006-06-09 21:02:31 +01003157 case 'd':
3158 case 'D':
3159 fac *= 24;
3160 /* fall through */
3161 case 'h':
3162 case 'H':
3163 fac *= 60;
3164 /* fall through */
3165 case 'm':
3166 case 'M':
3167 fac *= 60;
3168 /* fall through */
3169 case 's':
3170 case 'S':
3171 *lastp = 0;
3172 }
3173 }
3174
3175 for (cp = a[j]; *cp; cp++)
Simon Kelley76ff4402013-12-17 16:29:14 +00003176 if (isdigit((unsigned char)*cp))
3177 isdig = 1;
3178 else if (*cp != ' ')
Simon Kelley849a8352006-06-09 21:02:31 +01003179 break;
Simon Kelley76ff4402013-12-17 16:29:14 +00003180
Simon Kelley849a8352006-06-09 21:02:31 +01003181 if (*cp)
3182 {
3183 if (lastp)
3184 *lastp = last;
3185 if (strcmp(a[j], "infinite") == 0)
3186 {
3187 new->lease_time = 0xffffffff;
3188 new->flags |= CONFIG_TIME;
3189 }
3190 else if (strcmp(a[j], "ignore") == 0)
3191 new->flags |= CONFIG_DISABLE;
3192 else
3193 {
Simon Kelley1f15b812009-10-13 17:49:32 +01003194 if (!(new->hostname = canonicalise_opt(a[j])) ||
3195 !legal_hostname(new->hostname))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003196 ret_err(_("bad DHCP host name"));
3197
3198 new->flags |= CONFIG_NAME;
3199 new->domain = strip_hostname(new->hostname);
Simon Kelley849a8352006-06-09 21:02:31 +01003200 }
3201 }
Simon Kelley76ff4402013-12-17 16:29:14 +00003202 else if (isdig)
Simon Kelley849a8352006-06-09 21:02:31 +01003203 {
3204 new->lease_time = atoi(a[j]) * fac;
3205 /* Leases of a minute or less confuse
3206 some clients, notably Apple's */
3207 if (new->lease_time < 120)
3208 new->lease_time = 120;
3209 new->flags |= CONFIG_TIME;
3210 }
3211 }
3212
Simon Kelley5aabfc72007-08-29 11:24:47 +01003213 daemon->dhcp_conf = new;
Simon Kelley849a8352006-06-09 21:02:31 +01003214 break;
3215 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003216
3217 case LOPT_TAG_IF: /* --tag-if */
3218 {
3219 struct tag_if *new = opt_malloc(sizeof(struct tag_if));
3220
3221 new->tag = NULL;
3222 new->set = NULL;
3223 new->next = NULL;
3224
3225 /* preserve order */
3226 if (!daemon->tag_if)
3227 daemon->tag_if = new;
3228 else
3229 {
3230 struct tag_if *tmp;
3231 for (tmp = daemon->tag_if; tmp->next; tmp = tmp->next);
3232 tmp->next = new;
3233 }
3234
3235 while (arg)
3236 {
3237 size_t len;
3238
3239 comma = split(arg);
3240 len = strlen(arg);
3241
3242 if (len < 5)
3243 {
3244 new->set = NULL;
3245 break;
3246 }
3247 else
3248 {
3249 struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
3250 newtag->net = opt_malloc(len - 3);
3251 strcpy(newtag->net, arg+4);
3252 unhide_metas(newtag->net);
3253
3254 if (strstr(arg, "set:") == arg)
3255 {
3256 struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
3257 newlist->next = new->set;
3258 new->set = newlist;
3259 newlist->list = newtag;
3260 }
3261 else if (strstr(arg, "tag:") == arg)
3262 {
3263 newtag->next = new->tag;
3264 new->tag = newtag;
3265 }
3266 else
3267 {
3268 new->set = NULL;
Simon Kelley4dc9c652013-02-04 21:43:52 +00003269 free(newtag);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003270 break;
3271 }
3272 }
3273
3274 arg = comma;
3275 }
3276
3277 if (!new->set)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003278 ret_err(_("bad tag-if"));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003279
3280 break;
3281 }
3282
Simon Kelley849a8352006-06-09 21:02:31 +01003283
Simon Kelley73a08a22009-02-05 20:28:08 +00003284 case 'O': /* --dhcp-option */
3285 case LOPT_FORCE: /* --dhcp-option-force */
Simon Kelley824af852008-02-12 20:43:05 +00003286 case LOPT_OPTS:
Simon Kelley73a08a22009-02-05 20:28:08 +00003287 case LOPT_MATCH: /* --dhcp-match */
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003288 return parse_dhcp_opt(errstr, arg,
3289 option == LOPT_FORCE ? DHOPT_FORCE :
3290 (option == LOPT_MATCH ? DHOPT_MATCH :
3291 (option == LOPT_OPTS ? DHOPT_BANK : 0)));
3292
Simon Kelleyf2621c72007-04-29 19:47:21 +01003293 case 'M': /* --dhcp-boot */
Simon Kelley849a8352006-06-09 21:02:31 +01003294 {
3295 struct dhcp_netid *id = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003296 while (is_tag_prefix(arg))
Simon Kelley849a8352006-06-09 21:02:31 +01003297 {
Simon Kelley824af852008-02-12 20:43:05 +00003298 struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
Simon Kelley849a8352006-06-09 21:02:31 +01003299 newid->next = id;
3300 id = newid;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003301 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00003302 newid->net = opt_string_alloc(arg+4);
Simon Kelley849a8352006-06-09 21:02:31 +01003303 arg = comma;
3304 };
3305
3306 if (!arg)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003307 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01003308 else
3309 {
Simon Kelley7de060b2011-08-26 17:24:52 +01003310 char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +01003311 struct in_addr dhcp_next_server;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003312 struct dhcp_boot *new;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003313 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00003314 dhcp_file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003315 dhcp_next_server.s_addr = 0;
3316 if (comma)
3317 {
3318 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003319 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00003320 dhcp_sname = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003321 if (comma)
3322 {
3323 unhide_metas(comma);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003324 if (!(inet_pton(AF_INET, comma, &dhcp_next_server) > 0))
3325 {
3326 /*
3327 * The user may have specified the tftp hostname here.
3328 * save it so that it can be resolved/looked up during
3329 * actual dhcp_reply().
3330 */
3331
3332 tftp_sname = opt_string_alloc(comma);
3333 dhcp_next_server.s_addr = 0;
3334 }
Simon Kelley849a8352006-06-09 21:02:31 +01003335 }
3336 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003337
3338 new = opt_malloc(sizeof(struct dhcp_boot));
3339 new->file = dhcp_file;
3340 new->sname = dhcp_sname;
3341 new->tftp_sname = tftp_sname;
3342 new->next_server = dhcp_next_server;
3343 new->netid = id;
3344 new->next = daemon->boot_config;
3345 daemon->boot_config = new;
Simon Kelley849a8352006-06-09 21:02:31 +01003346 }
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003347
Simon Kelley849a8352006-06-09 21:02:31 +01003348 break;
3349 }
Simon Kelley7622fc02009-06-04 20:32:05 +01003350
Floris Bos503c6092017-04-09 23:07:13 +01003351 case LOPT_REPLY_DELAY: /* --dhcp-reply-delay */
3352 {
3353 struct dhcp_netid *id = NULL;
3354 while (is_tag_prefix(arg))
3355 {
3356 struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
3357 newid->next = id;
3358 id = newid;
3359 comma = split(arg);
3360 newid->net = opt_string_alloc(arg+4);
3361 arg = comma;
3362 };
3363
3364 if (!arg)
3365 ret_err(gen_err);
3366 else
3367 {
3368 struct delay_config *new;
3369 int delay;
3370 if (!atoi_check(arg, &delay))
3371 ret_err(gen_err);
3372
3373 new = opt_malloc(sizeof(struct delay_config));
3374 new->delay = delay;
3375 new->netid = id;
3376 new->next = daemon->delay_conf;
3377 daemon->delay_conf = new;
3378 }
3379
3380 break;
3381 }
3382
Simon Kelley7622fc02009-06-04 20:32:05 +01003383 case LOPT_PXE_PROMT: /* --pxe-prompt */
3384 {
3385 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
3386 int timeout;
Floris Bos503c6092017-04-09 23:07:13 +01003387
Simon Kelley7622fc02009-06-04 20:32:05 +01003388 new->netid = NULL;
3389 new->opt = 10; /* PXE_MENU_PROMPT */
3390
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003391 while (is_tag_prefix(arg))
3392 {
Simon Kelley7622fc02009-06-04 20:32:05 +01003393 struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
3394 comma = split(arg);
3395 nn->next = new->netid;
3396 new->netid = nn;
3397 nn->net = opt_string_alloc(arg+4);
3398 arg = comma;
3399 }
3400
3401 if (!arg)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003402 ret_err(gen_err);
Simon Kelley7622fc02009-06-04 20:32:05 +01003403 else
3404 {
3405 comma = split(arg);
3406 unhide_metas(arg);
3407 new->len = strlen(arg) + 1;
3408 new->val = opt_malloc(new->len);
3409 memcpy(new->val + 1, arg, new->len - 1);
3410
3411 new->u.vendor_class = (unsigned char *)"PXEClient";
3412 new->flags = DHOPT_VENDOR;
3413
3414 if (comma && atoi_check(comma, &timeout))
3415 *(new->val) = timeout;
3416 else
3417 *(new->val) = 255;
3418
3419 new->next = daemon->dhcp_opts;
3420 daemon->dhcp_opts = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003421 daemon->enable_pxe = 1;
Simon Kelley7622fc02009-06-04 20:32:05 +01003422 }
3423
3424 break;
3425 }
3426
3427 case LOPT_PXE_SERV: /* --pxe-service */
3428 {
3429 struct pxe_service *new = opt_malloc(sizeof(struct pxe_service));
3430 char *CSA[] = { "x86PC", "PC98", "IA64_EFI", "Alpha", "Arc_x86", "Intel_Lean_Client",
Simon Kelley68bea102016-05-11 22:15:06 +01003431 "IA32_EFI", "x86-64_EFI", "Xscale_EFI", "BC_EFI",
3432 "ARM32_EFI", "ARM64_EFI", NULL };
Simon Kelley7622fc02009-06-04 20:32:05 +01003433 static int boottype = 32768;
3434
3435 new->netid = NULL;
Simon Kelley751d6f42012-02-10 15:24:51 +00003436 new->sname = NULL;
Simon Kelley7622fc02009-06-04 20:32:05 +01003437 new->server.s_addr = 0;
3438
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003439 while (is_tag_prefix(arg))
Simon Kelley7622fc02009-06-04 20:32:05 +01003440 {
3441 struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
3442 comma = split(arg);
3443 nn->next = new->netid;
3444 new->netid = nn;
3445 nn->net = opt_string_alloc(arg+4);
3446 arg = comma;
3447 }
3448
3449 if (arg && (comma = split(arg)))
3450 {
3451 for (i = 0; CSA[i]; i++)
3452 if (strcasecmp(CSA[i], arg) == 0)
3453 break;
3454
3455 if (CSA[i] || atoi_check(arg, &i))
3456 {
3457 arg = comma;
3458 comma = split(arg);
3459
3460 new->CSA = i;
3461 new->menu = opt_string_alloc(arg);
3462
Simon Kelley316e2732010-01-22 20:16:09 +00003463 if (!comma)
3464 {
3465 new->type = 0; /* local boot */
3466 new->basename = NULL;
3467 }
3468 else
Simon Kelley7622fc02009-06-04 20:32:05 +01003469 {
3470 arg = comma;
3471 comma = split(arg);
3472 if (atoi_check(arg, &i))
3473 {
3474 new->type = i;
3475 new->basename = NULL;
3476 }
3477 else
3478 {
3479 new->type = boottype++;
3480 new->basename = opt_string_alloc(arg);
3481 }
3482
Simon Kelley751d6f42012-02-10 15:24:51 +00003483 if (comma)
3484 {
3485 if (!inet_pton(AF_INET, comma, &new->server))
3486 {
3487 new->server.s_addr = 0;
3488 new->sname = opt_string_alloc(comma);
3489 }
3490
3491 }
Simon Kelley7622fc02009-06-04 20:32:05 +01003492 }
Simon Kelley751d6f42012-02-10 15:24:51 +00003493
Simon Kelley316e2732010-01-22 20:16:09 +00003494 /* Order matters */
3495 new->next = NULL;
3496 if (!daemon->pxe_services)
3497 daemon->pxe_services = new;
3498 else
3499 {
3500 struct pxe_service *s;
3501 for (s = daemon->pxe_services; s->next; s = s->next);
3502 s->next = new;
3503 }
3504
3505 daemon->enable_pxe = 1;
3506 break;
3507
Simon Kelley7622fc02009-06-04 20:32:05 +01003508 }
3509 }
3510
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003511 ret_err(gen_err);
Simon Kelley7622fc02009-06-04 20:32:05 +01003512 }
3513
Simon Kelleyf2621c72007-04-29 19:47:21 +01003514 case '4': /* --dhcp-mac */
Simon Kelley849a8352006-06-09 21:02:31 +01003515 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01003516 if (!(comma = split(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003517 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01003518 else
3519 {
Simon Kelley824af852008-02-12 20:43:05 +00003520 struct dhcp_mac *new = opt_malloc(sizeof(struct dhcp_mac));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003521 new->netid.net = opt_string_alloc(set_prefix(arg));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003522 unhide_metas(comma);
3523 new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
Simon Kelley28866e92011-02-14 20:19:14 +00003524 if (new->hwaddr_len == -1)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003525 ret_err(gen_err);
Simon Kelley28866e92011-02-14 20:19:14 +00003526 else
3527 {
3528 new->next = daemon->dhcp_macs;
3529 daemon->dhcp_macs = new;
3530 }
Simon Kelley849a8352006-06-09 21:02:31 +01003531 }
3532 }
3533 break;
Simon Kelleyc6309242013-03-07 20:59:28 +00003534
3535#ifdef OPTION6_PREFIX_CLASS
3536 case LOPT_PREF_CLSS: /* --dhcp-prefix-class */
3537 {
3538 struct prefix_class *new = opt_malloc(sizeof(struct prefix_class));
3539
3540 if (!(comma = split(arg)) ||
3541 !atoi_check16(comma, &new->class))
3542 ret_err(gen_err);
3543
3544 new->tag.net = opt_string_alloc(set_prefix(arg));
3545 new->next = daemon->prefix_classes;
3546 daemon->prefix_classes = new;
3547
3548 break;
3549 }
3550#endif
3551
3552
Simon Kelleyf2621c72007-04-29 19:47:21 +01003553 case 'U': /* --dhcp-vendorclass */
3554 case 'j': /* --dhcp-userclass */
3555 case LOPT_CIRCUIT: /* --dhcp-circuitid */
3556 case LOPT_REMOTE: /* --dhcp-remoteid */
3557 case LOPT_SUBSCR: /* --dhcp-subscrid */
Simon Kelley849a8352006-06-09 21:02:31 +01003558 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003559 unsigned char *p;
3560 int dig = 0;
3561 struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
3562
3563 if (!(comma = split(arg)))
3564 ret_err(gen_err);
3565
3566 new->netid.net = opt_string_alloc(set_prefix(arg));
3567 /* check for hex string - must digits may include : must not have nothing else,
3568 only allowed for agent-options. */
3569
3570 arg = comma;
3571 if ((comma = split(arg)))
3572 {
3573 if (option != 'U' || strstr(arg, "enterprise:") != arg)
3574 ret_err(gen_err);
3575 else
3576 new->enterprise = atoi(arg+11);
3577 }
3578 else
3579 comma = arg;
3580
3581 for (p = (unsigned char *)comma; *p; p++)
3582 if (isxdigit(*p))
3583 dig = 1;
3584 else if (*p != ':')
3585 break;
3586 unhide_metas(comma);
3587 if (option == 'U' || option == 'j' || *p || !dig)
3588 {
3589 new->len = strlen(comma);
3590 new->data = opt_malloc(new->len);
3591 memcpy(new->data, comma, new->len);
3592 }
3593 else
3594 {
3595 new->len = parse_hex(comma, (unsigned char *)comma, strlen(comma), NULL, NULL);
3596 new->data = opt_malloc(new->len);
3597 memcpy(new->data, comma, new->len);
3598 }
3599
3600 switch (option)
3601 {
3602 case 'j':
3603 new->match_type = MATCH_USER;
3604 break;
3605 case 'U':
3606 new->match_type = MATCH_VENDOR;
3607 break;
3608 case LOPT_CIRCUIT:
3609 new->match_type = MATCH_CIRCUIT;
3610 break;
3611 case LOPT_REMOTE:
3612 new->match_type = MATCH_REMOTE;
3613 break;
3614 case LOPT_SUBSCR:
3615 new->match_type = MATCH_SUBSCRIBER;
3616 break;
3617 }
3618 new->next = daemon->dhcp_vendors;
3619 daemon->dhcp_vendors = new;
Simon Kelleya5c72ab2012-02-10 13:42:47 +00003620
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003621 break;
Simon Kelley849a8352006-06-09 21:02:31 +01003622 }
3623
Simon Kelley9e038942008-05-30 20:06:34 +01003624 case LOPT_ALTPORT: /* --dhcp-alternate-port */
3625 if (!arg)
3626 {
3627 daemon->dhcp_server_port = DHCP_SERVER_ALTPORT;
3628 daemon->dhcp_client_port = DHCP_CLIENT_ALTPORT;
3629 }
3630 else
3631 {
3632 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01003633 if (!atoi_check16(arg, &daemon->dhcp_server_port) ||
3634 (comma && !atoi_check16(comma, &daemon->dhcp_client_port)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003635 ret_err(_("invalid port number"));
Simon Kelley9e038942008-05-30 20:06:34 +01003636 if (!comma)
3637 daemon->dhcp_client_port = daemon->dhcp_server_port+1;
3638 }
3639 break;
3640
Simon Kelley824af852008-02-12 20:43:05 +00003641 case 'J': /* --dhcp-ignore */
3642 case LOPT_NO_NAMES: /* --dhcp-ignore-names */
3643 case LOPT_BROADCAST: /* --dhcp-broadcast */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003644 case '3': /* --bootp-dynamic */
3645 case LOPT_GEN_NAMES: /* --dhcp-generate-names */
Simon Kelley849a8352006-06-09 21:02:31 +01003646 {
Simon Kelley824af852008-02-12 20:43:05 +00003647 struct dhcp_netid_list *new = opt_malloc(sizeof(struct dhcp_netid_list));
Simon Kelley849a8352006-06-09 21:02:31 +01003648 struct dhcp_netid *list = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00003649 if (option == 'J')
3650 {
3651 new->next = daemon->dhcp_ignore;
3652 daemon->dhcp_ignore = new;
3653 }
Simon Kelley824af852008-02-12 20:43:05 +00003654 else if (option == LOPT_BROADCAST)
3655 {
3656 new->next = daemon->force_broadcast;
3657 daemon->force_broadcast = new;
3658 }
Simon Kelley9009d742008-11-14 20:04:27 +00003659 else if (option == '3')
3660 {
3661 new->next = daemon->bootp_dynamic;
3662 daemon->bootp_dynamic = new;
3663 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003664 else if (option == LOPT_GEN_NAMES)
3665 {
3666 new->next = daemon->dhcp_gen_names;
3667 daemon->dhcp_gen_names = new;
3668 }
Simon Kelley832af0b2007-01-21 20:01:28 +00003669 else
3670 {
3671 new->next = daemon->dhcp_ignore_names;
3672 daemon->dhcp_ignore_names = new;
3673 }
3674
3675 while (arg) {
Simon Kelley824af852008-02-12 20:43:05 +00003676 struct dhcp_netid *member = opt_malloc(sizeof(struct dhcp_netid));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003677 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003678 member->next = list;
3679 list = member;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003680 if (is_tag_prefix(arg))
Simon Kelley9009d742008-11-14 20:04:27 +00003681 member->net = opt_string_alloc(arg+4);
3682 else
3683 member->net = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003684 arg = comma;
Simon Kelley832af0b2007-01-21 20:01:28 +00003685 }
Simon Kelley849a8352006-06-09 21:02:31 +01003686
3687 new->list = list;
3688 break;
3689 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003690
3691 case LOPT_PROXY: /* --dhcp-proxy */
3692 daemon->override = 1;
3693 while (arg) {
3694 struct addr_list *new = opt_malloc(sizeof(struct addr_list));
3695 comma = split(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003696 if (!(inet_pton(AF_INET, arg, &new->addr) > 0))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003697 ret_err(_("bad dhcp-proxy address"));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003698 new->next = daemon->override_relays;
3699 daemon->override_relays = new;
3700 arg = comma;
3701 }
3702 break;
Simon Kelleyff7eea22013-09-04 18:01:38 +01003703
3704 case LOPT_RELAY: /* --dhcp-relay */
3705 {
3706 struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
3707 comma = split(arg);
3708 new->interface = opt_string_alloc(split(comma));
3709 new->iface_index = 0;
3710 if (inet_pton(AF_INET, arg, &new->local) && inet_pton(AF_INET, comma, &new->server))
3711 {
3712 new->next = daemon->relay4;
3713 daemon->relay4 = new;
3714 }
3715#ifdef HAVE_DHCP6
3716 else if (inet_pton(AF_INET6, arg, &new->local) && inet_pton(AF_INET6, comma, &new->server))
3717 {
3718 new->next = daemon->relay6;
3719 daemon->relay6 = new;
3720 }
3721#endif
3722 else
3723 ret_err(_("Bad dhcp-relay"));
3724
3725 break;
3726 }
3727
Simon Kelley7622fc02009-06-04 20:32:05 +01003728#endif
Simon Kelley849a8352006-06-09 21:02:31 +01003729
Simon Kelley8b372702012-03-09 17:45:10 +00003730#ifdef HAVE_DHCP6
Simon Kelleyc4cd95d2013-10-10 20:58:11 +01003731 case LOPT_RA_PARAM: /* --ra-param */
3732 if ((comma = split(arg)))
3733 {
3734 struct ra_interface *new = opt_malloc(sizeof(struct ra_interface));
3735 new->lifetime = -1;
3736 new->prio = 0;
David Flamand005c46d2017-04-11 11:49:54 +01003737 new->mtu = 0;
Vladislav Grishenko6ec5f5c2017-04-24 22:34:45 +01003738 new->mtu_name = NULL;
Simon Kelleyc4cd95d2013-10-10 20:58:11 +01003739 new->name = opt_string_alloc(arg);
David Flamand005c46d2017-04-11 11:49:54 +01003740 if (strcasestr(comma, "mtu:") == comma)
3741 {
3742 arg = comma + 4;
3743 if (!(comma = split(comma)))
3744 goto err;
3745 if (!strcasecmp(arg, "off"))
3746 new->mtu = -1;
Vladislav Grishenko6ec5f5c2017-04-24 22:34:45 +01003747 else if (!atoi_check(arg, &new->mtu))
3748 new->mtu_name = opt_string_alloc(arg);
3749 else if (new->mtu < 1280)
David Flamand005c46d2017-04-11 11:49:54 +01003750 goto err;
3751 }
Simon Kelleyc4cd95d2013-10-10 20:58:11 +01003752 if (strcasestr(comma, "high") == comma || strcasestr(comma, "low") == comma)
3753 {
3754 if (*comma == 'l' || *comma == 'L')
3755 new->prio = 0x18;
3756 else
3757 new->prio = 0x08;
3758 comma = split(comma);
3759 }
3760 arg = split(comma);
3761 if (!atoi_check(comma, &new->interval) ||
3762 (arg && !atoi_check(arg, &new->lifetime)))
David Flamand005c46d2017-04-11 11:49:54 +01003763err:
Simon Kelleyc4cd95d2013-10-10 20:58:11 +01003764 ret_err(_("bad RA-params"));
3765
3766 new->next = daemon->ra_interfaces;
3767 daemon->ra_interfaces = new;
3768 }
3769 break;
3770
Simon Kelley8b372702012-03-09 17:45:10 +00003771 case LOPT_DUID: /* --dhcp-duid */
3772 if (!(comma = split(arg)) || !atoi_check(arg, (int *)&daemon->duid_enterprise))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003773 ret_err(_("bad DUID"));
Simon Kelley8b372702012-03-09 17:45:10 +00003774 else
3775 {
3776 daemon->duid_config_len = parse_hex(comma,(unsigned char *)comma, strlen(comma), NULL, NULL);
3777 daemon->duid_config = opt_malloc(daemon->duid_config_len);
3778 memcpy(daemon->duid_config, comma, daemon->duid_config_len);
3779 }
3780 break;
3781#endif
3782
Simon Kelleyf2621c72007-04-29 19:47:21 +01003783 case 'V': /* --alias */
Simon Kelley849a8352006-06-09 21:02:31 +01003784 {
Simon Kelley73a08a22009-02-05 20:28:08 +00003785 char *dash, *a[3] = { NULL, NULL, NULL };
Simon Kelleyf2621c72007-04-29 19:47:21 +01003786 int k = 0;
Simon Kelley73a08a22009-02-05 20:28:08 +00003787 struct doctor *new = opt_malloc(sizeof(struct doctor));
3788 new->next = daemon->doctors;
3789 daemon->doctors = new;
3790 new->mask.s_addr = 0xffffffff;
3791 new->end.s_addr = 0;
3792
Simon Kelley849a8352006-06-09 21:02:31 +01003793 if ((a[0] = arg))
3794 for (k = 1; k < 3; k++)
3795 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01003796 if (!(a[k] = split(a[k-1])))
Simon Kelley849a8352006-06-09 21:02:31 +01003797 break;
Simon Kelley849a8352006-06-09 21:02:31 +01003798 unhide_metas(a[k]);
3799 }
Simon Kelley849a8352006-06-09 21:02:31 +01003800
Simon Kelley73a08a22009-02-05 20:28:08 +00003801 dash = split_chr(a[0], '-');
3802
Simon Kelley849a8352006-06-09 21:02:31 +01003803 if ((k < 2) ||
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003804 (!(inet_pton(AF_INET, a[0], &new->in) > 0)) ||
Simon Kelleya3bd7e72018-07-19 22:00:08 +01003805 (!(inet_pton(AF_INET, a[1], &new->out) > 0)) ||
3806 (k == 3 && !inet_pton(AF_INET, a[2], &new->mask)))
3807 ret_err(_("missing address in alias"));
Simon Kelley849a8352006-06-09 21:02:31 +01003808
Simon Kelley73a08a22009-02-05 20:28:08 +00003809 if (dash &&
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003810 (!(inet_pton(AF_INET, dash, &new->end) > 0) ||
Simon Kelley73a08a22009-02-05 20:28:08 +00003811 !is_same_net(new->in, new->end, new->mask) ||
3812 ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003813 ret_err(_("invalid alias range"));
Simon Kelley849a8352006-06-09 21:02:31 +01003814
3815 break;
3816 }
3817
Simon Kelleyf2621c72007-04-29 19:47:21 +01003818 case LOPT_INTNAME: /* --interface-name */
3819 {
3820 struct interface_name *new, **up;
Simon Kelley1f15b812009-10-13 17:49:32 +01003821 char *domain = NULL;
3822
Simon Kelleyf2621c72007-04-29 19:47:21 +01003823 comma = split(arg);
3824
Simon Kelley1f15b812009-10-13 17:49:32 +01003825 if (!comma || !(domain = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003826 ret_err(_("bad interface name"));
Simon Kelley1f15b812009-10-13 17:49:32 +01003827
Simon Kelley824af852008-02-12 20:43:05 +00003828 new = opt_malloc(sizeof(struct interface_name));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003829 new->next = NULL;
Simon Kelley376d48c2013-11-13 13:04:30 +00003830 new->addr = NULL;
3831
Simon Kelleyf2621c72007-04-29 19:47:21 +01003832 /* Add to the end of the list, so that first name
3833 of an interface is used for PTR lookups. */
Simon Kelley824af852008-02-12 20:43:05 +00003834 for (up = &daemon->int_names; *up; up = &((*up)->next));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003835 *up = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003836 new->name = domain;
Simon Kelleyf7029f52013-11-21 15:09:09 +00003837 new->family = 0;
3838 arg = split_chr(comma, '/');
3839 if (arg)
3840 {
3841 if (strcmp(arg, "4") == 0)
3842 new->family = AF_INET;
3843#ifdef HAVE_IPV6
3844 else if (strcmp(arg, "6") == 0)
3845 new->family = AF_INET6;
3846#endif
3847 else
3848 ret_err(gen_err);
3849 }
Simon Kelley824af852008-02-12 20:43:05 +00003850 new->intr = opt_string_alloc(comma);
Simon Kelleyf2621c72007-04-29 19:47:21 +01003851 break;
3852 }
Simon Kelley9009d742008-11-14 20:04:27 +00003853
3854 case LOPT_CNAME: /* --cname */
3855 {
3856 struct cname *new;
Simon Kelleya1d973f2016-12-22 22:09:50 +00003857 char *alias, *target, *last, *pen;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00003858 int ttl = -1;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003859
Simon Kelleya1d973f2016-12-22 22:09:50 +00003860 for (last = pen = NULL, comma = arg; comma; comma = split(comma))
Simon Kelley9009d742008-11-14 20:04:27 +00003861 {
Simon Kelleya1d973f2016-12-22 22:09:50 +00003862 pen = last;
3863 last = comma;
3864 }
3865
3866 if (!pen)
3867 ret_err(_("bad CNAME"));
3868
3869 if (pen != arg && atoi_check(last, &ttl))
3870 last = pen;
3871
3872 target = canonicalise_opt(last);
3873
3874 while (arg != last)
3875 {
Petr Menšík56f06232018-03-06 23:13:32 +00003876 int arglen = strlen(arg);
Simon Kelleya1d973f2016-12-22 22:09:50 +00003877 alias = canonicalise_opt(arg);
Simon Kelley56144132017-05-03 22:54:09 +01003878
3879 if (!alias || !target)
3880 ret_err(_("bad CNAME"));
Simon Kelleya1d973f2016-12-22 22:09:50 +00003881
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003882 for (new = daemon->cnames; new; new = new->next)
Simon Kelley56144132017-05-03 22:54:09 +01003883 if (hostname_isequal(new->alias, alias))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003884 ret_err(_("duplicate CNAME"));
3885 new = opt_malloc(sizeof(struct cname));
3886 new->next = daemon->cnames;
3887 daemon->cnames = new;
3888 new->alias = alias;
3889 new->target = target;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00003890 new->ttl = ttl;
Simon Kelleya1d973f2016-12-22 22:09:50 +00003891
Petr Menšík56f06232018-03-06 23:13:32 +00003892 for (arg += arglen+1; *arg && isspace(*arg); arg++);
Simon Kelley9009d742008-11-14 20:04:27 +00003893 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003894
Simon Kelley9009d742008-11-14 20:04:27 +00003895 break;
3896 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01003897
3898 case LOPT_PTR: /* --ptr-record */
Simon Kelley832af0b2007-01-21 20:01:28 +00003899 {
3900 struct ptr_record *new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003901 char *dom, *target = NULL;
3902
Simon Kelleyf2621c72007-04-29 19:47:21 +01003903 comma = split(arg);
3904
Simon Kelley1f15b812009-10-13 17:49:32 +01003905 if (!(dom = canonicalise_opt(arg)) ||
3906 (comma && !(target = canonicalise_opt(comma))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003907 ret_err(_("bad PTR record"));
Simon Kelley1f15b812009-10-13 17:49:32 +01003908 else
3909 {
3910 new = opt_malloc(sizeof(struct ptr_record));
3911 new->next = daemon->ptr;
3912 daemon->ptr = new;
3913 new->name = dom;
3914 new->ptr = target;
3915 }
Simon Kelley832af0b2007-01-21 20:01:28 +00003916 break;
3917 }
3918
Simon Kelley1a6bca82008-07-11 11:11:42 +01003919 case LOPT_NAPTR: /* --naptr-record */
3920 {
3921 char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
3922 int k = 0;
3923 struct naptr *new;
3924 int order, pref;
Simon Kelley1f15b812009-10-13 17:49:32 +01003925 char *name, *replace = NULL;
Simon Kelley1a6bca82008-07-11 11:11:42 +01003926
3927 if ((a[0] = arg))
3928 for (k = 1; k < 7; k++)
3929 if (!(a[k] = split(a[k-1])))
3930 break;
3931
3932
3933 if (k < 6 ||
Simon Kelley1f15b812009-10-13 17:49:32 +01003934 !(name = canonicalise_opt(a[0])) ||
Simon Kelley1ad24ae2008-07-20 20:22:50 +01003935 !atoi_check16(a[1], &order) ||
3936 !atoi_check16(a[2], &pref) ||
Simon Kelley1f15b812009-10-13 17:49:32 +01003937 (k == 7 && !(replace = canonicalise_opt(a[6]))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003938 ret_err(_("bad NAPTR record"));
Simon Kelley1a6bca82008-07-11 11:11:42 +01003939 else
3940 {
3941 new = opt_malloc(sizeof(struct naptr));
3942 new->next = daemon->naptr;
3943 daemon->naptr = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003944 new->name = name;
Simon Kelley1a6bca82008-07-11 11:11:42 +01003945 new->flags = opt_string_alloc(a[3]);
3946 new->services = opt_string_alloc(a[4]);
3947 new->regexp = opt_string_alloc(a[5]);
Simon Kelley1f15b812009-10-13 17:49:32 +01003948 new->replace = replace;
Simon Kelley1a6bca82008-07-11 11:11:42 +01003949 new->order = order;
3950 new->pref = pref;
3951 }
3952 break;
3953 }
Simon Kelley9f7f3b12012-05-28 21:39:57 +01003954
3955 case LOPT_RR: /* dns-rr */
3956 {
3957 struct txt_record *new;
Simon Kelley4caa86d2016-03-16 18:44:16 +00003958 size_t len = 0;
Simon Kelley9f7f3b12012-05-28 21:39:57 +01003959 char *data;
3960 int val;
3961
3962 comma = split(arg);
3963 data = split(comma);
3964
3965 new = opt_malloc(sizeof(struct txt_record));
3966 new->next = daemon->rr;
3967 daemon->rr = new;
3968
3969 if (!atoi_check(comma, &val) ||
3970 !(new->name = canonicalise_opt(arg)) ||
Simon Kelley51931b82012-05-29 17:06:02 +01003971 (data && (len = parse_hex(data, (unsigned char *)data, -1, NULL, NULL)) == -1U))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003972 ret_err(_("bad RR record"));
3973
Simon Kelley9f7f3b12012-05-28 21:39:57 +01003974 new->class = val;
3975 new->len = 0;
3976
3977 if (data)
3978 {
3979 new->txt=opt_malloc(len);
3980 new->len = len;
3981 memcpy(new->txt, data, len);
3982 }
3983
3984 break;
3985 }
3986
Simon Kelleyf2621c72007-04-29 19:47:21 +01003987 case 'Y': /* --txt-record */
Simon Kelley849a8352006-06-09 21:02:31 +01003988 {
3989 struct txt_record *new;
Simon Kelley28866e92011-02-14 20:19:14 +00003990 unsigned char *p, *cnt;
3991 size_t len;
3992
3993 comma = split(arg);
3994
Simon Kelley824af852008-02-12 20:43:05 +00003995 new = opt_malloc(sizeof(struct txt_record));
Simon Kelley849a8352006-06-09 21:02:31 +01003996 new->next = daemon->txt;
3997 daemon->txt = new;
3998 new->class = C_IN;
Simon Kelleyfec216d2014-03-27 20:54:34 +00003999 new->stat = 0;
4000
Simon Kelley1f15b812009-10-13 17:49:32 +01004001 if (!(new->name = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004002 ret_err(_("bad TXT record"));
4003
Simon Kelley28866e92011-02-14 20:19:14 +00004004 len = comma ? strlen(comma) : 0;
4005 len += (len/255) + 1; /* room for extra counts */
4006 new->txt = p = opt_malloc(len);
4007
4008 cnt = p++;
4009 *cnt = 0;
4010
4011 while (comma && *comma)
4012 {
4013 unsigned char c = (unsigned char)*comma++;
4014
4015 if (c == ',' || *cnt == 255)
4016 {
4017 if (c != ',')
4018 comma--;
4019 cnt = p++;
4020 *cnt = 0;
4021 }
4022 else
4023 {
4024 *p++ = unhide_meta(c);
4025 (*cnt)++;
4026 }
4027 }
4028
4029 new->len = p - new->txt;
4030
Simon Kelley849a8352006-06-09 21:02:31 +01004031 break;
4032 }
4033
Simon Kelleyf2621c72007-04-29 19:47:21 +01004034 case 'W': /* --srv-host */
Simon Kelley849a8352006-06-09 21:02:31 +01004035 {
4036 int port = 1, priority = 0, weight = 0;
4037 char *name, *target = NULL;
4038 struct mx_srv_record *new;
4039
Simon Kelleyf2621c72007-04-29 19:47:21 +01004040 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01004041
Simon Kelley1f15b812009-10-13 17:49:32 +01004042 if (!(name = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004043 ret_err(_("bad SRV record"));
4044
Simon Kelley849a8352006-06-09 21:02:31 +01004045 if (comma)
4046 {
4047 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01004048 comma = split(arg);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004049 if (!(target = canonicalise_opt(arg)))
4050 ret_err(_("bad SRV target"));
Simon Kelley824af852008-02-12 20:43:05 +00004051
Simon Kelley849a8352006-06-09 21:02:31 +01004052 if (comma)
4053 {
4054 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01004055 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01004056 if (!atoi_check16(arg, &port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004057 ret_err(_("invalid port number"));
Simon Kelley824af852008-02-12 20:43:05 +00004058
Simon Kelley849a8352006-06-09 21:02:31 +01004059 if (comma)
4060 {
4061 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01004062 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01004063 if (!atoi_check16(arg, &priority))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004064 ret_err(_("invalid priority"));
Simon Kelley824af852008-02-12 20:43:05 +00004065
Simon Kelley407a1f32016-03-01 17:06:07 +00004066 if (comma && !atoi_check16(comma, &weight))
4067 ret_err(_("invalid weight"));
Simon Kelley849a8352006-06-09 21:02:31 +01004068 }
4069 }
4070 }
4071
Simon Kelley824af852008-02-12 20:43:05 +00004072 new = opt_malloc(sizeof(struct mx_srv_record));
Simon Kelley849a8352006-06-09 21:02:31 +01004073 new->next = daemon->mxnames;
4074 daemon->mxnames = new;
4075 new->issrv = 1;
4076 new->name = name;
4077 new->target = target;
4078 new->srvport = port;
4079 new->priority = priority;
4080 new->weight = weight;
4081 break;
4082 }
Simon Kelley7622fc02009-06-04 20:32:05 +01004083
Simon Kelleye759d422012-03-16 13:18:57 +00004084 case LOPT_HOST_REC: /* --host-record */
4085 {
4086 struct host_record *new = opt_malloc(sizeof(struct host_record));
4087 memset(new, 0, sizeof(struct host_record));
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004088 new->ttl = -1;
4089
Simon Kelleye759d422012-03-16 13:18:57 +00004090 if (!arg || !(comma = split(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004091 ret_err(_("Bad host-record"));
4092
4093 while (arg)
4094 {
4095 struct all_addr addr;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004096 char *dig;
4097
4098 for (dig = arg; *dig != 0; dig++)
4099 if (*dig < '0' || *dig > '9')
4100 break;
4101 if (*dig == 0)
4102 new->ttl = atoi(arg);
4103 else if (inet_pton(AF_INET, arg, &addr))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004104 new->addr = addr.addr.addr4;
Simon Kelleye759d422012-03-16 13:18:57 +00004105#ifdef HAVE_IPV6
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004106 else if (inet_pton(AF_INET6, arg, &addr))
4107 new->addr6 = addr.addr.addr6;
Simon Kelleye759d422012-03-16 13:18:57 +00004108#endif
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004109 else
4110 {
4111 int nomem;
4112 char *canon = canonicalise(arg, &nomem);
4113 struct name_list *nl = opt_malloc(sizeof(struct name_list));
4114 if (!canon)
4115 ret_err(_("Bad name in host-record"));
4116
4117 nl->name = canon;
4118 /* keep order, so that PTR record goes to first name */
4119 nl->next = NULL;
4120 if (!new->names)
4121 new->names = nl;
4122 else
4123 {
4124 struct name_list *tmp;
4125 for (tmp = new->names; tmp->next; tmp = tmp->next);
4126 tmp->next = nl;
4127 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004128 }
Simon Kelleye4807d82012-09-27 21:52:26 +01004129
4130 arg = comma;
4131 comma = split(arg);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004132 }
Simon Kelleye759d422012-03-16 13:18:57 +00004133
4134 /* Keep list order */
4135 if (!daemon->host_records_tail)
4136 daemon->host_records = new;
4137 else
4138 daemon->host_records_tail->next = new;
4139 new->next = NULL;
4140 daemon->host_records_tail = new;
4141 break;
4142 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00004143
4144#ifdef HAVE_DNSSEC
Simon Kelleyf3e57872018-07-20 21:10:48 +01004145 case LOPT_DNSSEC_STAMP: /* --dnssec-timestamp */
Simon Kelleyf6e62e22015-03-01 18:17:54 +00004146 daemon->timestamp_file = opt_string_alloc(arg);
4147 break;
4148
Simon Kelleyf3e57872018-07-20 21:10:48 +01004149 case LOPT_DNSSEC_CHECK: /* --dnssec-check-unsigned */
Simon Kelleya6918532018-04-15 16:20:52 +01004150 if (arg)
4151 {
4152 if (strcmp(arg, "no") == 0)
4153 set_option_bool(OPT_DNSSEC_IGN_NS);
4154 else
4155 ret_err(_("bad value for dnssec-check-unsigned"));
4156 }
4157 break;
4158
Simon Kelleyf3e57872018-07-20 21:10:48 +01004159 case LOPT_TRUST_ANCHOR: /* --trust-anchor */
Simon Kelley0fc2f312014-01-08 10:26:58 +00004160 {
Simon Kelleyee415862014-02-11 11:07:22 +00004161 struct ds_config *new = opt_malloc(sizeof(struct ds_config));
4162 char *cp, *cp1, *keyhex, *digest, *algo = NULL;
4163 int len;
Simon Kelleycbf13a22014-01-25 17:59:14 +00004164
4165 new->class = C_IN;
Simon Kelley0fc2f312014-01-08 10:26:58 +00004166
Simon Kelleycbf13a22014-01-25 17:59:14 +00004167 if ((comma = split(arg)) && (algo = split(comma)))
4168 {
4169 int class = 0;
4170 if (strcmp(comma, "IN") == 0)
4171 class = C_IN;
4172 else if (strcmp(comma, "CH") == 0)
4173 class = C_CHAOS;
4174 else if (strcmp(comma, "HS") == 0)
4175 class = C_HESIOD;
4176
4177 if (class != 0)
4178 {
4179 new->class = class;
4180 comma = algo;
4181 algo = split(comma);
4182 }
4183 }
4184
Simon Kelleyee415862014-02-11 11:07:22 +00004185 if (!comma || !algo || !(digest = split(algo)) || !(keyhex = split(digest)) ||
4186 !atoi_check16(comma, &new->keytag) ||
4187 !atoi_check8(algo, &new->algo) ||
4188 !atoi_check8(digest, &new->digest_type) ||
Simon Kelleycbf13a22014-01-25 17:59:14 +00004189 !(new->name = canonicalise_opt(arg)))
Simon Kelleyee415862014-02-11 11:07:22 +00004190 ret_err(_("bad trust anchor"));
Simon Kelleycbf13a22014-01-25 17:59:14 +00004191
Simon Kelley0fc2f312014-01-08 10:26:58 +00004192 /* Upper bound on length */
Simon Kelleyee415862014-02-11 11:07:22 +00004193 len = (2*strlen(keyhex))+1;
4194 new->digest = opt_malloc(len);
4195 unhide_metas(keyhex);
4196 /* 4034: "Whitespace is allowed within digits" */
4197 for (cp = keyhex; *cp; )
4198 if (isspace(*cp))
4199 for (cp1 = cp; *cp1; cp1++)
4200 *cp1 = *(cp1+1);
4201 else
4202 cp++;
4203 if ((new->digestlen = parse_hex(keyhex, (unsigned char *)new->digest, len, NULL, NULL)) == -1)
4204 ret_err(_("bad HEX in trust anchor"));
Simon Kelley0fc2f312014-01-08 10:26:58 +00004205
Simon Kelleyee415862014-02-11 11:07:22 +00004206 new->next = daemon->ds;
4207 daemon->ds = new;
4208
Simon Kelley0fc2f312014-01-08 10:26:58 +00004209 break;
4210 }
4211#endif
4212
Simon Kelley7622fc02009-06-04 20:32:05 +01004213 default:
Simon Kelley0fc2f312014-01-08 10:26:58 +00004214 ret_err(_("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"));
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004215
Simon Kelley849a8352006-06-09 21:02:31 +01004216 }
Simon Kelley824af852008-02-12 20:43:05 +00004217
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004218 return 1;
Simon Kelley849a8352006-06-09 21:02:31 +01004219}
4220
Simon Kelley28866e92011-02-14 20:19:14 +00004221static void read_file(char *file, FILE *f, int hard_opt)
Simon Kelley849a8352006-06-09 21:02:31 +01004222{
Simon Kelley824af852008-02-12 20:43:05 +00004223 volatile int lineno = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004224 char *buff = daemon->namebuff;
Simon Kelley849a8352006-06-09 21:02:31 +01004225
4226 while (fgets(buff, MAXDNAME, f))
4227 {
Simon Kelley7b1eae42014-02-20 13:43:28 +00004228 int white, i;
4229 volatile int option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt;
Simon Kelley13dee6f2017-02-28 16:51:58 +00004230 char *errmess, *p, *arg, *start;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004231 size_t len;
Simon Kelley832af0b2007-01-21 20:01:28 +00004232
Simon Kelley824af852008-02-12 20:43:05 +00004233 /* Memory allocation failure longjmps here if mem_recover == 1 */
Simon Kelley7b1eae42014-02-20 13:43:28 +00004234 if (option != 0 || hard_opt == LOPT_REV_SERV)
Simon Kelley824af852008-02-12 20:43:05 +00004235 {
4236 if (setjmp(mem_jmp))
4237 continue;
4238 mem_recover = 1;
4239 }
4240
Simon Kelley13dee6f2017-02-28 16:51:58 +00004241 arg = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +01004242 lineno++;
Simon Kelley824af852008-02-12 20:43:05 +00004243 errmess = NULL;
4244
Simon Kelley849a8352006-06-09 21:02:31 +01004245 /* Implement quotes, inside quotes we allow \\ \" \n and \t
4246 metacharacters get hidden also strip comments */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004247 for (white = 1, p = buff; *p; p++)
Simon Kelley849a8352006-06-09 21:02:31 +01004248 {
4249 if (*p == '"')
4250 {
4251 memmove(p, p+1, strlen(p+1)+1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004252
Simon Kelley849a8352006-06-09 21:02:31 +01004253 for(; *p && *p != '"'; p++)
4254 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01004255 if (*p == '\\' && strchr("\"tnebr\\", p[1]))
Simon Kelley849a8352006-06-09 21:02:31 +01004256 {
4257 if (p[1] == 't')
4258 p[1] = '\t';
4259 else if (p[1] == 'n')
4260 p[1] = '\n';
Simon Kelley849a8352006-06-09 21:02:31 +01004261 else if (p[1] == 'b')
4262 p[1] = '\b';
4263 else if (p[1] == 'r')
4264 p[1] = '\r';
Simon Kelley6b010842007-02-12 20:32:07 +00004265 else if (p[1] == 'e') /* escape */
4266 p[1] = '\033';
Simon Kelley849a8352006-06-09 21:02:31 +01004267 memmove(p, p+1, strlen(p+1)+1);
4268 }
4269 *p = hide_meta(*p);
4270 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004271
4272 if (*p == 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +01004273 {
4274 errmess = _("missing \"");
4275 goto oops;
4276 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004277
4278 memmove(p, p+1, strlen(p+1)+1);
Simon Kelley849a8352006-06-09 21:02:31 +01004279 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01004280
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004281 if (isspace(*p))
4282 {
4283 *p = ' ';
4284 white = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01004285 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004286 else
4287 {
4288 if (white && *p == '#')
4289 {
4290 *p = 0;
4291 break;
4292 }
4293 white = 0;
4294 }
Simon Kelley849a8352006-06-09 21:02:31 +01004295 }
4296
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004297
4298 /* strip leading spaces */
4299 for (start = buff; *start && *start == ' '; start++);
4300
4301 /* strip trailing spaces */
4302 for (len = strlen(start); (len != 0) && (start[len-1] == ' '); len--);
4303
4304 if (len == 0)
Simon Kelley849a8352006-06-09 21:02:31 +01004305 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004306 else
4307 start[len] = 0;
4308
Simon Kelley611ebc52012-07-16 16:23:46 +01004309 if (option != 0)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004310 arg = start;
4311 else if ((p=strchr(start, '=')))
Simon Kelley849a8352006-06-09 21:02:31 +01004312 {
4313 /* allow spaces around "=" */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004314 for (arg = p+1; *arg == ' '; arg++);
4315 for (; p >= start && (*p == ' ' || *p == '='); p--)
Simon Kelley849a8352006-06-09 21:02:31 +01004316 *p = 0;
4317 }
4318 else
4319 arg = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00004320
Simon Kelley611ebc52012-07-16 16:23:46 +01004321 if (option == 0)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004322 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01004323 for (option = 0, i = 0; opts[i].name; i++)
4324 if (strcmp(opts[i].name, start) == 0)
4325 {
4326 option = opts[i].val;
4327 break;
4328 }
4329
4330 if (!option)
4331 errmess = _("bad option");
4332 else if (opts[i].has_arg == 0 && arg)
4333 errmess = _("extraneous parameter");
4334 else if (opts[i].has_arg == 1 && !arg)
4335 errmess = _("missing parameter");
Simon Kelley7b1eae42014-02-20 13:43:28 +00004336 else if (hard_opt == LOPT_REV_SERV && option != 'S' && option != LOPT_REV_SERV)
4337 errmess = _("illegal option");
Simon Kelley5aabfc72007-08-29 11:24:47 +01004338 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004339
4340 oops:
Simon Kelley832af0b2007-01-21 20:01:28 +00004341 if (errmess)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004342 strcpy(daemon->namebuff, errmess);
4343
Simon Kelley7b1eae42014-02-20 13:43:28 +00004344 if (errmess || !one_opt(option, arg, buff, _("error"), 0, hard_opt == LOPT_REV_SERV))
Simon Kelleyf2621c72007-04-29 19:47:21 +01004345 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004346 sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file);
Simon Kelley824af852008-02-12 20:43:05 +00004347 if (hard_opt != 0)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004348 my_syslog(LOG_ERR, "%s", daemon->namebuff);
Simon Kelley5aabfc72007-08-29 11:24:47 +01004349 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004350 die("%s", daemon->namebuff, EC_BADCONF);
Simon Kelleyf2621c72007-04-29 19:47:21 +01004351 }
Simon Kelley849a8352006-06-09 21:02:31 +01004352 }
4353
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004354 mem_recover = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01004355 fclose(f);
4356}
4357
Simon Kelley4f7bb572018-03-08 18:47:08 +00004358#if defined(HAVE_DHCP) && defined(HAVE_INOTIFY)
Simon Kelley70d18732015-01-31 19:59:29 +00004359int option_read_dynfile(char *file, int flags)
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00004360{
Simon Kelleyf9c86372015-02-03 21:52:48 +00004361 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), file);
4362
Simon Kelley70d18732015-01-31 19:59:29 +00004363 if (flags & AH_DHCP_HST)
4364 return one_file(file, LOPT_BANK);
4365 else if (flags & AH_DHCP_OPT)
4366 return one_file(file, LOPT_OPTS);
Simon Kelleyf9c86372015-02-03 21:52:48 +00004367
Simon Kelley70d18732015-01-31 19:59:29 +00004368 return 0;
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00004369}
4370#endif
4371
Simon Kelley395eb712012-07-06 22:07:05 +01004372static int one_file(char *file, int hard_opt)
Simon Kelley28866e92011-02-14 20:19:14 +00004373{
4374 FILE *f;
4375 int nofile_ok = 0;
4376 static int read_stdin = 0;
4377 static struct fileread {
4378 dev_t dev;
4379 ino_t ino;
4380 struct fileread *next;
4381 } *filesread = NULL;
4382
4383 if (hard_opt == '7')
4384 {
4385 /* default conf-file reading */
4386 hard_opt = 0;
4387 nofile_ok = 1;
4388 }
4389
4390 if (hard_opt == 0 && strcmp(file, "-") == 0)
4391 {
4392 if (read_stdin == 1)
Simon Kelley395eb712012-07-06 22:07:05 +01004393 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00004394 read_stdin = 1;
4395 file = "stdin";
4396 f = stdin;
4397 }
4398 else
4399 {
4400 /* ignore repeated files. */
4401 struct stat statbuf;
4402
4403 if (hard_opt == 0 && stat(file, &statbuf) == 0)
4404 {
4405 struct fileread *r;
4406
4407 for (r = filesread; r; r = r->next)
4408 if (r->dev == statbuf.st_dev && r->ino == statbuf.st_ino)
Simon Kelley395eb712012-07-06 22:07:05 +01004409 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00004410
4411 r = safe_malloc(sizeof(struct fileread));
4412 r->next = filesread;
4413 filesread = r;
4414 r->dev = statbuf.st_dev;
4415 r->ino = statbuf.st_ino;
4416 }
4417
4418 if (!(f = fopen(file, "r")))
4419 {
4420 if (errno == ENOENT && nofile_ok)
Simon Kelley395eb712012-07-06 22:07:05 +01004421 return 1; /* No conffile, all done. */
Simon Kelley28866e92011-02-14 20:19:14 +00004422 else
4423 {
4424 char *str = _("cannot read %s: %s");
4425 if (hard_opt != 0)
4426 {
4427 my_syslog(LOG_ERR, str, file, strerror(errno));
Simon Kelley395eb712012-07-06 22:07:05 +01004428 return 0;
Simon Kelley28866e92011-02-14 20:19:14 +00004429 }
4430 else
4431 die(str, file, EC_FILE);
4432 }
4433 }
4434 }
4435
4436 read_file(file, f, hard_opt);
Simon Kelley395eb712012-07-06 22:07:05 +01004437 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00004438}
4439
4440/* expand any name which is a directory */
4441struct hostsfile *expand_filelist(struct hostsfile *list)
4442{
Simon Kelley19c51cf2014-03-18 22:38:30 +00004443 unsigned int i;
Simon Kelley28866e92011-02-14 20:19:14 +00004444 struct hostsfile *ah;
4445
Simon Kelley19c51cf2014-03-18 22:38:30 +00004446 /* find largest used index */
4447 for (i = SRC_AH, ah = list; ah; ah = ah->next)
Simon Kelley28866e92011-02-14 20:19:14 +00004448 {
4449 if (i <= ah->index)
4450 i = ah->index + 1;
4451
4452 if (ah->flags & AH_DIR)
4453 ah->flags |= AH_INACTIVE;
4454 else
4455 ah->flags &= ~AH_INACTIVE;
4456 }
4457
4458 for (ah = list; ah; ah = ah->next)
4459 if (!(ah->flags & AH_INACTIVE))
4460 {
4461 struct stat buf;
4462 if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode))
4463 {
4464 DIR *dir_stream;
4465 struct dirent *ent;
4466
4467 /* don't read this as a file */
4468 ah->flags |= AH_INACTIVE;
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00004469
Simon Kelley28866e92011-02-14 20:19:14 +00004470 if (!(dir_stream = opendir(ah->fname)))
4471 my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
4472 ah->fname, strerror(errno));
4473 else
4474 {
4475 while ((ent = readdir(dir_stream)))
4476 {
4477 size_t lendir = strlen(ah->fname);
4478 size_t lenfile = strlen(ent->d_name);
4479 struct hostsfile *ah1;
4480 char *path;
4481
4482 /* ignore emacs backups and dotfiles */
4483 if (lenfile == 0 ||
4484 ent->d_name[lenfile - 1] == '~' ||
4485 (ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
4486 ent->d_name[0] == '.')
4487 continue;
4488
4489 /* see if we have an existing record.
4490 dir is ah->fname
4491 file is ent->d_name
4492 path to match is ah1->fname */
4493
4494 for (ah1 = list; ah1; ah1 = ah1->next)
4495 {
4496 if (lendir < strlen(ah1->fname) &&
4497 strstr(ah1->fname, ah->fname) == ah1->fname &&
4498 ah1->fname[lendir] == '/' &&
4499 strcmp(ah1->fname + lendir + 1, ent->d_name) == 0)
4500 {
4501 ah1->flags &= ~AH_INACTIVE;
4502 break;
4503 }
4504 }
4505
4506 /* make new record */
4507 if (!ah1)
4508 {
4509 if (!(ah1 = whine_malloc(sizeof(struct hostsfile))))
4510 continue;
4511
4512 if (!(path = whine_malloc(lendir + lenfile + 2)))
4513 {
4514 free(ah1);
4515 continue;
4516 }
4517
4518 strcpy(path, ah->fname);
4519 strcat(path, "/");
4520 strcat(path, ent->d_name);
4521 ah1->fname = path;
4522 ah1->index = i++;
4523 ah1->flags = AH_DIR;
4524 ah1->next = list;
4525 list = ah1;
4526 }
4527
4528 /* inactivate record if not regular file */
4529 if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode))
4530 ah1->flags |= AH_INACTIVE;
4531
4532 }
4533 closedir(dir_stream);
4534 }
4535 }
4536 }
4537
4538 return list;
4539}
4540
Simon Kelley7b1eae42014-02-20 13:43:28 +00004541void read_servers_file(void)
4542{
4543 FILE *f;
4544
4545 if (!(f = fopen(daemon->servers_file, "r")))
4546 {
4547 my_syslog(LOG_ERR, _("cannot read %s: %s"), daemon->servers_file, strerror(errno));
4548 return;
4549 }
4550
4551 mark_servers(SERV_FROM_FILE);
4552 cleanup_servers();
4553
4554 read_file(daemon->servers_file, f, LOPT_REV_SERV);
4555}
4556
Simon Kelley28866e92011-02-14 20:19:14 +00004557
Simon Kelley7622fc02009-06-04 20:32:05 +01004558#ifdef HAVE_DHCP
Simon Kelley4f7bb572018-03-08 18:47:08 +00004559static void clear_dynamic_conf(void)
4560{
4561 struct dhcp_config *configs, *cp, **up;
4562
4563 /* remove existing... */
4564 for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
4565 {
4566 cp = configs->next;
4567
4568 if (configs->flags & CONFIG_BANK)
4569 {
4570 struct hwaddr_config *mac, *tmp;
4571 struct dhcp_netid_list *list, *tmplist;
4572
4573 for (mac = configs->hwaddr; mac; mac = tmp)
4574 {
4575 tmp = mac->next;
4576 free(mac);
4577 }
4578
4579 if (configs->flags & CONFIG_CLID)
4580 free(configs->clid);
4581
4582 for (list = configs->netid; list; list = tmplist)
4583 {
4584 free(list->list);
4585 tmplist = list->next;
4586 free(list);
4587 }
4588
4589 if (configs->flags & CONFIG_NAME)
4590 free(configs->hostname);
4591
4592 *up = configs->next;
4593 free(configs);
4594 }
4595 else
4596 up = &configs->next;
4597 }
4598}
4599
4600static void clear_dynamic_opt(void)
4601{
4602 struct dhcp_opt *opts, *cp, **up;
4603 struct dhcp_netid *id, *next;
4604
4605 for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
4606 {
4607 cp = opts->next;
4608
4609 if (opts->flags & DHOPT_BANK)
4610 {
4611 if ((opts->flags & DHOPT_VENDOR))
4612 free(opts->u.vendor_class);
4613 free(opts->val);
4614 for (id = opts->netid; id; id = next)
4615 {
4616 next = id->next;
4617 free(id->net);
4618 free(id);
4619 }
4620 *up = opts->next;
4621 free(opts);
4622 }
4623 else
4624 up = &opts->next;
4625 }
4626}
4627
Simon Kelley824af852008-02-12 20:43:05 +00004628void reread_dhcp(void)
4629{
Simon Kelley4f7bb572018-03-08 18:47:08 +00004630 struct hostsfile *hf;
Simon Kelley28866e92011-02-14 20:19:14 +00004631
Simon Kelley4f7bb572018-03-08 18:47:08 +00004632 /* Do these even if there is no daemon->dhcp_hosts_file or
4633 daemon->dhcp_opts_file since entries may have been created by the
4634 inotify dynamic file reading system. */
4635
4636 clear_dynamic_conf();
4637 clear_dynamic_opt();
4638
4639 if (daemon->dhcp_hosts_file)
Simon Kelley824af852008-02-12 20:43:05 +00004640 {
Simon Kelley28866e92011-02-14 20:19:14 +00004641 daemon->dhcp_hosts_file = expand_filelist(daemon->dhcp_hosts_file);
4642 for (hf = daemon->dhcp_hosts_file; hf; hf = hf->next)
Simon Kelley4f7bb572018-03-08 18:47:08 +00004643 if (!(hf->flags & AH_INACTIVE))
4644 {
4645 if (one_file(hf->fname, LOPT_BANK))
4646 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
4647 }
Simon Kelley824af852008-02-12 20:43:05 +00004648 }
4649
4650 if (daemon->dhcp_opts_file)
4651 {
Simon Kelley28866e92011-02-14 20:19:14 +00004652 daemon->dhcp_opts_file = expand_filelist(daemon->dhcp_opts_file);
4653 for (hf = daemon->dhcp_opts_file; hf; hf = hf->next)
4654 if (!(hf->flags & AH_INACTIVE))
4655 {
Simon Kelley395eb712012-07-06 22:07:05 +01004656 if (one_file(hf->fname, LOPT_OPTS))
4657 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
Simon Kelley28866e92011-02-14 20:19:14 +00004658 }
Simon Kelley824af852008-02-12 20:43:05 +00004659 }
Simon Kelley4f7bb572018-03-08 18:47:08 +00004660
4661# ifdef HAVE_INOTIFY
4662 /* Setup notify and read pre-existing files. */
4663 set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
4664# endif
Simon Kelley824af852008-02-12 20:43:05 +00004665}
Simon Kelley7622fc02009-06-04 20:32:05 +01004666#endif
Simon Kelley4f7bb572018-03-08 18:47:08 +00004667
Simon Kelley5aabfc72007-08-29 11:24:47 +01004668void read_opts(int argc, char **argv, char *compile_opts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004669{
Neil Jerram3bd4c472018-01-18 22:49:38 +00004670 size_t argbuf_size = MAXDNAME;
4671 char *argbuf = opt_malloc(argbuf_size);
Simon Kelley824af852008-02-12 20:43:05 +00004672 char *buff = opt_malloc(MAXDNAME);
Simon Kelley28866e92011-02-14 20:19:14 +00004673 int option, conffile_opt = '7', testmode = 0;
Simon Kelley90cb2222015-07-05 21:59:10 +01004674 char *arg, *conffile = CONFFILE;
Simon Kelley849a8352006-06-09 21:02:31 +01004675
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004676 opterr = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +01004677
Simon Kelley824af852008-02-12 20:43:05 +00004678 daemon = opt_malloc(sizeof(struct daemon));
Simon Kelley3be34542004-09-11 19:12:13 +01004679 memset(daemon, 0, sizeof(struct daemon));
4680 daemon->namebuff = buff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004681
Simon Kelley3be34542004-09-11 19:12:13 +01004682 /* Set defaults - everything else is zero or NULL */
Simon Kelley3be34542004-09-11 19:12:13 +01004683 daemon->cachesize = CACHESIZ;
Simon Kelley208b65c2006-08-05 21:41:37 +01004684 daemon->ftabsize = FTABSIZ;
Simon Kelley3be34542004-09-11 19:12:13 +01004685 daemon->port = NAMESERVER_PORT;
Simon Kelley9e038942008-05-30 20:06:34 +01004686 daemon->dhcp_client_port = DHCP_CLIENT_PORT;
4687 daemon->dhcp_server_port = DHCP_SERVER_PORT;
Simon Kelley3be34542004-09-11 19:12:13 +01004688 daemon->default_resolv.is_default = 1;
4689 daemon->default_resolv.name = RESOLVFILE;
4690 daemon->resolv_files = &daemon->default_resolv;
4691 daemon->username = CHUSER;
Simon Kelley3be34542004-09-11 19:12:13 +01004692 daemon->runfile = RUNFILE;
4693 daemon->dhcp_max = MAXLEASES;
Simon Kelley832af0b2007-01-21 20:01:28 +00004694 daemon->tftp_max = TFTP_MAX_CONNECTIONS;
Simon Kelley3be34542004-09-11 19:12:13 +01004695 daemon->edns_pktsz = EDNS_PKTSZ;
Simon Kelley849a8352006-06-09 21:02:31 +01004696 daemon->log_fac = -1;
Simon Kelley4f7b3042012-11-28 21:27:02 +00004697 daemon->auth_ttl = AUTH_TTL;
4698 daemon->soa_refresh = SOA_REFRESH;
4699 daemon->soa_retry = SOA_RETRY;
4700 daemon->soa_expiry = SOA_EXPIRY;
Hans Dedecker926332a2016-01-23 10:48:12 +00004701 daemon->max_port = MAX_PORT;
Simon Kelleybaf553d2018-01-29 22:49:27 +00004702 daemon->min_port = MIN_PORT;
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01004703
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01004704#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +00004705 add_txt("version.bind", "dnsmasq-" VERSION, 0 );
4706 add_txt("authors.bind", "Simon Kelley", 0);
4707 add_txt("copyright.bind", COPYRIGHT, 0);
4708 add_txt("cachesize.bind", NULL, TXT_STAT_CACHESIZE);
4709 add_txt("insertions.bind", NULL, TXT_STAT_INSERTS);
4710 add_txt("evictions.bind", NULL, TXT_STAT_EVICTIONS);
4711 add_txt("misses.bind", NULL, TXT_STAT_MISSES);
4712 add_txt("hits.bind", NULL, TXT_STAT_HITS);
4713#ifdef HAVE_AUTH
4714 add_txt("auth.bind", NULL, TXT_STAT_AUTH);
4715#endif
4716 add_txt("servers.bind", NULL, TXT_STAT_SERVERS);
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01004717#endif
Simon Kelley0a852542005-03-23 20:28:59 +00004718
Simon Kelley849a8352006-06-09 21:02:31 +01004719 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004720 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004721#ifdef HAVE_GETOPT_LONG
Simon Kelley849a8352006-06-09 21:02:31 +01004722 option = getopt_long(argc, argv, OPTSTRING, opts, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004723#else
Simon Kelley849a8352006-06-09 21:02:31 +01004724 option = getopt(argc, argv, OPTSTRING);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004725#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004726
4727 if (option == -1)
Simon Kelley28866e92011-02-14 20:19:14 +00004728 {
Simon Kelley572b41e2011-02-18 18:11:18 +00004729 for (; optind < argc; optind++)
4730 {
4731 unsigned char *c = (unsigned char *)argv[optind];
4732 for (; *c != 0; c++)
4733 if (!isspace(*c))
4734 die(_("junk found in command line"), NULL, EC_BADCONF);
4735 }
Simon Kelley28866e92011-02-14 20:19:14 +00004736 break;
4737 }
4738
Simon Kelley849a8352006-06-09 21:02:31 +01004739 /* Copy optarg so that argv doesn't get changed */
4740 if (optarg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004741 {
Neil Jerram3bd4c472018-01-18 22:49:38 +00004742 if (strlen(optarg) >= argbuf_size)
4743 {
4744 free(argbuf);
4745 argbuf_size = strlen(optarg) + 1;
4746 argbuf = opt_malloc(argbuf_size);
4747 }
4748 strncpy(argbuf, optarg, argbuf_size);
4749 argbuf[argbuf_size-1] = 0;
4750 arg = argbuf;
Simon Kelley849a8352006-06-09 21:02:31 +01004751 }
4752 else
4753 arg = NULL;
4754
4755 /* command-line only stuff */
Simon Kelley7622fc02009-06-04 20:32:05 +01004756 if (option == LOPT_TEST)
4757 testmode = 1;
4758 else if (option == 'w')
Simon Kelley849a8352006-06-09 21:02:31 +01004759 {
Simon Kelley7622fc02009-06-04 20:32:05 +01004760#ifdef HAVE_DHCP
Simon Kelley4cb1b322012-02-06 14:30:41 +00004761 if (argc == 3 && strcmp(argv[2], "dhcp") == 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01004762 display_opts();
Simon Kelley4cb1b322012-02-06 14:30:41 +00004763#ifdef HAVE_DHCP6
4764 else if (argc == 3 && strcmp(argv[2], "dhcp6") == 0)
4765 display_opts6();
Simon Kelley7622fc02009-06-04 20:32:05 +01004766#endif
Simon Kelley4cb1b322012-02-06 14:30:41 +00004767 else
4768#endif
4769 do_usage();
4770
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004771 exit(0);
4772 }
Simon Kelley849a8352006-06-09 21:02:31 +01004773 else if (option == 'v')
4774 {
4775 printf(_("Dnsmasq version %s %s\n"), VERSION, COPYRIGHT);
Simon Kelleyc72daea2012-01-05 21:33:27 +00004776 printf(_("Compile time options: %s\n\n"), compile_opts);
Simon Kelleyb8187c82005-11-26 21:46:27 +00004777 printf(_("This software comes with ABSOLUTELY NO WARRANTY.\n"));
4778 printf(_("Dnsmasq is free software, and you are welcome to redistribute it\n"));
Simon Kelley824af852008-02-12 20:43:05 +00004779 printf(_("under the terms of the GNU General Public License, version 2 or 3.\n"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004780 exit(0);
4781 }
Simon Kelley849a8352006-06-09 21:02:31 +01004782 else if (option == 'C')
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004783 {
Simon Kelley28866e92011-02-14 20:19:14 +00004784 conffile_opt = 0; /* file must exist */
Simon Kelley824af852008-02-12 20:43:05 +00004785 conffile = opt_string_alloc(arg);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004786 }
Simon Kelley849a8352006-06-09 21:02:31 +01004787 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004788 {
Simon Kelley26128d22004-11-14 16:43:54 +00004789#ifdef HAVE_GETOPT_LONG
Simon Kelley7b1eae42014-02-20 13:43:28 +00004790 if (!one_opt(option, arg, daemon->namebuff, _("try --help"), 1, 0))
Simon Kelley849a8352006-06-09 21:02:31 +01004791#else
Simon Kelley7b1eae42014-02-20 13:43:28 +00004792 if (!one_opt(option, arg, daemon->namebuff, _("try -w"), 1, 0))
Simon Kelley849a8352006-06-09 21:02:31 +01004793#endif
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004794 die(_("bad command line options: %s"), daemon->namebuff, EC_BADCONF);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004795 }
4796 }
Simon Kelley849a8352006-06-09 21:02:31 +01004797
Neil Jerram3bd4c472018-01-18 22:49:38 +00004798 free(argbuf);
4799
Simon Kelley849a8352006-06-09 21:02:31 +01004800 if (conffile)
Chen Wei28b879a2015-02-17 22:07:35 +00004801 {
4802 one_file(conffile, conffile_opt);
Simon Kelley90cb2222015-07-05 21:59:10 +01004803 if (conffile_opt == 0)
4804 free(conffile);
Chen Wei28b879a2015-02-17 22:07:35 +00004805 }
Simon Kelley849a8352006-06-09 21:02:31 +01004806
Simon Kelley1a6bca82008-07-11 11:11:42 +01004807 /* port might not be known when the address is parsed - fill in here */
Simon Kelley3be34542004-09-11 19:12:13 +01004808 if (daemon->servers)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004809 {
4810 struct server *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +01004811 for (tmp = daemon->servers; tmp; tmp = tmp->next)
Simon Kelley14ffa072016-04-25 16:36:44 +01004812 if (!(tmp->flags & SERV_HAS_SOURCE))
4813 {
4814 if (tmp->source_addr.sa.sa_family == AF_INET)
4815 tmp->source_addr.in.sin_port = htons(daemon->query_port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004816#ifdef HAVE_IPV6
Simon Kelley14ffa072016-04-25 16:36:44 +01004817 else if (tmp->source_addr.sa.sa_family == AF_INET6)
4818 tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
Simon Kelley5aabfc72007-08-29 11:24:47 +01004819#endif
Simon Kelley14ffa072016-04-25 16:36:44 +01004820 }
4821 }
4822
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004823 if (daemon->host_records)
4824 {
4825 struct host_record *hr;
4826
4827 for (hr = daemon->host_records; hr; hr = hr->next)
4828 if (hr->ttl == -1)
4829 hr->ttl = daemon->local_ttl;
4830 }
4831
4832 if (daemon->cnames)
4833 {
Simon Kelley903df072017-01-19 17:22:00 +00004834 struct cname *cn, *cn2, *cn3;
4835
4836#define NOLOOP 1
4837#define TESTLOOP 2
4838
4839 /* Fill in TTL for CNAMES noe we have local_ttl.
4840 Also prepare to do loop detection. */
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004841 for (cn = daemon->cnames; cn; cn = cn->next)
Simon Kelley903df072017-01-19 17:22:00 +00004842 {
4843 if (cn->ttl == -1)
4844 cn->ttl = daemon->local_ttl;
4845 cn->flag = 0;
4846 cn->targetp = NULL;
4847 for (cn2 = daemon->cnames; cn2; cn2 = cn2->next)
4848 if (hostname_isequal(cn->target, cn2->alias))
4849 {
4850 cn->targetp = cn2;
4851 break;
4852 }
4853 }
4854
4855 /* Find any CNAME loops.*/
4856 for (cn = daemon->cnames; cn; cn = cn->next)
4857 {
4858 for (cn2 = cn->targetp; cn2; cn2 = cn2->targetp)
4859 {
4860 if (cn2->flag == NOLOOP)
4861 break;
4862
4863 if (cn2->flag == TESTLOOP)
4864 die(_("CNAME loop involving %s"), cn->alias, EC_BADCONF);
4865
4866 cn2->flag = TESTLOOP;
4867 }
4868
4869 for (cn3 = cn->targetp; cn3 != cn2; cn3 = cn3->targetp)
4870 cn3->flag = NOLOOP;
4871 }
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004872 }
4873
Simon Kelley3be34542004-09-11 19:12:13 +01004874 if (daemon->if_addrs)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004875 {
4876 struct iname *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +01004877 for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004878 if (tmp->addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +01004879 tmp->addr.in.sin_port = htons(daemon->port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004880#ifdef HAVE_IPV6
4881 else if (tmp->addr.sa.sa_family == AF_INET6)
Simon Kelley3be34542004-09-11 19:12:13 +01004882 tmp->addr.in6.sin6_port = htons(daemon->port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004883#endif /* IPv6 */
4884 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00004885
4886 /* create default, if not specified */
4887 if (daemon->authserver && !daemon->hostmaster)
4888 {
4889 strcpy(buff, "hostmaster.");
4890 strcat(buff, daemon->authserver);
4891 daemon->hostmaster = opt_string_alloc(buff);
4892 }
4893
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004894 /* only one of these need be specified: the other defaults to the host-name */
Simon Kelley28866e92011-02-14 20:19:14 +00004895 if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004896 {
Simon Kelley0a852542005-03-23 20:28:59 +00004897 struct mx_srv_record *mx;
4898
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004899 if (gethostname(buff, MAXDNAME) == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004900 die(_("cannot get host-name: %s"), NULL, EC_MISC);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004901
Simon Kelley0a852542005-03-23 20:28:59 +00004902 for (mx = daemon->mxnames; mx; mx = mx->next)
4903 if (!mx->issrv && hostname_isequal(mx->name, buff))
4904 break;
4905
Simon Kelley28866e92011-02-14 20:19:14 +00004906 if ((daemon->mxtarget || option_bool(OPT_LOCALMX)) && !mx)
Simon Kelleyde379512004-06-22 20:23:33 +01004907 {
Simon Kelley824af852008-02-12 20:43:05 +00004908 mx = opt_malloc(sizeof(struct mx_srv_record));
Simon Kelley91dccd02005-03-31 17:48:32 +01004909 mx->next = daemon->mxnames;
4910 mx->issrv = 0;
4911 mx->target = NULL;
Simon Kelley824af852008-02-12 20:43:05 +00004912 mx->name = opt_string_alloc(buff);
Simon Kelley91dccd02005-03-31 17:48:32 +01004913 daemon->mxnames = mx;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004914 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004915
Simon Kelley3be34542004-09-11 19:12:13 +01004916 if (!daemon->mxtarget)
Simon Kelley824af852008-02-12 20:43:05 +00004917 daemon->mxtarget = opt_string_alloc(buff);
Simon Kelley0a852542005-03-23 20:28:59 +00004918
4919 for (mx = daemon->mxnames; mx; mx = mx->next)
4920 if (!mx->issrv && !mx->target)
4921 mx->target = daemon->mxtarget;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004922 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004923
Simon Kelley28866e92011-02-14 20:19:14 +00004924 if (!option_bool(OPT_NO_RESOLV) &&
Simon Kelley208b65c2006-08-05 21:41:37 +01004925 daemon->resolv_files &&
4926 daemon->resolv_files->next &&
Simon Kelley28866e92011-02-14 20:19:14 +00004927 option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +01004928 die(_("only one resolv.conf file allowed in no-poll mode."), NULL, EC_BADCONF);
Simon Kelleyde379512004-06-22 20:23:33 +01004929
Simon Kelley28866e92011-02-14 20:19:14 +00004930 if (option_bool(OPT_RESOLV_DOMAIN))
Simon Kelleyde379512004-06-22 20:23:33 +01004931 {
4932 char *line;
Simon Kelley849a8352006-06-09 21:02:31 +01004933 FILE *f;
4934
Simon Kelley28866e92011-02-14 20:19:14 +00004935 if (option_bool(OPT_NO_RESOLV) ||
Simon Kelley208b65c2006-08-05 21:41:37 +01004936 !daemon->resolv_files ||
4937 (daemon->resolv_files)->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004938 die(_("must have exactly one resolv.conf to read domain from."), NULL, EC_BADCONF);
Simon Kelleyde379512004-06-22 20:23:33 +01004939
Simon Kelley3be34542004-09-11 19:12:13 +01004940 if (!(f = fopen((daemon->resolv_files)->name, "r")))
Simon Kelley5aabfc72007-08-29 11:24:47 +01004941 die(_("failed to read %s: %s"), (daemon->resolv_files)->name, EC_FILE);
Simon Kelleyde379512004-06-22 20:23:33 +01004942
4943 while ((line = fgets(buff, MAXDNAME, f)))
4944 {
4945 char *token = strtok(line, " \t\n\r");
4946
4947 if (!token || strcmp(token, "search") != 0)
4948 continue;
4949
4950 if ((token = strtok(NULL, " \t\n\r")) &&
Simon Kelley1f15b812009-10-13 17:49:32 +01004951 (daemon->domain_suffix = canonicalise_opt(token)))
Simon Kelleyde379512004-06-22 20:23:33 +01004952 break;
4953 }
Simon Kelley3be34542004-09-11 19:12:13 +01004954
Simon Kelleyde379512004-06-22 20:23:33 +01004955 fclose(f);
Simon Kelley8a911cc2004-03-16 18:35:52 +00004956
Simon Kelley3be34542004-09-11 19:12:13 +01004957 if (!daemon->domain_suffix)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004958 die(_("no search directive found in %s"), (daemon->resolv_files)->name, EC_MISC);
Simon Kelleyde379512004-06-22 20:23:33 +01004959 }
Simon Kelley3d8df262005-08-29 12:19:27 +01004960
4961 if (daemon->domain_suffix)
4962 {
4963 /* add domain for any srv record without one. */
4964 struct mx_srv_record *srv;
Simon Kelleyde379512004-06-22 20:23:33 +01004965
Simon Kelley3d8df262005-08-29 12:19:27 +01004966 for (srv = daemon->mxnames; srv; srv = srv->next)
4967 if (srv->issrv &&
4968 strchr(srv->name, '.') &&
4969 strchr(srv->name, '.') == strrchr(srv->name, '.'))
4970 {
4971 strcpy(buff, srv->name);
4972 strcat(buff, ".");
4973 strcat(buff, daemon->domain_suffix);
4974 free(srv->name);
Simon Kelley824af852008-02-12 20:43:05 +00004975 srv->name = opt_string_alloc(buff);
Simon Kelley3d8df262005-08-29 12:19:27 +01004976 }
4977 }
Simon Kelley28866e92011-02-14 20:19:14 +00004978 else if (option_bool(OPT_DHCP_FQDN))
Simon Kelley9009d742008-11-14 20:04:27 +00004979 die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
Simon Kelley7622fc02009-06-04 20:32:05 +01004980
Simon Kelleyc8a80482014-03-05 14:29:54 +00004981 /* If there's access-control config, then ignore --local-service, it's intended
4982 as a system default to keep otherwise unconfigured installations safe. */
4983 if (daemon->if_names || daemon->if_except || daemon->if_addrs || daemon->authserver)
4984 reset_option_bool(OPT_LOCAL_SERVICE);
4985
Simon Kelley7622fc02009-06-04 20:32:05 +01004986 if (testmode)
4987 {
4988 fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
4989 exit(0);
4990 }
Simon Kelley849a8352006-06-09 21:02:31 +01004991}