]>
Commit | Line | Data |
---|---|---|
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 | ||
17 | struct 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 | 26 | static 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 | ||
88 | struct optflags { | |
89 | char c; | |
90 | unsigned int flag; | |
91 | }; | |
92 | ||
3d8df260 | 93 | static 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 | 119 | static 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 | ||
190 | static char meta[] = "\000123456\a\b\t\n78\r90abcdefABCDEF:,."; | |
191 | ||
192 | static 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 | ||
203 | static 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 | ||
213 | static void unhide_metas(char *cp) | |
214 | { | |
215 | if (cp) | |
216 | for(; *cp; cp++) | |
217 | *cp = unhide_meta(*cp); | |
218 | } | |
219 | ||
220 | static 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 | ||
236 | static char *safe_strchr(char *s, int c) | |
237 | { | |
238 | if (!s) | |
239 | return NULL; | |
240 | ||
241 | return strchr(s, c); | |
242 | } | |
243 | ||
244 | static int canonicalise_opt(char *s) | |
245 | { | |
246 | if (!s) | |
247 | return 0; | |
248 | ||
249 | unhide_metas(s); | |
250 | return canonicalise(s); | |
251 | } | |
252 | ||
253 | static 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 |
270 | static 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 | 285 | struct 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 |