Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/resolv/res_init.c
39476 views
1
/*-
2
* SPDX-License-Identifier: (BSD-3-Clause AND ISC)
3
*
4
* Copyright (c) 1985, 1989, 1993
5
* The Regents of the University of California. All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
* 3. Neither the name of the University nor the names of its contributors
16
* may be used to endorse or promote products derived from this software
17
* without specific prior written permission.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
* SUCH DAMAGE.
30
*/
31
32
/*
33
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
34
*
35
* Permission to use, copy, modify, and distribute this software for any
36
* purpose with or without fee is hereby granted, provided that the above
37
* copyright notice and this permission notice appear in all copies, and that
38
* the name of Digital Equipment Corporation not be used in advertising or
39
* publicity pertaining to distribution of the document or software without
40
* specific, written prior permission.
41
*
42
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
43
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
44
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
45
* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
46
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
47
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
48
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
49
* SOFTWARE.
50
*/
51
52
/*
53
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
54
* Portions Copyright (c) 1996-1999 by Internet Software Consortium.
55
*
56
* Permission to use, copy, modify, and distribute this software for any
57
* purpose with or without fee is hereby granted, provided that the above
58
* copyright notice and this permission notice appear in all copies.
59
*
60
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
61
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
62
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
63
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
64
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
65
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
66
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
67
*/
68
69
#include "port_before.h"
70
71
#include "namespace.h"
72
73
#include <sys/param.h>
74
#include <sys/socket.h>
75
#include <sys/stat.h>
76
#include <sys/time.h>
77
78
#include <netinet/in.h>
79
#include <arpa/inet.h>
80
#include <arpa/nameser.h>
81
82
#include <ctype.h>
83
#include <stdio.h>
84
#include <stdlib.h>
85
#include <string.h>
86
#include <unistd.h>
87
#include <netdb.h>
88
89
#ifndef HAVE_MD5
90
# include "../dst/md5.h"
91
#else
92
# ifdef SOLARIS2
93
# include <sys/md5.h>
94
# elif _LIBC
95
# include <md5.h>
96
# endif
97
#endif
98
#ifndef _MD5_H_
99
# define _MD5_H_ 1 /*%< make sure we do not include rsaref md5.h file */
100
#endif
101
102
#include "un-namespace.h"
103
104
#include "port_after.h"
105
106
/* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
107
#include <resolv.h>
108
109
#include "res_private.h"
110
111
#ifdef SOLARIS2
112
#include <sys/systeminfo.h>
113
#endif
114
115
static void res_setoptions(res_state, const char *, const char *);
116
117
#ifdef RESOLVSORT
118
static const char sort_mask[] = "/&";
119
#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
120
static u_int32_t net_mask(struct in_addr);
121
#endif
122
123
#if !defined(isascii) /*%< XXX - could be a function */
124
# define isascii(c) (!(c & 0200))
125
#endif
126
127
/*
128
* Resolver state default settings.
129
*/
130
131
/*%
132
* Set up default settings. If the configuration file exist, the values
133
* there will have precedence. Otherwise, the server address is set to
134
* INADDR_ANY and the default domain name comes from the gethostname().
135
*
136
* An interim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
137
* rather than INADDR_ANY ("0.0.0.0") as the default name server address
138
* since it was noted that INADDR_ANY actually meant ``the first interface
139
* you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
140
* it had to be "up" in order for you to reach your own name server. It
141
* was later decided that since the recommended practice is to always
142
* install local static routes through 127.0.0.1 for all your network
143
* interfaces, that we could solve this problem without a code change.
144
*
145
* The configuration file should always be used, since it is the only way
146
* to specify a default domain. If you are running a server on your local
147
* machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
148
* in the configuration file.
149
*
150
* Return 0 if completes successfully, -1 on error
151
*/
152
int
153
res_ninit(res_state statp) {
154
extern int __res_vinit(res_state, int);
155
156
return (__res_vinit(statp, 0));
157
}
158
159
/*% This function has to be reachable by res_data.c but not publicly. */
160
int
161
__res_vinit(res_state statp, int preinit) {
162
FILE *fp;
163
char *cp, **pp;
164
int n;
165
char buf[BUFSIZ];
166
int nserv = 0; /*%< number of nameserver records read from file */
167
int haveenv = 0;
168
int havesearch = 0;
169
#ifdef RESOLVSORT
170
int nsort = 0;
171
char *net;
172
#endif
173
int dots;
174
union res_sockaddr_union u[2];
175
int maxns = MAXNS;
176
177
RES_SET_H_ERRNO(statp, 0);
178
if (statp->_u._ext.ext != NULL)
179
res_ndestroy(statp);
180
181
if (!preinit) {
182
statp->retrans = RES_TIMEOUT;
183
statp->retry = RES_DFLRETRY;
184
statp->options = RES_DEFAULT;
185
}
186
187
statp->_rnd = malloc(16);
188
res_rndinit(statp);
189
statp->id = res_nrandomid(statp);
190
191
memset(u, 0, sizeof(u));
192
u[nserv].sin.sin_addr.s_addr = INADDR_ANY;
193
u[nserv].sin.sin_family = AF_INET;
194
u[nserv].sin.sin_port = htons(NAMESERVER_PORT);
195
#ifdef HAVE_SA_LEN
196
u[nserv].sin.sin_len = sizeof(struct sockaddr_in);
197
#endif
198
nserv++;
199
#ifdef HAS_INET6_STRUCTS
200
u[nserv].sin6.sin6_addr = in6addr_any;
201
u[nserv].sin6.sin6_family = AF_INET6;
202
u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT);
203
#ifdef HAVE_SA_LEN
204
u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6);
205
#endif
206
nserv++;
207
#endif
208
statp->nscount = 0;
209
statp->ndots = 1;
210
statp->pfcode = 0;
211
statp->_vcsock = -1;
212
statp->_flags = 0;
213
statp->qhook = NULL;
214
statp->rhook = NULL;
215
statp->_u._ext.nscount = 0;
216
statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext));
217
if (statp->_u._ext.ext != NULL) {
218
memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext));
219
statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr;
220
strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa");
221
strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int");
222
statp->_u._ext.ext->reload_period = 2;
223
} else {
224
/*
225
* Historically res_init() rarely, if at all, failed.
226
* Examples and applications exist which do not check
227
* our return code. Furthermore several applications
228
* simply call us to get the systems domainname. So
229
* rather then immediately fail here we store the
230
* failure, which is returned later, in h_errno. And
231
* prevent the collection of 'nameserver' information
232
* by setting maxns to 0. Thus applications that fail
233
* to check our return code wont be able to make
234
* queries anyhow.
235
*/
236
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
237
maxns = 0;
238
}
239
#ifdef RESOLVSORT
240
statp->nsort = 0;
241
#endif
242
res_setservers(statp, u, nserv);
243
244
#ifdef SOLARIS2
245
/*
246
* The old libresolv derived the defaultdomain from NIS/NIS+.
247
* We want to keep this behaviour
248
*/
249
{
250
char buf[sizeof(statp->defdname)], *cp;
251
int ret;
252
253
if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 &&
254
(unsigned int)ret <= sizeof(buf)) {
255
if (buf[0] == '+')
256
buf[0] = '.';
257
cp = strchr(buf, '.');
258
cp = (cp == NULL) ? buf : (cp + 1);
259
strncpy(statp->defdname, cp,
260
sizeof(statp->defdname) - 1);
261
statp->defdname[sizeof(statp->defdname) - 1] = '\0';
262
}
263
}
264
#endif /* SOLARIS2 */
265
266
/* Allow user to override the local domain definition */
267
if ((cp = secure_getenv("LOCALDOMAIN")) != NULL) {
268
(void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
269
statp->defdname[sizeof(statp->defdname) - 1] = '\0';
270
haveenv++;
271
272
/*
273
* Set search list to be blank-separated strings
274
* from rest of env value. Permits users of LOCALDOMAIN
275
* to still have a search list, and anyone to set the
276
* one that they want to use as an individual (even more
277
* important now that the rfc1535 stuff restricts searches)
278
*/
279
cp = statp->defdname;
280
pp = statp->dnsrch;
281
*pp++ = cp;
282
for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
283
if (*cp == '\n') /*%< silly backwards compat */
284
break;
285
else if (*cp == ' ' || *cp == '\t') {
286
*cp = 0;
287
n = 1;
288
} else if (n) {
289
*pp++ = cp;
290
n = 0;
291
havesearch = 1;
292
}
293
}
294
/* null terminate last domain if there are excess */
295
while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
296
cp++;
297
*cp = '\0';
298
*pp++ = NULL;
299
}
300
301
#define MATCH(line, name) \
302
(!strncmp(line, name, sizeof(name) - 1) && \
303
(line[sizeof(name) - 1] == ' ' || \
304
line[sizeof(name) - 1] == '\t'))
305
306
nserv = 0;
307
if ((fp = fopen(_PATH_RESCONF, "re")) != NULL) {
308
struct stat sb;
309
struct timespec now;
310
311
if (statp->_u._ext.ext != NULL) {
312
if (_fstat(fileno(fp), &sb) == 0) {
313
statp->_u._ext.ext->conf_mtim = sb.st_mtim;
314
if (clock_gettime(CLOCK_MONOTONIC_FAST, &now) == 0) {
315
statp->_u._ext.ext->conf_stat = now.tv_sec;
316
}
317
}
318
}
319
320
/* read the config file */
321
while (fgets(buf, sizeof(buf), fp) != NULL) {
322
/* skip comments */
323
if (*buf == ';' || *buf == '#')
324
continue;
325
/* read default domain name */
326
if (MATCH(buf, "domain")) {
327
if (haveenv) /*%< skip if have from environ */
328
continue;
329
cp = buf + sizeof("domain") - 1;
330
while (*cp == ' ' || *cp == '\t')
331
cp++;
332
if ((*cp == '\0') || (*cp == '\n'))
333
continue;
334
strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
335
statp->defdname[sizeof(statp->defdname) - 1] = '\0';
336
if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
337
*cp = '\0';
338
havesearch = 0;
339
continue;
340
}
341
/* set search list */
342
if (MATCH(buf, "search")) {
343
if (haveenv) /*%< skip if have from environ */
344
continue;
345
cp = buf + sizeof("search") - 1;
346
while (*cp == ' ' || *cp == '\t')
347
cp++;
348
if ((*cp == '\0') || (*cp == '\n'))
349
continue;
350
strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
351
statp->defdname[sizeof(statp->defdname) - 1] = '\0';
352
if ((cp = strchr(statp->defdname, '\n')) != NULL)
353
*cp = '\0';
354
/*
355
* Set search list to be blank-separated strings
356
* on rest of line.
357
*/
358
cp = statp->defdname;
359
pp = statp->dnsrch;
360
*pp++ = cp;
361
for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
362
if (*cp == ' ' || *cp == '\t') {
363
*cp = 0;
364
n = 1;
365
} else if (n) {
366
*pp++ = cp;
367
n = 0;
368
}
369
}
370
/* null terminate last domain if there are excess */
371
while (*cp != '\0' && *cp != ' ' && *cp != '\t')
372
cp++;
373
*cp = '\0';
374
*pp++ = NULL;
375
havesearch = 1;
376
continue;
377
}
378
/* read nameservers to query */
379
if (MATCH(buf, "nameserver") && nserv < maxns) {
380
struct addrinfo hints, *ai;
381
char sbuf[NI_MAXSERV];
382
const size_t minsiz =
383
sizeof(statp->_u._ext.ext->nsaddrs[0]);
384
385
cp = buf + sizeof("nameserver") - 1;
386
while (*cp == ' ' || *cp == '\t')
387
cp++;
388
cp[strcspn(cp, ";# \t\n")] = '\0';
389
if ((*cp != '\0') && (*cp != '\n')) {
390
memset(&hints, 0, sizeof(hints));
391
hints.ai_family = PF_UNSPEC;
392
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
393
hints.ai_flags = AI_NUMERICHOST;
394
sprintf(sbuf, "%u", NAMESERVER_PORT);
395
if (getaddrinfo(cp, sbuf, &hints, &ai) == 0) {
396
if (ai->ai_addrlen <= minsiz) {
397
if (statp->_u._ext.ext != NULL) {
398
memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
399
ai->ai_addr, ai->ai_addrlen);
400
}
401
if (ai->ai_addrlen <=
402
sizeof(statp->nsaddr_list[nserv])) {
403
memcpy(&statp->nsaddr_list[nserv],
404
ai->ai_addr, ai->ai_addrlen);
405
} else
406
statp->nsaddr_list[nserv].sin_family = 0;
407
nserv++;
408
}
409
freeaddrinfo(ai);
410
}
411
}
412
continue;
413
}
414
#ifdef RESOLVSORT
415
if (MATCH(buf, "sortlist")) {
416
struct in_addr a;
417
struct in6_addr a6;
418
int m, i;
419
u_char *u;
420
struct __res_state_ext *ext = statp->_u._ext.ext;
421
422
cp = buf + sizeof("sortlist") - 1;
423
while (nsort < MAXRESOLVSORT) {
424
while (*cp == ' ' || *cp == '\t')
425
cp++;
426
if (*cp == '\0' || *cp == '\n' || *cp == ';')
427
break;
428
net = cp;
429
while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
430
isascii(*cp) && !isspace((unsigned char)*cp))
431
cp++;
432
n = *cp;
433
*cp = 0;
434
if (inet_aton(net, &a)) {
435
statp->sort_list[nsort].addr = a;
436
if (ISSORTMASK(n)) {
437
*cp++ = n;
438
net = cp;
439
while (*cp && *cp != ';' &&
440
isascii(*cp) &&
441
!isspace((unsigned char)*cp))
442
cp++;
443
n = *cp;
444
*cp = 0;
445
if (inet_aton(net, &a)) {
446
statp->sort_list[nsort].mask = a.s_addr;
447
} else {
448
statp->sort_list[nsort].mask =
449
net_mask(statp->sort_list[nsort].addr);
450
}
451
} else {
452
statp->sort_list[nsort].mask =
453
net_mask(statp->sort_list[nsort].addr);
454
}
455
ext->sort_list[nsort].af = AF_INET;
456
ext->sort_list[nsort].addr.ina =
457
statp->sort_list[nsort].addr;
458
ext->sort_list[nsort].mask.ina.s_addr =
459
statp->sort_list[nsort].mask;
460
nsort++;
461
}
462
else if (inet_pton(AF_INET6, net, &a6) == 1) {
463
464
ext->sort_list[nsort].af = AF_INET6;
465
ext->sort_list[nsort].addr.in6a = a6;
466
u = (u_char *)&ext->sort_list[nsort].mask.in6a;
467
*cp++ = n;
468
net = cp;
469
while (*cp && *cp != ';' &&
470
isascii(*cp) && !isspace(*cp))
471
cp++;
472
m = n;
473
n = *cp;
474
*cp = 0;
475
switch (m) {
476
case '/':
477
m = atoi(net);
478
break;
479
case '&':
480
if (inet_pton(AF_INET6, net, u) == 1) {
481
m = -1;
482
break;
483
}
484
/*FALLTHROUGH*/
485
default:
486
m = sizeof(struct in6_addr) * CHAR_BIT;
487
break;
488
}
489
if (m >= 0) {
490
for (i = 0; i < sizeof(struct in6_addr); i++) {
491
if (m <= 0) {
492
*u = 0;
493
} else {
494
m -= CHAR_BIT;
495
*u = (u_char)~0;
496
if (m < 0)
497
*u <<= -m;
498
}
499
u++;
500
}
501
}
502
statp->sort_list[nsort].addr.s_addr =
503
(u_int32_t)0xffffffff;
504
statp->sort_list[nsort].mask =
505
(u_int32_t)0xffffffff;
506
nsort++;
507
}
508
*cp = n;
509
}
510
continue;
511
}
512
#endif
513
if (MATCH(buf, "options")) {
514
res_setoptions(statp, buf + sizeof("options") - 1, "conf");
515
continue;
516
}
517
}
518
if (nserv > 0)
519
statp->nscount = nserv;
520
#ifdef RESOLVSORT
521
statp->nsort = nsort;
522
#endif
523
(void) fclose(fp);
524
}
525
/*
526
* Last chance to get a nameserver. This should not normally
527
* be necessary
528
*/
529
#ifdef NO_RESOLV_CONF
530
if(nserv == 0)
531
nserv = get_nameservers(statp);
532
#endif
533
534
if (statp->defdname[0] == 0 &&
535
gethostname(buf, sizeof(statp->defdname) - 1) == 0 &&
536
(cp = strchr(buf, '.')) != NULL)
537
strcpy(statp->defdname, cp + 1);
538
539
/* find components of local domain that might be searched */
540
if (havesearch == 0) {
541
pp = statp->dnsrch;
542
*pp++ = statp->defdname;
543
*pp = NULL;
544
545
dots = 0;
546
for (cp = statp->defdname; *cp; cp++)
547
dots += (*cp == '.');
548
549
cp = statp->defdname;
550
while (pp < statp->dnsrch + MAXDFLSRCH) {
551
if (dots < LOCALDOMAINPARTS)
552
break;
553
cp = strchr(cp, '.') + 1; /*%< we know there is one */
554
*pp++ = cp;
555
dots--;
556
}
557
*pp = NULL;
558
#ifdef DEBUG
559
if (statp->options & RES_DEBUG) {
560
printf(";; res_init()... default dnsrch list:\n");
561
for (pp = statp->dnsrch; *pp; pp++)
562
printf(";;\t%s\n", *pp);
563
printf(";;\t..END..\n");
564
}
565
#endif
566
}
567
568
if (issetugid())
569
statp->options |= RES_NOALIASES;
570
else if ((cp = getenv("RES_OPTIONS")) != NULL)
571
res_setoptions(statp, cp, "env");
572
statp->options |= RES_INIT;
573
return (statp->res_h_errno);
574
}
575
576
static void
577
res_setoptions(res_state statp, const char *options, const char *source)
578
{
579
const char *cp = options;
580
int i;
581
struct __res_state_ext *ext = statp->_u._ext.ext;
582
583
#ifdef DEBUG
584
if (statp->options & RES_DEBUG)
585
printf(";; res_setoptions(\"%s\", \"%s\")...\n",
586
options, source);
587
#endif
588
while (*cp) {
589
/* skip leading and inner runs of spaces */
590
while (*cp == ' ' || *cp == '\t')
591
cp++;
592
/* search for and process individual options */
593
if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
594
i = atoi(cp + sizeof("ndots:") - 1);
595
if (i <= RES_MAXNDOTS)
596
statp->ndots = i;
597
else
598
statp->ndots = RES_MAXNDOTS;
599
#ifdef DEBUG
600
if (statp->options & RES_DEBUG)
601
printf(";;\tndots=%d\n", statp->ndots);
602
#endif
603
} else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
604
i = atoi(cp + sizeof("timeout:") - 1);
605
if (i <= RES_MAXRETRANS)
606
statp->retrans = i;
607
else
608
statp->retrans = RES_MAXRETRANS;
609
#ifdef DEBUG
610
if (statp->options & RES_DEBUG)
611
printf(";;\ttimeout=%d\n", statp->retrans);
612
#endif
613
#ifdef SOLARIS2
614
} else if (!strncmp(cp, "retrans:", sizeof("retrans:") - 1)) {
615
/*
616
* For backward compatibility, 'retrans' is
617
* supported as an alias for 'timeout', though
618
* without an imposed maximum.
619
*/
620
statp->retrans = atoi(cp + sizeof("retrans:") - 1);
621
} else if (!strncmp(cp, "retry:", sizeof("retry:") - 1)){
622
/*
623
* For backward compatibility, 'retry' is
624
* supported as an alias for 'attempts', though
625
* without an imposed maximum.
626
*/
627
statp->retry = atoi(cp + sizeof("retry:") - 1);
628
#endif /* SOLARIS2 */
629
} else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
630
i = atoi(cp + sizeof("attempts:") - 1);
631
if (i <= RES_MAXRETRY)
632
statp->retry = i;
633
else
634
statp->retry = RES_MAXRETRY;
635
#ifdef DEBUG
636
if (statp->options & RES_DEBUG)
637
printf(";;\tattempts=%d\n", statp->retry);
638
#endif
639
} else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
640
#ifdef DEBUG
641
if (!(statp->options & RES_DEBUG)) {
642
printf(";; res_setoptions(\"%s\", \"%s\")..\n",
643
options, source);
644
statp->options |= RES_DEBUG;
645
}
646
printf(";;\tdebug\n");
647
#endif
648
} else if (!strncmp(cp, "no_tld_query",
649
sizeof("no_tld_query") - 1) ||
650
!strncmp(cp, "no-tld-query",
651
sizeof("no-tld-query") - 1)) {
652
statp->options |= RES_NOTLDQUERY;
653
} else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
654
statp->options |= RES_USE_INET6;
655
} else if (!strncmp(cp, "insecure1", sizeof("insecure1") - 1)) {
656
statp->options |= RES_INSECURE1;
657
} else if (!strncmp(cp, "insecure2", sizeof("insecure2") - 1)) {
658
statp->options |= RES_INSECURE2;
659
} else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
660
statp->options |= RES_ROTATE;
661
} else if (!strncmp(cp, "usevc", sizeof("usevc") - 1)) {
662
statp->options |= RES_USEVC;
663
} else if (!strncmp(cp, "no-check-names",
664
sizeof("no-check-names") - 1)) {
665
statp->options |= RES_NOCHECKNAME;
666
} else if (!strncmp(cp, "reload-period:",
667
sizeof("reload-period:") - 1)) {
668
if (ext != NULL) {
669
ext->reload_period = (u_short)
670
atoi(cp + sizeof("reload-period:") - 1);
671
}
672
}
673
#ifdef RES_USE_EDNS0
674
else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
675
statp->options |= RES_USE_EDNS0;
676
}
677
#endif
678
#ifndef _LIBC
679
else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
680
statp->options |= RES_USE_DNAME;
681
}
682
else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) {
683
if (ext == NULL)
684
goto skip;
685
cp += sizeof("nibble:") - 1;
686
i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1);
687
strncpy(ext->nsuffix, cp, i);
688
ext->nsuffix[i] = '\0';
689
}
690
else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) {
691
if (ext == NULL)
692
goto skip;
693
cp += sizeof("nibble2:") - 1;
694
i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1);
695
strncpy(ext->nsuffix2, cp, i);
696
ext->nsuffix2[i] = '\0';
697
}
698
else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) {
699
cp += sizeof("v6revmode:") - 1;
700
/* "nibble" and "bitstring" used to be valid */
701
if (!strncmp(cp, "single", sizeof("single") - 1)) {
702
statp->options |= RES_NO_NIBBLE2;
703
} else if (!strncmp(cp, "both", sizeof("both") - 1)) {
704
statp->options &=
705
~RES_NO_NIBBLE2;
706
}
707
}
708
#endif
709
else {
710
/* XXX - print a warning here? */
711
}
712
#ifndef _LIBC
713
skip:
714
#endif
715
/* skip to next run of spaces */
716
while (*cp && *cp != ' ' && *cp != '\t')
717
cp++;
718
}
719
}
720
721
#ifdef RESOLVSORT
722
/* XXX - should really support CIDR which means explicit masks always. */
723
static u_int32_t
724
net_mask(struct in_addr in) /*!< XXX - should really use system's version of this */
725
{
726
u_int32_t i = ntohl(in.s_addr);
727
728
if (IN_CLASSA(i))
729
return (htonl(IN_CLASSA_NET));
730
else if (IN_CLASSB(i))
731
return (htonl(IN_CLASSB_NET));
732
return (htonl(IN_CLASSC_NET));
733
}
734
#endif
735
736
static u_char srnd[16];
737
738
void
739
res_rndinit(res_state statp)
740
{
741
struct timeval now;
742
u_int32_t u32;
743
u_int16_t u16;
744
u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd;
745
746
gettimeofday(&now, NULL);
747
u32 = now.tv_sec;
748
memcpy(rnd, &u32, 4);
749
u32 = now.tv_usec;
750
memcpy(rnd + 4, &u32, 4);
751
u32 += now.tv_sec;
752
memcpy(rnd + 8, &u32, 4);
753
u16 = getpid();
754
memcpy(rnd + 12, &u16, 2);
755
}
756
757
u_int
758
res_nrandomid(res_state statp) {
759
struct timeval now;
760
u_int16_t u16;
761
MD5_CTX ctx;
762
u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd;
763
764
gettimeofday(&now, NULL);
765
u16 = (u_int16_t) (now.tv_sec ^ now.tv_usec);
766
memcpy(rnd + 14, &u16, 2);
767
#ifndef HAVE_MD5
768
MD5_Init(&ctx);
769
MD5_Update(&ctx, rnd, 16);
770
MD5_Final(rnd, &ctx);
771
#else
772
MD5Init(&ctx);
773
MD5Update(&ctx, rnd, 16);
774
MD5Final(rnd, &ctx);
775
#endif
776
memcpy(&u16, rnd + 14, 2);
777
return ((u_int) u16);
778
}
779
780
/*%
781
* This routine is for closing the socket if a virtual circuit is used and
782
* the program wants to close it. This provides support for endhostent()
783
* which expects to close the socket.
784
*
785
* This routine is not expected to be user visible.
786
*/
787
void
788
res_nclose(res_state statp) {
789
int ns;
790
791
if (statp->_vcsock >= 0) {
792
(void) _close(statp->_vcsock);
793
statp->_vcsock = -1;
794
statp->_flags &= ~(RES_F_VC | RES_F_CONN);
795
}
796
for (ns = 0; ns < statp->_u._ext.nscount; ns++) {
797
if (statp->_u._ext.nssocks[ns] != -1) {
798
(void) _close(statp->_u._ext.nssocks[ns]);
799
statp->_u._ext.nssocks[ns] = -1;
800
}
801
}
802
}
803
804
void
805
res_ndestroy(res_state statp) {
806
res_nclose(statp);
807
if (statp->_u._ext.ext != NULL) {
808
free(statp->_u._ext.ext);
809
statp->_u._ext.ext = NULL;
810
}
811
if (statp->_rnd != NULL) {
812
free(statp->_rnd);
813
statp->_rnd = NULL;
814
}
815
statp->options &= ~RES_INIT;
816
}
817
818
#ifndef _LIBC
819
const char *
820
res_get_nibblesuffix(res_state statp) {
821
if (statp->_u._ext.ext)
822
return (statp->_u._ext.ext->nsuffix);
823
return ("ip6.arpa");
824
}
825
826
const char *
827
res_get_nibblesuffix2(res_state statp) {
828
if (statp->_u._ext.ext)
829
return (statp->_u._ext.ext->nsuffix2);
830
return ("ip6.int");
831
}
832
#endif
833
834
void
835
res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
836
int i, nserv;
837
size_t size;
838
839
/* close open servers */
840
res_nclose(statp);
841
842
/* cause rtt times to be forgotten */
843
statp->_u._ext.nscount = 0;
844
845
nserv = 0;
846
for (i = 0; i < cnt && nserv < MAXNS; i++) {
847
switch (set->sin.sin_family) {
848
case AF_INET:
849
size = sizeof(set->sin);
850
if (statp->_u._ext.ext)
851
memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
852
&set->sin, size);
853
if (size <= sizeof(statp->nsaddr_list[nserv]))
854
memcpy(&statp->nsaddr_list[nserv],
855
&set->sin, size);
856
else
857
statp->nsaddr_list[nserv].sin_family = 0;
858
nserv++;
859
break;
860
861
#ifdef HAS_INET6_STRUCTS
862
case AF_INET6:
863
size = sizeof(set->sin6);
864
if (statp->_u._ext.ext)
865
memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
866
&set->sin6, size);
867
if (size <= sizeof(statp->nsaddr_list[nserv]))
868
memcpy(&statp->nsaddr_list[nserv],
869
&set->sin6, size);
870
else
871
statp->nsaddr_list[nserv].sin_family = 0;
872
nserv++;
873
break;
874
#endif
875
876
default:
877
break;
878
}
879
set++;
880
}
881
statp->nscount = nserv;
882
883
}
884
885
int
886
res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) {
887
int i;
888
size_t size;
889
u_int16_t family;
890
891
for (i = 0; i < statp->nscount && i < cnt; i++) {
892
if (statp->_u._ext.ext)
893
family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family;
894
else
895
family = statp->nsaddr_list[i].sin_family;
896
897
switch (family) {
898
case AF_INET:
899
size = sizeof(set->sin);
900
if (statp->_u._ext.ext)
901
memcpy(&set->sin,
902
&statp->_u._ext.ext->nsaddrs[i],
903
size);
904
else
905
memcpy(&set->sin, &statp->nsaddr_list[i],
906
size);
907
break;
908
909
#ifdef HAS_INET6_STRUCTS
910
case AF_INET6:
911
size = sizeof(set->sin6);
912
if (statp->_u._ext.ext)
913
memcpy(&set->sin6,
914
&statp->_u._ext.ext->nsaddrs[i],
915
size);
916
else
917
memcpy(&set->sin6, &statp->nsaddr_list[i],
918
size);
919
break;
920
#endif
921
922
default:
923
set->sin.sin_family = 0;
924
break;
925
}
926
set++;
927
}
928
return (statp->nscount);
929
}
930
931
/*! \file */
932
933