blob: 7ca851dc73c3865f785011ec402021c5a6d57cdc [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 Kelleyae5b7e02019-03-27 22:33:28 +0000169#define LOPT_SHARED_NET 357
Florent Fourcot13a58f92019-06-20 10:26:40 +0200170#define LOPT_IGNORE_CLID 358
Simon Kelleybec366b2016-02-24 22:03:26 +0000171
Simon Kelley849a8352006-06-09 21:02:31 +0100172#ifdef HAVE_GETOPT_LONG
173static const struct option opts[] =
174#else
175static const struct myoption opts[] =
176#endif
177 {
Simon Kelley7622fc02009-06-04 20:32:05 +0100178 { "version", 0, 0, 'v' },
179 { "no-hosts", 0, 0, 'h' },
180 { "no-poll", 0, 0, 'n' },
181 { "help", 0, 0, 'w' },
182 { "no-daemon", 0, 0, 'd' },
Simon Kelley25cf5e32015-01-09 15:53:03 +0000183 { "log-queries", 2, 0, 'q' },
Simon Kelley7622fc02009-06-04 20:32:05 +0100184 { "user", 2, 0, 'u' },
185 { "group", 2, 0, 'g' },
186 { "resolv-file", 2, 0, 'r' },
Simon Kelley7b1eae42014-02-20 13:43:28 +0000187 { "servers-file", 1, 0, LOPT_SERVERS_FILE },
Simon Kelley7622fc02009-06-04 20:32:05 +0100188 { "mx-host", 1, 0, 'm' },
189 { "mx-target", 1, 0, 't' },
190 { "cache-size", 2, 0, 'c' },
191 { "port", 1, 0, 'p' },
192 { "dhcp-leasefile", 2, 0, 'l' },
193 { "dhcp-lease", 1, 0, 'l' },
194 { "dhcp-host", 1, 0, 'G' },
195 { "dhcp-range", 1, 0, 'F' },
196 { "dhcp-option", 1, 0, 'O' },
197 { "dhcp-boot", 1, 0, 'M' },
198 { "domain", 1, 0, 's' },
199 { "domain-suffix", 1, 0, 's' },
200 { "interface", 1, 0, 'i' },
201 { "listen-address", 1, 0, 'a' },
Simon Kelleyc8a80482014-03-05 14:29:54 +0000202 { "local-service", 0, 0, LOPT_LOCAL_SERVICE },
Simon Kelley7622fc02009-06-04 20:32:05 +0100203 { "bogus-priv", 0, 0, 'b' },
204 { "bogus-nxdomain", 1, 0, 'B' },
Glen Huang32fc6db2014-12-27 15:28:12 +0000205 { "ignore-address", 1, 0, LOPT_IGNORE_ADDR },
Simon Kelley7622fc02009-06-04 20:32:05 +0100206 { "selfmx", 0, 0, 'e' },
207 { "filterwin2k", 0, 0, 'f' },
208 { "pid-file", 2, 0, 'x' },
209 { "strict-order", 0, 0, 'o' },
210 { "server", 1, 0, 'S' },
Simon Kelleyde73a492014-02-17 21:43:27 +0000211 { "rev-server", 1, 0, LOPT_REV_SERV },
Simon Kelley7622fc02009-06-04 20:32:05 +0100212 { "local", 1, 0, LOPT_LOCAL },
213 { "address", 1, 0, 'A' },
214 { "conf-file", 2, 0, 'C' },
215 { "no-resolv", 0, 0, 'R' },
216 { "expand-hosts", 0, 0, 'E' },
217 { "localmx", 0, 0, 'L' },
218 { "local-ttl", 1, 0, 'T' },
219 { "no-negcache", 0, 0, 'N' },
220 { "addn-hosts", 1, 0, 'H' },
Simon Kelley70d18732015-01-31 19:59:29 +0000221 { "hostsdir", 1, 0, LOPT_HOST_INOTIFY },
Simon Kelley7622fc02009-06-04 20:32:05 +0100222 { "query-port", 1, 0, 'Q' },
223 { "except-interface", 1, 0, 'I' },
224 { "no-dhcp-interface", 1, 0, '2' },
225 { "domain-needed", 0, 0, 'D' },
226 { "dhcp-lease-max", 1, 0, 'X' },
227 { "bind-interfaces", 0, 0, 'z' },
228 { "read-ethers", 0, 0, 'Z' },
229 { "alias", 1, 0, 'V' },
230 { "dhcp-vendorclass", 1, 0, 'U' },
231 { "dhcp-userclass", 1, 0, 'j' },
232 { "dhcp-ignore", 1, 0, 'J' },
233 { "edns-packet-max", 1, 0, 'P' },
234 { "keep-in-foreground", 0, 0, 'k' },
235 { "dhcp-authoritative", 0, 0, 'K' },
236 { "srv-host", 1, 0, 'W' },
237 { "localise-queries", 0, 0, 'y' },
238 { "txt-record", 1, 0, 'Y' },
Simon Kelley974a6d02018-08-23 23:01:16 +0100239 { "caa-record", 1, 0 , LOPT_CAA },
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100240 { "dns-rr", 1, 0, LOPT_RR },
Simon Kelleyad094272012-08-10 17:10:54 +0100241 { "enable-dbus", 2, 0, '1' },
Julian Kornberger8dcdb332018-07-21 22:11:08 +0100242 { "enable-ubus", 0, 0, LOPT_UBUS },
Simon Kelley7622fc02009-06-04 20:32:05 +0100243 { "bootp-dynamic", 2, 0, '3' },
244 { "dhcp-mac", 1, 0, '4' },
245 { "no-ping", 0, 0, '5' },
246 { "dhcp-script", 1, 0, '6' },
247 { "conf-dir", 1, 0, '7' },
248 { "log-facility", 1, 0 ,'8' },
249 { "leasefile-ro", 0, 0, '9' },
250 { "dns-forward-max", 1, 0, '0' },
251 { "clear-on-reload", 0, 0, LOPT_RELOAD },
252 { "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
Simon Kelley2937f8a2013-07-29 19:49:07 +0100253 { "enable-tftp", 2, 0, LOPT_TFTP },
Simon Kelley7622fc02009-06-04 20:32:05 +0100254 { "tftp-secure", 0, 0, LOPT_SECURE },
Stefan Tomanek30d08792015-03-31 22:32:11 +0100255 { "tftp-no-fail", 0, 0, LOPT_TFTP_NO_FAIL },
Floris Bos60704f52017-04-09 22:22:49 +0100256 { "tftp-unique-root", 2, 0, LOPT_APREF },
Simon Kelley7622fc02009-06-04 20:32:05 +0100257 { "tftp-root", 1, 0, LOPT_PREFIX },
258 { "tftp-max", 1, 0, LOPT_TFTP_MAX },
Simon Kelleybec366b2016-02-24 22:03:26 +0000259 { "tftp-mtu", 1, 0, LOPT_TFTP_MTU },
Simon Kelley61ce6002012-04-20 21:28:49 +0100260 { "tftp-lowercase", 0, 0, LOPT_TFTP_LC },
Simon Kelley7622fc02009-06-04 20:32:05 +0100261 { "ptr-record", 1, 0, LOPT_PTR },
262 { "naptr-record", 1, 0, LOPT_NAPTR },
263 { "bridge-interface", 1, 0 , LOPT_BRIDGE },
Simon Kelleyae5b7e02019-03-27 22:33:28 +0000264 { "shared-network", 1, 0, LOPT_SHARED_NET },
Simon Kelley7622fc02009-06-04 20:32:05 +0100265 { "dhcp-option-force", 1, 0, LOPT_FORCE },
266 { "tftp-no-blocksize", 0, 0, LOPT_NOBLOCK },
267 { "log-dhcp", 0, 0, LOPT_LOG_OPTS },
268 { "log-async", 2, 0, LOPT_MAX_LOGS },
269 { "dhcp-circuitid", 1, 0, LOPT_CIRCUIT },
270 { "dhcp-remoteid", 1, 0, LOPT_REMOTE },
271 { "dhcp-subscrid", 1, 0, LOPT_SUBSCR },
272 { "interface-name", 1, 0, LOPT_INTNAME },
273 { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
274 { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
Simon Kelley5f4dc5c2015-01-20 20:51:02 +0000275 { "dhcp-hostsdir", 1, 0, LOPT_DHCP_INOTIFY },
Simon Kelley70d18732015-01-31 19:59:29 +0000276 { "dhcp-optsdir", 1, 0, LOPT_DHOPT_INOTIFY },
Simon Kelley7622fc02009-06-04 20:32:05 +0100277 { "dhcp-no-override", 0, 0, LOPT_OVERRIDE },
278 { "tftp-port-range", 1, 0, LOPT_TFTPPORTS },
279 { "stop-dns-rebind", 0, 0, LOPT_REBIND },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100280 { "rebind-domain-ok", 1, 0, LOPT_NO_REBIND },
Simon Kelley7622fc02009-06-04 20:32:05 +0100281 { "all-servers", 0, 0, LOPT_NOLAST },
Simon Kelleyc8226202018-08-08 23:46:03 +0100282 { "dhcp-match", 1, 0, LOPT_MATCH },
283 { "dhcp-name-match", 1, 0, LOPT_NAME_MATCH },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100284 { "dhcp-broadcast", 2, 0, LOPT_BROADCAST },
Simon Kelley7622fc02009-06-04 20:32:05 +0100285 { "neg-ttl", 1, 0, LOPT_NEGTTL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100286 { "max-ttl", 1, 0, LOPT_MAXTTL },
RinSatsuki28de3872015-01-10 15:22:21 +0000287 { "min-cache-ttl", 1, 0, LOPT_MINCTTL },
Simon Kelley1d860412012-09-20 20:48:04 +0100288 { "max-cache-ttl", 1, 0, LOPT_MAXCTTL },
Simon Kelley7622fc02009-06-04 20:32:05 +0100289 { "dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
290 { "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
291 { "min-port", 1, 0, LOPT_MINPORT },
Hans Dedecker926332a2016-01-23 10:48:12 +0000292 { "max-port", 1, 0, LOPT_MAXPORT },
Simon Kelley7622fc02009-06-04 20:32:05 +0100293 { "dhcp-fqdn", 0, 0, LOPT_DHCP_FQDN },
294 { "cname", 1, 0, LOPT_CNAME },
295 { "pxe-prompt", 1, 0, LOPT_PXE_PROMT },
296 { "pxe-service", 1, 0, LOPT_PXE_SERV },
297 { "test", 0, 0, LOPT_TEST },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100298 { "tag-if", 1, 0, LOPT_TAG_IF },
299 { "dhcp-proxy", 2, 0, LOPT_PROXY },
300 { "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES },
301 { "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
Simon Kelley1e505122016-01-25 21:29:23 +0000302 { "add-mac", 2, 0, LOPT_ADD_MAC },
Simon Kelleyed4c0762013-10-08 20:46:34 +0100303 { "add-subnet", 2, 0, LOPT_ADD_SBNET },
Simon Kelley1e505122016-01-25 21:29:23 +0000304 { "add-cpe-id", 1, 0 , LOPT_CPE_ID },
Simon Kelley28866e92011-02-14 20:19:14 +0000305 { "proxy-dnssec", 0, 0, LOPT_DNSSEC },
Simon Kelley7de060b2011-08-26 17:24:52 +0100306 { "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR },
307 { "conntrack", 0, 0, LOPT_CONNTRACK },
Simon Kelleyc72daea2012-01-05 21:33:27 +0000308 { "dhcp-client-update", 0, 0, LOPT_FQDN },
309 { "dhcp-luascript", 1, 0, LOPT_LUASCRIPT },
Simon Kelleyc5ad4e72012-02-24 16:06:20 +0000310 { "enable-ra", 0, 0, LOPT_RA },
Simon Kelley8b372702012-03-09 17:45:10 +0000311 { "dhcp-duid", 1, 0, LOPT_DUID },
Simon Kelleye759d422012-03-16 13:18:57 +0000312 { "host-record", 1, 0, LOPT_HOST_REC },
Simon Kelley54dd3932012-06-20 11:23:38 +0100313 { "bind-dynamic", 0, 0, LOPT_CLVERBIND },
Simon Kelley4f7b3042012-11-28 21:27:02 +0000314 { "auth-zone", 1, 0, LOPT_AUTHZONE },
315 { "auth-server", 1, 0, LOPT_AUTHSERV },
316 { "auth-ttl", 1, 0, LOPT_AUTHTTL },
317 { "auth-soa", 1, 0, LOPT_AUTHSOA },
Simon Kelleye1ff4192012-12-09 17:08:47 +0000318 { "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
Simon Kelley49678762012-12-09 18:24:58 +0000319 { "auth-peer", 1, 0, LOPT_AUTHPEER },
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000320 { "ipset", 1, 0, LOPT_IPSET },
Simon Kelley2bb73af2013-04-24 17:38:19 +0100321 { "synth-domain", 1, 0, LOPT_SYNTH },
Giovanni Bajo7dbe1932012-04-05 02:50:13 +0200322 { "dnssec", 0, 0, LOPT_SEC_VALID },
Simon Kelleyee415862014-02-11 11:07:22 +0000323 { "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR },
Simon Kelley5b3bf922014-01-25 17:03:07 +0000324 { "dnssec-debug", 0, 0, LOPT_DNSSEC_DEBUG },
Simon Kelleya6918532018-04-15 16:20:52 +0100325 { "dnssec-check-unsigned", 2, 0, LOPT_DNSSEC_CHECK },
Simon Kelleye98bd522014-03-28 20:41:23 +0000326 { "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME },
Simon Kelleyf6e62e22015-03-01 18:17:54 +0000327 { "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP },
Simon Kelleyc6309242013-03-07 20:59:28 +0000328#ifdef OPTION6_PREFIX_CLASS
329 { "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
330#endif
Simon Kelleyff7eea22013-09-04 18:01:38 +0100331 { "dhcp-relay", 1, 0, LOPT_RELAY },
Simon Kelleyc4cd95d2013-10-10 20:58:11 +0100332 { "ra-param", 1, 0, LOPT_RA_PARAM },
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100333 { "quiet-dhcp", 0, 0, LOPT_QUIET_DHCP },
334 { "quiet-dhcp6", 0, 0, LOPT_QUIET_DHCP6 },
335 { "quiet-ra", 0, 0, LOPT_QUIET_RA },
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +0100336 { "dns-loop-detect", 0, 0, LOPT_LOOP_DETECT },
Simon Kelley1e505122016-01-25 21:29:23 +0000337 { "script-arp", 0, 0, LOPT_SCRIPT_ARP },
Simon Kelley832e47b2016-02-24 21:24:45 +0000338 { "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },
Floris Bos503c6092017-04-09 23:07:13 +0100339 { "dhcp-reply-delay", 1, 0, LOPT_REPLY_DELAY },
Simon Kelley734d5312018-03-23 23:09:53 +0000340 { "dhcp-rapid-commit", 0, 0, LOPT_RAPID_COMMIT },
Simon Kelley6b173352018-05-08 18:32:14 +0100341 { "dumpfile", 1, 0, LOPT_DUMPFILE },
342 { "dumpmask", 1, 0, LOPT_DUMPMASK },
Florent Fourcot13a58f92019-06-20 10:26:40 +0200343 { "dhcp-ignore-clid", 0, 0, LOPT_IGNORE_CLID },
Simon Kelley849a8352006-06-09 21:02:31 +0100344 { NULL, 0, 0, 0 }
345 };
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000346
Simon Kelley28866e92011-02-14 20:19:14 +0000347
348#define ARG_DUP OPT_LAST
349#define ARG_ONE OPT_LAST + 1
350#define ARG_USED_CL OPT_LAST + 2
351#define ARG_USED_FILE OPT_LAST + 3
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000352
Simon Kelley1a6bca82008-07-11 11:11:42 +0100353static struct {
354 int opt;
355 unsigned int rept;
356 char * const flagdesc;
Simon Kelleyb8187c82005-11-26 21:46:27 +0000357 char * const desc;
358 char * const arg;
359} usage[] = {
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000360 { 'a', ARG_DUP, "<ipaddr>", gettext_noop("Specify local address(es) to listen on."), NULL },
361 { 'A', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Return ipaddr for all hosts in specified domains."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100362 { 'b', OPT_BOGUSPRIV, NULL, gettext_noop("Fake reverse lookups for RFC1918 private address ranges."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000363 { 'B', ARG_DUP, "<ipaddr>", gettext_noop("Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."), NULL },
364 { 'c', ARG_ONE, "<integer>", gettext_noop("Specify the size of the cache in entries (defaults to %s)."), "$" },
365 { 'C', ARG_DUP, "<path>", gettext_noop("Specify configuration file (defaults to %s)."), CONFFILE },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100366 { 'd', OPT_DEBUG, NULL, gettext_noop("Do NOT fork into the background: run in debug mode."), NULL },
367 { 'D', OPT_NODOTS_LOCAL, NULL, gettext_noop("Do NOT forward queries with no domain part."), NULL },
368 { 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL },
369 { 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
370 { 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000371 { 'F', ARG_DUP, "<ipaddr>,...", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
372 { 'g', ARG_ONE, "<groupname>", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100373 { 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000374 { LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL },
375 { LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL },
Simon Kelley5f4dc5c2015-01-20 20:51:02 +0000376 { LOPT_DHCP_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from a directory."), NULL },
Simon Kelley70d18732015-01-31 19:59:29 +0000377 { LOPT_DHOPT_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP options from a directory."), NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100378 { LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100379 { 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000380 { '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 +0000381 { LOPT_HOST_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read hosts files from a directory."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000382 { 'i', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) to listen on."), NULL },
383 { 'I', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100384 { 'j', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
385 { LOPT_CIRCUIT, ARG_DUP, "set:<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
386 { LOPT_REMOTE, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
387 { LOPT_SUBSCR, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3993 subscriber-id to tag."), NULL },
388 { 'J', ARG_DUP, "tag:<tag>...", gettext_noop("Don't do DHCP for hosts with tag set."), NULL },
389 { LOPT_BROADCAST, ARG_DUP, "[=tag:<tag>...]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100390 { 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
391 { '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 +0000392 { 'l', ARG_ONE, "<path>", gettext_noop("Specify where to store DHCP leases (defaults to %s)."), LEASEFILE },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100393 { 'L', OPT_LOCALMX, NULL, gettext_noop("Return MX records for local hosts."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000394 { 'm', ARG_DUP, "<host_name>,<target>,<pref>", gettext_noop("Specify an MX record."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100395 { 'M', ARG_DUP, "<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL },
396 { 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE },
397 { 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL },
398 { 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE },
399 { 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL },
400 { 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 +0000401 { 'p', ARG_ONE, "<integer>", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
402 { 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
Simon Kelley25cf5e32015-01-09 15:53:03 +0000403 { 'q', ARG_DUP, NULL, gettext_noop("Log DNS queries."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000404 { 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100405 { 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000406 { 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
Simon Kelley7b1eae42014-02-20 13:43:28 +0000407 { LOPT_SERVERS_FILE, ARG_ONE, "<path>", gettext_noop("Specify path to file with server= options"), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000408 { 'S', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
Simon Kelleyde73a492014-02-17 21:43:27 +0000409 { 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 +0000410 { LOPT_LOCAL, ARG_DUP, "/<domain>/", gettext_noop("Never forward queries to specified domains."), NULL },
Simon Kelley9009d742008-11-14 20:04:27 +0000411 { 's', ARG_DUP, "<domain>[,<range>]", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000412 { 't', ARG_ONE, "<host_name>", gettext_noop("Specify default target in an MX record."), NULL },
413 { 'T', ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
414 { LOPT_NEGTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
415 { 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 +0000416 { LOPT_MAXCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live ceiling for cache."), NULL },
417 { LOPT_MINCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live floor for cache."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000418 { 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100419 { 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100420 { 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000421 { 'V', ARG_DUP, "<ipaddr>,<ipaddr>,<netmask>", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },
422 { 'W', ARG_DUP, "<name>,<target>,...", gettext_noop("Specify a SRV record."), NULL },
Simon Kelley09217a12016-05-03 17:04:35 +0100423 { '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 +0000424 { 'x', ARG_ONE, "<path>", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE },
425 { 'X', ARG_ONE, "<integer>", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100426 { '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 +0000427 { 'Y', ARG_DUP, "<name>,<txt>[,<txt]", gettext_noop("Specify TXT DNS record."), NULL },
428 { LOPT_PTR, ARG_DUP, "<name>,<target>", gettext_noop("Specify PTR DNS record."), NULL },
429 { LOPT_INTNAME, ARG_DUP, "<name>,<interface>", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100430 { 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
431 { 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
Simon Kelleyad094272012-08-10 17:10:54 +0100432 { '1', ARG_ONE, "[=<busname>]", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
Julian Kornberger8dcdb332018-07-21 22:11:08 +0100433 { LOPT_UBUS, OPT_UBUS, NULL, gettext_noop("Enable the UBus interface."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000434 { '2', ARG_DUP, "<interface>", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100435 { '3', ARG_DUP, "[=tag:<tag>]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
436 { '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 +0000437 { LOPT_BRIDGE, ARG_DUP, "<iface>,<alias>..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL },
Simon Kelleyae5b7e02019-03-27 22:33:28 +0000438 { LOPT_SHARED_NET, ARG_DUP, "<iface>|<addr>,<addr>", gettext_noop("Specify extra networks sharing a broadcast domain for DHCP"), NULL},
Simon Kelley1a6bca82008-07-11 11:11:42 +0100439 { '5', OPT_NO_PING, NULL, gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000440 { '6', ARG_ONE, "<path>", gettext_noop("Shell script to run on DHCP lease creation and destruction."), NULL },
441 { LOPT_LUASCRIPT, ARG_DUP, "path", gettext_noop("Lua script to run on DHCP lease creation and destruction."), NULL },
442 { LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change scripts as this user."), NULL },
Simon Kelley1e505122016-01-25 21:29:23 +0000443 { 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 +0000444 { '7', ARG_DUP, "<path>", gettext_noop("Read configuration from all the files in this directory."), NULL },
Josh Soref730c6742017-02-06 16:14:04 +0000445 { '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 +0100446 { '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000447 { '0', ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100448 { LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100449 { LOPT_NO_NAMES, ARG_DUP, "[=tag:<tag>]...", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100450 { 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 +0100451 { LOPT_TFTP, ARG_DUP, "[=<intr>[,<intr>]]", gettext_noop("Enable integrated read-only TFTP server."), NULL },
Simon Kelley8b3ae2f2012-06-13 13:43:49 +0100452 { 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 +0100453 { 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 +0100454 { 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 +0100455 { 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 +0000456 { LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent TFTP transfers (defaults to %s)."), "#" },
Simon Kelleybec366b2016-02-24 22:03:26 +0000457 { LOPT_TFTP_MTU, ARG_ONE, "<integer>", gettext_noop("Maximum MTU to use for TFTP transfers."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100458 { LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
Simon Kelley61ce6002012-04-20 21:28:49 +0100459 { LOPT_TFTP_LC, OPT_TFTP_LC, NULL, gettext_noop("Convert TFTP filenames to lowercase"), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100460 { LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
461 { LOPT_LOG_OPTS, OPT_LOG_OPTS, NULL, gettext_noop("Extra logging for DHCP."), NULL },
Simon Kelley8ecfaa42012-01-07 15:29:48 +0000462 { LOPT_MAX_LOGS, ARG_ONE, "[=<integer>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100463 { 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 +0100464 { 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 +0000465 { LOPT_NO_REBIND, ARG_DUP, "/<domain>/", gettext_noop("Inhibit DNS-rebind protection on this domain."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100466 { LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL },
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100467 { 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 +0100468 { 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 +0100469 { LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100470 { LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
471 { LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
Hans Dedecker926332a2016-01-23 10:48:12 +0000472 { LOPT_MAXPORT, ARG_ONE, "<port>", gettext_noop("Specify highest port available for DNS query transmission."), NULL },
Simon Kelley9009d742008-11-14 20:04:27 +0000473 { 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 +0000474 { LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
475 { LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
Peter Wu3c0c1112016-08-28 20:53:09 +0100476 { 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 +0000477 { LOPT_CNAME, ARG_DUP, "<alias>,<target>[,<ttl>]", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
Simon Kelley7622fc02009-06-04 20:32:05 +0100478 { LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
479 { LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
480 { LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
Simon Kelley22c0f4f2016-02-17 22:12:31 +0000481 { 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 +0100482 { 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 +0000483 { LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client identification to forwarded DNS queries."), NULL },
Simon Kelley5a4120d2013-10-25 13:13:11 +0100484 { LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
Simon Kelley7de060b2011-08-26 17:24:52 +0100485 { LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
Florent Fourcot13a58f92019-06-20 10:26:40 +0200486 { LOPT_IGNORE_CLID, OPT_IGNORE_CLID, NULL, gettext_noop("Ignore client identifier option sent by DHCP clients."), NULL },
Simon Kelley7de060b2011-08-26 17:24:52 +0100487 { LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
Simon Kelleyc72daea2012-01-05 21:33:27 +0000488 { 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 +0000489 { LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
Simon Kelley8b372702012-03-09 17:45:10 +0000490 { LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
Simon Kelleydf3d54f2016-02-24 21:03:38 +0000491 { 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 +0100492 { LOPT_CAA, ARG_DUP, "<name>,<flags>,<tag>,<value>", gettext_noop("Specify certification authority authorization record"), NULL },
Simon Kelley9f7f3b12012-05-28 21:39:57 +0100493 { LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
Simon Kelley4f7b3042012-11-28 21:27:02 +0000494 { LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL },
Simon Kelley86e3b9a2012-11-30 13:46:48 +0000495 { LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>", gettext_noop("Export local names to global DNS"), NULL },
Simon Kelley333b2ce2013-01-07 21:46:03 +0000496 { LOPT_AUTHZONE, ARG_DUP, "<domain>,[<subnet>...]", gettext_noop("Domain to export to global DNS"), NULL },
Simon Kelley4f7b3042012-11-28 21:27:02 +0000497 { LOPT_AUTHTTL, ARG_ONE, "<integer>", gettext_noop("Set TTL for authoritative replies"), NULL },
Josh Soref730c6742017-02-06 16:14:04 +0000498 { LOPT_AUTHSOA, ARG_ONE, "<serial>[,...]", gettext_noop("Set authoritative zone information"), NULL },
Simon Kelley49678762012-12-09 18:24:58 +0000499 { LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
500 { LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL },
Peter Wu3c0c1112016-08-28 20:53:09 +0100501 { 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 +0100502 { 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 +0000503 { LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
Simon Kelleyee415862014-02-11 11:07:22 +0000504 { LOPT_TRUST_ANCHOR, ARG_DUP, "<domain>,[<class>],...", gettext_noop("Specify trust anchor key digest."), NULL },
Simon Kelley5b3bf922014-01-25 17:03:07 +0000505 { LOPT_DNSSEC_DEBUG, OPT_DNSSEC_DEBUG, NULL, gettext_noop("Disable upstream checking for DNSSEC debugging."), NULL },
Simon Kelleya6918532018-04-15 16:20:52 +0100506 { LOPT_DNSSEC_CHECK, ARG_DUP, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
Simon Kelleye98bd522014-03-28 20:41:23 +0000507 { 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 +0000508 { LOPT_DNSSEC_STAMP, ARG_ONE, "<path>", gettext_noop("Timestamp file to verify system clock for DNSSEC"), NULL },
Simon Kelleyc6309242013-03-07 20:59:28 +0000509#ifdef OPTION6_PREFIX_CLASS
510 { LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
511#endif
Vladislav Grishenko6ec5f5c2017-04-24 22:34:45 +0100512 { 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 +0100513 { LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
514 { LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
515 { LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
Simon Kelley832e47b2016-02-24 21:24:45 +0000516 { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks."), NULL },
517 { LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops."), NULL },
Glen Huang32fc6db2014-12-27 15:28:12 +0000518 { LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL },
Simon Kelley832e47b2016-02-24 21:24:45 +0000519 { LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL },
Floris Bos503c6092017-04-09 23:07:13 +0100520 { 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 +0000521 { LOPT_RAPID_COMMIT, OPT_RAPID_COMMIT, NULL, gettext_noop("Enables DHCPv4 Rapid Commit option."), NULL },
Simon Kelley6b173352018-05-08 18:32:14 +0100522 { LOPT_DUMPFILE, ARG_ONE, "<path>", gettext_noop("Path to debug packet dump file"), NULL },
523 { LOPT_DUMPMASK, ARG_ONE, "<hex>", gettext_noop("Mask which packets to dump"), NULL },
Simon Kelley1a6bca82008-07-11 11:11:42 +0100524 { 0, 0, NULL, NULL, NULL }
Simon Kelleyb8187c82005-11-26 21:46:27 +0000525};
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000526
Josh Soref730c6742017-02-06 16:14:04 +0000527/* We hide metacharacters in quoted strings by mapping them into the ASCII control
Simon Kelleyf2621c72007-04-29 19:47:21 +0100528 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 +0100529 following sequence so that they map to themselves: it is therefore possible to call
530 unhide_metas repeatedly on string without breaking things.
Simon Kelley824af852008-02-12 20:43:05 +0000531 The transformation gets undone by opt_canonicalise, atoi_check and opt_string_alloc, and a
Simon Kelleyf2621c72007-04-29 19:47:21 +0100532 couple of other places.
533 Note that space is included here so that
534 --dhcp-option=3, string
535 has five characters, whilst
536 --dhcp-option=3," string"
537 has six.
538*/
Simon Kelley3d8df262005-08-29 12:19:27 +0100539
Simon Kelleyf2621c72007-04-29 19:47:21 +0100540static const char meta[] = "\000123456 \b\t\n78\r90abcdefABCDE\033F:,.";
Simon Kelley3d8df262005-08-29 12:19:27 +0100541
542static char hide_meta(char c)
543{
544 unsigned int i;
545
546 for (i = 0; i < (sizeof(meta) - 1); i++)
547 if (c == meta[i])
548 return (char)i;
549
550 return c;
551}
552
553static char unhide_meta(char cr)
554{
555 unsigned int c = cr;
556
557 if (c < (sizeof(meta) - 1))
558 cr = meta[c];
559
560 return cr;
561}
562
563static void unhide_metas(char *cp)
564{
565 if (cp)
566 for(; *cp; cp++)
567 *cp = unhide_meta(*cp);
568}
569
Simon Kelley824af852008-02-12 20:43:05 +0000570static void *opt_malloc(size_t size)
571{
572 void *ret;
573
574 if (mem_recover)
575 {
576 ret = whine_malloc(size);
577 if (!ret)
578 longjmp(mem_jmp, 1);
579 }
580 else
581 ret = safe_malloc(size);
582
583 return ret;
584}
585
Petr Menšík59e47032018-11-02 22:39:39 +0000586static char *opt_string_alloc(const char *cp)
Simon Kelley3d8df262005-08-29 12:19:27 +0100587{
588 char *ret = NULL;
Petr Menšík59e47032018-11-02 22:39:39 +0000589 size_t len;
Simon Kelley3d8df262005-08-29 12:19:27 +0100590
Petr Menšík59e47032018-11-02 22:39:39 +0000591 if (cp && (len = strlen(cp)) != 0)
Simon Kelley3d8df262005-08-29 12:19:27 +0100592 {
Petr Menšík59e47032018-11-02 22:39:39 +0000593 ret = opt_malloc(len+1);
594 memcpy(ret, cp, len+1);
Simon Kelley3d8df262005-08-29 12:19:27 +0100595
596 /* restore hidden metachars */
597 unhide_metas(ret);
598 }
599
600 return ret;
601}
602
Simon Kelley3d8df262005-08-29 12:19:27 +0100603
Simon Kelleyf2621c72007-04-29 19:47:21 +0100604/* find next comma, split string with zero and eliminate spaces.
605 return start of string following comma */
Simon Kelley73a08a22009-02-05 20:28:08 +0000606
607static char *split_chr(char *s, char c)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100608{
609 char *comma, *p;
610
Simon Kelley73a08a22009-02-05 20:28:08 +0000611 if (!s || !(comma = strchr(s, c)))
Simon Kelleyf2621c72007-04-29 19:47:21 +0100612 return NULL;
613
614 p = comma;
615 *comma = ' ';
616
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100617 for (; *comma == ' '; comma++);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100618
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100619 for (; (p >= s) && *p == ' '; p--)
Simon Kelleyf2621c72007-04-29 19:47:21 +0100620 *p = 0;
621
622 return comma;
Simon Kelley3d8df262005-08-29 12:19:27 +0100623}
624
Simon Kelley73a08a22009-02-05 20:28:08 +0000625static char *split(char *s)
626{
627 return split_chr(s, ',');
628}
629
Simon Kelley1f15b812009-10-13 17:49:32 +0100630static char *canonicalise_opt(char *s)
Simon Kelley3d8df262005-08-29 12:19:27 +0100631{
Simon Kelley1f15b812009-10-13 17:49:32 +0100632 char *ret;
633 int nomem;
634
Simon Kelley3d8df262005-08-29 12:19:27 +0100635 if (!s)
636 return 0;
637
638 unhide_metas(s);
Simon Kelley1f15b812009-10-13 17:49:32 +0100639 if (!(ret = canonicalise(s, &nomem)) && nomem)
640 {
641 if (mem_recover)
642 longjmp(mem_jmp, 1);
643 else
644 die(_("could not get memory"), NULL, EC_NOMEM);
645 }
646
647 return ret;
Simon Kelley3d8df262005-08-29 12:19:27 +0100648}
649
650static int atoi_check(char *a, int *res)
651{
652 char *p;
653
654 if (!a)
655 return 0;
656
657 unhide_metas(a);
658
659 for (p = a; *p; p++)
660 if (*p < '0' || *p > '9')
661 return 0;
662
663 *res = atoi(a);
664 return 1;
665}
666
Simon Kelley1ad24ae2008-07-20 20:22:50 +0100667static int atoi_check16(char *a, int *res)
668{
669 if (!(atoi_check(a, res)) ||
670 *res < 0 ||
671 *res > 0xffff)
672 return 0;
673
674 return 1;
675}
Simon Kelleyee415862014-02-11 11:07:22 +0000676
Simon Kelleyde73a492014-02-17 21:43:27 +0000677#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +0000678static int atoi_check8(char *a, int *res)
679{
680 if (!(atoi_check(a, res)) ||
681 *res < 0 ||
682 *res > 0xff)
683 return 0;
684
685 return 1;
686}
Simon Kelleyde73a492014-02-17 21:43:27 +0000687#endif
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +0100688
689#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +0000690static void add_txt(char *name, char *txt, int stat)
Simon Kelley0a852542005-03-23 20:28:59 +0000691{
Simon Kelley824af852008-02-12 20:43:05 +0000692 struct txt_record *r = opt_malloc(sizeof(struct txt_record));
Simon Kelleyfec216d2014-03-27 20:54:34 +0000693
694 if (txt)
695 {
696 size_t len = strlen(txt);
697 r->txt = opt_malloc(len+1);
698 r->len = len+1;
699 *(r->txt) = len;
700 memcpy((r->txt)+1, txt, len);
701 }
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +0100702
Simon Kelleyfec216d2014-03-27 20:54:34 +0000703 r->stat = stat;
Simon Kelley824af852008-02-12 20:43:05 +0000704 r->name = opt_string_alloc(name);
Simon Kelley0a852542005-03-23 20:28:59 +0000705 r->next = daemon->txt;
706 daemon->txt = r;
707 r->class = C_CHAOS;
Simon Kelley0a852542005-03-23 20:28:59 +0000708}
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +0100709#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000710
Simon Kelley849a8352006-06-09 21:02:31 +0100711static void do_usage(void)
712{
713 char buff[100];
Simon Kelley832af0b2007-01-21 20:01:28 +0000714 int i, j;
715
716 struct {
717 char handle;
718 int val;
719 } tab[] = {
720 { '$', CACHESIZ },
721 { '*', EDNS_PKTSZ },
722 { '&', MAXLEASES },
723 { '!', FTABSIZ },
724 { '#', TFTP_MAX_CONNECTIONS },
725 { '\0', 0 }
726 };
Simon Kelley849a8352006-06-09 21:02:31 +0100727
728 printf(_("Usage: dnsmasq [options]\n\n"));
729#ifndef HAVE_GETOPT_LONG
730 printf(_("Use short options only on the command line.\n"));
731#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100732 printf(_("Valid options are:\n"));
Simon Kelley849a8352006-06-09 21:02:31 +0100733
Simon Kelley1a6bca82008-07-11 11:11:42 +0100734 for (i = 0; usage[i].opt != 0; i++)
Simon Kelley849a8352006-06-09 21:02:31 +0100735 {
Simon Kelley1a6bca82008-07-11 11:11:42 +0100736 char *desc = usage[i].flagdesc;
737 char *eq = "=";
738
739 if (!desc || *desc == '[')
740 eq = "";
741
742 if (!desc)
743 desc = "";
744
745 for ( j = 0; opts[j].name; j++)
746 if (opts[j].val == usage[i].opt)
747 break;
748 if (usage[i].opt < 256)
749 sprintf(buff, "-%c, ", usage[i].opt);
750 else
751 sprintf(buff, " ");
752
753 sprintf(buff+4, "--%s%s%s", opts[j].name, eq, desc);
Peter Wu3c0c1112016-08-28 20:53:09 +0100754 printf("%-55.55s", buff);
Simon Kelley1a6bca82008-07-11 11:11:42 +0100755
Simon Kelley849a8352006-06-09 21:02:31 +0100756 if (usage[i].arg)
757 {
Simon Kelley832af0b2007-01-21 20:01:28 +0000758 strcpy(buff, usage[i].arg);
759 for (j = 0; tab[j].handle; j++)
760 if (tab[j].handle == *(usage[i].arg))
761 sprintf(buff, "%d", tab[j].val);
Simon Kelley849a8352006-06-09 21:02:31 +0100762 }
Simon Kelley849a8352006-06-09 21:02:31 +0100763 printf(_(usage[i].desc), buff);
764 printf("\n");
765 }
766}
767
Simon Kelleyc740e4f2012-08-09 16:19:01 +0100768#define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
Petr Menšík59e47032018-11-02 22:39:39 +0000769#define ret_err_free(x,m) do { strcpy(errstr, (x)); free((m)); return 0; } while (0)
770#define goto_err(x) do { strcpy(errstr, (x)); goto on_error; } while (0)
Simon Kelleyc740e4f2012-08-09 16:19:01 +0100771
Ed Bardsleya7369be2015-08-05 21:17:18 +0100772static char *parse_mysockaddr(char *arg, union mysockaddr *addr)
773{
774 if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
775 addr->sa.sa_family = AF_INET;
Ed Bardsleya7369be2015-08-05 21:17:18 +0100776 else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
777 addr->sa.sa_family = AF_INET6;
Ed Bardsleya7369be2015-08-05 21:17:18 +0100778 else
779 return _("bad address");
780
781 return NULL;
782}
783
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100784char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags)
785{
786 int source_port = 0, serv_port = NAMESERVER_PORT;
787 char *portno, *source;
Kristian Evensen4e7694d2017-03-22 21:32:50 +0000788 char *interface_opt = NULL;
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100789 int scope_index = 0;
790 char *scope_id;
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100791
Simon Kelleyd68c2ca2014-02-18 22:30:30 +0000792 if (!arg || strlen(arg) == 0)
793 {
794 *flags |= SERV_NO_ADDR;
795 *interface = 0;
796 return NULL;
797 }
798
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100799 if ((source = split_chr(arg, '@')) && /* is there a source. */
800 (portno = split_chr(source, '#')) &&
801 !atoi_check16(portno, &source_port))
802 return _("bad port");
803
804 if ((portno = split_chr(arg, '#')) && /* is there a port no. */
805 !atoi_check16(portno, &serv_port))
806 return _("bad port");
807
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100808 scope_id = split_chr(arg, '%');
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100809
Kristian Evensen4e7694d2017-03-22 21:32:50 +0000810 if (source) {
811 interface_opt = split_chr(source, '@');
812
813 if (interface_opt)
814 {
815#if defined(SO_BINDTODEVICE)
Petr Menšík47b45b22018-08-15 18:17:00 +0200816 safe_strncpy(interface, interface_opt, IF_NAMESIZE);
Kristian Evensen4e7694d2017-03-22 21:32:50 +0000817#else
818 return _("interface binding not supported");
819#endif
820 }
821 }
822
Simon Kelleyddd9a6b2013-04-29 17:00:21 +0100823 if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100824 {
825 addr->in.sin_port = htons(serv_port);
826 addr->sa.sa_family = source_addr->sa.sa_family = AF_INET;
827#ifdef HAVE_SOCKADDR_SA_LEN
828 source_addr->in.sin_len = addr->in.sin_len = sizeof(struct sockaddr_in);
829#endif
830 source_addr->in.sin_addr.s_addr = INADDR_ANY;
831 source_addr->in.sin_port = htons(daemon->query_port);
832
833 if (source)
834 {
835 if (flags)
836 *flags |= SERV_HAS_SOURCE;
837 source_addr->in.sin_port = htons(source_port);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +0100838 if (!(inet_pton(AF_INET, source, &source_addr->in.sin_addr) > 0))
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100839 {
840#if defined(SO_BINDTODEVICE)
Kristian Evensen4e7694d2017-03-22 21:32:50 +0000841 if (interface_opt)
842 return _("interface can only be specified once");
843
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100844 source_addr->in.sin_addr.s_addr = INADDR_ANY;
Petr Menšík47b45b22018-08-15 18:17:00 +0200845 safe_strncpy(interface, source, IF_NAMESIZE);
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100846#else
847 return _("interface binding not supported");
848#endif
849 }
850 }
851 }
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100852 else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
853 {
854 if (scope_id && (scope_index = if_nametoindex(scope_id)) == 0)
855 return _("bad interface name");
856
857 addr->in6.sin6_port = htons(serv_port);
858 addr->in6.sin6_scope_id = scope_index;
859 source_addr->in6.sin6_addr = in6addr_any;
860 source_addr->in6.sin6_port = htons(daemon->query_port);
861 source_addr->in6.sin6_scope_id = 0;
862 addr->sa.sa_family = source_addr->sa.sa_family = AF_INET6;
863 addr->in6.sin6_flowinfo = source_addr->in6.sin6_flowinfo = 0;
864#ifdef HAVE_SOCKADDR_SA_LEN
865 addr->in6.sin6_len = source_addr->in6.sin6_len = sizeof(addr->in6);
866#endif
867 if (source)
868 {
869 if (flags)
870 *flags |= SERV_HAS_SOURCE;
871 source_addr->in6.sin6_port = htons(source_port);
872 if (inet_pton(AF_INET6, source, &source_addr->in6.sin6_addr) == 0)
873 {
874#if defined(SO_BINDTODEVICE)
Kristian Evensen4e7694d2017-03-22 21:32:50 +0000875 if (interface_opt)
876 return _("interface can only be specified once");
877
878 source_addr->in6.sin6_addr = in6addr_any;
Petr Menšík47b45b22018-08-15 18:17:00 +0200879 safe_strncpy(interface, source, IF_NAMESIZE);
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100880#else
881 return _("interface binding not supported");
882#endif
883 }
884 }
885 }
Simon Kelleyfaafb3f2012-09-20 14:17:39 +0100886 else
887 return _("bad address");
888
889 return NULL;
890}
891
Simon Kelleyde73a492014-02-17 21:43:27 +0000892static struct server *add_rev4(struct in_addr addr, int msize)
893{
894 struct server *serv = opt_malloc(sizeof(struct server));
Olivier Gayot916959c2017-03-06 22:14:50 +0000895 in_addr_t a = ntohl(addr.s_addr);
Simon Kelleyde73a492014-02-17 21:43:27 +0000896 char *p;
897
898 memset(serv, 0, sizeof(struct server));
Olivier Gayot916959c2017-03-06 22:14:50 +0000899 p = serv->domain = opt_malloc(29); /* strlen("xxx.yyy.zzz.ttt.in-addr.arpa")+1 */
900
901 switch (msize)
902 {
903 case 32:
Rosen Penevcbd29e52017-06-27 22:29:51 +0100904 p += sprintf(p, "%u.", a & 0xff);
Olivier Gayot916959c2017-03-06 22:14:50 +0000905 /* fall through */
906 case 24:
907 p += sprintf(p, "%d.", (a >> 8) & 0xff);
908 /* fall through */
Olivier Gayot916959c2017-03-06 22:14:50 +0000909 case 16:
910 p += sprintf(p, "%d.", (a >> 16) & 0xff);
911 /* fall through */
912 case 8:
913 p += sprintf(p, "%d.", (a >> 24) & 0xff);
914 break;
Olivier Gayotdc990582017-03-06 22:17:21 +0000915 default:
Petr Menšík59e47032018-11-02 22:39:39 +0000916 free(serv->domain);
917 free(serv);
Olivier Gayotdc990582017-03-06 22:17:21 +0000918 return NULL;
Olivier Gayot916959c2017-03-06 22:14:50 +0000919 }
920
921 p += sprintf(p, "in-addr.arpa");
Simon Kelleyde73a492014-02-17 21:43:27 +0000922
923 serv->flags = SERV_HAS_DOMAIN;
924 serv->next = daemon->servers;
925 daemon->servers = serv;
926
927 return serv;
928
929}
930
931static struct server *add_rev6(struct in6_addr *addr, int msize)
932{
933 struct server *serv = opt_malloc(sizeof(struct server));
934 char *p;
935 int i;
936
937 memset(serv, 0, sizeof(struct server));
938 p = serv->domain = opt_malloc(73); /* strlen("32*<n.>ip6.arpa")+1 */
939
940 for (i = msize-1; i >= 0; i -= 4)
941 {
942 int dig = ((unsigned char *)addr)[i>>3];
943 p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
944 }
945 p += sprintf(p, "ip6.arpa");
946
947 serv->flags = SERV_HAS_DOMAIN;
948 serv->next = daemon->servers;
949 daemon->servers = serv;
950
951 return serv;
952}
953
Simon Kelleyb5a8dd12012-12-10 11:37:25 +0000954#ifdef HAVE_DHCP
955
956static int is_tag_prefix(char *arg)
957{
958 if (arg && (strstr(arg, "net:") == arg || strstr(arg, "tag:") == arg))
959 return 1;
960
961 return 0;
962}
963
964static char *set_prefix(char *arg)
965{
966 if (strstr(arg, "set:") == arg)
967 return arg+4;
968
969 return arg;
970}
971
Petr Menšík59e47032018-11-02 22:39:39 +0000972static struct dhcp_netid *
973dhcp_netid_create(const char *net, struct dhcp_netid *next)
974{
975 struct dhcp_netid *tt;
976 tt = opt_malloc(sizeof (struct dhcp_netid));
977 tt->net = opt_string_alloc(net);
978 tt->next = next;
979 return tt;
980}
981
982static void dhcp_netid_free(struct dhcp_netid *nid)
983{
984 while (nid)
985 {
986 struct dhcp_netid *tmp = nid;
987 nid = nid->next;
988 free(tmp->net);
989 free(tmp);
990 }
991}
992
993/* Parse one or more tag:s before parameters.
994 * Moves arg to the end of tags. */
995static struct dhcp_netid * dhcp_tags(char **arg)
996{
997 struct dhcp_netid *id = NULL;
998
999 while (is_tag_prefix(*arg))
1000 {
1001 char *comma = split(*arg);
1002 id = dhcp_netid_create((*arg)+4, id);
1003 *arg = comma;
1004 };
1005 if (!*arg)
1006 {
1007 dhcp_netid_free(id);
1008 id = NULL;
1009 }
1010 return id;
1011}
1012
1013static void dhcp_netid_list_free(struct dhcp_netid_list *netid)
1014{
1015 while (netid)
1016 {
1017 struct dhcp_netid_list *tmplist = netid;
1018 netid = netid->next;
1019 dhcp_netid_free(tmplist->list);
1020 free(tmplist);
1021 }
1022}
1023
1024static void dhcp_config_free(struct dhcp_config *config)
1025{
1026 if (config)
1027 {
1028 struct hwaddr_config *hwaddr = config->hwaddr;
1029 while (hwaddr)
1030 {
1031 struct hwaddr_config *tmp = hwaddr;
1032 hwaddr = hwaddr->next;
1033 free(tmp);
1034 }
1035 dhcp_netid_list_free(config->netid);
1036 if (config->flags & CONFIG_CLID)
1037 free(config->clid);
1038 free(config);
1039 }
1040}
1041
1042static void dhcp_context_free(struct dhcp_context *ctx)
1043{
1044 if (ctx)
1045 {
1046 dhcp_netid_free(ctx->filter);
1047 free(ctx->netid.net);
Kevin Darbyshire-Bryantb683cf32018-12-10 10:34:35 +00001048#ifdef HAVE_DHCP6
Petr Menšík59e47032018-11-02 22:39:39 +00001049 free(ctx->template_interface);
Kevin Darbyshire-Bryantb683cf32018-12-10 10:34:35 +00001050#endif
Petr Menšík59e47032018-11-02 22:39:39 +00001051 free(ctx);
1052 }
1053}
1054
1055static void dhcp_opt_free(struct dhcp_opt *opt)
1056{
1057 if (opt->flags & DHOPT_VENDOR)
1058 free(opt->u.vendor_class);
1059 dhcp_netid_free(opt->netid);
1060 free(opt->val);
1061 free(opt);
1062}
1063
1064
Simon Kelley832af0b2007-01-21 20:01:28 +00001065/* This is too insanely large to keep in-line in the switch */
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001066static int parse_dhcp_opt(char *errstr, char *arg, int flags)
Simon Kelley832af0b2007-01-21 20:01:28 +00001067{
Simon Kelley824af852008-02-12 20:43:05 +00001068 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
Simon Kelley832af0b2007-01-21 20:01:28 +00001069 char lenchar = 0, *cp;
Simon Kelley40ef23b2012-03-13 21:59:28 +00001070 int addrs, digs, is_addr, is_addr6, is_hex, is_dec, is_string, dots;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001071 char *comma = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001072 u16 opt_len = 0;
1073 int is6 = 0;
Simon Kelleybd08ae62013-04-19 10:22:06 +01001074 int option_ok = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001075
1076 new->len = 0;
Simon Kelley824af852008-02-12 20:43:05 +00001077 new->flags = flags;
Simon Kelley832af0b2007-01-21 20:01:28 +00001078 new->netid = NULL;
1079 new->val = NULL;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001080 new->opt = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001081
Simon Kelleyf2621c72007-04-29 19:47:21 +01001082 while (arg)
Simon Kelley832af0b2007-01-21 20:01:28 +00001083 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001084 comma = split(arg);
1085
1086 for (cp = arg; *cp; cp++)
1087 if (*cp < '0' || *cp > '9')
Simon Kelley832af0b2007-01-21 20:01:28 +00001088 break;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001089
1090 if (!*cp)
1091 {
1092 new->opt = atoi(arg);
1093 opt_len = 0;
Simon Kelleybd08ae62013-04-19 10:22:06 +01001094 option_ok = 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001095 break;
1096 }
1097
1098 if (strstr(arg, "option:") == arg)
1099 {
Simon Kelleybd08ae62013-04-19 10:22:06 +01001100 if ((new->opt = lookup_dhcp_opt(AF_INET, arg+7)) != -1)
1101 {
1102 opt_len = lookup_dhcp_len(AF_INET, new->opt);
1103 /* option:<optname> must follow tag and vendor string. */
1104 if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
1105 option_ok = 1;
1106 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001107 break;
1108 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001109#ifdef HAVE_DHCP6
1110 else if (strstr(arg, "option6:") == arg)
1111 {
1112 for (cp = arg+8; *cp; cp++)
1113 if (*cp < '0' || *cp > '9')
1114 break;
1115
1116 if (!*cp)
1117 {
1118 new->opt = atoi(arg+8);
1119 opt_len = 0;
Simon Kelleybd08ae62013-04-19 10:22:06 +01001120 option_ok = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001121 }
1122 else
Simon Kelley40ef23b2012-03-13 21:59:28 +00001123 {
Simon Kelleybd08ae62013-04-19 10:22:06 +01001124 if ((new->opt = lookup_dhcp_opt(AF_INET6, arg+8)) != -1)
1125 {
1126 opt_len = lookup_dhcp_len(AF_INET6, new->opt);
1127 if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
1128 option_ok = 1;
1129 }
Simon Kelley40ef23b2012-03-13 21:59:28 +00001130 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001131 /* option6:<opt>|<optname> must follow tag and vendor string. */
1132 is6 = 1;
1133 break;
1134 }
1135#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +01001136 else if (strstr(arg, "vendor:") == arg)
1137 {
Simon Kelley73a08a22009-02-05 20:28:08 +00001138 new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7);
1139 new->flags |= DHOPT_VENDOR;
1140 }
1141 else if (strstr(arg, "encap:") == arg)
1142 {
1143 new->u.encap = atoi(arg+6);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001144 new->flags |= DHOPT_ENCAPSULATE;
1145 }
Simon Kelley316e2732010-01-22 20:16:09 +00001146 else if (strstr(arg, "vi-encap:") == arg)
1147 {
1148 new->u.encap = atoi(arg+9);
1149 new->flags |= DHOPT_RFC3925;
1150 if (flags == DHOPT_MATCH)
1151 {
Simon Kelleybd08ae62013-04-19 10:22:06 +01001152 option_ok = 1;
Simon Kelley316e2732010-01-22 20:16:09 +00001153 break;
1154 }
1155 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001156 else
1157 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001158 /* allow optional "net:" or "tag:" for consistency */
Petr Menšík59e47032018-11-02 22:39:39 +00001159 const char *name = (is_tag_prefix(arg)) ? arg+4 : set_prefix(arg);
1160 new->netid = dhcp_netid_create(name, new->netid);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001161 }
1162
1163 arg = comma;
Simon Kelley832af0b2007-01-21 20:01:28 +00001164 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001165
1166#ifdef HAVE_DHCP6
1167 if (is6)
1168 {
1169 if (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))
Petr Menšík59e47032018-11-02 22:39:39 +00001170 goto_err(_("unsupported encapsulation for IPv6 option"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001171
1172 if (opt_len == 0 &&
1173 !(new->flags & DHOPT_RFC3925))
Simon Kelleybd08ae62013-04-19 10:22:06 +01001174 opt_len = lookup_dhcp_len(AF_INET6, new->opt);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001175 }
1176 else
1177#endif
1178 if (opt_len == 0 &&
1179 !(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
Simon Kelleybd08ae62013-04-19 10:22:06 +01001180 opt_len = lookup_dhcp_len(AF_INET, new->opt);
Simon Kelley40ef23b2012-03-13 21:59:28 +00001181
Simon Kelley316e2732010-01-22 20:16:09 +00001182 /* option may be missing with rfc3925 match */
Simon Kelleybd08ae62013-04-19 10:22:06 +01001183 if (!option_ok)
Petr Menšík59e47032018-11-02 22:39:39 +00001184 goto_err(_("bad dhcp-option"));
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001185
1186 if (comma)
Simon Kelley832af0b2007-01-21 20:01:28 +00001187 {
1188 /* characterise the value */
Simon Kelleyf2621c72007-04-29 19:47:21 +01001189 char c;
Simon Kelley67993202019-03-04 22:59:42 +00001190 int found_dig = 0, found_colon = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001191 is_addr = is_addr6 = is_hex = is_dec = is_string = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001192 addrs = digs = 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001193 dots = 0;
1194 for (cp = comma; (c = *cp); cp++)
1195 if (c == ',')
Simon Kelley832af0b2007-01-21 20:01:28 +00001196 {
1197 addrs++;
1198 is_dec = is_hex = 0;
1199 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001200 else if (c == ':')
Simon Kelley832af0b2007-01-21 20:01:28 +00001201 {
1202 digs++;
1203 is_dec = is_addr = 0;
Simon Kelley67993202019-03-04 22:59:42 +00001204 found_colon = 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001205 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001206 else if (c == '/')
Simon Kelley832af0b2007-01-21 20:01:28 +00001207 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001208 is_addr6 = is_dec = is_hex = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001209 if (cp == comma) /* leading / means a pathname */
1210 is_addr = 0;
1211 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001212 else if (c == '.')
1213 {
Simon Kelley23245c02012-07-18 16:21:11 +01001214 is_addr6 = is_dec = is_hex = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001215 dots++;
1216 }
1217 else if (c == '-')
Simon Kelley4cb1b322012-02-06 14:30:41 +00001218 is_hex = is_addr = is_addr6 = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001219 else if (c == ' ')
Simon Kelley832af0b2007-01-21 20:01:28 +00001220 is_dec = is_hex = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001221 else if (!(c >='0' && c <= '9'))
Simon Kelley832af0b2007-01-21 20:01:28 +00001222 {
1223 is_addr = 0;
1224 if (cp[1] == 0 && is_dec &&
Simon Kelleyf2621c72007-04-29 19:47:21 +01001225 (c == 'b' || c == 's' || c == 'i'))
Simon Kelley832af0b2007-01-21 20:01:28 +00001226 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001227 lenchar = c;
Simon Kelley832af0b2007-01-21 20:01:28 +00001228 *cp = 0;
1229 }
1230 else
1231 is_dec = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001232 if (!((c >='A' && c <= 'F') ||
Simon Kelley73a08a22009-02-05 20:28:08 +00001233 (c >='a' && c <= 'f') ||
1234 (c == '*' && (flags & DHOPT_MATCH))))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001235 {
1236 is_hex = 0;
1237 if (c != '[' && c != ']')
1238 is_addr6 = 0;
1239 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001240 }
Simon Kelley28866e92011-02-14 20:19:14 +00001241 else
1242 found_dig = 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001243
Simon Kelley28866e92011-02-14 20:19:14 +00001244 if (!found_dig)
1245 is_dec = is_addr = 0;
Simon Kelley67993202019-03-04 22:59:42 +00001246
1247 if (!found_colon)
1248 is_addr6 = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001249
Simon Kelleyf2621c72007-04-29 19:47:21 +01001250 /* We know that some options take addresses */
Simon Kelley7622fc02009-06-04 20:32:05 +01001251 if (opt_len & OT_ADDR_LIST)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001252 {
1253 is_string = is_dec = is_hex = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001254
1255 if (!is6 && (!is_addr || dots == 0))
Petr Menšík59e47032018-11-02 22:39:39 +00001256 goto_err(_("bad IP address"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001257
1258 if (is6 && !is_addr6)
Petr Menšík59e47032018-11-02 22:39:39 +00001259 goto_err(_("bad IPv6 address"));
Simon Kelleyf2621c72007-04-29 19:47:21 +01001260 }
Simon Kelley28866e92011-02-14 20:19:14 +00001261 /* or names */
Simon Kelley4cb1b322012-02-06 14:30:41 +00001262 else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING))
1263 is_addr6 = is_addr = is_dec = is_hex = 0;
Simon Kelley23245c02012-07-18 16:21:11 +01001264
1265 if (found_dig && (opt_len & OT_TIME) && strlen(comma) > 0)
1266 {
1267 int val, fac = 1;
1268
1269 switch (comma[strlen(comma) - 1])
1270 {
Simon Kelley42243212012-07-20 15:19:18 +01001271 case 'w':
1272 case 'W':
1273 fac *= 7;
1274 /* fall through */
Simon Kelley23245c02012-07-18 16:21:11 +01001275 case 'd':
1276 case 'D':
1277 fac *= 24;
Simon Kelley87e00fe2018-02-16 21:27:35 +00001278 /* fall through */
Simon Kelley23245c02012-07-18 16:21:11 +01001279 case 'h':
1280 case 'H':
1281 fac *= 60;
1282 /* fall through */
1283 case 'm':
1284 case 'M':
1285 fac *= 60;
1286 /* fall through */
1287 case 's':
1288 case 'S':
1289 comma[strlen(comma) - 1] = 0;
1290 }
1291
1292 new->len = 4;
1293 new->val = opt_malloc(4);
1294 val = atoi(comma);
1295 *((int *)new->val) = htonl(val * fac);
1296 }
1297 else if (is_hex && digs > 1)
Simon Kelley832af0b2007-01-21 20:01:28 +00001298 {
1299 new->len = digs;
Simon Kelley824af852008-02-12 20:43:05 +00001300 new->val = opt_malloc(new->len);
Simon Kelley73a08a22009-02-05 20:28:08 +00001301 parse_hex(comma, new->val, digs, (flags & DHOPT_MATCH) ? &new->u.wildcard_mask : NULL, NULL);
1302 new->flags |= DHOPT_HEX;
Simon Kelley832af0b2007-01-21 20:01:28 +00001303 }
1304 else if (is_dec)
1305 {
1306 int i, val = atoi(comma);
1307 /* assume numeric arg is 1 byte except for
1308 options where it is known otherwise.
1309 For vendor class option, we have to hack. */
Simon Kelleyf2621c72007-04-29 19:47:21 +01001310 if (opt_len != 0)
1311 new->len = opt_len;
1312 else if (val & 0xffff0000)
1313 new->len = 4;
1314 else if (val & 0xff00)
1315 new->len = 2;
1316 else
1317 new->len = 1;
1318
Simon Kelley832af0b2007-01-21 20:01:28 +00001319 if (lenchar == 'b')
1320 new->len = 1;
1321 else if (lenchar == 's')
1322 new->len = 2;
1323 else if (lenchar == 'i')
1324 new->len = 4;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001325
Simon Kelley824af852008-02-12 20:43:05 +00001326 new->val = opt_malloc(new->len);
Simon Kelley832af0b2007-01-21 20:01:28 +00001327 for (i=0; i<new->len; i++)
1328 new->val[i] = val>>((new->len - i - 1)*8);
1329 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001330 else if (is_addr && !is6)
Simon Kelley832af0b2007-01-21 20:01:28 +00001331 {
1332 struct in_addr in;
1333 unsigned char *op;
1334 char *slash;
1335 /* max length of address/subnet descriptor is five bytes,
1336 add one for the option 120 enc byte too */
Simon Kelley824af852008-02-12 20:43:05 +00001337 new->val = op = opt_malloc((5 * addrs) + 1);
Simon Kelley6b010842007-02-12 20:32:07 +00001338 new->flags |= DHOPT_ADDR;
1339
Simon Kelley572b41e2011-02-18 18:11:18 +00001340 if (!(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
1341 new->opt == OPTION_SIP_SERVER)
Simon Kelley832af0b2007-01-21 20:01:28 +00001342 {
Simon Kelley6b010842007-02-12 20:32:07 +00001343 *(op++) = 1; /* RFC 3361 "enc byte" */
1344 new->flags &= ~DHOPT_ADDR;
Simon Kelley832af0b2007-01-21 20:01:28 +00001345 }
1346 while (addrs--)
1347 {
1348 cp = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001349 comma = split(cp);
Simon Kelley73a08a22009-02-05 20:28:08 +00001350 slash = split_chr(cp, '/');
Simon Kelleya2bc2542016-04-21 22:34:22 +01001351 if (!inet_pton(AF_INET, cp, &in))
Petr Menšík59e47032018-11-02 22:39:39 +00001352 goto_err(_("bad IPv4 address"));
Simon Kelley832af0b2007-01-21 20:01:28 +00001353 if (!slash)
1354 {
1355 memcpy(op, &in, INADDRSZ);
1356 op += INADDRSZ;
1357 }
1358 else
1359 {
1360 unsigned char *p = (unsigned char *)&in;
1361 int netsize = atoi(slash);
1362 *op++ = netsize;
1363 if (netsize > 0)
1364 *op++ = *p++;
1365 if (netsize > 8)
1366 *op++ = *p++;
1367 if (netsize > 16)
1368 *op++ = *p++;
1369 if (netsize > 24)
1370 *op++ = *p++;
1371 new->flags &= ~DHOPT_ADDR; /* cannot re-write descriptor format */
1372 }
1373 }
1374 new->len = op - new->val;
1375 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001376 else if (is_addr6 && is6)
1377 {
1378 unsigned char *op;
1379 new->val = op = opt_malloc(16 * addrs);
1380 new->flags |= DHOPT_ADDR6;
1381 while (addrs--)
1382 {
1383 cp = comma;
1384 comma = split(cp);
1385
1386 /* check for [1234::7] */
1387 if (*cp == '[')
1388 cp++;
1389 if (strlen(cp) > 1 && cp[strlen(cp)-1] == ']')
1390 cp[strlen(cp)-1] = 0;
1391
1392 if (inet_pton(AF_INET6, cp, op))
1393 {
1394 op += IN6ADDRSZ;
1395 continue;
1396 }
Petr Menšík59e47032018-11-02 22:39:39 +00001397
1398 goto_err(_("bad IPv6 address"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001399 }
1400 new->len = op - new->val;
1401 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001402 else if (is_string)
Simon Kelley832af0b2007-01-21 20:01:28 +00001403 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001404 /* text arg */
Simon Kelley572b41e2011-02-18 18:11:18 +00001405 if ((new->opt == OPTION_DOMAIN_SEARCH || new->opt == OPTION_SIP_SERVER) &&
Simon Kelley4cb1b322012-02-06 14:30:41 +00001406 !is6 && !(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
Simon Kelley832af0b2007-01-21 20:01:28 +00001407 {
1408 /* dns search, RFC 3397, or SIP, RFC 3361 */
1409 unsigned char *q, *r, *tail;
Simon Kelley824af852008-02-12 20:43:05 +00001410 unsigned char *p, *m = NULL, *newp;
Simon Kelley832af0b2007-01-21 20:01:28 +00001411 size_t newlen, len = 0;
Simon Kelley572b41e2011-02-18 18:11:18 +00001412 int header_size = (new->opt == OPTION_DOMAIN_SEARCH) ? 0 : 1;
Simon Kelley832af0b2007-01-21 20:01:28 +00001413
1414 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001415 comma = split(arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00001416
1417 while (arg && *arg)
1418 {
Simon Kelleyc52e1892010-06-07 22:01:39 +01001419 char *in, *dom = NULL;
1420 size_t domlen = 1;
1421 /* Allow "." as an empty domain */
1422 if (strcmp (arg, ".") != 0)
Simon Kelley832af0b2007-01-21 20:01:28 +00001423 {
Simon Kelleyc52e1892010-06-07 22:01:39 +01001424 if (!(dom = canonicalise_opt(arg)))
Petr Menšík59e47032018-11-02 22:39:39 +00001425 goto_err(_("bad domain in dhcp-option"));
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001426
Simon Kelleyc52e1892010-06-07 22:01:39 +01001427 domlen = strlen(dom) + 2;
Simon Kelley832af0b2007-01-21 20:01:28 +00001428 }
Simon Kelleyc52e1892010-06-07 22:01:39 +01001429
1430 newp = opt_malloc(len + domlen + header_size);
Simon Kelley824af852008-02-12 20:43:05 +00001431 if (m)
Simon Kelleyc52e1892010-06-07 22:01:39 +01001432 {
1433 memcpy(newp, m, header_size + len);
1434 free(m);
1435 }
Simon Kelley824af852008-02-12 20:43:05 +00001436 m = newp;
Simon Kelley832af0b2007-01-21 20:01:28 +00001437 p = m + header_size;
1438 q = p + len;
1439
1440 /* add string on the end in RFC1035 format */
Simon Kelleyc52e1892010-06-07 22:01:39 +01001441 for (in = dom; in && *in;)
Simon Kelley832af0b2007-01-21 20:01:28 +00001442 {
1443 unsigned char *cp = q++;
1444 int j;
Simon Kelleyc52e1892010-06-07 22:01:39 +01001445 for (j = 0; *in && (*in != '.'); in++, j++)
1446 *q++ = *in;
Simon Kelley832af0b2007-01-21 20:01:28 +00001447 *cp = j;
Simon Kelleyc52e1892010-06-07 22:01:39 +01001448 if (*in)
1449 in++;
Simon Kelley832af0b2007-01-21 20:01:28 +00001450 }
1451 *q++ = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +01001452 free(dom);
Simon Kelleyc52e1892010-06-07 22:01:39 +01001453
Simon Kelley832af0b2007-01-21 20:01:28 +00001454 /* Now tail-compress using earlier names. */
1455 newlen = q - p;
1456 for (tail = p + len; *tail; tail += (*tail) + 1)
1457 for (r = p; r - p < (int)len; r += (*r) + 1)
1458 if (strcmp((char *)r, (char *)tail) == 0)
1459 {
1460 PUTSHORT((r - p) | 0xc000, tail);
1461 newlen = tail - p;
1462 goto end;
1463 }
1464 end:
1465 len = newlen;
1466
1467 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001468 comma = split(arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00001469 }
1470
1471 /* RFC 3361, enc byte is zero for names */
Simon Kelley572b41e2011-02-18 18:11:18 +00001472 if (new->opt == OPTION_SIP_SERVER)
Simon Kelley832af0b2007-01-21 20:01:28 +00001473 m[0] = 0;
1474 new->len = (int) len + header_size;
1475 new->val = m;
1476 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001477#ifdef HAVE_DHCP6
1478 else if (comma && (opt_len & OT_CSTRING))
1479 {
1480 /* length fields are two bytes so need 16 bits for each string */
Simon Kelley40ef23b2012-03-13 21:59:28 +00001481 int i, commas = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001482 unsigned char *p, *newp;
1483
Simon Kelley40ef23b2012-03-13 21:59:28 +00001484 for (i = 0; comma[i]; i++)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001485 if (comma[i] == ',')
1486 commas++;
1487
1488 newp = opt_malloc(strlen(comma)+(2*commas));
1489 p = newp;
1490 arg = comma;
1491 comma = split(arg);
1492
1493 while (arg && *arg)
1494 {
1495 u16 len = strlen(arg);
Simon Kelley18f0fb02012-03-31 21:18:55 +01001496 unhide_metas(arg);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001497 PUTSHORT(len, p);
1498 memcpy(p, arg, len);
1499 p += len;
1500
1501 arg = comma;
1502 comma = split(arg);
1503 }
1504
1505 new->val = newp;
1506 new->len = p - newp;
1507 }
1508 else if (comma && (opt_len & OT_RFC1035_NAME))
1509 {
Simon Kelley18f0fb02012-03-31 21:18:55 +01001510 unsigned char *p = NULL, *newp, *end;
1511 int len = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001512 arg = comma;
1513 comma = split(arg);
1514
1515 while (arg && *arg)
1516 {
Simon Kelley18f0fb02012-03-31 21:18:55 +01001517 char *dom = canonicalise_opt(arg);
1518 if (!dom)
Petr Menšík59e47032018-11-02 22:39:39 +00001519 goto_err(_("bad domain in dhcp-option"));
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001520
Simon Kelley18f0fb02012-03-31 21:18:55 +01001521 newp = opt_malloc(len + strlen(dom) + 2);
1522
1523 if (p)
1524 {
1525 memcpy(newp, p, len);
1526 free(p);
1527 }
1528
1529 p = newp;
Simon Kelley0549c732017-09-25 18:17:11 +01001530 end = do_rfc1035_name(p + len, dom, NULL);
Simon Kelley18f0fb02012-03-31 21:18:55 +01001531 *end++ = 0;
1532 len = end - p;
1533 free(dom);
1534
Simon Kelley4cb1b322012-02-06 14:30:41 +00001535 arg = comma;
1536 comma = split(arg);
1537 }
1538
Simon Kelley18f0fb02012-03-31 21:18:55 +01001539 new->val = p;
1540 new->len = len;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001541 }
1542#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001543 else
1544 {
1545 new->len = strlen(comma);
1546 /* keep terminating zero on string */
Simon Kelley824af852008-02-12 20:43:05 +00001547 new->val = (unsigned char *)opt_string_alloc(comma);
Simon Kelley832af0b2007-01-21 20:01:28 +00001548 new->flags |= DHOPT_STRING;
1549 }
1550 }
1551 }
1552
Simon Kelley4cb1b322012-02-06 14:30:41 +00001553 if (!is6 &&
1554 ((new->len > 255) ||
Simon Kelley316e2732010-01-22 20:16:09 +00001555 (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) ||
Simon Kelley4cb1b322012-02-06 14:30:41 +00001556 (new->len > 250 && (new->flags & DHOPT_RFC3925))))
Petr Menšík59e47032018-11-02 22:39:39 +00001557 goto_err(_("dhcp-option too long"));
Simon Kelley832af0b2007-01-21 20:01:28 +00001558
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001559 if (flags == DHOPT_MATCH)
Simon Kelley824af852008-02-12 20:43:05 +00001560 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001561 if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||
1562 !new->netid ||
1563 new->netid->next)
Petr Menšík59e47032018-11-02 22:39:39 +00001564 goto_err(_("illegal dhcp-match"));
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001565
1566 if (is6)
Simon Kelley73a08a22009-02-05 20:28:08 +00001567 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001568 new->next = daemon->dhcp_match6;
1569 daemon->dhcp_match6 = new;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001570 }
1571 else
Simon Kelley73a08a22009-02-05 20:28:08 +00001572 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001573 new->next = daemon->dhcp_match;
1574 daemon->dhcp_match = new;
Simon Kelley73a08a22009-02-05 20:28:08 +00001575 }
Simon Kelley824af852008-02-12 20:43:05 +00001576 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001577 else if (is6)
1578 {
1579 new->next = daemon->dhcp_opts6;
1580 daemon->dhcp_opts6 = new;
1581 }
1582 else
1583 {
1584 new->next = daemon->dhcp_opts;
1585 daemon->dhcp_opts = new;
1586 }
1587
1588 return 1;
Petr Menšík59e47032018-11-02 22:39:39 +00001589on_error:
1590 dhcp_opt_free(new);
1591 return 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001592}
1593
Simon Kelley7622fc02009-06-04 20:32:05 +01001594#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001595
Simon Kelley28866e92011-02-14 20:19:14 +00001596void set_option_bool(unsigned int opt)
1597{
Petr Menšík24b87602018-10-24 22:30:18 +01001598 option_var(opt) |= option_val(opt);
Simon Kelley28866e92011-02-14 20:19:14 +00001599}
1600
Simon Kelley2b5bae92012-06-26 16:55:23 +01001601void reset_option_bool(unsigned int opt)
1602{
Petr Menšík24b87602018-10-24 22:30:18 +01001603 option_var(opt) &= ~(option_val(opt));
Simon Kelley2b5bae92012-06-26 16:55:23 +01001604}
1605
Petr Menšík59e47032018-11-02 22:39:39 +00001606static void server_list_free(struct server *list)
1607{
1608 while (list)
1609 {
1610 struct server *tmp = list;
1611 list = list->next;
1612 free(tmp);
1613 }
1614}
1615
Simon Kelley7b1eae42014-02-20 13:43:28 +00001616static 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 +01001617{
1618 int i;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001619 char *comma;
Simon Kelley849a8352006-06-09 21:02:31 +01001620
Simon Kelley832af0b2007-01-21 20:01:28 +00001621 if (option == '?')
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001622 ret_err(gen_err);
Simon Kelley832af0b2007-01-21 20:01:28 +00001623
Simon Kelley1a6bca82008-07-11 11:11:42 +01001624 for (i=0; usage[i].opt != 0; i++)
1625 if (usage[i].opt == option)
Simon Kelley849a8352006-06-09 21:02:31 +01001626 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001627 int rept = usage[i].rept;
1628
Simon Kelley28866e92011-02-14 20:19:14 +00001629 if (command_line)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001630 {
1631 /* command line */
1632 if (rept == ARG_USED_CL)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001633 ret_err(_("illegal repeated flag"));
Simon Kelley1a6bca82008-07-11 11:11:42 +01001634 if (rept == ARG_ONE)
1635 usage[i].rept = ARG_USED_CL;
1636 }
1637 else
1638 {
1639 /* allow file to override command line */
1640 if (rept == ARG_USED_FILE)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001641 ret_err(_("illegal repeated keyword"));
Simon Kelley1a6bca82008-07-11 11:11:42 +01001642 if (rept == ARG_USED_CL || rept == ARG_ONE)
1643 usage[i].rept = ARG_USED_FILE;
1644 }
1645
1646 if (rept != ARG_DUP && rept != ARG_ONE && rept != ARG_USED_CL)
1647 {
Simon Kelley28866e92011-02-14 20:19:14 +00001648 set_option_bool(rept);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001649 return 1;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001650 }
1651
1652 break;
Simon Kelley849a8352006-06-09 21:02:31 +01001653 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001654
Simon Kelley849a8352006-06-09 21:02:31 +01001655 switch (option)
1656 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001657 case 'C': /* --conf-file */
Simon Kelley849a8352006-06-09 21:02:31 +01001658 {
Simon Kelley824af852008-02-12 20:43:05 +00001659 char *file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001660 if (file)
Simon Kelley9009d742008-11-14 20:04:27 +00001661 {
Simon Kelley28866e92011-02-14 20:19:14 +00001662 one_file(file, 0);
Simon Kelley9009d742008-11-14 20:04:27 +00001663 free(file);
1664 }
Simon Kelley849a8352006-06-09 21:02:31 +01001665 break;
1666 }
1667
Simon Kelleyf2621c72007-04-29 19:47:21 +01001668 case '7': /* --conf-dir */
Simon Kelley849a8352006-06-09 21:02:31 +01001669 {
1670 DIR *dir_stream;
1671 struct dirent *ent;
1672 char *directory, *path;
Simon Kelley1f15b812009-10-13 17:49:32 +01001673 struct list {
1674 char *suffix;
1675 struct list *next;
Simon Kelley3e1551a2014-09-09 21:46:07 +01001676 } *ignore_suffix = NULL, *match_suffix = NULL, *li;
Simon Kelley849a8352006-06-09 21:02:31 +01001677
Simon Kelley1f15b812009-10-13 17:49:32 +01001678 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00001679 if (!(directory = opt_string_alloc(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01001680 break;
1681
Simon Kelley1f15b812009-10-13 17:49:32 +01001682 for (arg = comma; arg; arg = comma)
1683 {
1684 comma = split(arg);
Simon Kelley00cd9d52014-10-02 21:44:21 +01001685 if (strlen(arg) != 0)
Simon Kelley3e1551a2014-09-09 21:46:07 +01001686 {
Simon Kelley00cd9d52014-10-02 21:44:21 +01001687 li = opt_malloc(sizeof(struct list));
1688 if (*arg == '*')
1689 {
Simon Kelley0007ee92015-11-21 21:47:41 +00001690 /* "*" with no suffix is a no-op */
1691 if (arg[1] == 0)
1692 free(li);
1693 else
1694 {
1695 li->next = match_suffix;
1696 match_suffix = li;
1697 /* Have to copy: buffer is overwritten */
1698 li->suffix = opt_string_alloc(arg+1);
1699 }
Simon Kelley00cd9d52014-10-02 21:44:21 +01001700 }
1701 else
1702 {
1703 li->next = ignore_suffix;
1704 ignore_suffix = li;
1705 /* Have to copy: buffer is overwritten */
1706 li->suffix = opt_string_alloc(arg);
1707 }
Simon Kelley3e1551a2014-09-09 21:46:07 +01001708 }
Simon Kelley00cd9d52014-10-02 21:44:21 +01001709 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001710
Simon Kelley849a8352006-06-09 21:02:31 +01001711 if (!(dir_stream = opendir(directory)))
Simon Kelley5aabfc72007-08-29 11:24:47 +01001712 die(_("cannot access directory %s: %s"), directory, EC_FILE);
Simon Kelley1f15b812009-10-13 17:49:32 +01001713
Simon Kelley849a8352006-06-09 21:02:31 +01001714 while ((ent = readdir(dir_stream)))
1715 {
Simon Kelley7622fc02009-06-04 20:32:05 +01001716 size_t len = strlen(ent->d_name);
Simon Kelley849a8352006-06-09 21:02:31 +01001717 struct stat buf;
Simon Kelley1f15b812009-10-13 17:49:32 +01001718
1719 /* ignore emacs backups and dotfiles */
Simon Kelley7622fc02009-06-04 20:32:05 +01001720 if (len == 0 ||
1721 ent->d_name[len - 1] == '~' ||
Simon Kelley849a8352006-06-09 21:02:31 +01001722 (ent->d_name[0] == '#' && ent->d_name[len - 1] == '#') ||
1723 ent->d_name[0] == '.')
1724 continue;
Simon Kelley7622fc02009-06-04 20:32:05 +01001725
Simon Kelley3e1551a2014-09-09 21:46:07 +01001726 if (match_suffix)
1727 {
1728 for (li = match_suffix; li; li = li->next)
1729 {
1730 /* check for required suffices */
1731 size_t ls = strlen(li->suffix);
1732 if (len > ls &&
1733 strcmp(li->suffix, &ent->d_name[len - ls]) == 0)
1734 break;
1735 }
1736 if (!li)
1737 continue;
1738 }
1739
Simon Kelley1f15b812009-10-13 17:49:32 +01001740 for (li = ignore_suffix; li; li = li->next)
1741 {
1742 /* check for proscribed suffices */
1743 size_t ls = strlen(li->suffix);
1744 if (len > ls &&
1745 strcmp(li->suffix, &ent->d_name[len - ls]) == 0)
1746 break;
1747 }
1748 if (li)
1749 continue;
1750
Simon Kelley824af852008-02-12 20:43:05 +00001751 path = opt_malloc(strlen(directory) + len + 2);
Simon Kelley849a8352006-06-09 21:02:31 +01001752 strcpy(path, directory);
1753 strcat(path, "/");
1754 strcat(path, ent->d_name);
Simon Kelley7622fc02009-06-04 20:32:05 +01001755
Simon Kelley39595cf2013-02-04 21:40:07 +00001756 /* files must be readable */
Simon Kelley849a8352006-06-09 21:02:31 +01001757 if (stat(path, &buf) == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001758 die(_("cannot access %s: %s"), path, EC_FILE);
Simon Kelley849a8352006-06-09 21:02:31 +01001759
Simon Kelley39595cf2013-02-04 21:40:07 +00001760 /* only reg files allowed. */
1761 if (S_ISREG(buf.st_mode))
1762 one_file(path, 0);
1763
Simon Kelley849a8352006-06-09 21:02:31 +01001764 free(path);
1765 }
1766
1767 closedir(dir_stream);
Simon Kelley9009d742008-11-14 20:04:27 +00001768 free(directory);
Simon Kelley1f15b812009-10-13 17:49:32 +01001769 for(; ignore_suffix; ignore_suffix = li)
1770 {
1771 li = ignore_suffix->next;
1772 free(ignore_suffix->suffix);
1773 free(ignore_suffix);
1774 }
Simon Kelley00cd9d52014-10-02 21:44:21 +01001775 for(; match_suffix; match_suffix = li)
1776 {
1777 li = match_suffix->next;
1778 free(match_suffix->suffix);
1779 free(match_suffix);
Ed Bardsleya7369be2015-08-05 21:17:18 +01001780 }
Simon Kelley849a8352006-06-09 21:02:31 +01001781 break;
1782 }
1783
Simon Kelleyed4c0762013-10-08 20:46:34 +01001784 case LOPT_ADD_SBNET: /* --add-subnet */
1785 set_option_bool(OPT_CLIENT_SUBNET);
1786 if (arg)
1787 {
Ed Bardsleya7369be2015-08-05 21:17:18 +01001788 char *err, *end;
Simon Kelleyed4c0762013-10-08 20:46:34 +01001789 comma = split(arg);
Ed Bardsleya7369be2015-08-05 21:17:18 +01001790
1791 struct mysubnet* new = opt_malloc(sizeof(struct mysubnet));
1792 if ((end = split_chr(arg, '/')))
1793 {
1794 /* has subnet+len */
1795 err = parse_mysockaddr(arg, &new->addr);
1796 if (err)
Petr Menšík59e47032018-11-02 22:39:39 +00001797 ret_err_free(err, new);
Ed Bardsleya7369be2015-08-05 21:17:18 +01001798 if (!atoi_check(end, &new->mask))
Petr Menšík59e47032018-11-02 22:39:39 +00001799 ret_err_free(gen_err, new);
Ed Bardsleya7369be2015-08-05 21:17:18 +01001800 new->addr_used = 1;
1801 }
1802 else if (!atoi_check(arg, &new->mask))
Petr Menšík59e47032018-11-02 22:39:39 +00001803 ret_err_free(gen_err, new);
Ed Bardsleya7369be2015-08-05 21:17:18 +01001804
1805 daemon->add_subnet4 = new;
1806
Ed Bardsleya7369be2015-08-05 21:17:18 +01001807 if (comma)
1808 {
Simon Kelley22fe2fd2016-02-28 17:07:10 +00001809 new = opt_malloc(sizeof(struct mysubnet));
1810 if ((end = split_chr(comma, '/')))
1811 {
1812 /* has subnet+len */
Ed Bardsleya7369be2015-08-05 21:17:18 +01001813 err = parse_mysockaddr(comma, &new->addr);
1814 if (err)
Petr Menšík59e47032018-11-02 22:39:39 +00001815 ret_err_free(err, new);
Ed Bardsleya7369be2015-08-05 21:17:18 +01001816 if (!atoi_check(end, &new->mask))
Petr Menšík59e47032018-11-02 22:39:39 +00001817 ret_err_free(gen_err, new);
Ed Bardsleya7369be2015-08-05 21:17:18 +01001818 new->addr_used = 1;
1819 }
1820 else
1821 {
1822 if (!atoi_check(comma, &new->mask))
Petr Menšík59e47032018-11-02 22:39:39 +00001823 ret_err_free(gen_err, new);
Ed Bardsleya7369be2015-08-05 21:17:18 +01001824 }
Simon Kelley22fe2fd2016-02-28 17:07:10 +00001825
1826 daemon->add_subnet6 = new;
1827 }
Simon Kelleyed4c0762013-10-08 20:46:34 +01001828 }
1829 break;
1830
Simon Kelleyad094272012-08-10 17:10:54 +01001831 case '1': /* --enable-dbus */
1832 set_option_bool(OPT_DBUS);
1833 if (arg)
1834 daemon->dbus_name = opt_string_alloc(arg);
1835 else
1836 daemon->dbus_name = DNSMASQ_SERVICE;
1837 break;
1838
Simon Kelleyf2621c72007-04-29 19:47:21 +01001839 case '8': /* --log-facility */
1840 /* may be a filename */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001841 if (strchr(arg, '/') || strcmp (arg, "-") == 0)
Simon Kelley824af852008-02-12 20:43:05 +00001842 daemon->log_file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001843 else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001844 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001845#ifdef __ANDROID__
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001846 ret_err(_("setting log facility is not possible under Android"));
Simon Kelley572b41e2011-02-18 18:11:18 +00001847#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001848 for (i = 0; facilitynames[i].c_name; i++)
1849 if (hostname_isequal((char *)facilitynames[i].c_name, arg))
1850 break;
1851
1852 if (facilitynames[i].c_name)
1853 daemon->log_fac = facilitynames[i].c_val;
1854 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001855 ret_err(_("bad log facility"));
Simon Kelley572b41e2011-02-18 18:11:18 +00001856#endif
Simon Kelley849a8352006-06-09 21:02:31 +01001857 }
1858 break;
Julian Kornberger8dcdb332018-07-21 22:11:08 +01001859
Simon Kelleyf2621c72007-04-29 19:47:21 +01001860 case 'x': /* --pid-file */
Simon Kelley824af852008-02-12 20:43:05 +00001861 daemon->runfile = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001862 break;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001863
Simon Kelleyf2621c72007-04-29 19:47:21 +01001864 case 'r': /* --resolv-file */
Simon Kelley849a8352006-06-09 21:02:31 +01001865 {
Simon Kelley824af852008-02-12 20:43:05 +00001866 char *name = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001867 struct resolvc *new, *list = daemon->resolv_files;
1868
1869 if (list && list->is_default)
1870 {
1871 /* replace default resolv file - possibly with nothing */
1872 if (name)
1873 {
1874 list->is_default = 0;
1875 list->name = name;
1876 }
1877 else
1878 list = NULL;
1879 }
1880 else if (name)
1881 {
Simon Kelley824af852008-02-12 20:43:05 +00001882 new = opt_malloc(sizeof(struct resolvc));
Simon Kelley849a8352006-06-09 21:02:31 +01001883 new->next = list;
1884 new->name = name;
1885 new->is_default = 0;
1886 new->mtime = 0;
1887 new->logged = 0;
1888 list = new;
1889 }
1890 daemon->resolv_files = list;
1891 break;
1892 }
Simon Kelley7b1eae42014-02-20 13:43:28 +00001893
1894 case LOPT_SERVERS_FILE:
1895 daemon->servers_file = opt_string_alloc(arg);
1896 break;
Simon Kelley849a8352006-06-09 21:02:31 +01001897
Simon Kelleyf2621c72007-04-29 19:47:21 +01001898 case 'm': /* --mx-host */
Simon Kelley849a8352006-06-09 21:02:31 +01001899 {
1900 int pref = 1;
1901 struct mx_srv_record *new;
Simon Kelley1f15b812009-10-13 17:49:32 +01001902 char *name, *target = NULL;
1903
Simon Kelleyf2621c72007-04-29 19:47:21 +01001904 if ((comma = split(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01001905 {
1906 char *prefstr;
Simon Kelley1f15b812009-10-13 17:49:32 +01001907 if ((prefstr = split(comma)) && !atoi_check16(prefstr, &pref))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001908 ret_err(_("bad MX preference"));
Simon Kelley849a8352006-06-09 21:02:31 +01001909 }
1910
Simon Kelley1f15b812009-10-13 17:49:32 +01001911 if (!(name = canonicalise_opt(arg)) ||
1912 (comma && !(target = canonicalise_opt(comma))))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001913 ret_err(_("bad MX name"));
Simon Kelley1f15b812009-10-13 17:49:32 +01001914
Simon Kelley824af852008-02-12 20:43:05 +00001915 new = opt_malloc(sizeof(struct mx_srv_record));
Simon Kelley849a8352006-06-09 21:02:31 +01001916 new->next = daemon->mxnames;
1917 daemon->mxnames = new;
1918 new->issrv = 0;
Simon Kelley1f15b812009-10-13 17:49:32 +01001919 new->name = name;
1920 new->target = target; /* may be NULL */
Simon Kelley849a8352006-06-09 21:02:31 +01001921 new->weight = pref;
1922 break;
1923 }
1924
Simon Kelleyf2621c72007-04-29 19:47:21 +01001925 case 't': /* --mx-target */
Simon Kelley1f15b812009-10-13 17:49:32 +01001926 if (!(daemon->mxtarget = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001927 ret_err(_("bad MX target"));
Simon Kelley849a8352006-06-09 21:02:31 +01001928 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01001929
Simon Kelley6b173352018-05-08 18:32:14 +01001930 case LOPT_DUMPFILE: /* --dumpfile */
1931 daemon->dump_file = opt_string_alloc(arg);
1932 break;
1933
1934 case LOPT_DUMPMASK: /* --dumpmask */
1935 daemon->dump_mask = strtol(arg, NULL, 0);
1936 break;
1937
Simon Kelley7622fc02009-06-04 20:32:05 +01001938#ifdef HAVE_DHCP
Simon Kelleyf2621c72007-04-29 19:47:21 +01001939 case 'l': /* --dhcp-leasefile */
Simon Kelley824af852008-02-12 20:43:05 +00001940 daemon->lease_file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001941 break;
1942
Simon Kelleyc72daea2012-01-05 21:33:27 +00001943 /* Sorry about the gross pre-processor abuse */
1944 case '6': /* --dhcp-script */
1945 case LOPT_LUASCRIPT: /* --dhcp-luascript */
Simon Kelley48d12f12018-11-02 21:55:04 +00001946# if !defined(HAVE_SCRIPT)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001947 ret_err(_("recompile with HAVE_SCRIPT defined to enable lease-change scripts"));
Simon Kelley7622fc02009-06-04 20:32:05 +01001948# else
Simon Kelleyc72daea2012-01-05 21:33:27 +00001949 if (option == LOPT_LUASCRIPT)
1950# if !defined(HAVE_LUASCRIPT)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01001951 ret_err(_("recompile with HAVE_LUASCRIPT defined to enable Lua scripts"));
Simon Kelleyc72daea2012-01-05 21:33:27 +00001952# else
1953 daemon->luascript = opt_string_alloc(arg);
1954# endif
1955 else
1956 daemon->lease_change_command = opt_string_alloc(arg);
Simon Kelley7622fc02009-06-04 20:32:05 +01001957# endif
Simon Kelley849a8352006-06-09 21:02:31 +01001958 break;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001959#endif /* HAVE_DHCP */
Simon Kelley7622fc02009-06-04 20:32:05 +01001960
Simon Kelley70d18732015-01-31 19:59:29 +00001961 case LOPT_DHCP_HOST: /* --dhcp-hostsfile */
1962 case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
1963 case LOPT_DHCP_INOTIFY: /* --dhcp-hostsdir */
1964 case LOPT_DHOPT_INOTIFY: /* --dhcp-optsdir */
1965 case LOPT_HOST_INOTIFY: /* --hostsdir */
1966 case 'H': /* --addn-hosts */
Simon Kelley849a8352006-06-09 21:02:31 +01001967 {
Simon Kelley824af852008-02-12 20:43:05 +00001968 struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
Simon Kelley19c51cf2014-03-18 22:38:30 +00001969 static unsigned int hosts_index = SRC_AH;
Simon Kelley824af852008-02-12 20:43:05 +00001970 new->fname = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01001971 new->index = hosts_index++;
Simon Kelley7622fc02009-06-04 20:32:05 +01001972 new->flags = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00001973 if (option == 'H')
1974 {
1975 new->next = daemon->addn_hosts;
1976 daemon->addn_hosts = new;
1977 }
1978 else if (option == LOPT_DHCP_HOST)
1979 {
1980 new->next = daemon->dhcp_hosts_file;
1981 daemon->dhcp_hosts_file = new;
1982 }
Simon Kelleye1ff4192012-12-09 17:08:47 +00001983 else if (option == LOPT_DHCP_OPTS)
Simon Kelley28866e92011-02-14 20:19:14 +00001984 {
1985 new->next = daemon->dhcp_opts_file;
1986 daemon->dhcp_opts_file = new;
1987 }
Simon Kelley70d18732015-01-31 19:59:29 +00001988 else
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00001989 {
Simon Kelley70d18732015-01-31 19:59:29 +00001990 new->next = daemon->dynamic_dirs;
1991 daemon->dynamic_dirs = new;
1992 if (option == LOPT_DHCP_INOTIFY)
1993 new->flags |= AH_DHCP_HST;
1994 else if (option == LOPT_DHOPT_INOTIFY)
1995 new->flags |= AH_DHCP_OPT;
1996 else if (option == LOPT_HOST_INOTIFY)
1997 new->flags |= AH_HOSTS;
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00001998 }
1999
Simon Kelley849a8352006-06-09 21:02:31 +01002000 break;
2001 }
2002
Simon Kelley4f7b3042012-11-28 21:27:02 +00002003 case LOPT_AUTHSERV: /* --auth-server */
Simon Kelley08933472018-10-05 16:34:35 +01002004 comma = split(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002005
Simon Kelley4f7b3042012-11-28 21:27:02 +00002006 daemon->authserver = opt_string_alloc(arg);
Simon Kelley08933472018-10-05 16:34:35 +01002007
2008 while ((arg = comma))
2009 {
2010 struct iname *new = opt_malloc(sizeof(struct iname));
2011 comma = split(arg);
2012 new->name = NULL;
2013 unhide_metas(arg);
2014 if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0)
2015 new->addr.sa.sa_family = AF_INET;
Simon Kelley08933472018-10-05 16:34:35 +01002016 else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
2017 new->addr.sa.sa_family = AF_INET6;
Simon Kelley08933472018-10-05 16:34:35 +01002018 else
2019 {
2020 char *fam = split_chr(arg, '/');
2021 new->name = opt_string_alloc(arg);
2022 new->addr.sa.sa_family = 0;
2023 if (fam)
2024 {
2025 if (strcmp(fam, "4") == 0)
2026 new->addr.sa.sa_family = AF_INET;
Simon Kelley08933472018-10-05 16:34:35 +01002027 else if (strcmp(fam, "6") == 0)
2028 new->addr.sa.sa_family = AF_INET6;
Simon Kelley08933472018-10-05 16:34:35 +01002029 else
Petr Menšík59e47032018-11-02 22:39:39 +00002030 {
2031 free(new->name);
2032 ret_err_free(gen_err, new);
2033 }
Simon Kelley08933472018-10-05 16:34:35 +01002034 }
2035 }
2036 new->next = daemon->authinterface;
2037 daemon->authinterface = new;
2038 };
Simon Kelley429798f2012-12-10 20:45:53 +00002039
Simon Kelley4f7b3042012-11-28 21:27:02 +00002040 break;
Simon Kelleye1ff4192012-12-09 17:08:47 +00002041
2042 case LOPT_AUTHSFS: /* --auth-sec-servers */
2043 {
2044 struct name_list *new;
2045
2046 do {
2047 comma = split(arg);
Simon Kelley429798f2012-12-10 20:45:53 +00002048 new = opt_malloc(sizeof(struct name_list));
Simon Kelleye1ff4192012-12-09 17:08:47 +00002049 new->name = opt_string_alloc(arg);
2050 new->next = daemon->secondary_forward_server;
2051 daemon->secondary_forward_server = new;
2052 arg = comma;
2053 } while (arg);
2054 break;
2055 }
2056
Simon Kelley4f7b3042012-11-28 21:27:02 +00002057 case LOPT_AUTHZONE: /* --auth-zone */
2058 {
2059 struct auth_zone *new;
2060
2061 comma = split(arg);
Simon Kelley1e14cc02012-12-29 17:27:59 +00002062
Simon Kelley429798f2012-12-10 20:45:53 +00002063 new = opt_malloc(sizeof(struct auth_zone));
Simon Kelley4f7b3042012-11-28 21:27:02 +00002064 new->domain = opt_string_alloc(arg);
2065 new->subnet = NULL;
Mathias Kresin094bfae2016-07-24 14:15:22 +01002066 new->exclude = NULL;
Simon Kelley376d48c2013-11-13 13:04:30 +00002067 new->interface_names = NULL;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002068 new->next = daemon->auth_zones;
2069 daemon->auth_zones = new;
2070
2071 while ((arg = comma))
2072 {
2073 int prefixlen = 0;
Mathias Kresin094bfae2016-07-24 14:15:22 +01002074 int is_exclude = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002075 char *prefix;
Simon Kelley376d48c2013-11-13 13:04:30 +00002076 struct addrlist *subnet = NULL;
Simon Kelleycc921df2019-01-02 22:48:59 +00002077 union all_addr addr;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002078
2079 comma = split(arg);
2080 prefix = split_chr(arg, '/');
2081
2082 if (prefix && !atoi_check(prefix, &prefixlen))
2083 ret_err(gen_err);
2084
Mathias Kresin094bfae2016-07-24 14:15:22 +01002085 if (strstr(arg, "exclude:") == arg)
2086 {
2087 is_exclude = 1;
2088 arg = arg+8;
2089 }
2090
Simon Kelleycc921df2019-01-02 22:48:59 +00002091 if (inet_pton(AF_INET, arg, &addr.addr4))
Simon Kelley4f7b3042012-11-28 21:27:02 +00002092 {
Simon Kelley376d48c2013-11-13 13:04:30 +00002093 subnet = opt_malloc(sizeof(struct addrlist));
Simon Kelley4f7b3042012-11-28 21:27:02 +00002094 subnet->prefixlen = (prefixlen == 0) ? 24 : prefixlen;
Simon Kelley376d48c2013-11-13 13:04:30 +00002095 subnet->flags = ADDRLIST_LITERAL;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002096 }
Simon Kelleycc921df2019-01-02 22:48:59 +00002097 else if (inet_pton(AF_INET6, arg, &addr.addr6))
Simon Kelley4f7b3042012-11-28 21:27:02 +00002098 {
Simon Kelley376d48c2013-11-13 13:04:30 +00002099 subnet = opt_malloc(sizeof(struct addrlist));
Simon Kelley4f7b3042012-11-28 21:27:02 +00002100 subnet->prefixlen = (prefixlen == 0) ? 64 : prefixlen;
Simon Kelley376d48c2013-11-13 13:04:30 +00002101 subnet->flags = ADDRLIST_LITERAL | ADDRLIST_IPV6;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002102 }
Simon Kelley376d48c2013-11-13 13:04:30 +00002103 else
2104 {
2105 struct auth_name_list *name = opt_malloc(sizeof(struct auth_name_list));
2106 name->name = opt_string_alloc(arg);
2107 name->flags = AUTH4 | AUTH6;
2108 name->next = new->interface_names;
2109 new->interface_names = name;
2110 if (prefix)
2111 {
2112 if (prefixlen == 4)
2113 name->flags &= ~AUTH6;
Simon Kelley376d48c2013-11-13 13:04:30 +00002114 else if (prefixlen == 6)
2115 name->flags &= ~AUTH4;
Simon Kelley376d48c2013-11-13 13:04:30 +00002116 else
2117 ret_err(gen_err);
2118 }
2119 }
2120
2121 if (subnet)
2122 {
2123 subnet->addr = addr;
Mathias Kresin094bfae2016-07-24 14:15:22 +01002124
2125 if (is_exclude)
2126 {
2127 subnet->next = new->exclude;
2128 new->exclude = subnet;
2129 }
2130 else
2131 {
2132 subnet->next = new->subnet;
2133 new->subnet = subnet;
2134 }
Simon Kelley376d48c2013-11-13 13:04:30 +00002135 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002136 }
2137 break;
2138 }
Simon Kelley376d48c2013-11-13 13:04:30 +00002139
Simon Kelley4f7b3042012-11-28 21:27:02 +00002140 case LOPT_AUTHSOA: /* --auth-soa */
2141 comma = split(arg);
Simon Kelley5c72bb92013-08-19 14:12:59 +01002142 daemon->soa_sn = (u32)atoi(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002143 if (comma)
2144 {
Simon Kelley86e3b9a2012-11-30 13:46:48 +00002145 char *cp;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002146 arg = comma;
2147 comma = split(arg);
2148 daemon->hostmaster = opt_string_alloc(arg);
Simon Kelley86e3b9a2012-11-30 13:46:48 +00002149 for (cp = daemon->hostmaster; *cp; cp++)
2150 if (*cp == '@')
2151 *cp = '.';
2152
Simon Kelley4f7b3042012-11-28 21:27:02 +00002153 if (comma)
2154 {
2155 arg = comma;
2156 comma = split(arg);
Simon Kelley5c72bb92013-08-19 14:12:59 +01002157 daemon->soa_refresh = (u32)atoi(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002158 if (comma)
2159 {
2160 arg = comma;
2161 comma = split(arg);
Simon Kelley5c72bb92013-08-19 14:12:59 +01002162 daemon->soa_retry = (u32)atoi(arg);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002163 if (comma)
Simon Kelley407a1f32016-03-01 17:06:07 +00002164 daemon->soa_expiry = (u32)atoi(comma);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002165 }
2166 }
2167 }
2168
2169 break;
2170
Simon Kelley2bb73af2013-04-24 17:38:19 +01002171 case 's': /* --domain */
2172 case LOPT_SYNTH: /* --synth-domain */
Simon Kelley849a8352006-06-09 21:02:31 +01002173 if (strcmp (arg, "#") == 0)
Simon Kelley28866e92011-02-14 20:19:14 +00002174 set_option_bool(OPT_RESOLV_DOMAIN);
Simon Kelley849a8352006-06-09 21:02:31 +01002175 else
Simon Kelley9009d742008-11-14 20:04:27 +00002176 {
Simon Kelley1f15b812009-10-13 17:49:32 +01002177 char *d;
Simon Kelley9009d742008-11-14 20:04:27 +00002178 comma = split(arg);
Simon Kelley1f15b812009-10-13 17:49:32 +01002179 if (!(d = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002180 ret_err(gen_err);
Simon Kelley9009d742008-11-14 20:04:27 +00002181 else
2182 {
Simon Kelley9009d742008-11-14 20:04:27 +00002183 if (comma)
2184 {
Simon Kelley429798f2012-12-10 20:45:53 +00002185 struct cond_domain *new = opt_malloc(sizeof(struct cond_domain));
Simon Kelley28866e92011-02-14 20:19:14 +00002186 char *netpart;
Simon Kelley2bb73af2013-04-24 17:38:19 +01002187
Simon Kelley48fd1c42013-04-25 09:49:38 +01002188 new->prefix = NULL;
Simon Kelley6b2b5642018-03-10 18:12:04 +00002189 new->indexed = 0;
2190
Simon Kelley9009d742008-11-14 20:04:27 +00002191 unhide_metas(comma);
Simon Kelley28866e92011-02-14 20:19:14 +00002192 if ((netpart = split_chr(comma, '/')))
Simon Kelley9009d742008-11-14 20:04:27 +00002193 {
Simon Kelleyd74942a2012-02-07 20:51:56 +00002194 int msize;
2195
Simon Kelley28866e92011-02-14 20:19:14 +00002196 arg = split(netpart);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002197 if (!atoi_check(netpart, &msize))
Petr Menšík59e47032018-11-02 22:39:39 +00002198 ret_err_free(gen_err, new);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002199 else if (inet_pton(AF_INET, comma, &new->start))
Simon Kelley9009d742008-11-14 20:04:27 +00002200 {
Simon Kelleyd74942a2012-02-07 20:51:56 +00002201 int mask = (1 << (32 - msize)) - 1;
2202 new->is6 = 0;
Simon Kelley9009d742008-11-14 20:04:27 +00002203 new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask);
2204 new->end.s_addr = new->start.s_addr | htonl(mask);
Simon Kelley28866e92011-02-14 20:19:14 +00002205 if (arg)
2206 {
Simon Kelley48fd1c42013-04-25 09:49:38 +01002207 if (option != 's')
Simon Kelleyb5a7ff42013-04-25 11:03:47 +01002208 {
2209 if (!(new->prefix = canonicalise_opt(arg)) ||
2210 strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
Petr Menšík59e47032018-11-02 22:39:39 +00002211 ret_err_free(_("bad prefix"), new);
Simon Kelleyb5a7ff42013-04-25 11:03:47 +01002212 }
Simon Kelley48fd1c42013-04-25 09:49:38 +01002213 else if (strcmp(arg, "local") != 0 ||
2214 (msize != 8 && msize != 16 && msize != 24))
Petr Menšík59e47032018-11-02 22:39:39 +00002215 ret_err_free(gen_err, new);
Simon Kelley28866e92011-02-14 20:19:14 +00002216 else
2217 {
Simon Kelleyde73a492014-02-17 21:43:27 +00002218 /* generate the equivalent of
Simon Kelleyde73a492014-02-17 21:43:27 +00002219 local=/xxx.yyy.zzz.in-addr.arpa/ */
2220 struct server *serv = add_rev4(new->start, msize);
Olivier Gayotdc990582017-03-06 22:17:21 +00002221 if (!serv)
Petr Menšík59e47032018-11-02 22:39:39 +00002222 ret_err_free(_("bad prefix"), new);
Olivier Gayotdc990582017-03-06 22:17:21 +00002223
Simon Kelleyde73a492014-02-17 21:43:27 +00002224 serv->flags |= SERV_NO_ADDR;
Simon Kelley3ad3f3b2014-12-16 18:25:17 +00002225
2226 /* local=/<domain>/ */
2227 serv = opt_malloc(sizeof(struct server));
2228 memset(serv, 0, sizeof(struct server));
2229 serv->domain = d;
2230 serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
2231 serv->next = daemon->servers;
2232 daemon->servers = serv;
Simon Kelley28866e92011-02-14 20:19:14 +00002233 }
2234 }
Simon Kelley9009d742008-11-14 20:04:27 +00002235 }
Simon Kelleyd74942a2012-02-07 20:51:56 +00002236 else if (inet_pton(AF_INET6, comma, &new->start6))
2237 {
2238 u64 mask = (1LLU << (128 - msize)) - 1LLU;
2239 u64 addrpart = addr6part(&new->start6);
2240 new->is6 = 1;
Simon Kelley48fd1c42013-04-25 09:49:38 +01002241
Simon Kelleyd74942a2012-02-07 20:51:56 +00002242 /* prefix==64 overflows the mask calculation above */
2243 if (msize == 64)
2244 mask = (u64)-1LL;
Simon Kelley48fd1c42013-04-25 09:49:38 +01002245
Simon Kelleyd74942a2012-02-07 20:51:56 +00002246 new->end6 = new->start6;
2247 setaddr6part(&new->start6, addrpart & ~mask);
2248 setaddr6part(&new->end6, addrpart | mask);
2249
2250 if (msize < 64)
Petr Menšík59e47032018-11-02 22:39:39 +00002251 ret_err_free(gen_err, new);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002252 else if (arg)
2253 {
Simon Kelley48fd1c42013-04-25 09:49:38 +01002254 if (option != 's')
Simon Kelleyb5a7ff42013-04-25 11:03:47 +01002255 {
2256 if (!(new->prefix = canonicalise_opt(arg)) ||
2257 strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
Petr Menšík59e47032018-11-02 22:39:39 +00002258 ret_err_free(_("bad prefix"), new);
Simon Kelleyb5a7ff42013-04-25 11:03:47 +01002259 }
Simon Kelley48fd1c42013-04-25 09:49:38 +01002260 else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
Petr Menšík59e47032018-11-02 22:39:39 +00002261 ret_err_free(gen_err, new);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002262 else
2263 {
Simon Kelley48fd1c42013-04-25 09:49:38 +01002264 /* generate the equivalent of
Simon Kelley48fd1c42013-04-25 09:49:38 +01002265 local=/xxx.yyy.zzz.ip6.arpa/ */
Simon Kelleyde73a492014-02-17 21:43:27 +00002266 struct server *serv = add_rev6(&new->start6, msize);
2267 serv->flags |= SERV_NO_ADDR;
Simon Kelley3ad3f3b2014-12-16 18:25:17 +00002268
2269 /* local=/<domain>/ */
2270 serv = opt_malloc(sizeof(struct server));
2271 memset(serv, 0, sizeof(struct server));
2272 serv->domain = d;
2273 serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
2274 serv->next = daemon->servers;
2275 daemon->servers = serv;
Simon Kelleyd74942a2012-02-07 20:51:56 +00002276 }
2277 }
2278 }
Simon Kelleyd74942a2012-02-07 20:51:56 +00002279 else
Petr Menšík59e47032018-11-02 22:39:39 +00002280 ret_err_free(gen_err, new);
Simon Kelley9009d742008-11-14 20:04:27 +00002281 }
Simon Kelleyeec5c1e2013-10-25 10:37:30 +01002282 else
Simon Kelleyd74942a2012-02-07 20:51:56 +00002283 {
Simon Kelleyeec5c1e2013-10-25 10:37:30 +01002284 char *prefstr;
Simon Kelleyd74942a2012-02-07 20:51:56 +00002285 arg = split(comma);
Simon Kelleyeec5c1e2013-10-25 10:37:30 +01002286 prefstr = split(arg);
2287
Simon Kelleyd74942a2012-02-07 20:51:56 +00002288 if (inet_pton(AF_INET, comma, &new->start))
2289 {
2290 new->is6 = 0;
2291 if (!arg)
2292 new->end.s_addr = new->start.s_addr;
2293 else if (!inet_pton(AF_INET, arg, &new->end))
Petr Menšík59e47032018-11-02 22:39:39 +00002294 ret_err_free(gen_err, new);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002295 }
Simon Kelleyd74942a2012-02-07 20:51:56 +00002296 else if (inet_pton(AF_INET6, comma, &new->start6))
2297 {
2298 new->is6 = 1;
2299 if (!arg)
2300 memcpy(&new->end6, &new->start6, IN6ADDRSZ);
2301 else if (!inet_pton(AF_INET6, arg, &new->end6))
Petr Menšík59e47032018-11-02 22:39:39 +00002302 ret_err_free(gen_err, new);
Simon Kelleyd74942a2012-02-07 20:51:56 +00002303 }
Simon Kelleyd74942a2012-02-07 20:51:56 +00002304 else
Petr Menšík59e47032018-11-02 22:39:39 +00002305 ret_err_free(gen_err, new);
Simon Kelleyeec5c1e2013-10-25 10:37:30 +01002306
2307 if (option != 's' && prefstr)
2308 {
2309 if (!(new->prefix = canonicalise_opt(prefstr)) ||
2310 strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
Petr Menšík59e47032018-11-02 22:39:39 +00002311 ret_err_free(_("bad prefix"), new);
Simon Kelleyeec5c1e2013-10-25 10:37:30 +01002312 }
Simon Kelleyd74942a2012-02-07 20:51:56 +00002313 }
Simon Kelley2307eac2012-02-13 10:13:13 +00002314
2315 new->domain = d;
Simon Kelley2bb73af2013-04-24 17:38:19 +01002316 if (option == 's')
2317 {
2318 new->next = daemon->cond_domain;
2319 daemon->cond_domain = new;
2320 }
2321 else
2322 {
Simon Kelley6b2b5642018-03-10 18:12:04 +00002323 char *star;
Simon Kelley2bb73af2013-04-24 17:38:19 +01002324 new->next = daemon->synth_domains;
2325 daemon->synth_domains = new;
Simon Kelleydd33e982018-07-30 14:55:39 +01002326 if (new->prefix &&
2327 (star = strrchr(new->prefix, '*'))
2328 && *(star+1) == 0)
Simon Kelley6b2b5642018-03-10 18:12:04 +00002329 {
2330 *star = 0;
2331 new->indexed = 1;
2332 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01002333 }
Simon Kelley9009d742008-11-14 20:04:27 +00002334 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01002335 else if (option == 's')
Simon Kelley9009d742008-11-14 20:04:27 +00002336 daemon->domain_suffix = d;
Simon Kelley2bb73af2013-04-24 17:38:19 +01002337 else
2338 ret_err(gen_err);
Simon Kelley9009d742008-11-14 20:04:27 +00002339 }
2340 }
Simon Kelley849a8352006-06-09 21:02:31 +01002341 break;
2342
Simon Kelley1e505122016-01-25 21:29:23 +00002343 case LOPT_CPE_ID: /* --add-dns-client */
2344 if (arg)
Simon Kelley33702ab2015-12-28 23:17:15 +00002345 daemon->dns_client_id = opt_string_alloc(arg);
2346 break;
2347
Simon Kelleyc7f3bd22016-02-28 21:48:34 +00002348 case LOPT_ADD_MAC: /* --add-mac */
Simon Kelley1e505122016-01-25 21:29:23 +00002349 if (!arg)
2350 set_option_bool(OPT_ADD_MAC);
2351 else
2352 {
2353 unhide_metas(arg);
2354 if (strcmp(arg, "base64") == 0)
2355 set_option_bool(OPT_MAC_B64);
Simon Kelley9e4cf472016-02-17 20:26:32 +00002356 else if (strcmp(arg, "text") == 0)
2357 set_option_bool(OPT_MAC_HEX);
Simon Kelley22c0f4f2016-02-17 22:12:31 +00002358 else
2359 ret_err(gen_err);
Simon Kelley1e505122016-01-25 21:29:23 +00002360 }
2361 break;
2362
Simon Kelleyf2621c72007-04-29 19:47:21 +01002363 case 'u': /* --user */
Simon Kelley824af852008-02-12 20:43:05 +00002364 daemon->username = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002365 break;
2366
Simon Kelleyf2621c72007-04-29 19:47:21 +01002367 case 'g': /* --group */
Simon Kelley824af852008-02-12 20:43:05 +00002368 daemon->groupname = opt_string_alloc(arg);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002369 daemon->group_set = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01002370 break;
Simon Kelley9e038942008-05-30 20:06:34 +01002371
Simon Kelley7622fc02009-06-04 20:32:05 +01002372#ifdef HAVE_DHCP
Simon Kelley9e038942008-05-30 20:06:34 +01002373 case LOPT_SCRIPTUSR: /* --scriptuser */
2374 daemon->scriptuser = opt_string_alloc(arg);
2375 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01002376#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002377
Simon Kelleyf2621c72007-04-29 19:47:21 +01002378 case 'i': /* --interface */
Simon Kelley849a8352006-06-09 21:02:31 +01002379 do {
Simon Kelley824af852008-02-12 20:43:05 +00002380 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01002381 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002382 new->next = daemon->if_names;
2383 daemon->if_names = new;
2384 /* new->name may be NULL if someone does
2385 "interface=" to disable all interfaces except loop. */
Simon Kelley824af852008-02-12 20:43:05 +00002386 new->name = opt_string_alloc(arg);
Simon Kelley4ce4f372012-06-14 11:50:45 +01002387 new->used = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002388 arg = comma;
2389 } while (arg);
2390 break;
2391
Simon Kelley2937f8a2013-07-29 19:49:07 +01002392 case LOPT_TFTP: /* --enable-tftp */
2393 set_option_bool(OPT_TFTP);
2394 if (!arg)
2395 break;
2396 /* fall through */
2397
Simon Kelleyf2621c72007-04-29 19:47:21 +01002398 case 'I': /* --except-interface */
2399 case '2': /* --no-dhcp-interface */
Simon Kelley849a8352006-06-09 21:02:31 +01002400 do {
Simon Kelley824af852008-02-12 20:43:05 +00002401 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01002402 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00002403 new->name = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002404 if (option == 'I')
2405 {
2406 new->next = daemon->if_except;
2407 daemon->if_except = new;
2408 }
Simon Kelley2937f8a2013-07-29 19:49:07 +01002409 else if (option == LOPT_TFTP)
2410 {
2411 new->next = daemon->tftp_interfaces;
2412 daemon->tftp_interfaces = new;
2413 }
Simon Kelley849a8352006-06-09 21:02:31 +01002414 else
2415 {
2416 new->next = daemon->dhcp_except;
2417 daemon->dhcp_except = new;
2418 }
2419 arg = comma;
2420 } while (arg);
2421 break;
2422
Simon Kelleyf2621c72007-04-29 19:47:21 +01002423 case 'B': /* --bogus-nxdomain */
Glen Huang32fc6db2014-12-27 15:28:12 +00002424 case LOPT_IGNORE_ADDR: /* --ignore-address */
2425 {
Simon Kelley849a8352006-06-09 21:02:31 +01002426 struct in_addr addr;
2427 unhide_metas(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002428 if (arg && (inet_pton(AF_INET, arg, &addr) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01002429 {
Simon Kelley824af852008-02-12 20:43:05 +00002430 struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
Glen Huang32fc6db2014-12-27 15:28:12 +00002431 if (option == 'B')
2432 {
2433 baddr->next = daemon->bogus_addr;
2434 daemon->bogus_addr = baddr;
2435 }
2436 else
2437 {
2438 baddr->next = daemon->ignore_addr;
2439 daemon->ignore_addr = baddr;
2440 }
Simon Kelley849a8352006-06-09 21:02:31 +01002441 baddr->addr = addr;
2442 }
2443 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002444 ret_err(gen_err); /* error */
Simon Kelley849a8352006-06-09 21:02:31 +01002445 break;
2446 }
2447
Simon Kelleyf2621c72007-04-29 19:47:21 +01002448 case 'a': /* --listen-address */
Simon Kelley49678762012-12-09 18:24:58 +00002449 case LOPT_AUTHPEER: /* --auth-peer */
Simon Kelley849a8352006-06-09 21:02:31 +01002450 do {
Simon Kelley824af852008-02-12 20:43:05 +00002451 struct iname *new = opt_malloc(sizeof(struct iname));
Simon Kelleyf2621c72007-04-29 19:47:21 +01002452 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01002453 unhide_metas(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01002454 if (arg && (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01002455 {
2456 new->addr.sa.sa_family = AF_INET;
Simon Kelley49678762012-12-09 18:24:58 +00002457 new->addr.in.sin_port = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002458#ifdef HAVE_SOCKADDR_SA_LEN
2459 new->addr.in.sin_len = sizeof(new->addr.in);
2460#endif
2461 }
Simon Kelley849a8352006-06-09 21:02:31 +01002462 else if (arg && inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
2463 {
2464 new->addr.sa.sa_family = AF_INET6;
2465 new->addr.in6.sin6_flowinfo = 0;
2466 new->addr.in6.sin6_scope_id = 0;
Simon Kelley49678762012-12-09 18:24:58 +00002467 new->addr.in6.sin6_port = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01002468#ifdef HAVE_SOCKADDR_SA_LEN
2469 new->addr.in6.sin6_len = sizeof(new->addr.in6);
2470#endif
2471 }
Simon Kelley849a8352006-06-09 21:02:31 +01002472 else
Petr Menšík59e47032018-11-02 22:39:39 +00002473 ret_err_free(gen_err, new);
Simon Kelley4ce4f372012-06-14 11:50:45 +01002474
2475 new->used = 0;
Simon Kelley49678762012-12-09 18:24:58 +00002476 if (option == 'a')
2477 {
2478 new->next = daemon->if_addrs;
2479 daemon->if_addrs = new;
2480 }
2481 else
2482 {
2483 new->next = daemon->auth_peers;
2484 daemon->auth_peers = new;
2485 }
Simon Kelley849a8352006-06-09 21:02:31 +01002486 arg = comma;
2487 } while (arg);
2488 break;
2489
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002490 case 'S': /* --server */
2491 case LOPT_LOCAL: /* --local */
2492 case 'A': /* --address */
2493 case LOPT_NO_REBIND: /* --rebind-domain-ok */
Simon Kelley849a8352006-06-09 21:02:31 +01002494 {
2495 struct server *serv, *newlist = NULL;
2496
2497 unhide_metas(arg);
2498
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002499 if (arg && (*arg == '/' || option == LOPT_NO_REBIND))
Simon Kelley849a8352006-06-09 21:02:31 +01002500 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002501 int rebind = !(*arg == '/');
2502 char *end = NULL;
2503 if (!rebind)
2504 arg++;
2505 while (rebind || (end = split_chr(arg, '/')))
Simon Kelley849a8352006-06-09 21:02:31 +01002506 {
2507 char *domain = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002508 /* elide leading dots - they are implied in the search algorithm */
2509 while (*arg == '.') arg++;
Simon Kelley849a8352006-06-09 21:02:31 +01002510 /* # matches everything and becomes a zero length domain string */
2511 if (strcmp(arg, "#") == 0)
2512 domain = "";
Simon Kelley1f15b812009-10-13 17:49:32 +01002513 else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
Simon Kelleya3bd7e72018-07-19 22:00:08 +01002514 ret_err(gen_err);
Simon Kelley824af852008-02-12 20:43:05 +00002515 serv = opt_malloc(sizeof(struct server));
2516 memset(serv, 0, sizeof(struct server));
Simon Kelley849a8352006-06-09 21:02:31 +01002517 serv->next = newlist;
2518 newlist = serv;
Simon Kelley849a8352006-06-09 21:02:31 +01002519 serv->domain = domain;
2520 serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
Simon Kelley73a08a22009-02-05 20:28:08 +00002521 arg = end;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002522 if (rebind)
2523 break;
Simon Kelley849a8352006-06-09 21:02:31 +01002524 }
2525 if (!newlist)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002526 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002527 }
2528 else
2529 {
Simon Kelley824af852008-02-12 20:43:05 +00002530 newlist = opt_malloc(sizeof(struct server));
2531 memset(newlist, 0, sizeof(struct server));
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002532#ifdef HAVE_LOOP
2533 newlist->uid = rand32();
2534#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002535 }
2536
Simon Kelley7b1eae42014-02-20 13:43:28 +00002537 if (servers_only && option == 'S')
2538 newlist->flags |= SERV_FROM_FILE;
2539
Simon Kelley849a8352006-06-09 21:02:31 +01002540 if (option == 'A')
2541 {
2542 newlist->flags |= SERV_LITERAL_ADDRESS;
2543 if (!(newlist->flags & SERV_TYPE))
Petr Menšík59e47032018-11-02 22:39:39 +00002544 {
2545 server_list_free(newlist);
2546 ret_err(gen_err);
2547 }
Simon Kelley849a8352006-06-09 21:02:31 +01002548 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002549 else if (option == LOPT_NO_REBIND)
2550 newlist->flags |= SERV_NO_REBIND;
Simon Kelley849a8352006-06-09 21:02:31 +01002551
2552 if (!arg || !*arg)
2553 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002554 if (!(newlist->flags & SERV_NO_REBIND))
2555 newlist->flags |= SERV_NO_ADDR; /* no server */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002556 }
2557
2558 else if (strcmp(arg, "#") == 0)
Simon Kelleyda8b6512018-09-03 23:18:36 +01002559 newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
Simon Kelley849a8352006-06-09 21:02:31 +01002560 else
2561 {
Simon Kelleyfaafb3f2012-09-20 14:17:39 +01002562 char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
2563 if (err)
Petr Menšík59e47032018-11-02 22:39:39 +00002564 {
2565 server_list_free(newlist);
2566 ret_err(err);
2567 }
Simon Kelley849a8352006-06-09 21:02:31 +01002568 }
2569
Simon Kelleyf2621c72007-04-29 19:47:21 +01002570 serv = newlist;
2571 while (serv->next)
Simon Kelley849a8352006-06-09 21:02:31 +01002572 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01002573 serv->next->flags = serv->flags;
2574 serv->next->addr = serv->addr;
2575 serv->next->source_addr = serv->source_addr;
Simon Kelleyfaafb3f2012-09-20 14:17:39 +01002576 strcpy(serv->next->interface, serv->interface);
Simon Kelleyf2621c72007-04-29 19:47:21 +01002577 serv = serv->next;
Simon Kelley849a8352006-06-09 21:02:31 +01002578 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01002579 serv->next = daemon->servers;
2580 daemon->servers = newlist;
Simon Kelley849a8352006-06-09 21:02:31 +01002581 break;
2582 }
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002583
Simon Kelleyde73a492014-02-17 21:43:27 +00002584 case LOPT_REV_SERV: /* --rev-server */
2585 {
2586 char *string;
2587 int size;
2588 struct server *serv;
2589 struct in_addr addr4;
Simon Kelleyde73a492014-02-17 21:43:27 +00002590 struct in6_addr addr6;
Simon Kelleyde73a492014-02-17 21:43:27 +00002591
2592 unhide_metas(arg);
2593 if (!arg || !(comma=split(arg)) || !(string = split_chr(arg, '/')) || !atoi_check(string, &size))
2594 ret_err(gen_err);
2595
2596 if (inet_pton(AF_INET, arg, &addr4))
Olivier Gayotdc990582017-03-06 22:17:21 +00002597 {
2598 serv = add_rev4(addr4, size);
2599 if (!serv)
2600 ret_err(_("bad prefix"));
2601 }
Simon Kelleyde73a492014-02-17 21:43:27 +00002602 else if (inet_pton(AF_INET6, arg, &addr6))
2603 serv = add_rev6(&addr6, size);
Simon Kelleyde73a492014-02-17 21:43:27 +00002604 else
2605 ret_err(gen_err);
2606
2607 string = parse_server(comma, &serv->addr, &serv->source_addr, serv->interface, &serv->flags);
2608
2609 if (string)
2610 ret_err(string);
Simon Kelley7b1eae42014-02-20 13:43:28 +00002611
2612 if (servers_only)
2613 serv->flags |= SERV_FROM_FILE;
2614
Simon Kelleyde73a492014-02-17 21:43:27 +00002615 break;
2616 }
2617
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002618 case LOPT_IPSET: /* --ipset */
2619#ifndef HAVE_IPSET
2620 ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
2621 break;
2622#else
2623 {
2624 struct ipsets ipsets_head;
2625 struct ipsets *ipsets = &ipsets_head;
2626 int size;
2627 char *end;
2628 char **sets, **sets_pos;
2629 memset(ipsets, 0, sizeof(struct ipsets));
2630 unhide_metas(arg);
2631 if (arg && *arg == '/')
2632 {
2633 arg++;
2634 while ((end = split_chr(arg, '/')))
2635 {
2636 char *domain = NULL;
2637 /* elide leading dots - they are implied in the search algorithm */
2638 while (*arg == '.')
2639 arg++;
2640 /* # matches everything and becomes a zero length domain string */
2641 if (strcmp(arg, "#") == 0 || !*arg)
2642 domain = "";
2643 else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg)))
Simon Kelleya3bd7e72018-07-19 22:00:08 +01002644 ret_err(gen_err);
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002645 ipsets->next = opt_malloc(sizeof(struct ipsets));
2646 ipsets = ipsets->next;
2647 memset(ipsets, 0, sizeof(struct ipsets));
2648 ipsets->domain = domain;
2649 arg = end;
2650 }
2651 }
2652 else
2653 {
2654 ipsets->next = opt_malloc(sizeof(struct ipsets));
2655 ipsets = ipsets->next;
2656 memset(ipsets, 0, sizeof(struct ipsets));
2657 ipsets->domain = "";
2658 }
Simon Kelleya3bd7e72018-07-19 22:00:08 +01002659
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002660 if (!arg || !*arg)
Simon Kelleya3bd7e72018-07-19 22:00:08 +01002661 ret_err(gen_err);
2662
2663 for (size = 2, end = arg; *end; ++end)
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +00002664 if (*end == ',')
2665 ++size;
2666
2667 sets = sets_pos = opt_malloc(sizeof(char *) * size);
2668
2669 do {
2670 end = split(arg);
2671 *sets_pos++ = opt_string_alloc(arg);
2672 arg = end;
2673 } while (end);
2674 *sets_pos = 0;
2675 for (ipsets = &ipsets_head; ipsets->next; ipsets = ipsets->next)
2676 ipsets->next->sets = sets;
2677 ipsets->next = daemon->ipsets;
2678 daemon->ipsets = ipsets_head.next;
2679
2680 break;
2681 }
2682#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002683
Simon Kelleyf2621c72007-04-29 19:47:21 +01002684 case 'c': /* --cache-size */
Simon Kelley849a8352006-06-09 21:02:31 +01002685 {
2686 int size;
2687
2688 if (!atoi_check(arg, &size))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002689 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002690 else
2691 {
2692 /* zero is OK, and means no caching. */
2693
2694 if (size < 0)
2695 size = 0;
Simon Kelley248efe82019-08-20 23:36:49 +01002696
2697 /* Note that for very large cache sizes, the malloc()
2698 will overflow. For the size of the cache record
2699 at the time this was noted, the value of "very large"
2700 was 46684428. Limit to an order of magnitude less than
2701 that to be safe from changes to the cache record. */
2702 if (size > 5000000)
2703 size = 5000000;
Simon Kelley849a8352006-06-09 21:02:31 +01002704
2705 daemon->cachesize = size;
2706 }
2707 break;
2708 }
2709
Simon Kelleyf2621c72007-04-29 19:47:21 +01002710 case 'p': /* --port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002711 if (!atoi_check16(arg, &daemon->port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002712 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002713 break;
Simon Kelley208b65c2006-08-05 21:41:37 +01002714
Simon Kelley1a6bca82008-07-11 11:11:42 +01002715 case LOPT_MINPORT: /* --min-port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002716 if (!atoi_check16(arg, &daemon->min_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002717 ret_err(gen_err);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002718 break;
2719
Hans Dedecker926332a2016-01-23 10:48:12 +00002720 case LOPT_MAXPORT: /* --max-port */
2721 if (!atoi_check16(arg, &daemon->max_port))
2722 ret_err(gen_err);
2723 break;
2724
Simon Kelleyf2621c72007-04-29 19:47:21 +01002725 case '0': /* --dns-forward-max */
Simon Kelley208b65c2006-08-05 21:41:37 +01002726 if (!atoi_check(arg, &daemon->ftabsize))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002727 ret_err(gen_err);
Simon Kelley208b65c2006-08-05 21:41:37 +01002728 break;
2729
Simon Kelley25cf5e32015-01-09 15:53:03 +00002730 case 'q': /* --log-queries */
2731 set_option_bool(OPT_LOG);
2732 if (arg && strcmp(arg, "extra") == 0)
2733 set_option_bool(OPT_EXTRALOG);
2734 break;
2735
Simon Kelleyf2621c72007-04-29 19:47:21 +01002736 case LOPT_MAX_LOGS: /* --log-async */
2737 daemon->max_logs = LOG_MAX; /* default */
2738 if (arg && !atoi_check(arg, &daemon->max_logs))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002739 ret_err(gen_err);
Simon Kelleyf2621c72007-04-29 19:47:21 +01002740 else if (daemon->max_logs > 100)
2741 daemon->max_logs = 100;
2742 break;
2743
2744 case 'P': /* --edns-packet-max */
Simon Kelley849a8352006-06-09 21:02:31 +01002745 {
2746 int i;
2747 if (!atoi_check(arg, &i))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002748 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002749 daemon->edns_pktsz = (unsigned short)i;
2750 break;
2751 }
2752
Simon Kelleyf2621c72007-04-29 19:47:21 +01002753 case 'Q': /* --query-port */
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002754 if (!atoi_check16(arg, &daemon->query_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002755 ret_err(gen_err);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002756 /* if explicitly set to zero, use single OS ephemeral port
2757 and disable random ports */
2758 if (daemon->query_port == 0)
2759 daemon->osport = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01002760 break;
2761
Simon Kelley824af852008-02-12 20:43:05 +00002762 case 'T': /* --local-ttl */
2763 case LOPT_NEGTTL: /* --neg-ttl */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002764 case LOPT_MAXTTL: /* --max-ttl */
RinSatsuki28de3872015-01-10 15:22:21 +00002765 case LOPT_MINCTTL: /* --min-cache-ttl */
Simon Kelley1d860412012-09-20 20:48:04 +01002766 case LOPT_MAXCTTL: /* --max-cache-ttl */
Simon Kelley4f7b3042012-11-28 21:27:02 +00002767 case LOPT_AUTHTTL: /* --auth-ttl */
Simon Kelley832e47b2016-02-24 21:24:45 +00002768 case LOPT_DHCPTTL: /* --dhcp-ttl */
Simon Kelley849a8352006-06-09 21:02:31 +01002769 {
2770 int ttl;
2771 if (!atoi_check(arg, &ttl))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002772 ret_err(gen_err);
Simon Kelley824af852008-02-12 20:43:05 +00002773 else if (option == LOPT_NEGTTL)
2774 daemon->neg_ttl = (unsigned long)ttl;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002775 else if (option == LOPT_MAXTTL)
2776 daemon->max_ttl = (unsigned long)ttl;
RinSatsuki28de3872015-01-10 15:22:21 +00002777 else if (option == LOPT_MINCTTL)
2778 {
2779 if (ttl > TTL_FLOOR_LIMIT)
2780 ttl = TTL_FLOOR_LIMIT;
2781 daemon->min_cache_ttl = (unsigned long)ttl;
2782 }
Simon Kelley1d860412012-09-20 20:48:04 +01002783 else if (option == LOPT_MAXCTTL)
2784 daemon->max_cache_ttl = (unsigned long)ttl;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002785 else if (option == LOPT_AUTHTTL)
2786 daemon->auth_ttl = (unsigned long)ttl;
Simon Kelley832e47b2016-02-24 21:24:45 +00002787 else if (option == LOPT_DHCPTTL)
2788 {
2789 daemon->dhcp_ttl = (unsigned long)ttl;
2790 daemon->use_dhcp_ttl = 1;
2791 }
Simon Kelley849a8352006-06-09 21:02:31 +01002792 else
2793 daemon->local_ttl = (unsigned long)ttl;
2794 break;
2795 }
2796
Simon Kelley7622fc02009-06-04 20:32:05 +01002797#ifdef HAVE_DHCP
Simon Kelleyf2621c72007-04-29 19:47:21 +01002798 case 'X': /* --dhcp-lease-max */
Simon Kelley849a8352006-06-09 21:02:31 +01002799 if (!atoi_check(arg, &daemon->dhcp_max))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002800 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01002801 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01002802#endif
Simon Kelley849a8352006-06-09 21:02:31 +01002803
Simon Kelley7622fc02009-06-04 20:32:05 +01002804#ifdef HAVE_TFTP
Simon Kelleyf2621c72007-04-29 19:47:21 +01002805 case LOPT_TFTP_MAX: /* --tftp-max */
Simon Kelley832af0b2007-01-21 20:01:28 +00002806 if (!atoi_check(arg, &daemon->tftp_max))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002807 ret_err(gen_err);
Simon Kelley832af0b2007-01-21 20:01:28 +00002808 break;
2809
Simon Kelleybec366b2016-02-24 22:03:26 +00002810 case LOPT_TFTP_MTU: /* --tftp-mtu */
2811 if (!atoi_check(arg, &daemon->tftp_mtu))
2812 ret_err(gen_err);
2813 break;
2814
Simon Kelley824af852008-02-12 20:43:05 +00002815 case LOPT_PREFIX: /* --tftp-prefix */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01002816 comma = split(arg);
2817 if (comma)
2818 {
2819 struct tftp_prefix *new = opt_malloc(sizeof(struct tftp_prefix));
2820 new->interface = opt_string_alloc(comma);
2821 new->prefix = opt_string_alloc(arg);
2822 new->next = daemon->if_prefix;
2823 daemon->if_prefix = new;
2824 }
2825 else
2826 daemon->tftp_prefix = opt_string_alloc(arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00002827 break;
2828
Simon Kelley824af852008-02-12 20:43:05 +00002829 case LOPT_TFTPPORTS: /* --tftp-port-range */
2830 if (!(comma = split(arg)) ||
Simon Kelley1ad24ae2008-07-20 20:22:50 +01002831 !atoi_check16(arg, &daemon->start_tftp_port) ||
2832 !atoi_check16(comma, &daemon->end_tftp_port))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002833 ret_err(_("bad port range"));
Simon Kelley824af852008-02-12 20:43:05 +00002834
2835 if (daemon->start_tftp_port > daemon->end_tftp_port)
2836 {
2837 int tmp = daemon->start_tftp_port;
2838 daemon->start_tftp_port = daemon->end_tftp_port;
2839 daemon->end_tftp_port = tmp;
2840 }
2841
2842 break;
Floris Bos60704f52017-04-09 22:22:49 +01002843
2844 case LOPT_APREF: /* --tftp-unique-root */
2845 if (!arg || strcasecmp(arg, "ip") == 0)
2846 set_option_bool(OPT_TFTP_APREF_IP);
2847 else if (strcasecmp(arg, "mac") == 0)
2848 set_option_bool(OPT_TFTP_APREF_MAC);
2849 else
2850 ret_err(gen_err);
2851 break;
Simon Kelley7622fc02009-06-04 20:32:05 +01002852#endif
Simon Kelley824af852008-02-12 20:43:05 +00002853
Simon Kelleyf2621c72007-04-29 19:47:21 +01002854 case LOPT_BRIDGE: /* --bridge-interface */
Simon Kelley832af0b2007-01-21 20:01:28 +00002855 {
Simon Kelley22cd8602018-01-14 22:57:14 +00002856 struct dhcp_bridge *new;
2857
Simon Kelley316e2732010-01-22 20:16:09 +00002858 if (!(comma = split(arg)) || strlen(arg) > IF_NAMESIZE - 1 )
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002859 ret_err(_("bad bridge-interface"));
Simon Kelley832af0b2007-01-21 20:01:28 +00002860
Simon Kelley22cd8602018-01-14 22:57:14 +00002861 for (new = daemon->bridges; new; new = new->next)
2862 if (strcmp(new->iface, arg) == 0)
2863 break;
2864
2865 if (!new)
2866 {
2867 new = opt_malloc(sizeof(struct dhcp_bridge));
2868 strcpy(new->iface, arg);
2869 new->alias = NULL;
2870 new->next = daemon->bridges;
2871 daemon->bridges = new;
2872 }
2873
Simon Kelley832af0b2007-01-21 20:01:28 +00002874 do {
Simon Kelleyf2621c72007-04-29 19:47:21 +01002875 arg = comma;
2876 comma = split(arg);
Simon Kelley316e2732010-01-22 20:16:09 +00002877 if (strlen(arg) != 0 && strlen(arg) <= IF_NAMESIZE - 1)
Simon Kelley832af0b2007-01-21 20:01:28 +00002878 {
Simon Kelley824af852008-02-12 20:43:05 +00002879 struct dhcp_bridge *b = opt_malloc(sizeof(struct dhcp_bridge));
Simon Kelley832af0b2007-01-21 20:01:28 +00002880 b->next = new->alias;
2881 new->alias = b;
Simon Kelley316e2732010-01-22 20:16:09 +00002882 strcpy(b->iface, arg);
Simon Kelley832af0b2007-01-21 20:01:28 +00002883 }
2884 } while (comma);
2885
2886 break;
2887 }
Simon Kelley832af0b2007-01-21 20:01:28 +00002888
Simon Kelley7622fc02009-06-04 20:32:05 +01002889#ifdef HAVE_DHCP
Simon Kelleyae5b7e02019-03-27 22:33:28 +00002890 case LOPT_SHARED_NET: /* --shared-network */
2891 {
2892 struct shared_network *new = opt_malloc(sizeof(struct shared_network));
2893
2894#ifdef HAVE_DHCP6
2895 new->shared_addr.s_addr = 0;
2896#endif
2897 new->if_index = 0;
2898
2899 if (!(comma = split(arg)))
2900 {
2901 snerr:
2902 free(new);
2903 ret_err(_("bad shared-network"));
2904 }
2905
2906 if (inet_pton(AF_INET, comma, &new->shared_addr))
2907 {
2908 if (!inet_pton(AF_INET, arg, &new->match_addr) &&
2909 !(new->if_index = if_nametoindex(arg)))
2910 goto snerr;
2911 }
2912#ifdef HAVE_DHCP6
2913 else if (inet_pton(AF_INET6, comma, &new->shared_addr6))
2914 {
2915 if (!inet_pton(AF_INET6, arg, &new->match_addr6) &&
2916 !(new->if_index = if_nametoindex(arg)))
2917 goto snerr;
2918 }
2919#endif
2920 else
2921 goto snerr;
2922
2923 new->next = daemon->shared_networks;
2924 daemon->shared_networks = new;
2925 break;
2926 }
2927
Simon Kelleyf2621c72007-04-29 19:47:21 +01002928 case 'F': /* --dhcp-range */
Simon Kelley849a8352006-06-09 21:02:31 +01002929 {
2930 int k, leasepos = 2;
Simon Kelley8445f5d2012-12-17 21:54:08 +00002931 char *cp, *a[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
Simon Kelley824af852008-02-12 20:43:05 +00002932 struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
Simon Kelley849a8352006-06-09 21:02:31 +01002933
Simon Kelley52b92f42012-01-22 16:05:15 +00002934 memset (new, 0, sizeof(*new));
Simon Kelley849a8352006-06-09 21:02:31 +01002935 new->lease_time = DEFLEASE;
Simon Kelley52b92f42012-01-22 16:05:15 +00002936
Simon Kelley849a8352006-06-09 21:02:31 +01002937 while(1)
2938 {
2939 for (cp = arg; *cp; cp++)
Simon Kelley52b92f42012-01-22 16:05:15 +00002940 if (!(*cp == ' ' || *cp == '.' || *cp == ':' ||
2941 (*cp >= 'a' && *cp <= 'f') || (*cp >= 'A' && *cp <= 'F') ||
2942 (*cp >='0' && *cp <= '9')))
Simon Kelley849a8352006-06-09 21:02:31 +01002943 break;
2944
Simon Kelleyf2621c72007-04-29 19:47:21 +01002945 if (*cp != ',' && (comma = split(arg)))
Simon Kelley849a8352006-06-09 21:02:31 +01002946 {
Simon Kelley8bc4cec2012-07-03 21:04:11 +01002947 if (is_tag_prefix(arg))
Simon Kelley849a8352006-06-09 21:02:31 +01002948 {
Simon Kelley0c387192013-09-05 10:21:12 +01002949 /* ignore empty tag */
Petr Menšík59e47032018-11-02 22:39:39 +00002950 if (arg[4])
2951 new->filter = dhcp_netid_create(arg+4, new->filter);
Simon Kelley849a8352006-06-09 21:02:31 +01002952 }
2953 else
2954 {
2955 if (new->netid.net)
Petr Menšík59e47032018-11-02 22:39:39 +00002956 {
2957 dhcp_context_free(new);
2958 ret_err(_("only one tag allowed"));
2959 }
Simon Kelley849a8352006-06-09 21:02:31 +01002960 else
Petr Menšík59e47032018-11-02 22:39:39 +00002961 new->netid.net = opt_string_alloc(set_prefix(arg));
Simon Kelley849a8352006-06-09 21:02:31 +01002962 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01002963 arg = comma;
Simon Kelley849a8352006-06-09 21:02:31 +01002964 }
2965 else
2966 {
2967 a[0] = arg;
2968 break;
2969 }
2970 }
2971
Simon Kelley1f776932012-12-16 19:46:08 +00002972 for (k = 1; k < 8; k++)
Simon Kelleyf2621c72007-04-29 19:47:21 +01002973 if (!(a[k] = split(a[k-1])))
2974 break;
Simon Kelley849a8352006-06-09 21:02:31 +01002975
Simon Kelley52b92f42012-01-22 16:05:15 +00002976 if (k < 2)
Petr Menšík59e47032018-11-02 22:39:39 +00002977 {
2978 dhcp_context_free(new);
2979 ret_err(_("bad dhcp-range"));
2980 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01002981
2982 if (inet_pton(AF_INET, a[0], &new->start))
Simon Kelley849a8352006-06-09 21:02:31 +01002983 {
Simon Kelley52b92f42012-01-22 16:05:15 +00002984 new->next = daemon->dhcp;
2985 daemon->dhcp = new;
Simon Kelley30cd9662012-03-25 20:44:38 +01002986 new->end = new->start;
Simon Kelley52b92f42012-01-22 16:05:15 +00002987 if (strcmp(a[1], "static") == 0)
Simon Kelley30cd9662012-03-25 20:44:38 +01002988 new->flags |= CONTEXT_STATIC;
Simon Kelley52b92f42012-01-22 16:05:15 +00002989 else if (strcmp(a[1], "proxy") == 0)
Simon Kelley30cd9662012-03-25 20:44:38 +01002990 new->flags |= CONTEXT_PROXY;
2991 else if (!inet_pton(AF_INET, a[1], &new->end))
Petr Menšík59e47032018-11-02 22:39:39 +00002992 {
2993 dhcp_context_free(new);
2994 ret_err(_("bad dhcp-range"));
2995 }
Simon Kelley52b92f42012-01-22 16:05:15 +00002996
2997 if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
2998 {
2999 struct in_addr tmp = new->start;
3000 new->start = new->end;
3001 new->end = tmp;
3002 }
3003
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003004 if (k >= 3 && strchr(a[2], '.') &&
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003005 (inet_pton(AF_INET, a[2], &new->netmask) > 0))
Simon Kelley52b92f42012-01-22 16:05:15 +00003006 {
3007 new->flags |= CONTEXT_NETMASK;
3008 leasepos = 3;
3009 if (!is_same_net(new->start, new->end, new->netmask))
Petr Menšík59e47032018-11-02 22:39:39 +00003010 {
3011 dhcp_context_free(new);
3012 ret_err(_("inconsistent DHCP range"));
3013 }
Simon Kelleyfa794662016-03-03 20:33:54 +00003014
Simon Kelley52b92f42012-01-22 16:05:15 +00003015
Simon Kelleyfa794662016-03-03 20:33:54 +00003016 if (k >= 4 && strchr(a[3], '.') &&
3017 (inet_pton(AF_INET, a[3], &new->broadcast) > 0))
3018 {
3019 new->flags |= CONTEXT_BRDCAST;
3020 leasepos = 4;
3021 }
Simon Kelley52b92f42012-01-22 16:05:15 +00003022 }
Simon Kelley849a8352006-06-09 21:02:31 +01003023 }
Simon Kelley52b92f42012-01-22 16:05:15 +00003024#ifdef HAVE_DHCP6
3025 else if (inet_pton(AF_INET6, a[0], &new->start6))
Simon Kelley7622fc02009-06-04 20:32:05 +01003026 {
Petr Menšík59e47032018-11-02 22:39:39 +00003027 const char *err = NULL;
3028
Simon Kelley89500e32013-09-20 16:29:20 +01003029 new->flags |= CONTEXT_V6;
Simon Kelley52b92f42012-01-22 16:05:15 +00003030 new->prefix = 64; /* default */
Simon Kelley30cd9662012-03-25 20:44:38 +01003031 new->end6 = new->start6;
Simon Kelley6692a1a2013-08-20 14:41:31 +01003032 new->next = daemon->dhcp6;
3033 daemon->dhcp6 = new;
3034
Simon Kelley30cd9662012-03-25 20:44:38 +01003035 for (leasepos = 1; leasepos < k; leasepos++)
3036 {
3037 if (strcmp(a[leasepos], "static") == 0)
3038 new->flags |= CONTEXT_STATIC | CONTEXT_DHCP;
3039 else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 )
Simon Kelley7ea3d3f2014-04-25 22:04:05 +01003040 new->flags |= CONTEXT_RA;
Simon Kelley30cd9662012-03-25 20:44:38 +01003041 else if (strcmp(a[leasepos], "ra-names") == 0)
Simon Kelley1f776932012-12-16 19:46:08 +00003042 new->flags |= CONTEXT_RA_NAME | CONTEXT_RA;
Simon Kelley7ea3d3f2014-04-25 22:04:05 +01003043 else if (strcmp(a[leasepos], "ra-advrouter") == 0)
3044 new->flags |= CONTEXT_RA_ROUTER | CONTEXT_RA;
Simon Kelley30cd9662012-03-25 20:44:38 +01003045 else if (strcmp(a[leasepos], "ra-stateless") == 0)
Simon Kelley1f776932012-12-16 19:46:08 +00003046 new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA;
Neil Jerram2fd5bc92015-06-10 22:13:06 +01003047 else if (strcmp(a[leasepos], "off-link") == 0)
3048 new->flags |= CONTEXT_RA_OFF_LINK;
Simon Kelley30cd9662012-03-25 20:44:38 +01003049 else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6))
3050 new->flags |= CONTEXT_DHCP;
Simon Kelley1f776932012-12-16 19:46:08 +00003051 else if (strstr(a[leasepos], "constructor:") == a[leasepos])
3052 {
3053 new->template_interface = opt_string_alloc(a[leasepos] + 12);
3054 new->flags |= CONTEXT_TEMPLATE;
3055 }
Simon Kelley30cd9662012-03-25 20:44:38 +01003056 else
3057 break;
3058 }
Simon Kelley6692a1a2013-08-20 14:41:31 +01003059
Simon Kelley52b92f42012-01-22 16:05:15 +00003060 /* bare integer < 128 is prefix value */
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003061 if (leasepos < k)
Simon Kelley52b92f42012-01-22 16:05:15 +00003062 {
3063 int pref;
Simon Kelley30cd9662012-03-25 20:44:38 +01003064 for (cp = a[leasepos]; *cp; cp++)
Simon Kelley52b92f42012-01-22 16:05:15 +00003065 if (!(*cp >= '0' && *cp <= '9'))
3066 break;
Simon Kelley30cd9662012-03-25 20:44:38 +01003067 if (!*cp && (pref = atoi(a[leasepos])) <= 128)
Simon Kelley52b92f42012-01-22 16:05:15 +00003068 {
3069 new->prefix = pref;
Simon Kelley30cd9662012-03-25 20:44:38 +01003070 leasepos++;
Simon Kelley52b92f42012-01-22 16:05:15 +00003071 }
3072 }
Simon Kelley30cd9662012-03-25 20:44:38 +01003073
Petr Menšík59e47032018-11-02 22:39:39 +00003074 if (new->prefix > 64)
Simon Kelley6692a1a2013-08-20 14:41:31 +01003075 {
Simon Kelley7ea3d3f2014-04-25 22:04:05 +01003076 if (new->flags & CONTEXT_RA)
Petr Menšík59e47032018-11-02 22:39:39 +00003077 err=(_("prefix length must be exactly 64 for RA subnets"));
Simon Kelley6692a1a2013-08-20 14:41:31 +01003078 else if (new->flags & CONTEXT_TEMPLATE)
Petr Menšík59e47032018-11-02 22:39:39 +00003079 err=(_("prefix length must be exactly 64 for subnet constructors"));
Simon Kelley6692a1a2013-08-20 14:41:31 +01003080 }
Petr Menšík59e47032018-11-02 22:39:39 +00003081 else if (new->prefix < 64)
3082 err=(_("prefix length must be at least 64"));
Simon Kelley6692a1a2013-08-20 14:41:31 +01003083
Petr Menšík59e47032018-11-02 22:39:39 +00003084 if (!err && !is_same_net6(&new->start6, &new->end6, new->prefix))
3085 err=(_("inconsistent DHCPv6 range"));
3086
3087 if (err)
3088 {
3089 dhcp_context_free(new);
3090 ret_err(err);
3091 }
Simon Kelley6692a1a2013-08-20 14:41:31 +01003092
3093 /* dhcp-range=:: enables DHCP stateless on any interface */
3094 if (IN6_IS_ADDR_UNSPECIFIED(&new->start6) && !(new->flags & CONTEXT_TEMPLATE))
3095 new->prefix = 0;
Simon Kelley66409192013-08-01 20:19:32 +01003096
3097 if (new->flags & CONTEXT_TEMPLATE)
3098 {
3099 struct in6_addr zero;
3100 memset(&zero, 0, sizeof(zero));
3101 if (!is_same_net6(&zero, &new->start6, new->prefix))
Petr Menšík59e47032018-11-02 22:39:39 +00003102 {
3103 dhcp_context_free(new);
3104 ret_err(_("prefix must be zero with \"constructor:\" argument"));
3105 }
Simon Kelley66409192013-08-01 20:19:32 +01003106 }
3107
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003108 if (addr6part(&new->start6) > addr6part(&new->end6))
Simon Kelley52b92f42012-01-22 16:05:15 +00003109 {
3110 struct in6_addr tmp = new->start6;
3111 new->start6 = new->end6;
3112 new->end6 = tmp;
3113 }
Simon Kelley849a8352006-06-09 21:02:31 +01003114 }
Simon Kelley52b92f42012-01-22 16:05:15 +00003115#endif
Simon Kelleyd9ee9c02013-04-12 11:17:55 +01003116 else
Petr Menšík59e47032018-11-02 22:39:39 +00003117 {
3118 dhcp_context_free(new);
3119 ret_err(_("bad dhcp-range"));
3120 }
Simon Kelley849a8352006-06-09 21:02:31 +01003121
Simon Kelley30cd9662012-03-25 20:44:38 +01003122 if (leasepos < k)
Simon Kelley849a8352006-06-09 21:02:31 +01003123 {
Simon Kelleyfa794662016-03-03 20:33:54 +00003124 if (leasepos != k-1)
Petr Menšík59e47032018-11-02 22:39:39 +00003125 {
3126 dhcp_context_free(new);
3127 ret_err(_("bad dhcp-range"));
3128 }
Simon Kelleyfa794662016-03-03 20:33:54 +00003129
Simon Kelley849a8352006-06-09 21:02:31 +01003130 if (strcmp(a[leasepos], "infinite") == 0)
3131 new->lease_time = 0xffffffff;
Simon Kelleyc8257542012-03-28 21:15:41 +01003132 else if (strcmp(a[leasepos], "deprecated") == 0)
3133 new->flags |= CONTEXT_DEPRECATE;
Simon Kelley849a8352006-06-09 21:02:31 +01003134 else
3135 {
3136 int fac = 1;
3137 if (strlen(a[leasepos]) > 0)
3138 {
3139 switch (a[leasepos][strlen(a[leasepos]) - 1])
3140 {
Simon Kelley42243212012-07-20 15:19:18 +01003141 case 'w':
3142 case 'W':
3143 fac *= 7;
3144 /* fall through */
Simon Kelley849a8352006-06-09 21:02:31 +01003145 case 'd':
3146 case 'D':
3147 fac *= 24;
Simon Kelley87e00fe2018-02-16 21:27:35 +00003148 /* fall through */
Simon Kelley849a8352006-06-09 21:02:31 +01003149 case 'h':
3150 case 'H':
3151 fac *= 60;
3152 /* fall through */
3153 case 'm':
3154 case 'M':
3155 fac *= 60;
3156 /* fall through */
3157 case 's':
3158 case 'S':
Simon Kelleyf2621c72007-04-29 19:47:21 +01003159 a[leasepos][strlen(a[leasepos]) - 1] = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01003160 }
3161
Simon Kelleybe379862012-12-23 12:01:39 +00003162 for (cp = a[leasepos]; *cp; cp++)
3163 if (!(*cp >= '0' && *cp <= '9'))
3164 break;
3165
Simon Kelley54dae552013-02-05 17:55:10 +00003166 if (*cp || (leasepos+1 < k))
Petr Menšík59e47032018-11-02 22:39:39 +00003167 ret_err_free(_("bad dhcp-range"), new);
Simon Kelleybe379862012-12-23 12:01:39 +00003168
Simon Kelley849a8352006-06-09 21:02:31 +01003169 new->lease_time = atoi(a[leasepos]) * fac;
3170 /* Leases of a minute or less confuse
3171 some clients, notably Apple's */
3172 if (new->lease_time < 120)
3173 new->lease_time = 120;
3174 }
3175 }
3176 }
3177 break;
3178 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01003179
Simon Kelley5aabfc72007-08-29 11:24:47 +01003180 case LOPT_BANK:
Simon Kelleyf2621c72007-04-29 19:47:21 +01003181 case 'G': /* --dhcp-host */
Simon Kelley849a8352006-06-09 21:02:31 +01003182 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01003183 int j, k = 0;
Simon Kelley3e8ed782013-05-29 14:31:33 +01003184 char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
Simon Kelley5aabfc72007-08-29 11:24:47 +01003185 struct dhcp_config *new;
Simon Kelley849a8352006-06-09 21:02:31 +01003186 struct in_addr in;
3187
Simon Kelley824af852008-02-12 20:43:05 +00003188 new = opt_malloc(sizeof(struct dhcp_config));
3189
Simon Kelley849a8352006-06-09 21:02:31 +01003190 new->next = daemon->dhcp_conf;
Simon Kelley9009d742008-11-14 20:04:27 +00003191 new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
3192 new->hwaddr = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003193 new->netid = NULL;
Petr Menšík59e47032018-11-02 22:39:39 +00003194 new->clid = NULL;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003195
Simon Kelley849a8352006-06-09 21:02:31 +01003196 if ((a[0] = arg))
Simon Kelley3e8ed782013-05-29 14:31:33 +01003197 for (k = 1; k < 7; k++)
Simon Kelleyf2621c72007-04-29 19:47:21 +01003198 if (!(a[k] = split(a[k-1])))
3199 break;
Simon Kelley849a8352006-06-09 21:02:31 +01003200
3201 for (j = 0; j < k; j++)
3202 if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
3203 {
3204 char *arg = a[j];
3205
3206 if ((arg[0] == 'i' || arg[0] == 'I') &&
3207 (arg[1] == 'd' || arg[1] == 'D') &&
3208 arg[2] == ':')
3209 {
3210 if (arg[3] == '*')
3211 new->flags |= CONFIG_NOCLID;
3212 else
3213 {
3214 int len;
3215 arg += 3; /* dump id: */
3216 if (strchr(arg, ':'))
3217 len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
3218 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01003219 {
3220 unhide_metas(arg);
3221 len = (int) strlen(arg);
3222 }
3223
Simon Kelley28866e92011-02-14 20:19:14 +00003224 if (len == -1)
Petr Menšík59e47032018-11-02 22:39:39 +00003225 {
3226 dhcp_config_free(new);
3227 ret_err(_("bad hex constant"));
3228 }
Simon Kelley28866e92011-02-14 20:19:14 +00003229 else if ((new->clid = opt_malloc(len)))
Simon Kelley5aabfc72007-08-29 11:24:47 +01003230 {
3231 new->flags |= CONFIG_CLID;
3232 new->clid_len = len;
3233 memcpy(new->clid, arg, len);
3234 }
Simon Kelley849a8352006-06-09 21:02:31 +01003235 }
3236 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003237 /* dhcp-host has strange backwards-compat needs. */
3238 else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg)
Simon Kelley849a8352006-06-09 21:02:31 +01003239 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003240 struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003241 newlist->next = new->netid;
3242 new->netid = newlist;
Petr Menšík59e47032018-11-02 22:39:39 +00003243 newlist->list = dhcp_netid_create(arg+4, NULL);
Simon Kelley849a8352006-06-09 21:02:31 +01003244 }
Simon Kelley7de060b2011-08-26 17:24:52 +01003245 else if (strstr(arg, "tag:") == arg)
Petr Menšík59e47032018-11-02 22:39:39 +00003246 {
3247
3248 dhcp_config_free(new);
3249 ret_err(_("cannot match tags in --dhcp-host"));
3250 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00003251#ifdef HAVE_DHCP6
3252 else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
3253 {
3254 arg[strlen(arg)-1] = 0;
3255 arg++;
3256
3257 if (!inet_pton(AF_INET6, arg, &new->addr6))
Petr Menšík59e47032018-11-02 22:39:39 +00003258 {
3259 dhcp_config_free(new);
3260 ret_err(_("bad IPv6 address"));
3261 }
Simon Kelley30393102013-01-17 16:34:16 +00003262
3263 for (i= 0; i < 8; i++)
3264 if (new->addr6.s6_addr[i] != 0)
3265 break;
3266
3267 /* set WILDCARD if network part all zeros */
3268 if (i == 8)
3269 new->flags |= CONFIG_WILDCARD;
Simon Kelley4cb1b322012-02-06 14:30:41 +00003270
3271 new->flags |= CONFIG_ADDR6;
3272 }
3273#endif
Simon Kelley7de060b2011-08-26 17:24:52 +01003274 else
Simon Kelley849a8352006-06-09 21:02:31 +01003275 {
Simon Kelley9009d742008-11-14 20:04:27 +00003276 struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
Simon Kelley28866e92011-02-14 20:19:14 +00003277 if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
3278 &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
Petr Menšík59e47032018-11-02 22:39:39 +00003279 {
3280 free(newhw);
3281 dhcp_config_free(new);
3282 ret_err(_("bad hex constant"));
3283 }
Simon Kelley28866e92011-02-14 20:19:14 +00003284 else
3285 {
Simon Kelley28866e92011-02-14 20:19:14 +00003286 newhw->next = new->hwaddr;
3287 new->hwaddr = newhw;
3288 }
Simon Kelley849a8352006-06-09 21:02:31 +01003289 }
3290 }
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003291 else if (strchr(a[j], '.') && (inet_pton(AF_INET, a[j], &in) > 0))
Simon Kelley849a8352006-06-09 21:02:31 +01003292 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003293 struct dhcp_config *configs;
3294
Simon Kelley849a8352006-06-09 21:02:31 +01003295 new->addr = in;
3296 new->flags |= CONFIG_ADDR;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003297
3298 /* If the same IP appears in more than one host config, then DISCOVER
3299 for one of the hosts will get the address, but REQUEST will be NAKed,
3300 since the address is reserved by the other one -> protocol loop. */
3301 for (configs = daemon->dhcp_conf; configs; configs = configs->next)
3302 if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr)
3303 {
3304 sprintf(errstr, _("duplicate dhcp-host IP address %s"), inet_ntoa(in));
3305 return 0;
3306 }
Simon Kelley849a8352006-06-09 21:02:31 +01003307 }
3308 else
3309 {
3310 char *cp, *lastp = NULL, last = 0;
Simon Kelley76ff4402013-12-17 16:29:14 +00003311 int fac = 1, isdig = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01003312
3313 if (strlen(a[j]) > 1)
3314 {
3315 lastp = a[j] + strlen(a[j]) - 1;
3316 last = *lastp;
3317 switch (last)
3318 {
Simon Kelley42243212012-07-20 15:19:18 +01003319 case 'w':
3320 case 'W':
3321 fac *= 7;
3322 /* fall through */
Simon Kelley849a8352006-06-09 21:02:31 +01003323 case 'd':
3324 case 'D':
3325 fac *= 24;
3326 /* fall through */
3327 case 'h':
3328 case 'H':
3329 fac *= 60;
3330 /* fall through */
3331 case 'm':
3332 case 'M':
3333 fac *= 60;
3334 /* fall through */
3335 case 's':
3336 case 'S':
3337 *lastp = 0;
3338 }
3339 }
3340
3341 for (cp = a[j]; *cp; cp++)
Simon Kelley76ff4402013-12-17 16:29:14 +00003342 if (isdigit((unsigned char)*cp))
3343 isdig = 1;
3344 else if (*cp != ' ')
Simon Kelley849a8352006-06-09 21:02:31 +01003345 break;
Simon Kelley76ff4402013-12-17 16:29:14 +00003346
Simon Kelley849a8352006-06-09 21:02:31 +01003347 if (*cp)
3348 {
3349 if (lastp)
3350 *lastp = last;
3351 if (strcmp(a[j], "infinite") == 0)
3352 {
3353 new->lease_time = 0xffffffff;
3354 new->flags |= CONFIG_TIME;
3355 }
3356 else if (strcmp(a[j], "ignore") == 0)
3357 new->flags |= CONFIG_DISABLE;
3358 else
3359 {
Simon Kelley1f15b812009-10-13 17:49:32 +01003360 if (!(new->hostname = canonicalise_opt(a[j])) ||
3361 !legal_hostname(new->hostname))
Petr Menšík59e47032018-11-02 22:39:39 +00003362 {
3363 dhcp_config_free(new);
3364 ret_err(_("bad DHCP host name"));
3365 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003366
3367 new->flags |= CONFIG_NAME;
3368 new->domain = strip_hostname(new->hostname);
Simon Kelley849a8352006-06-09 21:02:31 +01003369 }
3370 }
Simon Kelley76ff4402013-12-17 16:29:14 +00003371 else if (isdig)
Simon Kelley849a8352006-06-09 21:02:31 +01003372 {
3373 new->lease_time = atoi(a[j]) * fac;
3374 /* Leases of a minute or less confuse
3375 some clients, notably Apple's */
3376 if (new->lease_time < 120)
3377 new->lease_time = 120;
3378 new->flags |= CONFIG_TIME;
3379 }
3380 }
3381
Simon Kelley5aabfc72007-08-29 11:24:47 +01003382 daemon->dhcp_conf = new;
Simon Kelley849a8352006-06-09 21:02:31 +01003383 break;
3384 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003385
3386 case LOPT_TAG_IF: /* --tag-if */
3387 {
3388 struct tag_if *new = opt_malloc(sizeof(struct tag_if));
3389
3390 new->tag = NULL;
3391 new->set = NULL;
3392 new->next = NULL;
3393
3394 /* preserve order */
3395 if (!daemon->tag_if)
3396 daemon->tag_if = new;
3397 else
3398 {
3399 struct tag_if *tmp;
3400 for (tmp = daemon->tag_if; tmp->next; tmp = tmp->next);
3401 tmp->next = new;
3402 }
3403
3404 while (arg)
3405 {
3406 size_t len;
3407
3408 comma = split(arg);
3409 len = strlen(arg);
3410
3411 if (len < 5)
3412 {
3413 new->set = NULL;
3414 break;
3415 }
3416 else
3417 {
Petr Menšík59e47032018-11-02 22:39:39 +00003418 struct dhcp_netid *newtag = dhcp_netid_create(arg+4, NULL);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003419
3420 if (strstr(arg, "set:") == arg)
3421 {
3422 struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
3423 newlist->next = new->set;
3424 new->set = newlist;
3425 newlist->list = newtag;
3426 }
3427 else if (strstr(arg, "tag:") == arg)
3428 {
3429 newtag->next = new->tag;
3430 new->tag = newtag;
3431 }
3432 else
3433 {
3434 new->set = NULL;
Petr Menšík59e47032018-11-02 22:39:39 +00003435 dhcp_netid_free(newtag);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003436 break;
3437 }
3438 }
3439
3440 arg = comma;
3441 }
3442
3443 if (!new->set)
Petr Menšík59e47032018-11-02 22:39:39 +00003444 {
3445 dhcp_netid_free(new->tag);
3446 dhcp_netid_list_free(new->set);
3447 ret_err_free(_("bad tag-if"), new);
3448 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003449
3450 break;
3451 }
3452
Simon Kelley849a8352006-06-09 21:02:31 +01003453
Simon Kelley73a08a22009-02-05 20:28:08 +00003454 case 'O': /* --dhcp-option */
3455 case LOPT_FORCE: /* --dhcp-option-force */
Simon Kelley824af852008-02-12 20:43:05 +00003456 case LOPT_OPTS:
Simon Kelley73a08a22009-02-05 20:28:08 +00003457 case LOPT_MATCH: /* --dhcp-match */
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003458 return parse_dhcp_opt(errstr, arg,
3459 option == LOPT_FORCE ? DHOPT_FORCE :
3460 (option == LOPT_MATCH ? DHOPT_MATCH :
3461 (option == LOPT_OPTS ? DHOPT_BANK : 0)));
Simon Kelleyc8226202018-08-08 23:46:03 +01003462
3463 case LOPT_NAME_MATCH: /* --dhcp-name-match */
3464 {
3465 struct dhcp_match_name *new = opt_malloc(sizeof(struct dhcp_match_name));
3466 struct dhcp_netid *id = opt_malloc(sizeof(struct dhcp_netid));
3467 ssize_t len;
3468
3469 if (!(comma = split(arg)) || (len = strlen(comma)) == 0)
3470 ret_err(gen_err);
3471
3472 new->wildcard = 0;
3473 new->netid = id;
3474 id->net = opt_string_alloc(set_prefix(arg));
3475
3476 if (comma[len-1] == '*')
3477 {
3478 comma[len-1] = 0;
3479 new->wildcard = 1;
3480 }
3481 new->name = opt_string_alloc(comma);
3482
3483 new->next = daemon->dhcp_name_match;
3484 daemon->dhcp_name_match = new;
3485
3486 break;
3487 }
3488
Simon Kelleyf2621c72007-04-29 19:47:21 +01003489 case 'M': /* --dhcp-boot */
Simon Kelley849a8352006-06-09 21:02:31 +01003490 {
Petr Menšík59e47032018-11-02 22:39:39 +00003491 struct dhcp_netid *id = dhcp_tags(&arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003492
Petr Menšík137e9f82018-12-16 21:25:29 +00003493 if (!arg)
Petr Menšík59e47032018-11-02 22:39:39 +00003494 {
3495 ret_err(gen_err);
3496 }
Simon Kelley849a8352006-06-09 21:02:31 +01003497 else
3498 {
Simon Kelley7de060b2011-08-26 17:24:52 +01003499 char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +01003500 struct in_addr dhcp_next_server;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003501 struct dhcp_boot *new;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003502 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00003503 dhcp_file = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003504 dhcp_next_server.s_addr = 0;
3505 if (comma)
3506 {
3507 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01003508 comma = split(arg);
Simon Kelley824af852008-02-12 20:43:05 +00003509 dhcp_sname = opt_string_alloc(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01003510 if (comma)
3511 {
3512 unhide_metas(comma);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003513 if (!(inet_pton(AF_INET, comma, &dhcp_next_server) > 0))
3514 {
3515 /*
3516 * The user may have specified the tftp hostname here.
3517 * save it so that it can be resolved/looked up during
3518 * actual dhcp_reply().
3519 */
3520
3521 tftp_sname = opt_string_alloc(comma);
3522 dhcp_next_server.s_addr = 0;
3523 }
Simon Kelley849a8352006-06-09 21:02:31 +01003524 }
3525 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003526
3527 new = opt_malloc(sizeof(struct dhcp_boot));
3528 new->file = dhcp_file;
3529 new->sname = dhcp_sname;
3530 new->tftp_sname = tftp_sname;
3531 new->next_server = dhcp_next_server;
3532 new->netid = id;
3533 new->next = daemon->boot_config;
3534 daemon->boot_config = new;
Simon Kelley849a8352006-06-09 21:02:31 +01003535 }
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003536
Simon Kelley849a8352006-06-09 21:02:31 +01003537 break;
3538 }
Simon Kelley7622fc02009-06-04 20:32:05 +01003539
Floris Bos503c6092017-04-09 23:07:13 +01003540 case LOPT_REPLY_DELAY: /* --dhcp-reply-delay */
3541 {
Petr Menšík59e47032018-11-02 22:39:39 +00003542 struct dhcp_netid *id = dhcp_tags(&arg);
Floris Bos503c6092017-04-09 23:07:13 +01003543
Petr Menšík137e9f82018-12-16 21:25:29 +00003544 if (!arg)
Petr Menšík59e47032018-11-02 22:39:39 +00003545 {
3546 ret_err(gen_err);
3547 }
Floris Bos503c6092017-04-09 23:07:13 +01003548 else
3549 {
3550 struct delay_config *new;
3551 int delay;
3552 if (!atoi_check(arg, &delay))
3553 ret_err(gen_err);
3554
3555 new = opt_malloc(sizeof(struct delay_config));
3556 new->delay = delay;
3557 new->netid = id;
3558 new->next = daemon->delay_conf;
3559 daemon->delay_conf = new;
3560 }
3561
3562 break;
3563 }
3564
Simon Kelley7622fc02009-06-04 20:32:05 +01003565 case LOPT_PXE_PROMT: /* --pxe-prompt */
3566 {
3567 struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
3568 int timeout;
Floris Bos503c6092017-04-09 23:07:13 +01003569
Simon Kelley7622fc02009-06-04 20:32:05 +01003570 new->netid = NULL;
3571 new->opt = 10; /* PXE_MENU_PROMPT */
Petr Menšík59e47032018-11-02 22:39:39 +00003572 new->netid = dhcp_tags(&arg);
Simon Kelley7622fc02009-06-04 20:32:05 +01003573
Petr Menšík137e9f82018-12-16 21:25:29 +00003574 if (!arg)
Petr Menšík59e47032018-11-02 22:39:39 +00003575 {
3576 dhcp_opt_free(new);
3577 ret_err(gen_err);
3578 }
Simon Kelley7622fc02009-06-04 20:32:05 +01003579 else
3580 {
3581 comma = split(arg);
3582 unhide_metas(arg);
3583 new->len = strlen(arg) + 1;
3584 new->val = opt_malloc(new->len);
3585 memcpy(new->val + 1, arg, new->len - 1);
3586
3587 new->u.vendor_class = (unsigned char *)"PXEClient";
3588 new->flags = DHOPT_VENDOR;
3589
3590 if (comma && atoi_check(comma, &timeout))
3591 *(new->val) = timeout;
3592 else
3593 *(new->val) = 255;
3594
3595 new->next = daemon->dhcp_opts;
3596 daemon->dhcp_opts = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01003597 daemon->enable_pxe = 1;
Simon Kelley7622fc02009-06-04 20:32:05 +01003598 }
3599
3600 break;
3601 }
3602
3603 case LOPT_PXE_SERV: /* --pxe-service */
3604 {
3605 struct pxe_service *new = opt_malloc(sizeof(struct pxe_service));
3606 char *CSA[] = { "x86PC", "PC98", "IA64_EFI", "Alpha", "Arc_x86", "Intel_Lean_Client",
Simon Kelley68bea102016-05-11 22:15:06 +01003607 "IA32_EFI", "x86-64_EFI", "Xscale_EFI", "BC_EFI",
3608 "ARM32_EFI", "ARM64_EFI", NULL };
Simon Kelley7622fc02009-06-04 20:32:05 +01003609 static int boottype = 32768;
3610
3611 new->netid = NULL;
Simon Kelley751d6f42012-02-10 15:24:51 +00003612 new->sname = NULL;
Simon Kelley7622fc02009-06-04 20:32:05 +01003613 new->server.s_addr = 0;
Petr Menšík59e47032018-11-02 22:39:39 +00003614 new->netid = dhcp_tags(&arg);
Simon Kelley7622fc02009-06-04 20:32:05 +01003615
Simon Kelley7622fc02009-06-04 20:32:05 +01003616 if (arg && (comma = split(arg)))
3617 {
3618 for (i = 0; CSA[i]; i++)
3619 if (strcasecmp(CSA[i], arg) == 0)
3620 break;
3621
3622 if (CSA[i] || atoi_check(arg, &i))
3623 {
3624 arg = comma;
3625 comma = split(arg);
3626
3627 new->CSA = i;
3628 new->menu = opt_string_alloc(arg);
3629
Simon Kelley316e2732010-01-22 20:16:09 +00003630 if (!comma)
3631 {
3632 new->type = 0; /* local boot */
3633 new->basename = NULL;
3634 }
3635 else
Simon Kelley7622fc02009-06-04 20:32:05 +01003636 {
3637 arg = comma;
3638 comma = split(arg);
3639 if (atoi_check(arg, &i))
3640 {
3641 new->type = i;
3642 new->basename = NULL;
3643 }
3644 else
3645 {
3646 new->type = boottype++;
3647 new->basename = opt_string_alloc(arg);
3648 }
3649
Simon Kelley751d6f42012-02-10 15:24:51 +00003650 if (comma)
3651 {
3652 if (!inet_pton(AF_INET, comma, &new->server))
3653 {
3654 new->server.s_addr = 0;
3655 new->sname = opt_string_alloc(comma);
3656 }
3657
3658 }
Simon Kelley7622fc02009-06-04 20:32:05 +01003659 }
Simon Kelley751d6f42012-02-10 15:24:51 +00003660
Simon Kelley316e2732010-01-22 20:16:09 +00003661 /* Order matters */
3662 new->next = NULL;
3663 if (!daemon->pxe_services)
3664 daemon->pxe_services = new;
3665 else
3666 {
3667 struct pxe_service *s;
3668 for (s = daemon->pxe_services; s->next; s = s->next);
3669 s->next = new;
3670 }
3671
3672 daemon->enable_pxe = 1;
3673 break;
3674
Simon Kelley7622fc02009-06-04 20:32:05 +01003675 }
3676 }
3677
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003678 ret_err(gen_err);
Simon Kelley7622fc02009-06-04 20:32:05 +01003679 }
3680
Simon Kelleyf2621c72007-04-29 19:47:21 +01003681 case '4': /* --dhcp-mac */
Simon Kelley849a8352006-06-09 21:02:31 +01003682 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01003683 if (!(comma = split(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003684 ret_err(gen_err);
Simon Kelley849a8352006-06-09 21:02:31 +01003685 else
3686 {
Simon Kelley824af852008-02-12 20:43:05 +00003687 struct dhcp_mac *new = opt_malloc(sizeof(struct dhcp_mac));
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003688 new->netid.net = opt_string_alloc(set_prefix(arg));
Simon Kelleyf2621c72007-04-29 19:47:21 +01003689 unhide_metas(comma);
3690 new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
Simon Kelley28866e92011-02-14 20:19:14 +00003691 if (new->hwaddr_len == -1)
Petr Menšík59e47032018-11-02 22:39:39 +00003692 {
3693 free(new->netid.net);
3694 ret_err_free(gen_err, new);
3695 }
Simon Kelley28866e92011-02-14 20:19:14 +00003696 else
3697 {
3698 new->next = daemon->dhcp_macs;
3699 daemon->dhcp_macs = new;
3700 }
Simon Kelley849a8352006-06-09 21:02:31 +01003701 }
3702 }
3703 break;
Simon Kelleyc6309242013-03-07 20:59:28 +00003704
3705#ifdef OPTION6_PREFIX_CLASS
3706 case LOPT_PREF_CLSS: /* --dhcp-prefix-class */
3707 {
3708 struct prefix_class *new = opt_malloc(sizeof(struct prefix_class));
3709
3710 if (!(comma = split(arg)) ||
3711 !atoi_check16(comma, &new->class))
Petr Menšík59e47032018-11-02 22:39:39 +00003712 ret_err_free(gen_err, new);
Simon Kelleyc6309242013-03-07 20:59:28 +00003713
3714 new->tag.net = opt_string_alloc(set_prefix(arg));
3715 new->next = daemon->prefix_classes;
3716 daemon->prefix_classes = new;
3717
3718 break;
3719 }
3720#endif
3721
3722
Simon Kelleyf2621c72007-04-29 19:47:21 +01003723 case 'U': /* --dhcp-vendorclass */
3724 case 'j': /* --dhcp-userclass */
3725 case LOPT_CIRCUIT: /* --dhcp-circuitid */
3726 case LOPT_REMOTE: /* --dhcp-remoteid */
3727 case LOPT_SUBSCR: /* --dhcp-subscrid */
Simon Kelley849a8352006-06-09 21:02:31 +01003728 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003729 unsigned char *p;
3730 int dig = 0;
3731 struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
3732
3733 if (!(comma = split(arg)))
Petr Menšík59e47032018-11-02 22:39:39 +00003734 ret_err_free(gen_err, new);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003735
3736 new->netid.net = opt_string_alloc(set_prefix(arg));
3737 /* check for hex string - must digits may include : must not have nothing else,
3738 only allowed for agent-options. */
3739
3740 arg = comma;
3741 if ((comma = split(arg)))
3742 {
3743 if (option != 'U' || strstr(arg, "enterprise:") != arg)
Petr Menšík59e47032018-11-02 22:39:39 +00003744 {
3745 free(new->netid.net);
3746 ret_err_free(gen_err, new);
3747 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003748 else
3749 new->enterprise = atoi(arg+11);
3750 }
3751 else
3752 comma = arg;
3753
3754 for (p = (unsigned char *)comma; *p; p++)
3755 if (isxdigit(*p))
3756 dig = 1;
3757 else if (*p != ':')
3758 break;
3759 unhide_metas(comma);
3760 if (option == 'U' || option == 'j' || *p || !dig)
3761 {
3762 new->len = strlen(comma);
3763 new->data = opt_malloc(new->len);
3764 memcpy(new->data, comma, new->len);
3765 }
3766 else
3767 {
3768 new->len = parse_hex(comma, (unsigned char *)comma, strlen(comma), NULL, NULL);
3769 new->data = opt_malloc(new->len);
3770 memcpy(new->data, comma, new->len);
3771 }
3772
3773 switch (option)
3774 {
3775 case 'j':
3776 new->match_type = MATCH_USER;
3777 break;
3778 case 'U':
3779 new->match_type = MATCH_VENDOR;
3780 break;
3781 case LOPT_CIRCUIT:
3782 new->match_type = MATCH_CIRCUIT;
3783 break;
3784 case LOPT_REMOTE:
3785 new->match_type = MATCH_REMOTE;
3786 break;
3787 case LOPT_SUBSCR:
3788 new->match_type = MATCH_SUBSCRIBER;
3789 break;
3790 }
3791 new->next = daemon->dhcp_vendors;
3792 daemon->dhcp_vendors = new;
Simon Kelleya5c72ab2012-02-10 13:42:47 +00003793
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003794 break;
Simon Kelley849a8352006-06-09 21:02:31 +01003795 }
3796
Simon Kelley9e038942008-05-30 20:06:34 +01003797 case LOPT_ALTPORT: /* --dhcp-alternate-port */
3798 if (!arg)
3799 {
3800 daemon->dhcp_server_port = DHCP_SERVER_ALTPORT;
3801 daemon->dhcp_client_port = DHCP_CLIENT_ALTPORT;
3802 }
3803 else
3804 {
3805 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01003806 if (!atoi_check16(arg, &daemon->dhcp_server_port) ||
3807 (comma && !atoi_check16(comma, &daemon->dhcp_client_port)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003808 ret_err(_("invalid port number"));
Simon Kelley9e038942008-05-30 20:06:34 +01003809 if (!comma)
3810 daemon->dhcp_client_port = daemon->dhcp_server_port+1;
3811 }
3812 break;
3813
Simon Kelley824af852008-02-12 20:43:05 +00003814 case 'J': /* --dhcp-ignore */
3815 case LOPT_NO_NAMES: /* --dhcp-ignore-names */
3816 case LOPT_BROADCAST: /* --dhcp-broadcast */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003817 case '3': /* --bootp-dynamic */
3818 case LOPT_GEN_NAMES: /* --dhcp-generate-names */
Simon Kelley849a8352006-06-09 21:02:31 +01003819 {
Simon Kelley824af852008-02-12 20:43:05 +00003820 struct dhcp_netid_list *new = opt_malloc(sizeof(struct dhcp_netid_list));
Simon Kelley849a8352006-06-09 21:02:31 +01003821 struct dhcp_netid *list = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00003822 if (option == 'J')
3823 {
3824 new->next = daemon->dhcp_ignore;
3825 daemon->dhcp_ignore = new;
3826 }
Simon Kelley824af852008-02-12 20:43:05 +00003827 else if (option == LOPT_BROADCAST)
3828 {
3829 new->next = daemon->force_broadcast;
3830 daemon->force_broadcast = new;
3831 }
Simon Kelley9009d742008-11-14 20:04:27 +00003832 else if (option == '3')
3833 {
3834 new->next = daemon->bootp_dynamic;
3835 daemon->bootp_dynamic = new;
3836 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003837 else if (option == LOPT_GEN_NAMES)
3838 {
3839 new->next = daemon->dhcp_gen_names;
3840 daemon->dhcp_gen_names = new;
3841 }
Simon Kelley832af0b2007-01-21 20:01:28 +00003842 else
3843 {
3844 new->next = daemon->dhcp_ignore_names;
3845 daemon->dhcp_ignore_names = new;
3846 }
3847
3848 while (arg) {
Simon Kelleyf2621c72007-04-29 19:47:21 +01003849 comma = split(arg);
Petr Menšík59e47032018-11-02 22:39:39 +00003850 list = dhcp_netid_create(is_tag_prefix(arg) ? arg+4 :arg, list);
Simon Kelley849a8352006-06-09 21:02:31 +01003851 arg = comma;
Simon Kelley832af0b2007-01-21 20:01:28 +00003852 }
Simon Kelley849a8352006-06-09 21:02:31 +01003853
3854 new->list = list;
3855 break;
3856 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003857
3858 case LOPT_PROXY: /* --dhcp-proxy */
3859 daemon->override = 1;
3860 while (arg) {
3861 struct addr_list *new = opt_malloc(sizeof(struct addr_list));
3862 comma = split(arg);
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003863 if (!(inet_pton(AF_INET, arg, &new->addr) > 0))
Petr Menšík59e47032018-11-02 22:39:39 +00003864 ret_err_free(_("bad dhcp-proxy address"), new);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01003865 new->next = daemon->override_relays;
3866 daemon->override_relays = new;
3867 arg = comma;
3868 }
3869 break;
Simon Kelleyff7eea22013-09-04 18:01:38 +01003870
3871 case LOPT_RELAY: /* --dhcp-relay */
3872 {
3873 struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
3874 comma = split(arg);
3875 new->interface = opt_string_alloc(split(comma));
3876 new->iface_index = 0;
3877 if (inet_pton(AF_INET, arg, &new->local) && inet_pton(AF_INET, comma, &new->server))
3878 {
3879 new->next = daemon->relay4;
3880 daemon->relay4 = new;
3881 }
3882#ifdef HAVE_DHCP6
3883 else if (inet_pton(AF_INET6, arg, &new->local) && inet_pton(AF_INET6, comma, &new->server))
3884 {
3885 new->next = daemon->relay6;
3886 daemon->relay6 = new;
3887 }
3888#endif
3889 else
Petr Menšík59e47032018-11-02 22:39:39 +00003890 {
3891 free(new->interface);
3892 ret_err_free(_("Bad dhcp-relay"), new);
3893 }
Simon Kelleyff7eea22013-09-04 18:01:38 +01003894
3895 break;
3896 }
3897
Simon Kelley7622fc02009-06-04 20:32:05 +01003898#endif
Simon Kelley849a8352006-06-09 21:02:31 +01003899
Simon Kelley8b372702012-03-09 17:45:10 +00003900#ifdef HAVE_DHCP6
Simon Kelleyc4cd95d2013-10-10 20:58:11 +01003901 case LOPT_RA_PARAM: /* --ra-param */
3902 if ((comma = split(arg)))
3903 {
3904 struct ra_interface *new = opt_malloc(sizeof(struct ra_interface));
3905 new->lifetime = -1;
3906 new->prio = 0;
David Flamand005c46d2017-04-11 11:49:54 +01003907 new->mtu = 0;
Vladislav Grishenko6ec5f5c2017-04-24 22:34:45 +01003908 new->mtu_name = NULL;
Simon Kelleyc4cd95d2013-10-10 20:58:11 +01003909 new->name = opt_string_alloc(arg);
David Flamand005c46d2017-04-11 11:49:54 +01003910 if (strcasestr(comma, "mtu:") == comma)
3911 {
3912 arg = comma + 4;
3913 if (!(comma = split(comma)))
3914 goto err;
3915 if (!strcasecmp(arg, "off"))
3916 new->mtu = -1;
Vladislav Grishenko6ec5f5c2017-04-24 22:34:45 +01003917 else if (!atoi_check(arg, &new->mtu))
3918 new->mtu_name = opt_string_alloc(arg);
3919 else if (new->mtu < 1280)
David Flamand005c46d2017-04-11 11:49:54 +01003920 goto err;
3921 }
Simon Kelleyc4cd95d2013-10-10 20:58:11 +01003922 if (strcasestr(comma, "high") == comma || strcasestr(comma, "low") == comma)
3923 {
3924 if (*comma == 'l' || *comma == 'L')
3925 new->prio = 0x18;
3926 else
3927 new->prio = 0x08;
3928 comma = split(comma);
3929 }
3930 arg = split(comma);
3931 if (!atoi_check(comma, &new->interval) ||
3932 (arg && !atoi_check(arg, &new->lifetime)))
Petr Menšík59e47032018-11-02 22:39:39 +00003933 {
David Flamand005c46d2017-04-11 11:49:54 +01003934err:
Petr Menšík59e47032018-11-02 22:39:39 +00003935 free(new->name);
3936 ret_err_free(_("bad RA-params"), new);
3937 }
Simon Kelleyc4cd95d2013-10-10 20:58:11 +01003938
3939 new->next = daemon->ra_interfaces;
3940 daemon->ra_interfaces = new;
3941 }
3942 break;
3943
Simon Kelley8b372702012-03-09 17:45:10 +00003944 case LOPT_DUID: /* --dhcp-duid */
3945 if (!(comma = split(arg)) || !atoi_check(arg, (int *)&daemon->duid_enterprise))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003946 ret_err(_("bad DUID"));
Simon Kelley8b372702012-03-09 17:45:10 +00003947 else
3948 {
3949 daemon->duid_config_len = parse_hex(comma,(unsigned char *)comma, strlen(comma), NULL, NULL);
3950 daemon->duid_config = opt_malloc(daemon->duid_config_len);
3951 memcpy(daemon->duid_config, comma, daemon->duid_config_len);
3952 }
3953 break;
3954#endif
3955
Simon Kelleyf2621c72007-04-29 19:47:21 +01003956 case 'V': /* --alias */
Simon Kelley849a8352006-06-09 21:02:31 +01003957 {
Simon Kelley73a08a22009-02-05 20:28:08 +00003958 char *dash, *a[3] = { NULL, NULL, NULL };
Simon Kelleyf2621c72007-04-29 19:47:21 +01003959 int k = 0;
Simon Kelley73a08a22009-02-05 20:28:08 +00003960 struct doctor *new = opt_malloc(sizeof(struct doctor));
3961 new->next = daemon->doctors;
3962 daemon->doctors = new;
3963 new->mask.s_addr = 0xffffffff;
3964 new->end.s_addr = 0;
3965
Simon Kelley849a8352006-06-09 21:02:31 +01003966 if ((a[0] = arg))
3967 for (k = 1; k < 3; k++)
3968 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01003969 if (!(a[k] = split(a[k-1])))
Simon Kelley849a8352006-06-09 21:02:31 +01003970 break;
Simon Kelley849a8352006-06-09 21:02:31 +01003971 unhide_metas(a[k]);
3972 }
Simon Kelley849a8352006-06-09 21:02:31 +01003973
Simon Kelley73a08a22009-02-05 20:28:08 +00003974 dash = split_chr(a[0], '-');
3975
Simon Kelley849a8352006-06-09 21:02:31 +01003976 if ((k < 2) ||
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003977 (!(inet_pton(AF_INET, a[0], &new->in) > 0)) ||
Simon Kelleya3bd7e72018-07-19 22:00:08 +01003978 (!(inet_pton(AF_INET, a[1], &new->out) > 0)) ||
3979 (k == 3 && !inet_pton(AF_INET, a[2], &new->mask)))
3980 ret_err(_("missing address in alias"));
Simon Kelley849a8352006-06-09 21:02:31 +01003981
Simon Kelley73a08a22009-02-05 20:28:08 +00003982 if (dash &&
Simon Kelleyddd9a6b2013-04-29 17:00:21 +01003983 (!(inet_pton(AF_INET, dash, &new->end) > 0) ||
Simon Kelley73a08a22009-02-05 20:28:08 +00003984 !is_same_net(new->in, new->end, new->mask) ||
3985 ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
Petr Menšík59e47032018-11-02 22:39:39 +00003986 ret_err_free(_("invalid alias range"), new);
Simon Kelley849a8352006-06-09 21:02:31 +01003987
3988 break;
3989 }
3990
Simon Kelleyf2621c72007-04-29 19:47:21 +01003991 case LOPT_INTNAME: /* --interface-name */
3992 {
3993 struct interface_name *new, **up;
Simon Kelley1f15b812009-10-13 17:49:32 +01003994 char *domain = NULL;
3995
Simon Kelleyf2621c72007-04-29 19:47:21 +01003996 comma = split(arg);
3997
Simon Kelley1f15b812009-10-13 17:49:32 +01003998 if (!comma || !(domain = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01003999 ret_err(_("bad interface name"));
Simon Kelley1f15b812009-10-13 17:49:32 +01004000
Simon Kelley824af852008-02-12 20:43:05 +00004001 new = opt_malloc(sizeof(struct interface_name));
Simon Kelleyf2621c72007-04-29 19:47:21 +01004002 new->next = NULL;
Simon Kelley376d48c2013-11-13 13:04:30 +00004003 new->addr = NULL;
4004
Simon Kelleyf2621c72007-04-29 19:47:21 +01004005 /* Add to the end of the list, so that first name
4006 of an interface is used for PTR lookups. */
Simon Kelley824af852008-02-12 20:43:05 +00004007 for (up = &daemon->int_names; *up; up = &((*up)->next));
Simon Kelleyf2621c72007-04-29 19:47:21 +01004008 *up = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01004009 new->name = domain;
Simon Kelleyf7029f52013-11-21 15:09:09 +00004010 new->family = 0;
4011 arg = split_chr(comma, '/');
4012 if (arg)
4013 {
4014 if (strcmp(arg, "4") == 0)
4015 new->family = AF_INET;
Simon Kelleyf7029f52013-11-21 15:09:09 +00004016 else if (strcmp(arg, "6") == 0)
4017 new->family = AF_INET6;
Simon Kelleyf7029f52013-11-21 15:09:09 +00004018 else
Petr Menšík59e47032018-11-02 22:39:39 +00004019 ret_err_free(gen_err, new);
Simon Kelleyf7029f52013-11-21 15:09:09 +00004020 }
Simon Kelley824af852008-02-12 20:43:05 +00004021 new->intr = opt_string_alloc(comma);
Simon Kelleyf2621c72007-04-29 19:47:21 +01004022 break;
4023 }
Simon Kelley9009d742008-11-14 20:04:27 +00004024
4025 case LOPT_CNAME: /* --cname */
4026 {
4027 struct cname *new;
Simon Kelleya1d973f2016-12-22 22:09:50 +00004028 char *alias, *target, *last, *pen;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004029 int ttl = -1;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004030
Simon Kelleya1d973f2016-12-22 22:09:50 +00004031 for (last = pen = NULL, comma = arg; comma; comma = split(comma))
Simon Kelley9009d742008-11-14 20:04:27 +00004032 {
Simon Kelleya1d973f2016-12-22 22:09:50 +00004033 pen = last;
4034 last = comma;
4035 }
4036
4037 if (!pen)
4038 ret_err(_("bad CNAME"));
4039
4040 if (pen != arg && atoi_check(last, &ttl))
4041 last = pen;
4042
4043 target = canonicalise_opt(last);
4044
4045 while (arg != last)
4046 {
Petr Menšík56f06232018-03-06 23:13:32 +00004047 int arglen = strlen(arg);
Simon Kelleya1d973f2016-12-22 22:09:50 +00004048 alias = canonicalise_opt(arg);
Simon Kelley56144132017-05-03 22:54:09 +01004049
4050 if (!alias || !target)
Petr Menšík59e47032018-11-02 22:39:39 +00004051 {
4052 free(target);
4053 free(alias);
4054 ret_err(_("bad CNAME"));
4055 }
Simon Kelleya1d973f2016-12-22 22:09:50 +00004056
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004057 for (new = daemon->cnames; new; new = new->next)
Simon Kelley56144132017-05-03 22:54:09 +01004058 if (hostname_isequal(new->alias, alias))
Petr Menšík59e47032018-11-02 22:39:39 +00004059 {
4060 free(target);
4061 free(alias);
4062 ret_err(_("duplicate CNAME"));
4063 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004064 new = opt_malloc(sizeof(struct cname));
4065 new->next = daemon->cnames;
4066 daemon->cnames = new;
4067 new->alias = alias;
4068 new->target = target;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004069 new->ttl = ttl;
Simon Kelleya1d973f2016-12-22 22:09:50 +00004070
Petr Menšík56f06232018-03-06 23:13:32 +00004071 for (arg += arglen+1; *arg && isspace(*arg); arg++);
Simon Kelley9009d742008-11-14 20:04:27 +00004072 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004073
Simon Kelley9009d742008-11-14 20:04:27 +00004074 break;
4075 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01004076
4077 case LOPT_PTR: /* --ptr-record */
Simon Kelley832af0b2007-01-21 20:01:28 +00004078 {
4079 struct ptr_record *new;
Simon Kelley1f15b812009-10-13 17:49:32 +01004080 char *dom, *target = NULL;
4081
Simon Kelleyf2621c72007-04-29 19:47:21 +01004082 comma = split(arg);
4083
Simon Kelley1f15b812009-10-13 17:49:32 +01004084 if (!(dom = canonicalise_opt(arg)) ||
4085 (comma && !(target = canonicalise_opt(comma))))
Petr Menšík59e47032018-11-02 22:39:39 +00004086 {
4087 free(dom);
4088 free(target);
4089 ret_err(_("bad PTR record"));
4090 }
Simon Kelley1f15b812009-10-13 17:49:32 +01004091 else
4092 {
4093 new = opt_malloc(sizeof(struct ptr_record));
4094 new->next = daemon->ptr;
4095 daemon->ptr = new;
4096 new->name = dom;
4097 new->ptr = target;
4098 }
Simon Kelley832af0b2007-01-21 20:01:28 +00004099 break;
4100 }
4101
Simon Kelley1a6bca82008-07-11 11:11:42 +01004102 case LOPT_NAPTR: /* --naptr-record */
4103 {
4104 char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
4105 int k = 0;
4106 struct naptr *new;
4107 int order, pref;
Petr Menšík59e47032018-11-02 22:39:39 +00004108 char *name=NULL, *replace = NULL;
Simon Kelley1a6bca82008-07-11 11:11:42 +01004109
4110 if ((a[0] = arg))
4111 for (k = 1; k < 7; k++)
4112 if (!(a[k] = split(a[k-1])))
4113 break;
4114
4115
4116 if (k < 6 ||
Simon Kelley1f15b812009-10-13 17:49:32 +01004117 !(name = canonicalise_opt(a[0])) ||
Simon Kelley1ad24ae2008-07-20 20:22:50 +01004118 !atoi_check16(a[1], &order) ||
4119 !atoi_check16(a[2], &pref) ||
Simon Kelley1f15b812009-10-13 17:49:32 +01004120 (k == 7 && !(replace = canonicalise_opt(a[6]))))
Petr Menšík59e47032018-11-02 22:39:39 +00004121 {
4122 free(name);
4123 free(replace);
4124 ret_err(_("bad NAPTR record"));
4125 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01004126 else
4127 {
4128 new = opt_malloc(sizeof(struct naptr));
4129 new->next = daemon->naptr;
4130 daemon->naptr = new;
Simon Kelley1f15b812009-10-13 17:49:32 +01004131 new->name = name;
Simon Kelley1a6bca82008-07-11 11:11:42 +01004132 new->flags = opt_string_alloc(a[3]);
4133 new->services = opt_string_alloc(a[4]);
4134 new->regexp = opt_string_alloc(a[5]);
Simon Kelley1f15b812009-10-13 17:49:32 +01004135 new->replace = replace;
Simon Kelley1a6bca82008-07-11 11:11:42 +01004136 new->order = order;
4137 new->pref = pref;
4138 }
4139 break;
4140 }
Simon Kelley9f7f3b12012-05-28 21:39:57 +01004141
4142 case LOPT_RR: /* dns-rr */
4143 {
4144 struct txt_record *new;
Simon Kelley4caa86d2016-03-16 18:44:16 +00004145 size_t len = 0;
Simon Kelley9f7f3b12012-05-28 21:39:57 +01004146 char *data;
Petr Menšík59e47032018-11-02 22:39:39 +00004147 int class;
Simon Kelley9f7f3b12012-05-28 21:39:57 +01004148
4149 comma = split(arg);
4150 data = split(comma);
4151
4152 new = opt_malloc(sizeof(struct txt_record));
Petr Menšík59e47032018-11-02 22:39:39 +00004153 new->name = NULL;
Simon Kelley9f7f3b12012-05-28 21:39:57 +01004154
Petr Menšík59e47032018-11-02 22:39:39 +00004155 if (!atoi_check(comma, &class) ||
Simon Kelley9f7f3b12012-05-28 21:39:57 +01004156 !(new->name = canonicalise_opt(arg)) ||
Simon Kelley51931b82012-05-29 17:06:02 +01004157 (data && (len = parse_hex(data, (unsigned char *)data, -1, NULL, NULL)) == -1U))
Petr Menšík59e47032018-11-02 22:39:39 +00004158 {
4159 free(new->name);
4160 ret_err_free(_("bad RR record"), new);
4161 }
4162
Simon Kelley9f7f3b12012-05-28 21:39:57 +01004163 new->len = 0;
Petr Menšík59e47032018-11-02 22:39:39 +00004164 new->class = class;
4165 new->next = daemon->rr;
4166 daemon->rr = new;
Simon Kelley9f7f3b12012-05-28 21:39:57 +01004167
4168 if (data)
4169 {
Simon Kelley974a6d02018-08-23 23:01:16 +01004170 new->txt = opt_malloc(len);
Simon Kelley9f7f3b12012-05-28 21:39:57 +01004171 new->len = len;
4172 memcpy(new->txt, data, len);
4173 }
4174
4175 break;
4176 }
4177
Simon Kelley974a6d02018-08-23 23:01:16 +01004178 case LOPT_CAA: /* --caa-record */
4179 {
4180 struct txt_record *new;
4181 char *tag, *value;
4182 int flags;
4183
4184 comma = split(arg);
4185 tag = split(comma);
4186 value = split(tag);
4187
4188 new = opt_malloc(sizeof(struct txt_record));
4189 new->next = daemon->rr;
4190 daemon->rr = new;
4191
4192 if (!atoi_check(comma, &flags) || !tag || !value || !(new->name = canonicalise_opt(arg)))
4193 ret_err(_("bad CAA record"));
4194
4195 unhide_metas(tag);
4196 unhide_metas(value);
4197
4198 new->len = strlen(tag) + strlen(value) + 2;
4199 new->txt = opt_malloc(new->len);
4200 new->txt[0] = flags;
4201 new->txt[1] = strlen(tag);
4202 memcpy(&new->txt[2], tag, strlen(tag));
4203 memcpy(&new->txt[2 + strlen(tag)], value, strlen(value));
4204 new->class = T_CAA;
4205
4206 break;
4207 }
4208
Simon Kelleyf2621c72007-04-29 19:47:21 +01004209 case 'Y': /* --txt-record */
Simon Kelley849a8352006-06-09 21:02:31 +01004210 {
4211 struct txt_record *new;
Simon Kelley28866e92011-02-14 20:19:14 +00004212 unsigned char *p, *cnt;
4213 size_t len;
4214
4215 comma = split(arg);
4216
Simon Kelley824af852008-02-12 20:43:05 +00004217 new = opt_malloc(sizeof(struct txt_record));
Simon Kelley849a8352006-06-09 21:02:31 +01004218 new->class = C_IN;
Simon Kelleyfec216d2014-03-27 20:54:34 +00004219 new->stat = 0;
4220
Simon Kelley1f15b812009-10-13 17:49:32 +01004221 if (!(new->name = canonicalise_opt(arg)))
Petr Menšík59e47032018-11-02 22:39:39 +00004222 ret_err_free(_("bad TXT record"), new);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004223
Petr Menšík59e47032018-11-02 22:39:39 +00004224 new->next = daemon->txt;
4225 daemon->txt = new;
Simon Kelley28866e92011-02-14 20:19:14 +00004226 len = comma ? strlen(comma) : 0;
4227 len += (len/255) + 1; /* room for extra counts */
4228 new->txt = p = opt_malloc(len);
4229
4230 cnt = p++;
4231 *cnt = 0;
4232
4233 while (comma && *comma)
4234 {
4235 unsigned char c = (unsigned char)*comma++;
4236
4237 if (c == ',' || *cnt == 255)
4238 {
4239 if (c != ',')
4240 comma--;
4241 cnt = p++;
4242 *cnt = 0;
4243 }
4244 else
4245 {
4246 *p++ = unhide_meta(c);
4247 (*cnt)++;
4248 }
4249 }
4250
4251 new->len = p - new->txt;
4252
Simon Kelley849a8352006-06-09 21:02:31 +01004253 break;
4254 }
4255
Simon Kelleyf2621c72007-04-29 19:47:21 +01004256 case 'W': /* --srv-host */
Simon Kelley849a8352006-06-09 21:02:31 +01004257 {
4258 int port = 1, priority = 0, weight = 0;
4259 char *name, *target = NULL;
4260 struct mx_srv_record *new;
4261
Simon Kelleyf2621c72007-04-29 19:47:21 +01004262 comma = split(arg);
Simon Kelley849a8352006-06-09 21:02:31 +01004263
Simon Kelley1f15b812009-10-13 17:49:32 +01004264 if (!(name = canonicalise_opt(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004265 ret_err(_("bad SRV record"));
4266
Simon Kelley849a8352006-06-09 21:02:31 +01004267 if (comma)
4268 {
4269 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01004270 comma = split(arg);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004271 if (!(target = canonicalise_opt(arg)))
Petr Menšík59e47032018-11-02 22:39:39 +00004272 ret_err_free(_("bad SRV target"), name);
Simon Kelley824af852008-02-12 20:43:05 +00004273
Simon Kelley849a8352006-06-09 21:02:31 +01004274 if (comma)
4275 {
4276 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01004277 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01004278 if (!atoi_check16(arg, &port))
Petr Menšík59e47032018-11-02 22:39:39 +00004279 {
4280 free(name);
4281 ret_err_free(_("invalid port number"), target);
4282 }
Simon Kelley824af852008-02-12 20:43:05 +00004283
Simon Kelley849a8352006-06-09 21:02:31 +01004284 if (comma)
4285 {
4286 arg = comma;
Simon Kelleyf2621c72007-04-29 19:47:21 +01004287 comma = split(arg);
Simon Kelley1ad24ae2008-07-20 20:22:50 +01004288 if (!atoi_check16(arg, &priority))
Petr Menšík59e47032018-11-02 22:39:39 +00004289 {
4290 free(name);
4291 ret_err_free(_("invalid priority"), target);
4292 }
Simon Kelley407a1f32016-03-01 17:06:07 +00004293 if (comma && !atoi_check16(comma, &weight))
Petr Menšík59e47032018-11-02 22:39:39 +00004294 {
4295 free(name);
4296 ret_err_free(_("invalid weight"), target);
4297 }
Simon Kelley849a8352006-06-09 21:02:31 +01004298 }
4299 }
4300 }
4301
Simon Kelley824af852008-02-12 20:43:05 +00004302 new = opt_malloc(sizeof(struct mx_srv_record));
Simon Kelley849a8352006-06-09 21:02:31 +01004303 new->next = daemon->mxnames;
4304 daemon->mxnames = new;
4305 new->issrv = 1;
4306 new->name = name;
4307 new->target = target;
4308 new->srvport = port;
4309 new->priority = priority;
4310 new->weight = weight;
4311 break;
4312 }
Simon Kelley7622fc02009-06-04 20:32:05 +01004313
Simon Kelleye759d422012-03-16 13:18:57 +00004314 case LOPT_HOST_REC: /* --host-record */
4315 {
Petr Menšík59e47032018-11-02 22:39:39 +00004316 struct host_record *new;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004317
Simon Kelleye759d422012-03-16 13:18:57 +00004318 if (!arg || !(comma = split(arg)))
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004319 ret_err(_("Bad host-record"));
4320
Petr Menšík59e47032018-11-02 22:39:39 +00004321 new = opt_malloc(sizeof(struct host_record));
4322 memset(new, 0, sizeof(struct host_record));
4323 new->ttl = -1;
4324
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004325 while (arg)
4326 {
Simon Kelleycc921df2019-01-02 22:48:59 +00004327 union all_addr addr;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00004328 char *dig;
4329
4330 for (dig = arg; *dig != 0; dig++)
4331 if (*dig < '0' || *dig > '9')
4332 break;
4333 if (*dig == 0)
4334 new->ttl = atoi(arg);
Simon Kelleycc921df2019-01-02 22:48:59 +00004335 else if (inet_pton(AF_INET, arg, &addr.addr4))
4336 new->addr = addr.addr4;
4337 else if (inet_pton(AF_INET6, arg, &addr.addr6))
4338 new->addr6 = addr.addr6;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004339 else
4340 {
4341 int nomem;
4342 char *canon = canonicalise(arg, &nomem);
Petr Menšík59e47032018-11-02 22:39:39 +00004343 struct name_list *nl;
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004344 if (!canon)
Petr Menšík59e47032018-11-02 22:39:39 +00004345 {
4346 struct name_list *tmp = new->names, *next;
4347 for (tmp = new->names; tmp; tmp = next)
4348 {
4349 next = tmp->next;
4350 free(tmp);
4351 }
4352 ret_err_free(_("Bad name in host-record"), new);
4353 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004354
Petr Menšík59e47032018-11-02 22:39:39 +00004355 nl = opt_malloc(sizeof(struct name_list));
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004356 nl->name = canon;
4357 /* keep order, so that PTR record goes to first name */
4358 nl->next = NULL;
4359 if (!new->names)
4360 new->names = nl;
4361 else
4362 {
4363 struct name_list *tmp;
4364 for (tmp = new->names; tmp->next; tmp = tmp->next);
4365 tmp->next = nl;
4366 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004367 }
Simon Kelleye4807d82012-09-27 21:52:26 +01004368
4369 arg = comma;
4370 comma = split(arg);
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004371 }
Simon Kelleye759d422012-03-16 13:18:57 +00004372
4373 /* Keep list order */
4374 if (!daemon->host_records_tail)
4375 daemon->host_records = new;
4376 else
4377 daemon->host_records_tail->next = new;
4378 new->next = NULL;
4379 daemon->host_records_tail = new;
4380 break;
4381 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00004382
4383#ifdef HAVE_DNSSEC
Simon Kelleyf3e57872018-07-20 21:10:48 +01004384 case LOPT_DNSSEC_STAMP: /* --dnssec-timestamp */
Simon Kelleyf6e62e22015-03-01 18:17:54 +00004385 daemon->timestamp_file = opt_string_alloc(arg);
4386 break;
4387
Simon Kelleyf3e57872018-07-20 21:10:48 +01004388 case LOPT_DNSSEC_CHECK: /* --dnssec-check-unsigned */
Simon Kelleya6918532018-04-15 16:20:52 +01004389 if (arg)
4390 {
4391 if (strcmp(arg, "no") == 0)
4392 set_option_bool(OPT_DNSSEC_IGN_NS);
4393 else
4394 ret_err(_("bad value for dnssec-check-unsigned"));
4395 }
4396 break;
4397
Simon Kelleyf3e57872018-07-20 21:10:48 +01004398 case LOPT_TRUST_ANCHOR: /* --trust-anchor */
Simon Kelley0fc2f312014-01-08 10:26:58 +00004399 {
Simon Kelleyee415862014-02-11 11:07:22 +00004400 struct ds_config *new = opt_malloc(sizeof(struct ds_config));
4401 char *cp, *cp1, *keyhex, *digest, *algo = NULL;
4402 int len;
Simon Kelleycbf13a22014-01-25 17:59:14 +00004403
4404 new->class = C_IN;
Petr Menšík59e47032018-11-02 22:39:39 +00004405 new->name = NULL;
Simon Kelley0fc2f312014-01-08 10:26:58 +00004406
Simon Kelleycbf13a22014-01-25 17:59:14 +00004407 if ((comma = split(arg)) && (algo = split(comma)))
4408 {
4409 int class = 0;
4410 if (strcmp(comma, "IN") == 0)
4411 class = C_IN;
4412 else if (strcmp(comma, "CH") == 0)
4413 class = C_CHAOS;
4414 else if (strcmp(comma, "HS") == 0)
4415 class = C_HESIOD;
4416
4417 if (class != 0)
4418 {
4419 new->class = class;
4420 comma = algo;
4421 algo = split(comma);
4422 }
4423 }
4424
Simon Kelleyee415862014-02-11 11:07:22 +00004425 if (!comma || !algo || !(digest = split(algo)) || !(keyhex = split(digest)) ||
4426 !atoi_check16(comma, &new->keytag) ||
4427 !atoi_check8(algo, &new->algo) ||
4428 !atoi_check8(digest, &new->digest_type) ||
Simon Kelleycbf13a22014-01-25 17:59:14 +00004429 !(new->name = canonicalise_opt(arg)))
Petr Menšík59e47032018-11-02 22:39:39 +00004430 ret_err_free(_("bad trust anchor"), new);
Simon Kelleycbf13a22014-01-25 17:59:14 +00004431
Simon Kelley0fc2f312014-01-08 10:26:58 +00004432 /* Upper bound on length */
Simon Kelleyee415862014-02-11 11:07:22 +00004433 len = (2*strlen(keyhex))+1;
4434 new->digest = opt_malloc(len);
4435 unhide_metas(keyhex);
4436 /* 4034: "Whitespace is allowed within digits" */
4437 for (cp = keyhex; *cp; )
4438 if (isspace(*cp))
4439 for (cp1 = cp; *cp1; cp1++)
4440 *cp1 = *(cp1+1);
4441 else
4442 cp++;
4443 if ((new->digestlen = parse_hex(keyhex, (unsigned char *)new->digest, len, NULL, NULL)) == -1)
Petr Menšík59e47032018-11-02 22:39:39 +00004444 {
4445 free(new->name);
4446 ret_err_free(_("bad HEX in trust anchor"), new);
4447 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00004448
Simon Kelleyee415862014-02-11 11:07:22 +00004449 new->next = daemon->ds;
4450 daemon->ds = new;
4451
Simon Kelley0fc2f312014-01-08 10:26:58 +00004452 break;
4453 }
4454#endif
4455
Simon Kelley7622fc02009-06-04 20:32:05 +01004456 default:
Simon Kelley0fc2f312014-01-08 10:26:58 +00004457 ret_err(_("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)"));
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004458
Simon Kelley849a8352006-06-09 21:02:31 +01004459 }
Simon Kelley824af852008-02-12 20:43:05 +00004460
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004461 return 1;
Simon Kelley849a8352006-06-09 21:02:31 +01004462}
4463
Simon Kelley28866e92011-02-14 20:19:14 +00004464static void read_file(char *file, FILE *f, int hard_opt)
Simon Kelley849a8352006-06-09 21:02:31 +01004465{
Simon Kelley824af852008-02-12 20:43:05 +00004466 volatile int lineno = 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004467 char *buff = daemon->namebuff;
Simon Kelley849a8352006-06-09 21:02:31 +01004468
4469 while (fgets(buff, MAXDNAME, f))
4470 {
Simon Kelley7b1eae42014-02-20 13:43:28 +00004471 int white, i;
4472 volatile int option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt;
Simon Kelley13dee6f2017-02-28 16:51:58 +00004473 char *errmess, *p, *arg, *start;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004474 size_t len;
Simon Kelley832af0b2007-01-21 20:01:28 +00004475
Simon Kelley824af852008-02-12 20:43:05 +00004476 /* Memory allocation failure longjmps here if mem_recover == 1 */
Simon Kelley7b1eae42014-02-20 13:43:28 +00004477 if (option != 0 || hard_opt == LOPT_REV_SERV)
Simon Kelley824af852008-02-12 20:43:05 +00004478 {
4479 if (setjmp(mem_jmp))
4480 continue;
4481 mem_recover = 1;
4482 }
4483
Simon Kelley13dee6f2017-02-28 16:51:58 +00004484 arg = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +01004485 lineno++;
Simon Kelley824af852008-02-12 20:43:05 +00004486 errmess = NULL;
4487
Simon Kelley849a8352006-06-09 21:02:31 +01004488 /* Implement quotes, inside quotes we allow \\ \" \n and \t
4489 metacharacters get hidden also strip comments */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004490 for (white = 1, p = buff; *p; p++)
Simon Kelley849a8352006-06-09 21:02:31 +01004491 {
4492 if (*p == '"')
4493 {
4494 memmove(p, p+1, strlen(p+1)+1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004495
Simon Kelley849a8352006-06-09 21:02:31 +01004496 for(; *p && *p != '"'; p++)
4497 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01004498 if (*p == '\\' && strchr("\"tnebr\\", p[1]))
Simon Kelley849a8352006-06-09 21:02:31 +01004499 {
4500 if (p[1] == 't')
4501 p[1] = '\t';
4502 else if (p[1] == 'n')
4503 p[1] = '\n';
Simon Kelley849a8352006-06-09 21:02:31 +01004504 else if (p[1] == 'b')
4505 p[1] = '\b';
4506 else if (p[1] == 'r')
4507 p[1] = '\r';
Simon Kelley6b010842007-02-12 20:32:07 +00004508 else if (p[1] == 'e') /* escape */
4509 p[1] = '\033';
Simon Kelley849a8352006-06-09 21:02:31 +01004510 memmove(p, p+1, strlen(p+1)+1);
4511 }
4512 *p = hide_meta(*p);
4513 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004514
4515 if (*p == 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +01004516 {
4517 errmess = _("missing \"");
4518 goto oops;
4519 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004520
4521 memmove(p, p+1, strlen(p+1)+1);
Simon Kelley849a8352006-06-09 21:02:31 +01004522 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01004523
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004524 if (isspace(*p))
4525 {
4526 *p = ' ';
4527 white = 1;
Simon Kelley849a8352006-06-09 21:02:31 +01004528 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004529 else
4530 {
4531 if (white && *p == '#')
4532 {
4533 *p = 0;
4534 break;
4535 }
4536 white = 0;
4537 }
Simon Kelley849a8352006-06-09 21:02:31 +01004538 }
4539
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004540
4541 /* strip leading spaces */
4542 for (start = buff; *start && *start == ' '; start++);
4543
4544 /* strip trailing spaces */
4545 for (len = strlen(start); (len != 0) && (start[len-1] == ' '); len--);
4546
4547 if (len == 0)
Simon Kelley849a8352006-06-09 21:02:31 +01004548 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004549 else
4550 start[len] = 0;
4551
Simon Kelley611ebc52012-07-16 16:23:46 +01004552 if (option != 0)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004553 arg = start;
4554 else if ((p=strchr(start, '=')))
Simon Kelley849a8352006-06-09 21:02:31 +01004555 {
4556 /* allow spaces around "=" */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004557 for (arg = p+1; *arg == ' '; arg++);
4558 for (; p >= start && (*p == ' ' || *p == '='); p--)
Simon Kelley849a8352006-06-09 21:02:31 +01004559 *p = 0;
4560 }
4561 else
4562 arg = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00004563
Simon Kelley611ebc52012-07-16 16:23:46 +01004564 if (option == 0)
Simon Kelley5aabfc72007-08-29 11:24:47 +01004565 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01004566 for (option = 0, i = 0; opts[i].name; i++)
4567 if (strcmp(opts[i].name, start) == 0)
4568 {
4569 option = opts[i].val;
4570 break;
4571 }
4572
4573 if (!option)
4574 errmess = _("bad option");
4575 else if (opts[i].has_arg == 0 && arg)
4576 errmess = _("extraneous parameter");
4577 else if (opts[i].has_arg == 1 && !arg)
4578 errmess = _("missing parameter");
Simon Kelley7b1eae42014-02-20 13:43:28 +00004579 else if (hard_opt == LOPT_REV_SERV && option != 'S' && option != LOPT_REV_SERV)
4580 errmess = _("illegal option");
Simon Kelley5aabfc72007-08-29 11:24:47 +01004581 }
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004582
4583 oops:
Simon Kelley832af0b2007-01-21 20:01:28 +00004584 if (errmess)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004585 strcpy(daemon->namebuff, errmess);
4586
Simon Kelley9bafdc62018-08-21 22:53:38 +01004587 if (errmess || !one_opt(option, arg, daemon->namebuff, _("error"), 0, hard_opt == LOPT_REV_SERV))
Simon Kelleyf2621c72007-04-29 19:47:21 +01004588 {
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004589 sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file);
Simon Kelley824af852008-02-12 20:43:05 +00004590 if (hard_opt != 0)
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004591 my_syslog(LOG_ERR, "%s", daemon->namebuff);
Simon Kelley5aabfc72007-08-29 11:24:47 +01004592 else
Simon Kelleyc4a7f902012-07-12 20:52:12 +01004593 die("%s", daemon->namebuff, EC_BADCONF);
Simon Kelleyf2621c72007-04-29 19:47:21 +01004594 }
Simon Kelley849a8352006-06-09 21:02:31 +01004595 }
4596
Simon Kelley8ef5ada2010-06-03 19:42:45 +01004597 mem_recover = 0;
Simon Kelley849a8352006-06-09 21:02:31 +01004598 fclose(f);
4599}
4600
Simon Kelley4f7bb572018-03-08 18:47:08 +00004601#if defined(HAVE_DHCP) && defined(HAVE_INOTIFY)
Simon Kelley70d18732015-01-31 19:59:29 +00004602int option_read_dynfile(char *file, int flags)
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00004603{
Simon Kelleyf9c86372015-02-03 21:52:48 +00004604 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), file);
4605
Simon Kelley70d18732015-01-31 19:59:29 +00004606 if (flags & AH_DHCP_HST)
4607 return one_file(file, LOPT_BANK);
4608 else if (flags & AH_DHCP_OPT)
4609 return one_file(file, LOPT_OPTS);
Simon Kelleyf9c86372015-02-03 21:52:48 +00004610
Simon Kelley70d18732015-01-31 19:59:29 +00004611 return 0;
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00004612}
4613#endif
4614
Simon Kelley395eb712012-07-06 22:07:05 +01004615static int one_file(char *file, int hard_opt)
Simon Kelley28866e92011-02-14 20:19:14 +00004616{
4617 FILE *f;
4618 int nofile_ok = 0;
4619 static int read_stdin = 0;
4620 static struct fileread {
4621 dev_t dev;
4622 ino_t ino;
4623 struct fileread *next;
4624 } *filesread = NULL;
4625
4626 if (hard_opt == '7')
4627 {
4628 /* default conf-file reading */
4629 hard_opt = 0;
4630 nofile_ok = 1;
4631 }
4632
4633 if (hard_opt == 0 && strcmp(file, "-") == 0)
4634 {
4635 if (read_stdin == 1)
Simon Kelley395eb712012-07-06 22:07:05 +01004636 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00004637 read_stdin = 1;
4638 file = "stdin";
4639 f = stdin;
4640 }
4641 else
4642 {
4643 /* ignore repeated files. */
4644 struct stat statbuf;
4645
4646 if (hard_opt == 0 && stat(file, &statbuf) == 0)
4647 {
4648 struct fileread *r;
4649
4650 for (r = filesread; r; r = r->next)
4651 if (r->dev == statbuf.st_dev && r->ino == statbuf.st_ino)
Simon Kelley395eb712012-07-06 22:07:05 +01004652 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00004653
4654 r = safe_malloc(sizeof(struct fileread));
4655 r->next = filesread;
4656 filesread = r;
4657 r->dev = statbuf.st_dev;
4658 r->ino = statbuf.st_ino;
4659 }
4660
4661 if (!(f = fopen(file, "r")))
4662 {
4663 if (errno == ENOENT && nofile_ok)
Simon Kelley395eb712012-07-06 22:07:05 +01004664 return 1; /* No conffile, all done. */
Simon Kelley28866e92011-02-14 20:19:14 +00004665 else
4666 {
4667 char *str = _("cannot read %s: %s");
4668 if (hard_opt != 0)
4669 {
4670 my_syslog(LOG_ERR, str, file, strerror(errno));
Simon Kelley395eb712012-07-06 22:07:05 +01004671 return 0;
Simon Kelley28866e92011-02-14 20:19:14 +00004672 }
4673 else
4674 die(str, file, EC_FILE);
4675 }
4676 }
4677 }
4678
4679 read_file(file, f, hard_opt);
Simon Kelley395eb712012-07-06 22:07:05 +01004680 return 1;
Simon Kelley28866e92011-02-14 20:19:14 +00004681}
4682
4683/* expand any name which is a directory */
4684struct hostsfile *expand_filelist(struct hostsfile *list)
4685{
Simon Kelley19c51cf2014-03-18 22:38:30 +00004686 unsigned int i;
Simon Kelley28866e92011-02-14 20:19:14 +00004687 struct hostsfile *ah;
4688
Simon Kelley19c51cf2014-03-18 22:38:30 +00004689 /* find largest used index */
4690 for (i = SRC_AH, ah = list; ah; ah = ah->next)
Simon Kelley28866e92011-02-14 20:19:14 +00004691 {
4692 if (i <= ah->index)
4693 i = ah->index + 1;
4694
4695 if (ah->flags & AH_DIR)
4696 ah->flags |= AH_INACTIVE;
4697 else
4698 ah->flags &= ~AH_INACTIVE;
4699 }
4700
4701 for (ah = list; ah; ah = ah->next)
4702 if (!(ah->flags & AH_INACTIVE))
4703 {
4704 struct stat buf;
4705 if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode))
4706 {
4707 DIR *dir_stream;
4708 struct dirent *ent;
4709
4710 /* don't read this as a file */
4711 ah->flags |= AH_INACTIVE;
Simon Kelley5f4dc5c2015-01-20 20:51:02 +00004712
Simon Kelley28866e92011-02-14 20:19:14 +00004713 if (!(dir_stream = opendir(ah->fname)))
4714 my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
4715 ah->fname, strerror(errno));
4716 else
4717 {
4718 while ((ent = readdir(dir_stream)))
4719 {
4720 size_t lendir = strlen(ah->fname);
4721 size_t lenfile = strlen(ent->d_name);
4722 struct hostsfile *ah1;
4723 char *path;
4724
4725 /* ignore emacs backups and dotfiles */
4726 if (lenfile == 0 ||
4727 ent->d_name[lenfile - 1] == '~' ||
4728 (ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
4729 ent->d_name[0] == '.')
4730 continue;
4731
4732 /* see if we have an existing record.
4733 dir is ah->fname
4734 file is ent->d_name
4735 path to match is ah1->fname */
4736
4737 for (ah1 = list; ah1; ah1 = ah1->next)
4738 {
4739 if (lendir < strlen(ah1->fname) &&
4740 strstr(ah1->fname, ah->fname) == ah1->fname &&
4741 ah1->fname[lendir] == '/' &&
4742 strcmp(ah1->fname + lendir + 1, ent->d_name) == 0)
4743 {
4744 ah1->flags &= ~AH_INACTIVE;
4745 break;
4746 }
4747 }
4748
4749 /* make new record */
4750 if (!ah1)
4751 {
4752 if (!(ah1 = whine_malloc(sizeof(struct hostsfile))))
4753 continue;
4754
4755 if (!(path = whine_malloc(lendir + lenfile + 2)))
4756 {
4757 free(ah1);
4758 continue;
4759 }
4760
4761 strcpy(path, ah->fname);
4762 strcat(path, "/");
4763 strcat(path, ent->d_name);
4764 ah1->fname = path;
4765 ah1->index = i++;
4766 ah1->flags = AH_DIR;
4767 ah1->next = list;
4768 list = ah1;
4769 }
4770
4771 /* inactivate record if not regular file */
4772 if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode))
4773 ah1->flags |= AH_INACTIVE;
4774
4775 }
4776 closedir(dir_stream);
4777 }
4778 }
4779 }
4780
4781 return list;
4782}
4783
Simon Kelley7b1eae42014-02-20 13:43:28 +00004784void read_servers_file(void)
4785{
4786 FILE *f;
4787
4788 if (!(f = fopen(daemon->servers_file, "r")))
4789 {
4790 my_syslog(LOG_ERR, _("cannot read %s: %s"), daemon->servers_file, strerror(errno));
4791 return;
4792 }
4793
4794 mark_servers(SERV_FROM_FILE);
4795 cleanup_servers();
4796
4797 read_file(daemon->servers_file, f, LOPT_REV_SERV);
4798}
4799
Simon Kelley28866e92011-02-14 20:19:14 +00004800
Simon Kelley7622fc02009-06-04 20:32:05 +01004801#ifdef HAVE_DHCP
Simon Kelley4f7bb572018-03-08 18:47:08 +00004802static void clear_dynamic_conf(void)
4803{
4804 struct dhcp_config *configs, *cp, **up;
4805
4806 /* remove existing... */
4807 for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
4808 {
4809 cp = configs->next;
4810
4811 if (configs->flags & CONFIG_BANK)
4812 {
4813 struct hwaddr_config *mac, *tmp;
4814 struct dhcp_netid_list *list, *tmplist;
4815
4816 for (mac = configs->hwaddr; mac; mac = tmp)
4817 {
4818 tmp = mac->next;
4819 free(mac);
4820 }
4821
4822 if (configs->flags & CONFIG_CLID)
4823 free(configs->clid);
4824
4825 for (list = configs->netid; list; list = tmplist)
4826 {
4827 free(list->list);
4828 tmplist = list->next;
4829 free(list);
4830 }
4831
4832 if (configs->flags & CONFIG_NAME)
4833 free(configs->hostname);
4834
4835 *up = configs->next;
4836 free(configs);
4837 }
4838 else
4839 up = &configs->next;
4840 }
4841}
4842
4843static void clear_dynamic_opt(void)
4844{
4845 struct dhcp_opt *opts, *cp, **up;
4846 struct dhcp_netid *id, *next;
4847
4848 for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
4849 {
4850 cp = opts->next;
4851
4852 if (opts->flags & DHOPT_BANK)
4853 {
4854 if ((opts->flags & DHOPT_VENDOR))
4855 free(opts->u.vendor_class);
4856 free(opts->val);
4857 for (id = opts->netid; id; id = next)
4858 {
4859 next = id->next;
4860 free(id->net);
4861 free(id);
4862 }
4863 *up = opts->next;
4864 free(opts);
4865 }
4866 else
4867 up = &opts->next;
4868 }
4869}
4870
Simon Kelley824af852008-02-12 20:43:05 +00004871void reread_dhcp(void)
4872{
Simon Kelley4f7bb572018-03-08 18:47:08 +00004873 struct hostsfile *hf;
Simon Kelley28866e92011-02-14 20:19:14 +00004874
Simon Kelley4f7bb572018-03-08 18:47:08 +00004875 /* Do these even if there is no daemon->dhcp_hosts_file or
4876 daemon->dhcp_opts_file since entries may have been created by the
4877 inotify dynamic file reading system. */
4878
4879 clear_dynamic_conf();
4880 clear_dynamic_opt();
4881
4882 if (daemon->dhcp_hosts_file)
Simon Kelley824af852008-02-12 20:43:05 +00004883 {
Simon Kelley28866e92011-02-14 20:19:14 +00004884 daemon->dhcp_hosts_file = expand_filelist(daemon->dhcp_hosts_file);
4885 for (hf = daemon->dhcp_hosts_file; hf; hf = hf->next)
Simon Kelley4f7bb572018-03-08 18:47:08 +00004886 if (!(hf->flags & AH_INACTIVE))
4887 {
4888 if (one_file(hf->fname, LOPT_BANK))
4889 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
4890 }
Simon Kelley824af852008-02-12 20:43:05 +00004891 }
4892
4893 if (daemon->dhcp_opts_file)
4894 {
Simon Kelley28866e92011-02-14 20:19:14 +00004895 daemon->dhcp_opts_file = expand_filelist(daemon->dhcp_opts_file);
4896 for (hf = daemon->dhcp_opts_file; hf; hf = hf->next)
4897 if (!(hf->flags & AH_INACTIVE))
4898 {
Simon Kelley395eb712012-07-06 22:07:05 +01004899 if (one_file(hf->fname, LOPT_OPTS))
4900 my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
Simon Kelley28866e92011-02-14 20:19:14 +00004901 }
Simon Kelley824af852008-02-12 20:43:05 +00004902 }
Simon Kelley4f7bb572018-03-08 18:47:08 +00004903
4904# ifdef HAVE_INOTIFY
4905 /* Setup notify and read pre-existing files. */
4906 set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
4907# endif
Simon Kelley824af852008-02-12 20:43:05 +00004908}
Simon Kelley7622fc02009-06-04 20:32:05 +01004909#endif
Simon Kelley4f7bb572018-03-08 18:47:08 +00004910
Simon Kelley5aabfc72007-08-29 11:24:47 +01004911void read_opts(int argc, char **argv, char *compile_opts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004912{
Neil Jerram3bd4c472018-01-18 22:49:38 +00004913 size_t argbuf_size = MAXDNAME;
4914 char *argbuf = opt_malloc(argbuf_size);
Simon Kelley824af852008-02-12 20:43:05 +00004915 char *buff = opt_malloc(MAXDNAME);
Petr Menšík59e47032018-11-02 22:39:39 +00004916 int option, testmode = 0;
4917 char *arg, *conffile = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +01004918
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004919 opterr = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +01004920
Simon Kelley824af852008-02-12 20:43:05 +00004921 daemon = opt_malloc(sizeof(struct daemon));
Simon Kelley3be34542004-09-11 19:12:13 +01004922 memset(daemon, 0, sizeof(struct daemon));
4923 daemon->namebuff = buff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004924
Simon Kelley3be34542004-09-11 19:12:13 +01004925 /* Set defaults - everything else is zero or NULL */
Simon Kelley3be34542004-09-11 19:12:13 +01004926 daemon->cachesize = CACHESIZ;
Simon Kelley208b65c2006-08-05 21:41:37 +01004927 daemon->ftabsize = FTABSIZ;
Simon Kelley3be34542004-09-11 19:12:13 +01004928 daemon->port = NAMESERVER_PORT;
Simon Kelley9e038942008-05-30 20:06:34 +01004929 daemon->dhcp_client_port = DHCP_CLIENT_PORT;
4930 daemon->dhcp_server_port = DHCP_SERVER_PORT;
Simon Kelley3be34542004-09-11 19:12:13 +01004931 daemon->default_resolv.is_default = 1;
4932 daemon->default_resolv.name = RESOLVFILE;
4933 daemon->resolv_files = &daemon->default_resolv;
4934 daemon->username = CHUSER;
Simon Kelley3be34542004-09-11 19:12:13 +01004935 daemon->runfile = RUNFILE;
4936 daemon->dhcp_max = MAXLEASES;
Simon Kelley832af0b2007-01-21 20:01:28 +00004937 daemon->tftp_max = TFTP_MAX_CONNECTIONS;
Simon Kelley3be34542004-09-11 19:12:13 +01004938 daemon->edns_pktsz = EDNS_PKTSZ;
Simon Kelley849a8352006-06-09 21:02:31 +01004939 daemon->log_fac = -1;
Simon Kelley4f7b3042012-11-28 21:27:02 +00004940 daemon->auth_ttl = AUTH_TTL;
4941 daemon->soa_refresh = SOA_REFRESH;
4942 daemon->soa_retry = SOA_RETRY;
4943 daemon->soa_expiry = SOA_EXPIRY;
Hans Dedecker926332a2016-01-23 10:48:12 +00004944 daemon->max_port = MAX_PORT;
Simon Kelleybaf553d2018-01-29 22:49:27 +00004945 daemon->min_port = MIN_PORT;
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01004946
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01004947#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +00004948 add_txt("version.bind", "dnsmasq-" VERSION, 0 );
4949 add_txt("authors.bind", "Simon Kelley", 0);
4950 add_txt("copyright.bind", COPYRIGHT, 0);
4951 add_txt("cachesize.bind", NULL, TXT_STAT_CACHESIZE);
4952 add_txt("insertions.bind", NULL, TXT_STAT_INSERTS);
4953 add_txt("evictions.bind", NULL, TXT_STAT_EVICTIONS);
4954 add_txt("misses.bind", NULL, TXT_STAT_MISSES);
4955 add_txt("hits.bind", NULL, TXT_STAT_HITS);
4956#ifdef HAVE_AUTH
4957 add_txt("auth.bind", NULL, TXT_STAT_AUTH);
4958#endif
4959 add_txt("servers.bind", NULL, TXT_STAT_SERVERS);
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01004960#endif
Simon Kelley0a852542005-03-23 20:28:59 +00004961
Simon Kelley849a8352006-06-09 21:02:31 +01004962 while (1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004963 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004964#ifdef HAVE_GETOPT_LONG
Simon Kelley849a8352006-06-09 21:02:31 +01004965 option = getopt_long(argc, argv, OPTSTRING, opts, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004966#else
Simon Kelley849a8352006-06-09 21:02:31 +01004967 option = getopt(argc, argv, OPTSTRING);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004968#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004969
4970 if (option == -1)
Simon Kelley28866e92011-02-14 20:19:14 +00004971 {
Simon Kelley572b41e2011-02-18 18:11:18 +00004972 for (; optind < argc; optind++)
4973 {
4974 unsigned char *c = (unsigned char *)argv[optind];
4975 for (; *c != 0; c++)
4976 if (!isspace(*c))
4977 die(_("junk found in command line"), NULL, EC_BADCONF);
4978 }
Simon Kelley28866e92011-02-14 20:19:14 +00004979 break;
4980 }
4981
Simon Kelley849a8352006-06-09 21:02:31 +01004982 /* Copy optarg so that argv doesn't get changed */
4983 if (optarg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00004984 {
Neil Jerram3bd4c472018-01-18 22:49:38 +00004985 if (strlen(optarg) >= argbuf_size)
4986 {
4987 free(argbuf);
4988 argbuf_size = strlen(optarg) + 1;
4989 argbuf = opt_malloc(argbuf_size);
4990 }
Petr Menšík47b45b22018-08-15 18:17:00 +02004991 safe_strncpy(argbuf, optarg, argbuf_size);
Neil Jerram3bd4c472018-01-18 22:49:38 +00004992 arg = argbuf;
Simon Kelley849a8352006-06-09 21:02:31 +01004993 }
4994 else
4995 arg = NULL;
4996
4997 /* command-line only stuff */
Simon Kelley7622fc02009-06-04 20:32:05 +01004998 if (option == LOPT_TEST)
4999 testmode = 1;
5000 else if (option == 'w')
Simon Kelley849a8352006-06-09 21:02:31 +01005001 {
Simon Kelley7622fc02009-06-04 20:32:05 +01005002#ifdef HAVE_DHCP
Simon Kelley4cb1b322012-02-06 14:30:41 +00005003 if (argc == 3 && strcmp(argv[2], "dhcp") == 0)
Simon Kelley7622fc02009-06-04 20:32:05 +01005004 display_opts();
Simon Kelley4cb1b322012-02-06 14:30:41 +00005005#ifdef HAVE_DHCP6
5006 else if (argc == 3 && strcmp(argv[2], "dhcp6") == 0)
5007 display_opts6();
Simon Kelley7622fc02009-06-04 20:32:05 +01005008#endif
Simon Kelley4cb1b322012-02-06 14:30:41 +00005009 else
5010#endif
5011 do_usage();
5012
Simon Kelley9e4abcb2004-01-22 19:47:41 +00005013 exit(0);
5014 }
Simon Kelley849a8352006-06-09 21:02:31 +01005015 else if (option == 'v')
5016 {
5017 printf(_("Dnsmasq version %s %s\n"), VERSION, COPYRIGHT);
Simon Kelleyc72daea2012-01-05 21:33:27 +00005018 printf(_("Compile time options: %s\n\n"), compile_opts);
Simon Kelleyb8187c82005-11-26 21:46:27 +00005019 printf(_("This software comes with ABSOLUTELY NO WARRANTY.\n"));
5020 printf(_("Dnsmasq is free software, and you are welcome to redistribute it\n"));
Simon Kelley824af852008-02-12 20:43:05 +00005021 printf(_("under the terms of the GNU General Public License, version 2 or 3.\n"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00005022 exit(0);
5023 }
Simon Kelley849a8352006-06-09 21:02:31 +01005024 else if (option == 'C')
Simon Kelley9e4abcb2004-01-22 19:47:41 +00005025 {
Simon Kelley5c464ef2019-03-29 23:11:05 +00005026 if (!conffile)
5027 conffile = opt_string_alloc(arg);
5028 else
5029 {
5030 char *extra = opt_string_alloc(arg);
5031 one_file(extra, 0);
5032 free(extra);
5033 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00005034 }
Simon Kelley849a8352006-06-09 21:02:31 +01005035 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +00005036 {
Simon Kelley26128d22004-11-14 16:43:54 +00005037#ifdef HAVE_GETOPT_LONG
Simon Kelley7b1eae42014-02-20 13:43:28 +00005038 if (!one_opt(option, arg, daemon->namebuff, _("try --help"), 1, 0))
Simon Kelley849a8352006-06-09 21:02:31 +01005039#else
Simon Kelley7b1eae42014-02-20 13:43:28 +00005040 if (!one_opt(option, arg, daemon->namebuff, _("try -w"), 1, 0))
Simon Kelley849a8352006-06-09 21:02:31 +01005041#endif
Simon Kelleyc4a7f902012-07-12 20:52:12 +01005042 die(_("bad command line options: %s"), daemon->namebuff, EC_BADCONF);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00005043 }
5044 }
Simon Kelley849a8352006-06-09 21:02:31 +01005045
Neil Jerram3bd4c472018-01-18 22:49:38 +00005046 free(argbuf);
5047
Simon Kelley849a8352006-06-09 21:02:31 +01005048 if (conffile)
Chen Wei28b879a2015-02-17 22:07:35 +00005049 {
Petr Menšík59e47032018-11-02 22:39:39 +00005050 one_file(conffile, 0);
5051 free(conffile);
Chen Wei28b879a2015-02-17 22:07:35 +00005052 }
Petr Menšík59e47032018-11-02 22:39:39 +00005053 else
5054 one_file(CONFFILE, '7');
Simon Kelley849a8352006-06-09 21:02:31 +01005055
Simon Kelley1a6bca82008-07-11 11:11:42 +01005056 /* port might not be known when the address is parsed - fill in here */
Simon Kelley3be34542004-09-11 19:12:13 +01005057 if (daemon->servers)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00005058 {
5059 struct server *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +01005060 for (tmp = daemon->servers; tmp; tmp = tmp->next)
Simon Kelley14ffa072016-04-25 16:36:44 +01005061 if (!(tmp->flags & SERV_HAS_SOURCE))
5062 {
5063 if (tmp->source_addr.sa.sa_family == AF_INET)
5064 tmp->source_addr.in.sin_port = htons(daemon->query_port);
Simon Kelley14ffa072016-04-25 16:36:44 +01005065 else if (tmp->source_addr.sa.sa_family == AF_INET6)
5066 tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
Simon Kelley14ffa072016-04-25 16:36:44 +01005067 }
5068 }
5069
Simon Kelleydf3d54f2016-02-24 21:03:38 +00005070 if (daemon->host_records)
5071 {
5072 struct host_record *hr;
5073
5074 for (hr = daemon->host_records; hr; hr = hr->next)
5075 if (hr->ttl == -1)
5076 hr->ttl = daemon->local_ttl;
5077 }
5078
5079 if (daemon->cnames)
5080 {
Simon Kelley903df072017-01-19 17:22:00 +00005081 struct cname *cn, *cn2, *cn3;
5082
5083#define NOLOOP 1
5084#define TESTLOOP 2
5085
5086 /* Fill in TTL for CNAMES noe we have local_ttl.
5087 Also prepare to do loop detection. */
Simon Kelleydf3d54f2016-02-24 21:03:38 +00005088 for (cn = daemon->cnames; cn; cn = cn->next)
Simon Kelley903df072017-01-19 17:22:00 +00005089 {
5090 if (cn->ttl == -1)
5091 cn->ttl = daemon->local_ttl;
5092 cn->flag = 0;
5093 cn->targetp = NULL;
5094 for (cn2 = daemon->cnames; cn2; cn2 = cn2->next)
5095 if (hostname_isequal(cn->target, cn2->alias))
5096 {
5097 cn->targetp = cn2;
5098 break;
5099 }
5100 }
5101
5102 /* Find any CNAME loops.*/
5103 for (cn = daemon->cnames; cn; cn = cn->next)
5104 {
5105 for (cn2 = cn->targetp; cn2; cn2 = cn2->targetp)
5106 {
5107 if (cn2->flag == NOLOOP)
5108 break;
5109
5110 if (cn2->flag == TESTLOOP)
5111 die(_("CNAME loop involving %s"), cn->alias, EC_BADCONF);
5112
5113 cn2->flag = TESTLOOP;
5114 }
5115
5116 for (cn3 = cn->targetp; cn3 != cn2; cn3 = cn3->targetp)
5117 cn3->flag = NOLOOP;
5118 }
Simon Kelleydf3d54f2016-02-24 21:03:38 +00005119 }
5120
Simon Kelley3be34542004-09-11 19:12:13 +01005121 if (daemon->if_addrs)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00005122 {
5123 struct iname *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +01005124 for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00005125 if (tmp->addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +01005126 tmp->addr.in.sin_port = htons(daemon->port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00005127 else if (tmp->addr.sa.sa_family == AF_INET6)
Simon Kelley3be34542004-09-11 19:12:13 +01005128 tmp->addr.in6.sin6_port = htons(daemon->port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00005129 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00005130
5131 /* create default, if not specified */
5132 if (daemon->authserver && !daemon->hostmaster)
5133 {
5134 strcpy(buff, "hostmaster.");
5135 strcat(buff, daemon->authserver);
5136 daemon->hostmaster = opt_string_alloc(buff);
5137 }
5138
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00005139 /* only one of these need be specified: the other defaults to the host-name */
Simon Kelley28866e92011-02-14 20:19:14 +00005140 if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00005141 {
Simon Kelley0a852542005-03-23 20:28:59 +00005142 struct mx_srv_record *mx;
5143
Simon Kelley9e4abcb2004-01-22 19:47:41 +00005144 if (gethostname(buff, MAXDNAME) == -1)
Simon Kelley5aabfc72007-08-29 11:24:47 +01005145 die(_("cannot get host-name: %s"), NULL, EC_MISC);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00005146
Simon Kelley0a852542005-03-23 20:28:59 +00005147 for (mx = daemon->mxnames; mx; mx = mx->next)
5148 if (!mx->issrv && hostname_isequal(mx->name, buff))
5149 break;
5150
Simon Kelley28866e92011-02-14 20:19:14 +00005151 if ((daemon->mxtarget || option_bool(OPT_LOCALMX)) && !mx)
Simon Kelleyde379512004-06-22 20:23:33 +01005152 {
Simon Kelley824af852008-02-12 20:43:05 +00005153 mx = opt_malloc(sizeof(struct mx_srv_record));
Simon Kelley91dccd02005-03-31 17:48:32 +01005154 mx->next = daemon->mxnames;
5155 mx->issrv = 0;
5156 mx->target = NULL;
Simon Kelley824af852008-02-12 20:43:05 +00005157 mx->name = opt_string_alloc(buff);
Simon Kelley91dccd02005-03-31 17:48:32 +01005158 daemon->mxnames = mx;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00005159 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00005160
Simon Kelley3be34542004-09-11 19:12:13 +01005161 if (!daemon->mxtarget)
Simon Kelley824af852008-02-12 20:43:05 +00005162 daemon->mxtarget = opt_string_alloc(buff);
Simon Kelley0a852542005-03-23 20:28:59 +00005163
5164 for (mx = daemon->mxnames; mx; mx = mx->next)
5165 if (!mx->issrv && !mx->target)
5166 mx->target = daemon->mxtarget;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00005167 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00005168
Simon Kelley28866e92011-02-14 20:19:14 +00005169 if (!option_bool(OPT_NO_RESOLV) &&
Simon Kelley208b65c2006-08-05 21:41:37 +01005170 daemon->resolv_files &&
5171 daemon->resolv_files->next &&
Simon Kelley28866e92011-02-14 20:19:14 +00005172 option_bool(OPT_NO_POLL))
Simon Kelley5aabfc72007-08-29 11:24:47 +01005173 die(_("only one resolv.conf file allowed in no-poll mode."), NULL, EC_BADCONF);
Simon Kelleyde379512004-06-22 20:23:33 +01005174
Simon Kelley28866e92011-02-14 20:19:14 +00005175 if (option_bool(OPT_RESOLV_DOMAIN))
Simon Kelleyde379512004-06-22 20:23:33 +01005176 {
5177 char *line;
Simon Kelley849a8352006-06-09 21:02:31 +01005178 FILE *f;
5179
Simon Kelley28866e92011-02-14 20:19:14 +00005180 if (option_bool(OPT_NO_RESOLV) ||
Simon Kelley208b65c2006-08-05 21:41:37 +01005181 !daemon->resolv_files ||
5182 (daemon->resolv_files)->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01005183 die(_("must have exactly one resolv.conf to read domain from."), NULL, EC_BADCONF);
Simon Kelleyde379512004-06-22 20:23:33 +01005184
Simon Kelley3be34542004-09-11 19:12:13 +01005185 if (!(f = fopen((daemon->resolv_files)->name, "r")))
Simon Kelley5aabfc72007-08-29 11:24:47 +01005186 die(_("failed to read %s: %s"), (daemon->resolv_files)->name, EC_FILE);
Simon Kelleyde379512004-06-22 20:23:33 +01005187
5188 while ((line = fgets(buff, MAXDNAME, f)))
5189 {
5190 char *token = strtok(line, " \t\n\r");
5191
5192 if (!token || strcmp(token, "search") != 0)
5193 continue;
5194
5195 if ((token = strtok(NULL, " \t\n\r")) &&
Simon Kelley1f15b812009-10-13 17:49:32 +01005196 (daemon->domain_suffix = canonicalise_opt(token)))
Simon Kelleyde379512004-06-22 20:23:33 +01005197 break;
5198 }
Simon Kelley3be34542004-09-11 19:12:13 +01005199
Simon Kelleyde379512004-06-22 20:23:33 +01005200 fclose(f);
Simon Kelley8a911cc2004-03-16 18:35:52 +00005201
Simon Kelley3be34542004-09-11 19:12:13 +01005202 if (!daemon->domain_suffix)
Simon Kelley5aabfc72007-08-29 11:24:47 +01005203 die(_("no search directive found in %s"), (daemon->resolv_files)->name, EC_MISC);
Simon Kelleyde379512004-06-22 20:23:33 +01005204 }
Simon Kelley3d8df262005-08-29 12:19:27 +01005205
5206 if (daemon->domain_suffix)
5207 {
5208 /* add domain for any srv record without one. */
5209 struct mx_srv_record *srv;
Simon Kelleyde379512004-06-22 20:23:33 +01005210
Simon Kelley3d8df262005-08-29 12:19:27 +01005211 for (srv = daemon->mxnames; srv; srv = srv->next)
5212 if (srv->issrv &&
5213 strchr(srv->name, '.') &&
5214 strchr(srv->name, '.') == strrchr(srv->name, '.'))
5215 {
5216 strcpy(buff, srv->name);
5217 strcat(buff, ".");
5218 strcat(buff, daemon->domain_suffix);
5219 free(srv->name);
Simon Kelley824af852008-02-12 20:43:05 +00005220 srv->name = opt_string_alloc(buff);
Simon Kelley3d8df262005-08-29 12:19:27 +01005221 }
5222 }
Simon Kelley28866e92011-02-14 20:19:14 +00005223 else if (option_bool(OPT_DHCP_FQDN))
Simon Kelley9009d742008-11-14 20:04:27 +00005224 die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
Simon Kelley7622fc02009-06-04 20:32:05 +01005225
Simon Kelleyc8a80482014-03-05 14:29:54 +00005226 /* If there's access-control config, then ignore --local-service, it's intended
5227 as a system default to keep otherwise unconfigured installations safe. */
5228 if (daemon->if_names || daemon->if_except || daemon->if_addrs || daemon->authserver)
5229 reset_option_bool(OPT_LOCAL_SERVICE);
5230
Simon Kelley7622fc02009-06-04 20:32:05 +01005231 if (testmode)
5232 {
5233 fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
5234 exit(0);
5235 }
Simon Kelley849a8352006-06-09 21:02:31 +01005236}