]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/option.c
import of dnsmasq-2.23.tar.gz
[people/ms/dnsmasq.git] / src / option.c
CommitLineData
f6b7dc47 1/* dnsmasq is Copyright (c) 2000 - 2005 Simon Kelley
9e4abcb5
SK
2
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
5 the Free Software Foundation; version 2 dated June, 1991.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11*/
12
13/* Author's email: simon@thekelleys.org.uk */
14
15#include "dnsmasq.h"
16
17struct myoption {
18 const char *name;
19 int has_arg;
20 int *flag;
21 int val;
22};
23
3d8df260 24#define OPTSTRING "31yZDNLERKzowefnbvhdkqr: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:"
9e4abcb5 25
3d8df260 26static const struct myoption opts[] = {
9e4abcb5
SK
27 {"version", 0, 0, 'v'},
28 {"no-hosts", 0, 0, 'h'},
29 {"no-poll", 0, 0, 'n'},
30 {"help", 0, 0, 'w'},
31 {"no-daemon", 0, 0, 'd'},
32 {"log-queries", 0, 0, 'q'},
33 {"user", 1, 0, 'u'},
34 {"group", 1, 0, 'g'},
35 {"resolv-file", 1, 0, 'r'},
36 {"mx-host", 1, 0, 'm'},
37 {"mx-target", 1, 0, 't'},
38 {"cache-size", 1, 0, 'c'},
39 {"port", 1, 0, 'p'},
40 {"dhcp-leasefile", 1, 0, 'l'},
41 {"dhcp-lease", 1, 0, 'l' },
42 {"dhcp-host", 1, 0, 'G'},
43 {"dhcp-range", 1, 0, 'F'},
44 {"dhcp-option", 1, 0, 'O'},
45 {"dhcp-boot", 1, 0, 'M'},
46 {"domain", 1, 0, 's'},
47 {"domain-suffix", 1, 0, 's'},
48 {"interface", 1, 0, 'i'},
49 {"listen-address", 1, 0, 'a'},
50 {"bogus-priv", 0, 0, 'b'},
51 {"bogus-nxdomain", 1, 0, 'B'},
52 {"selfmx", 0, 0, 'e'},
53 {"filterwin2k", 0, 0, 'f'},
54 {"pid-file", 1, 0, 'x'},
55 {"strict-order", 0, 0, 'o'},
56 {"server", 1, 0, 'S'},
57 {"local", 1, 0, 'S' },
58 {"address", 1, 0, 'A' },
59 {"conf-file", 1, 0, 'C'},
60 {"no-resolv", 0, 0, 'R'},
61 {"expand-hosts", 0, 0, 'E'},
62 {"localmx", 0, 0, 'L'},
63 {"local-ttl", 1, 0, 'T'},
64 {"no-negcache", 0, 0, 'N'},
65 {"addn-hosts", 1, 0, 'H'},
66 {"query-port", 1, 0, 'Q'},
67 {"except-interface", 1, 0, 'I'},
3d8df260 68 {"no-dhcp-interface", 1, 0, '2'},
9e4abcb5 69 {"domain-needed", 0, 0, 'D'},
44a2a316 70 {"dhcp-lease-max", 1, 0, 'X' },
1cff166d 71 {"bind-interfaces", 0, 0, 'z'},
44a2a316 72 {"read-ethers", 0, 0, 'Z' },
1cff166d 73 {"alias", 1, 0, 'V' },
a84fa1d0 74 {"dhcp-vendorclass", 1, 0, 'U'},
a222641c 75 {"dhcp-userclass", 1, 0, 'j'},
26128d27 76 {"dhcp-ignore", 1, 0, 'J'},
feba5c1d 77 {"edns-packet-max", 1, 0, 'P'},
3be34541 78 {"keep-in-foreground", 0, 0, 'k'},
fd9fa481 79 {"dhcp-authoritative", 0, 0, 'K'},
f6b7dc47
SK
80 {"srv-host", 1, 0, 'W'},
81 {"localise-queries", 0, 0, 'y'},
0a852541 82 {"txt-record", 1, 0, 'Y'},
3d8df260
SK
83 {"enable-dbus", 0, 0, '1'},
84 {"bootp-dynamic", 0, 0, '3'},
9e4abcb5
SK
85 {0, 0, 0, 0}
86};
87
88struct optflags {
89 char c;
90 unsigned int flag;
91};
92
3d8df260 93static const struct optflags optmap[] = {
9e4abcb5
SK
94 { 'b', OPT_BOGUSPRIV },
95 { 'f', OPT_FILTER },
96 { 'q', OPT_LOG },
97 { 'e', OPT_SELFMX },
98 { 'h', OPT_NO_HOSTS },
99 { 'n', OPT_NO_POLL },
100 { 'd', OPT_DEBUG },
3be34541 101 { 'k', OPT_NO_FORK },
fd9fa481 102 { 'K', OPT_AUTHORITATIVE },
9e4abcb5
SK
103 { 'o', OPT_ORDER },
104 { 'R', OPT_NO_RESOLV },
105 { 'E', OPT_EXPAND },
44a2a316
SK
106 { 'L', OPT_LOCALMX },
107 { 'N', OPT_NO_NEG },
108 { 'D', OPT_NODOTS_LOCAL },
109 { 'z', OPT_NOWILD },
110 { 'Z', OPT_ETHERS },
f6b7dc47 111 { 'y', OPT_LOCALISE },
3d8df260
SK
112 { '1', OPT_DBUS },
113 { '3', OPT_BOOTP_DYNAMIC },
9e4abcb5
SK
114 { 'v', 0},
115 { 'w', 0},
116 { 0, 0 }
117};
118
3d8df260 119static const char * const usage =
26128d27
SK
120"Usage: dnsmasq [options]\n\n"
121#ifndef HAVE_GETOPT_LONG
122"Use short options only on the command line.\n"
123#endif
124"Valid options are :\n"
9e4abcb5
SK
125"-a, --listen-address=ipaddr Specify local address(es) to listen on.\n"
126"-A, --address=/domain/ipaddr Return ipaddr for all hosts in specified domains.\n"
127"-b, --bogus-priv Fake reverse lookups for RFC1918 private address ranges.\n"
128"-B, --bogus-nxdomain=ipaddr Treat ipaddr as NXDOMAIN (defeats Verisign wildcard).\n"
129"-c, --cache-size=cachesize Specify the size of the cache in entries (defaults to %d).\n"
130"-C, --conf-file=path Specify configuration file (defaults to " CONFFILE ").\n"
131"-d, --no-daemon Do NOT fork into the background: run in debug mode.\n"
132"-D, --domain-needed Do NOT forward queries with no domain part.\n"
133"-e, --selfmx Return self-pointing MX records for local hosts.\n"
134"-E, --expand-hosts Expand simple names in /etc/hosts with domain-suffix.\n"
135"-f, --filterwin2k Don't forward spurious DNS requests from Windows hosts.\n"
136"-F, --dhcp-range=ipaddr,ipaddr,time Enable DHCP in the range given with lease duration.\n"
137"-g, --group=groupname Change to this group after startup (defaults to " CHGRP ").\n"
138"-G, --dhcp-host=<hostspec> Set address or hostname for a specified machine.\n"
139"-h, --no-hosts Do NOT load " HOSTSFILE " file.\n"
140"-H, --addn-hosts=path Specify a hosts file to be read in addition to " HOSTSFILE ".\n"
141"-i, --interface=interface Specify interface(s) to listen on.\n"
142"-I, --except-interface=int Specify interface(s) NOT to listen on.\n"
a222641c 143"-j, --dhcp-userclass=<id>,<class> Map DHCP user class to option set.\n"
26128d27 144"-J, --dhcp-ignore=<id> Don't do DHCP for hosts in option set.\n"
3be34541 145"-k, --keep-in-foreground Do NOT fork into the background, do NOT run in debug mode.\n"
fd9fa481 146"-K, --dhcp-authoritative Assume we are the only DHCP server on the local network.\n"
9e4abcb5
SK
147"-l, --dhcp-leasefile=path Specify where to store DHCP leases (defaults to " LEASEFILE ").\n"
148"-L, --localmx Return MX records for local hosts.\n"
f6b7dc47 149"-m, --mx-host=host_name,target,pref Specify an MX record.\n"
9e4abcb5
SK
150"-M, --dhcp-boot=<bootp opts> Specify BOOTP options to DHCP server.\n"
151"-n, --no-poll Do NOT poll " RESOLVFILE " file, reload only on SIGHUP.\n"
152"-N, --no-negcache Do NOT cache failed search results.\n"
153"-o, --strict-order Use nameservers strictly in the order given in " RESOLVFILE ".\n"
154"-O, --dhcp-option=<optspec> Set extra options to be set to DHCP clients.\n"
155"-p, --port=number Specify port to listen for DNS requests on (defaults to 53).\n"
feba5c1d 156"-P, --edns-packet-max=<size> Maximum supported UDP packet size for EDNS.0 (defaults to %d).\n"
9e4abcb5
SK
157"-q, --log-queries Log queries.\n"
158"-Q, --query-port=number Force the originating port for upstream queries.\n"
159"-R, --no-resolv Do NOT read resolv.conf.\n"
160"-r, --resolv-file=path Specify path to resolv.conf (defaults to " RESOLVFILE ").\n"
161"-S, --server=/domain/ipaddr Specify address(es) of upstream servers with optional domains.\n"
162" --local=/domain/ Never forward queries to specified domains.\n"
163"-s, --domain=domain Specify the domain to be assigned in DHCP leases.\n"
f6b7dc47 164"-t, --mx-target=host_name Specify default target in an MX record.\n"
9e4abcb5
SK
165"-T, --local-ttl=time Specify time-to-live in seconds for replies from /etc/hosts.\n"
166"-u, --user=username Change to this user after startup. (defaults to " CHUSER ").\n"
a84fa1d0 167"-U, --dhcp-vendorclass=<id>,<class> Map DHCP vendor class to option set.\n"
feba5c1d 168"-v, --version Display dnsmasq version and copyright information.\n"
1cff166d 169"-V, --alias=addr,addr,mask Translate IPv4 addresses from upstream servers.\n"
0a852541 170"-W, --srv-host=name,target,... Specify a SRV record.\n"
9e4abcb5
SK
171"-w, --help Display this message.\n"
172"-x, --pid-file=path Specify path of PID file. (defaults to " RUNFILE ").\n"
44a2a316 173"-X, --dhcp-lease-max=number Specify maximum number of DHCP leases (defaults to %d).\n"
0a852541
SK
174"-y, --localise-queries Answer DNS queries based on the interface a query was sent to.\n"
175"-Y --txt-record=name,txt.... Specify TXT DNS record.\n"
44a2a316
SK
176"-z, --bind-interfaces Bind only to interfaces in use.\n"
177"-Z, --read-ethers Read DHCP static host information from " ETHERSFILE ".\n"
3d8df260
SK
178"-1, --enable-dbus Enable the DBus interface for setting upstream servers, etc.\n"
179"-2, --no-dhcp-interface=interface Do not provide DHCP on this interface, only provide DNS.\n"
180"-3, --bootp-dynamic Enable dynamic address allocation for bootp.\n"
9e4abcb5
SK
181"\n";
182
3d8df260
SK
183/* We hide metacharaters in quoted strings by mapping them into the ASCII control
184 character space. Note that the \0, \t \a \b \r and \n characters are carefully placed in the
185 following sequence so that they map to themselves: it is therefore possible to call
186 unhide_metas repeatedly on string without breaking things.
187 The transformation gets undone by opt_canonicalise, atoi_check and safe_string_alloc, and a
188 couple of other places. */
189
190static char meta[] = "\000123456\a\b\t\n78\r90abcdefABCDEF:,.";
191
192static char hide_meta(char c)
193{
194 unsigned int i;
195
196 for (i = 0; i < (sizeof(meta) - 1); i++)
197 if (c == meta[i])
198 return (char)i;
199
200 return c;
201}
202
203static char unhide_meta(char cr)
204{
205 unsigned int c = cr;
206
207 if (c < (sizeof(meta) - 1))
208 cr = meta[c];
209
210 return cr;
211}
212
213static void unhide_metas(char *cp)
214{
215 if (cp)
216 for(; *cp; cp++)
217 *cp = unhide_meta(*cp);
218}
219
220static char *safe_string_alloc(char *cp)
221{
222 char *ret = NULL;
223
224 if (cp && strlen(cp) != 0)
225 {
226 ret = safe_malloc(strlen(cp)+1);
227 strcpy(ret, cp);
228
229 /* restore hidden metachars */
230 unhide_metas(ret);
231 }
232
233 return ret;
234}
235
236static char *safe_strchr(char *s, int c)
237{
238 if (!s)
239 return NULL;
240
241 return strchr(s, c);
242}
243
244static int canonicalise_opt(char *s)
245{
246 if (!s)
247 return 0;
248
249 unhide_metas(s);
250 return canonicalise(s);
251}
252
253static int atoi_check(char *a, int *res)
254{
255 char *p;
256
257 if (!a)
258 return 0;
259
260 unhide_metas(a);
261
262 for (p = a; *p; p++)
263 if (*p < '0' || *p > '9')
264 return 0;
265
266 *res = atoi(a);
267 return 1;
268}
269
0a852541
SK
270static void add_txt(struct daemon *daemon, char *name, char *txt)
271{
272 size_t len = strlen(txt);
273 struct txt_record *r = safe_malloc(sizeof(struct txt_record));
274
275 r->name = safe_string_alloc(name);
276 r->next = daemon->txt;
277 daemon->txt = r;
278 r->class = C_CHAOS;
279 r->txt = safe_malloc(len+1);
280 r->len = len+1;
281 *(r->txt) = len;
282 memcpy((r->txt)+1, txt, len);
283}
9e4abcb5 284
3d8df260 285struct daemon *read_opts (int argc, char **argv, char *compile_opts)
9e4abcb5 286{
3be34541 287 struct daemon *daemon = safe_malloc(sizeof(struct daemon));
36717eee 288 char *problem = NULL, *buff = safe_malloc(MAXDNAME);
9e4abcb5 289 int option = 0, i;
33820b7e 290 FILE *file_save = NULL, *f = NULL;
91dccd09 291 char *p, *arg, *comma, *file_name_save = NULL, *conffile = CONFFILE;
fd9fa481 292 int hosts_index = 1, conffile_set = 0;
33820b7e 293 int line_save = 0, lineno = 0;
9e4abcb5 294 opterr = 0;
44a2a316 295
3be34541
SK
296 memset(daemon, 0, sizeof(struct daemon));
297 daemon->namebuff = buff;
9e4abcb5 298
3be34541
SK
299 /* Set defaults - everything else is zero or NULL */
300 daemon->min_leasetime = UINT_MAX;
301 daemon->cachesize = CACHESIZ;
302 daemon->port = NAMESERVER_PORT;
303 daemon->default_resolv.is_default = 1;
304 daemon->default_resolv.name = RESOLVFILE;
305 daemon->resolv_files = &daemon->default_resolv;
306 daemon->username = CHUSER;
307 daemon->groupname = CHGRP;
308 daemon->runfile = RUNFILE;
309 daemon->dhcp_max = MAXLEASES;
310 daemon->edns_pktsz = EDNS_PKTSZ;
0a852541
SK
311 add_txt(daemon, "version.bind", "dnsmasq-" VERSION );
312 add_txt(daemon, "authors.bind", "Simon Kelley");
313 add_txt(daemon, "copyright.bind", COPYRIGHT);
314
3be34541 315
9e4abcb5
SK
316 while (1)
317 {
36717eee
SK
318 problem = NULL;
319
9e4abcb5 320 if (!f)
0a852541 321 {
9e4abcb5 322#ifdef HAVE_GETOPT_LONG
0a852541 323 option = getopt_long(argc, argv, OPTSTRING, (struct option *)opts, NULL);
9e4abcb5 324#else
0a852541 325 option = getopt(argc, argv, OPTSTRING);
9e4abcb5 326#endif
91dccd09 327 /* Copy optarg so that argv doesn't get changed */
0a852541 328 if (optarg)
91dccd09
SK
329 {
330 strncpy(buff, optarg, MAXDNAME);
331 buff[MAXDNAME-1] = 0;
332 arg = buff;
91dccd09
SK
333 }
334 else
335 arg = NULL;
0a852541 336 }
9e4abcb5
SK
337 else
338 { /* f non-NULL, reading from conffile. */
33820b7e 339 reread:
9e4abcb5
SK
340 if (!fgets(buff, MAXDNAME, f))
341 {
342 /* At end of file, all done */
343 fclose(f);
33820b7e
SK
344 if (file_save)
345 {
346 /* may be nested */
347 conffile = file_name_save;
348 f = file_save;
349 file_save = NULL;
350 lineno = line_save;
351 goto reread;
352 }
9e4abcb5
SK
353 break;
354 }
355 else
356 {
33820b7e 357 int white;
3d8df260 358 unsigned int lastquote;
44a2a316 359 lineno++;
0a852541
SK
360
361 /* Implement quotes, inside quotes we allow \\ \" \n and \t
3d8df260 362 metacharacters get hidden also strip comments */
0a852541 363
3d8df260 364 for (white = 1, lastquote = 0, p = buff; *p; p++)
0a852541
SK
365 {
366 if (*p == '"')
367 {
368 memmove(p, p+1, strlen(p+1)+1);
369 for(; *p && *p != '"'; p++)
3d8df260
SK
370 {
371 if (*p == '\\' && strchr("\"tnabr\\", p[1]))
372 {
373 if (p[1] == 't')
374 p[1] = '\t';
375 else if (p[1] == 'n')
376 p[1] = '\n';
377 else if (p[1] == 'a')
378 p[1] = '\a';
379 else if (p[1] == 'b')
380 p[1] = '\b';
381 else if (p[1] == 'r')
382 p[1] = '\r';
383 memmove(p, p+1, strlen(p+1)+1);
384 }
385 *p = hide_meta(*p);
386 }
0a852541 387 if (*p == '"')
3d8df260
SK
388 {
389 memmove(p, p+1, strlen(p+1)+1);
390 lastquote = p - buff;
391 }
0a852541
SK
392 else
393 complain("missing \"", lineno, conffile);
394 }
395
396 if (white && *p == '#')
397 {
398 *p = 0;
399 break;
400 }
3d8df260 401 white = isspace(unhide_meta(*p));
0a852541 402 }
9e4abcb5 403 /* fgets gets end of line char too. */
3d8df260 404 while (strlen(buff) > lastquote && isspace(unhide_meta(buff[strlen(buff)-1])))
9e4abcb5 405 buff[strlen(buff)-1] = 0;
1ab84e2f
SK
406 if (*buff == 0)
407 continue;
9e4abcb5
SK
408 if ((p=strchr(buff, '=')))
409 {
91dccd09 410 arg = p+1;
9e4abcb5
SK
411 *p = 0;
412 }
413 else
91dccd09 414 arg = NULL;
9e4abcb5
SK
415
416 option = 0;
417 for (i=0; opts[i].name; i++)
418 if (strcmp(opts[i].name, buff) == 0)
419 option = opts[i].val;
420 if (!option)
44a2a316 421 {
0a852541 422 complain("bad option", lineno, conffile);
44a2a316
SK
423 continue;
424 }
9e4abcb5
SK
425 }
426 }
427
428 if (option == -1)
429 { /* end of command line args, start reading conffile. */
430 if (!conffile)
431 break; /* "confile=" option disables */
33820b7e 432 fileopen:
9e4abcb5
SK
433 option = 0;
434 if (!(f = fopen(conffile, "r")))
435 {
436 if (errno == ENOENT && !conffile_set)
437 break; /* No conffile, all done. */
438 else
439 die("cannot read %s: %s", conffile);
440 }
441 }
442
443 if (!f && option == 'w')
444 {
0a852541 445 printf (usage, CACHESIZ, EDNS_PKTSZ, MAXLEASES);
9e4abcb5
SK
446 exit(0);
447 }
448
449 if (!f && option == 'v')
450 {
3d8df260
SK
451 printf("Dnsmasq version %s %s\n", VERSION, COPYRIGHT);
452 printf("Compile time options %s\n\n", compile_opts);
0a852541
SK
453 printf("This software comes with ABSOLUTELY NO WARRANTY.\n");
454 printf("Dnsmasq is free software, and you are welcome to redistribute it\n");
455 printf("under the terms of the GNU General Public License, version 2.\n");
9e4abcb5
SK
456 exit(0);
457 }
458
459 for (i=0; optmap[i].c; i++)
460 if (option == optmap[i].c)
461 {
3be34541 462 daemon->options |= optmap[i].flag;
9e4abcb5 463 option = 0;
91dccd09 464 if (f && arg)
0a852541 465 complain("extraneous parameter", lineno, conffile);
9e4abcb5
SK
466 break;
467 }
468
469 if (option && option != '?')
470 {
91dccd09 471 if (f && !arg)
44a2a316 472 {
0a852541 473 complain("missing parameter", lineno, conffile);
44a2a316
SK
474 continue;
475 }
36717eee 476
9e4abcb5
SK
477 switch (option)
478 {
479 case 'C':
33820b7e
SK
480 if (!f)
481 {
3d8df260 482 conffile = safe_string_alloc(arg);
33820b7e
SK
483 conffile_set = 1;
484 break;
485 }
486
487 /* nest conffiles one deep */
488 if (file_save)
489 {
0a852541 490 complain("nested includes not allowed", lineno, conffile);
33820b7e
SK
491 continue;
492 }
493 file_name_save = conffile;
494 file_save = f;
495 line_save = lineno;
3d8df260 496 conffile = safe_string_alloc(arg);
9e4abcb5 497 conffile_set = 1;
33820b7e
SK
498 lineno = 0;
499 goto fileopen;
9e4abcb5
SK
500
501 case 'x':
3d8df260 502 daemon->runfile = safe_string_alloc(arg);
9e4abcb5
SK
503 break;
504
505 case 'r':
506 {
3d8df260 507 char *name = safe_string_alloc(arg);
3be34541 508 struct resolvc *new, *list = daemon->resolv_files;
91dccd09 509
9e4abcb5
SK
510 if (list && list->is_default)
511 {
512 /* replace default resolv file - possibly with nothing */
513 if (name)
514 {
515 list->is_default = 0;
516 list->name = name;
517 }
518 else
519 list = NULL;
520 }
521 else if (name)
522 {
523 new = safe_malloc(sizeof(struct resolvc));
524 new->next = list;
525 new->name = name;
526 new->is_default = 0;
3d8df260 527 new->mtime = 0;
9e4abcb5
SK
528 new->logged = 0;
529 list = new;
530 }
3be34541 531 daemon->resolv_files = list;
9e4abcb5
SK
532 break;
533 }
534
535 case 'm':
de37951c 536 {
f6b7dc47 537 int pref = 1;
0a852541 538 struct mx_srv_record *new;
f6b7dc47 539
3d8df260 540 if ((comma = safe_strchr(arg, ',')))
f6b7dc47
SK
541 {
542 char *prefstr;
543 *(comma++) = 0;
3d8df260 544 if ((prefstr=strchr(comma, ',')))
f6b7dc47
SK
545 {
546 *(prefstr++) = 0;
547 if (!atoi_check(prefstr, &pref))
548 {
549 option = '?';
550 problem = "bad MX preference";
551 break;
552 }
553 }
554 }
555
3d8df260 556 if (!canonicalise_opt(arg) || (comma && !canonicalise_opt(comma)))
36717eee
SK
557 {
558 option = '?';
559 problem = "bad MX name";
f6b7dc47 560 break;
36717eee 561 }
f6b7dc47 562
0a852541 563 new = safe_malloc(sizeof(struct mx_srv_record));
f6b7dc47
SK
564 new->next = daemon->mxnames;
565 daemon->mxnames = new;
0a852541 566 new->issrv = 0;
91dccd09 567 new->name = safe_string_alloc(arg);
0a852541
SK
568 new->target = safe_string_alloc(comma); /* may be NULL */
569 new->weight = pref;
de37951c
SK
570 break;
571 }
f6b7dc47 572
9e4abcb5 573 case 't':
3d8df260 574 if (!canonicalise_opt(arg))
36717eee
SK
575 {
576 option = '?';
577 problem = "bad MX target";
578 }
9e4abcb5 579 else
91dccd09 580 daemon->mxtarget = safe_string_alloc(arg);
9e4abcb5
SK
581 break;
582
583 case 'l':
3d8df260 584 daemon->lease_file = safe_string_alloc(arg);
9e4abcb5
SK
585 break;
586
587 case 'H':
fd9fa481
SK
588 {
589 struct hostsfile *new = safe_malloc(sizeof(struct hostsfile));
3d8df260 590 new->fname = safe_string_alloc(arg);
fd9fa481
SK
591 new->index = hosts_index++;
592 new->next = daemon->addn_hosts;
593 daemon->addn_hosts = new;
594 break;
595 }
596
9e4abcb5 597 case 's':
91dccd09 598 if (strcmp (arg, "#") == 0)
3be34541 599 daemon->options |= OPT_RESOLV_DOMAIN;
3d8df260 600 else if (!canonicalise_opt(arg))
9e4abcb5
SK
601 option = '?';
602 else
91dccd09 603 daemon->domain_suffix = safe_string_alloc(arg);
9e4abcb5
SK
604 break;
605
606 case 'u':
91dccd09 607 daemon->username = safe_string_alloc(arg);
9e4abcb5
SK
608 break;
609
610 case 'g':
91dccd09 611 daemon->groupname = safe_string_alloc(arg);
9e4abcb5
SK
612 break;
613
614 case 'i':
26128d27 615 do {
9e4abcb5 616 struct iname *new = safe_malloc(sizeof(struct iname));
3d8df260 617 if ((comma = safe_strchr(arg, ',')))
26128d27 618 *comma++ = 0;
3be34541
SK
619 new->next = daemon->if_names;
620 daemon->if_names = new;
9e4abcb5
SK
621 /* new->name may be NULL if someone does
622 "interface=" to disable all interfaces except loop. */
91dccd09 623 new->name = safe_string_alloc(arg);
de37951c 624 new->isloop = new->used = 0;
3d8df260 625 if (safe_strchr(new->name, ':'))
3be34541 626 daemon->options |= OPT_NOWILD;
91dccd09
SK
627 arg = comma;
628 } while (arg);
26128d27
SK
629 break;
630
9e4abcb5 631 case 'I':
3d8df260 632 case '2':
26128d27 633 do {
9e4abcb5 634 struct iname *new = safe_malloc(sizeof(struct iname));
3d8df260 635 if ((comma = safe_strchr(arg, ',')))
26128d27 636 *comma++ = 0;
91dccd09 637 new->name = safe_string_alloc(arg);
3d8df260
SK
638 if (option == 'I')
639 {
640 new->next = daemon->if_except;
641 daemon->if_except = new;
642 if (safe_strchr(new->name, ':'))
643 daemon->options |= OPT_NOWILD;
644 }
645 else
646 {
647 new->next = daemon->dhcp_except;
648 daemon->dhcp_except = new;
649 }
91dccd09
SK
650 arg = comma;
651 } while (arg);
26128d27 652 break;
3d8df260 653
9e4abcb5
SK
654 case 'B':
655 {
656 struct in_addr addr;
3d8df260
SK
657 unhide_metas(arg);
658 if (arg && (addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
9e4abcb5
SK
659 {
660 struct bogus_addr *baddr = safe_malloc(sizeof(struct bogus_addr));
3be34541
SK
661 baddr->next = daemon->bogus_addr;
662 daemon->bogus_addr = baddr;
9e4abcb5
SK
663 baddr->addr = addr;
664 }
665 else
666 option = '?'; /* error */
667 break;
668 }
669
670 case 'a':
59353a6b 671 do {
9e4abcb5 672 struct iname *new = safe_malloc(sizeof(struct iname));
3d8df260 673 if ((comma = safe_strchr(arg, ',')))
59353a6b 674 *comma++ = 0;
3d8df260 675 unhide_metas(arg);
3be34541 676 new->next = daemon->if_addrs;
3d8df260 677 if (arg && (new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
9e4abcb5
SK
678 {
679 new->addr.sa.sa_family = AF_INET;
680#ifdef HAVE_SOCKADDR_SA_LEN
681 new->addr.in.sin_len = sizeof(struct sockaddr_in);
682#endif
683 }
3d8df260
SK
684#ifdef HAVE_IPV6
685 else if (arg && inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
9e4abcb5
SK
686 {
687 new->addr.sa.sa_family = AF_INET6;
688 new->addr.in6.sin6_flowinfo = htonl(0);
689#ifdef HAVE_SOCKADDR_SA_LEN
690 new->addr.in6.sin6_len = sizeof(struct sockaddr_in6);
691#endif
692 }
9e4abcb5
SK
693#endif
694 else
44a2a316
SK
695 {
696 option = '?'; /* error */
697 free(new);
59353a6b 698 break;
44a2a316
SK
699 }
700
59353a6b 701 daemon->if_addrs = new;
91dccd09
SK
702 arg = comma;
703 } while (arg);
59353a6b
SK
704 break;
705
9e4abcb5
SK
706 case 'S':
707 case 'A':
708 {
709 struct server *serv, *newlist = NULL;
710
3d8df260
SK
711 unhide_metas(arg);
712
713 if (arg && *arg == '/')
9e4abcb5
SK
714 {
715 char *end;
91dccd09
SK
716 arg++;
717 while ((end = strchr(arg, '/')))
9e4abcb5 718 {
a222641c 719 char *domain = NULL;
9e4abcb5 720 *end = 0;
a222641c 721 /* # matches everything and becomes a zero length domain string */
91dccd09 722 if (strcmp(arg, "#") == 0)
a222641c 723 domain = "";
3d8df260 724 else if (!canonicalise_opt(arg) && strlen(arg) != 0)
44a2a316 725 option = '?';
a222641c 726 else
91dccd09 727 domain = safe_string_alloc(arg); /* NULL if strlen is zero */
9e4abcb5
SK
728 serv = safe_malloc(sizeof(struct server));
729 serv->next = newlist;
730 newlist = serv;
731 serv->sfd = NULL;
732 serv->domain = domain;
733 serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
91dccd09 734 arg = end+1;
9e4abcb5
SK
735 }
736 if (!newlist)
737 {
738 option = '?';
739 break;
740 }
741
742 }
743 else
744 {
745 newlist = safe_malloc(sizeof(struct server));
746 newlist->next = NULL;
747 newlist->flags = 0;
748 newlist->sfd = NULL;
749 newlist->domain = NULL;
750 }
751
752 if (option == 'A')
753 {
754 newlist->flags |= SERV_LITERAL_ADDRESS;
755 if (!(newlist->flags & SERV_TYPE))
44a2a316 756 option = '?';
9e4abcb5
SK
757 }
758
3d8df260 759 if (!arg || !*arg)
9e4abcb5
SK
760 {
761 newlist->flags |= SERV_NO_ADDR; /* no server */
762 if (newlist->flags & SERV_LITERAL_ADDRESS)
44a2a316 763 option = '?';
9e4abcb5
SK
764 }
765 else
766 {
767 int source_port = 0, serv_port = NAMESERVER_PORT;
768 char *portno, *source;
769
91dccd09 770 if ((source = strchr(arg, '@'))) /* is there a source. */
9e4abcb5
SK
771 {
772 *source = 0;
773 if ((portno = strchr(source+1, '#')))
774 {
775 *portno = 0;
a222641c 776 if (!atoi_check(portno+1, &source_port))
36717eee
SK
777 {
778 option = '?';
779 problem = "bad port";
780 }
9e4abcb5
SK
781 }
782 }
783
91dccd09 784 if ((portno = strchr(arg, '#'))) /* is there a port no. */
9e4abcb5
SK
785 {
786 *portno = 0;
a222641c 787 if (!atoi_check(portno+1, &serv_port))
36717eee
SK
788 {
789 option = '?';
790 problem = "bad port";
791 }
9e4abcb5
SK
792 }
793
91dccd09 794 if ((newlist->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1)
9e4abcb5
SK
795 {
796 newlist->addr.in.sin_port = htons(serv_port);
797 newlist->source_addr.in.sin_port = htons(source_port);
798 newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET;
799#ifdef HAVE_SOCKADDR_SA_LEN
800 newlist->source_addr.in.sin_len = newlist->addr.in.sin_len = sizeof(struct sockaddr_in);
801#endif
802 if (source)
803 {
9e4abcb5 804 if ((newlist->source_addr.in.sin_addr.s_addr = inet_addr(source+1)) != (in_addr_t) -1)
9e4abcb5
SK
805 newlist->flags |= SERV_HAS_SOURCE;
806 else
807 option = '?'; /* error */
808 }
809 else
810 newlist->source_addr.in.sin_addr.s_addr = INADDR_ANY;
811 }
812#ifdef HAVE_IPV6
3d8df260 813 else if (inet_pton(AF_INET6, arg, &newlist->addr.in6.sin6_addr) > 0)
9e4abcb5
SK
814 {
815 newlist->addr.in6.sin6_port = htons(serv_port);
816 newlist->source_addr.in6.sin6_port = htons(source_port);
817 newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET6;
818 newlist->addr.in6.sin6_flowinfo = newlist->source_addr.in6.sin6_flowinfo = htonl(0);
819#ifdef HAVE_SOCKADDR_SA_LEN
820 newlist->addr.in6.sin6_len = newlist->source_addr.in6.sin6_len = sizeof(struct sockaddr_in6);
821#endif
822 if (source)
823 {
3d8df260 824 if (inet_pton(AF_INET6, source+1, &newlist->source_addr.in6.sin6_addr) > 0)
9e4abcb5
SK
825 newlist->flags |= SERV_HAS_SOURCE;
826 else
827 option = '?'; /* error */
828 }
829 else
830 newlist->source_addr.in6.sin6_addr = in6addr_any;
831 }
832#endif
833 else
834 option = '?'; /* error */
835
836 }
837
44a2a316
SK
838 if (option == '?')
839 while (newlist)
840 {
841 serv = newlist;
842 newlist = newlist->next;
843 free(serv);
844 }
845 else
9e4abcb5 846 {
44a2a316
SK
847 serv = newlist;
848 while (serv->next)
849 {
850 serv->next->flags = serv->flags;
851 serv->next->addr = serv->addr;
852 serv->next->source_addr = serv->source_addr;
853 serv = serv->next;
854 }
3be34541
SK
855 serv->next = daemon->servers;
856 daemon->servers = newlist;
9e4abcb5 857 }
9e4abcb5
SK
858 break;
859 }
860
861 case 'c':
862 {
a222641c 863 int size;
3d8df260 864
91dccd09 865 if (!atoi_check(arg, &size))
a222641c
SK
866 option = '?';
867 else
868 {
869 /* zero is OK, and means no caching. */
870
871 if (size < 0)
872 size = 0;
873 else if (size > 10000)
874 size = 10000;
875
3be34541 876 daemon->cachesize = size;
a222641c 877 }
9e4abcb5
SK
878 break;
879 }
880
881 case 'p':
91dccd09 882 if (!atoi_check(arg, &daemon->port))
a222641c 883 option = '?';
9e4abcb5
SK
884 break;
885
feba5c1d
SK
886 case 'P':
887 {
888 int i;
91dccd09 889 if (!atoi_check(arg, &i))
feba5c1d 890 option = '?';
3be34541 891 daemon->edns_pktsz = (unsigned short)i;
feba5c1d
SK
892 break;
893 }
894
9e4abcb5 895 case 'Q':
91dccd09 896 if (!atoi_check(arg, &daemon->query_port))
a222641c 897 option = '?';
9e4abcb5
SK
898 break;
899
900 case 'T':
a222641c
SK
901 {
902 int ttl;
91dccd09 903 if (!atoi_check(arg, &ttl))
a222641c
SK
904 option = '?';
905 else
3be34541 906 daemon->local_ttl = (unsigned long)ttl;
a222641c
SK
907 break;
908 }
9e4abcb5 909
44a2a316 910 case 'X':
91dccd09 911 if (!atoi_check(arg, &daemon->dhcp_max))
a222641c 912 option = '?';
44a2a316
SK
913 break;
914
9e4abcb5
SK
915 case 'F':
916 {
44a2a316 917 int k, leasepos = 2;
26128d27 918 char *cp, *a[5] = { NULL, NULL, NULL, NULL, NULL };
9e4abcb5
SK
919 struct dhcp_context *new = safe_malloc(sizeof(struct dhcp_context));
920
3be34541 921 new->next = daemon->dhcp;
feba5c1d
SK
922 new->lease_time = DEFLEASE;
923 new->addr_epoch = 0;
44a2a316
SK
924 new->netmask.s_addr = 0;
925 new->broadcast.s_addr = 0;
3be34541 926 new->router.s_addr = 0;
a222641c 927 new->netid.net = NULL;
0a852541 928 new->flags = 0;
9e4abcb5 929
36717eee
SK
930 problem = "bad dhcp-range";
931
3d8df260
SK
932 if (!arg)
933 {
934 option = '?';
935 break;
936 }
937
91dccd09 938 for (cp = arg; *cp; cp++)
44a2a316 939 if (!(*cp == ' ' || *cp == '.' || (*cp >='0' && *cp <= '9')))
9e4abcb5 940 break;
44a2a316 941
3d8df260 942 if (*cp != ',' && (comma = strchr(arg, ',')))
44a2a316
SK
943 {
944 *comma = 0;
91dccd09 945 if (strstr(arg, "net:") == arg)
f6b7dc47 946 {
91dccd09 947 new->netid.net = safe_string_alloc(arg+4);
f6b7dc47 948 new->netid.next = NULL;
0a852541 949 new->flags |= CONTEXT_FILTER;
f6b7dc47
SK
950 }
951 else
91dccd09 952 new->netid.net = safe_string_alloc(arg);
44a2a316 953 a[0] = comma + 1;
9e4abcb5 954 }
44a2a316 955 else
91dccd09 956 a[0] = arg;
44a2a316 957
9e4abcb5 958
44a2a316
SK
959 for (k = 1; k < 5; k++)
960 {
3d8df260 961 if (!(a[k] = strchr(a[k-1], ',')))
44a2a316
SK
962 break;
963 *(a[k]++) = 0;
964 }
965
33820b7e
SK
966 if ((k < 2) || ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1))
967 option = '?';
968 else if (strcmp(a[1], "static") == 0)
3be34541
SK
969 {
970 new->end = new->start;
0a852541 971 new->flags |= CONTEXT_STATIC;
3be34541 972 }
33820b7e
SK
973 else if ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1)
974 option = '?';
975
3be34541
SK
976 if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
977 {
978 struct in_addr tmp = new->start;
979 new->start = new->end;
980 new->end = tmp;
981 }
982
36717eee
SK
983 if (option != '?' && k >= 3 && strchr(a[2], '.') &&
984 ((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
985 {
0a852541 986 new->flags |= CONTEXT_NETMASK;
36717eee
SK
987 leasepos = 3;
988 if (!is_same_net(new->start, new->end, new->netmask))
989 {
990 problem = "inconsistent DHCP range";
991 option = '?';
992 }
993 }
994
33820b7e 995 if (option == '?')
9e4abcb5 996 {
44a2a316
SK
997 free(new);
998 break;
999 }
1000 else
3be34541 1001 daemon->dhcp = new;
36717eee 1002
44a2a316
SK
1003 if (k >= 4 && strchr(a[3], '.') &&
1004 ((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1))
0a852541
SK
1005 {
1006 new->flags |= CONTEXT_BRDCAST;
1007 leasepos = 4;
1008 }
44a2a316
SK
1009
1010 if (k >= leasepos+1)
1011 {
1012 if (strcmp(a[leasepos], "infinite") == 0)
9e4abcb5
SK
1013 new->lease_time = 0xffffffff;
1014 else
1015 {
1016 int fac = 1;
44a2a316 1017 if (strlen(a[leasepos]) > 0)
9e4abcb5 1018 {
44a2a316 1019 switch (a[leasepos][strlen(a[leasepos]) - 1])
9e4abcb5 1020 {
3d8df260
SK
1021 case 'd':
1022 case 'D':
1023 fac *= 24;
1024 /* fall though */
9e4abcb5
SK
1025 case 'h':
1026 case 'H':
1027 fac *= 60;
1028 /* fall through */
1029 case 'm':
1030 case 'M':
1031 fac *= 60;
44a2a316
SK
1032 /* fall through */
1033 case 's':
1034 case 'S':
1035 a[leasepos][strlen(a[leasepos]) - 1] = 0;
9e4abcb5
SK
1036 }
1037
44a2a316 1038 new->lease_time = atoi(a[leasepos]) * fac;
0a852541
SK
1039 /* Leases of a minute or less confuse
1040 some clients, notably Apple's */
1041 if (new->lease_time < 120)
1042 new->lease_time = 120;
9e4abcb5
SK
1043 }
1044 }
1045 }
44a2a316 1046
3be34541
SK
1047 if (new->lease_time < daemon->min_leasetime)
1048 daemon->min_leasetime = new->lease_time;
9e4abcb5
SK
1049 break;
1050 }
1051
1052 case 'G':
1053 {
1054 int j, k;
33820b7e 1055 char *a[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
9e4abcb5
SK
1056 struct dhcp_config *new = safe_malloc(sizeof(struct dhcp_config));
1057 struct in_addr in;
1058
3be34541 1059 new->next = daemon->dhcp_conf;
33820b7e
SK
1060 new->flags = 0;
1061
9e4abcb5 1062
3d8df260
SK
1063 if ((a[0] = arg))
1064 for (k = 1; k < 6; k++)
1065 {
1066 if (!(a[k] = strchr(a[k-1], ',')))
1067 break;
1068 *(a[k]++) = 0;
1069 }
1070 else
1071 k = 0;
9e4abcb5 1072
3d8df260 1073 for (j = 0; j < k; j++)
33820b7e 1074 if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
9e4abcb5
SK
1075 {
1076 char *arg = a[j];
0a852541 1077
9e4abcb5
SK
1078 if ((arg[0] == 'i' || arg[0] == 'I') &&
1079 (arg[1] == 'd' || arg[1] == 'D') &&
1080 arg[2] == ':')
1081 {
a84fa1d0
SK
1082 if (arg[3] == '*')
1083 new->flags |= CONFIG_NOCLID;
1084 else
9e4abcb5 1085 {
a84fa1d0
SK
1086 int len;
1087 arg += 3; /* dump id: */
1088 if (strchr(arg, ':'))
3d8df260 1089 len = parse_hex(arg, (unsigned char *)arg, -1, NULL);
a84fa1d0 1090 else
0a852541 1091 len = (int) strlen(arg);
a84fa1d0
SK
1092
1093 new->flags |= CONFIG_CLID;
1094 new->clid_len = len;
1095 new->clid = safe_malloc(len);
1096 memcpy(new->clid, arg, len);
9e4abcb5 1097 }
9e4abcb5 1098 }
26128d27 1099 else if (strstr(arg, "net:") == arg)
33820b7e
SK
1100 {
1101 new->flags |= CONFIG_NETID;
a222641c 1102 new->netid.net = safe_string_alloc(arg+4);
33820b7e 1103 }
0a852541 1104 else if (parse_hex(a[j], new->hwaddr, 6, &new->wildcard_mask) == 6)
33820b7e 1105 new->flags |= CONFIG_HWADDR;
9e4abcb5
SK
1106 else
1107 option = '?';
1108 }
1109 else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1)
33820b7e
SK
1110 {
1111 new->addr = in;
1112 new->flags |= CONFIG_ADDR;
1113 }
9e4abcb5
SK
1114 else
1115 {
1116 char *cp, *lastp = NULL, last = 0;
1117 int fac = 1;
1118
1119 if (strlen(a[j]) > 1)
1120 {
1121 lastp = a[j] + strlen(a[j]) - 1;
1122 last = *lastp;
1123 switch (last)
1124 {
3d8df260
SK
1125 case 'd':
1126 case 'D':
1127 fac *= 24;
1128 /* fall through */
9e4abcb5
SK
1129 case 'h':
1130 case 'H':
1ab84e2f
SK
1131 fac *= 60;
1132 /* fall through */
9e4abcb5
SK
1133 case 'm':
1134 case 'M':
1135 fac *= 60;
44a2a316
SK
1136 /* fall through */
1137 case 's':
1138 case 'S':
9e4abcb5
SK
1139 *lastp = 0;
1140 }
1141 }
1142
1143 for (cp = a[j]; *cp; cp++)
1ab84e2f 1144 if (!isdigit(*cp) && *cp != ' ')
9e4abcb5
SK
1145 break;
1146
1147 if (*cp)
1148 {
1149 if (lastp)
1150 *lastp = last;
1151 if (strcmp(a[j], "infinite") == 0)
33820b7e
SK
1152 {
1153 new->lease_time = 0xffffffff;
1154 new->flags |= CONFIG_TIME;
1155 }
1156 else if (strcmp(a[j], "ignore") == 0)
1157 new->flags |= CONFIG_DISABLE;
9e4abcb5 1158 else
33820b7e
SK
1159 {
1160 new->hostname = safe_string_alloc(a[j]);
1161 new->flags |= CONFIG_NAME;
1162 }
9e4abcb5
SK
1163 }
1164 else
33820b7e
SK
1165 {
1166 new->lease_time = atoi(a[j]) * fac;
0a852541
SK
1167 /* Leases of a minute or less confuse
1168 some clients, notably Apple's */
1169 if (new->lease_time < 120)
1170 new->lease_time = 120;
33820b7e
SK
1171 new->flags |= CONFIG_TIME;
1172 }
9e4abcb5 1173 }
44a2a316
SK
1174
1175 if (option == '?')
33820b7e 1176 {
36717eee 1177 problem = "bad dhcp-host";
33820b7e
SK
1178 if (new->flags & CONFIG_NAME)
1179 free(new->hostname);
1180 if (new->flags & CONFIG_CLID)
1181 free(new->clid);
1182 if (new->flags & CONFIG_NETID)
a222641c 1183 free(new->netid.net);
33820b7e
SK
1184 free(new);
1185 }
44a2a316 1186 else
8a911ccc 1187 {
3be34541
SK
1188 if ((new->flags & CONFIG_TIME) && new->lease_time < daemon->min_leasetime)
1189 daemon->min_leasetime = new->lease_time;
1190 daemon->dhcp_conf = new;
8a911ccc 1191 }
9e4abcb5
SK
1192 break;
1193 }
1194
1195 case 'O':
1196 {
1197 struct dhcp_opt *new = safe_malloc(sizeof(struct dhcp_opt));
91dccd09 1198 char lenchar = 0, *cp;
33820b7e 1199 int addrs, digs, is_addr, is_hex, is_dec;
9e4abcb5 1200
1ab84e2f
SK
1201 new->len = 0;
1202 new->is_addr = 0;
44a2a316 1203 new->netid = NULL;
fd9fa481 1204 new->val = NULL;
91dccd09 1205 new->vendor_class = NULL;
44a2a316 1206
3d8df260 1207 if ((comma = safe_strchr(arg, ',')))
44a2a316 1208 {
26128d27 1209 struct dhcp_netid *np = NULL;
fd9fa481 1210 *comma++ = 0;
44a2a316 1211
26128d27 1212 do {
91dccd09 1213 for (cp = arg; *cp; cp++)
26128d27
SK
1214 if (!(*cp == ' ' || (*cp >='0' && *cp <= '9')))
1215 break;
1216 if (!*cp)
44a2a316 1217 break;
26128d27 1218
91dccd09 1219 if (strstr(arg, "vendor:") == arg)
3d8df260 1220 new->vendor_class = (unsigned char *)safe_string_alloc(arg+7);
91dccd09
SK
1221 else
1222 {
1223 new->netid = safe_malloc(sizeof (struct dhcp_netid));
1224 new->netid->net = safe_string_alloc(arg);
1225 new->netid->next = np;
1226 np = new->netid;
1227 }
1228 arg = comma;
3d8df260 1229 if ((comma = safe_strchr(arg, ',')))
26128d27 1230 *comma++ = 0;
91dccd09 1231 } while (arg);
44a2a316 1232 }
9e4abcb5 1233
91dccd09 1234 if (!arg || (new->opt = atoi(arg)) == 0)
9e4abcb5
SK
1235 {
1236 option = '?';
26128d27 1237 problem = "bad dhcp-option";
9e4abcb5 1238 }
91dccd09 1239 else if (comma && new->opt == 119 && !new->vendor_class)
fd9fa481
SK
1240 {
1241 /* dns search, RFC 3397 */
1242 unsigned char *q, *r, *tail;
1243 unsigned char *p = NULL;
0a852541 1244 size_t newlen, len = 0;
fd9fa481 1245
91dccd09 1246 arg = comma;
3d8df260 1247 if ((comma = safe_strchr(arg, ',')))
fd9fa481
SK
1248 *(comma++) = 0;
1249
91dccd09 1250 while (arg && *arg)
33820b7e 1251 {
3d8df260 1252 if (!canonicalise_opt(arg))
fd9fa481
SK
1253 {
1254 option = '?';
26128d27 1255 problem = "bad domain in dhcp-option";
fd9fa481
SK
1256 break;
1257 }
1258
91dccd09 1259 if (!(p = realloc(p, len + strlen(arg) + 2)))
fd9fa481 1260 die("could not get memory", NULL);
fd9fa481
SK
1261 q = p + len;
1262
1263 /* add string on the end in RFC1035 format */
91dccd09 1264 while (*arg)
fd9fa481 1265 {
3d8df260 1266 unsigned char *cp = q++;
fd9fa481 1267 int j;
91dccd09
SK
1268 for (j = 0; *arg && (*arg != '.'); arg++, j++)
1269 *q++ = *arg;
fd9fa481 1270 *cp = j;
91dccd09
SK
1271 if (*arg)
1272 arg++;
fd9fa481
SK
1273 }
1274 *q++ = 0;
1275
1276 /* Now tail-compress using earlier names. */
1277 newlen = q - p;
1278 for (tail = p + len; *tail; tail += (*tail) + 1)
0a852541 1279 for (r = p; r - p < (int)len; r += (*r) + 1)
3d8df260 1280 if (strcmp((char *)r, (char *)tail) == 0)
fd9fa481
SK
1281 {
1282 PUTSHORT((r - p) | 0xc000, tail);
1283 newlen = tail - p;
1284 goto end;
1285 }
1286 end:
1287 len = newlen;
1288
91dccd09 1289 arg = comma;
3d8df260 1290 if ((comma = safe_strchr(arg, ',')))
fd9fa481 1291 *(comma++) = 0;
33820b7e 1292 }
fd9fa481 1293
0a852541 1294 new->len = (int) len;
fd9fa481
SK
1295 new->val = p;
1296 }
1297 else if (comma)
9e4abcb5 1298 {
fd9fa481
SK
1299 /* not option 119 */
1300 /* characterise the value */
1301 is_addr = is_hex = is_dec = 1;
1302 addrs = digs = 1;
1303 for (cp = comma; *cp; cp++)
3d8df260 1304 if (*cp == ',')
fd9fa481
SK
1305 {
1306 addrs++;
1307 is_dec = is_hex = 0;
1308 }
1309 else if (*cp == ':')
1310 {
1311 digs++;
1312 is_dec = is_addr = 0;
1313 }
1314 else if (*cp == '.')
1315 is_dec = is_hex = 0;
26128d27 1316 else if (!((*cp >='0' && *cp <= '9') || *cp == '-'))
fd9fa481 1317 {
91dccd09
SK
1318 is_addr = 0;
1319 if (cp[1] == 0 && is_dec &&
1320 (*cp == 'b' || *cp == 's' || *cp == 'i'))
1321 {
1322 lenchar = *cp;
1323 *cp = 0;
1324 }
1325 else
1326 is_dec = 0;
fd9fa481
SK
1327 if (!((*cp >='A' && *cp <= 'F') ||
1328 (*cp >='a' && *cp <= 'f')))
1329 is_hex = 0;
1330 }
1331
1332 if (is_hex && digs > 1)
33820b7e 1333 {
fd9fa481 1334 new->len = digs;
0a852541
SK
1335 new->val = safe_malloc(new->len);
1336 parse_hex(comma, new->val, digs, NULL);
fd9fa481
SK
1337 }
1338 else if (is_dec)
1339 {
26128d27
SK
1340 int i, val = atoi(comma);
1341 /* assume numeric arg is 1 byte except for
91dccd09
SK
1342 options where it is known otherwise.
1343 For vendor class option, we have to hack. */
1344 new->len = 1;
1345 if (lenchar == 'b')
1346 new->len = 1;
1347 else if (lenchar == 's')
1348 new->len = 2;
1349 else if (lenchar == 'i')
1350 new->len = 4;
1351 else if (new->vendor_class)
fd9fa481 1352 {
91dccd09
SK
1353 if (val & 0xffff0000)
1354 new->len = 4;
1355 else if (val & 0xff00)
1356 new->len = 2;
1357 }
1358 else
1359 switch (new->opt)
1360 {
1361 case 13: case 22: case 25: case 26:
1362 new->len = 2;
1363 break;
1364 case 2: case 24: case 35: case 38:
1365 new->len = 4;
1366 break;
1367 }
26128d27
SK
1368 new->val = safe_malloc(new->len);
1369 for (i=0; i<new->len; i++)
1370 new->val[i] = val>>((new->len - i - 1)*8);
33820b7e 1371 }
fd9fa481 1372 else if (is_addr)
9e4abcb5 1373 {
fd9fa481
SK
1374 struct in_addr in;
1375 unsigned char *op;
1376 new->len = INADDRSZ * addrs;
1377 new->val = op = safe_malloc(new->len);
1378 new->is_addr = 1;
1379 while (addrs--)
1380 {
1381 cp = comma;
3d8df260 1382 if ((comma = strchr(cp, ',')))
fd9fa481
SK
1383 *comma++ = 0;
1384 in.s_addr = inet_addr(cp);
1385 memcpy(op, &in, INADDRSZ);
1386 op += INADDRSZ;
1387 }
1ab84e2f
SK
1388 }
1389 else
1390 {
fd9fa481
SK
1391 /* text arg */
1392 new->len = strlen(comma);
91dccd09 1393 /* keep terminating zero on string */
3d8df260 1394 new->val = (unsigned char *)safe_string_alloc(comma);
9e4abcb5
SK
1395 }
1396 }
fd9fa481 1397
0a852541 1398 if (new->len > 255)
33820b7e 1399 {
fd9fa481
SK
1400 option = '?';
1401 problem = "dhcp-option too long";
33820b7e 1402 }
fd9fa481
SK
1403
1404 if (option == '?')
33820b7e 1405 {
fd9fa481
SK
1406 if (new->netid)
1407 free(new->netid);
1408 if (new->val)
1409 free(new->val);
91dccd09
SK
1410 if (new->vendor_class)
1411 free(new->vendor_class);
fd9fa481 1412 free(new);
33820b7e 1413 }
91dccd09
SK
1414 else if (new->vendor_class)
1415 {
1416 new->next = daemon->vendor_opts;
1417 daemon->vendor_opts = new;
1418 }
fd9fa481 1419 else
91dccd09
SK
1420 {
1421 new->next = daemon->dhcp_opts;
1422 daemon->dhcp_opts = new;
1423 }
9e4abcb5
SK
1424 break;
1425 }
1426
1427 case 'M':
1428 {
26128d27 1429 struct dhcp_netid *id = NULL;
91dccd09 1430 while (arg && strstr(arg, "net:") == arg)
26128d27
SK
1431 {
1432 struct dhcp_netid *newid = safe_malloc(sizeof(struct dhcp_netid));
1433 newid->next = id;
1434 id = newid;
3d8df260 1435 if ((comma = strchr(arg, ',')))
26128d27 1436 *comma++ = 0;
91dccd09
SK
1437 newid->net = safe_string_alloc(arg+4);
1438 arg = comma;
26128d27 1439 };
9e4abcb5 1440
91dccd09 1441 if (!arg)
26128d27
SK
1442 option = '?';
1443 else
9e4abcb5 1444 {
26128d27
SK
1445 char *dhcp_file, *dhcp_sname = NULL;
1446 struct in_addr dhcp_next_server;
3d8df260 1447 if ((comma = strchr(arg, ',')))
26128d27 1448 *comma++ = 0;
91dccd09 1449 dhcp_file = safe_string_alloc(arg);
26128d27
SK
1450 dhcp_next_server.s_addr = 0;
1451 if (comma)
1452 {
91dccd09 1453 arg = comma;
3d8df260 1454 if ((comma = strchr(arg, ',')))
26128d27 1455 *comma++ = 0;
91dccd09 1456 dhcp_sname = safe_string_alloc(arg);
3d8df260
SK
1457 if (comma)
1458 {
1459 unhide_metas(comma);
1460 if ((dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
1461 option = '?';
1462 }
26128d27
SK
1463 }
1464 if (option != '?')
1465 {
1466 struct dhcp_boot *new = safe_malloc(sizeof(struct dhcp_boot));
1467 new->file = dhcp_file;
1468 new->sname = dhcp_sname;
1469 new->next_server = dhcp_next_server;
1470 new->netid = id;
1471 new->next = daemon->boot_config;
1472 daemon->boot_config = new;
1473 }
1474 }
1475
1476 if (option == '?')
1477 {
1478 struct dhcp_netid *tmp;
1479 for (; id; id = tmp)
1480 {
1481 tmp = id->next;
1482 free(id);
1483 }
9e4abcb5
SK
1484 }
1485 break;
1486 }
1cff166d 1487
a84fa1d0 1488 case 'U':
a222641c 1489 case 'j':
a84fa1d0 1490 {
3d8df260 1491 if (!(comma = safe_strchr(arg, ',')))
a84fa1d0
SK
1492 option = '?';
1493 else
1494 {
1495 struct dhcp_vendor *new = safe_malloc(sizeof(struct dhcp_vendor));
1496 *comma = 0;
91dccd09 1497 new->netid.net = safe_string_alloc(arg);
3d8df260 1498 unhide_metas(comma+1);
a84fa1d0
SK
1499 new->len = strlen(comma+1);
1500 new->data = safe_malloc(new->len);
1501 memcpy(new->data, comma+1, new->len);
a222641c 1502 new->is_vendor = (option == 'U');
3be34541
SK
1503 new->next = daemon->dhcp_vendors;
1504 daemon->dhcp_vendors = new;
a84fa1d0
SK
1505 }
1506 break;
1507 }
26128d27
SK
1508
1509 case 'J':
1510 {
1511 struct dhcp_netid_list *new = safe_malloc(sizeof(struct dhcp_netid_list));
1512 struct dhcp_netid *list = NULL;
1513 new->next = daemon->dhcp_ignore;
1514 daemon->dhcp_ignore = new;
1515 do {
1516 struct dhcp_netid *member = safe_malloc(sizeof(struct dhcp_netid));
3d8df260 1517 if ((comma = safe_strchr(arg, ',')))
26128d27
SK
1518 *comma++ = 0;
1519 member->next = list;
1520 list = member;
91dccd09
SK
1521 member->net = safe_string_alloc(arg);
1522 arg = comma;
1523 } while (arg);
26128d27
SK
1524
1525 new->list = list;
1526 break;
1527 }
1528
1cff166d
SK
1529 case 'V':
1530 {
1531 char *a[3] = { NULL, NULL, NULL };
1532 int k;
1533 struct in_addr in, out, mask;
1534 struct doctor *new;
1535
1536 mask.s_addr = 0xffffffff;
1537
3d8df260
SK
1538 if ((a[0] = arg))
1539 for (k = 1; k < 3; k++)
1540 {
1541 if (!(a[k] = strchr(a[k-1], ',')))
1542 break;
1543 *(a[k]++) = 0;
1544 unhide_metas(a[k]);
1545 }
1546 else
1547 k = 0;
1cff166d 1548
3d8df260 1549 if ((k < 2) ||
1cff166d
SK
1550 ((in.s_addr = inet_addr(a[0])) == (in_addr_t)-1) ||
1551 ((out.s_addr = inet_addr(a[1])) == (in_addr_t)-1))
1552 {
1553 option = '?';
1554 break;
1555 }
1556
1557 if (k == 3)
1558 mask.s_addr = inet_addr(a[2]);
1559
1560 new = safe_malloc(sizeof(struct doctor));
1561 new->in = in;
1562 new->out = out;
1563 new->mask = mask;
3be34541
SK
1564 new->next = daemon->doctors;
1565 daemon->doctors = new;
1cff166d
SK
1566
1567 break;
1568 }
f6b7dc47 1569
0a852541
SK
1570 case 'Y':
1571 {
1572 struct txt_record *new;
1573 unsigned char *p, *q;
1574
3d8df260 1575 if ((comma = safe_strchr(arg, ',')))
0a852541
SK
1576 *(comma) = 0;
1577
3d8df260 1578 if (!canonicalise_opt(arg))
0a852541
SK
1579 {
1580 option = '?';
1581 problem = "bad TXT record";
1582 break;
1583 }
1584
3d8df260 1585 if ((q = (unsigned char *)comma))
0a852541
SK
1586 while (1)
1587 {
1588 size_t len;
3d8df260 1589 if ((p = (unsigned char *)strchr((char*)q+1, ',')))
0a852541
SK
1590 {
1591 if ((len = p - q - 1) > 255)
1592 {
1593 option = '?';
1594 break;
1595 }
1596 *q = len;
3d8df260
SK
1597 for (q = q+1; q < p; q++)
1598 *q = unhide_meta(*q);
0a852541
SK
1599 }
1600 else
1601 {
3d8df260 1602 if ((len = strlen((char *)q+1)) > 255)
0a852541
SK
1603 option = '?';
1604 *q = len;
3d8df260
SK
1605 for (q = q+1; *q; q++)
1606 *q = unhide_meta(*q);
0a852541
SK
1607 break;
1608 }
1609 }
1610
1611 if (option == '?')
1612 {
1613 problem = "TXT record string too long";
1614 break;
1615 }
1616
1617 new = safe_malloc(sizeof(struct txt_record));
1618 new->next = daemon->txt;
1619 daemon->txt = new;
1620 new->class = C_IN;
1621 if (comma)
1622 {
3d8df260 1623 new->len = q - ((unsigned char *)comma);
0a852541
SK
1624 new->txt = safe_malloc(new->len);
1625 memcpy(new->txt, comma, new->len);
1626 }
1627 else
1628 {
1629 static char empty[] = "";
1630 new->len = 1;
1631 new->txt = empty;
1632 }
1633
1634 if (comma)
1635 *comma = 0;
91dccd09 1636 new->name = safe_string_alloc(arg);
0a852541
SK
1637 break;
1638 }
1639
f6b7dc47
SK
1640 case 'W':
1641 {
1642 int port = 1, priority = 0, weight = 0;
1643 char *name, *target = NULL;
0a852541 1644 struct mx_srv_record *new;
f6b7dc47 1645
3d8df260 1646 if ((comma = safe_strchr(arg, ',')))
f6b7dc47
SK
1647 *(comma++) = 0;
1648
3d8df260 1649 if (!canonicalise_opt(arg))
f6b7dc47
SK
1650 {
1651 option = '?';
1652 problem = "bad SRV record";
1653 break;
1654 }
91dccd09 1655 name = safe_string_alloc(arg);
f6b7dc47
SK
1656
1657 if (comma)
1658 {
91dccd09 1659 arg = comma;
3d8df260 1660 if ((comma = strchr(arg, ',')))
f6b7dc47 1661 *(comma++) = 0;
3d8df260 1662 if (!canonicalise_opt(arg))
f6b7dc47
SK
1663 {
1664 option = '?';
1665 problem = "bad SRV target";
1666 break;
1667 }
91dccd09 1668 target = safe_string_alloc(arg);
f6b7dc47
SK
1669 if (comma)
1670 {
91dccd09 1671 arg = comma;
3d8df260 1672 if ((comma = strchr(arg, ',')))
f6b7dc47 1673 *(comma++) = 0;
91dccd09 1674 if (!atoi_check(arg, &port))
f6b7dc47
SK
1675 {
1676 option = '?';
1677 problem = "invalid port number";
1678 break;
1679 }
1680 if (comma)
1681 {
91dccd09 1682 arg = comma;
3d8df260 1683 if ((comma = strchr(arg, ',')))
f6b7dc47 1684 *(comma++) = 0;
91dccd09 1685 if (!atoi_check(arg, &priority))
f6b7dc47
SK
1686 {
1687 option = '?';
1688 problem = "invalid priority";
1689 break;
1690 }
1691 if (comma)
1692 {
91dccd09 1693 arg = comma;
3d8df260 1694 if ((comma = strchr(arg, ',')))
f6b7dc47 1695 *(comma++) = 0;
91dccd09 1696 if (!atoi_check(arg, &weight))
f6b7dc47
SK
1697 {
1698 option = '?';
1699 problem = "invalid weight";
1700 break;
1701 }
1702 }
1703 }
1704 }
1705 }
1706
0a852541
SK
1707 new = safe_malloc(sizeof(struct mx_srv_record));
1708 new->next = daemon->mxnames;
1709 daemon->mxnames = new;
1710 new->issrv = 1;
1711 new->name = name;
1712 new->target = target;
f6b7dc47
SK
1713 new->srvport = port;
1714 new->priority = priority;
1715 new->weight = weight;
1716 break;
1717 }
9e4abcb5
SK
1718 }
1719 }
1720
1721 if (option == '?')
1722 {
1723 if (f)
0a852541 1724 complain( problem ? problem : "error", lineno, conffile);
9e4abcb5 1725 else
26128d27 1726#ifdef HAVE_GETOPT_LONG
36717eee 1727 die("bad command line options: %s.", problem ? problem : "try --help");
26128d27
SK
1728#else
1729 die("bad command line options: %s.", problem ? problem : "try -w");
1730#endif
9e4abcb5
SK
1731 }
1732 }
1733
1734 /* port might no be known when the address is parsed - fill in here */
3be34541 1735 if (daemon->servers)
9e4abcb5
SK
1736 {
1737 struct server *tmp;
3be34541 1738 for (tmp = daemon->servers; tmp; tmp = tmp->next)
9e4abcb5
SK
1739 if (!(tmp->flags & SERV_HAS_SOURCE))
1740 {
1741 if (tmp->source_addr.sa.sa_family == AF_INET)
3be34541 1742 tmp->source_addr.in.sin_port = htons(daemon->query_port);
9e4abcb5
SK
1743#ifdef HAVE_IPV6
1744 else if (tmp->source_addr.sa.sa_family == AF_INET6)
3be34541 1745 tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
9e4abcb5
SK
1746#endif
1747 }
1748 }
1749
3be34541 1750 if (daemon->if_addrs)
9e4abcb5
SK
1751 {
1752 struct iname *tmp;
3be34541 1753 for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)
9e4abcb5 1754 if (tmp->addr.sa.sa_family == AF_INET)
3be34541 1755 tmp->addr.in.sin_port = htons(daemon->port);
9e4abcb5
SK
1756#ifdef HAVE_IPV6
1757 else if (tmp->addr.sa.sa_family == AF_INET6)
3be34541 1758 tmp->addr.in6.sin6_port = htons(daemon->port);
9e4abcb5
SK
1759#endif /* IPv6 */
1760 }
1761
f6b7dc47 1762 /* only one of these need be specified: the other defaults to the host-name */
3be34541 1763 if ((daemon->options & OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
9e4abcb5 1764 {
0a852541
SK
1765 struct mx_srv_record *mx;
1766
9e4abcb5
SK
1767 if (gethostname(buff, MAXDNAME) == -1)
1768 die("cannot get host-name: %s", NULL);
f6b7dc47 1769
0a852541
SK
1770 for (mx = daemon->mxnames; mx; mx = mx->next)
1771 if (!mx->issrv && hostname_isequal(mx->name, buff))
1772 break;
1773
1774 if ((daemon->mxtarget || (daemon->options & OPT_LOCALMX)) && !mx)
de37951c 1775 {
91dccd09
SK
1776 mx = safe_malloc(sizeof(struct mx_srv_record));
1777 mx->next = daemon->mxnames;
1778 mx->issrv = 0;
1779 mx->target = NULL;
1780 mx->name = safe_string_alloc(buff);
1781 daemon->mxnames = mx;
f6b7dc47 1782 }
9e4abcb5 1783
3be34541
SK
1784 if (!daemon->mxtarget)
1785 daemon->mxtarget = safe_string_alloc(buff);
0a852541
SK
1786
1787 for (mx = daemon->mxnames; mx; mx = mx->next)
1788 if (!mx->issrv && !mx->target)
1789 mx->target = daemon->mxtarget;
9e4abcb5 1790 }
f6b7dc47 1791
3be34541
SK
1792 if (daemon->options & OPT_NO_RESOLV)
1793 daemon->resolv_files = 0;
3d8df260
SK
1794 else if (daemon->resolv_files &&
1795 (daemon->resolv_files)->next &&
1796 (daemon->options & OPT_NO_POLL))
9e4abcb5 1797 die("only one resolv.conf file allowed in no-poll mode.", NULL);
de37951c 1798
3be34541 1799 if (daemon->options & OPT_RESOLV_DOMAIN)
de37951c
SK
1800 {
1801 char *line;
1802
3be34541 1803 if (!daemon->resolv_files || (daemon->resolv_files)->next)
de37951c
SK
1804 die("must have exactly one resolv.conf to read domain from.", NULL);
1805
3be34541
SK
1806 if (!(f = fopen((daemon->resolv_files)->name, "r")))
1807 die("failed to read %s: %m", (daemon->resolv_files)->name);
de37951c
SK
1808
1809 while ((line = fgets(buff, MAXDNAME, f)))
1810 {
1811 char *token = strtok(line, " \t\n\r");
1812
1813 if (!token || strcmp(token, "search") != 0)
1814 continue;
1815
1816 if ((token = strtok(NULL, " \t\n\r")) &&
3d8df260 1817 canonicalise_opt(token) &&
3be34541 1818 (daemon->domain_suffix = safe_string_alloc(token)))
de37951c
SK
1819 break;
1820 }
3be34541 1821
de37951c 1822 fclose(f);
8a911ccc 1823
3be34541
SK
1824 if (!daemon->domain_suffix)
1825 die("no search directive found in %s", (daemon->resolv_files)->name);
de37951c 1826 }
3d8df260
SK
1827
1828 if (daemon->domain_suffix)
1829 {
1830 /* add domain for any srv record without one. */
1831 struct mx_srv_record *srv;
de37951c 1832
3d8df260
SK
1833 for (srv = daemon->mxnames; srv; srv = srv->next)
1834 if (srv->issrv &&
1835 strchr(srv->name, '.') &&
1836 strchr(srv->name, '.') == strrchr(srv->name, '.'))
1837 {
1838 strcpy(buff, srv->name);
1839 strcat(buff, ".");
1840 strcat(buff, daemon->domain_suffix);
1841 free(srv->name);
1842 srv->name = safe_string_alloc(buff);
1843 }
1844 }
1845
3be34541 1846 return daemon;
9e4abcb5
SK
1847}
1848
1849
1850