blob: a393ec1a23566a8a4a04d2c2168c97b664552490 [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 Kelleyc8226202018-08-08 23:46:03 +0100167#define LOPT_NAME_MATCH 355
Simon Kelley974a6d02018-08-23 23:01:16 +0100168#define LOPT_CAA 356
Simon Kelleybec366b2016-02-24 22:03:26 +0000169
Simon Kelley849a8352006-06-09 21:02:31 +0100170#ifdef HAVE_GETOPT_LONG
171static const struct option opts[] =
172#else
173static const struct myoption opts[] =
174#endif
175 {
Simon Kelley7622fc02009-06-04 20:32:05 +0100176 { "version", 0, 0, 'v' },
177 { "no-hosts", 0, 0, 'h' },
178 { "no-poll", 0, 0, 'n' },
179 { "help", 0, 0, 'w' },
180 { "no-daemon", 0, 0, 'd' },
Simon Kelley25cf5e32015-01-09 15:53:03 +0000181 { "log-queries", 2, 0, 'q' },
Simon Kelley7622fc02009-06-04 20:32:05 +0100182 { "user", 2, 0, 'u' },
183 { "group", 2, 0, 'g' },
184 { "resolv-file", 2, 0, 'r' },
Simon Kelley7b1eae42014-02-20 13:43:28 +0000185 { "servers-file", 1, 0, LOPT_SERVERS_FILE },
Simon Kelley7622fc02009-06-04 20:32:05 +0100186 { "mx-host", 1, 0, 'm' },
187 { "mx-target", 1, 0, 't' },
188 { "cache-size", 2, 0, 'c' },
189 { "port", 1, 0, 'p' },
190 { "dhcp-leasefile", 2, 0, 'l' },
191 { "dhcp-lease", 1, 0, 'l' },
192 { "dhcp-host", 1, 0, 'G' },
193 { "dhcp-range", 1, 0, 'F' },
194 { "dhcp-option", 1, 0, 'O' },
195 { "dhcp-boot", 1, 0, 'M' },
196 { "domain", 1, 0, 's' },
197 { "domain-suffix", 1, 0, 's' },
198 { "interface", 1, 0, 'i' },
199 { "listen-address", 1, 0, 'a' },
Simon Kelleyc8a80482014-03-05 14:29:54 +0000200 { "local-service", 0, 0, LOPT_LOCAL_SERVICE },
Simon Kelley7622fc02009-06-04 20:32:05 +0100201 { "bogus-priv", 0, 0, 'b' },
202 { "bogus-nxdomain", 1, 0, 'B' },
Glen Huang32fc6db2014-12-27 15:28:12 +0000203 { "ignore-address", 1, 0, LOPT_IGNORE_ADDR },
Simon Kelley7622fc02009-06-04 20:32:05 +0100204 { "selfmx", 0, 0, 'e' },
205 { "filterwin2k", 0, 0, 'f' },
206 { "pid-file", 2, 0, 'x' },
207 { "strict-order", 0, 0, 'o' },
208 { "server", 1, 0, 'S' },
Simon Kelleyde73a492014-02-17 21:43:27 +0000209 { "rev-server", 1, 0, LOPT_REV_SERV },
Simon Kelley7622fc02009-06-04 20:32:05 +0100210 { "local", 1, 0, LOPT_LOCAL },
211 { "address", 1, 0, 'A' },
212 { "conf-file", 2, 0, 'C' },
213 { "no-resolv", 0, 0, 'R' },
214 { "expand-hosts", 0, 0, 'E' },
215 { "localmx", 0, 0, 'L' },
216 { "local-ttl", 1, 0, 'T' },
217 { "no-negcache", 0, 0, 'N' },
218 { "addn-hosts", 1, 0, 'H' },
Simon Kelley70d18732015-01-31 19:59:29 +0000219 { "hostsdir", 1, 0, LOPT_HOST_INOTIFY },
Simon Kelley7622fc02009-06-04 20:32:05 +0100220 { "query-port", 1, 0, 'Q' },
221 { "except-interface", 1, 0, 'I' },
222 { "no-dhcp-interface", 1, 0, '2' },
223 { "domain-needed", 0, 0, 'D' },
224 { "dhcp-lease-max", 1, 0, 'X' },
225 { "bind-interfaces", 0, 0, 'z' },
226 { "read-ethers", 0, 0, 'Z' },
227 { "alias", 1, 0, 'V' },
228 { "dhcp-vendorclass", 1, 0, 'U' },
229 { "dhcp-userclass", 1, 0, 'j' },
230 { "dhcp-ignore", 1, 0, 'J' },
231 { "edns-packet-max", 1, 0, 'P' },
232 { "keep-in-foreground", 0, 0, 'k' },
233 { "dhcp-authoritative", 0, 0, 'K' },
234 { "srv-host", 1, 0, 'W' },
235 { "localise-queries", 0, 0, 'y' },
236 { "txt-record", 1, 0, 'Y' },
Simon Kelley974a6d02018-08-23 23:01:16 +0100237 { "caa-record", 1, 0 , LOPT_CAA },
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100238 { "dns-rr", 1, 0, LOPT_RR },
Simon Kelleyad094272012-08-10 17:10:54 +0100239 { "enable-dbus", 2, 0, '1' },
Julian Kornberger8dcdb332018-07-21 22:11:08 +0100240 { "enable-ubus", 0, 0, LOPT_UBUS },
Simon Kelley7622fc02009-06-04 20:32:05 +0100241 { "bootp-dynamic", 2, 0, '3' },
242 { "dhcp-mac", 1, 0, '4' },
243 { "no-ping", 0, 0, '5' },
244 { "dhcp-script", 1, 0, '6' },
245 { "conf-dir", 1, 0, '7' },
246 { "log-facility", 1, 0 ,'8' },
247 { "leasefile-ro", 0, 0, '9' },
248 { "dns-forward-max", 1, 0, '0' },
249 { "clear-on-reload", 0, 0, LOPT_RELOAD },
250 { "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
Simon Kelley2937f8a2013-07-29 19:49:07 +0100251 { "enable-tftp", 2, 0, LOPT_TFTP },
Simon Kelley7622fc02009-06-04 20:32:05 +0100252 { "tftp-secure", 0, 0, LOPT_SECURE },
Stefan Tomanek30d08792015-03-31 22:32:11 +0100253 { "tftp-no-fail", 0, 0, LOPT_TFTP_NO_FAIL },
Floris Bos60704f52017-04-09 22:22:49 +0100254 { "tftp-unique-root", 2, 0, LOPT_APREF },
Simon Kelley7622fc02009-06-04 20:32:05 +0100255 { "tftp-root", 1, 0, LOPT_PREFIX },
256 { "tftp-max", 1, 0, LOPT_TFTP_MAX },
Simon Kelleybec366b2016-02-24 22:03:26 +0000257 { "tftp-mtu", 1, 0, LOPT_TFTP_MTU },
Simon Kelley61ce6002012-04-20 21:28:49 +0100258 { "tftp-lowercase", 0, 0, LOPT_TFTP_LC },
Simon Kelley7622fc02009-06-04 20:32:05 +0100259 { "ptr-record", 1, 0, LOPT_PTR },
260 { "naptr-record", 1, 0, LOPT_NAPTR },
261 { "bridge-interface", 1, 0 , LOPT_BRIDGE },
262 { "dhcp-option-force", 1, 0, LOPT_FORCE },
263 { "tftp-no-blocksize", 0, 0, LOPT_NOBLOCK },
264 { "log-dhcp", 0, 0, LOPT_LOG_OPTS },
265 { "log-async", 2, 0, LOPT_MAX_LOGS },
266 { "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
267 { "dhcp-remoteid", 1, 0, LOPT_REMOTE },
268 { "dhcp-subscrid", 1, 0, LOPT_SUBSCR },
269 { "interface-name", 1, 0, LOPT_INTNAME },
270 { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
271 { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
Simon Kelley5f4dc5c2015-01-20 20:51:02 +0000272 { "dhcp-hostsdir", 1, 0, LOPT_DHCP_INOTIFY },
Simon Kelley70d18732015-01-31 19:59:29 +0000273 { "dhcp-optsdir", 1, 0, LOPT_DHOPT_INOTIFY },
Simon Kelley7622fc02009-06-04 20:32:05 +0100274 { "dhcp-no-override", 0, 0, LOPT_OVERRIDE },
275 { "tftp-port-range", 1, 0, LOPT_TFTPPORTS },
276 { "stop-dns-rebind", 0, 0, LOPT_REBIND },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100277 { "rebind-domain-ok", 1, 0, LOPT_NO_REBIND },
Simon Kelley7622fc02009-06-04 20:32:05 +0100278 { "all-servers", 0, 0, LOPT_NOLAST },
Simon Kelleyc8226202018-08-08 23:46:03 +0100279 { "dhcp-match", 1, 0, LOPT_MATCH },
280 { "dhcp-name-match", 1, 0, LOPT_NAME_MATCH },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100281 { "dhcp-broadcast", 2, 0, LOPT_BROADCAST },
Simon Kelley7622fc02009-06-04 20:32:05 +0100282 { "neg-ttl", 1, 0, LOPT_NEGTTL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100283 { "max-ttl", 1, 0, LOPT_MAXTTL },
RinSatsuki28de3872015-01-10 15:22:21 +0000284 { "min-cache-ttl", 1, 0, LOPT_MINCTTL },
Simon Kelley1d860412012-09-20 20:48:04 +0100285 { "max-cache-ttl", 1, 0, LOPT_MAXCTTL },
Simon Kelley7622fc02009-06-04 20:32:05 +0100286 { "dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
287 { "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
288 { "min-port", 1, 0, LOPT_MINPORT },
Hans Dedecker926332a2016-01-23 10:48:12 +0000289 { "max-port", 1, 0, LOPT_MAXPORT },
Simon Kelley7622fc02009-06-04 20:32:05 +0100290 { "dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN },
291 { "cname", 1, 0, LOPT_CNAME },
292 { "pxe-prompt", 1, 0, LOPT_PXE_PROMT },
293 { "pxe-service", 1, 0, LOPT_PXE_SERV },
294 { "test", 0, 0, LOPT_TEST },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100295 { "tag-if", 1, 0, LOPT_TAG_IF },
296 { "dhcp-proxy", 2, 0, LOPT_PROXY },
297 { "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES },
298 { "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
Simon Kelley1e505122016-01-25 21:29:23 +0000299 { "add-mac", 2, 0, LOPT_ADD_MAC },
Simon Kelleyed4c0762013-10-08 20:46:34 +0100300 { "add-subnet", 2, 0, LOPT_ADD_SBNET },
Simon Kelley1e505122016-01-25 21:29:23 +0000301 { "add-cpe-id", 1, 0 , LOPT_CPE_ID },
Simon Kelley28866e92011-02-14 20:19:14 +0000302 { "proxy-dnssec", 0, 0, LOPT_DNSSEC },
Simon Kelley7de060b2011-08-26 17:24:52 +0100303 { "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR },
304 { "conntrack", 0, 0, LOPT_CONNTRACK },
Simon Kelleyc72daea2012-01-05 21:33:27 +0000305 { "dhcp-client-update", 0, 0, LOPT_FQDN },
306 { "dhcp-luascript", 1, 0, LOPT_LUASCRIPT },
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000307 { "enable-ra", 0, 0, LOPT_RA },
Simon Kelley8b372702012-03-09 17:45:10 +0000308 { "dhcp-duid", 1, 0, LOPT_DUID },
Simon Kelleye759d422012-03-16 13:18:57 +0000309 { "host-record", 1, 0, LOPT_HOST_REC },
Simon Kelley54dd3932012-06-20 11:23:38 +0100310 { "bind-dynamic", 0, 0, LOPT_CLVERBIND },
Simon Kelley4f7b3042012-11-28 21:27:02 +0000311 { "auth-zone", 1, 0, LOPT_AUTHZONE },
312 { "auth-server", 1, 0, LOPT_AUTHSERV },
313 { "auth-ttl", 1, 0, LOPT_AUTHTTL },
314 { "auth-soa", 1, 0, LOPT_AUTHSOA },
Simon Kelleye1ff4192012-12-09 17:08:47 +0000315 { "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
Simon Kelley49678762012-12-09 18:24:58 +0000316 { "auth-peer", 1, 0, LOPT_AUTHPEER },
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000317 { "ipset", 1, 0, LOPT_IPSET },
Simon Kelley2bb73af2013-04-24 17:38:19 +0100318 { "synth-domain", 1, 0, LOPT_SYNTH },
Giovanni Bajo7dbe1932012-04-05 02:50:13 +0200319 { "dnssec", 0, 0, LOPT_SEC_VALID },
Simon Kelleyee415862014-02-11 11:07:22 +0000320 { "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR },
Simon Kelley5b3bf922014-01-25 17:03:07 +0000321 { "dnssec-debug", 0, 0, LOPT_DNSSEC_DEBUG },
Simon Kelleya6918532018-04-15 16:20:52 +0100322 { "dnssec-check-unsigned", 2, 0, LOPT_DNSSEC_CHECK },
Simon Kelleye98bd522014-03-28 20:41:23 +0000323 { "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME },
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000324 { "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP },
Simon Kelleyc6309242013-03-07 20:59:28 +0000325#ifdef OPTION6_PREFIX_CLASS
326 { "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
327#endif
Simon Kelleyff7eea22013-09-04 18:01:38 +0100328 { "dhcp-relay", 1, 0, LOPT_RELAY },
Simon Kelleyc4cd95d2013-10-10 20:58:11 +0100329 { "ra-param", 1, 0, LOPT_RA_PARAM },
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100330 { "quiet-dhcp", 0, 0, LOPT_QUIET_DHCP },
331 { "quiet-dhcp6", 0, 0, LOPT_QUIET_DHCP6 },
332 { "quiet-ra", 0, 0, LOPT_QUIET_RA },
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +0100333 { "dns-loop-detect", 0, 0, LOPT_LOOP_DETECT },
Simon Kelley1e505122016-01-25 21:29:23 +0000334 { "script-arp", 0, 0, LOPT_SCRIPT_ARP },
Simon Kelley832e47b2016-02-24 21:24:45 +0000335 { "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },
Floris Bos503c6092017-04-09 23:07:13 +0100336 { "dhcp-reply-delay", 1, 0, LOPT_REPLY_DELAY },
Simon Kelley734d5312018-03-23 23:09:53 +0000337 { "dhcp-rapid-commit", 0, 0, LOPT_RAPID_COMMIT },
Simon Kelley6b173352018-05-08 18:32:14 +0100338 { "dumpfile", 1, 0, LOPT_DUMPFILE },
339 { "dumpmask", 1, 0, LOPT_DUMPMASK },
Simon Kelley849a8352006-06-09 21:02:31 +0100340 { NULL, 0, 0, 0 }
341 };
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000342
Simon Kelley28866e92011-02-14 20:19:14 +0000343
344#define ARG_DUP OPT_LAST
345#define ARG_ONE OPT_LAST + 1
346#define ARG_USED_CL OPT_LAST + 2
347#define ARG_USED_FILE OPT_LAST + 3
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000348
Simon Kelley1a6bca82008-07-11 11:11:42 +0100349static struct {
350 int opt;
351 unsigned int rept;
352 char * const flagdesc;
Simon Kelleyb8187c82005-11-26 21:46:27 +0000353 char * const desc;
354 char * const arg;
355} usage[] = {
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000356 { 'a', ARG_DUP, "<ipaddr>", gettext_noop("Specify local address(es) to listen on."), NULL },
357 { 'A', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Return ipaddr for all hosts in specified domains."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100358 { 'b', OPT_BOGUSPRIV, NULL, gettext_noop("Fake reverse lookups for RFC1918 private address ranges."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000359 { 'B', ARG_DUP, "<ipaddr>", gettext_noop("Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."), NULL },
360 { 'c', ARG_ONE, "<integer>", gettext_noop("Specify the size of the cache in entries (defaults to %s)."), "$" },
361 { 'C', ARG_DUP, "<path>", gettext_noop("Specify configuration file (defaults to %s)."), CONFFILE },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100362 { 'd', OPT_DEBUG, NULL, gettext_noop("Do NOT fork into the background: run in debug mode."), NULL },
363 { 'D', OPT_NODOTS_LOCAL, NULL, gettext_noop("Do NOT forward queries with no domain part."), NULL },
364 { 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL },
365 { 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
366 { 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000367 { 'F', ARG_DUP, "<ipaddr>,...", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
368 { 'g', ARG_ONE, "<groupname>", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100369 { 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000370 { LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL },
371 { LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL },
Simon Kelley5f4dc5c2015-01-20 20:51:02 +0000372 { LOPT_DHCP_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from a directory."), NULL },
Simon Kelley70d18732015-01-31 19:59:29 +0000373 { LOPT_DHOPT_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP options from a directory."), NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100374 { LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100375 { 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000376 { '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 +0000377 { LOPT_HOST_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read hosts files from a directory."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000378 { 'i', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) to listen on."), NULL },
379 { 'I', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100380 { 'j', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
381 { LOPT_CIRCUIT, ARG_DUP, "set:<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
382 { LOPT_REMOTE, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
383 { LOPT_SUBSCR, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
384 { 'J', ARG_DUP, "tag:<tag>...", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
385 { LOPT_BROADCAST, ARG_DUP, "[=tag:<tag>...]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100386 { 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
387 { '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 +0000388 { 'l', ARG_ONE, "<path>", gettext_noop("Specify where to store DHCP leases (defaults to %s)."), LEASEFILE },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100389 { 'L', OPT_LOCALMX, NULL, gettext_noop("Return MX records for local hosts."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000390 { 'm', ARG_DUP, "<host_name>,<target>,<pref>", gettext_noop("Specify an MX record."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100391 { 'M', ARG_DUP, "<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL },
392 { 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE },
393 { 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL },
394 { 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE },
395 { 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL },
396 { 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 +0000397 { 'p', ARG_ONE, "<integer>", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
398 { 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
Simon Kelley25cf5e32015-01-09 15:53:03 +0000399 { 'q', ARG_DUP, NULL, gettext_noop("Log DNS queries."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000400 { 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100401 { 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000402 { 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
Simon Kelley7b1eae42014-02-20 13:43:28 +0000403 { LOPT_SERVERS_FILE, ARG_ONE, "<path>", gettext_noop("Specify path to file with server= options"), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000404 { 'S', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
Simon Kelleyde73a492014-02-17 21:43:27 +0000405 { 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 +0000406 { LOPT_LOCAL, ARG_DUP, "/<domain>/", gettext_noop("Never forward queries to specified domains."), NULL },
Simon Kelley9009d742008-11-14 20:04:27 +0000407 { 's', ARG_DUP, "<domain>[,<range>]", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000408 { 't', ARG_ONE, "<host_name>", gettext_noop("Specify default target in an MX record."), NULL },
409 { 'T', ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
410 { LOPT_NEGTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
411 { 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 +0000412 { LOPT_MAXCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live ceiling for cache."), NULL },
413 { LOPT_MINCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live floor for cache."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000414 { 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100415 { 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100416 { 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000417 { 'V', ARG_DUP, "<ipaddr>,<ipaddr>,<netmask>", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },
418 { 'W', ARG_DUP, "<name>,<target>,...", gettext_noop("Specify a SRV record."), NULL },
Simon Kelley09217a12016-05-03 17:04:35 +0100419 { '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 +0000420 { 'x', ARG_ONE, "<path>", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE },
421 { 'X', ARG_ONE, "<integer>", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100422 { '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 +0000423 { 'Y', ARG_DUP, "<name>,<txt>[,<txt]", gettext_noop("Specify TXT DNS record."), NULL },
424 { LOPT_PTR, ARG_DUP, "<name>,<target>", gettext_noop("Specify PTR DNS record."), NULL },
425 { LOPT_INTNAME, ARG_DUP, "<name>,<interface>", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100426 { 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
427 { 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
Simon Kelleyad094272012-08-10 17:10:54 +0100428 { '1', ARG_ONE, "[=<busname>]", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
Julian Kornberger8dcdb332018-07-21 22:11:08 +0100429 { LOPT_UBUS, OPT_UBUS, NULL, gettext_noop("Enable the UBus interface."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000430 { '2', ARG_DUP, "<interface>", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100431 { '3', ARG_DUP, "[=tag:<tag>]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
432 { '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 +0000433 { 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 +0100434 { '5', OPT_NO_PING, NULL, gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000435 { '6', ARG_ONE, "<path>", gettext_noop("Shell script to run on DHCP lease creation and destruction."), NULL },
436 { LOPT_LUASCRIPT, ARG_DUP, "path", gettext_noop("Lua script to run on DHCP lease creation and destruction."), NULL },
437 { LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change scripts as this user."), NULL },
Simon Kelley1e505122016-01-25 21:29:23 +0000438 { 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 +0000439 { '7', ARG_DUP, "<path>", gettext_noop("Read configuration from all the files in this directory."), NULL },
Josh Soref730c6742017-02-06 16:14:04 +0000440 { '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 +0100441 { '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000442 { '0', ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100443 { LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100444 { LOPT_NO_NAMES, ARG_DUP, "[=tag:<tag>]...", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100445 { 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 +0100446 { LOPT_TFTP, ARG_DUP, "[=<intr>[,<intr>]]", gettext_noop("Enable integrated read-only TFTP server."), NULL },
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100447 { 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 +0100448 { 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 +0100449 { 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 +0100450 { 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 +0000451 { LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent TFTP transfers (defaults to %s)."), "#" },
Simon Kelleybec366b2016-02-24 22:03:26 +0000452 { LOPT_TFTP_MTU, ARG_ONE, "<integer>", gettext_noop("Maximum MTU to use for TFTP transfers."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100453 { LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
Simon Kelley61ce6002012-04-20 21:28:49 +0100454 { LOPT_TFTP_LC, OPT_TFTP_LC, NULL, gettext_noop("Convert TFTP filenames to lowercase"), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100455 { LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
456 { LOPT_LOG_OPTS, OPT_LOG_OPTS, NULL, gettext_noop("Extra logging for DHCP."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000457 { LOPT_MAX_LOGS, ARG_ONE, "[=<integer>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100458 { 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 +0100459 { 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 +0000460 { LOPT_NO_REBIND, ARG_DUP, "/<domain>/", gettext_noop("Inhibit DNS-rebind protection on this domain."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100461 { LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100462 { LOPT_MATCH, ARG_DUP, "set:<tag>,<optspec>", gettext_noop("Set tag if client includes matching option in request."), NULL },
Simon Kelleyc8226202018-08-08 23:46:03 +0100463 { LOPT_NAME_MATCH, ARG_DUP, "set:<tag>,<string>[*]", gettext_noop("Set tag if client provides given name."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100464 { LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100465 { LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
466 { LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
Hans Dedecker926332a2016-01-23 10:48:12 +0000467 { LOPT_MAXPORT, ARG_ONE, "<port>", gettext_noop("Specify highest port available for DNS query transmission."), NULL },
Simon Kelley9009d742008-11-14 20:04:27 +0000468 { 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 +0000469 { LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
470 { LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
Peter Wu3c0c1112016-08-28 20:53:09 +0100471 { 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 +0000472 { LOPT_CNAME, ARG_DUP, "<alias>,<target>[,<ttl>]", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
Simon Kelley7622fc02009-06-04 20:32:05 +0100473 { LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
474 { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
475 { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
Simon Kelley22c0f4f2016-02-17 22:12:31 +0000476 { 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 +0100477 { 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 +0000478 { LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client identification to forwarded DNS queries."), NULL },
Simon Kelley5a4120d2013-10-25 13:13:11 +0100479 { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
Simon Kelley7de060b2011-08-26 17:24:52 +0100480 { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
481 { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
Simon Kelleyc72daea2012-01-05 21:33:27 +0000482 { 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 +0000483 { LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
Simon Kelley8b372702012-03-09 17:45:10 +0000484 { LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
Simon Kelleydf3d54f2016-02-24 21:03:38 +0000485 { LOPT_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
Simon Kelley974a6d02018-08-23 23:01:16 +0100486 { LOPT_CAA, ARG_DUP, "<name>,<flags>,<tag>,<value>", gettext_noop("Specify certification authority authorization record"), NULL },
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100487 { LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
Simon Kelley4f7b3042012-11-28 21:27:02 +0000488 { LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL },
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000489 { LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>", gettext_noop("Export local names to global DNS"), NULL },
Simon Kelley333b2ce2013-01-07 21:46:03 +0000490 { LOPT_AUTHZONE, ARG_DUP, "<domain>,[<subnet>...]", gettext_noop("Domain to export to global DNS"), NULL },
Simon Kelley4f7b3042012-11-28 21:27:02 +0000491 { LOPT_AUTHTTL, ARG_ONE, "<integer>", gettext_noop("Set TTL for authoritative replies"), NULL },
Josh Soref730c6742017-02-06 16:14:04 +0000492 { LOPT_AUTHSOA, ARG_ONE, "<serial>[,...]", gettext_noop("Set authoritative zone information"), NULL },
Simon Kelley49678762012-12-09 18:24:58 +0000493 { LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
494 { LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL },
Peter Wu3c0c1112016-08-28 20:53:09 +0100495 { 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 +0100496 { 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 +0000497 { LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
Simon Kelleyee415862014-02-11 11:07:22 +0000498 { LOPT_TRUST_ANCHOR, ARG_DUP, "<domain>,[<class>],...", gettext_noop("Specify trust anchor key digest."), NULL },
Simon Kelley5b3bf922014-01-25 17:03:07 +0000499 { LOPT_DNSSEC_DEBUG, OPT_DNSSEC_DEBUG, NULL, gettext_noop("Disable upstream checking for DNSSEC debugging."), NULL },
Simon Kelleya6918532018-04-15 16:20:52 +0100500 { LOPT_DNSSEC_CHECK, ARG_DUP, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
Simon Kelleye98bd522014-03-28 20:41:23 +0000501 { 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 +0000502 { LOPT_DNSSEC_STAMP, ARG_ONE, "<path>", gettext_noop("Timestamp file to verify system clock for DNSSEC"), NULL },
Simon Kelleyc6309242013-03-07 20:59:28 +0000503#ifdef OPTION6_PREFIX_CLASS
504 { LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
505#endif
Vladislav Grishenko6ec5f5c2017-04-24 22:34:45 +0100506 { 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 +0100507 { LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
508 { LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
509 { LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
Simon Kelley832e47b2016-02-24 21:24:45 +0000510 { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks."), NULL },
511 { LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops."), NULL },
Glen Huang32fc6db2014-12-27 15:28:12 +0000512 { LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL },
Simon Kelley832e47b2016-02-24 21:24:45 +0000513 { LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL },
Floris Bos503c6092017-04-09 23:07:13 +0100514 { 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 +0000515 { LOPT_RAPID_COMMIT, OPT_RAPID_COMMIT, NULL, gettext_noop("Enables DHCPv4 Rapid Commit option."), NULL },
Simon Kelley6b173352018-05-08 18:32:14 +0100516 { LOPT_DUMPFILE, ARG_ONE, "<path>", gettext_noop("Path to debug packet dump file"), NULL },
517 { LOPT_DUMPMASK, ARG_ONE, "<hex>", gettext_noop("Mask which packets to dump"), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100518 { 0, 0, NULL, NULL, NULL }
Simon Kelleyb8187c82005-11-26 21:46:27 +0000519};
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000520
Josh Soref730c6742017-02-06 16:14:04 +0000521/* We hide metacharacters in quoted strings by mapping them into the ASCII control
Simon Kelleyf2621c72007-04-29 19:47:21 +0100522 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 +0100523 following sequence so that they map to themselves: it is therefore possible to call
524 unhide_metas repeatedly on string without breaking things.
Simon Kelley824af852008-02-12 20:43:05 +0000525 The transformation gets undone by opt_canonicalise, atoi_check and opt_string_alloc, and a
Simon Kelleyf2621c72007-04-29 19:47:21 +0100526 couple of other places.
527 Note that space is included here so that
528 --dhcp-option=3, string
529 has five characters, whilst
530 --dhcp-option=3," string"
531 has six.
532*/
Simon Kelley3d8df262005-08-29 12:19:27 +0100533
Simon Kelleyf2621c72007-04-29 19:47:21 +0100534static const char meta[] = "\000123456 \b\t\n78\r90abcdefABCDE\033F:,.";
Simon Kelley3d8df262005-08-29 12:19:27 +0100535
536static char hide_meta(char c)
537{
538 unsigned int i;
539
540 for (i = 0; i < (sizeof(meta) - 1); i++)
541 if (c == meta[i])
542 return (char)i;
543
544 return c;
545}
546
547static char unhide_meta(char cr)
548{
549 unsigned int c = cr;
550
551 if (c < (sizeof(meta) - 1))
552 cr = meta[c];
553
554 return cr;
555}
556
557static void unhide_metas(char *cp)
558{
559 if (cp)
560 for(; *cp; cp++)
561 *cp = unhide_meta(*cp);
562}
563
Simon Kelley824af852008-02-12 20:43:05 +0000564static void *opt_malloc(size_t size)
565{
566 void *ret;
567
568 if (mem_recover)
569 {
570 ret = whine_malloc(size);
571 if (!ret)
572 longjmp(mem_jmp, 1);
573 }
574 else
575 ret = safe_malloc(size);
576
577 return ret;
578}
579
580static char *opt_string_alloc(char *cp)
Simon Kelley3d8df262005-08-29 12:19:27 +0100581{
582 char *ret = NULL;
583
584 if (cp && strlen(cp) != 0)
585 {
Simon Kelley824af852008-02-12 20:43:05 +0000586 ret = opt_malloc(strlen(cp)+1);
Simon Kelley3d8df262005-08-29 12:19:27 +0100587 strcpy(ret, cp);
588
589 /* restore hidden metachars */
590 unhide_metas(ret);
591 }
592
593 return ret;
594}
595
Simon Kelley3d8df262005-08-29 12:19:27 +0100596
Simon Kelleyf2621c72007-04-29 19:47:21 +0100597/* find next comma, split string with zero and eliminate spaces.
598 return start of string following comma */
Simon Kelley73a08a22009-02-05 20:28:08 +0000599
600static char *split_chr(char *s, char c)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100601{
602 char *comma, *p;
603
Simon Kelley73a08a22009-02-05 20:28:08 +0000604 if (!s || !(comma = strchr(s, c)))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100605 return NULL;
606
607 p = comma;
608 *comma = ' ';
609
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100610 for (; *comma == ' '; comma++);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100611
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100612 for (; (p >= s) && *p == ' '; p--)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100613 *p = 0;
614
615 return comma;
Simon Kelley3d8df262005-08-29 12:19:27 +0100616}
617
Simon Kelley73a08a22009-02-05 20:28:08 +0000618static char *split(char *s)
619{
620 return split_chr(s, ',');
621}
622
Simon Kelley1f15b812009-10-13 17:49:32 +0100623static char *canonicalise_opt(char *s)
Simon Kelley3d8df262005-08-29 12:19:27 +0100624{
Simon Kelley1f15b812009-10-13 17:49:32 +0100625 char *ret;
626 int nomem;
627
Simon Kelley3d8df262005-08-29 12:19:27 +0100628 if (!s)
629 return 0;
630
631 unhide_metas(s);
Simon Kelley1f15b812009-10-13 17:49:32 +0100632 if (!(ret = canonicalise(s, &nomem)) && nomem)
633 {
634 if (mem_recover)
635 longjmp(mem_jmp, 1);
636 else
637 die(_("could not get memory"), NULL, EC_NOMEM);
638 }
639
640 return ret;
Simon Kelley3d8df262005-08-29 12:19:27 +0100641}
642
643static int atoi_check(char *a, int *res)
644{
645 char *p;
646
647 if (!a)
648 return 0;
649
650 unhide_metas(a);
651
652 for (p = a; *p; p++)
653 if (*p < '0' || *p > '9')
654 return 0;
655
656 *res = atoi(a);
657 return 1;
658}
659
Simon Kelley1ad24ae2008-07-20 20:22:50 +0100660static int atoi_check16(char *a, int *res)
661{
662 if (!(atoi_check(a, res)) ||
663 *res < 0 ||
664 *res > 0xffff)
665 return 0;
666
667 return 1;
668}
Simon Kelleyee415862014-02-11 11:07:22 +0000669
Simon Kelleyde73a492014-02-17 21:43:27 +0000670#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +0000671static int atoi_check8(char *a, int *res)
672{
673 if (!(atoi_check(a, res)) ||
674 *res < 0 ||
675 *res > 0xff)
676 return 0;
677
678 return 1;
679}
Simon Kelleyde73a492014-02-17 21:43:27 +0000680#endif
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +0100681
682#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +0000683static void add_txt(char *name, char *txt, int stat)
Simon Kelley0a852542005-03-23 20:28:59 +0000684{
Simon Kelley824af852008-02-12 20:43:05 +0000685 struct txt_record *r = opt_malloc(sizeof(struct txt_record));
Simon Kelleyfec216d2014-03-27 20:54:34 +0000686
687 if (txt)
688 {
689 size_t len = strlen(txt);
690 r->txt = opt_malloc(len+1);
691 r->len = len+1;
692 *(r->txt) = len;
693 memcpy((r->txt)+1, txt, len);
694 }
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +0100695
Simon Kelleyfec216d2014-03-27 20:54:34 +0000696 r->stat = stat;
Simon Kelley824af852008-02-12 20:43:05 +0000697 r->name = opt_string_alloc(name);
Simon Kelley0a852542005-03-23 20:28:59 +0000698 r->next = daemon->txt;
699 daemon->txt = r;
700 r->class = C_CHAOS;
Simon Kelley0a852542005-03-23 20:28:59 +0000701}
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +0100702#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000703
Simon Kelley849a8352006-06-09 21:02:31 +0100704static void do_usage(void)
705{
706 char buff[100];
Simon Kelley832af0b2007-01-21 20:01:28 +0000707 int i, j;
708
709 struct {
710 char handle;
711 int val;
712 } tab[] = {
713 { '$', CACHESIZ },
714 { '*', EDNS_PKTSZ },
715 { '&', MAXLEASES },
716 { '!', FTABSIZ },
717 { '#', TFTP_MAX_CONNECTIONS },
718 { '\0', 0 }
719 };
Simon Kelley849a8352006-06-09 21:02:31 +0100720
721 printf(_("Usage: dnsmasq [options]\n\n"));
722#ifndef HAVE_GETOPT_LONG
723 printf(_("Use short options only on the command line.\n"));
724#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100725 printf(_("Valid options are:\n"));
Simon Kelley849a8352006-06-09 21:02:31 +0100726
Simon Kelley1a6bca82008-07-11 11:11:42 +0100727 for (i = 0; usage[i].opt != 0; i++)
Simon Kelley849a8352006-06-09 21:02:31 +0100728 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100729 char *desc = usage[i].flagdesc;
730 char *eq = "=";
731
732 if (!desc || *desc == '[')
733 eq = "";
734
735 if (!desc)
736 desc = "";
737
738 for ( j = 0; opts[j].name; j++)
739 if (opts[j].val == usage[i].opt)
740 break;
741 if (usage[i].opt < 256)
742 sprintf(buff, "-%c, ", usage[i].opt);
743 else
744 sprintf(buff, " ");
745
746 sprintf(buff+4, "--%s%s%s", opts[j].name, eq, desc);
Peter Wu3c0c1112016-08-28 20:53:09 +0100747 printf("%-55.55s", buff);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100748
Simon Kelley849a8352006-06-09 21:02:31 +0100749 if (usage[i].arg)
750 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000751 strcpy(buff, usage[i].arg);
752 for (j = 0; tab[j].handle; j++)
753 if (tab[j].handle == *(usage[i].arg))
754 sprintf(buff, "%d", tab[j].val);
Simon Kelley849a8352006-06-09 21:02:31 +0100755 }
Simon Kelley849a8352006-06-09 21:02:31 +0100756 printf(_(usage[i].desc), buff);
757 printf("\n");
758 }
759}
760
Simon Kelleyc740e4f2012-08-09 16:19:01 +0100761#define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
762
Ed Bardsleya7369be2015-08-05 21:17:18 +0100763static char *parse_mysockaddr(char *arg, union mysockaddr *addr)
764{
765 if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
766 addr->sa.sa_family = AF_INET;
767#ifdef HAVE_IPV6
768 else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
769 addr->sa.sa_family = AF_INET6;
770#endif
771 else
772 return _("bad address");
773
774 return NULL;
775}
776
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100777char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags)
778{
779 int source_port = 0, serv_port = NAMESERVER_PORT;
780 char *portno, *source;
Kristian Evensen4e7694d2017-03-22 21:32:50 +0000781 char *interface_opt = NULL;
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100782#ifdef HAVE_IPV6
783 int scope_index = 0;
784 char *scope_id;
785#endif
786
Simon Kelleyd68c2ca2014-02-18 22:30:30 +0000787 if (!arg || strlen(arg) == 0)
788 {
789 *flags |= SERV_NO_ADDR;
790 *interface = 0;
791 return NULL;
792 }
793
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100794 if ((source = split_chr(arg, '@')) && /* is there a source. */
795 (portno = split_chr(source, '#')) &&
796 !atoi_check16(portno, &source_port))
797 return _("bad port");
798
799 if ((portno = split_chr(arg, '#')) && /* is there a port no. */
800 !atoi_check16(portno, &serv_port))
801 return _("bad port");
802
803#ifdef HAVE_IPV6
804 scope_id = split_chr(arg, '%');
805#endif
806
Kristian Evensen4e7694d2017-03-22 21:32:50 +0000807 if (source) {
808 interface_opt = split_chr(source, '@');
809
810 if (interface_opt)
811 {
812#if defined(SO_BINDTODEVICE)
813 strncpy(interface, interface_opt, IF_NAMESIZE - 1);
814#else
815 return _("interface binding not supported");
816#endif
817 }
818 }
819
Simon Kelleyddd9a6b2013-04-29 17:00:21 +0100820 if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100821 {
822 addr->in.sin_port = htons(serv_port);
823 addr->sa.sa_family = source_addr->sa.sa_family = AF_INET;
824#ifdef HAVE_SOCKADDR_SA_LEN
825 source_addr->in.sin_len = addr->in.sin_len = sizeof(struct sockaddr_in);
826#endif
827 source_addr->in.sin_addr.s_addr = INADDR_ANY;
828 source_addr->in.sin_port = htons(daemon->query_port);
829
830 if (source)
831 {
832 if (flags)
833 *flags |= SERV_HAS_SOURCE;
834 source_addr->in.sin_port = htons(source_port);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +0100835 if (!(inet_pton(AF_INET, source, &source_addr->in.sin_addr) > 0))
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100836 {
837#if defined(SO_BINDTODEVICE)
Kristian Evensen4e7694d2017-03-22 21:32:50 +0000838 if (interface_opt)
839 return _("interface can only be specified once");
840
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100841 source_addr->in.sin_addr.s_addr = INADDR_ANY;
842 strncpy(interface, source, IF_NAMESIZE - 1);
843#else
844 return _("interface binding not supported");
845#endif
846 }
847 }
848 }
849#ifdef HAVE_IPV6
850 else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
851 {
852 if (scope_id && (scope_index = if_nametoindex(scope_id)) == 0)
853 return _("bad interface name");
854
855 addr->in6.sin6_port = htons(serv_port);
856 addr->in6.sin6_scope_id = scope_index;
857 source_addr->in6.sin6_addr = in6addr_any;
858 source_addr->in6.sin6_port = htons(daemon->query_port);
859 source_addr->in6.sin6_scope_id = 0;
860 addr->sa.sa_family = source_addr->sa.sa_family = AF_INET6;
861 addr->in6.sin6_flowinfo = source_addr->in6.sin6_flowinfo = 0;
862#ifdef HAVE_SOCKADDR_SA_LEN
863 addr->in6.sin6_len = source_addr->in6.sin6_len = sizeof(addr->in6);
864#endif
865 if (source)
866 {
867 if (flags)
868 *flags |= SERV_HAS_SOURCE;
869 source_addr->in6.sin6_port = htons(source_port);
870 if (inet_pton(AF_INET6, source, &source_addr->in6.sin6_addr) == 0)
871 {
872#if defined(SO_BINDTODEVICE)
Kristian Evensen4e7694d2017-03-22 21:32:50 +0000873 if (interface_opt)
874 return _("interface can only be specified once");
875
876 source_addr->in6.sin6_addr = in6addr_any;
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100877 strncpy(interface, source, IF_NAMESIZE - 1);
878#else
879 return _("interface binding not supported");
880#endif
881 }
882 }
883 }
884#endif
885 else
886 return _("bad address");
887
888 return NULL;
889}
890
Simon Kelleyde73a492014-02-17 21:43:27 +0000891static struct server *add_rev4(struct in_addr addr, int msize)
892{
893 struct server *serv = opt_malloc(sizeof(struct server));
Olivier Gayot916959c2017-03-06 22:14:50 +0000894 in_addr_t a = ntohl(addr.s_addr);
Simon Kelleyde73a492014-02-17 21:43:27 +0000895 char *p;
896
897 memset(serv, 0, sizeof(struct server));
Olivier Gayot916959c2017-03-06 22:14:50 +0000898 p = serv->domain = opt_malloc(29); /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */
899
900 switch (msize)
901 {
902 case 32:
Rosen Penevcbd29e52017-06-27 22:29:51 +0100903 p += sprintf(p, "%u.", a & 0xff);
Olivier Gayot916959c2017-03-06 22:14:50 +0000904 /* fall through */
905 case 24:
906 p += sprintf(p, "%d.", (a >> 8) & 0xff);
907 /* fall through */
Olivier Gayot916959c2017-03-06 22:14:50 +0000908 case 16:
909 p += sprintf(p, "%d.", (a >> 16) & 0xff);
910 /* fall through */
911 case 8:
912 p += sprintf(p, "%d.", (a >> 24) & 0xff);
913 break;
Olivier Gayotdc990582017-03-06 22:17:21 +0000914 default:
915 return NULL;
Olivier Gayot916959c2017-03-06 22:14:50 +0000916 }
917
918 p += sprintf(p, "in-addr.arpa");
Simon Kelleyde73a492014-02-17 21:43:27 +0000919
920 serv->flags = SERV_HAS_DOMAIN;
921 serv->next = daemon->servers;
922 daemon->servers = serv;
923
924 return serv;
925
926}
927
928static struct server *add_rev6(struct in6_addr *addr, int msize)
929{
930 struct server *serv = opt_malloc(sizeof(struct server));
931 char *p;
932 int i;
933
934 memset(serv, 0, sizeof(struct server));
935 p = serv->domain = opt_malloc(73); /* strlen("32*<n.>ip6.arpa")+1 */
936
937 for (i = msize-1; i >= 0; i -= 4)
938 {
939 int dig = ((unsigned char *)addr)[i>>3];
940 p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
941 }
942 p += sprintf(p, "ip6.arpa");
943
944 serv->flags = SERV_HAS_DOMAIN;
945 serv->next = daemon->servers;
946 daemon->servers = serv;
947
948 return serv;
949}
950
Simon Kelleyb5a8dd12012-12-10 11:37:25 +0000951#ifdef HAVE_DHCP
952
953static int is_tag_prefix(char *arg)
954{
955 if (arg && (strstr(arg, "net:") == arg || strstr(arg, "tag:") == arg))
956 return 1;
957
958 return 0;
959}
960
961static char *set_prefix(char *arg)
962{
963 if (strstr(arg, "set:") == arg)
964 return arg+4;
965
966 return arg;
967}
968
Simon Kelley832af0b2007-01-21 20:01:28 +0000969/* This is too insanely large to keep in-line in the switch */
Simon Kelleyc4a7f902012-07-12 20:52:12 +0100970static int parse_dhcp_opt(char *errstr, char *arg, int flags)
Simon Kelley832af0b2007-01-21 20:01:28 +0000971{
Simon Kelley824af852008-02-12 20:43:05 +0000972 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
Simon Kelley832af0b2007-01-21 20:01:28 +0000973 char lenchar = 0, *cp;
Simon Kelley40ef23b2012-03-13 21:59:28 +0000974 int addrs, digs, is_addr, is_addr6, is_hex, is_dec, is_string, dots;
Simon Kelleyc4a7f902012-07-12 20:52:12 +0100975 char *comma = NULL;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100976 struct dhcp_netid *np = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000977 u16 opt_len = 0;
978 int is6 = 0;
Simon Kelleybd08ae62013-04-19 10:22:06 +0100979 int option_ok = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000980
981 new->len = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000982 new->flags = flags;
Simon Kelley832af0b2007-01-21 20:01:28 +0000983 new->netid = NULL;
984 new->val = NULL;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100985 new->opt = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +0000986
Simon Kelleyf2621c72007-04-29 19:47:21 +0100987 while (arg)
Simon Kelley832af0b2007-01-21 20:01:28 +0000988 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100989 comma = split(arg);
990
991 for (cp = arg; *cp; cp++)
992 if (*cp < '0' || *cp > '9')
Simon Kelley832af0b2007-01-21 20:01:28 +0000993 break;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100994
995 if (!*cp)
996 {
997 new->opt = atoi(arg);
998 opt_len = 0;
Simon Kelleybd08ae62013-04-19 10:22:06 +0100999 option_ok = 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001000 break;
1001 }
1002
1003 if (strstr(arg, "option:") == arg)
1004 {
Simon Kelleybd08ae62013-04-19 10:22:06 +01001005 if ((new->opt = lookup_dhcp_opt(AF_INET, arg+7)) != -1)
1006 {
1007 opt_len = lookup_dhcp_len(AF_INET, new->opt);
1008 /* option:<optname> must follow tag and vendor string. */
1009 if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
1010 option_ok = 1;
1011 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001012 break;
1013 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001014#ifdef HAVE_DHCP6
1015 else if (strstr(arg, "option6:") == arg)
1016 {
1017 for (cp = arg+8; *cp; cp++)
1018 if (*cp < '0' || *cp > '9')
1019 break;
1020
1021 if (!*cp)
1022 {
1023 new->opt = atoi(arg+8);
1024 opt_len = 0;
Simon Kelleybd08ae62013-04-19 10:22:06 +01001025 option_ok = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001026 }
1027 else
Simon Kelley40ef23b2012-03-13 21:59:28 +00001028 {
Simon Kelleybd08ae62013-04-19 10:22:06 +01001029 if ((new->opt = lookup_dhcp_opt(AF_INET6, arg+8)) != -1)
1030 {
1031 opt_len = lookup_dhcp_len(AF_INET6, new->opt);
1032 if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
1033 option_ok = 1;
1034 }
Simon Kelley40ef23b2012-03-13 21:59:28 +00001035 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001036 /* option6:<opt>|<optname> must follow tag and vendor string. */
1037 is6 = 1;
1038 break;
1039 }
1040#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +01001041 else if (strstr(arg, "vendor:") == arg)
1042 {
Simon Kelley73a08a22009-02-05 20:28:08 +00001043 new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7);
1044 new->flags |= DHOPT_VENDOR;
1045 }
1046 else if (strstr(arg, "encap:") == arg)
1047 {
1048 new->u.encap = atoi(arg+6);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001049 new->flags |= DHOPT_ENCAPSULATE;
1050 }
Simon Kelley316e2732010-01-22 20:16:09 +00001051 else if (strstr(arg, "vi-encap:") == arg)
1052 {
1053 new->u.encap = atoi(arg+9);
1054 new->flags |= DHOPT_RFC3925;
1055 if (flags == DHOPT_MATCH)
1056 {
Simon Kelleybd08ae62013-04-19 10:22:06 +01001057 option_ok = 1;
Simon Kelley316e2732010-01-22 20:16:09 +00001058 break;
1059 }
1060 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001061 else
1062 {
Simon Kelley824af852008-02-12 20:43:05 +00001063 new->netid = opt_malloc(sizeof (struct dhcp_netid));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001064 /* allow optional "net:" or "tag:" for consistency */
1065 if (is_tag_prefix(arg))
Simon Kelley824af852008-02-12 20:43:05 +00001066 new->netid->net = opt_string_alloc(arg+4);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001067 else
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001068 new->netid->net = opt_string_alloc(set_prefix(arg));
Simon Kelleyf2621c72007-04-29 19:47:21 +01001069 new->netid->next = np;
1070 np = new->netid;
1071 }
1072
1073 arg = comma;
Simon Kelley832af0b2007-01-21 20:01:28 +00001074 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001075
1076#ifdef HAVE_DHCP6
1077 if (is6)
1078 {
1079 if (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001080 ret_err(_("unsupported encapsulation for IPv6 option"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001081
1082 if (opt_len == 0 &&
1083 !(new->flags & DHOPT_RFC3925))
Simon Kelleybd08ae62013-04-19 10:22:06 +01001084 opt_len = lookup_dhcp_len(AF_INET6, new->opt);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001085 }
1086 else
1087#endif
1088 if (opt_len == 0 &&
1089 !(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
Simon Kelleybd08ae62013-04-19 10:22:06 +01001090 opt_len = lookup_dhcp_len(AF_INET, new->opt);
Simon Kelley40ef23b2012-03-13 21:59:28 +00001091
Simon Kelley316e2732010-01-22 20:16:09 +00001092 /* option may be missing with rfc3925 match */
Simon Kelleybd08ae62013-04-19 10:22:06 +01001093 if (!option_ok)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001094 ret_err(_("bad dhcp-option"));
1095
1096 if (comma)
Simon Kelley832af0b2007-01-21 20:01:28 +00001097 {
1098 /* characterise the value */
Simon Kelleyf2621c72007-04-29 19:47:21 +01001099 char c;
Simon Kelley28866e92011-02-14 20:19:14 +00001100 int found_dig = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001101 is_addr = is_addr6 = is_hex = is_dec = is_string = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001102 addrs = digs = 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001103 dots = 0;
1104 for (cp = comma; (c = *cp); cp++)
1105 if (c == ',')
Simon Kelley832af0b2007-01-21 20:01:28 +00001106 {
1107 addrs++;
1108 is_dec = is_hex = 0;
1109 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001110 else if (c == ':')
Simon Kelley832af0b2007-01-21 20:01:28 +00001111 {
1112 digs++;
1113 is_dec = is_addr = 0;
1114 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001115 else if (c == '/')
Simon Kelley832af0b2007-01-21 20:01:28 +00001116 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001117 is_addr6 = is_dec = is_hex = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001118 if (cp == comma) /* leading / means a pathname */
1119 is_addr = 0;
1120 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001121 else if (c == '.')
1122 {
Simon Kelley23245c02012-07-18 16:21:11 +01001123 is_addr6 = is_dec = is_hex = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001124 dots++;
1125 }
1126 else if (c == '-')
Simon Kelley4cb1b322012-02-06 14:30:41 +00001127 is_hex = is_addr = is_addr6 = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001128 else if (c == ' ')
Simon Kelley832af0b2007-01-21 20:01:28 +00001129 is_dec = is_hex = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001130 else if (!(c >='0' && c <= '9'))
Simon Kelley832af0b2007-01-21 20:01:28 +00001131 {
1132 is_addr = 0;
1133 if (cp[1] == 0 && is_dec &&
Simon Kelleyf2621c72007-04-29 19:47:21 +01001134 (c == 'b' || c == 's' || c == 'i'))
Simon Kelley832af0b2007-01-21 20:01:28 +00001135 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001136 lenchar = c;
Simon Kelley832af0b2007-01-21 20:01:28 +00001137 *cp = 0;
1138 }
1139 else
1140 is_dec = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001141 if (!((c >='A' && c <= 'F') ||
Simon Kelley73a08a22009-02-05 20:28:08 +00001142 (c >='a' && c <= 'f') ||
1143 (c == '*' && (flags & DHOPT_MATCH))))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001144 {
1145 is_hex = 0;
1146 if (c != '[' && c != ']')
1147 is_addr6 = 0;
1148 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001149 }
Simon Kelley28866e92011-02-14 20:19:14 +00001150 else
1151 found_dig = 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001152
Simon Kelley28866e92011-02-14 20:19:14 +00001153 if (!found_dig)
1154 is_dec = is_addr = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001155
Simon Kelleyf2621c72007-04-29 19:47:21 +01001156 /* We know that some options take addresses */
Simon Kelley7622fc02009-06-04 20:32:05 +01001157 if (opt_len & OT_ADDR_LIST)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001158 {
1159 is_string = is_dec = is_hex = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001160
1161 if (!is6 && (!is_addr || dots == 0))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001162 ret_err(_("bad IP address"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001163
1164 if (is6 && !is_addr6)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001165 ret_err(_("bad IPv6 address"));
Simon Kelleyf2621c72007-04-29 19:47:21 +01001166 }
Simon Kelley28866e92011-02-14 20:19:14 +00001167 /* or names */
Simon Kelley4cb1b322012-02-06 14:30:41 +00001168 else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING))
1169 is_addr6 = is_addr = is_dec = is_hex = 0;
Simon Kelley23245c02012-07-18 16:21:11 +01001170
1171 if (found_dig && (opt_len & OT_TIME) && strlen(comma) > 0)
1172 {
1173 int val, fac = 1;
1174
1175 switch (comma[strlen(comma) - 1])
1176 {
Simon Kelley42243212012-07-20 15:19:18 +01001177 case 'w':
1178 case 'W':
1179 fac *= 7;
1180 /* fall through */
Simon Kelley23245c02012-07-18 16:21:11 +01001181 case 'd':
1182 case 'D':
1183 fac *= 24;
Simon Kelley87e00fe2018-02-16 21:27:35 +00001184 /* fall through */
Simon Kelley23245c02012-07-18 16:21:11 +01001185 case 'h':
1186 case 'H':
1187 fac *= 60;
1188 /* fall through */
1189 case 'm':
1190 case 'M':
1191 fac *= 60;
1192 /* fall through */
1193 case 's':
1194 case 'S':
1195 comma[strlen(comma) - 1] = 0;
1196 }
1197
1198 new->len = 4;
1199 new->val = opt_malloc(4);
1200 val = atoi(comma);
1201 *((int *)new->val) = htonl(val * fac);
1202 }
1203 else if (is_hex && digs > 1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001204 {
1205 new->len = digs;
Simon Kelley824af852008-02-12 20:43:05 +00001206 new->val = opt_malloc(new->len);
Simon Kelley73a08a22009-02-05 20:28:08 +00001207 parse_hex(comma, new->val, digs, (flags & DHOPT_MATCH) ? &new->u.wildcard_mask : NULL, NULL);
1208 new->flags |= DHOPT_HEX;
Simon Kelley832af0b2007-01-21 20:01:28 +00001209 }
1210 else if (is_dec)
1211 {
1212 int i, val = atoi(comma);
1213 /* assume numeric arg is 1 byte except for
1214 options where it is known otherwise.
1215 For vendor class option, we have to hack. */
Simon Kelleyf2621c72007-04-29 19:47:21 +01001216 if (opt_len != 0)
1217 new->len = opt_len;
1218 else if (val & 0xffff0000)
1219 new->len = 4;
1220 else if (val & 0xff00)
1221 new->len = 2;
1222 else
1223 new->len = 1;
1224
Simon Kelley832af0b2007-01-21 20:01:28 +00001225 if (lenchar == 'b')
1226 new->len = 1;
1227 else if (lenchar == 's')
1228 new->len = 2;
1229 else if (lenchar == 'i')
1230 new->len = 4;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001231
Simon Kelley824af852008-02-12 20:43:05 +00001232 new->val = opt_malloc(new->len);
Simon Kelley832af0b2007-01-21 20:01:28 +00001233 for (i=0; i<new->len; i++)
1234 new->val[i] = val>>((new->len - i - 1)*8);
1235 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001236 else if (is_addr && !is6)
Simon Kelley832af0b2007-01-21 20:01:28 +00001237 {
1238 struct in_addr in;
1239 unsigned char *op;
1240 char *slash;
1241 /* max length of address/subnet descriptor is five bytes,
1242 add one for the option 120 enc byte too */
Simon Kelley824af852008-02-12 20:43:05 +00001243 new->val = op = opt_malloc((5 * addrs) + 1);
Simon Kelley6b010842007-02-12 20:32:07 +00001244 new->flags |= DHOPT_ADDR;
1245
Simon Kelley572b41e2011-02-18 18:11:18 +00001246 if (!(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
1247 new->opt == OPTION_SIP_SERVER)
Simon Kelley832af0b2007-01-21 20:01:28 +00001248 {
Simon Kelley6b010842007-02-12 20:32:07 +00001249 *(op++) = 1; /* RFC 3361 "enc byte" */
1250 new->flags &= ~DHOPT_ADDR;
Simon Kelley832af0b2007-01-21 20:01:28 +00001251 }
1252 while (addrs--)
1253 {
1254 cp = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001255 comma = split(cp);
Simon Kelley73a08a22009-02-05 20:28:08 +00001256 slash = split_chr(cp, '/');
Simon Kelleya2bc2542016-04-21 22:34:22 +01001257 if (!inet_pton(AF_INET, cp, &in))
1258 ret_err(_("bad IPv4 address"));
Simon Kelley832af0b2007-01-21 20:01:28 +00001259 if (!slash)
1260 {
1261 memcpy(op, &in, INADDRSZ);
1262 op += INADDRSZ;
1263 }
1264 else
1265 {
1266 unsigned char *p = (unsigned char *)&in;
1267 int netsize = atoi(slash);
1268 *op++ = netsize;
1269 if (netsize > 0)
1270 *op++ = *p++;
1271 if (netsize > 8)
1272 *op++ = *p++;
1273 if (netsize > 16)
1274 *op++ = *p++;
1275 if (netsize > 24)
1276 *op++ = *p++;
1277 new->flags &= ~DHOPT_ADDR; /* cannot re-write descriptor format */
1278 }
1279 }
1280 new->len = op - new->val;
1281 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001282 else if (is_addr6 && is6)
1283 {
1284 unsigned char *op;
1285 new->val = op = opt_malloc(16 * addrs);
1286 new->flags |= DHOPT_ADDR6;
1287 while (addrs--)
1288 {
1289 cp = comma;
1290 comma = split(cp);
1291
1292 /* check for [1234::7] */
1293 if (*cp == '[')
1294 cp++;
1295 if (strlen(cp) > 1 && cp[strlen(cp)-1] == ']')
1296 cp[strlen(cp)-1] = 0;
1297
1298 if (inet_pton(AF_INET6, cp, op))
1299 {
1300 op += IN6ADDRSZ;
1301 continue;
1302 }
1303
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001304 ret_err(_("bad IPv6 address"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001305 }
1306 new->len = op - new->val;
1307 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001308 else if (is_string)
Simon Kelley832af0b2007-01-21 20:01:28 +00001309 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001310 /* text arg */
Simon Kelley572b41e2011-02-18 18:11:18 +00001311 if ((new->opt == OPTION_DOMAIN_SEARCH || new->opt == OPTION_SIP_SERVER) &&
Simon Kelley4cb1b322012-02-06 14:30:41 +00001312 !is6 && !(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
Simon Kelley832af0b2007-01-21 20:01:28 +00001313 {
1314 /* dns search, RFC 3397, or SIP, RFC 3361 */
1315 unsigned char *q, *r, *tail;
Simon Kelley824af852008-02-12 20:43:05 +00001316 unsigned char *p, *m = NULL, *newp;
Simon Kelley832af0b2007-01-21 20:01:28 +00001317 size_t newlen, len = 0;
Simon Kelley572b41e2011-02-18 18:11:18 +00001318 int header_size = (new->opt == OPTION_DOMAIN_SEARCH) ? 0 : 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001319
1320 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001321 comma = split(arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00001322
1323 while (arg && *arg)
1324 {
Simon Kelleyc52e1892010-06-07 22:01:39 +01001325 char *in, *dom = NULL;
1326 size_t domlen = 1;
1327 /* Allow "." as an empty domain */
1328 if (strcmp (arg, ".") != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001329 {
Simon Kelleyc52e1892010-06-07 22:01:39 +01001330 if (!(dom = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001331 ret_err(_("bad domain in dhcp-option"));
1332
Simon Kelleyc52e1892010-06-07 22:01:39 +01001333 domlen = strlen(dom) + 2;
Simon Kelley832af0b2007-01-21 20:01:28 +00001334 }
Simon Kelleyc52e1892010-06-07 22:01:39 +01001335
1336 newp = opt_malloc(len + domlen + header_size);
Simon Kelley824af852008-02-12 20:43:05 +00001337 if (m)
Simon Kelleyc52e1892010-06-07 22:01:39 +01001338 {
1339 memcpy(newp, m, header_size + len);
1340 free(m);
1341 }
Simon Kelley824af852008-02-12 20:43:05 +00001342 m = newp;
Simon Kelley832af0b2007-01-21 20:01:28 +00001343 p = m + header_size;
1344 q = p + len;
1345
1346 /* add string on the end in RFC1035 format */
Simon Kelleyc52e1892010-06-07 22:01:39 +01001347 for (in = dom; in && *in;)
Simon Kelley832af0b2007-01-21 20:01:28 +00001348 {
1349 unsigned char *cp = q++;
1350 int j;
Simon Kelleyc52e1892010-06-07 22:01:39 +01001351 for (j = 0; *in && (*in != '.'); in++, j++)
1352 *q++ = *in;
Simon Kelley832af0b2007-01-21 20:01:28 +00001353 *cp = j;
Simon Kelleyc52e1892010-06-07 22:01:39 +01001354 if (*in)
1355 in++;
Simon Kelley832af0b2007-01-21 20:01:28 +00001356 }
1357 *q++ = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +01001358 free(dom);
Simon Kelleyc52e1892010-06-07 22:01:39 +01001359
Simon Kelley832af0b2007-01-21 20:01:28 +00001360 /* Now tail-compress using earlier names. */
1361 newlen = q - p;
1362 for (tail = p + len; *tail; tail += (*tail) + 1)
1363 for (r = p; r - p < (int)len; r += (*r) + 1)
1364 if (strcmp((char *)r, (char *)tail) == 0)
1365 {
1366 PUTSHORT((r - p) | 0xc000, tail);
1367 newlen = tail - p;
1368 goto end;
1369 }
1370 end:
1371 len = newlen;
1372
1373 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001374 comma = split(arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00001375 }
1376
1377 /* RFC 3361, enc byte is zero for names */
Simon Kelley572b41e2011-02-18 18:11:18 +00001378 if (new->opt == OPTION_SIP_SERVER)
Simon Kelley832af0b2007-01-21 20:01:28 +00001379 m[0] = 0;
1380 new->len = (int) len + header_size;
1381 new->val = m;
1382 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001383#ifdef HAVE_DHCP6
1384 else if (comma && (opt_len & OT_CSTRING))
1385 {
1386 /* length fields are two bytes so need 16 bits for each string */
Simon Kelley40ef23b2012-03-13 21:59:28 +00001387 int i, commas = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001388 unsigned char *p, *newp;
1389
Simon Kelley40ef23b2012-03-13 21:59:28 +00001390 for (i = 0; comma[i]; i++)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001391 if (comma[i] == ',')
1392 commas++;
1393
1394 newp = opt_malloc(strlen(comma)+(2*commas));
1395 p = newp;
1396 arg = comma;
1397 comma = split(arg);
1398
1399 while (arg && *arg)
1400 {
1401 u16 len = strlen(arg);
Simon Kelley18f0fb02012-03-31 21:18:55 +01001402 unhide_metas(arg);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001403 PUTSHORT(len, p);
1404 memcpy(p, arg, len);
1405 p += len;
1406
1407 arg = comma;
1408 comma = split(arg);
1409 }
1410
1411 new->val = newp;
1412 new->len = p - newp;
1413 }
1414 else if (comma && (opt_len & OT_RFC1035_NAME))
1415 {
Simon Kelley18f0fb02012-03-31 21:18:55 +01001416 unsigned char *p = NULL, *newp, *end;
1417 int len = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001418 arg = comma;
1419 comma = split(arg);
1420
1421 while (arg && *arg)
1422 {
Simon Kelley18f0fb02012-03-31 21:18:55 +01001423 char *dom = canonicalise_opt(arg);
1424 if (!dom)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001425 ret_err(_("bad domain in dhcp-option"));
1426
Simon Kelley18f0fb02012-03-31 21:18:55 +01001427 newp = opt_malloc(len + strlen(dom) + 2);
1428
1429 if (p)
1430 {
1431 memcpy(newp, p, len);
1432 free(p);
1433 }
1434
1435 p = newp;
Simon Kelley0549c732017-09-25 18:17:11 +01001436 end = do_rfc1035_name(p + len, dom, NULL);
Simon Kelley18f0fb02012-03-31 21:18:55 +01001437 *end++ = 0;
1438 len = end - p;
1439 free(dom);
1440
Simon Kelley4cb1b322012-02-06 14:30:41 +00001441 arg = comma;
1442 comma = split(arg);
1443 }
1444
Simon Kelley18f0fb02012-03-31 21:18:55 +01001445 new->val = p;
1446 new->len = len;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001447 }
1448#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001449 else
1450 {
1451 new->len = strlen(comma);
1452 /* keep terminating zero on string */
Simon Kelley824af852008-02-12 20:43:05 +00001453 new->val = (unsigned char *)opt_string_alloc(comma);
Simon Kelley832af0b2007-01-21 20:01:28 +00001454 new->flags |= DHOPT_STRING;
1455 }
1456 }
1457 }
1458
Simon Kelley4cb1b322012-02-06 14:30:41 +00001459 if (!is6 &&
1460 ((new->len > 255) ||
Simon Kelley316e2732010-01-22 20:16:09 +00001461 (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) ||
Simon Kelley4cb1b322012-02-06 14:30:41 +00001462 (new->len > 250 && (new->flags & DHOPT_RFC3925))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001463 ret_err(_("dhcp-option too long"));
Simon Kelley832af0b2007-01-21 20:01:28 +00001464
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001465 if (flags == DHOPT_MATCH)
Simon Kelley824af852008-02-12 20:43:05 +00001466 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001467 if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||
1468 !new->netid ||
1469 new->netid->next)
1470 ret_err(_("illegal dhcp-match"));
1471
1472 if (is6)
Simon Kelley73a08a22009-02-05 20:28:08 +00001473 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001474 new->next = daemon->dhcp_match6;
1475 daemon->dhcp_match6 = new;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001476 }
1477 else
Simon Kelley73a08a22009-02-05 20:28:08 +00001478 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001479 new->next = daemon->dhcp_match;
1480 daemon->dhcp_match = new;
Simon Kelley73a08a22009-02-05 20:28:08 +00001481 }
Simon Kelley824af852008-02-12 20:43:05 +00001482 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001483 else if (is6)
1484 {
1485 new->next = daemon->dhcp_opts6;
1486 daemon->dhcp_opts6 = new;
1487 }
1488 else
1489 {
1490 new->next = daemon->dhcp_opts;
1491 daemon->dhcp_opts = new;
1492 }
1493
1494 return 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001495}
1496
Simon Kelley7622fc02009-06-04 20:32:05 +01001497#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001498
Simon Kelley28866e92011-02-14 20:19:14 +00001499void set_option_bool(unsigned int opt)
1500{
1501 if (opt < 32)
1502 daemon->options |= 1u << opt;
1503 else
1504 daemon->options2 |= 1u << (opt - 32);
1505}
1506
Simon Kelley2b5bae92012-06-26 16:55:23 +01001507void reset_option_bool(unsigned int opt)
1508{
1509 if (opt < 32)
1510 daemon->options &= ~(1u << opt);
1511 else
1512 daemon->options2 &= ~(1u << (opt - 32));
1513}
1514
Simon Kelley7b1eae42014-02-20 13:43:28 +00001515static 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 +01001516{
1517 int i;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001518 char *comma;
Simon Kelley849a8352006-06-09 21:02:31 +01001519
Simon Kelley832af0b2007-01-21 20:01:28 +00001520 if (option == '?')
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001521 ret_err(gen_err);
Simon Kelley832af0b2007-01-21 20:01:28 +00001522
Simon Kelley1a6bca82008-07-11 11:11:42 +01001523 for (i=0; usage[i].opt != 0; i++)
1524 if (usage[i].opt == option)
Simon Kelley849a8352006-06-09 21:02:31 +01001525 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001526 int rept = usage[i].rept;
1527
Simon Kelley28866e92011-02-14 20:19:14 +00001528 if (command_line)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001529 {
1530 /* command line */
1531 if (rept == ARG_USED_CL)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001532 ret_err(_("illegal repeated flag"));
Simon Kelley1a6bca82008-07-11 11:11:42 +01001533 if (rept == ARG_ONE)
1534 usage[i].rept = ARG_USED_CL;
1535 }
1536 else
1537 {
1538 /* allow file to override command line */
1539 if (rept == ARG_USED_FILE)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001540 ret_err(_("illegal repeated keyword"));
Simon Kelley1a6bca82008-07-11 11:11:42 +01001541 if (rept == ARG_USED_CL || rept == ARG_ONE)
1542 usage[i].rept = ARG_USED_FILE;
1543 }
1544
1545 if (rept != ARG_DUP && rept != ARG_ONE && rept != ARG_USED_CL)
1546 {
Simon Kelley28866e92011-02-14 20:19:14 +00001547 set_option_bool(rept);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001548 return 1;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001549 }
1550
1551 break;
Simon Kelley849a8352006-06-09 21:02:31 +01001552 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001553
Simon Kelley849a8352006-06-09 21:02:31 +01001554 switch (option)
1555 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001556 case 'C': /* --conf-file */
Simon Kelley849a8352006-06-09 21:02:31 +01001557 {
Simon Kelley824af852008-02-12 20:43:05 +00001558 char *file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001559 if (file)
Simon Kelley9009d742008-11-14 20:04:27 +00001560 {
Simon Kelley28866e92011-02-14 20:19:14 +00001561 one_file(file, 0);
Simon Kelley9009d742008-11-14 20:04:27 +00001562 free(file);
1563 }
Simon Kelley849a8352006-06-09 21:02:31 +01001564 break;
1565 }
1566
Simon Kelleyf2621c72007-04-29 19:47:21 +01001567 case '7': /* --conf-dir */
Simon Kelley849a8352006-06-09 21:02:31 +01001568 {
1569 DIR *dir_stream;
1570 struct dirent *ent;
1571 char *directory, *path;
Simon Kelley1f15b812009-10-13 17:49:32 +01001572 struct list {
1573 char *suffix;
1574 struct list *next;
Simon Kelley3e1551a2014-09-09 21:46:07 +01001575 } *ignore_suffix = NULL, *match_suffix = NULL, *li;
Simon Kelley849a8352006-06-09 21:02:31 +01001576
Simon Kelley1f15b812009-10-13 17:49:32 +01001577 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00001578 if (!(directory = opt_string_alloc(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01001579 break;
1580
Simon Kelley1f15b812009-10-13 17:49:32 +01001581 for (arg = comma; arg; arg = comma)
1582 {
1583 comma = split(arg);
Simon Kelley00cd9d52014-10-02 21:44:21 +01001584 if (strlen(arg) != 0)
Simon Kelley3e1551a2014-09-09 21:46:07 +01001585 {
Simon Kelley00cd9d52014-10-02 21:44:21 +01001586 li = opt_malloc(sizeof(struct list));
1587 if (*arg == '*')
1588 {
Simon Kelley0007ee92015-11-21 21:47:41 +00001589 /* "*" with no suffix is a no-op */
1590 if (arg[1] == 0)
1591 free(li);
1592 else
1593 {
1594 li->next = match_suffix;
1595 match_suffix = li;
1596 /* Have to copy: buffer is overwritten */
1597 li->suffix = opt_string_alloc(arg+1);
1598 }
Simon Kelley00cd9d52014-10-02 21:44:21 +01001599 }
1600 else
1601 {
1602 li->next = ignore_suffix;
1603 ignore_suffix = li;
1604 /* Have to copy: buffer is overwritten */
1605 li->suffix = opt_string_alloc(arg);
1606 }
Simon Kelley3e1551a2014-09-09 21:46:07 +01001607 }
Simon Kelley00cd9d52014-10-02 21:44:21 +01001608 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001609
Simon Kelley849a8352006-06-09 21:02:31 +01001610 if (!(dir_stream = opendir(directory)))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001611 die(_("cannot access directory %s: %s"), directory, EC_FILE);
Simon Kelley1f15b812009-10-13 17:49:32 +01001612
Simon Kelley849a8352006-06-09 21:02:31 +01001613 while ((ent = readdir(dir_stream)))
1614 {
Simon Kelley7622fc02009-06-04 20:32:05 +01001615 size_t len = strlen(ent->d_name);
Simon Kelley849a8352006-06-09 21:02:31 +01001616 struct stat buf;
Simon Kelley1f15b812009-10-13 17:49:32 +01001617
1618 /* ignore emacs backups and dotfiles */
Simon Kelley7622fc02009-06-04 20:32:05 +01001619 if (len == 0 ||
1620 ent->d_name[len - 1] == '~' ||
Simon Kelley849a8352006-06-09 21:02:31 +01001621 (ent->d_name[0] == '#' && ent->d_name[len - 1] == '#') ||
1622 ent->d_name[0] == '.')
1623 continue;
Simon Kelley7622fc02009-06-04 20:32:05 +01001624
Simon Kelley3e1551a2014-09-09 21:46:07 +01001625 if (match_suffix)
1626 {
1627 for (li = match_suffix; li; li = li->next)
1628 {
1629 /* check for required suffices */
1630 size_t ls = strlen(li->suffix);
1631 if (len > ls &&
1632 strcmp(li->suffix, &ent->d_name[len - ls]) == 0)
1633 break;
1634 }
1635 if (!li)
1636 continue;
1637 }
1638
Simon Kelley1f15b812009-10-13 17:49:32 +01001639 for (li = ignore_suffix; li; li = li->next)
1640 {
1641 /* check for proscribed suffices */
1642 size_t ls = strlen(li->suffix);
1643 if (len > ls &&
1644 strcmp(li->suffix, &ent->d_name[len - ls]) == 0)
1645 break;
1646 }
1647 if (li)
1648 continue;
1649
Simon Kelley824af852008-02-12 20:43:05 +00001650 path = opt_malloc(strlen(directory) + len + 2);
Simon Kelley849a8352006-06-09 21:02:31 +01001651 strcpy(path, directory);
1652 strcat(path, "/");
1653 strcat(path, ent->d_name);
Simon Kelley7622fc02009-06-04 20:32:05 +01001654
Simon Kelley39595cf2013-02-04 21:40:07 +00001655 /* files must be readable */
Simon Kelley849a8352006-06-09 21:02:31 +01001656 if (stat(path, &buf) == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001657 die(_("cannot access %s: %s"), path, EC_FILE);
Simon Kelley849a8352006-06-09 21:02:31 +01001658
Simon Kelley39595cf2013-02-04 21:40:07 +00001659 /* only reg files allowed. */
1660 if (S_ISREG(buf.st_mode))
1661 one_file(path, 0);
1662
Simon Kelley849a8352006-06-09 21:02:31 +01001663 free(path);
1664 }
1665
1666 closedir(dir_stream);
Simon Kelley9009d742008-11-14 20:04:27 +00001667 free(directory);
Simon Kelley1f15b812009-10-13 17:49:32 +01001668 for(; ignore_suffix; ignore_suffix = li)
1669 {
1670 li = ignore_suffix->next;
1671 free(ignore_suffix->suffix);
1672 free(ignore_suffix);
1673 }
Simon Kelley00cd9d52014-10-02 21:44:21 +01001674 for(; match_suffix; match_suffix = li)
1675 {
1676 li = match_suffix->next;
1677 free(match_suffix->suffix);
1678 free(match_suffix);
Ed Bardsleya7369be2015-08-05 21:17:18 +01001679 }
Simon Kelley849a8352006-06-09 21:02:31 +01001680 break;
1681 }
1682
Simon Kelleyed4c0762013-10-08 20:46:34 +01001683 case LOPT_ADD_SBNET: /* --add-subnet */
1684 set_option_bool(OPT_CLIENT_SUBNET);
1685 if (arg)
1686 {
Ed Bardsleya7369be2015-08-05 21:17:18 +01001687 char *err, *end;
Simon Kelleyed4c0762013-10-08 20:46:34 +01001688 comma = split(arg);
Ed Bardsleya7369be2015-08-05 21:17:18 +01001689
1690 struct mysubnet* new = opt_malloc(sizeof(struct mysubnet));
1691 if ((end = split_chr(arg, '/')))
1692 {
1693 /* has subnet+len */
1694 err = parse_mysockaddr(arg, &new->addr);
1695 if (err)
1696 ret_err(err);
1697 if (!atoi_check(end, &new->mask))
1698 ret_err(gen_err);
1699 new->addr_used = 1;
1700 }
1701 else if (!atoi_check(arg, &new->mask))
1702 ret_err(gen_err);
1703
1704 daemon->add_subnet4 = new;
1705
Ed Bardsleya7369be2015-08-05 21:17:18 +01001706 if (comma)
1707 {
Simon Kelley22fe2fd2016-02-28 17:07:10 +00001708 new = opt_malloc(sizeof(struct mysubnet));
1709 if ((end = split_chr(comma, '/')))
1710 {
1711 /* has subnet+len */
Ed Bardsleya7369be2015-08-05 21:17:18 +01001712 err = parse_mysockaddr(comma, &new->addr);
1713 if (err)
1714 ret_err(err);
1715 if (!atoi_check(end, &new->mask))
1716 ret_err(gen_err);
1717 new->addr_used = 1;
1718 }
1719 else
1720 {
1721 if (!atoi_check(comma, &new->mask))
1722 ret_err(gen_err);
1723 }
Simon Kelley22fe2fd2016-02-28 17:07:10 +00001724
1725 daemon->add_subnet6 = new;
1726 }
Simon Kelleyed4c0762013-10-08 20:46:34 +01001727 }
1728 break;
1729
Simon Kelleyad094272012-08-10 17:10:54 +01001730 case '1': /* --enable-dbus */
1731 set_option_bool(OPT_DBUS);
1732 if (arg)
1733 daemon->dbus_name = opt_string_alloc(arg);
1734 else
1735 daemon->dbus_name = DNSMASQ_SERVICE;
1736 break;
1737
Simon Kelleyf2621c72007-04-29 19:47:21 +01001738 case '8': /* --log-facility */
1739 /* may be a filename */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001740 if (strchr(arg, '/') || strcmp (arg, "-") == 0)
Simon Kelley824af852008-02-12 20:43:05 +00001741 daemon->log_file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001742 else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001743 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001744#ifdef __ANDROID__
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001745 ret_err(_("setting log facility is not possible under Android"));
Simon Kelley572b41e2011-02-18 18:11:18 +00001746#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001747 for (i = 0; facilitynames[i].c_name; i++)
1748 if (hostname_isequal((char *)facilitynames[i].c_name, arg))
1749 break;
1750
1751 if (facilitynames[i].c_name)
1752 daemon->log_fac = facilitynames[i].c_val;
1753 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001754 ret_err(_("bad log facility"));
Simon Kelley572b41e2011-02-18 18:11:18 +00001755#endif
Simon Kelley849a8352006-06-09 21:02:31 +01001756 }
1757 break;
Julian Kornberger8dcdb332018-07-21 22:11:08 +01001758
Simon Kelleyf2621c72007-04-29 19:47:21 +01001759 case 'x': /* --pid-file */
Simon Kelley824af852008-02-12 20:43:05 +00001760 daemon->runfile = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001761 break;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001762
Simon Kelleyf2621c72007-04-29 19:47:21 +01001763 case 'r': /* --resolv-file */
Simon Kelley849a8352006-06-09 21:02:31 +01001764 {
Simon Kelley824af852008-02-12 20:43:05 +00001765 char *name = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001766 struct resolvc *new, *list = daemon->resolv_files;
1767
1768 if (list && list->is_default)
1769 {
1770 /* replace default resolv file - possibly with nothing */
1771 if (name)
1772 {
1773 list->is_default = 0;
1774 list->name = name;
1775 }
1776 else
1777 list = NULL;
1778 }
1779 else if (name)
1780 {
Simon Kelley824af852008-02-12 20:43:05 +00001781 new = opt_malloc(sizeof(struct resolvc));
Simon Kelley849a8352006-06-09 21:02:31 +01001782 new->next = list;
1783 new->name = name;
1784 new->is_default = 0;
1785 new->mtime = 0;
1786 new->logged = 0;
1787 list = new;
1788 }
1789 daemon->resolv_files = list;
1790 break;
1791 }
Simon Kelley7b1eae42014-02-20 13:43:28 +00001792
1793 case LOPT_SERVERS_FILE:
1794 daemon->servers_file = opt_string_alloc(arg);
1795 break;
Simon Kelley849a8352006-06-09 21:02:31 +01001796
Simon Kelleyf2621c72007-04-29 19:47:21 +01001797 case 'm': /* --mx-host */
Simon Kelley849a8352006-06-09 21:02:31 +01001798 {
1799 int pref = 1;
1800 struct mx_srv_record *new;
Simon Kelley1f15b812009-10-13 17:49:32 +01001801 char *name, *target = NULL;
1802
Simon Kelleyf2621c72007-04-29 19:47:21 +01001803 if ((comma = split(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01001804 {
1805 char *prefstr;
Simon Kelley1f15b812009-10-13 17:49:32 +01001806 if ((prefstr = split(comma)) && !atoi_check16(prefstr, &pref))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001807 ret_err(_("bad MX preference"));
Simon Kelley849a8352006-06-09 21:02:31 +01001808 }
1809
Simon Kelley1f15b812009-10-13 17:49:32 +01001810 if (!(name = canonicalise_opt(arg)) ||
1811 (comma && !(target = canonicalise_opt(comma))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001812 ret_err(_("bad MX name"));
Simon Kelley1f15b812009-10-13 17:49:32 +01001813
Simon Kelley824af852008-02-12 20:43:05 +00001814 new = opt_malloc(sizeof(struct mx_srv_record));
Simon Kelley849a8352006-06-09 21:02:31 +01001815 new->next = daemon->mxnames;
1816 daemon->mxnames = new;
1817 new->issrv = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +01001818 new->name = name;
1819 new->target = target; /* may be NULL */
Simon Kelley849a8352006-06-09 21:02:31 +01001820 new->weight = pref;
1821 break;
1822 }
1823
Simon Kelleyf2621c72007-04-29 19:47:21 +01001824 case 't': /* --mx-target */
Simon Kelley1f15b812009-10-13 17:49:32 +01001825 if (!(daemon->mxtarget = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001826 ret_err(_("bad MX target"));
Simon Kelley849a8352006-06-09 21:02:31 +01001827 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01001828
Simon Kelley6b173352018-05-08 18:32:14 +01001829 case LOPT_DUMPFILE: /* --dumpfile */
1830 daemon->dump_file = opt_string_alloc(arg);
1831 break;
1832
1833 case LOPT_DUMPMASK: /* --dumpmask */
1834 daemon->dump_mask = strtol(arg, NULL, 0);
1835 break;
1836
Simon Kelley7622fc02009-06-04 20:32:05 +01001837#ifdef HAVE_DHCP
Simon Kelleyf2621c72007-04-29 19:47:21 +01001838 case 'l': /* --dhcp-leasefile */
Simon Kelley824af852008-02-12 20:43:05 +00001839 daemon->lease_file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001840 break;
1841
Simon Kelleyc72daea2012-01-05 21:33:27 +00001842 /* Sorry about the gross pre-processor abuse */
1843 case '6': /* --dhcp-script */
1844 case LOPT_LUASCRIPT: /* --dhcp-luascript */
Simon Kelley1f15b812009-10-13 17:49:32 +01001845# if defined(NO_FORK)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001846 ret_err(_("cannot run scripts under uClinux"));
Simon Kelley1f15b812009-10-13 17:49:32 +01001847# elif !defined(HAVE_SCRIPT)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001848 ret_err(_("recompile with HAVE_SCRIPT defined to enable lease-change scripts"));
Simon Kelley7622fc02009-06-04 20:32:05 +01001849# else
Simon Kelleyc72daea2012-01-05 21:33:27 +00001850 if (option == LOPT_LUASCRIPT)
1851# if !defined(HAVE_LUASCRIPT)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001852 ret_err(_("recompile with HAVE_LUASCRIPT defined to enable Lua scripts"));
Simon Kelleyc72daea2012-01-05 21:33:27 +00001853# else
1854 daemon->luascript = opt_string_alloc(arg);
1855# endif
1856 else
1857 daemon->lease_change_command = opt_string_alloc(arg);
Simon Kelley7622fc02009-06-04 20:32:05 +01001858# endif
Simon Kelley849a8352006-06-09 21:02:31 +01001859 break;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001860#endif /* HAVE_DHCP */
Simon Kelley7622fc02009-06-04 20:32:05 +01001861
Simon Kelley70d18732015-01-31 19:59:29 +00001862 case LOPT_DHCP_HOST: /* --dhcp-hostsfile */
1863 case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
1864 case LOPT_DHCP_INOTIFY: /* --dhcp-hostsdir */
1865 case LOPT_DHOPT_INOTIFY: /* --dhcp-optsdir */
1866 case LOPT_HOST_INOTIFY: /* --hostsdir */
1867 case 'H': /* --addn-hosts */
Simon Kelley849a8352006-06-09 21:02:31 +01001868 {
Simon Kelley824af852008-02-12 20:43:05 +00001869 struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
Simon Kelley19c51cf2014-03-18 22:38:30 +00001870 static unsigned int hosts_index = SRC_AH;
Simon Kelley824af852008-02-12 20:43:05 +00001871 new->fname = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001872 new->index = hosts_index++;
Simon Kelley7622fc02009-06-04 20:32:05 +01001873 new->flags = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00001874 if (option == 'H')
1875 {
1876 new->next = daemon->addn_hosts;
1877 daemon->addn_hosts = new;
1878 }
1879 else if (option == LOPT_DHCP_HOST)
1880 {
1881 new->next = daemon->dhcp_hosts_file;
1882 daemon->dhcp_hosts_file = new;
1883 }
Simon Kelleye1ff4192012-12-09 17:08:47 +00001884 else if (option == LOPT_DHCP_OPTS)
Simon Kelley28866e92011-02-14 20:19:14 +00001885 {
1886 new->next = daemon->dhcp_opts_file;
1887 daemon->dhcp_opts_file = new;
1888 }
Simon Kelley70d18732015-01-31 19:59:29 +00001889 else
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00001890 {
Simon Kelley70d18732015-01-31 19:59:29 +00001891 new->next = daemon->dynamic_dirs;
1892 daemon->dynamic_dirs = new;
1893 if (option == LOPT_DHCP_INOTIFY)
1894 new->flags |= AH_DHCP_HST;
1895 else if (option == LOPT_DHOPT_INOTIFY)
1896 new->flags |= AH_DHCP_OPT;
1897 else if (option == LOPT_HOST_INOTIFY)
1898 new->flags |= AH_HOSTS;
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00001899 }
1900
Simon Kelley849a8352006-06-09 21:02:31 +01001901 break;
1902 }
1903
Simon Kelley4f7b3042012-11-28 21:27:02 +00001904 case LOPT_AUTHSERV: /* --auth-server */
Simon Kelley86e3b9a2012-11-30 13:46:48 +00001905 if (!(comma = split(arg)))
Simon Kelley4f7b3042012-11-28 21:27:02 +00001906 ret_err(gen_err);
1907
Simon Kelley4f7b3042012-11-28 21:27:02 +00001908 daemon->authserver = opt_string_alloc(arg);
Simon Kelley429798f2012-12-10 20:45:53 +00001909 arg = comma;
1910 do {
1911 struct iname *new = opt_malloc(sizeof(struct iname));
1912 comma = split(arg);
1913 new->name = NULL;
1914 unhide_metas(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01001915 if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0)
Simon Kelley429798f2012-12-10 20:45:53 +00001916 new->addr.sa.sa_family = AF_INET;
1917#ifdef HAVE_IPV6
1918 else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
1919 new->addr.sa.sa_family = AF_INET6;
1920#endif
1921 else
Simon Kelleyf25e6c62013-11-17 12:23:42 +00001922 {
1923 char *fam = split_chr(arg, '/');
1924 new->name = opt_string_alloc(arg);
1925 new->addr.sa.sa_family = 0;
1926 if (fam)
1927 {
1928 if (strcmp(fam, "4") == 0)
1929 new->addr.sa.sa_family = AF_INET;
1930#ifdef HAVE_IPV6
1931 else if (strcmp(fam, "6") == 0)
1932 new->addr.sa.sa_family = AF_INET6;
1933#endif
1934 else
1935 ret_err(gen_err);
1936 }
1937 }
Simon Kelley429798f2012-12-10 20:45:53 +00001938 new->next = daemon->authinterface;
1939 daemon->authinterface = new;
1940
1941 arg = comma;
1942 } while (arg);
1943
Simon Kelley4f7b3042012-11-28 21:27:02 +00001944 break;
Simon Kelleye1ff4192012-12-09 17:08:47 +00001945
1946 case LOPT_AUTHSFS: /* --auth-sec-servers */
1947 {
1948 struct name_list *new;
1949
1950 do {
1951 comma = split(arg);
Simon Kelley429798f2012-12-10 20:45:53 +00001952 new = opt_malloc(sizeof(struct name_list));
Simon Kelleye1ff4192012-12-09 17:08:47 +00001953 new->name = opt_string_alloc(arg);
1954 new->next = daemon->secondary_forward_server;
1955 daemon->secondary_forward_server = new;
1956 arg = comma;
1957 } while (arg);
1958 break;
1959 }
1960
Simon Kelley4f7b3042012-11-28 21:27:02 +00001961 case LOPT_AUTHZONE: /* --auth-zone */
1962 {
1963 struct auth_zone *new;
1964
1965 comma = split(arg);
Simon Kelley1e14cc02012-12-29 17:27:59 +00001966
Simon Kelley429798f2012-12-10 20:45:53 +00001967 new = opt_malloc(sizeof(struct auth_zone));
Simon Kelley4f7b3042012-11-28 21:27:02 +00001968 new->domain = opt_string_alloc(arg);
1969 new->subnet = NULL;
Mathias Kresin094bfae2016-07-24 14:15:22 +01001970 new->exclude = NULL;
Simon Kelley376d48c2013-11-13 13:04:30 +00001971 new->interface_names = NULL;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001972 new->next = daemon->auth_zones;
1973 daemon->auth_zones = new;
1974
1975 while ((arg = comma))
1976 {
1977 int prefixlen = 0;
Mathias Kresin094bfae2016-07-24 14:15:22 +01001978 int is_exclude = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001979 char *prefix;
Simon Kelley376d48c2013-11-13 13:04:30 +00001980 struct addrlist *subnet = NULL;
1981 struct all_addr addr;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001982
1983 comma = split(arg);
1984 prefix = split_chr(arg, '/');
1985
1986 if (prefix && !atoi_check(prefix, &prefixlen))
1987 ret_err(gen_err);
1988
Mathias Kresin094bfae2016-07-24 14:15:22 +01001989 if (strstr(arg, "exclude:") == arg)
1990 {
1991 is_exclude = 1;
1992 arg = arg+8;
1993 }
1994
Simon Kelley376d48c2013-11-13 13:04:30 +00001995 if (inet_pton(AF_INET, arg, &addr.addr.addr4))
Simon Kelley4f7b3042012-11-28 21:27:02 +00001996 {
Simon Kelley376d48c2013-11-13 13:04:30 +00001997 subnet = opt_malloc(sizeof(struct addrlist));
Simon Kelley4f7b3042012-11-28 21:27:02 +00001998 subnet->prefixlen = (prefixlen == 0) ? 24 : prefixlen;
Simon Kelley376d48c2013-11-13 13:04:30 +00001999 subnet->flags = ADDRLIST_LITERAL;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002000 }
2001#ifdef HAVE_IPV6
Simon Kelley376d48c2013-11-13 13:04:30 +00002002 else if (inet_pton(AF_INET6, arg, &addr.addr.addr6))
Simon Kelley4f7b3042012-11-28 21:27:02 +00002003 {
Simon Kelley376d48c2013-11-13 13:04:30 +00002004 subnet = opt_malloc(sizeof(struct addrlist));
Simon Kelley4f7b3042012-11-28 21:27:02 +00002005 subnet->prefixlen = (prefixlen == 0) ? 64 : prefixlen;
Simon Kelley376d48c2013-11-13 13:04:30 +00002006 subnet->flags = ADDRLIST_LITERAL | ADDRLIST_IPV6;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002007 }
2008#endif
Simon Kelley376d48c2013-11-13 13:04:30 +00002009 else
2010 {
2011 struct auth_name_list *name = opt_malloc(sizeof(struct auth_name_list));
2012 name->name = opt_string_alloc(arg);
2013 name->flags = AUTH4 | AUTH6;
2014 name->next = new->interface_names;
2015 new->interface_names = name;
2016 if (prefix)
2017 {
2018 if (prefixlen == 4)
2019 name->flags &= ~AUTH6;
2020#ifdef HAVE_IPV6
2021 else if (prefixlen == 6)
2022 name->flags &= ~AUTH4;
2023#endif
2024 else
2025 ret_err(gen_err);
2026 }
2027 }
2028
2029 if (subnet)
2030 {
2031 subnet->addr = addr;
Mathias Kresin094bfae2016-07-24 14:15:22 +01002032
2033 if (is_exclude)
2034 {
2035 subnet->next = new->exclude;
2036 new->exclude = subnet;
2037 }
2038 else
2039 {
2040 subnet->next = new->subnet;
2041 new->subnet = subnet;
2042 }
Simon Kelley376d48c2013-11-13 13:04:30 +00002043 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002044 }
2045 break;
2046 }
Simon Kelley376d48c2013-11-13 13:04:30 +00002047
Simon Kelley4f7b3042012-11-28 21:27:02 +00002048 case LOPT_AUTHSOA: /* --auth-soa */
2049 comma = split(arg);
Simon Kelley5c72bb92013-08-19 14:12:59 +01002050 daemon->soa_sn = (u32)atoi(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002051 if (comma)
2052 {
Simon Kelley86e3b9a2012-11-30 13:46:48 +00002053 char *cp;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002054 arg = comma;
2055 comma = split(arg);
2056 daemon->hostmaster = opt_string_alloc(arg);
Simon Kelley86e3b9a2012-11-30 13:46:48 +00002057 for (cp = daemon->hostmaster; *cp; cp++)
2058 if (*cp == '@')
2059 *cp = '.';
2060
Simon Kelley4f7b3042012-11-28 21:27:02 +00002061 if (comma)
2062 {
2063 arg = comma;
2064 comma = split(arg);
Simon Kelley5c72bb92013-08-19 14:12:59 +01002065 daemon->soa_refresh = (u32)atoi(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002066 if (comma)
2067 {
2068 arg = comma;
2069 comma = split(arg);
Simon Kelley5c72bb92013-08-19 14:12:59 +01002070 daemon->soa_retry = (u32)atoi(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002071 if (comma)
Simon Kelley407a1f32016-03-01 17:06:07 +00002072 daemon->soa_expiry = (u32)atoi(comma);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002073 }
2074 }
2075 }
2076
2077 break;
2078
Simon Kelley2bb73af2013-04-24 17:38:19 +01002079 case 's': /* --domain */
2080 case LOPT_SYNTH: /* --synth-domain */
Simon Kelley849a8352006-06-09 21:02:31 +01002081 if (strcmp (arg, "#") == 0)
Simon Kelley28866e92011-02-14 20:19:14 +00002082 set_option_bool(OPT_RESOLV_DOMAIN);
Simon Kelley849a8352006-06-09 21:02:31 +01002083 else
Simon Kelley9009d742008-11-14 20:04:27 +00002084 {
Simon Kelley1f15b812009-10-13 17:49:32 +01002085 char *d;
Simon Kelley9009d742008-11-14 20:04:27 +00002086 comma = split(arg);
Simon Kelley1f15b812009-10-13 17:49:32 +01002087 if (!(d = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002088 ret_err(gen_err);
Simon Kelley9009d742008-11-14 20:04:27 +00002089 else
2090 {
Simon Kelley9009d742008-11-14 20:04:27 +00002091 if (comma)
2092 {
Simon Kelley429798f2012-12-10 20:45:53 +00002093 struct cond_domain *new = opt_malloc(sizeof(struct cond_domain));
Simon Kelley28866e92011-02-14 20:19:14 +00002094 char *netpart;
Simon Kelley2bb73af2013-04-24 17:38:19 +01002095
Simon Kelley48fd1c42013-04-25 09:49:38 +01002096 new->prefix = NULL;
Simon Kelley6b2b5642018-03-10 18:12:04 +00002097 new->indexed = 0;
2098
Simon Kelley9009d742008-11-14 20:04:27 +00002099 unhide_metas(comma);
Simon Kelley28866e92011-02-14 20:19:14 +00002100 if ((netpart = split_chr(comma, '/')))
Simon Kelley9009d742008-11-14 20:04:27 +00002101 {
Simon Kelleyd74942a2012-02-07 20:51:56 +00002102 int msize;
2103
Simon Kelley28866e92011-02-14 20:19:14 +00002104 arg = split(netpart);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002105 if (!atoi_check(netpart, &msize))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002106 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002107 else if (inet_pton(AF_INET, comma, &new->start))
Simon Kelley9009d742008-11-14 20:04:27 +00002108 {
Simon Kelleyd74942a2012-02-07 20:51:56 +00002109 int mask = (1 << (32 - msize)) - 1;
2110 new->is6 = 0;
Simon Kelley9009d742008-11-14 20:04:27 +00002111 new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask);
2112 new->end.s_addr = new->start.s_addr | htonl(mask);
Simon Kelley28866e92011-02-14 20:19:14 +00002113 if (arg)
2114 {
Simon Kelley48fd1c42013-04-25 09:49:38 +01002115 if (option != 's')
Simon Kelleyb5a7ff42013-04-25 11:03:47 +01002116 {
2117 if (!(new->prefix = canonicalise_opt(arg)) ||
2118 strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
2119 ret_err(_("bad prefix"));
2120 }
Simon Kelley48fd1c42013-04-25 09:49:38 +01002121 else if (strcmp(arg, "local") != 0 ||
2122 (msize != 8 && msize != 16 && msize != 24))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002123 ret_err(gen_err);
Simon Kelley28866e92011-02-14 20:19:14 +00002124 else
2125 {
Simon Kelleyde73a492014-02-17 21:43:27 +00002126 /* generate the equivalent of
Simon Kelleyde73a492014-02-17 21:43:27 +00002127 local=/xxx.yyy.zzz.in-addr.arpa/ */
2128 struct server *serv = add_rev4(new->start, msize);
Olivier Gayotdc990582017-03-06 22:17:21 +00002129 if (!serv)
2130 ret_err(_("bad prefix"));
2131
Simon Kelleyde73a492014-02-17 21:43:27 +00002132 serv->flags |= SERV_NO_ADDR;
Simon Kelley3ad3f3b2014-12-16 18:25:17 +00002133
2134 /* local=/<domain>/ */
2135 serv = opt_malloc(sizeof(struct server));
2136 memset(serv, 0, sizeof(struct server));
2137 serv->domain = d;
2138 serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
2139 serv->next = daemon->servers;
2140 daemon->servers = serv;
Simon Kelley28866e92011-02-14 20:19:14 +00002141 }
2142 }
Simon Kelley9009d742008-11-14 20:04:27 +00002143 }
Simon Kelleyd74942a2012-02-07 20:51:56 +00002144#ifdef HAVE_IPV6
2145 else if (inet_pton(AF_INET6, comma, &new->start6))
2146 {
2147 u64 mask = (1LLU << (128 - msize)) - 1LLU;
2148 u64 addrpart = addr6part(&new->start6);
2149 new->is6 = 1;
Simon Kelley48fd1c42013-04-25 09:49:38 +01002150
Simon Kelleyd74942a2012-02-07 20:51:56 +00002151 /* prefix==64 overflows the mask calculation above */
2152 if (msize == 64)
2153 mask = (u64)-1LL;
Simon Kelley48fd1c42013-04-25 09:49:38 +01002154
Simon Kelleyd74942a2012-02-07 20:51:56 +00002155 new->end6 = new->start6;
2156 setaddr6part(&new->start6, addrpart & ~mask);
2157 setaddr6part(&new->end6, addrpart | mask);
2158
2159 if (msize < 64)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002160 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002161 else if (arg)
2162 {
Simon Kelley48fd1c42013-04-25 09:49:38 +01002163 if (option != 's')
Simon Kelleyb5a7ff42013-04-25 11:03:47 +01002164 {
2165 if (!(new->prefix = canonicalise_opt(arg)) ||
2166 strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
2167 ret_err(_("bad prefix"));
2168 }
Simon Kelley48fd1c42013-04-25 09:49:38 +01002169 else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002170 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002171 else
2172 {
Simon Kelley48fd1c42013-04-25 09:49:38 +01002173 /* generate the equivalent of
Simon Kelley48fd1c42013-04-25 09:49:38 +01002174 local=/xxx.yyy.zzz.ip6.arpa/ */
Simon Kelleyde73a492014-02-17 21:43:27 +00002175 struct server *serv = add_rev6(&new->start6, msize);
2176 serv->flags |= SERV_NO_ADDR;
Simon Kelley3ad3f3b2014-12-16 18:25:17 +00002177
2178 /* local=/<domain>/ */
2179 serv = opt_malloc(sizeof(struct server));
2180 memset(serv, 0, sizeof(struct server));
2181 serv->domain = d;
2182 serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
2183 serv->next = daemon->servers;
2184 daemon->servers = serv;
Simon Kelleyd74942a2012-02-07 20:51:56 +00002185 }
2186 }
2187 }
2188#endif
2189 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002190 ret_err(gen_err);
Simon Kelley9009d742008-11-14 20:04:27 +00002191 }
Simon Kelleyeec5c1e2013-10-25 10:37:30 +01002192 else
Simon Kelleyd74942a2012-02-07 20:51:56 +00002193 {
Simon Kelleyeec5c1e2013-10-25 10:37:30 +01002194 char *prefstr;
Simon Kelleyd74942a2012-02-07 20:51:56 +00002195 arg = split(comma);
Simon Kelleyeec5c1e2013-10-25 10:37:30 +01002196 prefstr = split(arg);
2197
Simon Kelleyd74942a2012-02-07 20:51:56 +00002198 if (inet_pton(AF_INET, comma, &new->start))
2199 {
2200 new->is6 = 0;
2201 if (!arg)
2202 new->end.s_addr = new->start.s_addr;
2203 else if (!inet_pton(AF_INET, arg, &new->end))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002204 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002205 }
2206#ifdef HAVE_IPV6
2207 else if (inet_pton(AF_INET6, comma, &new->start6))
2208 {
2209 new->is6 = 1;
2210 if (!arg)
2211 memcpy(&new->end6, &new->start6, IN6ADDRSZ);
2212 else if (!inet_pton(AF_INET6, arg, &new->end6))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002213 ret_err(gen_err);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002214 }
2215#endif
2216 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002217 ret_err(gen_err);
Simon Kelleyeec5c1e2013-10-25 10:37:30 +01002218
2219 if (option != 's' && prefstr)
2220 {
2221 if (!(new->prefix = canonicalise_opt(prefstr)) ||
2222 strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
2223 ret_err(_("bad prefix"));
2224 }
Simon Kelleyd74942a2012-02-07 20:51:56 +00002225 }
Simon Kelley2307eac2012-02-13 10:13:13 +00002226
2227 new->domain = d;
Simon Kelley2bb73af2013-04-24 17:38:19 +01002228 if (option == 's')
2229 {
2230 new->next = daemon->cond_domain;
2231 daemon->cond_domain = new;
2232 }
2233 else
2234 {
Simon Kelley6b2b5642018-03-10 18:12:04 +00002235 char *star;
Simon Kelley2bb73af2013-04-24 17:38:19 +01002236 new->next = daemon->synth_domains;
2237 daemon->synth_domains = new;
Simon Kelleydd33e982018-07-30 14:55:39 +01002238 if (new->prefix &&
2239 (star = strrchr(new->prefix, '*'))
2240 && *(star+1) == 0)
Simon Kelley6b2b5642018-03-10 18:12:04 +00002241 {
2242 *star = 0;
2243 new->indexed = 1;
2244 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01002245 }
Simon Kelley9009d742008-11-14 20:04:27 +00002246 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01002247 else if (option == 's')
Simon Kelley9009d742008-11-14 20:04:27 +00002248 daemon->domain_suffix = d;
Simon Kelley2bb73af2013-04-24 17:38:19 +01002249 else
2250 ret_err(gen_err);
Simon Kelley9009d742008-11-14 20:04:27 +00002251 }
2252 }
Simon Kelley849a8352006-06-09 21:02:31 +01002253 break;
2254
Simon Kelley1e505122016-01-25 21:29:23 +00002255 case LOPT_CPE_ID: /* --add-dns-client */
2256 if (arg)
Simon Kelley33702ab2015-12-28 23:17:15 +00002257 daemon->dns_client_id = opt_string_alloc(arg);
2258 break;
2259
Simon Kelleyc7f3bd22016-02-28 21:48:34 +00002260 case LOPT_ADD_MAC: /* --add-mac */
Simon Kelley1e505122016-01-25 21:29:23 +00002261 if (!arg)
2262 set_option_bool(OPT_ADD_MAC);
2263 else
2264 {
2265 unhide_metas(arg);
2266 if (strcmp(arg, "base64") == 0)
2267 set_option_bool(OPT_MAC_B64);
Simon Kelley9e4cf472016-02-17 20:26:32 +00002268 else if (strcmp(arg, "text") == 0)
2269 set_option_bool(OPT_MAC_HEX);
Simon Kelley22c0f4f2016-02-17 22:12:31 +00002270 else
2271 ret_err(gen_err);
Simon Kelley1e505122016-01-25 21:29:23 +00002272 }
2273 break;
2274
Simon Kelleyf2621c72007-04-29 19:47:21 +01002275 case 'u': /* --user */
Simon Kelley824af852008-02-12 20:43:05 +00002276 daemon->username = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002277 break;
2278
Simon Kelleyf2621c72007-04-29 19:47:21 +01002279 case 'g': /* --group */
Simon Kelley824af852008-02-12 20:43:05 +00002280 daemon->groupname = opt_string_alloc(arg);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002281 daemon->group_set = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01002282 break;
Simon Kelley9e038942008-05-30 20:06:34 +01002283
Simon Kelley7622fc02009-06-04 20:32:05 +01002284#ifdef HAVE_DHCP
Simon Kelley9e038942008-05-30 20:06:34 +01002285 case LOPT_SCRIPTUSR: /* --scriptuser */
2286 daemon->scriptuser = opt_string_alloc(arg);
2287 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01002288#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002289
Simon Kelleyf2621c72007-04-29 19:47:21 +01002290 case 'i': /* --interface */
Simon Kelley849a8352006-06-09 21:02:31 +01002291 do {
Simon Kelley824af852008-02-12 20:43:05 +00002292 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01002293 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002294 new->next = daemon->if_names;
2295 daemon->if_names = new;
2296 /* new->name may be NULL if someone does
2297 "interface=" to disable all interfaces except loop. */
Simon Kelley824af852008-02-12 20:43:05 +00002298 new->name = opt_string_alloc(arg);
Simon Kelley4ce4f372012-06-14 11:50:45 +01002299 new->used = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002300 arg = comma;
2301 } while (arg);
2302 break;
2303
Simon Kelley2937f8a2013-07-29 19:49:07 +01002304 case LOPT_TFTP: /* --enable-tftp */
2305 set_option_bool(OPT_TFTP);
2306 if (!arg)
2307 break;
2308 /* fall through */
2309
Simon Kelleyf2621c72007-04-29 19:47:21 +01002310 case 'I': /* --except-interface */
2311 case '2': /* --no-dhcp-interface */
Simon Kelley849a8352006-06-09 21:02:31 +01002312 do {
Simon Kelley824af852008-02-12 20:43:05 +00002313 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01002314 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00002315 new->name = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002316 if (option == 'I')
2317 {
2318 new->next = daemon->if_except;
2319 daemon->if_except = new;
2320 }
Simon Kelley2937f8a2013-07-29 19:49:07 +01002321 else if (option == LOPT_TFTP)
2322 {
2323 new->next = daemon->tftp_interfaces;
2324 daemon->tftp_interfaces = new;
2325 }
Simon Kelley849a8352006-06-09 21:02:31 +01002326 else
2327 {
2328 new->next = daemon->dhcp_except;
2329 daemon->dhcp_except = new;
2330 }
2331 arg = comma;
2332 } while (arg);
2333 break;
2334
Simon Kelleyf2621c72007-04-29 19:47:21 +01002335 case 'B': /* --bogus-nxdomain */
Glen Huang32fc6db2014-12-27 15:28:12 +00002336 case LOPT_IGNORE_ADDR: /* --ignore-address */
2337 {
Simon Kelley849a8352006-06-09 21:02:31 +01002338 struct in_addr addr;
2339 unhide_metas(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002340 if (arg && (inet_pton(AF_INET, arg, &addr) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01002341 {
Simon Kelley824af852008-02-12 20:43:05 +00002342 struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
Glen Huang32fc6db2014-12-27 15:28:12 +00002343 if (option == 'B')
2344 {
2345 baddr->next = daemon->bogus_addr;
2346 daemon->bogus_addr = baddr;
2347 }
2348 else
2349 {
2350 baddr->next = daemon->ignore_addr;
2351 daemon->ignore_addr = baddr;
2352 }
Simon Kelley849a8352006-06-09 21:02:31 +01002353 baddr->addr = addr;
2354 }
2355 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002356 ret_err(gen_err); /* error */
Simon Kelley849a8352006-06-09 21:02:31 +01002357 break;
2358 }
2359
Simon Kelleyf2621c72007-04-29 19:47:21 +01002360 case 'a': /* --listen-address */
Simon Kelley49678762012-12-09 18:24:58 +00002361 case LOPT_AUTHPEER: /* --auth-peer */
Simon Kelley849a8352006-06-09 21:02:31 +01002362 do {
Simon Kelley824af852008-02-12 20:43:05 +00002363 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01002364 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002365 unhide_metas(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002366 if (arg && (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01002367 {
2368 new->addr.sa.sa_family = AF_INET;
Simon Kelley49678762012-12-09 18:24:58 +00002369 new->addr.in.sin_port = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002370#ifdef HAVE_SOCKADDR_SA_LEN
2371 new->addr.in.sin_len = sizeof(new->addr.in);
2372#endif
2373 }
2374#ifdef HAVE_IPV6
2375 else if (arg && inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
2376 {
2377 new->addr.sa.sa_family = AF_INET6;
2378 new->addr.in6.sin6_flowinfo = 0;
2379 new->addr.in6.sin6_scope_id = 0;
Simon Kelley49678762012-12-09 18:24:58 +00002380 new->addr.in6.sin6_port = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002381#ifdef HAVE_SOCKADDR_SA_LEN
2382 new->addr.in6.sin6_len = sizeof(new->addr.in6);
2383#endif
2384 }
2385#endif
2386 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002387 ret_err(gen_err);
Simon Kelley4ce4f372012-06-14 11:50:45 +01002388
2389 new->used = 0;
Simon Kelley49678762012-12-09 18:24:58 +00002390 if (option == 'a')
2391 {
2392 new->next = daemon->if_addrs;
2393 daemon->if_addrs = new;
2394 }
2395 else
2396 {
2397 new->next = daemon->auth_peers;
2398 daemon->auth_peers = new;
2399 }
Simon Kelley849a8352006-06-09 21:02:31 +01002400 arg = comma;
2401 } while (arg);
2402 break;
2403
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002404 case 'S': /* --server */
2405 case LOPT_LOCAL: /* --local */
2406 case 'A': /* --address */
2407 case LOPT_NO_REBIND: /* --rebind-domain-ok */
Simon Kelley849a8352006-06-09 21:02:31 +01002408 {
2409 struct server *serv, *newlist = NULL;
2410
2411 unhide_metas(arg);
2412
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002413 if (arg && (*arg == '/' || option == LOPT_NO_REBIND))
Simon Kelley849a8352006-06-09 21:02:31 +01002414 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002415 int rebind = !(*arg == '/');
2416 char *end = NULL;
2417 if (!rebind)
2418 arg++;
2419 while (rebind || (end = split_chr(arg, '/')))
Simon Kelley849a8352006-06-09 21:02:31 +01002420 {
2421 char *domain = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002422 /* elide leading dots - they are implied in the search algorithm */
2423 while (*arg == '.') arg++;
Simon Kelley849a8352006-06-09 21:02:31 +01002424 /* # matches everything and becomes a zero length domain string */
2425 if (strcmp(arg, "#") == 0)
2426 domain = "";
Simon Kelley1f15b812009-10-13 17:49:32 +01002427 else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
Simon Kelleya3bd7e72018-07-19 22:00:08 +01002428 ret_err(gen_err);
Simon Kelley824af852008-02-12 20:43:05 +00002429 serv = opt_malloc(sizeof(struct server));
2430 memset(serv, 0, sizeof(struct server));
Simon Kelley849a8352006-06-09 21:02:31 +01002431 serv->next = newlist;
2432 newlist = serv;
Simon Kelley849a8352006-06-09 21:02:31 +01002433 serv->domain = domain;
2434 serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
Simon Kelley73a08a22009-02-05 20:28:08 +00002435 arg = end;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002436 if (rebind)
2437 break;
Simon Kelley849a8352006-06-09 21:02:31 +01002438 }
2439 if (!newlist)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002440 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002441 }
2442 else
2443 {
Simon Kelley824af852008-02-12 20:43:05 +00002444 newlist = opt_malloc(sizeof(struct server));
2445 memset(newlist, 0, sizeof(struct server));
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002446#ifdef HAVE_LOOP
2447 newlist->uid = rand32();
2448#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002449 }
2450
Simon Kelley7b1eae42014-02-20 13:43:28 +00002451 if (servers_only && option == 'S')
2452 newlist->flags |= SERV_FROM_FILE;
2453
Simon Kelley849a8352006-06-09 21:02:31 +01002454 if (option == 'A')
2455 {
2456 newlist->flags |= SERV_LITERAL_ADDRESS;
2457 if (!(newlist->flags & SERV_TYPE))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002458 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002459 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002460 else if (option == LOPT_NO_REBIND)
2461 newlist->flags |= SERV_NO_REBIND;
Simon Kelley849a8352006-06-09 21:02:31 +01002462
2463 if (!arg || !*arg)
2464 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002465 if (!(newlist->flags & SERV_NO_REBIND))
2466 newlist->flags |= SERV_NO_ADDR; /* no server */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002467 }
2468
2469 else if (strcmp(arg, "#") == 0)
2470 {
2471 newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
Simon Kelley849a8352006-06-09 21:02:31 +01002472 if (newlist->flags & SERV_LITERAL_ADDRESS)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002473 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002474 }
2475 else
2476 {
Simon Kelleyfaafb3f2012-09-20 14:17:39 +01002477 char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
2478 if (err)
2479 ret_err(err);
Simon Kelley849a8352006-06-09 21:02:31 +01002480 }
2481
Simon Kelleyf2621c72007-04-29 19:47:21 +01002482 serv = newlist;
2483 while (serv->next)
Simon Kelley849a8352006-06-09 21:02:31 +01002484 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01002485 serv->next->flags = serv->flags;
2486 serv->next->addr = serv->addr;
2487 serv->next->source_addr = serv->source_addr;
Simon Kelleyfaafb3f2012-09-20 14:17:39 +01002488 strcpy(serv->next->interface, serv->interface);
Simon Kelleyf2621c72007-04-29 19:47:21 +01002489 serv = serv->next;
Simon Kelley849a8352006-06-09 21:02:31 +01002490 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01002491 serv->next = daemon->servers;
2492 daemon->servers = newlist;
Simon Kelley849a8352006-06-09 21:02:31 +01002493 break;
2494 }
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002495
Simon Kelleyde73a492014-02-17 21:43:27 +00002496 case LOPT_REV_SERV: /* --rev-server */
2497 {
2498 char *string;
2499 int size;
2500 struct server *serv;
2501 struct in_addr addr4;
2502#ifdef HAVE_IPV6
2503 struct in6_addr addr6;
2504#endif
2505
2506 unhide_metas(arg);
2507 if (!arg || !(comma=split(arg)) || !(string = split_chr(arg, '/')) || !atoi_check(string, &size))
2508 ret_err(gen_err);
2509
2510 if (inet_pton(AF_INET, arg, &addr4))
Olivier Gayotdc990582017-03-06 22:17:21 +00002511 {
2512 serv = add_rev4(addr4, size);
2513 if (!serv)
2514 ret_err(_("bad prefix"));
2515 }
Simon Kelleyde73a492014-02-17 21:43:27 +00002516#ifdef HAVE_IPV6
2517 else if (inet_pton(AF_INET6, arg, &addr6))
2518 serv = add_rev6(&addr6, size);
2519#endif
2520 else
2521 ret_err(gen_err);
2522
2523 string = parse_server(comma, &serv->addr, &serv->source_addr, serv->interface, &serv->flags);
2524
2525 if (string)
2526 ret_err(string);
Simon Kelley7b1eae42014-02-20 13:43:28 +00002527
2528 if (servers_only)
2529 serv->flags |= SERV_FROM_FILE;
2530
Simon Kelleyde73a492014-02-17 21:43:27 +00002531 break;
2532 }
2533
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002534 case LOPT_IPSET: /* --ipset */
2535#ifndef HAVE_IPSET
2536 ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
2537 break;
2538#else
2539 {
2540 struct ipsets ipsets_head;
2541 struct ipsets *ipsets = &ipsets_head;
2542 int size;
2543 char *end;
2544 char **sets, **sets_pos;
2545 memset(ipsets, 0, sizeof(struct ipsets));
2546 unhide_metas(arg);
2547 if (arg && *arg == '/')
2548 {
2549 arg++;
2550 while ((end = split_chr(arg, '/')))
2551 {
2552 char *domain = NULL;
2553 /* elide leading dots - they are implied in the search algorithm */
2554 while (*arg == '.')
2555 arg++;
2556 /* # matches everything and becomes a zero length domain string */
2557 if (strcmp(arg, "#") == 0 || !*arg)
2558 domain = "";
2559 else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg)))
Simon Kelleya3bd7e72018-07-19 22:00:08 +01002560 ret_err(gen_err);
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002561 ipsets->next = opt_malloc(sizeof(struct ipsets));
2562 ipsets = ipsets->next;
2563 memset(ipsets, 0, sizeof(struct ipsets));
2564 ipsets->domain = domain;
2565 arg = end;
2566 }
2567 }
2568 else
2569 {
2570 ipsets->next = opt_malloc(sizeof(struct ipsets));
2571 ipsets = ipsets->next;
2572 memset(ipsets, 0, sizeof(struct ipsets));
2573 ipsets->domain = "";
2574 }
Simon Kelleya3bd7e72018-07-19 22:00:08 +01002575
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002576 if (!arg || !*arg)
Simon Kelleya3bd7e72018-07-19 22:00:08 +01002577 ret_err(gen_err);
2578
2579 for (size = 2, end = arg; *end; ++end)
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002580 if (*end == ',')
2581 ++size;
2582
2583 sets = sets_pos = opt_malloc(sizeof(char *) * size);
2584
2585 do {
2586 end = split(arg);
2587 *sets_pos++ = opt_string_alloc(arg);
2588 arg = end;
2589 } while (end);
2590 *sets_pos = 0;
2591 for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next)
2592 ipsets->next->sets = sets;
2593 ipsets->next = daemon->ipsets;
2594 daemon->ipsets = ipsets_head.next;
2595
2596 break;
2597 }
2598#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002599
Simon Kelleyf2621c72007-04-29 19:47:21 +01002600 case 'c': /* --cache-size */
Simon Kelley849a8352006-06-09 21:02:31 +01002601 {
2602 int size;
2603
2604 if (!atoi_check(arg, &size))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002605 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002606 else
2607 {
2608 /* zero is OK, and means no caching. */
2609
2610 if (size < 0)
2611 size = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002612
2613 daemon->cachesize = size;
2614 }
2615 break;
2616 }
2617
Simon Kelleyf2621c72007-04-29 19:47:21 +01002618 case 'p': /* --port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002619 if (!atoi_check16(arg, &daemon->port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002620 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002621 break;
Simon Kelley208b65c2006-08-05 21:41:37 +01002622
Simon Kelley1a6bca82008-07-11 11:11:42 +01002623 case LOPT_MINPORT: /* --min-port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002624 if (!atoi_check16(arg, &daemon->min_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002625 ret_err(gen_err);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002626 break;
2627
Hans Dedecker926332a2016-01-23 10:48:12 +00002628 case LOPT_MAXPORT: /* --max-port */
2629 if (!atoi_check16(arg, &daemon->max_port))
2630 ret_err(gen_err);
2631 break;
2632
Simon Kelleyf2621c72007-04-29 19:47:21 +01002633 case '0': /* --dns-forward-max */
Simon Kelley208b65c2006-08-05 21:41:37 +01002634 if (!atoi_check(arg, &daemon->ftabsize))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002635 ret_err(gen_err);
Simon Kelley208b65c2006-08-05 21:41:37 +01002636 break;
2637
Simon Kelley25cf5e32015-01-09 15:53:03 +00002638 case 'q': /* --log-queries */
2639 set_option_bool(OPT_LOG);
2640 if (arg && strcmp(arg, "extra") == 0)
2641 set_option_bool(OPT_EXTRALOG);
2642 break;
2643
Simon Kelleyf2621c72007-04-29 19:47:21 +01002644 case LOPT_MAX_LOGS: /* --log-async */
2645 daemon->max_logs = LOG_MAX; /* default */
2646 if (arg && !atoi_check(arg, &daemon->max_logs))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002647 ret_err(gen_err);
Simon Kelleyf2621c72007-04-29 19:47:21 +01002648 else if (daemon->max_logs > 100)
2649 daemon->max_logs = 100;
2650 break;
2651
2652 case 'P': /* --edns-packet-max */
Simon Kelley849a8352006-06-09 21:02:31 +01002653 {
2654 int i;
2655 if (!atoi_check(arg, &i))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002656 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002657 daemon->edns_pktsz = (unsigned short)i;
2658 break;
2659 }
2660
Simon Kelleyf2621c72007-04-29 19:47:21 +01002661 case 'Q': /* --query-port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002662 if (!atoi_check16(arg, &daemon->query_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002663 ret_err(gen_err);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002664 /* if explicitly set to zero, use single OS ephemeral port
2665 and disable random ports */
2666 if (daemon->query_port == 0)
2667 daemon->osport = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01002668 break;
2669
Simon Kelley824af852008-02-12 20:43:05 +00002670 case 'T': /* --local-ttl */
2671 case LOPT_NEGTTL: /* --neg-ttl */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002672 case LOPT_MAXTTL: /* --max-ttl */
RinSatsuki28de3872015-01-10 15:22:21 +00002673 case LOPT_MINCTTL: /* --min-cache-ttl */
Simon Kelley1d860412012-09-20 20:48:04 +01002674 case LOPT_MAXCTTL: /* --max-cache-ttl */
Simon Kelley4f7b3042012-11-28 21:27:02 +00002675 case LOPT_AUTHTTL: /* --auth-ttl */
Simon Kelley832e47b2016-02-24 21:24:45 +00002676 case LOPT_DHCPTTL: /* --dhcp-ttl */
Simon Kelley849a8352006-06-09 21:02:31 +01002677 {
2678 int ttl;
2679 if (!atoi_check(arg, &ttl))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002680 ret_err(gen_err);
Simon Kelley824af852008-02-12 20:43:05 +00002681 else if (option == LOPT_NEGTTL)
2682 daemon->neg_ttl = (unsigned long)ttl;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002683 else if (option == LOPT_MAXTTL)
2684 daemon->max_ttl = (unsigned long)ttl;
RinSatsuki28de3872015-01-10 15:22:21 +00002685 else if (option == LOPT_MINCTTL)
2686 {
2687 if (ttl > TTL_FLOOR_LIMIT)
2688 ttl = TTL_FLOOR_LIMIT;
2689 daemon->min_cache_ttl = (unsigned long)ttl;
2690 }
Simon Kelley1d860412012-09-20 20:48:04 +01002691 else if (option == LOPT_MAXCTTL)
2692 daemon->max_cache_ttl = (unsigned long)ttl;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002693 else if (option == LOPT_AUTHTTL)
2694 daemon->auth_ttl = (unsigned long)ttl;
Simon Kelley832e47b2016-02-24 21:24:45 +00002695 else if (option == LOPT_DHCPTTL)
2696 {
2697 daemon->dhcp_ttl = (unsigned long)ttl;
2698 daemon->use_dhcp_ttl = 1;
2699 }
Simon Kelley849a8352006-06-09 21:02:31 +01002700 else
2701 daemon->local_ttl = (unsigned long)ttl;
2702 break;
2703 }
2704
Simon Kelley7622fc02009-06-04 20:32:05 +01002705#ifdef HAVE_DHCP
Simon Kelleyf2621c72007-04-29 19:47:21 +01002706 case 'X': /* --dhcp-lease-max */
Simon Kelley849a8352006-06-09 21:02:31 +01002707 if (!atoi_check(arg, &daemon->dhcp_max))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002708 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002709 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01002710#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002711
Simon Kelley7622fc02009-06-04 20:32:05 +01002712#ifdef HAVE_TFTP
Simon Kelleyf2621c72007-04-29 19:47:21 +01002713 case LOPT_TFTP_MAX: /* --tftp-max */
Simon Kelley832af0b2007-01-21 20:01:28 +00002714 if (!atoi_check(arg, &daemon->tftp_max))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002715 ret_err(gen_err);
Simon Kelley832af0b2007-01-21 20:01:28 +00002716 break;
2717
Simon Kelleybec366b2016-02-24 22:03:26 +00002718 case LOPT_TFTP_MTU: /* --tftp-mtu */
2719 if (!atoi_check(arg, &daemon->tftp_mtu))
2720 ret_err(gen_err);
2721 break;
2722
Simon Kelley824af852008-02-12 20:43:05 +00002723 case LOPT_PREFIX: /* --tftp-prefix */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002724 comma = split(arg);
2725 if (comma)
2726 {
2727 struct tftp_prefix *new = opt_malloc(sizeof(struct tftp_prefix));
2728 new->interface = opt_string_alloc(comma);
2729 new->prefix = opt_string_alloc(arg);
2730 new->next = daemon->if_prefix;
2731 daemon->if_prefix = new;
2732 }
2733 else
2734 daemon->tftp_prefix = opt_string_alloc(arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00002735 break;
2736
Simon Kelley824af852008-02-12 20:43:05 +00002737 case LOPT_TFTPPORTS: /* --tftp-port-range */
2738 if (!(comma = split(arg)) ||
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002739 !atoi_check16(arg, &daemon->start_tftp_port) ||
2740 !atoi_check16(comma, &daemon->end_tftp_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002741 ret_err(_("bad port range"));
Simon Kelley824af852008-02-12 20:43:05 +00002742
2743 if (daemon->start_tftp_port > daemon->end_tftp_port)
2744 {
2745 int tmp = daemon->start_tftp_port;
2746 daemon->start_tftp_port = daemon->end_tftp_port;
2747 daemon->end_tftp_port = tmp;
2748 }
2749
2750 break;
Floris Bos60704f52017-04-09 22:22:49 +01002751
2752 case LOPT_APREF: /* --tftp-unique-root */
2753 if (!arg || strcasecmp(arg, "ip") == 0)
2754 set_option_bool(OPT_TFTP_APREF_IP);
2755 else if (strcasecmp(arg, "mac") == 0)
2756 set_option_bool(OPT_TFTP_APREF_MAC);
2757 else
2758 ret_err(gen_err);
2759 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01002760#endif
Simon Kelley824af852008-02-12 20:43:05 +00002761
Simon Kelleyf2621c72007-04-29 19:47:21 +01002762 case LOPT_BRIDGE: /* --bridge-interface */
Simon Kelley832af0b2007-01-21 20:01:28 +00002763 {
Simon Kelley22cd8602018-01-14 22:57:14 +00002764 struct dhcp_bridge *new;
2765
Simon Kelley316e2732010-01-22 20:16:09 +00002766 if (!(comma = split(arg)) || strlen(arg) > IF_NAMESIZE - 1 )
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002767 ret_err(_("bad bridge-interface"));
Simon Kelley832af0b2007-01-21 20:01:28 +00002768
Simon Kelley22cd8602018-01-14 22:57:14 +00002769 for (new = daemon->bridges; new; new = new->next)
2770 if (strcmp(new->iface, arg) == 0)
2771 break;
2772
2773 if (!new)
2774 {
2775 new = opt_malloc(sizeof(struct dhcp_bridge));
2776 strcpy(new->iface, arg);
2777 new->alias = NULL;
2778 new->next = daemon->bridges;
2779 daemon->bridges = new;
2780 }
2781
Simon Kelley832af0b2007-01-21 20:01:28 +00002782 do {
Simon Kelleyf2621c72007-04-29 19:47:21 +01002783 arg = comma;
2784 comma = split(arg);
Simon Kelley316e2732010-01-22 20:16:09 +00002785 if (strlen(arg) != 0 && strlen(arg) <= IF_NAMESIZE - 1)
Simon Kelley832af0b2007-01-21 20:01:28 +00002786 {
Simon Kelley824af852008-02-12 20:43:05 +00002787 struct dhcp_bridge *b = opt_malloc(sizeof(struct dhcp_bridge));
Simon Kelley832af0b2007-01-21 20:01:28 +00002788 b->next = new->alias;
2789 new->alias = b;
Simon Kelley316e2732010-01-22 20:16:09 +00002790 strcpy(b->iface, arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00002791 }
2792 } while (comma);
2793
2794 break;
2795 }
Simon Kelley832af0b2007-01-21 20:01:28 +00002796
Simon Kelley7622fc02009-06-04 20:32:05 +01002797#ifdef HAVE_DHCP
Simon Kelleyf2621c72007-04-29 19:47:21 +01002798 case 'F': /* --dhcp-range */
Simon Kelley849a8352006-06-09 21:02:31 +01002799 {
2800 int k, leasepos = 2;
Simon Kelley8445f5d2012-12-17 21:54:08 +00002801 char *cp, *a[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
Simon Kelley824af852008-02-12 20:43:05 +00002802 struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
Simon Kelley849a8352006-06-09 21:02:31 +01002803
Simon Kelley52b92f42012-01-22 16:05:15 +00002804 memset (new, 0, sizeof(*new));
Simon Kelley849a8352006-06-09 21:02:31 +01002805 new->lease_time = DEFLEASE;
Simon Kelley52b92f42012-01-22 16:05:15 +00002806
Simon Kelley849a8352006-06-09 21:02:31 +01002807 while(1)
2808 {
2809 for (cp = arg; *cp; cp++)
Simon Kelley52b92f42012-01-22 16:05:15 +00002810 if (!(*cp == ' ' || *cp == '.' || *cp == ':' ||
2811 (*cp >= 'a' && *cp <= 'f') || (*cp >= 'A' && *cp <= 'F') ||
2812 (*cp >='0' && *cp <= '9')))
Simon Kelley849a8352006-06-09 21:02:31 +01002813 break;
2814
Simon Kelleyf2621c72007-04-29 19:47:21 +01002815 if (*cp != ',' && (comma = split(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01002816 {
Simon Kelley8bc4cec2012-07-03 21:04:11 +01002817 if (is_tag_prefix(arg))
Simon Kelley849a8352006-06-09 21:02:31 +01002818 {
Simon Kelley824af852008-02-12 20:43:05 +00002819 struct dhcp_netid *tt = opt_malloc(sizeof (struct dhcp_netid));
2820 tt->net = opt_string_alloc(arg+4);
Simon Kelley849a8352006-06-09 21:02:31 +01002821 tt->next = new->filter;
Simon Kelley0c387192013-09-05 10:21:12 +01002822 /* ignore empty tag */
2823 if (tt->net)
2824 new->filter = tt;
Simon Kelley849a8352006-06-09 21:02:31 +01002825 }
2826 else
2827 {
2828 if (new->netid.net)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002829 ret_err(_("only one tag allowed"));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002830 else if (strstr(arg, "set:") == arg)
2831 new->netid.net = opt_string_alloc(arg+4);
Simon Kelley849a8352006-06-09 21:02:31 +01002832 else
Simon Kelley824af852008-02-12 20:43:05 +00002833 new->netid.net = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002834 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01002835 arg = comma;
Simon Kelley849a8352006-06-09 21:02:31 +01002836 }
2837 else
2838 {
2839 a[0] = arg;
2840 break;
2841 }
2842 }
2843
Simon Kelley1f776932012-12-16 19:46:08 +00002844 for (k = 1; k < 8; k++)
Simon Kelleyf2621c72007-04-29 19:47:21 +01002845 if (!(a[k] = split(a[k-1])))
2846 break;
Simon Kelley849a8352006-06-09 21:02:31 +01002847
Simon Kelley52b92f42012-01-22 16:05:15 +00002848 if (k < 2)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002849 ret_err(_("bad dhcp-range"));
2850
2851 if (inet_pton(AF_INET, a[0], &new->start))
Simon Kelley849a8352006-06-09 21:02:31 +01002852 {
Simon Kelley52b92f42012-01-22 16:05:15 +00002853 new->next = daemon->dhcp;
2854 daemon->dhcp = new;
Simon Kelley30cd9662012-03-25 20:44:38 +01002855 new->end = new->start;
Simon Kelley52b92f42012-01-22 16:05:15 +00002856 if (strcmp(a[1], "static") == 0)
Simon Kelley30cd9662012-03-25 20:44:38 +01002857 new->flags |= CONTEXT_STATIC;
Simon Kelley52b92f42012-01-22 16:05:15 +00002858 else if (strcmp(a[1], "proxy") == 0)
Simon Kelley30cd9662012-03-25 20:44:38 +01002859 new->flags |= CONTEXT_PROXY;
2860 else if (!inet_pton(AF_INET, a[1], &new->end))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002861 ret_err(_("bad dhcp-range"));
Simon Kelley52b92f42012-01-22 16:05:15 +00002862
2863 if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
2864 {
2865 struct in_addr tmp = new->start;
2866 new->start = new->end;
2867 new->end = tmp;
2868 }
2869
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002870 if (k >= 3 && strchr(a[2], '.') &&
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002871 (inet_pton(AF_INET, a[2], &new->netmask) > 0))
Simon Kelley52b92f42012-01-22 16:05:15 +00002872 {
2873 new->flags |= CONTEXT_NETMASK;
2874 leasepos = 3;
2875 if (!is_same_net(new->start, new->end, new->netmask))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002876 ret_err(_("inconsistent DHCP range"));
Simon Kelleyfa794662016-03-03 20:33:54 +00002877
Simon Kelley52b92f42012-01-22 16:05:15 +00002878
Simon Kelleyfa794662016-03-03 20:33:54 +00002879 if (k >= 4 && strchr(a[3], '.') &&
2880 (inet_pton(AF_INET, a[3], &new->broadcast) > 0))
2881 {
2882 new->flags |= CONTEXT_BRDCAST;
2883 leasepos = 4;
2884 }
Simon Kelley52b92f42012-01-22 16:05:15 +00002885 }
Simon Kelley849a8352006-06-09 21:02:31 +01002886 }
Simon Kelley52b92f42012-01-22 16:05:15 +00002887#ifdef HAVE_DHCP6
2888 else if (inet_pton(AF_INET6, a[0], &new->start6))
Simon Kelley7622fc02009-06-04 20:32:05 +01002889 {
Simon Kelley89500e32013-09-20 16:29:20 +01002890 new->flags |= CONTEXT_V6;
Simon Kelley52b92f42012-01-22 16:05:15 +00002891 new->prefix = 64; /* default */
Simon Kelley30cd9662012-03-25 20:44:38 +01002892 new->end6 = new->start6;
Simon Kelley6692a1a2013-08-20 14:41:31 +01002893 new->next = daemon->dhcp6;
2894 daemon->dhcp6 = new;
2895
Simon Kelley30cd9662012-03-25 20:44:38 +01002896 for (leasepos = 1; leasepos < k; leasepos++)
2897 {
2898 if (strcmp(a[leasepos], "static") == 0)
2899 new->flags |= CONTEXT_STATIC | CONTEXT_DHCP;
2900 else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 )
Simon Kelley7ea3d3f2014-04-25 22:04:05 +01002901 new->flags |= CONTEXT_RA;
Simon Kelley30cd9662012-03-25 20:44:38 +01002902 else if (strcmp(a[leasepos], "ra-names") == 0)
Simon Kelley1f776932012-12-16 19:46:08 +00002903 new->flags |= CONTEXT_RA_NAME | CONTEXT_RA;
Simon Kelley7ea3d3f2014-04-25 22:04:05 +01002904 else if (strcmp(a[leasepos], "ra-advrouter") == 0)
2905 new->flags |= CONTEXT_RA_ROUTER | CONTEXT_RA;
Simon Kelley30cd9662012-03-25 20:44:38 +01002906 else if (strcmp(a[leasepos], "ra-stateless") == 0)
Simon Kelley1f776932012-12-16 19:46:08 +00002907 new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA;
Neil Jerram2fd5bc92015-06-10 22:13:06 +01002908 else if (strcmp(a[leasepos], "off-link") == 0)
2909 new->flags |= CONTEXT_RA_OFF_LINK;
Simon Kelley30cd9662012-03-25 20:44:38 +01002910 else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6))
2911 new->flags |= CONTEXT_DHCP;
Simon Kelley1f776932012-12-16 19:46:08 +00002912 else if (strstr(a[leasepos], "constructor:") == a[leasepos])
2913 {
2914 new->template_interface = opt_string_alloc(a[leasepos] + 12);
2915 new->flags |= CONTEXT_TEMPLATE;
2916 }
Simon Kelley30cd9662012-03-25 20:44:38 +01002917 else
2918 break;
2919 }
Simon Kelley6692a1a2013-08-20 14:41:31 +01002920
Simon Kelley52b92f42012-01-22 16:05:15 +00002921 /* bare integer < 128 is prefix value */
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002922 if (leasepos < k)
Simon Kelley52b92f42012-01-22 16:05:15 +00002923 {
2924 int pref;
Simon Kelley30cd9662012-03-25 20:44:38 +01002925 for (cp = a[leasepos]; *cp; cp++)
Simon Kelley52b92f42012-01-22 16:05:15 +00002926 if (!(*cp >= '0' && *cp <= '9'))
2927 break;
Simon Kelley30cd9662012-03-25 20:44:38 +01002928 if (!*cp && (pref = atoi(a[leasepos])) <= 128)
Simon Kelley52b92f42012-01-22 16:05:15 +00002929 {
2930 new->prefix = pref;
Simon Kelley30cd9662012-03-25 20:44:38 +01002931 leasepos++;
Simon Kelley52b92f42012-01-22 16:05:15 +00002932 }
2933 }
Simon Kelley30cd9662012-03-25 20:44:38 +01002934
Simon Kelley6692a1a2013-08-20 14:41:31 +01002935 if (new->prefix != 64)
2936 {
Simon Kelley7ea3d3f2014-04-25 22:04:05 +01002937 if (new->flags & CONTEXT_RA)
Simon Kelley6692a1a2013-08-20 14:41:31 +01002938 ret_err(_("prefix length must be exactly 64 for RA subnets"));
2939 else if (new->flags & CONTEXT_TEMPLATE)
2940 ret_err(_("prefix length must be exactly 64 for subnet constructors"));
2941 }
2942
2943 if (new->prefix < 64)
2944 ret_err(_("prefix length must be at least 64"));
2945
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002946 if (!is_same_net6(&new->start6, &new->end6, new->prefix))
2947 ret_err(_("inconsistent DHCPv6 range"));
Simon Kelley6692a1a2013-08-20 14:41:31 +01002948
2949 /* dhcp-range=:: enables DHCP stateless on any interface */
2950 if (IN6_IS_ADDR_UNSPECIFIED(&new->start6) && !(new->flags & CONTEXT_TEMPLATE))
2951 new->prefix = 0;
Simon Kelley66409192013-08-01 20:19:32 +01002952
2953 if (new->flags & CONTEXT_TEMPLATE)
2954 {
2955 struct in6_addr zero;
2956 memset(&zero, 0, sizeof(zero));
2957 if (!is_same_net6(&zero, &new->start6, new->prefix))
2958 ret_err(_("prefix must be zero with \"constructor:\" argument"));
2959 }
2960
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002961 if (addr6part(&new->start6) > addr6part(&new->end6))
Simon Kelley52b92f42012-01-22 16:05:15 +00002962 {
2963 struct in6_addr tmp = new->start6;
2964 new->start6 = new->end6;
2965 new->end6 = tmp;
2966 }
Simon Kelley849a8352006-06-09 21:02:31 +01002967 }
Simon Kelley52b92f42012-01-22 16:05:15 +00002968#endif
Simon Kelleyd9ee9c02013-04-12 11:17:55 +01002969 else
2970 ret_err(_("bad dhcp-range"));
Simon Kelley849a8352006-06-09 21:02:31 +01002971
Simon Kelley30cd9662012-03-25 20:44:38 +01002972 if (leasepos < k)
Simon Kelley849a8352006-06-09 21:02:31 +01002973 {
Simon Kelleyfa794662016-03-03 20:33:54 +00002974 if (leasepos != k-1)
2975 ret_err(_("bad dhcp-range"));
2976
Simon Kelley849a8352006-06-09 21:02:31 +01002977 if (strcmp(a[leasepos], "infinite") == 0)
2978 new->lease_time = 0xffffffff;
Simon Kelleyc8257542012-03-28 21:15:41 +01002979 else if (strcmp(a[leasepos], "deprecated") == 0)
2980 new->flags |= CONTEXT_DEPRECATE;
Simon Kelley849a8352006-06-09 21:02:31 +01002981 else
2982 {
2983 int fac = 1;
2984 if (strlen(a[leasepos]) > 0)
2985 {
2986 switch (a[leasepos][strlen(a[leasepos]) - 1])
2987 {
Simon Kelley42243212012-07-20 15:19:18 +01002988 case 'w':
2989 case 'W':
2990 fac *= 7;
2991 /* fall through */
Simon Kelley849a8352006-06-09 21:02:31 +01002992 case 'd':
2993 case 'D':
2994 fac *= 24;
Simon Kelley87e00fe2018-02-16 21:27:35 +00002995 /* fall through */
Simon Kelley849a8352006-06-09 21:02:31 +01002996 case 'h':
2997 case 'H':
2998 fac *= 60;
2999 /* fall through */
3000 case 'm':
3001 case 'M':
3002 fac *= 60;
3003 /* fall through */
3004 case 's':
3005 case 'S':
Simon Kelleyf2621c72007-04-29 19:47:21 +01003006 a[leasepos][strlen(a[leasepos]) - 1] = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01003007 }
3008
Simon Kelleybe379862012-12-23 12:01:39 +00003009 for (cp = a[leasepos]; *cp; cp++)
3010 if (!(*cp >= '0' && *cp <= '9'))
3011 break;
3012
Simon Kelley54dae552013-02-05 17:55:10 +00003013 if (*cp || (leasepos+1 < k))
Simon Kelleybe379862012-12-23 12:01:39 +00003014 ret_err(_("bad dhcp-range"));
3015
Simon Kelley849a8352006-06-09 21:02:31 +01003016 new->lease_time = atoi(a[leasepos]) * fac;
3017 /* Leases of a minute or less confuse
3018 some clients, notably Apple's */
3019 if (new->lease_time < 120)
3020 new->lease_time = 120;
3021 }
3022 }
3023 }
3024 break;
3025 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01003026
Simon Kelley5aabfc72007-08-29 11:24:47 +01003027 case LOPT_BANK:
Simon Kelleyf2621c72007-04-29 19:47:21 +01003028 case 'G': /* --dhcp-host */
Simon Kelley849a8352006-06-09 21:02:31 +01003029 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01003030 int j, k = 0;
Simon Kelley3e8ed782013-05-29 14:31:33 +01003031 char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
Simon Kelley5aabfc72007-08-29 11:24:47 +01003032 struct dhcp_config *new;
Simon Kelley849a8352006-06-09 21:02:31 +01003033 struct in_addr in;
3034
Simon Kelley824af852008-02-12 20:43:05 +00003035 new = opt_malloc(sizeof(struct dhcp_config));
3036
Simon Kelley849a8352006-06-09 21:02:31 +01003037 new->next = daemon->dhcp_conf;
Simon Kelley9009d742008-11-14 20:04:27 +00003038 new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
3039 new->hwaddr = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003040 new->netid = NULL;
3041
Simon Kelley849a8352006-06-09 21:02:31 +01003042 if ((a[0] = arg))
Simon Kelley3e8ed782013-05-29 14:31:33 +01003043 for (k = 1; k < 7; k++)
Simon Kelleyf2621c72007-04-29 19:47:21 +01003044 if (!(a[k] = split(a[k-1])))
3045 break;
Simon Kelley849a8352006-06-09 21:02:31 +01003046
3047 for (j = 0; j < k; j++)
3048 if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
3049 {
3050 char *arg = a[j];
3051
3052 if ((arg[0] == 'i' || arg[0] == 'I') &&
3053 (arg[1] == 'd' || arg[1] == 'D') &&
3054 arg[2] == ':')
3055 {
3056 if (arg[3] == '*')
3057 new->flags |= CONFIG_NOCLID;
3058 else
3059 {
3060 int len;
3061 arg += 3; /* dump id: */
3062 if (strchr(arg, ':'))
3063 len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
3064 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01003065 {
3066 unhide_metas(arg);
3067 len = (int) strlen(arg);
3068 }
3069
Simon Kelley28866e92011-02-14 20:19:14 +00003070 if (len == -1)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003071 ret_err(_("bad hex constant"));
Simon Kelley28866e92011-02-14 20:19:14 +00003072 else if ((new->clid = opt_malloc(len)))
Simon Kelley5aabfc72007-08-29 11:24:47 +01003073 {
3074 new->flags |= CONFIG_CLID;
3075 new->clid_len = len;
3076 memcpy(new->clid, arg, len);
3077 }
Simon Kelley849a8352006-06-09 21:02:31 +01003078 }
3079 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003080 /* dhcp-host has strange backwards-compat needs. */
3081 else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg)
Simon Kelley849a8352006-06-09 21:02:31 +01003082 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003083 struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
3084 struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
3085 newtag->net = opt_malloc(strlen(arg + 4) + 1);
3086 newlist->next = new->netid;
3087 new->netid = newlist;
3088 newlist->list = newtag;
3089 strcpy(newtag->net, arg+4);
3090 unhide_metas(newtag->net);
Simon Kelley849a8352006-06-09 21:02:31 +01003091 }
Simon Kelley7de060b2011-08-26 17:24:52 +01003092 else if (strstr(arg, "tag:") == arg)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003093 ret_err(_("cannot match tags in --dhcp-host"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00003094#ifdef HAVE_DHCP6
3095 else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
3096 {
3097 arg[strlen(arg)-1] = 0;
3098 arg++;
3099
3100 if (!inet_pton(AF_INET6, arg, &new->addr6))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003101 ret_err(_("bad IPv6 address"));
Simon Kelley30393102013-01-17 16:34:16 +00003102
3103 for (i= 0; i < 8; i++)
3104 if (new->addr6.s6_addr[i] != 0)
3105 break;
3106
3107 /* set WILDCARD if network part all zeros */
3108 if (i == 8)
3109 new->flags |= CONFIG_WILDCARD;
Simon Kelley4cb1b322012-02-06 14:30:41 +00003110
3111 new->flags |= CONFIG_ADDR6;
3112 }
3113#endif
Simon Kelley7de060b2011-08-26 17:24:52 +01003114 else
Simon Kelley849a8352006-06-09 21:02:31 +01003115 {
Simon Kelley9009d742008-11-14 20:04:27 +00003116 struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
Simon Kelley28866e92011-02-14 20:19:14 +00003117 if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
3118 &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003119 ret_err(_("bad hex constant"));
Simon Kelley28866e92011-02-14 20:19:14 +00003120 else
3121 {
3122
3123 newhw->next = new->hwaddr;
3124 new->hwaddr = newhw;
3125 }
Simon Kelley849a8352006-06-09 21:02:31 +01003126 }
3127 }
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003128 else if (strchr(a[j], '.') && (inet_pton(AF_INET, a[j], &in) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01003129 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003130 struct dhcp_config *configs;
3131
Simon Kelley849a8352006-06-09 21:02:31 +01003132 new->addr = in;
3133 new->flags |= CONFIG_ADDR;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003134
3135 /* If the same IP appears in more than one host config, then DISCOVER
3136 for one of the hosts will get the address, but REQUEST will be NAKed,
3137 since the address is reserved by the other one -> protocol loop. */
3138 for (configs = daemon->dhcp_conf; configs; configs = configs->next)
3139 if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr)
3140 {
3141 sprintf(errstr, _("duplicate dhcp-host IP address %s"), inet_ntoa(in));
3142 return 0;
3143 }
Simon Kelley849a8352006-06-09 21:02:31 +01003144 }
3145 else
3146 {
3147 char *cp, *lastp = NULL, last = 0;
Simon Kelley76ff4402013-12-17 16:29:14 +00003148 int fac = 1, isdig = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01003149
3150 if (strlen(a[j]) > 1)
3151 {
3152 lastp = a[j] + strlen(a[j]) - 1;
3153 last = *lastp;
3154 switch (last)
3155 {
Simon Kelley42243212012-07-20 15:19:18 +01003156 case 'w':
3157 case 'W':
3158 fac *= 7;
3159 /* fall through */
Simon Kelley849a8352006-06-09 21:02:31 +01003160 case 'd':
3161 case 'D':
3162 fac *= 24;
3163 /* fall through */
3164 case 'h':
3165 case 'H':
3166 fac *= 60;
3167 /* fall through */
3168 case 'm':
3169 case 'M':
3170 fac *= 60;
3171 /* fall through */
3172 case 's':
3173 case 'S':
3174 *lastp = 0;
3175 }
3176 }
3177
3178 for (cp = a[j]; *cp; cp++)
Simon Kelley76ff4402013-12-17 16:29:14 +00003179 if (isdigit((unsigned char)*cp))
3180 isdig = 1;
3181 else if (*cp != ' ')
Simon Kelley849a8352006-06-09 21:02:31 +01003182 break;
Simon Kelley76ff4402013-12-17 16:29:14 +00003183
Simon Kelley849a8352006-06-09 21:02:31 +01003184 if (*cp)
3185 {
3186 if (lastp)
3187 *lastp = last;
3188 if (strcmp(a[j], "infinite") == 0)
3189 {
3190 new->lease_time = 0xffffffff;
3191 new->flags |= CONFIG_TIME;
3192 }
3193 else if (strcmp(a[j], "ignore") == 0)
3194 new->flags |= CONFIG_DISABLE;
3195 else
3196 {
Simon Kelley1f15b812009-10-13 17:49:32 +01003197 if (!(new->hostname = canonicalise_opt(a[j])) ||
3198 !legal_hostname(new->hostname))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003199 ret_err(_("bad DHCP host name"));
3200
3201 new->flags |= CONFIG_NAME;
3202 new->domain = strip_hostname(new->hostname);
Simon Kelley849a8352006-06-09 21:02:31 +01003203 }
3204 }
Simon Kelley76ff4402013-12-17 16:29:14 +00003205 else if (isdig)
Simon Kelley849a8352006-06-09 21:02:31 +01003206 {
3207 new->lease_time = atoi(a[j]) * fac;
3208 /* Leases of a minute or less confuse
3209 some clients, notably Apple's */
3210 if (new->lease_time < 120)
3211 new->lease_time = 120;
3212 new->flags |= CONFIG_TIME;
3213 }
3214 }
3215
Simon Kelley5aabfc72007-08-29 11:24:47 +01003216 daemon->dhcp_conf = new;
Simon Kelley849a8352006-06-09 21:02:31 +01003217 break;
3218 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003219
3220 case LOPT_TAG_IF: /* --tag-if */
3221 {
3222 struct tag_if *new = opt_malloc(sizeof(struct tag_if));
3223
3224 new->tag = NULL;
3225 new->set = NULL;
3226 new->next = NULL;
3227
3228 /* preserve order */
3229 if (!daemon->tag_if)
3230 daemon->tag_if = new;
3231 else
3232 {
3233 struct tag_if *tmp;
3234 for (tmp = daemon->tag_if; tmp->next; tmp = tmp->next);
3235 tmp->next = new;
3236 }
3237
3238 while (arg)
3239 {
3240 size_t len;
3241
3242 comma = split(arg);
3243 len = strlen(arg);
3244
3245 if (len < 5)
3246 {
3247 new->set = NULL;
3248 break;
3249 }
3250 else
3251 {
3252 struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
3253 newtag->net = opt_malloc(len - 3);
3254 strcpy(newtag->net, arg+4);
3255 unhide_metas(newtag->net);
3256
3257 if (strstr(arg, "set:") == arg)
3258 {
3259 struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
3260 newlist->next = new->set;
3261 new->set = newlist;
3262 newlist->list = newtag;
3263 }
3264 else if (strstr(arg, "tag:") == arg)
3265 {
3266 newtag->next = new->tag;
3267 new->tag = newtag;
3268 }
3269 else
3270 {
3271 new->set = NULL;
Simon Kelley4dc9c652013-02-04 21:43:52 +00003272 free(newtag);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003273 break;
3274 }
3275 }
3276
3277 arg = comma;
3278 }
3279
3280 if (!new->set)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003281 ret_err(_("bad tag-if"));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003282
3283 break;
3284 }
3285
Simon Kelley849a8352006-06-09 21:02:31 +01003286
Simon Kelley73a08a22009-02-05 20:28:08 +00003287 case 'O': /* --dhcp-option */
3288 case LOPT_FORCE: /* --dhcp-option-force */
Simon Kelley824af852008-02-12 20:43:05 +00003289 case LOPT_OPTS:
Simon Kelley73a08a22009-02-05 20:28:08 +00003290 case LOPT_MATCH: /* --dhcp-match */
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003291 return parse_dhcp_opt(errstr, arg,
3292 option == LOPT_FORCE ? DHOPT_FORCE :
3293 (option == LOPT_MATCH ? DHOPT_MATCH :
3294 (option == LOPT_OPTS ? DHOPT_BANK : 0)));
Simon Kelleyc8226202018-08-08 23:46:03 +01003295
3296 case LOPT_NAME_MATCH: /* --dhcp-name-match */
3297 {
3298 struct dhcp_match_name *new = opt_malloc(sizeof(struct dhcp_match_name));
3299 struct dhcp_netid *id = opt_malloc(sizeof(struct dhcp_netid));
3300 ssize_t len;
3301
3302 if (!(comma = split(arg)) || (len = strlen(comma)) == 0)
3303 ret_err(gen_err);
3304
3305 new->wildcard = 0;
3306 new->netid = id;
3307 id->net = opt_string_alloc(set_prefix(arg));
3308
3309 if (comma[len-1] == '*')
3310 {
3311 comma[len-1] = 0;
3312 new->wildcard = 1;
3313 }
3314 new->name = opt_string_alloc(comma);
3315
3316 new->next = daemon->dhcp_name_match;
3317 daemon->dhcp_name_match = new;
3318
3319 break;
3320 }
3321
Simon Kelleyf2621c72007-04-29 19:47:21 +01003322 case 'M': /* --dhcp-boot */
Simon Kelley849a8352006-06-09 21:02:31 +01003323 {
3324 struct dhcp_netid *id = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003325 while (is_tag_prefix(arg))
Simon Kelley849a8352006-06-09 21:02:31 +01003326 {
Simon Kelley824af852008-02-12 20:43:05 +00003327 struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
Simon Kelley849a8352006-06-09 21:02:31 +01003328 newid->next = id;
3329 id = newid;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003330 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00003331 newid->net = opt_string_alloc(arg+4);
Simon Kelley849a8352006-06-09 21:02:31 +01003332 arg = comma;
3333 };
3334
3335 if (!arg)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003336 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01003337 else
3338 {
Simon Kelley7de060b2011-08-26 17:24:52 +01003339 char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +01003340 struct in_addr dhcp_next_server;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003341 struct dhcp_boot *new;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003342 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00003343 dhcp_file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003344 dhcp_next_server.s_addr = 0;
3345 if (comma)
3346 {
3347 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003348 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00003349 dhcp_sname = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003350 if (comma)
3351 {
3352 unhide_metas(comma);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003353 if (!(inet_pton(AF_INET, comma, &dhcp_next_server) > 0))
3354 {
3355 /*
3356 * The user may have specified the tftp hostname here.
3357 * save it so that it can be resolved/looked up during
3358 * actual dhcp_reply().
3359 */
3360
3361 tftp_sname = opt_string_alloc(comma);
3362 dhcp_next_server.s_addr = 0;
3363 }
Simon Kelley849a8352006-06-09 21:02:31 +01003364 }
3365 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003366
3367 new = opt_malloc(sizeof(struct dhcp_boot));
3368 new->file = dhcp_file;
3369 new->sname = dhcp_sname;
3370 new->tftp_sname = tftp_sname;
3371 new->next_server = dhcp_next_server;
3372 new->netid = id;
3373 new->next = daemon->boot_config;
3374 daemon->boot_config = new;
Simon Kelley849a8352006-06-09 21:02:31 +01003375 }
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003376
Simon Kelley849a8352006-06-09 21:02:31 +01003377 break;
3378 }
Simon Kelley7622fc02009-06-04 20:32:05 +01003379
Floris Bos503c6092017-04-09 23:07:13 +01003380 case LOPT_REPLY_DELAY: /* --dhcp-reply-delay */
3381 {
3382 struct dhcp_netid *id = NULL;
3383 while (is_tag_prefix(arg))
3384 {
3385 struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
3386 newid->next = id;
3387 id = newid;
3388 comma = split(arg);
3389 newid->net = opt_string_alloc(arg+4);
3390 arg = comma;
3391 };
3392
3393 if (!arg)
3394 ret_err(gen_err);
3395 else
3396 {
3397 struct delay_config *new;
3398 int delay;
3399 if (!atoi_check(arg, &delay))
3400 ret_err(gen_err);
3401
3402 new = opt_malloc(sizeof(struct delay_config));
3403 new->delay = delay;
3404 new->netid = id;
3405 new->next = daemon->delay_conf;
3406 daemon->delay_conf = new;
3407 }
3408
3409 break;
3410 }
3411
Simon Kelley7622fc02009-06-04 20:32:05 +01003412 case LOPT_PXE_PROMT: /* --pxe-prompt */
3413 {
3414 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
3415 int timeout;
Floris Bos503c6092017-04-09 23:07:13 +01003416
Simon Kelley7622fc02009-06-04 20:32:05 +01003417 new->netid = NULL;
3418 new->opt = 10; /* PXE_MENU_PROMPT */
3419
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003420 while (is_tag_prefix(arg))
3421 {
Simon Kelley7622fc02009-06-04 20:32:05 +01003422 struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
3423 comma = split(arg);
3424 nn->next = new->netid;
3425 new->netid = nn;
3426 nn->net = opt_string_alloc(arg+4);
3427 arg = comma;
3428 }
3429
3430 if (!arg)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003431 ret_err(gen_err);
Simon Kelley7622fc02009-06-04 20:32:05 +01003432 else
3433 {
3434 comma = split(arg);
3435 unhide_metas(arg);
3436 new->len = strlen(arg) + 1;
3437 new->val = opt_malloc(new->len);
3438 memcpy(new->val + 1, arg, new->len - 1);
3439
3440 new->u.vendor_class = (unsigned char *)"PXEClient";
3441 new->flags = DHOPT_VENDOR;
3442
3443 if (comma && atoi_check(comma, &timeout))
3444 *(new->val) = timeout;
3445 else
3446 *(new->val) = 255;
3447
3448 new->next = daemon->dhcp_opts;
3449 daemon->dhcp_opts = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003450 daemon->enable_pxe = 1;
Simon Kelley7622fc02009-06-04 20:32:05 +01003451 }
3452
3453 break;
3454 }
3455
3456 case LOPT_PXE_SERV: /* --pxe-service */
3457 {
3458 struct pxe_service *new = opt_malloc(sizeof(struct pxe_service));
3459 char *CSA[] = { "x86PC", "PC98", "IA64_EFI", "Alpha", "Arc_x86", "Intel_Lean_Client",
Simon Kelley68bea102016-05-11 22:15:06 +01003460 "IA32_EFI", "x86-64_EFI", "Xscale_EFI", "BC_EFI",
3461 "ARM32_EFI", "ARM64_EFI", NULL };
Simon Kelley7622fc02009-06-04 20:32:05 +01003462 static int boottype = 32768;
3463
3464 new->netid = NULL;
Simon Kelley751d6f42012-02-10 15:24:51 +00003465 new->sname = NULL;
Simon Kelley7622fc02009-06-04 20:32:05 +01003466 new->server.s_addr = 0;
3467
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003468 while (is_tag_prefix(arg))
Simon Kelley7622fc02009-06-04 20:32:05 +01003469 {
3470 struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
3471 comma = split(arg);
3472 nn->next = new->netid;
3473 new->netid = nn;
3474 nn->net = opt_string_alloc(arg+4);
3475 arg = comma;
3476 }
3477
3478 if (arg && (comma = split(arg)))
3479 {
3480 for (i = 0; CSA[i]; i++)
3481 if (strcasecmp(CSA[i], arg) == 0)
3482 break;
3483
3484 if (CSA[i] || atoi_check(arg, &i))
3485 {
3486 arg = comma;
3487 comma = split(arg);
3488
3489 new->CSA = i;
3490 new->menu = opt_string_alloc(arg);
3491
Simon Kelley316e2732010-01-22 20:16:09 +00003492 if (!comma)
3493 {
3494 new->type = 0; /* local boot */
3495 new->basename = NULL;
3496 }
3497 else
Simon Kelley7622fc02009-06-04 20:32:05 +01003498 {
3499 arg = comma;
3500 comma = split(arg);
3501 if (atoi_check(arg, &i))
3502 {
3503 new->type = i;
3504 new->basename = NULL;
3505 }
3506 else
3507 {
3508 new->type = boottype++;
3509 new->basename = opt_string_alloc(arg);
3510 }
3511
Simon Kelley751d6f42012-02-10 15:24:51 +00003512 if (comma)
3513 {
3514 if (!inet_pton(AF_INET, comma, &new->server))
3515 {
3516 new->server.s_addr = 0;
3517 new->sname = opt_string_alloc(comma);
3518 }
3519
3520 }
Simon Kelley7622fc02009-06-04 20:32:05 +01003521 }
Simon Kelley751d6f42012-02-10 15:24:51 +00003522
Simon Kelley316e2732010-01-22 20:16:09 +00003523 /* Order matters */
3524 new->next = NULL;
3525 if (!daemon->pxe_services)
3526 daemon->pxe_services = new;
3527 else
3528 {
3529 struct pxe_service *s;
3530 for (s = daemon->pxe_services; s->next; s = s->next);
3531 s->next = new;
3532 }
3533
3534 daemon->enable_pxe = 1;
3535 break;
3536
Simon Kelley7622fc02009-06-04 20:32:05 +01003537 }
3538 }
3539
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003540 ret_err(gen_err);
Simon Kelley7622fc02009-06-04 20:32:05 +01003541 }
3542
Simon Kelleyf2621c72007-04-29 19:47:21 +01003543 case '4': /* --dhcp-mac */
Simon Kelley849a8352006-06-09 21:02:31 +01003544 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01003545 if (!(comma = split(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003546 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01003547 else
3548 {
Simon Kelley824af852008-02-12 20:43:05 +00003549 struct dhcp_mac *new = opt_malloc(sizeof(struct dhcp_mac));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003550 new->netid.net = opt_string_alloc(set_prefix(arg));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003551 unhide_metas(comma);
3552 new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
Simon Kelley28866e92011-02-14 20:19:14 +00003553 if (new->hwaddr_len == -1)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003554 ret_err(gen_err);
Simon Kelley28866e92011-02-14 20:19:14 +00003555 else
3556 {
3557 new->next = daemon->dhcp_macs;
3558 daemon->dhcp_macs = new;
3559 }
Simon Kelley849a8352006-06-09 21:02:31 +01003560 }
3561 }
3562 break;
Simon Kelleyc6309242013-03-07 20:59:28 +00003563
3564#ifdef OPTION6_PREFIX_CLASS
3565 case LOPT_PREF_CLSS: /* --dhcp-prefix-class */
3566 {
3567 struct prefix_class *new = opt_malloc(sizeof(struct prefix_class));
3568
3569 if (!(comma = split(arg)) ||
3570 !atoi_check16(comma, &new->class))
3571 ret_err(gen_err);
3572
3573 new->tag.net = opt_string_alloc(set_prefix(arg));
3574 new->next = daemon->prefix_classes;
3575 daemon->prefix_classes = new;
3576
3577 break;
3578 }
3579#endif
3580
3581
Simon Kelleyf2621c72007-04-29 19:47:21 +01003582 case 'U': /* --dhcp-vendorclass */
3583 case 'j': /* --dhcp-userclass */
3584 case LOPT_CIRCUIT: /* --dhcp-circuitid */
3585 case LOPT_REMOTE: /* --dhcp-remoteid */
3586 case LOPT_SUBSCR: /* --dhcp-subscrid */
Simon Kelley849a8352006-06-09 21:02:31 +01003587 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003588 unsigned char *p;
3589 int dig = 0;
3590 struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
3591
3592 if (!(comma = split(arg)))
3593 ret_err(gen_err);
3594
3595 new->netid.net = opt_string_alloc(set_prefix(arg));
3596 /* check for hex string - must digits may include : must not have nothing else,
3597 only allowed for agent-options. */
3598
3599 arg = comma;
3600 if ((comma = split(arg)))
3601 {
3602 if (option != 'U' || strstr(arg, "enterprise:") != arg)
3603 ret_err(gen_err);
3604 else
3605 new->enterprise = atoi(arg+11);
3606 }
3607 else
3608 comma = arg;
3609
3610 for (p = (unsigned char *)comma; *p; p++)
3611 if (isxdigit(*p))
3612 dig = 1;
3613 else if (*p != ':')
3614 break;
3615 unhide_metas(comma);
3616 if (option == 'U' || option == 'j' || *p || !dig)
3617 {
3618 new->len = strlen(comma);
3619 new->data = opt_malloc(new->len);
3620 memcpy(new->data, comma, new->len);
3621 }
3622 else
3623 {
3624 new->len = parse_hex(comma, (unsigned char *)comma, strlen(comma), NULL, NULL);
3625 new->data = opt_malloc(new->len);
3626 memcpy(new->data, comma, new->len);
3627 }
3628
3629 switch (option)
3630 {
3631 case 'j':
3632 new->match_type = MATCH_USER;
3633 break;
3634 case 'U':
3635 new->match_type = MATCH_VENDOR;
3636 break;
3637 case LOPT_CIRCUIT:
3638 new->match_type = MATCH_CIRCUIT;
3639 break;
3640 case LOPT_REMOTE:
3641 new->match_type = MATCH_REMOTE;
3642 break;
3643 case LOPT_SUBSCR:
3644 new->match_type = MATCH_SUBSCRIBER;
3645 break;
3646 }
3647 new->next = daemon->dhcp_vendors;
3648 daemon->dhcp_vendors = new;
Simon Kelleya5c72ab2012-02-10 13:42:47 +00003649
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003650 break;
Simon Kelley849a8352006-06-09 21:02:31 +01003651 }
3652
Simon Kelley9e038942008-05-30 20:06:34 +01003653 case LOPT_ALTPORT: /* --dhcp-alternate-port */
3654 if (!arg)
3655 {
3656 daemon->dhcp_server_port = DHCP_SERVER_ALTPORT;
3657 daemon->dhcp_client_port = DHCP_CLIENT_ALTPORT;
3658 }
3659 else
3660 {
3661 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01003662 if (!atoi_check16(arg, &daemon->dhcp_server_port) ||
3663 (comma && !atoi_check16(comma, &daemon->dhcp_client_port)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003664 ret_err(_("invalid port number"));
Simon Kelley9e038942008-05-30 20:06:34 +01003665 if (!comma)
3666 daemon->dhcp_client_port = daemon->dhcp_server_port+1;
3667 }
3668 break;
3669
Simon Kelley824af852008-02-12 20:43:05 +00003670 case 'J': /* --dhcp-ignore */
3671 case LOPT_NO_NAMES: /* --dhcp-ignore-names */
3672 case LOPT_BROADCAST: /* --dhcp-broadcast */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003673 case '3': /* --bootp-dynamic */
3674 case LOPT_GEN_NAMES: /* --dhcp-generate-names */
Simon Kelley849a8352006-06-09 21:02:31 +01003675 {
Simon Kelley824af852008-02-12 20:43:05 +00003676 struct dhcp_netid_list *new = opt_malloc(sizeof(struct dhcp_netid_list));
Simon Kelley849a8352006-06-09 21:02:31 +01003677 struct dhcp_netid *list = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00003678 if (option == 'J')
3679 {
3680 new->next = daemon->dhcp_ignore;
3681 daemon->dhcp_ignore = new;
3682 }
Simon Kelley824af852008-02-12 20:43:05 +00003683 else if (option == LOPT_BROADCAST)
3684 {
3685 new->next = daemon->force_broadcast;
3686 daemon->force_broadcast = new;
3687 }
Simon Kelley9009d742008-11-14 20:04:27 +00003688 else if (option == '3')
3689 {
3690 new->next = daemon->bootp_dynamic;
3691 daemon->bootp_dynamic = new;
3692 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003693 else if (option == LOPT_GEN_NAMES)
3694 {
3695 new->next = daemon->dhcp_gen_names;
3696 daemon->dhcp_gen_names = new;
3697 }
Simon Kelley832af0b2007-01-21 20:01:28 +00003698 else
3699 {
3700 new->next = daemon->dhcp_ignore_names;
3701 daemon->dhcp_ignore_names = new;
3702 }
3703
3704 while (arg) {
Simon Kelley824af852008-02-12 20:43:05 +00003705 struct dhcp_netid *member = opt_malloc(sizeof(struct dhcp_netid));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003706 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003707 member->next = list;
3708 list = member;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003709 if (is_tag_prefix(arg))
Simon Kelley9009d742008-11-14 20:04:27 +00003710 member->net = opt_string_alloc(arg+4);
3711 else
3712 member->net = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003713 arg = comma;
Simon Kelley832af0b2007-01-21 20:01:28 +00003714 }
Simon Kelley849a8352006-06-09 21:02:31 +01003715
3716 new->list = list;
3717 break;
3718 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003719
3720 case LOPT_PROXY: /* --dhcp-proxy */
3721 daemon->override = 1;
3722 while (arg) {
3723 struct addr_list *new = opt_malloc(sizeof(struct addr_list));
3724 comma = split(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003725 if (!(inet_pton(AF_INET, arg, &new->addr) > 0))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003726 ret_err(_("bad dhcp-proxy address"));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003727 new->next = daemon->override_relays;
3728 daemon->override_relays = new;
3729 arg = comma;
3730 }
3731 break;
Simon Kelleyff7eea22013-09-04 18:01:38 +01003732
3733 case LOPT_RELAY: /* --dhcp-relay */
3734 {
3735 struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
3736 comma = split(arg);
3737 new->interface = opt_string_alloc(split(comma));
3738 new->iface_index = 0;
3739 if (inet_pton(AF_INET, arg, &new->local) && inet_pton(AF_INET, comma, &new->server))
3740 {
3741 new->next = daemon->relay4;
3742 daemon->relay4 = new;
3743 }
3744#ifdef HAVE_DHCP6
3745 else if (inet_pton(AF_INET6, arg, &new->local) && inet_pton(AF_INET6, comma, &new->server))
3746 {
3747 new->next = daemon->relay6;
3748 daemon->relay6 = new;
3749 }
3750#endif
3751 else
3752 ret_err(_("Bad dhcp-relay"));
3753
3754 break;
3755 }
3756
Simon Kelley7622fc02009-06-04 20:32:05 +01003757#endif
Simon Kelley849a8352006-06-09 21:02:31 +01003758
Simon Kelley8b372702012-03-09 17:45:10 +00003759#ifdef HAVE_DHCP6
Simon Kelleyc4cd95d2013-10-10 20:58:11 +01003760 case LOPT_RA_PARAM: /* --ra-param */
3761 if ((comma = split(arg)))
3762 {
3763 struct ra_interface *new = opt_malloc(sizeof(struct ra_interface));
3764 new->lifetime = -1;
3765 new->prio = 0;
David Flamand005c46d2017-04-11 11:49:54 +01003766 new->mtu = 0;
Vladislav Grishenko6ec5f5c2017-04-24 22:34:45 +01003767 new->mtu_name = NULL;
Simon Kelleyc4cd95d2013-10-10 20:58:11 +01003768 new->name = opt_string_alloc(arg);
David Flamand005c46d2017-04-11 11:49:54 +01003769 if (strcasestr(comma, "mtu:") == comma)
3770 {
3771 arg = comma + 4;
3772 if (!(comma = split(comma)))
3773 goto err;
3774 if (!strcasecmp(arg, "off"))
3775 new->mtu = -1;
Vladislav Grishenko6ec5f5c2017-04-24 22:34:45 +01003776 else if (!atoi_check(arg, &new->mtu))
3777 new->mtu_name = opt_string_alloc(arg);
3778 else if (new->mtu < 1280)
David Flamand005c46d2017-04-11 11:49:54 +01003779 goto err;
3780 }
Simon Kelleyc4cd95d2013-10-10 20:58:11 +01003781 if (strcasestr(comma, "high") == comma || strcasestr(comma, "low") == comma)
3782 {
3783 if (*comma == 'l' || *comma == 'L')
3784 new->prio = 0x18;
3785 else
3786 new->prio = 0x08;
3787 comma = split(comma);
3788 }
3789 arg = split(comma);
3790 if (!atoi_check(comma, &new->interval) ||
3791 (arg && !atoi_check(arg, &new->lifetime)))
David Flamand005c46d2017-04-11 11:49:54 +01003792err:
Simon Kelleyc4cd95d2013-10-10 20:58:11 +01003793 ret_err(_("bad RA-params"));
3794
3795 new->next = daemon->ra_interfaces;
3796 daemon->ra_interfaces = new;
3797 }
3798 break;
3799
Simon Kelley8b372702012-03-09 17:45:10 +00003800 case LOPT_DUID: /* --dhcp-duid */
3801 if (!(comma = split(arg)) || !atoi_check(arg, (int *)&daemon->duid_enterprise))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003802 ret_err(_("bad DUID"));
Simon Kelley8b372702012-03-09 17:45:10 +00003803 else
3804 {
3805 daemon->duid_config_len = parse_hex(comma,(unsigned char *)comma, strlen(comma), NULL, NULL);
3806 daemon->duid_config = opt_malloc(daemon->duid_config_len);
3807 memcpy(daemon->duid_config, comma, daemon->duid_config_len);
3808 }
3809 break;
3810#endif
3811
Simon Kelleyf2621c72007-04-29 19:47:21 +01003812 case 'V': /* --alias */
Simon Kelley849a8352006-06-09 21:02:31 +01003813 {
Simon Kelley73a08a22009-02-05 20:28:08 +00003814 char *dash, *a[3] = { NULL, NULL, NULL };
Simon Kelleyf2621c72007-04-29 19:47:21 +01003815 int k = 0;
Simon Kelley73a08a22009-02-05 20:28:08 +00003816 struct doctor *new = opt_malloc(sizeof(struct doctor));
3817 new->next = daemon->doctors;
3818 daemon->doctors = new;
3819 new->mask.s_addr = 0xffffffff;
3820 new->end.s_addr = 0;
3821
Simon Kelley849a8352006-06-09 21:02:31 +01003822 if ((a[0] = arg))
3823 for (k = 1; k < 3; k++)
3824 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01003825 if (!(a[k] = split(a[k-1])))
Simon Kelley849a8352006-06-09 21:02:31 +01003826 break;
Simon Kelley849a8352006-06-09 21:02:31 +01003827 unhide_metas(a[k]);
3828 }
Simon Kelley849a8352006-06-09 21:02:31 +01003829
Simon Kelley73a08a22009-02-05 20:28:08 +00003830 dash = split_chr(a[0], '-');
3831
Simon Kelley849a8352006-06-09 21:02:31 +01003832 if ((k < 2) ||
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003833 (!(inet_pton(AF_INET, a[0], &new->in) > 0)) ||
Simon Kelleya3bd7e72018-07-19 22:00:08 +01003834 (!(inet_pton(AF_INET, a[1], &new->out) > 0)) ||
3835 (k == 3 && !inet_pton(AF_INET, a[2], &new->mask)))
3836 ret_err(_("missing address in alias"));
Simon Kelley849a8352006-06-09 21:02:31 +01003837
Simon Kelley73a08a22009-02-05 20:28:08 +00003838 if (dash &&
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003839 (!(inet_pton(AF_INET, dash, &new->end) > 0) ||
Simon Kelley73a08a22009-02-05 20:28:08 +00003840 !is_same_net(new->in, new->end, new->mask) ||
3841 ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003842 ret_err(_("invalid alias range"));
Simon Kelley849a8352006-06-09 21:02:31 +01003843
3844 break;
3845 }
3846
Simon Kelleyf2621c72007-04-29 19:47:21 +01003847 case LOPT_INTNAME: /* --interface-name */
3848 {
3849 struct interface_name *new, **up;
Simon Kelley1f15b812009-10-13 17:49:32 +01003850 char *domain = NULL;
3851
Simon Kelleyf2621c72007-04-29 19:47:21 +01003852 comma = split(arg);
3853
Simon Kelley1f15b812009-10-13 17:49:32 +01003854 if (!comma || !(domain = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003855 ret_err(_("bad interface name"));
Simon Kelley1f15b812009-10-13 17:49:32 +01003856
Simon Kelley824af852008-02-12 20:43:05 +00003857 new = opt_malloc(sizeof(struct interface_name));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003858 new->next = NULL;
Simon Kelley376d48c2013-11-13 13:04:30 +00003859 new->addr = NULL;
3860
Simon Kelleyf2621c72007-04-29 19:47:21 +01003861 /* Add to the end of the list, so that first name
3862 of an interface is used for PTR lookups. */
Simon Kelley824af852008-02-12 20:43:05 +00003863 for (up = &daemon->int_names; *up; up = &((*up)->next));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003864 *up = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003865 new->name = domain;
Simon Kelleyf7029f52013-11-21 15:09:09 +00003866 new->family = 0;
3867 arg = split_chr(comma, '/');
3868 if (arg)
3869 {
3870 if (strcmp(arg, "4") == 0)
3871 new->family = AF_INET;
3872#ifdef HAVE_IPV6
3873 else if (strcmp(arg, "6") == 0)
3874 new->family = AF_INET6;
3875#endif
3876 else
3877 ret_err(gen_err);
3878 }
Simon Kelley824af852008-02-12 20:43:05 +00003879 new->intr = opt_string_alloc(comma);
Simon Kelleyf2621c72007-04-29 19:47:21 +01003880 break;
3881 }
Simon Kelley9009d742008-11-14 20:04:27 +00003882
3883 case LOPT_CNAME: /* --cname */
3884 {
3885 struct cname *new;
Simon Kelleya1d973f2016-12-22 22:09:50 +00003886 char *alias, *target, *last, *pen;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00003887 int ttl = -1;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003888
Simon Kelleya1d973f2016-12-22 22:09:50 +00003889 for (last = pen = NULL, comma = arg; comma; comma = split(comma))
Simon Kelley9009d742008-11-14 20:04:27 +00003890 {
Simon Kelleya1d973f2016-12-22 22:09:50 +00003891 pen = last;
3892 last = comma;
3893 }
3894
3895 if (!pen)
3896 ret_err(_("bad CNAME"));
3897
3898 if (pen != arg && atoi_check(last, &ttl))
3899 last = pen;
3900
3901 target = canonicalise_opt(last);
3902
3903 while (arg != last)
3904 {
Petr Menšík56f06232018-03-06 23:13:32 +00003905 int arglen = strlen(arg);
Simon Kelleya1d973f2016-12-22 22:09:50 +00003906 alias = canonicalise_opt(arg);
Simon Kelley56144132017-05-03 22:54:09 +01003907
3908 if (!alias || !target)
3909 ret_err(_("bad CNAME"));
Simon Kelleya1d973f2016-12-22 22:09:50 +00003910
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003911 for (new = daemon->cnames; new; new = new->next)
Simon Kelley56144132017-05-03 22:54:09 +01003912 if (hostname_isequal(new->alias, alias))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003913 ret_err(_("duplicate CNAME"));
3914 new = opt_malloc(sizeof(struct cname));
3915 new->next = daemon->cnames;
3916 daemon->cnames = new;
3917 new->alias = alias;
3918 new->target = target;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00003919 new->ttl = ttl;
Simon Kelleya1d973f2016-12-22 22:09:50 +00003920
Petr Menšík56f06232018-03-06 23:13:32 +00003921 for (arg += arglen+1; *arg && isspace(*arg); arg++);
Simon Kelley9009d742008-11-14 20:04:27 +00003922 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003923
Simon Kelley9009d742008-11-14 20:04:27 +00003924 break;
3925 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01003926
3927 case LOPT_PTR: /* --ptr-record */
Simon Kelley832af0b2007-01-21 20:01:28 +00003928 {
3929 struct ptr_record *new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003930 char *dom, *target = NULL;
3931
Simon Kelleyf2621c72007-04-29 19:47:21 +01003932 comma = split(arg);
3933
Simon Kelley1f15b812009-10-13 17:49:32 +01003934 if (!(dom = canonicalise_opt(arg)) ||
3935 (comma && !(target = canonicalise_opt(comma))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003936 ret_err(_("bad PTR record"));
Simon Kelley1f15b812009-10-13 17:49:32 +01003937 else
3938 {
3939 new = opt_malloc(sizeof(struct ptr_record));
3940 new->next = daemon->ptr;
3941 daemon->ptr = new;
3942 new->name = dom;
3943 new->ptr = target;
3944 }
Simon Kelley832af0b2007-01-21 20:01:28 +00003945 break;
3946 }
3947
Simon Kelley1a6bca82008-07-11 11:11:42 +01003948 case LOPT_NAPTR: /* --naptr-record */
3949 {
3950 char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
3951 int k = 0;
3952 struct naptr *new;
3953 int order, pref;
Simon Kelley1f15b812009-10-13 17:49:32 +01003954 char *name, *replace = NULL;
Simon Kelley1a6bca82008-07-11 11:11:42 +01003955
3956 if ((a[0] = arg))
3957 for (k = 1; k < 7; k++)
3958 if (!(a[k] = split(a[k-1])))
3959 break;
3960
3961
3962 if (k < 6 ||
Simon Kelley1f15b812009-10-13 17:49:32 +01003963 !(name = canonicalise_opt(a[0])) ||
Simon Kelley1ad24ae2008-07-20 20:22:50 +01003964 !atoi_check16(a[1], &order) ||
3965 !atoi_check16(a[2], &pref) ||
Simon Kelley1f15b812009-10-13 17:49:32 +01003966 (k == 7 && !(replace = canonicalise_opt(a[6]))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003967 ret_err(_("bad NAPTR record"));
Simon Kelley1a6bca82008-07-11 11:11:42 +01003968 else
3969 {
3970 new = opt_malloc(sizeof(struct naptr));
3971 new->next = daemon->naptr;
3972 daemon->naptr = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003973 new->name = name;
Simon Kelley1a6bca82008-07-11 11:11:42 +01003974 new->flags = opt_string_alloc(a[3]);
3975 new->services = opt_string_alloc(a[4]);
3976 new->regexp = opt_string_alloc(a[5]);
Simon Kelley1f15b812009-10-13 17:49:32 +01003977 new->replace = replace;
Simon Kelley1a6bca82008-07-11 11:11:42 +01003978 new->order = order;
3979 new->pref = pref;
3980 }
3981 break;
3982 }
Simon Kelley9f7f3b12012-05-28 21:39:57 +01003983
3984 case LOPT_RR: /* dns-rr */
3985 {
3986 struct txt_record *new;
Simon Kelley4caa86d2016-03-16 18:44:16 +00003987 size_t len = 0;
Simon Kelley9f7f3b12012-05-28 21:39:57 +01003988 char *data;
3989 int val;
3990
3991 comma = split(arg);
3992 data = split(comma);
3993
3994 new = opt_malloc(sizeof(struct txt_record));
3995 new->next = daemon->rr;
3996 daemon->rr = new;
3997
3998 if (!atoi_check(comma, &val) ||
3999 !(new->name = canonicalise_opt(arg)) ||
Simon Kelley51931b82012-05-29 17:06:02 +01004000 (data && (len = parse_hex(data, (unsigned char *)data, -1, NULL, NULL)) == -1U))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004001 ret_err(_("bad RR record"));
4002
Simon Kelley9f7f3b12012-05-28 21:39:57 +01004003 new->class = val;
4004 new->len = 0;
4005
4006 if (data)
4007 {
Simon Kelley974a6d02018-08-23 23:01:16 +01004008 new->txt = opt_malloc(len);
Simon Kelley9f7f3b12012-05-28 21:39:57 +01004009 new->len = len;
4010 memcpy(new->txt, data, len);
4011 }
4012
4013 break;
4014 }
4015
Simon Kelley974a6d02018-08-23 23:01:16 +01004016 case LOPT_CAA: /* --caa-record */
4017 {
4018 struct txt_record *new;
4019 char *tag, *value;
4020 int flags;
4021
4022 comma = split(arg);
4023 tag = split(comma);
4024 value = split(tag);
4025
4026 new = opt_malloc(sizeof(struct txt_record));
4027 new->next = daemon->rr;
4028 daemon->rr = new;
4029
4030 if (!atoi_check(comma, &flags) || !tag || !value || !(new->name = canonicalise_opt(arg)))
4031 ret_err(_("bad CAA record"));
4032
4033 unhide_metas(tag);
4034 unhide_metas(value);
4035
4036 new->len = strlen(tag) + strlen(value) + 2;
4037 new->txt = opt_malloc(new->len);
4038 new->txt[0] = flags;
4039 new->txt[1] = strlen(tag);
4040 memcpy(&new->txt[2], tag, strlen(tag));
4041 memcpy(&new->txt[2 + strlen(tag)], value, strlen(value));
4042 new->class = T_CAA;
4043
4044 break;
4045 }
4046
Simon Kelleyf2621c72007-04-29 19:47:21 +01004047 case 'Y': /* --txt-record */
Simon Kelley849a8352006-06-09 21:02:31 +01004048 {
4049 struct txt_record *new;
Simon Kelley28866e92011-02-14 20:19:14 +00004050 unsigned char *p, *cnt;
4051 size_t len;
4052
4053 comma = split(arg);
4054
Simon Kelley824af852008-02-12 20:43:05 +00004055 new = opt_malloc(sizeof(struct txt_record));
Simon Kelley849a8352006-06-09 21:02:31 +01004056 new->next = daemon->txt;
4057 daemon->txt = new;
4058 new->class = C_IN;
Simon Kelleyfec216d2014-03-27 20:54:34 +00004059 new->stat = 0;
4060
Simon Kelley1f15b812009-10-13 17:49:32 +01004061 if (!(new->name = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004062 ret_err(_("bad TXT record"));
4063
Simon Kelley28866e92011-02-14 20:19:14 +00004064 len = comma ? strlen(comma) : 0;
4065 len += (len/255) + 1; /* room for extra counts */
4066 new->txt = p = opt_malloc(len);
4067
4068 cnt = p++;
4069 *cnt = 0;
4070
4071 while (comma && *comma)
4072 {
4073 unsigned char c = (unsigned char)*comma++;
4074
4075 if (c == ',' || *cnt == 255)
4076 {
4077 if (c != ',')
4078 comma--;
4079 cnt = p++;
4080 *cnt = 0;
4081 }
4082 else
4083 {
4084 *p++ = unhide_meta(c);
4085 (*cnt)++;
4086 }
4087 }
4088
4089 new->len = p - new->txt;
4090
Simon Kelley849a8352006-06-09 21:02:31 +01004091 break;
4092 }
4093
Simon Kelleyf2621c72007-04-29 19:47:21 +01004094 case 'W': /* --srv-host */
Simon Kelley849a8352006-06-09 21:02:31 +01004095 {
4096 int port = 1, priority = 0, weight = 0;
4097 char *name, *target = NULL;
4098 struct mx_srv_record *new;
4099
Simon Kelleyf2621c72007-04-29 19:47:21 +01004100 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01004101
Simon Kelley1f15b812009-10-13 17:49:32 +01004102 if (!(name = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004103 ret_err(_("bad SRV record"));
4104
Simon Kelley849a8352006-06-09 21:02:31 +01004105 if (comma)
4106 {
4107 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01004108 comma = split(arg);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004109 if (!(target = canonicalise_opt(arg)))
4110 ret_err(_("bad SRV target"));
Simon Kelley824af852008-02-12 20:43:05 +00004111
Simon Kelley849a8352006-06-09 21:02:31 +01004112 if (comma)
4113 {
4114 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01004115 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01004116 if (!atoi_check16(arg, &port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004117 ret_err(_("invalid port number"));
Simon Kelley824af852008-02-12 20:43:05 +00004118
Simon Kelley849a8352006-06-09 21:02:31 +01004119 if (comma)
4120 {
4121 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01004122 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01004123 if (!atoi_check16(arg, &priority))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004124 ret_err(_("invalid priority"));
Simon Kelley824af852008-02-12 20:43:05 +00004125
Simon Kelley407a1f32016-03-01 17:06:07 +00004126 if (comma && !atoi_check16(comma, &weight))
4127 ret_err(_("invalid weight"));
Simon Kelley849a8352006-06-09 21:02:31 +01004128 }
4129 }
4130 }
4131
Simon Kelley824af852008-02-12 20:43:05 +00004132 new = opt_malloc(sizeof(struct mx_srv_record));
Simon Kelley849a8352006-06-09 21:02:31 +01004133 new->next = daemon->mxnames;
4134 daemon->mxnames = new;
4135 new->issrv = 1;
4136 new->name = name;
4137 new->target = target;
4138 new->srvport = port;
4139 new->priority = priority;
4140 new->weight = weight;
4141 break;
4142 }
Simon Kelley7622fc02009-06-04 20:32:05 +01004143
Simon Kelleye759d422012-03-16 13:18:57 +00004144 case LOPT_HOST_REC: /* --host-record */
4145 {
4146 struct host_record *new = opt_malloc(sizeof(struct host_record));
4147 memset(new, 0, sizeof(struct host_record));
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004148 new->ttl = -1;
4149
Simon Kelleye759d422012-03-16 13:18:57 +00004150 if (!arg || !(comma = split(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004151 ret_err(_("Bad host-record"));
4152
4153 while (arg)
4154 {
4155 struct all_addr addr;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004156 char *dig;
4157
4158 for (dig = arg; *dig != 0; dig++)
4159 if (*dig < '0' || *dig > '9')
4160 break;
4161 if (*dig == 0)
4162 new->ttl = atoi(arg);
4163 else if (inet_pton(AF_INET, arg, &addr))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004164 new->addr = addr.addr.addr4;
Simon Kelleye759d422012-03-16 13:18:57 +00004165#ifdef HAVE_IPV6
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004166 else if (inet_pton(AF_INET6, arg, &addr))
4167 new->addr6 = addr.addr.addr6;
Simon Kelleye759d422012-03-16 13:18:57 +00004168#endif
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004169 else
4170 {
4171 int nomem;
4172 char *canon = canonicalise(arg, &nomem);
4173 struct name_list *nl = opt_malloc(sizeof(struct name_list));
4174 if (!canon)
4175 ret_err(_("Bad name in host-record"));
4176
4177 nl->name = canon;
4178 /* keep order, so that PTR record goes to first name */
4179 nl->next = NULL;
4180 if (!new->names)
4181 new->names = nl;
4182 else
4183 {
4184 struct name_list *tmp;
4185 for (tmp = new->names; tmp->next; tmp = tmp->next);
4186 tmp->next = nl;
4187 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004188 }
Simon Kelleye4807d82012-09-27 21:52:26 +01004189
4190 arg = comma;
4191 comma = split(arg);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004192 }
Simon Kelleye759d422012-03-16 13:18:57 +00004193
4194 /* Keep list order */
4195 if (!daemon->host_records_tail)
4196 daemon->host_records = new;
4197 else
4198 daemon->host_records_tail->next = new;
4199 new->next = NULL;
4200 daemon->host_records_tail = new;
4201 break;
4202 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00004203
4204#ifdef HAVE_DNSSEC
Simon Kelleyf3e57872018-07-20 21:10:48 +01004205 case LOPT_DNSSEC_STAMP: /* --dnssec-timestamp */
Simon Kelleyf6e62e22015-03-01 18:17:54 +00004206 daemon->timestamp_file = opt_string_alloc(arg);
4207 break;
4208
Simon Kelleyf3e57872018-07-20 21:10:48 +01004209 case LOPT_DNSSEC_CHECK: /* --dnssec-check-unsigned */
Simon Kelleya6918532018-04-15 16:20:52 +01004210 if (arg)
4211 {
4212 if (strcmp(arg, "no") == 0)
4213 set_option_bool(OPT_DNSSEC_IGN_NS);
4214 else
4215 ret_err(_("bad value for dnssec-check-unsigned"));
4216 }
4217 break;
4218
Simon Kelleyf3e57872018-07-20 21:10:48 +01004219 case LOPT_TRUST_ANCHOR: /* --trust-anchor */
Simon Kelley0fc2f312014-01-08 10:26:58 +00004220 {
Simon Kelleyee415862014-02-11 11:07:22 +00004221 struct ds_config *new = opt_malloc(sizeof(struct ds_config));
4222 char *cp, *cp1, *keyhex, *digest, *algo = NULL;
4223 int len;
Simon Kelleycbf13a22014-01-25 17:59:14 +00004224
4225 new->class = C_IN;
Simon Kelley0fc2f312014-01-08 10:26:58 +00004226
Simon Kelleycbf13a22014-01-25 17:59:14 +00004227 if ((comma = split(arg)) && (algo = split(comma)))
4228 {
4229 int class = 0;
4230 if (strcmp(comma, "IN") == 0)
4231 class = C_IN;
4232 else if (strcmp(comma, "CH") == 0)
4233 class = C_CHAOS;
4234 else if (strcmp(comma, "HS") == 0)
4235 class = C_HESIOD;
4236
4237 if (class != 0)
4238 {
4239 new->class = class;
4240 comma = algo;
4241 algo = split(comma);
4242 }
4243 }
4244
Simon Kelleyee415862014-02-11 11:07:22 +00004245 if (!comma || !algo || !(digest = split(algo)) || !(keyhex = split(digest)) ||
4246 !atoi_check16(comma, &new->keytag) ||
4247 !atoi_check8(algo, &new->algo) ||
4248 !atoi_check8(digest, &new->digest_type) ||
Simon Kelleycbf13a22014-01-25 17:59:14 +00004249 !(new->name = canonicalise_opt(arg)))
Simon Kelleyee415862014-02-11 11:07:22 +00004250 ret_err(_("bad trust anchor"));
Simon Kelleycbf13a22014-01-25 17:59:14 +00004251
Simon Kelley0fc2f312014-01-08 10:26:58 +00004252 /* Upper bound on length */
Simon Kelleyee415862014-02-11 11:07:22 +00004253 len = (2*strlen(keyhex))+1;
4254 new->digest = opt_malloc(len);
4255 unhide_metas(keyhex);
4256 /* 4034: "Whitespace is allowed within digits" */
4257 for (cp = keyhex; *cp; )
4258 if (isspace(*cp))
4259 for (cp1 = cp; *cp1; cp1++)
4260 *cp1 = *(cp1+1);
4261 else
4262 cp++;
4263 if ((new->digestlen = parse_hex(keyhex, (unsigned char *)new->digest, len, NULL, NULL)) == -1)
4264 ret_err(_("bad HEX in trust anchor"));
Simon Kelley0fc2f312014-01-08 10:26:58 +00004265
Simon Kelleyee415862014-02-11 11:07:22 +00004266 new->next = daemon->ds;
4267 daemon->ds = new;
4268
Simon Kelley0fc2f312014-01-08 10:26:58 +00004269 break;
4270 }
4271#endif
4272
Simon Kelley7622fc02009-06-04 20:32:05 +01004273 default:
Simon Kelley0fc2f312014-01-08 10:26:58 +00004274 ret_err(_("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"));
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004275
Simon Kelley849a8352006-06-09 21:02:31 +01004276 }
Simon Kelley824af852008-02-12 20:43:05 +00004277
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004278 return 1;
Simon Kelley849a8352006-06-09 21:02:31 +01004279}
4280
Simon Kelley28866e92011-02-14 20:19:14 +00004281static void read_file(char *file, FILE *f, int hard_opt)
Simon Kelley849a8352006-06-09 21:02:31 +01004282{
Simon Kelley824af852008-02-12 20:43:05 +00004283 volatile int lineno = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004284 char *buff = daemon->namebuff;
Simon Kelley849a8352006-06-09 21:02:31 +01004285
4286 while (fgets(buff, MAXDNAME, f))
4287 {
Simon Kelley7b1eae42014-02-20 13:43:28 +00004288 int white, i;
4289 volatile int option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt;
Simon Kelley13dee6f2017-02-28 16:51:58 +00004290 char *errmess, *p, *arg, *start;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004291 size_t len;
Simon Kelley832af0b2007-01-21 20:01:28 +00004292
Simon Kelley824af852008-02-12 20:43:05 +00004293 /* Memory allocation failure longjmps here if mem_recover == 1 */
Simon Kelley7b1eae42014-02-20 13:43:28 +00004294 if (option != 0 || hard_opt == LOPT_REV_SERV)
Simon Kelley824af852008-02-12 20:43:05 +00004295 {
4296 if (setjmp(mem_jmp))
4297 continue;
4298 mem_recover = 1;
4299 }
4300
Simon Kelley13dee6f2017-02-28 16:51:58 +00004301 arg = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +01004302 lineno++;
Simon Kelley824af852008-02-12 20:43:05 +00004303 errmess = NULL;
4304
Simon Kelley849a8352006-06-09 21:02:31 +01004305 /* Implement quotes, inside quotes we allow \\ \" \n and \t
4306 metacharacters get hidden also strip comments */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004307 for (white = 1, p = buff; *p; p++)
Simon Kelley849a8352006-06-09 21:02:31 +01004308 {
4309 if (*p == '"')
4310 {
4311 memmove(p, p+1, strlen(p+1)+1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004312
Simon Kelley849a8352006-06-09 21:02:31 +01004313 for(; *p && *p != '"'; p++)
4314 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01004315 if (*p == '\\' && strchr("\"tnebr\\", p[1]))
Simon Kelley849a8352006-06-09 21:02:31 +01004316 {
4317 if (p[1] == 't')
4318 p[1] = '\t';
4319 else if (p[1] == 'n')
4320 p[1] = '\n';
Simon Kelley849a8352006-06-09 21:02:31 +01004321 else if (p[1] == 'b')
4322 p[1] = '\b';
4323 else if (p[1] == 'r')
4324 p[1] = '\r';
Simon Kelley6b010842007-02-12 20:32:07 +00004325 else if (p[1] == 'e') /* escape */
4326 p[1] = '\033';
Simon Kelley849a8352006-06-09 21:02:31 +01004327 memmove(p, p+1, strlen(p+1)+1);
4328 }
4329 *p = hide_meta(*p);
4330 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004331
4332 if (*p == 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +01004333 {
4334 errmess = _("missing \"");
4335 goto oops;
4336 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004337
4338 memmove(p, p+1, strlen(p+1)+1);
Simon Kelley849a8352006-06-09 21:02:31 +01004339 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01004340
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004341 if (isspace(*p))
4342 {
4343 *p = ' ';
4344 white = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01004345 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004346 else
4347 {
4348 if (white && *p == '#')
4349 {
4350 *p = 0;
4351 break;
4352 }
4353 white = 0;
4354 }
Simon Kelley849a8352006-06-09 21:02:31 +01004355 }
4356
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004357
4358 /* strip leading spaces */
4359 for (start = buff; *start && *start == ' '; start++);
4360
4361 /* strip trailing spaces */
4362 for (len = strlen(start); (len != 0) && (start[len-1] == ' '); len--);
4363
4364 if (len == 0)
Simon Kelley849a8352006-06-09 21:02:31 +01004365 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004366 else
4367 start[len] = 0;
4368
Simon Kelley611ebc52012-07-16 16:23:46 +01004369 if (option != 0)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004370 arg = start;
4371 else if ((p=strchr(start, '=')))
Simon Kelley849a8352006-06-09 21:02:31 +01004372 {
4373 /* allow spaces around "=" */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004374 for (arg = p+1; *arg == ' '; arg++);
4375 for (; p >= start && (*p == ' ' || *p == '='); p--)
Simon Kelley849a8352006-06-09 21:02:31 +01004376 *p = 0;
4377 }
4378 else
4379 arg = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00004380
Simon Kelley611ebc52012-07-16 16:23:46 +01004381 if (option == 0)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004382 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01004383 for (option = 0, i = 0; opts[i].name; i++)
4384 if (strcmp(opts[i].name, start) == 0)
4385 {
4386 option = opts[i].val;
4387 break;
4388 }
4389
4390 if (!option)
4391 errmess = _("bad option");
4392 else if (opts[i].has_arg == 0 && arg)
4393 errmess = _("extraneous parameter");
4394 else if (opts[i].has_arg == 1 && !arg)
4395 errmess = _("missing parameter");
Simon Kelley7b1eae42014-02-20 13:43:28 +00004396 else if (hard_opt == LOPT_REV_SERV && option != 'S' && option != LOPT_REV_SERV)
4397 errmess = _("illegal option");
Simon Kelley5aabfc72007-08-29 11:24:47 +01004398 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004399
4400 oops:
Simon Kelley832af0b2007-01-21 20:01:28 +00004401 if (errmess)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004402 strcpy(daemon->namebuff, errmess);
4403
Simon Kelley9bafdc62018-08-21 22:53:38 +01004404 if (errmess || !one_opt(option, arg, daemon->namebuff, _("error"), 0, hard_opt == LOPT_REV_SERV))
Simon Kelleyf2621c72007-04-29 19:47:21 +01004405 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004406 sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file);
Simon Kelley824af852008-02-12 20:43:05 +00004407 if (hard_opt != 0)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004408 my_syslog(LOG_ERR, "%s", daemon->namebuff);
Simon Kelley5aabfc72007-08-29 11:24:47 +01004409 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004410 die("%s", daemon->namebuff, EC_BADCONF);
Simon Kelleyf2621c72007-04-29 19:47:21 +01004411 }
Simon Kelley849a8352006-06-09 21:02:31 +01004412 }
4413
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004414 mem_recover = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01004415 fclose(f);
4416}
4417
Simon Kelley4f7bb572018-03-08 18:47:08 +00004418#if defined(HAVE_DHCP) && defined(HAVE_INOTIFY)
Simon Kelley70d18732015-01-31 19:59:29 +00004419int option_read_dynfile(char *file, int flags)
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00004420{
Simon Kelleyf9c86372015-02-03 21:52:48 +00004421 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), file);
4422
Simon Kelley70d18732015-01-31 19:59:29 +00004423 if (flags & AH_DHCP_HST)
4424 return one_file(file, LOPT_BANK);
4425 else if (flags & AH_DHCP_OPT)
4426 return one_file(file, LOPT_OPTS);
Simon Kelleyf9c86372015-02-03 21:52:48 +00004427
Simon Kelley70d18732015-01-31 19:59:29 +00004428 return 0;
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00004429}
4430#endif
4431
Simon Kelley395eb712012-07-06 22:07:05 +01004432static int one_file(char *file, int hard_opt)
Simon Kelley28866e92011-02-14 20:19:14 +00004433{
4434 FILE *f;
4435 int nofile_ok = 0;
4436 static int read_stdin = 0;
4437 static struct fileread {
4438 dev_t dev;
4439 ino_t ino;
4440 struct fileread *next;
4441 } *filesread = NULL;
4442
4443 if (hard_opt == '7')
4444 {
4445 /* default conf-file reading */
4446 hard_opt = 0;
4447 nofile_ok = 1;
4448 }
4449
4450 if (hard_opt == 0 && strcmp(file, "-") == 0)
4451 {
4452 if (read_stdin == 1)
Simon Kelley395eb712012-07-06 22:07:05 +01004453 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00004454 read_stdin = 1;
4455 file = "stdin";
4456 f = stdin;
4457 }
4458 else
4459 {
4460 /* ignore repeated files. */
4461 struct stat statbuf;
4462
4463 if (hard_opt == 0 && stat(file, &statbuf) == 0)
4464 {
4465 struct fileread *r;
4466
4467 for (r = filesread; r; r = r->next)
4468 if (r->dev == statbuf.st_dev && r->ino == statbuf.st_ino)
Simon Kelley395eb712012-07-06 22:07:05 +01004469 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00004470
4471 r = safe_malloc(sizeof(struct fileread));
4472 r->next = filesread;
4473 filesread = r;
4474 r->dev = statbuf.st_dev;
4475 r->ino = statbuf.st_ino;
4476 }
4477
4478 if (!(f = fopen(file, "r")))
4479 {
4480 if (errno == ENOENT && nofile_ok)
Simon Kelley395eb712012-07-06 22:07:05 +01004481 return 1; /* No conffile, all done. */
Simon Kelley28866e92011-02-14 20:19:14 +00004482 else
4483 {
4484 char *str = _("cannot read %s: %s");
4485 if (hard_opt != 0)
4486 {
4487 my_syslog(LOG_ERR, str, file, strerror(errno));
Simon Kelley395eb712012-07-06 22:07:05 +01004488 return 0;
Simon Kelley28866e92011-02-14 20:19:14 +00004489 }
4490 else
4491 die(str, file, EC_FILE);
4492 }
4493 }
4494 }
4495
4496 read_file(file, f, hard_opt);
Simon Kelley395eb712012-07-06 22:07:05 +01004497 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00004498}
4499
4500/* expand any name which is a directory */
4501struct hostsfile *expand_filelist(struct hostsfile *list)
4502{
Simon Kelley19c51cf2014-03-18 22:38:30 +00004503 unsigned int i;
Simon Kelley28866e92011-02-14 20:19:14 +00004504 struct hostsfile *ah;
4505
Simon Kelley19c51cf2014-03-18 22:38:30 +00004506 /* find largest used index */
4507 for (i = SRC_AH, ah = list; ah; ah = ah->next)
Simon Kelley28866e92011-02-14 20:19:14 +00004508 {
4509 if (i <= ah->index)
4510 i = ah->index + 1;
4511
4512 if (ah->flags & AH_DIR)
4513 ah->flags |= AH_INACTIVE;
4514 else
4515 ah->flags &= ~AH_INACTIVE;
4516 }
4517
4518 for (ah = list; ah; ah = ah->next)
4519 if (!(ah->flags & AH_INACTIVE))
4520 {
4521 struct stat buf;
4522 if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode))
4523 {
4524 DIR *dir_stream;
4525 struct dirent *ent;
4526
4527 /* don't read this as a file */
4528 ah->flags |= AH_INACTIVE;
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00004529
Simon Kelley28866e92011-02-14 20:19:14 +00004530 if (!(dir_stream = opendir(ah->fname)))
4531 my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
4532 ah->fname, strerror(errno));
4533 else
4534 {
4535 while ((ent = readdir(dir_stream)))
4536 {
4537 size_t lendir = strlen(ah->fname);
4538 size_t lenfile = strlen(ent->d_name);
4539 struct hostsfile *ah1;
4540 char *path;
4541
4542 /* ignore emacs backups and dotfiles */
4543 if (lenfile == 0 ||
4544 ent->d_name[lenfile - 1] == '~' ||
4545 (ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
4546 ent->d_name[0] == '.')
4547 continue;
4548
4549 /* see if we have an existing record.
4550 dir is ah->fname
4551 file is ent->d_name
4552 path to match is ah1->fname */
4553
4554 for (ah1 = list; ah1; ah1 = ah1->next)
4555 {
4556 if (lendir < strlen(ah1->fname) &&
4557 strstr(ah1->fname, ah->fname) == ah1->fname &&
4558 ah1->fname[lendir] == '/' &&
4559 strcmp(ah1->fname + lendir + 1, ent->d_name) == 0)
4560 {
4561 ah1->flags &= ~AH_INACTIVE;
4562 break;
4563 }
4564 }
4565
4566 /* make new record */
4567 if (!ah1)
4568 {
4569 if (!(ah1 = whine_malloc(sizeof(struct hostsfile))))
4570 continue;
4571
4572 if (!(path = whine_malloc(lendir + lenfile + 2)))
4573 {
4574 free(ah1);
4575 continue;
4576 }
4577
4578 strcpy(path, ah->fname);
4579 strcat(path, "/");
4580 strcat(path, ent->d_name);
4581 ah1->fname = path;
4582 ah1->index = i++;
4583 ah1->flags = AH_DIR;
4584 ah1->next = list;
4585 list = ah1;
4586 }
4587
4588 /* inactivate record if not regular file */
4589 if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode))
4590 ah1->flags |= AH_INACTIVE;
4591
4592 }
4593 closedir(dir_stream);
4594 }
4595 }
4596 }
4597
4598 return list;
4599}
4600
Simon Kelley7b1eae42014-02-20 13:43:28 +00004601void read_servers_file(void)
4602{
4603 FILE *f;
4604
4605 if (!(f = fopen(daemon->servers_file, "r")))
4606 {
4607 my_syslog(LOG_ERR, _("cannot read %s: %s"), daemon->servers_file, strerror(errno));
4608 return;
4609 }
4610
4611 mark_servers(SERV_FROM_FILE);
4612 cleanup_servers();
4613
4614 read_file(daemon->servers_file, f, LOPT_REV_SERV);
4615}
4616
Simon Kelley28866e92011-02-14 20:19:14 +00004617
Simon Kelley7622fc02009-06-04 20:32:05 +01004618#ifdef HAVE_DHCP
Simon Kelley4f7bb572018-03-08 18:47:08 +00004619static void clear_dynamic_conf(void)
4620{
4621 struct dhcp_config *configs, *cp, **up;
4622
4623 /* remove existing... */
4624 for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
4625 {
4626 cp = configs->next;
4627
4628 if (configs->flags & CONFIG_BANK)
4629 {
4630 struct hwaddr_config *mac, *tmp;
4631 struct dhcp_netid_list *list, *tmplist;
4632
4633 for (mac = configs->hwaddr; mac; mac = tmp)
4634 {
4635 tmp = mac->next;
4636 free(mac);
4637 }
4638
4639 if (configs->flags & CONFIG_CLID)
4640 free(configs->clid);
4641
4642 for (list = configs->netid; list; list = tmplist)
4643 {
4644 free(list->list);
4645 tmplist = list->next;
4646 free(list);
4647 }
4648
4649 if (configs->flags & CONFIG_NAME)
4650 free(configs->hostname);
4651
4652 *up = configs->next;
4653 free(configs);
4654 }
4655 else
4656 up = &configs->next;
4657 }
4658}
4659
4660static void clear_dynamic_opt(void)
4661{
4662 struct dhcp_opt *opts, *cp, **up;
4663 struct dhcp_netid *id, *next;
4664
4665 for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
4666 {
4667 cp = opts->next;
4668
4669 if (opts->flags & DHOPT_BANK)
4670 {
4671 if ((opts->flags & DHOPT_VENDOR))
4672 free(opts->u.vendor_class);
4673 free(opts->val);
4674 for (id = opts->netid; id; id = next)
4675 {
4676 next = id->next;
4677 free(id->net);
4678 free(id);
4679 }
4680 *up = opts->next;
4681 free(opts);
4682 }
4683 else
4684 up = &opts->next;
4685 }
4686}
4687
Simon Kelley824af852008-02-12 20:43:05 +00004688void reread_dhcp(void)
4689{
Simon Kelley4f7bb572018-03-08 18:47:08 +00004690 struct hostsfile *hf;
Simon Kelley28866e92011-02-14 20:19:14 +00004691
Simon Kelley4f7bb572018-03-08 18:47:08 +00004692 /* Do these even if there is no daemon->dhcp_hosts_file or
4693 daemon->dhcp_opts_file since entries may have been created by the
4694 inotify dynamic file reading system. */
4695
4696 clear_dynamic_conf();
4697 clear_dynamic_opt();
4698
4699 if (daemon->dhcp_hosts_file)
Simon Kelley824af852008-02-12 20:43:05 +00004700 {
Simon Kelley28866e92011-02-14 20:19:14 +00004701 daemon->dhcp_hosts_file = expand_filelist(daemon->dhcp_hosts_file);
4702 for (hf = daemon->dhcp_hosts_file; hf; hf = hf->next)
Simon Kelley4f7bb572018-03-08 18:47:08 +00004703 if (!(hf->flags & AH_INACTIVE))
4704 {
4705 if (one_file(hf->fname, LOPT_BANK))
4706 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
4707 }
Simon Kelley824af852008-02-12 20:43:05 +00004708 }
4709
4710 if (daemon->dhcp_opts_file)
4711 {
Simon Kelley28866e92011-02-14 20:19:14 +00004712 daemon->dhcp_opts_file = expand_filelist(daemon->dhcp_opts_file);
4713 for (hf = daemon->dhcp_opts_file; hf; hf = hf->next)
4714 if (!(hf->flags & AH_INACTIVE))
4715 {
Simon Kelley395eb712012-07-06 22:07:05 +01004716 if (one_file(hf->fname, LOPT_OPTS))
4717 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
Simon Kelley28866e92011-02-14 20:19:14 +00004718 }
Simon Kelley824af852008-02-12 20:43:05 +00004719 }
Simon Kelley4f7bb572018-03-08 18:47:08 +00004720
4721# ifdef HAVE_INOTIFY
4722 /* Setup notify and read pre-existing files. */
4723 set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
4724# endif
Simon Kelley824af852008-02-12 20:43:05 +00004725}
Simon Kelley7622fc02009-06-04 20:32:05 +01004726#endif
Simon Kelley4f7bb572018-03-08 18:47:08 +00004727
Simon Kelley5aabfc72007-08-29 11:24:47 +01004728void read_opts(int argc, char **argv, char *compile_opts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004729{
Neil Jerram3bd4c472018-01-18 22:49:38 +00004730 size_t argbuf_size = MAXDNAME;
4731 char *argbuf = opt_malloc(argbuf_size);
Simon Kelley824af852008-02-12 20:43:05 +00004732 char *buff = opt_malloc(MAXDNAME);
Simon Kelley28866e92011-02-14 20:19:14 +00004733 int option, conffile_opt = '7', testmode = 0;
Simon Kelley90cb2222015-07-05 21:59:10 +01004734 char *arg, *conffile = CONFFILE;
Simon Kelley849a8352006-06-09 21:02:31 +01004735
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004736 opterr = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +01004737
Simon Kelley824af852008-02-12 20:43:05 +00004738 daemon = opt_malloc(sizeof(struct daemon));
Simon Kelley3be34542004-09-11 19:12:13 +01004739 memset(daemon, 0, sizeof(struct daemon));
4740 daemon->namebuff = buff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004741
Simon Kelley3be34542004-09-11 19:12:13 +01004742 /* Set defaults - everything else is zero or NULL */
Simon Kelley3be34542004-09-11 19:12:13 +01004743 daemon->cachesize = CACHESIZ;
Simon Kelley208b65c2006-08-05 21:41:37 +01004744 daemon->ftabsize = FTABSIZ;
Simon Kelley3be34542004-09-11 19:12:13 +01004745 daemon->port = NAMESERVER_PORT;
Simon Kelley9e038942008-05-30 20:06:34 +01004746 daemon->dhcp_client_port = DHCP_CLIENT_PORT;
4747 daemon->dhcp_server_port = DHCP_SERVER_PORT;
Simon Kelley3be34542004-09-11 19:12:13 +01004748 daemon->default_resolv.is_default = 1;
4749 daemon->default_resolv.name = RESOLVFILE;
4750 daemon->resolv_files = &daemon->default_resolv;
4751 daemon->username = CHUSER;
Simon Kelley3be34542004-09-11 19:12:13 +01004752 daemon->runfile = RUNFILE;
4753 daemon->dhcp_max = MAXLEASES;
Simon Kelley832af0b2007-01-21 20:01:28 +00004754 daemon->tftp_max = TFTP_MAX_CONNECTIONS;
Simon Kelley3be34542004-09-11 19:12:13 +01004755 daemon->edns_pktsz = EDNS_PKTSZ;
Simon Kelley849a8352006-06-09 21:02:31 +01004756 daemon->log_fac = -1;
Simon Kelley4f7b3042012-11-28 21:27:02 +00004757 daemon->auth_ttl = AUTH_TTL;
4758 daemon->soa_refresh = SOA_REFRESH;
4759 daemon->soa_retry = SOA_RETRY;
4760 daemon->soa_expiry = SOA_EXPIRY;
Hans Dedecker926332a2016-01-23 10:48:12 +00004761 daemon->max_port = MAX_PORT;
Simon Kelleybaf553d2018-01-29 22:49:27 +00004762 daemon->min_port = MIN_PORT;
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01004763
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01004764#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +00004765 add_txt("version.bind", "dnsmasq-" VERSION, 0 );
4766 add_txt("authors.bind", "Simon Kelley", 0);
4767 add_txt("copyright.bind", COPYRIGHT, 0);
4768 add_txt("cachesize.bind", NULL, TXT_STAT_CACHESIZE);
4769 add_txt("insertions.bind", NULL, TXT_STAT_INSERTS);
4770 add_txt("evictions.bind", NULL, TXT_STAT_EVICTIONS);
4771 add_txt("misses.bind", NULL, TXT_STAT_MISSES);
4772 add_txt("hits.bind", NULL, TXT_STAT_HITS);
4773#ifdef HAVE_AUTH
4774 add_txt("auth.bind", NULL, TXT_STAT_AUTH);
4775#endif
4776 add_txt("servers.bind", NULL, TXT_STAT_SERVERS);
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01004777#endif
Simon Kelley0a852542005-03-23 20:28:59 +00004778
Simon Kelley849a8352006-06-09 21:02:31 +01004779 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004780 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004781#ifdef HAVE_GETOPT_LONG
Simon Kelley849a8352006-06-09 21:02:31 +01004782 option = getopt_long(argc, argv, OPTSTRING, opts, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004783#else
Simon Kelley849a8352006-06-09 21:02:31 +01004784 option = getopt(argc, argv, OPTSTRING);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004785#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004786
4787 if (option == -1)
Simon Kelley28866e92011-02-14 20:19:14 +00004788 {
Simon Kelley572b41e2011-02-18 18:11:18 +00004789 for (; optind < argc; optind++)
4790 {
4791 unsigned char *c = (unsigned char *)argv[optind];
4792 for (; *c != 0; c++)
4793 if (!isspace(*c))
4794 die(_("junk found in command line"), NULL, EC_BADCONF);
4795 }
Simon Kelley28866e92011-02-14 20:19:14 +00004796 break;
4797 }
4798
Simon Kelley849a8352006-06-09 21:02:31 +01004799 /* Copy optarg so that argv doesn't get changed */
4800 if (optarg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004801 {
Neil Jerram3bd4c472018-01-18 22:49:38 +00004802 if (strlen(optarg) >= argbuf_size)
4803 {
4804 free(argbuf);
4805 argbuf_size = strlen(optarg) + 1;
4806 argbuf = opt_malloc(argbuf_size);
4807 }
4808 strncpy(argbuf, optarg, argbuf_size);
4809 argbuf[argbuf_size-1] = 0;
4810 arg = argbuf;
Simon Kelley849a8352006-06-09 21:02:31 +01004811 }
4812 else
4813 arg = NULL;
4814
4815 /* command-line only stuff */
Simon Kelley7622fc02009-06-04 20:32:05 +01004816 if (option == LOPT_TEST)
4817 testmode = 1;
4818 else if (option == 'w')
Simon Kelley849a8352006-06-09 21:02:31 +01004819 {
Simon Kelley7622fc02009-06-04 20:32:05 +01004820#ifdef HAVE_DHCP
Simon Kelley4cb1b322012-02-06 14:30:41 +00004821 if (argc == 3 && strcmp(argv[2], "dhcp") == 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01004822 display_opts();
Simon Kelley4cb1b322012-02-06 14:30:41 +00004823#ifdef HAVE_DHCP6
4824 else if (argc == 3 && strcmp(argv[2], "dhcp6") == 0)
4825 display_opts6();
Simon Kelley7622fc02009-06-04 20:32:05 +01004826#endif
Simon Kelley4cb1b322012-02-06 14:30:41 +00004827 else
4828#endif
4829 do_usage();
4830
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004831 exit(0);
4832 }
Simon Kelley849a8352006-06-09 21:02:31 +01004833 else if (option == 'v')
4834 {
4835 printf(_("Dnsmasq version %s %s\n"), VERSION, COPYRIGHT);
Simon Kelleyc72daea2012-01-05 21:33:27 +00004836 printf(_("Compile time options: %s\n\n"), compile_opts);
Simon Kelleyb8187c82005-11-26 21:46:27 +00004837 printf(_("This software comes with ABSOLUTELY NO WARRANTY.\n"));
4838 printf(_("Dnsmasq is free software, and you are welcome to redistribute it\n"));
Simon Kelley824af852008-02-12 20:43:05 +00004839 printf(_("under the terms of the GNU General Public License, version 2 or 3.\n"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004840 exit(0);
4841 }
Simon Kelley849a8352006-06-09 21:02:31 +01004842 else if (option == 'C')
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004843 {
Simon Kelley28866e92011-02-14 20:19:14 +00004844 conffile_opt = 0; /* file must exist */
Simon Kelley824af852008-02-12 20:43:05 +00004845 conffile = opt_string_alloc(arg);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004846 }
Simon Kelley849a8352006-06-09 21:02:31 +01004847 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004848 {
Simon Kelley26128d22004-11-14 16:43:54 +00004849#ifdef HAVE_GETOPT_LONG
Simon Kelley7b1eae42014-02-20 13:43:28 +00004850 if (!one_opt(option, arg, daemon->namebuff, _("try --help"), 1, 0))
Simon Kelley849a8352006-06-09 21:02:31 +01004851#else
Simon Kelley7b1eae42014-02-20 13:43:28 +00004852 if (!one_opt(option, arg, daemon->namebuff, _("try -w"), 1, 0))
Simon Kelley849a8352006-06-09 21:02:31 +01004853#endif
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004854 die(_("bad command line options: %s"), daemon->namebuff, EC_BADCONF);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004855 }
4856 }
Simon Kelley849a8352006-06-09 21:02:31 +01004857
Neil Jerram3bd4c472018-01-18 22:49:38 +00004858 free(argbuf);
4859
Simon Kelley849a8352006-06-09 21:02:31 +01004860 if (conffile)
Chen Wei28b879a2015-02-17 22:07:35 +00004861 {
4862 one_file(conffile, conffile_opt);
Simon Kelley90cb2222015-07-05 21:59:10 +01004863 if (conffile_opt == 0)
4864 free(conffile);
Chen Wei28b879a2015-02-17 22:07:35 +00004865 }
Simon Kelley849a8352006-06-09 21:02:31 +01004866
Simon Kelley1a6bca82008-07-11 11:11:42 +01004867 /* port might not be known when the address is parsed - fill in here */
Simon Kelley3be34542004-09-11 19:12:13 +01004868 if (daemon->servers)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004869 {
4870 struct server *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +01004871 for (tmp = daemon->servers; tmp; tmp = tmp->next)
Simon Kelley14ffa072016-04-25 16:36:44 +01004872 if (!(tmp->flags & SERV_HAS_SOURCE))
4873 {
4874 if (tmp->source_addr.sa.sa_family == AF_INET)
4875 tmp->source_addr.in.sin_port = htons(daemon->query_port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004876#ifdef HAVE_IPV6
Simon Kelley14ffa072016-04-25 16:36:44 +01004877 else if (tmp->source_addr.sa.sa_family == AF_INET6)
4878 tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
Simon Kelley5aabfc72007-08-29 11:24:47 +01004879#endif
Simon Kelley14ffa072016-04-25 16:36:44 +01004880 }
4881 }
4882
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004883 if (daemon->host_records)
4884 {
4885 struct host_record *hr;
4886
4887 for (hr = daemon->host_records; hr; hr = hr->next)
4888 if (hr->ttl == -1)
4889 hr->ttl = daemon->local_ttl;
4890 }
4891
4892 if (daemon->cnames)
4893 {
Simon Kelley903df072017-01-19 17:22:00 +00004894 struct cname *cn, *cn2, *cn3;
4895
4896#define NOLOOP 1
4897#define TESTLOOP 2
4898
4899 /* Fill in TTL for CNAMES noe we have local_ttl.
4900 Also prepare to do loop detection. */
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004901 for (cn = daemon->cnames; cn; cn = cn->next)
Simon Kelley903df072017-01-19 17:22:00 +00004902 {
4903 if (cn->ttl == -1)
4904 cn->ttl = daemon->local_ttl;
4905 cn->flag = 0;
4906 cn->targetp = NULL;
4907 for (cn2 = daemon->cnames; cn2; cn2 = cn2->next)
4908 if (hostname_isequal(cn->target, cn2->alias))
4909 {
4910 cn->targetp = cn2;
4911 break;
4912 }
4913 }
4914
4915 /* Find any CNAME loops.*/
4916 for (cn = daemon->cnames; cn; cn = cn->next)
4917 {
4918 for (cn2 = cn->targetp; cn2; cn2 = cn2->targetp)
4919 {
4920 if (cn2->flag == NOLOOP)
4921 break;
4922
4923 if (cn2->flag == TESTLOOP)
4924 die(_("CNAME loop involving %s"), cn->alias, EC_BADCONF);
4925
4926 cn2->flag = TESTLOOP;
4927 }
4928
4929 for (cn3 = cn->targetp; cn3 != cn2; cn3 = cn3->targetp)
4930 cn3->flag = NOLOOP;
4931 }
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004932 }
4933
Simon Kelley3be34542004-09-11 19:12:13 +01004934 if (daemon->if_addrs)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004935 {
4936 struct iname *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +01004937 for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004938 if (tmp->addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +01004939 tmp->addr.in.sin_port = htons(daemon->port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004940#ifdef HAVE_IPV6
4941 else if (tmp->addr.sa.sa_family == AF_INET6)
Simon Kelley3be34542004-09-11 19:12:13 +01004942 tmp->addr.in6.sin6_port = htons(daemon->port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004943#endif /* IPv6 */
4944 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00004945
4946 /* create default, if not specified */
4947 if (daemon->authserver && !daemon->hostmaster)
4948 {
4949 strcpy(buff, "hostmaster.");
4950 strcat(buff, daemon->authserver);
4951 daemon->hostmaster = opt_string_alloc(buff);
4952 }
4953
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004954 /* only one of these need be specified: the other defaults to the host-name */
Simon Kelley28866e92011-02-14 20:19:14 +00004955 if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004956 {
Simon Kelley0a852542005-03-23 20:28:59 +00004957 struct mx_srv_record *mx;
4958
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004959 if (gethostname(buff, MAXDNAME) == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004960 die(_("cannot get host-name: %s"), NULL, EC_MISC);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004961
Simon Kelley0a852542005-03-23 20:28:59 +00004962 for (mx = daemon->mxnames; mx; mx = mx->next)
4963 if (!mx->issrv && hostname_isequal(mx->name, buff))
4964 break;
4965
Simon Kelley28866e92011-02-14 20:19:14 +00004966 if ((daemon->mxtarget || option_bool(OPT_LOCALMX)) && !mx)
Simon Kelleyde379512004-06-22 20:23:33 +01004967 {
Simon Kelley824af852008-02-12 20:43:05 +00004968 mx = opt_malloc(sizeof(struct mx_srv_record));
Simon Kelley91dccd02005-03-31 17:48:32 +01004969 mx->next = daemon->mxnames;
4970 mx->issrv = 0;
4971 mx->target = NULL;
Simon Kelley824af852008-02-12 20:43:05 +00004972 mx->name = opt_string_alloc(buff);
Simon Kelley91dccd02005-03-31 17:48:32 +01004973 daemon->mxnames = mx;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004974 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004975
Simon Kelley3be34542004-09-11 19:12:13 +01004976 if (!daemon->mxtarget)
Simon Kelley824af852008-02-12 20:43:05 +00004977 daemon->mxtarget = opt_string_alloc(buff);
Simon Kelley0a852542005-03-23 20:28:59 +00004978
4979 for (mx = daemon->mxnames; mx; mx = mx->next)
4980 if (!mx->issrv && !mx->target)
4981 mx->target = daemon->mxtarget;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004982 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00004983
Simon Kelley28866e92011-02-14 20:19:14 +00004984 if (!option_bool(OPT_NO_RESOLV) &&
Simon Kelley208b65c2006-08-05 21:41:37 +01004985 daemon->resolv_files &&
4986 daemon->resolv_files->next &&
Simon Kelley28866e92011-02-14 20:19:14 +00004987 option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +01004988 die(_("only one resolv.conf file allowed in no-poll mode."), NULL, EC_BADCONF);
Simon Kelleyde379512004-06-22 20:23:33 +01004989
Simon Kelley28866e92011-02-14 20:19:14 +00004990 if (option_bool(OPT_RESOLV_DOMAIN))
Simon Kelleyde379512004-06-22 20:23:33 +01004991 {
4992 char *line;
Simon Kelley849a8352006-06-09 21:02:31 +01004993 FILE *f;
4994
Simon Kelley28866e92011-02-14 20:19:14 +00004995 if (option_bool(OPT_NO_RESOLV) ||
Simon Kelley208b65c2006-08-05 21:41:37 +01004996 !daemon->resolv_files ||
4997 (daemon->resolv_files)->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004998 die(_("must have exactly one resolv.conf to read domain from."), NULL, EC_BADCONF);
Simon Kelleyde379512004-06-22 20:23:33 +01004999
Simon Kelley3be34542004-09-11 19:12:13 +01005000 if (!(f = fopen((daemon->resolv_files)->name, "r")))
Simon Kelley5aabfc72007-08-29 11:24:47 +01005001 die(_("failed to read %s: %s"), (daemon->resolv_files)->name, EC_FILE);
Simon Kelleyde379512004-06-22 20:23:33 +01005002
5003 while ((line = fgets(buff, MAXDNAME, f)))
5004 {
5005 char *token = strtok(line, " \t\n\r");
5006
5007 if (!token || strcmp(token, "search") != 0)
5008 continue;
5009
5010 if ((token = strtok(NULL, " \t\n\r")) &&
Simon Kelley1f15b812009-10-13 17:49:32 +01005011 (daemon->domain_suffix = canonicalise_opt(token)))
Simon Kelleyde379512004-06-22 20:23:33 +01005012 break;
5013 }
Simon Kelley3be34542004-09-11 19:12:13 +01005014
Simon Kelleyde379512004-06-22 20:23:33 +01005015 fclose(f);
Simon Kelley8a911cc2004-03-16 18:35:52 +00005016
Simon Kelley3be34542004-09-11 19:12:13 +01005017 if (!daemon->domain_suffix)
Simon Kelley5aabfc72007-08-29 11:24:47 +01005018 die(_("no search directive found in %s"), (daemon->resolv_files)->name, EC_MISC);
Simon Kelleyde379512004-06-22 20:23:33 +01005019 }
Simon Kelley3d8df262005-08-29 12:19:27 +01005020
5021 if (daemon->domain_suffix)
5022 {
5023 /* add domain for any srv record without one. */
5024 struct mx_srv_record *srv;
Simon Kelleyde379512004-06-22 20:23:33 +01005025
Simon Kelley3d8df262005-08-29 12:19:27 +01005026 for (srv = daemon->mxnames; srv; srv = srv->next)
5027 if (srv->issrv &&
5028 strchr(srv->name, '.') &&
5029 strchr(srv->name, '.') == strrchr(srv->name, '.'))
5030 {
5031 strcpy(buff, srv->name);
5032 strcat(buff, ".");
5033 strcat(buff, daemon->domain_suffix);
5034 free(srv->name);
Simon Kelley824af852008-02-12 20:43:05 +00005035 srv->name = opt_string_alloc(buff);
Simon Kelley3d8df262005-08-29 12:19:27 +01005036 }
5037 }
Simon Kelley28866e92011-02-14 20:19:14 +00005038 else if (option_bool(OPT_DHCP_FQDN))
Simon Kelley9009d742008-11-14 20:04:27 +00005039 die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
Simon Kelley7622fc02009-06-04 20:32:05 +01005040
Simon Kelleyc8a80482014-03-05 14:29:54 +00005041 /* If there's access-control config, then ignore --local-service, it's intended
5042 as a system default to keep otherwise unconfigured installations safe. */
5043 if (daemon->if_names || daemon->if_except || daemon->if_addrs || daemon->authserver)
5044 reset_option_bool(OPT_LOCAL_SERVICE);
5045
Simon Kelley7622fc02009-06-04 20:32:05 +01005046 if (testmode)
5047 {
5048 fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
5049 exit(0);
5050 }
Simon Kelley849a8352006-06-09 21:02:31 +01005051}