blob: 5c46f0d9ed12eaa86d917501df3e8da88801f040 [file] [log] [blame]
Simon Kelleya84fa1d2004-04-23 22:21:21 +01001/* dnsmasq is Copyright (c) 2000 - 2004 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
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
Simon Kelley26128d22004-11-14 16:43:54 +000024#define OPTSTRING "ZDNLERKzowefnbvhdkqr: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:"
Simon Kelley9e4abcb2004-01-22 19:47:41 +000025
26static struct myoption opts[] = {
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'},
68 {"domain-needed", 0, 0, 'D'},
Simon Kelley44a2a312004-03-10 20:04:35 +000069 {"dhcp-lease-max", 1, 0, 'X' },
Simon Kelley1cff1662004-03-12 08:12:58 +000070 {"bind-interfaces", 0, 0, 'z'},
Simon Kelley44a2a312004-03-10 20:04:35 +000071 {"read-ethers", 0, 0, 'Z' },
Simon Kelley1cff1662004-03-12 08:12:58 +000072 {"alias", 1, 0, 'V' },
Simon Kelleya84fa1d2004-04-23 22:21:21 +010073 {"dhcp-vendorclass", 1, 0, 'U'},
Simon Kelleya2226412004-05-13 20:27:08 +010074 {"dhcp-userclass", 1, 0, 'j'},
Simon Kelley26128d22004-11-14 16:43:54 +000075 {"dhcp-ignore", 1, 0, 'J'},
Simon Kelleyfeba5c12004-07-27 20:28:58 +010076 {"edns-packet-max", 1, 0, 'P'},
Simon Kelley3be34542004-09-11 19:12:13 +010077 {"keep-in-foreground", 0, 0, 'k'},
Simon Kelleyfd9fa482004-10-21 20:24:00 +010078 {"dhcp-authoritative", 0, 0, 'K'},
Simon Kelley9e4abcb2004-01-22 19:47:41 +000079 {0, 0, 0, 0}
80};
81
82struct optflags {
83 char c;
84 unsigned int flag;
85};
86
87static struct optflags optmap[] = {
88 { 'b', OPT_BOGUSPRIV },
89 { 'f', OPT_FILTER },
90 { 'q', OPT_LOG },
91 { 'e', OPT_SELFMX },
92 { 'h', OPT_NO_HOSTS },
93 { 'n', OPT_NO_POLL },
94 { 'd', OPT_DEBUG },
Simon Kelley3be34542004-09-11 19:12:13 +010095 { 'k', OPT_NO_FORK },
Simon Kelleyfd9fa482004-10-21 20:24:00 +010096 { 'K', OPT_AUTHORITATIVE },
Simon Kelley9e4abcb2004-01-22 19:47:41 +000097 { 'o', OPT_ORDER },
98 { 'R', OPT_NO_RESOLV },
99 { 'E', OPT_EXPAND },
Simon Kelley44a2a312004-03-10 20:04:35 +0000100 { 'L', OPT_LOCALMX },
101 { 'N', OPT_NO_NEG },
102 { 'D', OPT_NODOTS_LOCAL },
103 { 'z', OPT_NOWILD },
104 { 'Z', OPT_ETHERS },
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000105 { 'v', 0},
106 { 'w', 0},
107 { 0, 0 }
108};
109
110static char *usage =
Simon Kelley26128d22004-11-14 16:43:54 +0000111"Usage: dnsmasq [options]\n\n"
112#ifndef HAVE_GETOPT_LONG
113"Use short options only on the command line.\n"
114#endif
115"Valid options are :\n"
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000116"-a, --listen-address=ipaddr Specify local address(es) to listen on.\n"
117"-A, --address=/domain/ipaddr Return ipaddr for all hosts in specified domains.\n"
118"-b, --bogus-priv Fake reverse lookups for RFC1918 private address ranges.\n"
119"-B, --bogus-nxdomain=ipaddr Treat ipaddr as NXDOMAIN (defeats Verisign wildcard).\n"
120"-c, --cache-size=cachesize Specify the size of the cache in entries (defaults to %d).\n"
121"-C, --conf-file=path Specify configuration file (defaults to " CONFFILE ").\n"
122"-d, --no-daemon Do NOT fork into the background: run in debug mode.\n"
123"-D, --domain-needed Do NOT forward queries with no domain part.\n"
124"-e, --selfmx Return self-pointing MX records for local hosts.\n"
125"-E, --expand-hosts Expand simple names in /etc/hosts with domain-suffix.\n"
126"-f, --filterwin2k Don't forward spurious DNS requests from Windows hosts.\n"
127"-F, --dhcp-range=ipaddr,ipaddr,time Enable DHCP in the range given with lease duration.\n"
128"-g, --group=groupname Change to this group after startup (defaults to " CHGRP ").\n"
129"-G, --dhcp-host=<hostspec> Set address or hostname for a specified machine.\n"
130"-h, --no-hosts Do NOT load " HOSTSFILE " file.\n"
131"-H, --addn-hosts=path Specify a hosts file to be read in addition to " HOSTSFILE ".\n"
132"-i, --interface=interface Specify interface(s) to listen on.\n"
133"-I, --except-interface=int Specify interface(s) NOT to listen on.\n"
Simon Kelleya2226412004-05-13 20:27:08 +0100134"-j, --dhcp-userclass=<id>,<class> Map DHCP user class to option set.\n"
Simon Kelley26128d22004-11-14 16:43:54 +0000135"-J, --dhcp-ignore=<id> Don't do DHCP for hosts in option set.\n"
Simon Kelley3be34542004-09-11 19:12:13 +0100136"-k, --keep-in-foreground Do NOT fork into the background, do NOT run in debug mode.\n"
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100137"-K, --dhcp-authoritative Assume we are the only DHCP server on the local network.\n"
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000138"-l, --dhcp-leasefile=path Specify where to store DHCP leases (defaults to " LEASEFILE ").\n"
139"-L, --localmx Return MX records for local hosts.\n"
140"-m, --mx-host=host_name Specify the MX name to reply to.\n"
141"-M, --dhcp-boot=<bootp opts> Specify BOOTP options to DHCP server.\n"
142"-n, --no-poll Do NOT poll " RESOLVFILE " file, reload only on SIGHUP.\n"
143"-N, --no-negcache Do NOT cache failed search results.\n"
144"-o, --strict-order Use nameservers strictly in the order given in " RESOLVFILE ".\n"
145"-O, --dhcp-option=<optspec> Set extra options to be set to DHCP clients.\n"
146"-p, --port=number Specify port to listen for DNS requests on (defaults to 53).\n"
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100147"-P, --edns-packet-max=<size> Maximum supported UDP packet size for EDNS.0 (defaults to %d).\n"
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000148"-q, --log-queries Log queries.\n"
149"-Q, --query-port=number Force the originating port for upstream queries.\n"
150"-R, --no-resolv Do NOT read resolv.conf.\n"
151"-r, --resolv-file=path Specify path to resolv.conf (defaults to " RESOLVFILE ").\n"
152"-S, --server=/domain/ipaddr Specify address(es) of upstream servers with optional domains.\n"
153" --local=/domain/ Never forward queries to specified domains.\n"
154"-s, --domain=domain Specify the domain to be assigned in DHCP leases.\n"
155"-t, --mx-target=host_name Specify the host in an MX reply.\n"
156"-T, --local-ttl=time Specify time-to-live in seconds for replies from /etc/hosts.\n"
157"-u, --user=username Change to this user after startup. (defaults to " CHUSER ").\n"
Simon Kelleya84fa1d2004-04-23 22:21:21 +0100158"-U, --dhcp-vendorclass=<id>,<class> Map DHCP vendor class to option set.\n"
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100159"-v, --version Display dnsmasq version and copyright information.\n"
Simon Kelley1cff1662004-03-12 08:12:58 +0000160"-V, --alias=addr,addr,mask Translate IPv4 addresses from upstream servers.\n"
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000161"-w, --help Display this message.\n"
162"-x, --pid-file=path Specify path of PID file. (defaults to " RUNFILE ").\n"
Simon Kelley44a2a312004-03-10 20:04:35 +0000163"-X, --dhcp-lease-max=number Specify maximum number of DHCP leases (defaults to %d).\n"
164"-z, --bind-interfaces Bind only to interfaces in use.\n"
165"-Z, --read-ethers Read DHCP static host information from " ETHERSFILE ".\n"
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000166"\n";
167
168
Simon Kelley3be34542004-09-11 19:12:13 +0100169struct daemon *read_opts (int argc, char **argv)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000170{
Simon Kelley3be34542004-09-11 19:12:13 +0100171 struct daemon *daemon = safe_malloc(sizeof(struct daemon));
Simon Kelley36717ee2004-09-20 19:20:58 +0100172 char *problem = NULL, *buff = safe_malloc(MAXDNAME);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000173 int option = 0, i;
Simon Kelley33820b72004-04-03 21:10:00 +0100174 FILE *file_save = NULL, *f = NULL;
Simon Kelley26128d22004-11-14 16:43:54 +0000175 char *comma, *file_name_save = NULL, *conffile = CONFFILE;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100176 int hosts_index = 1, conffile_set = 0;
Simon Kelley33820b72004-04-03 21:10:00 +0100177 int line_save = 0, lineno = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000178 opterr = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +0000179
Simon Kelley3be34542004-09-11 19:12:13 +0100180 memset(daemon, 0, sizeof(struct daemon));
181 daemon->namebuff = buff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000182
Simon Kelley3be34542004-09-11 19:12:13 +0100183 /* Set defaults - everything else is zero or NULL */
184 daemon->min_leasetime = UINT_MAX;
185 daemon->cachesize = CACHESIZ;
186 daemon->port = NAMESERVER_PORT;
187 daemon->default_resolv.is_default = 1;
188 daemon->default_resolv.name = RESOLVFILE;
189 daemon->resolv_files = &daemon->default_resolv;
190 daemon->username = CHUSER;
191 daemon->groupname = CHGRP;
192 daemon->runfile = RUNFILE;
193 daemon->dhcp_max = MAXLEASES;
194 daemon->edns_pktsz = EDNS_PKTSZ;
195
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000196 while (1)
197 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100198 problem = NULL;
199
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000200 if (!f)
201#ifdef HAVE_GETOPT_LONG
202 option = getopt_long(argc, argv, OPTSTRING, (struct option *)opts, NULL);
203#else
204 option = getopt(argc, argv, OPTSTRING);
205#endif
206 else
207 { /* f non-NULL, reading from conffile. */
Simon Kelley33820b72004-04-03 21:10:00 +0100208 reread:
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000209 if (!fgets(buff, MAXDNAME, f))
210 {
211 /* At end of file, all done */
212 fclose(f);
Simon Kelley33820b72004-04-03 21:10:00 +0100213 if (file_save)
214 {
215 /* may be nested */
216 conffile = file_name_save;
217 f = file_save;
218 file_save = NULL;
219 lineno = line_save;
220 goto reread;
221 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000222 break;
223 }
224 else
225 {
226 char *p;
Simon Kelley33820b72004-04-03 21:10:00 +0100227 int white;
Simon Kelley44a2a312004-03-10 20:04:35 +0000228 lineno++;
Simon Kelley1ab84e22004-01-29 16:48:35 +0000229 /* dump comments */
Simon Kelley33820b72004-04-03 21:10:00 +0100230 for (white = 1, p = buff; *p; p++)
231 if (white && *p == '#')
232 {
233 *p = 0;
234 break;
235 }
236 else
237 white = isspace(*p);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000238 /* fgets gets end of line char too. */
Simon Kelley33820b72004-04-03 21:10:00 +0100239 while (strlen(buff) > 0 && isspace(buff[strlen(buff)-1]))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000240 buff[strlen(buff)-1] = 0;
Simon Kelley1ab84e22004-01-29 16:48:35 +0000241 if (*buff == 0)
242 continue;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000243 if ((p=strchr(buff, '=')))
244 {
245 optarg = p+1;
246 *p = 0;
247 }
248 else
249 optarg = NULL;
250
251 option = 0;
252 for (i=0; opts[i].name; i++)
253 if (strcmp(opts[i].name, buff) == 0)
254 option = opts[i].val;
255 if (!option)
Simon Kelley44a2a312004-03-10 20:04:35 +0000256 {
257 sprintf(buff, "bad option at line %d of %s ", lineno, conffile);
258 complain(buff, NULL);
259 continue;
260 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000261 }
262 }
263
264 if (option == -1)
265 { /* end of command line args, start reading conffile. */
266 if (!conffile)
267 break; /* "confile=" option disables */
Simon Kelley33820b72004-04-03 21:10:00 +0100268 fileopen:
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000269 option = 0;
270 if (!(f = fopen(conffile, "r")))
271 {
272 if (errno == ENOENT && !conffile_set)
273 break; /* No conffile, all done. */
274 else
275 die("cannot read %s: %s", conffile);
276 }
277 }
278
279 if (!f && option == 'w')
280 {
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100281 fprintf (stderr, usage, CACHESIZ, EDNS_PKTSZ, MAXLEASES);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000282 exit(0);
283 }
284
285 if (!f && option == 'v')
286 {
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100287 fprintf(stderr, "Dnsmasq version %s %s\n\n", VERSION, COPYRIGHT);
288 fprintf(stderr, "This software comes with ABSOLUTELY NO WARRANTY.\n");
289 fprintf(stderr, "Dnsmasq is free software, and you are welcome to redistribute it\n");
290 fprintf(stderr, "under the terms of the GNU General Public License, version 2.\n");
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000291 exit(0);
292 }
293
294 for (i=0; optmap[i].c; i++)
295 if (option == optmap[i].c)
296 {
Simon Kelley3be34542004-09-11 19:12:13 +0100297 daemon->options |= optmap[i].flag;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000298 option = 0;
299 if (f && optarg)
Simon Kelley44a2a312004-03-10 20:04:35 +0000300 {
301 sprintf(buff, "extraneous parameter at line %d of %s ", lineno, conffile);
302 complain(buff, NULL);
303 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000304 break;
305 }
306
307 if (option && option != '?')
308 {
309 if (f && !optarg)
Simon Kelley44a2a312004-03-10 20:04:35 +0000310 {
311 sprintf(buff, "missing parameter at line %d of %s ", lineno, conffile);
312 complain(buff, NULL);
313 continue;
314 }
Simon Kelley36717ee2004-09-20 19:20:58 +0100315
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000316 switch (option)
317 {
318 case 'C':
Simon Kelley33820b72004-04-03 21:10:00 +0100319 if (!f)
320 {
321 conffile = safe_string_alloc(optarg);
322 conffile_set = 1;
323 break;
324 }
325
326 /* nest conffiles one deep */
327 if (file_save)
328 {
329 sprintf(buff, "nested includes not allowed at line %d of %s ", lineno, conffile);
330 complain(buff, NULL);
331 continue;
332 }
333 file_name_save = conffile;
334 file_save = f;
335 line_save = lineno;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000336 conffile = safe_string_alloc(optarg);
337 conffile_set = 1;
Simon Kelley33820b72004-04-03 21:10:00 +0100338 lineno = 0;
339 goto fileopen;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000340
341 case 'x':
Simon Kelley3be34542004-09-11 19:12:13 +0100342 daemon->runfile = safe_string_alloc(optarg);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000343 break;
344
345 case 'r':
346 {
347 char *name = safe_string_alloc(optarg);
Simon Kelley3be34542004-09-11 19:12:13 +0100348 struct resolvc *new, *list = daemon->resolv_files;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000349 if (list && list->is_default)
350 {
351 /* replace default resolv file - possibly with nothing */
352 if (name)
353 {
354 list->is_default = 0;
355 list->name = name;
356 }
357 else
358 list = NULL;
359 }
360 else if (name)
361 {
362 new = safe_malloc(sizeof(struct resolvc));
363 new->next = list;
364 new->name = name;
365 new->is_default = 0;
366 new->logged = 0;
367 list = new;
368 }
Simon Kelley3be34542004-09-11 19:12:13 +0100369 daemon->resolv_files = list;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000370 break;
371 }
372
373 case 'm':
Simon Kelleyde379512004-06-22 20:23:33 +0100374 {
Simon Kelley26128d22004-11-14 16:43:54 +0000375 if ((comma = strchr(optarg, ',')))
Simon Kelleyde379512004-06-22 20:23:33 +0100376 *(comma++) = 0;
377 if (!canonicalise(optarg) || (comma && !canonicalise(comma)))
Simon Kelley36717ee2004-09-20 19:20:58 +0100378 {
379 option = '?';
380 problem = "bad MX name";
381 }
Simon Kelleyde379512004-06-22 20:23:33 +0100382 else
383 {
384 struct mx_record *new = safe_malloc(sizeof(struct mx_record));
Simon Kelley3be34542004-09-11 19:12:13 +0100385 new->next = daemon->mxnames;
386 daemon->mxnames = new;
Simon Kelleyde379512004-06-22 20:23:33 +0100387 new->mxname = safe_string_alloc(optarg);
388 new->mxtarget = safe_string_alloc(comma); /* may be NULL */
389 }
390 break;
391 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000392
393 case 't':
394 if (!canonicalise(optarg))
Simon Kelley36717ee2004-09-20 19:20:58 +0100395 {
396 option = '?';
397 problem = "bad MX target";
398 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000399 else
Simon Kelley3be34542004-09-11 19:12:13 +0100400 daemon->mxtarget = safe_string_alloc(optarg);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000401 break;
402
403 case 'l':
Simon Kelley3be34542004-09-11 19:12:13 +0100404 daemon->lease_file = safe_string_alloc(optarg);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000405 break;
406
407 case 'H':
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100408 {
409 struct hostsfile *new = safe_malloc(sizeof(struct hostsfile));
410 new->fname = safe_string_alloc(optarg);
411 new->index = hosts_index++;
412 new->next = daemon->addn_hosts;
413 daemon->addn_hosts = new;
414 break;
415 }
416
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000417 case 's':
Simon Kelleyde379512004-06-22 20:23:33 +0100418 if (strcmp (optarg, "#") == 0)
Simon Kelley3be34542004-09-11 19:12:13 +0100419 daemon->options |= OPT_RESOLV_DOMAIN;
Simon Kelleyde379512004-06-22 20:23:33 +0100420 else if (!canonicalise(optarg))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000421 option = '?';
422 else
Simon Kelley3be34542004-09-11 19:12:13 +0100423 daemon->domain_suffix = safe_string_alloc(optarg);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000424 break;
425
426 case 'u':
Simon Kelley3be34542004-09-11 19:12:13 +0100427 daemon->username = safe_string_alloc(optarg);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000428 break;
429
430 case 'g':
Simon Kelley3be34542004-09-11 19:12:13 +0100431 daemon->groupname = safe_string_alloc(optarg);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000432 break;
433
434 case 'i':
Simon Kelley26128d22004-11-14 16:43:54 +0000435 do {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000436 struct iname *new = safe_malloc(sizeof(struct iname));
Simon Kelley26128d22004-11-14 16:43:54 +0000437 if ((comma = strchr(optarg, ',')))
438 *comma++ = 0;
Simon Kelley3be34542004-09-11 19:12:13 +0100439 new->next = daemon->if_names;
440 daemon->if_names = new;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000441 /* new->name may be NULL if someone does
442 "interface=" to disable all interfaces except loop. */
443 new->name = safe_string_alloc(optarg);
Simon Kelleyde379512004-06-22 20:23:33 +0100444 new->isloop = new->used = 0;
Simon Kelley8a911cc2004-03-16 18:35:52 +0000445 if (strchr(optarg, ':'))
Simon Kelley3be34542004-09-11 19:12:13 +0100446 daemon->options |= OPT_NOWILD;
Simon Kelley26128d22004-11-14 16:43:54 +0000447 optarg = comma;
448 } while (optarg);
449 break;
450
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000451 case 'I':
Simon Kelley26128d22004-11-14 16:43:54 +0000452 do {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000453 struct iname *new = safe_malloc(sizeof(struct iname));
Simon Kelley26128d22004-11-14 16:43:54 +0000454 if ((comma = strchr(optarg, ',')))
455 *comma++ = 0;
Simon Kelley3be34542004-09-11 19:12:13 +0100456 new->next = daemon->if_except;
457 daemon->if_except = new;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000458 new->name = safe_string_alloc(optarg);
Simon Kelley8a911cc2004-03-16 18:35:52 +0000459 if (strchr(optarg, ':'))
Simon Kelley26128d22004-11-14 16:43:54 +0000460 daemon->options |= OPT_NOWILD;
461 optarg = comma;
462 } while (optarg);
463 break;
464
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000465 case 'B':
466 {
467 struct in_addr addr;
468 if ((addr.s_addr = inet_addr(optarg)) != (in_addr_t)-1)
469 {
470 struct bogus_addr *baddr = safe_malloc(sizeof(struct bogus_addr));
Simon Kelley3be34542004-09-11 19:12:13 +0100471 baddr->next = daemon->bogus_addr;
472 daemon->bogus_addr = baddr;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000473 baddr->addr = addr;
474 }
475 else
476 option = '?'; /* error */
477 break;
478 }
479
480 case 'a':
481 {
482 struct iname *new = safe_malloc(sizeof(struct iname));
Simon Kelley3be34542004-09-11 19:12:13 +0100483 new->next = daemon->if_addrs;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000484#ifdef HAVE_IPV6
485 if (inet_pton(AF_INET, optarg, &new->addr.in.sin_addr))
486 {
487 new->addr.sa.sa_family = AF_INET;
488#ifdef HAVE_SOCKADDR_SA_LEN
489 new->addr.in.sin_len = sizeof(struct sockaddr_in);
490#endif
491 }
492 else if (inet_pton(AF_INET6, optarg, &new->addr.in6.sin6_addr))
493 {
494 new->addr.sa.sa_family = AF_INET6;
495 new->addr.in6.sin6_flowinfo = htonl(0);
496#ifdef HAVE_SOCKADDR_SA_LEN
497 new->addr.in6.sin6_len = sizeof(struct sockaddr_in6);
498#endif
499 }
500#else
501 if ((new->addr.in.sin_addr.s_addr = inet_addr(optarg)) != (in_addr_t)-1)
502 {
503 new->addr.sa.sa_family = AF_INET;
504#ifdef HAVE_SOCKADDR_SA_LEN
505 new->addr.in.sin_len = sizeof(struct sockaddr_in);
506#endif
507 }
508#endif
509 else
Simon Kelley44a2a312004-03-10 20:04:35 +0000510 {
511 option = '?'; /* error */
512 free(new);
513 new = NULL;
514 }
515
516 if (new)
Simon Kelley3be34542004-09-11 19:12:13 +0100517 daemon->if_addrs = new;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000518 break;
519 }
520
521 case 'S':
522 case 'A':
523 {
524 struct server *serv, *newlist = NULL;
525
526 if (*optarg == '/')
527 {
528 char *end;
529 optarg++;
530 while ((end = strchr(optarg, '/')))
531 {
Simon Kelleya2226412004-05-13 20:27:08 +0100532 char *domain = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000533 *end = 0;
Simon Kelleya2226412004-05-13 20:27:08 +0100534 /* # matches everything and becomes a zero length domain string */
535 if (strcmp(optarg, "#") == 0)
536 domain = "";
Simon Kelleyde379512004-06-22 20:23:33 +0100537 else if (!canonicalise(optarg) && strlen(optarg) != 0)
Simon Kelley44a2a312004-03-10 20:04:35 +0000538 option = '?';
Simon Kelleya2226412004-05-13 20:27:08 +0100539 else
540 domain = safe_string_alloc(optarg); /* NULL if strlen is zero */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000541 serv = safe_malloc(sizeof(struct server));
542 serv->next = newlist;
543 newlist = serv;
544 serv->sfd = NULL;
545 serv->domain = domain;
546 serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
547 optarg = end+1;
548 }
549 if (!newlist)
550 {
551 option = '?';
552 break;
553 }
554
555 }
556 else
557 {
558 newlist = safe_malloc(sizeof(struct server));
559 newlist->next = NULL;
560 newlist->flags = 0;
561 newlist->sfd = NULL;
562 newlist->domain = NULL;
563 }
564
565 if (option == 'A')
566 {
567 newlist->flags |= SERV_LITERAL_ADDRESS;
568 if (!(newlist->flags & SERV_TYPE))
Simon Kelley44a2a312004-03-10 20:04:35 +0000569 option = '?';
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000570 }
571
572 if (!*optarg)
573 {
574 newlist->flags |= SERV_NO_ADDR; /* no server */
575 if (newlist->flags & SERV_LITERAL_ADDRESS)
Simon Kelley44a2a312004-03-10 20:04:35 +0000576 option = '?';
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000577 }
578 else
579 {
580 int source_port = 0, serv_port = NAMESERVER_PORT;
581 char *portno, *source;
582
583 if ((source = strchr(optarg, '@'))) /* is there a source. */
584 {
585 *source = 0;
586 if ((portno = strchr(source+1, '#')))
587 {
588 *portno = 0;
Simon Kelleya2226412004-05-13 20:27:08 +0100589 if (!atoi_check(portno+1, &source_port))
Simon Kelley36717ee2004-09-20 19:20:58 +0100590 {
591 option = '?';
592 problem = "bad port";
593 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000594 }
595 }
596
597 if ((portno = strchr(optarg, '#'))) /* is there a port no. */
598 {
599 *portno = 0;
Simon Kelleya2226412004-05-13 20:27:08 +0100600 if (!atoi_check(portno+1, &serv_port))
Simon Kelley36717ee2004-09-20 19:20:58 +0100601 {
602 option = '?';
603 problem = "bad port";
604 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000605 }
606
607#ifdef HAVE_IPV6
608 if (inet_pton(AF_INET, optarg, &newlist->addr.in.sin_addr))
609#else
610 if ((newlist->addr.in.sin_addr.s_addr = inet_addr(optarg)) != (in_addr_t) -1)
611#endif
612 {
613 newlist->addr.in.sin_port = htons(serv_port);
614 newlist->source_addr.in.sin_port = htons(source_port);
615 newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET;
616#ifdef HAVE_SOCKADDR_SA_LEN
617 newlist->source_addr.in.sin_len = newlist->addr.in.sin_len = sizeof(struct sockaddr_in);
618#endif
619 if (source)
620 {
621#ifdef HAVE_IPV6
622 if (inet_pton(AF_INET, source+1, &newlist->source_addr.in.sin_addr))
623#else
624 if ((newlist->source_addr.in.sin_addr.s_addr = inet_addr(source+1)) != (in_addr_t) -1)
625#endif
626 newlist->flags |= SERV_HAS_SOURCE;
627 else
628 option = '?'; /* error */
629 }
630 else
631 newlist->source_addr.in.sin_addr.s_addr = INADDR_ANY;
632 }
633#ifdef HAVE_IPV6
634 else if (inet_pton(AF_INET6, optarg, &newlist->addr.in6.sin6_addr))
635 {
636 newlist->addr.in6.sin6_port = htons(serv_port);
637 newlist->source_addr.in6.sin6_port = htons(source_port);
638 newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET6;
639 newlist->addr.in6.sin6_flowinfo = newlist->source_addr.in6.sin6_flowinfo = htonl(0);
640#ifdef HAVE_SOCKADDR_SA_LEN
641 newlist->addr.in6.sin6_len = newlist->source_addr.in6.sin6_len = sizeof(struct sockaddr_in6);
642#endif
643 if (source)
644 {
645 if (inet_pton(AF_INET6, source+1, &newlist->source_addr.in6.sin6_addr))
646 newlist->flags |= SERV_HAS_SOURCE;
647 else
648 option = '?'; /* error */
649 }
650 else
651 newlist->source_addr.in6.sin6_addr = in6addr_any;
652 }
653#endif
654 else
655 option = '?'; /* error */
656
657 }
658
Simon Kelley44a2a312004-03-10 20:04:35 +0000659 if (option == '?')
660 while (newlist)
661 {
662 serv = newlist;
663 newlist = newlist->next;
664 free(serv);
665 }
666 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000667 {
Simon Kelley44a2a312004-03-10 20:04:35 +0000668 serv = newlist;
669 while (serv->next)
670 {
671 serv->next->flags = serv->flags;
672 serv->next->addr = serv->addr;
673 serv->next->source_addr = serv->source_addr;
674 serv = serv->next;
675 }
Simon Kelley3be34542004-09-11 19:12:13 +0100676 serv->next = daemon->servers;
677 daemon->servers = newlist;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000678 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000679 break;
680 }
681
682 case 'c':
683 {
Simon Kelleya2226412004-05-13 20:27:08 +0100684 int size;
685 if (!atoi_check(optarg, &size))
686 option = '?';
687 else
688 {
689 /* zero is OK, and means no caching. */
690
691 if (size < 0)
692 size = 0;
693 else if (size > 10000)
694 size = 10000;
695
Simon Kelley3be34542004-09-11 19:12:13 +0100696 daemon->cachesize = size;
Simon Kelleya2226412004-05-13 20:27:08 +0100697 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000698 break;
699 }
700
701 case 'p':
Simon Kelley3be34542004-09-11 19:12:13 +0100702 if (!atoi_check(optarg, &daemon->port))
Simon Kelleya2226412004-05-13 20:27:08 +0100703 option = '?';
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000704 break;
705
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100706 case 'P':
707 {
708 int i;
709 if (!atoi_check(optarg, &i))
710 option = '?';
Simon Kelley3be34542004-09-11 19:12:13 +0100711 daemon->edns_pktsz = (unsigned short)i;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100712 break;
713 }
714
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000715 case 'Q':
Simon Kelley3be34542004-09-11 19:12:13 +0100716 if (!atoi_check(optarg, &daemon->query_port))
Simon Kelleya2226412004-05-13 20:27:08 +0100717 option = '?';
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000718 break;
719
720 case 'T':
Simon Kelleya2226412004-05-13 20:27:08 +0100721 {
722 int ttl;
723 if (!atoi_check(optarg, &ttl))
724 option = '?';
725 else
Simon Kelley3be34542004-09-11 19:12:13 +0100726 daemon->local_ttl = (unsigned long)ttl;
Simon Kelleya2226412004-05-13 20:27:08 +0100727 break;
728 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000729
Simon Kelley44a2a312004-03-10 20:04:35 +0000730 case 'X':
Simon Kelley3be34542004-09-11 19:12:13 +0100731 if (!atoi_check(optarg, &daemon->dhcp_max))
Simon Kelleya2226412004-05-13 20:27:08 +0100732 option = '?';
Simon Kelley44a2a312004-03-10 20:04:35 +0000733 break;
734
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000735 case 'F':
736 {
Simon Kelley44a2a312004-03-10 20:04:35 +0000737 int k, leasepos = 2;
Simon Kelley26128d22004-11-14 16:43:54 +0000738 char *cp, *a[5] = { NULL, NULL, NULL, NULL, NULL };
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000739 struct dhcp_context *new = safe_malloc(sizeof(struct dhcp_context));
740
Simon Kelley3be34542004-09-11 19:12:13 +0100741 new->next = daemon->dhcp;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100742 new->lease_time = DEFLEASE;
743 new->addr_epoch = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +0000744 new->netmask.s_addr = 0;
745 new->broadcast.s_addr = 0;
Simon Kelley3be34542004-09-11 19:12:13 +0100746 new->router.s_addr = 0;
Simon Kelleya2226412004-05-13 20:27:08 +0100747 new->netid.net = NULL;
Simon Kelley3be34542004-09-11 19:12:13 +0100748 new->static_only = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +0000749
Simon Kelley36717ee2004-09-20 19:20:58 +0100750 problem = "bad dhcp-range";
751
Simon Kelley44a2a312004-03-10 20:04:35 +0000752 for (cp = optarg; *cp; cp++)
753 if (!(*cp == ' ' || *cp == '.' || (*cp >='0' && *cp <= '9')))
754 break;
755
756 if (*cp != ',' && (comma = strchr(optarg, ',')))
757 {
758 *comma = 0;
Simon Kelleya2226412004-05-13 20:27:08 +0100759 new->netid.net = safe_string_alloc(optarg);
Simon Kelley44a2a312004-03-10 20:04:35 +0000760 a[0] = comma + 1;
761 }
762 else
763 a[0] = optarg;
764
765
766 for (k = 1; k < 5; k++)
767 {
768 if (!(a[k] = strchr(a[k-1], ',')))
769 break;
770 *(a[k]++) = 0;
771 }
772
Simon Kelley33820b72004-04-03 21:10:00 +0100773 if ((k < 2) || ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1))
774 option = '?';
775 else if (strcmp(a[1], "static") == 0)
Simon Kelley3be34542004-09-11 19:12:13 +0100776 {
777 new->end = new->start;
778 new->static_only = 1;
779 }
Simon Kelley33820b72004-04-03 21:10:00 +0100780 else if ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1)
781 option = '?';
782
Simon Kelley3be34542004-09-11 19:12:13 +0100783 if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
784 {
785 struct in_addr tmp = new->start;
786 new->start = new->end;
787 new->end = tmp;
788 }
789
Simon Kelley36717ee2004-09-20 19:20:58 +0100790 if (option != '?' && k >= 3 && strchr(a[2], '.') &&
791 ((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
792 {
793 leasepos = 3;
794 if (!is_same_net(new->start, new->end, new->netmask))
795 {
796 problem = "inconsistent DHCP range";
797 option = '?';
798 }
799 }
800
Simon Kelley33820b72004-04-03 21:10:00 +0100801 if (option == '?')
Simon Kelley44a2a312004-03-10 20:04:35 +0000802 {
Simon Kelley44a2a312004-03-10 20:04:35 +0000803 free(new);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000804 break;
805 }
Simon Kelley44a2a312004-03-10 20:04:35 +0000806 else
Simon Kelley3be34542004-09-11 19:12:13 +0100807 daemon->dhcp = new;
Simon Kelley36717ee2004-09-20 19:20:58 +0100808
Simon Kelley44a2a312004-03-10 20:04:35 +0000809 if (k >= 4 && strchr(a[3], '.') &&
810 ((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1))
811 leasepos = 4;
812
813 if (k >= leasepos+1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000814 {
Simon Kelley44a2a312004-03-10 20:04:35 +0000815 if (strcmp(a[leasepos], "infinite") == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000816 new->lease_time = 0xffffffff;
817 else
818 {
819 int fac = 1;
Simon Kelley44a2a312004-03-10 20:04:35 +0000820 if (strlen(a[leasepos]) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000821 {
Simon Kelley44a2a312004-03-10 20:04:35 +0000822 switch (a[leasepos][strlen(a[leasepos]) - 1])
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000823 {
824 case 'h':
825 case 'H':
826 fac *= 60;
827 /* fall through */
828 case 'm':
829 case 'M':
830 fac *= 60;
Simon Kelley44a2a312004-03-10 20:04:35 +0000831 /* fall through */
832 case 's':
833 case 'S':
834 a[leasepos][strlen(a[leasepos]) - 1] = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000835 }
836
Simon Kelley44a2a312004-03-10 20:04:35 +0000837 new->lease_time = atoi(a[leasepos]) * fac;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000838 }
839 }
840 }
Simon Kelley44a2a312004-03-10 20:04:35 +0000841
Simon Kelley3be34542004-09-11 19:12:13 +0100842 if (new->lease_time < daemon->min_leasetime)
843 daemon->min_leasetime = new->lease_time;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000844 break;
845 }
846
847 case 'G':
848 {
849 int j, k;
Simon Kelley33820b72004-04-03 21:10:00 +0100850 char *a[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000851 unsigned int e0, e1, e2, e3, e4, e5;
852 struct dhcp_config *new = safe_malloc(sizeof(struct dhcp_config));
853 struct in_addr in;
854
Simon Kelley3be34542004-09-11 19:12:13 +0100855 new->next = daemon->dhcp_conf;
Simon Kelley33820b72004-04-03 21:10:00 +0100856 new->flags = 0;
857
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000858
859 a[0] = optarg;
Simon Kelley33820b72004-04-03 21:10:00 +0100860 for (k = 1; k < 6; k++)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000861 {
862 if (!(a[k] = strchr(a[k-1], ',')))
863 break;
864 *(a[k]++) = 0;
865 }
866
867 for(j = 0; j < k; j++)
Simon Kelley33820b72004-04-03 21:10:00 +0100868 if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000869 {
870 char *arg = a[j];
871 if ((arg[0] == 'i' || arg[0] == 'I') &&
872 (arg[1] == 'd' || arg[1] == 'D') &&
873 arg[2] == ':')
874 {
Simon Kelleya84fa1d2004-04-23 22:21:21 +0100875 if (arg[3] == '*')
876 new->flags |= CONFIG_NOCLID;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000877 else
Simon Kelleya84fa1d2004-04-23 22:21:21 +0100878 {
879 int len;
880 arg += 3; /* dump id: */
881 if (strchr(arg, ':'))
882 {
883 /* decode hex in place */
884 char *p = arg, *q = arg, *r;
885 while (*p)
886 {
887 for (r = p; *r && *r != ':'; r++);
888 if (*r)
889 {
890 if (r != p)
891 {
892 *r = 0;
893 *(q++) = strtol(p, NULL, 16);
894 }
895 p = r+1;
896 }
897 else
898 {
899 if (*p)
900 *(q++) = strtol(p, NULL, 16);
901 break;
902 }
903 }
904 len = q - arg;
905 }
906 else
907 len = strlen(arg);
908
909 new->flags |= CONFIG_CLID;
910 new->clid_len = len;
911 new->clid = safe_malloc(len);
912 memcpy(new->clid, arg, len);
913 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000914 }
Simon Kelley26128d22004-11-14 16:43:54 +0000915 else if (strstr(arg, "net:") == arg)
Simon Kelley33820b72004-04-03 21:10:00 +0100916 {
917 new->flags |= CONFIG_NETID;
Simon Kelleya2226412004-05-13 20:27:08 +0100918 new->netid.net = safe_string_alloc(arg+4);
Simon Kelley33820b72004-04-03 21:10:00 +0100919 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000920 else if (sscanf(a[j], "%x:%x:%x:%x:%x:%x",
921 &e0, &e1, &e2, &e3, &e4, &e5) == 6)
922 {
Simon Kelley33820b72004-04-03 21:10:00 +0100923 new->flags |= CONFIG_HWADDR;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000924 new->hwaddr[0] = e0;
925 new->hwaddr[1] = e1;
926 new->hwaddr[2] = e2;
927 new->hwaddr[3] = e3;
928 new->hwaddr[4] = e4;
929 new->hwaddr[5] = e5;
930 }
931 else
932 option = '?';
933 }
934 else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1)
Simon Kelley33820b72004-04-03 21:10:00 +0100935 {
936 new->addr = in;
937 new->flags |= CONFIG_ADDR;
938 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000939 else
940 {
941 char *cp, *lastp = NULL, last = 0;
942 int fac = 1;
943
944 if (strlen(a[j]) > 1)
945 {
946 lastp = a[j] + strlen(a[j]) - 1;
947 last = *lastp;
948 switch (last)
949 {
950 case 'h':
951 case 'H':
Simon Kelley1ab84e22004-01-29 16:48:35 +0000952 fac *= 60;
953 /* fall through */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000954 case 'm':
955 case 'M':
956 fac *= 60;
Simon Kelley44a2a312004-03-10 20:04:35 +0000957 /* fall through */
958 case 's':
959 case 'S':
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000960 *lastp = 0;
961 }
962 }
963
964 for (cp = a[j]; *cp; cp++)
Simon Kelley1ab84e22004-01-29 16:48:35 +0000965 if (!isdigit(*cp) && *cp != ' ')
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000966 break;
967
968 if (*cp)
969 {
970 if (lastp)
971 *lastp = last;
972 if (strcmp(a[j], "infinite") == 0)
Simon Kelley33820b72004-04-03 21:10:00 +0100973 {
974 new->lease_time = 0xffffffff;
975 new->flags |= CONFIG_TIME;
976 }
977 else if (strcmp(a[j], "ignore") == 0)
978 new->flags |= CONFIG_DISABLE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000979 else
Simon Kelley33820b72004-04-03 21:10:00 +0100980 {
981 new->hostname = safe_string_alloc(a[j]);
982 new->flags |= CONFIG_NAME;
983 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000984 }
985 else
Simon Kelley33820b72004-04-03 21:10:00 +0100986 {
987 new->lease_time = atoi(a[j]) * fac;
988 new->flags |= CONFIG_TIME;
989 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000990 }
Simon Kelley44a2a312004-03-10 20:04:35 +0000991
992 if (option == '?')
Simon Kelley33820b72004-04-03 21:10:00 +0100993 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100994 problem = "bad dhcp-host";
Simon Kelley33820b72004-04-03 21:10:00 +0100995 if (new->flags & CONFIG_NAME)
996 free(new->hostname);
997 if (new->flags & CONFIG_CLID)
998 free(new->clid);
999 if (new->flags & CONFIG_NETID)
Simon Kelleya2226412004-05-13 20:27:08 +01001000 free(new->netid.net);
Simon Kelley33820b72004-04-03 21:10:00 +01001001 free(new);
1002 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001003 else
Simon Kelley8a911cc2004-03-16 18:35:52 +00001004 {
Simon Kelley3be34542004-09-11 19:12:13 +01001005 if ((new->flags & CONFIG_TIME) && new->lease_time < daemon->min_leasetime)
1006 daemon->min_leasetime = new->lease_time;
1007 daemon->dhcp_conf = new;
Simon Kelley8a911cc2004-03-16 18:35:52 +00001008 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001009 break;
1010 }
1011
1012 case 'O':
1013 {
1014 struct dhcp_opt *new = safe_malloc(sizeof(struct dhcp_opt));
Simon Kelley26128d22004-11-14 16:43:54 +00001015 char *cp;
Simon Kelley33820b72004-04-03 21:10:00 +01001016 int addrs, digs, is_addr, is_hex, is_dec;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001017
Simon Kelley3be34542004-09-11 19:12:13 +01001018 new->next = daemon->dhcp_opts;
Simon Kelley1ab84e22004-01-29 16:48:35 +00001019 new->len = 0;
1020 new->is_addr = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +00001021 new->netid = NULL;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001022 new->val = NULL;
Simon Kelley44a2a312004-03-10 20:04:35 +00001023
1024 if ((comma = strchr(optarg, ',')))
1025 {
Simon Kelley26128d22004-11-14 16:43:54 +00001026 struct dhcp_netid *np = NULL;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001027 *comma++ = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +00001028
Simon Kelley26128d22004-11-14 16:43:54 +00001029 do {
1030 for (cp = optarg; *cp; cp++)
1031 if (!(*cp == ' ' || (*cp >='0' && *cp <= '9')))
1032 break;
1033 if (!*cp)
Simon Kelley44a2a312004-03-10 20:04:35 +00001034 break;
Simon Kelley26128d22004-11-14 16:43:54 +00001035
1036 new->netid = safe_malloc(sizeof (struct dhcp_netid));
1037 new->netid->net = safe_string_alloc(optarg);
1038 new->netid->next = np;
1039 np = new->netid;
1040 optarg = comma;
1041 if ((comma = strchr(optarg, ',')))
1042 *comma++ = 0;
1043 } while (optarg);
Simon Kelley44a2a312004-03-10 20:04:35 +00001044 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001045
Simon Kelley26128d22004-11-14 16:43:54 +00001046 if (!optarg || (new->opt = atoi(optarg)) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001047 {
1048 option = '?';
Simon Kelley26128d22004-11-14 16:43:54 +00001049 problem = "bad dhcp-option";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001050 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001051 else if (comma && new->opt == 119)
Simon Kelley33820b72004-04-03 21:10:00 +01001052 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001053 /* dns search, RFC 3397 */
1054 unsigned char *q, *r, *tail;
1055 unsigned char *p = NULL;
1056 int newlen, len = 0;
1057
1058 optarg = comma;
1059 if ((comma = strchr(optarg, ',')))
1060 *(comma++) = 0;
1061
1062 while (optarg && *optarg)
Simon Kelley33820b72004-04-03 21:10:00 +01001063 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001064 if (!canonicalise(optarg))
Simon Kelley33820b72004-04-03 21:10:00 +01001065 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001066 option = '?';
Simon Kelley26128d22004-11-14 16:43:54 +00001067 problem = "bad domain in dhcp-option";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001068 break;
1069 }
1070
1071 if (!(r = realloc(p, len + strlen(optarg) + 2)))
1072 die("could not get memory", NULL);
1073 p = memmove(r, p, len);
1074
1075 q = p + len;
1076
1077 /* add string on the end in RFC1035 format */
1078 while (*optarg)
1079 {
1080 char *cp = q++;
1081 int j;
1082 for (j = 0; *optarg && (*optarg != '.'); optarg++, j++)
1083 *q++ = *optarg;
1084 *cp = j;
1085 if (*optarg)
1086 optarg++;
1087 }
1088 *q++ = 0;
1089
1090 /* Now tail-compress using earlier names. */
1091 newlen = q - p;
1092 for (tail = p + len; *tail; tail += (*tail) + 1)
1093 for (r = p; r - p < len; r += (*r) + 1)
1094 if (strcmp(r, tail) == 0)
Simon Kelley33820b72004-04-03 21:10:00 +01001095 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001096 PUTSHORT((r - p) | 0xc000, tail);
1097 newlen = tail - p;
1098 goto end;
Simon Kelley33820b72004-04-03 21:10:00 +01001099 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001100 end:
1101 len = newlen;
1102
1103 optarg = comma;
1104 if (optarg && (comma = strchr(optarg, ',')))
1105 *(comma++) = 0;
1106 }
1107
1108 new->len = len;
1109 new->val = p;
1110 }
1111 else if (comma)
1112 {
1113 /* not option 119 */
1114 /* characterise the value */
1115 is_addr = is_hex = is_dec = 1;
1116 addrs = digs = 1;
1117 for (cp = comma; *cp; cp++)
1118 if (*cp == ',')
1119 {
1120 addrs++;
1121 is_dec = is_hex = 0;
1122 }
1123 else if (*cp == ':')
1124 {
1125 digs++;
1126 is_dec = is_addr = 0;
1127 }
1128 else if (*cp == '.')
1129 is_dec = is_hex = 0;
Simon Kelley26128d22004-11-14 16:43:54 +00001130 else if (!((*cp >='0' && *cp <= '9') || *cp == '-'))
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001131 {
1132 is_dec = is_addr = 0;
1133 if (!((*cp >='A' && *cp <= 'F') ||
1134 (*cp >='a' && *cp <= 'f')))
1135 is_hex = 0;
1136 }
1137
1138 if (is_hex && digs > 1)
1139 {
1140 char *p = comma, *q, *r;
1141 new->len = digs;
1142 q = new->val = safe_malloc(new->len);
1143 while (*p)
1144 {
1145 for (r = p; *r && *r != ':'; r++);
1146 if (*r)
1147 {
1148 if (r != p)
1149 {
1150 *r = 0;
1151 *(q++) = strtol(p, NULL, 16);
1152 }
1153 p = r+1;
1154 }
1155 else
1156 {
1157 if (*p)
1158 *(q++) = strtol(p, NULL, 16);
1159 break;
1160 }
1161 }
1162 }
1163 else if (is_dec)
1164 {
Simon Kelley26128d22004-11-14 16:43:54 +00001165 int i, val = atoi(comma);
1166 /* assume numeric arg is 1 byte except for
1167 options where it is known otherwise. */
1168 switch (new->opt)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001169 {
Simon Kelley26128d22004-11-14 16:43:54 +00001170 default:
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001171 new->len = 1;
Simon Kelley26128d22004-11-14 16:43:54 +00001172 break;
1173 case 13: case 22: case 25: case 26:
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001174 new->len = 2;
Simon Kelley26128d22004-11-14 16:43:54 +00001175 break;
1176 case 2: case 24: case 35: case 38:
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001177 new->len = 4;
Simon Kelley26128d22004-11-14 16:43:54 +00001178 break;
Simon Kelley33820b72004-04-03 21:10:00 +01001179 }
Simon Kelley26128d22004-11-14 16:43:54 +00001180 new->val = safe_malloc(new->len);
1181 for (i=0; i<new->len; i++)
1182 new->val[i] = val>>((new->len - i - 1)*8);
Simon Kelley33820b72004-04-03 21:10:00 +01001183 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001184 else if (is_addr)
Simon Kelley33820b72004-04-03 21:10:00 +01001185 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001186 struct in_addr in;
1187 unsigned char *op;
1188 new->len = INADDRSZ * addrs;
1189 new->val = op = safe_malloc(new->len);
1190 new->is_addr = 1;
1191 while (addrs--)
1192 {
1193 cp = comma;
1194 if ((comma = strchr(cp, ',')))
1195 *comma++ = 0;
1196 in.s_addr = inet_addr(cp);
1197 memcpy(op, &in, INADDRSZ);
1198 op += INADDRSZ;
1199 }
Simon Kelley33820b72004-04-03 21:10:00 +01001200 }
1201 else
1202 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001203 /* text arg */
1204 new->len = strlen(comma);
1205 new->val = safe_malloc(new->len);
1206 memcpy(new->val, comma, new->len);
Simon Kelley33820b72004-04-03 21:10:00 +01001207 }
1208 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001209
1210 if (new->len > 256)
Simon Kelley33820b72004-04-03 21:10:00 +01001211 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001212 option = '?';
1213 problem = "dhcp-option too long";
1214 }
1215
1216 if (option == '?')
1217 {
1218 if (new->netid)
1219 free(new->netid);
1220 if (new->val)
1221 free(new->val);
1222 free(new);
Simon Kelley33820b72004-04-03 21:10:00 +01001223 }
1224 else
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001225 daemon->dhcp_opts = new;
1226
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001227 break;
1228 }
1229
1230 case 'M':
1231 {
Simon Kelley26128d22004-11-14 16:43:54 +00001232 struct dhcp_netid *id = NULL;
1233 while (optarg && strstr(optarg, "net:") == optarg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001234 {
Simon Kelley26128d22004-11-14 16:43:54 +00001235 struct dhcp_netid *newid = safe_malloc(sizeof(struct dhcp_netid));
1236 newid->next = id;
1237 id = newid;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001238 if ((comma = strchr(optarg, ',')))
Simon Kelley26128d22004-11-14 16:43:54 +00001239 *comma++ = 0;
1240 newid->net = safe_string_alloc(optarg+4);
1241 optarg = comma;
1242 };
1243
1244 if (!optarg)
1245 option = '?';
1246 else
1247 {
1248 char *dhcp_file, *dhcp_sname = NULL;
1249 struct in_addr dhcp_next_server;
1250 if ((comma = strchr(optarg, ',')))
1251 *comma++ = 0;
1252 dhcp_file = safe_string_alloc(optarg);
1253 dhcp_next_server.s_addr = 0;
1254 if (comma)
1255 {
1256 optarg = comma;
1257 if ((comma = strchr(optarg, ',')))
1258 *comma++ = 0;
1259 dhcp_sname = safe_string_alloc(optarg);
1260 if (comma && (dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
1261 option = '?';
1262 }
1263 if (option != '?')
1264 {
1265 struct dhcp_boot *new = safe_malloc(sizeof(struct dhcp_boot));
1266 new->file = dhcp_file;
1267 new->sname = dhcp_sname;
1268 new->next_server = dhcp_next_server;
1269 new->netid = id;
1270 new->next = daemon->boot_config;
1271 daemon->boot_config = new;
1272 }
1273 }
1274
1275 if (option == '?')
1276 {
1277 struct dhcp_netid *tmp;
1278 for (; id; id = tmp)
1279 {
1280 tmp = id->next;
1281 free(id);
1282 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001283 }
1284 break;
1285 }
Simon Kelley1cff1662004-03-12 08:12:58 +00001286
Simon Kelleya84fa1d2004-04-23 22:21:21 +01001287 case 'U':
Simon Kelleya2226412004-05-13 20:27:08 +01001288 case 'j':
Simon Kelleya84fa1d2004-04-23 22:21:21 +01001289 {
Simon Kelleya84fa1d2004-04-23 22:21:21 +01001290 if (!(comma = strchr(optarg, ',')))
1291 option = '?';
1292 else
1293 {
1294 struct dhcp_vendor *new = safe_malloc(sizeof(struct dhcp_vendor));
1295 *comma = 0;
Simon Kelleya2226412004-05-13 20:27:08 +01001296 new->netid.net = safe_string_alloc(optarg);
Simon Kelleya84fa1d2004-04-23 22:21:21 +01001297 new->len = strlen(comma+1);
1298 new->data = safe_malloc(new->len);
1299 memcpy(new->data, comma+1, new->len);
Simon Kelleya2226412004-05-13 20:27:08 +01001300 new->is_vendor = (option == 'U');
Simon Kelley3be34542004-09-11 19:12:13 +01001301 new->next = daemon->dhcp_vendors;
1302 daemon->dhcp_vendors = new;
Simon Kelleya84fa1d2004-04-23 22:21:21 +01001303 }
1304 break;
1305 }
Simon Kelley26128d22004-11-14 16:43:54 +00001306
1307 case 'J':
1308 {
1309 struct dhcp_netid_list *new = safe_malloc(sizeof(struct dhcp_netid_list));
1310 struct dhcp_netid *list = NULL;
1311 new->next = daemon->dhcp_ignore;
1312 daemon->dhcp_ignore = new;
1313 do {
1314 struct dhcp_netid *member = safe_malloc(sizeof(struct dhcp_netid));
1315 if ((comma = strchr(optarg, ',')))
1316 *comma++ = 0;
1317 member->next = list;
1318 list = member;
1319 member->net = safe_string_alloc(optarg);
1320 optarg = comma;
1321 } while (optarg);
1322
1323 new->list = list;
1324 break;
1325 }
1326
Simon Kelley1cff1662004-03-12 08:12:58 +00001327 case 'V':
1328 {
1329 char *a[3] = { NULL, NULL, NULL };
1330 int k;
1331 struct in_addr in, out, mask;
1332 struct doctor *new;
1333
1334 mask.s_addr = 0xffffffff;
1335
1336 a[0] = optarg;
1337 for (k = 1; k < 4; k++)
1338 {
1339 if (!(a[k] = strchr(a[k-1], ',')))
1340 break;
1341 *(a[k]++) = 0;
1342 }
1343
1344 if ((k < 2) ||
1345 ((in.s_addr = inet_addr(a[0])) == (in_addr_t)-1) ||
1346 ((out.s_addr = inet_addr(a[1])) == (in_addr_t)-1))
1347 {
1348 option = '?';
1349 break;
1350 }
1351
1352 if (k == 3)
1353 mask.s_addr = inet_addr(a[2]);
1354
1355 new = safe_malloc(sizeof(struct doctor));
1356 new->in = in;
1357 new->out = out;
1358 new->mask = mask;
Simon Kelley3be34542004-09-11 19:12:13 +01001359 new->next = daemon->doctors;
1360 daemon->doctors = new;
Simon Kelley1cff1662004-03-12 08:12:58 +00001361
1362 break;
1363 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001364 }
1365 }
1366
1367 if (option == '?')
1368 {
1369 if (f)
Simon Kelley44a2a312004-03-10 20:04:35 +00001370 {
Simon Kelley36717ee2004-09-20 19:20:58 +01001371 sprintf(buff, "%s at line %d of %s ",
1372 problem ? problem : "error", lineno, conffile);
Simon Kelley44a2a312004-03-10 20:04:35 +00001373 complain(buff, NULL);
1374 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001375 else
Simon Kelley26128d22004-11-14 16:43:54 +00001376#ifdef HAVE_GETOPT_LONG
Simon Kelley36717ee2004-09-20 19:20:58 +01001377 die("bad command line options: %s.", problem ? problem : "try --help");
Simon Kelley26128d22004-11-14 16:43:54 +00001378#else
1379 die("bad command line options: %s.", problem ? problem : "try -w");
1380#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001381 }
1382 }
1383
1384 /* port might no be known when the address is parsed - fill in here */
Simon Kelley3be34542004-09-11 19:12:13 +01001385 if (daemon->servers)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001386 {
1387 struct server *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +01001388 for (tmp = daemon->servers; tmp; tmp = tmp->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001389 if (!(tmp->flags & SERV_HAS_SOURCE))
1390 {
1391 if (tmp->source_addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +01001392 tmp->source_addr.in.sin_port = htons(daemon->query_port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001393#ifdef HAVE_IPV6
1394 else if (tmp->source_addr.sa.sa_family == AF_INET6)
Simon Kelley3be34542004-09-11 19:12:13 +01001395 tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001396#endif
1397 }
1398 }
1399
Simon Kelley3be34542004-09-11 19:12:13 +01001400 if (daemon->if_addrs)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001401 {
1402 struct iname *tmp;
Simon Kelley3be34542004-09-11 19:12:13 +01001403 for(tmp = daemon->if_addrs; tmp; tmp = tmp->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001404 if (tmp->addr.sa.sa_family == AF_INET)
Simon Kelley3be34542004-09-11 19:12:13 +01001405 tmp->addr.in.sin_port = htons(daemon->port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001406#ifdef HAVE_IPV6
1407 else if (tmp->addr.sa.sa_family == AF_INET6)
Simon Kelley3be34542004-09-11 19:12:13 +01001408 tmp->addr.in6.sin6_port = htons(daemon->port);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001409#endif /* IPv6 */
1410 }
1411
1412 /* only one of these need be specified: the other defaults to the
1413 host-name */
Simon Kelley3be34542004-09-11 19:12:13 +01001414 if ((daemon->options & OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001415 {
1416 if (gethostname(buff, MAXDNAME) == -1)
1417 die("cannot get host-name: %s", NULL);
1418
Simon Kelley3be34542004-09-11 19:12:13 +01001419 if (!daemon->mxnames)
Simon Kelleyde379512004-06-22 20:23:33 +01001420 {
Simon Kelley3be34542004-09-11 19:12:13 +01001421 daemon->mxnames = safe_malloc(sizeof(struct mx_record));
1422 daemon->mxnames->next = NULL;
1423 daemon->mxnames->mxtarget = NULL;
1424 daemon->mxnames->mxname = safe_string_alloc(buff);
1425}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001426
Simon Kelley3be34542004-09-11 19:12:13 +01001427 if (!daemon->mxtarget)
1428 daemon->mxtarget = safe_string_alloc(buff);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001429 }
1430
Simon Kelley3be34542004-09-11 19:12:13 +01001431 if (daemon->options & OPT_NO_RESOLV)
1432 daemon->resolv_files = 0;
1433 else if (daemon->resolv_files && (daemon->resolv_files)->next && (daemon->options & OPT_NO_POLL))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001434 die("only one resolv.conf file allowed in no-poll mode.", NULL);
Simon Kelleyde379512004-06-22 20:23:33 +01001435
Simon Kelley3be34542004-09-11 19:12:13 +01001436 if (daemon->options & OPT_RESOLV_DOMAIN)
Simon Kelleyde379512004-06-22 20:23:33 +01001437 {
1438 char *line;
1439
Simon Kelley3be34542004-09-11 19:12:13 +01001440 if (!daemon->resolv_files || (daemon->resolv_files)->next)
Simon Kelleyde379512004-06-22 20:23:33 +01001441 die("must have exactly one resolv.conf to read domain from.", NULL);
1442
Simon Kelley3be34542004-09-11 19:12:13 +01001443 if (!(f = fopen((daemon->resolv_files)->name, "r")))
1444 die("failed to read %s: %m", (daemon->resolv_files)->name);
Simon Kelleyde379512004-06-22 20:23:33 +01001445
1446 while ((line = fgets(buff, MAXDNAME, f)))
1447 {
1448 char *token = strtok(line, " \t\n\r");
1449
1450 if (!token || strcmp(token, "search") != 0)
1451 continue;
1452
1453 if ((token = strtok(NULL, " \t\n\r")) &&
1454 canonicalise(token) &&
Simon Kelley3be34542004-09-11 19:12:13 +01001455 (daemon->domain_suffix = safe_string_alloc(token)))
Simon Kelleyde379512004-06-22 20:23:33 +01001456 break;
1457 }
Simon Kelley3be34542004-09-11 19:12:13 +01001458
Simon Kelleyde379512004-06-22 20:23:33 +01001459 fclose(f);
Simon Kelley8a911cc2004-03-16 18:35:52 +00001460
Simon Kelley3be34542004-09-11 19:12:13 +01001461 if (!daemon->domain_suffix)
1462 die("no search directive found in %s", (daemon->resolv_files)->name);
Simon Kelleyde379512004-06-22 20:23:33 +01001463 }
1464
Simon Kelley3be34542004-09-11 19:12:13 +01001465 return daemon;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001466}
1467
1468
1469