Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/resolv/res_init.c
104186 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
#include "un-namespace.h"
90
91
#include "port_after.h"
92
93
/* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
94
#include <resolv.h>
95
96
#include "res_private.h"
97
98
#ifdef SOLARIS2
99
#include <sys/systeminfo.h>
100
#endif
101
102
static void res_setoptions(res_state, const char *, const char *);
103
104
#ifdef RESOLVSORT
105
static const char sort_mask[] = "/&";
106
#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
107
static u_int32_t net_mask(struct in_addr);
108
#endif
109
110
#if !defined(isascii) /*%< XXX - could be a function */
111
# define isascii(c) (!(c & 0200))
112
#endif
113
114
/*
115
* Resolver state default settings.
116
*/
117
118
/*%
119
* Set up default settings. If the configuration file exist, the values
120
* there will have precedence. Otherwise, the server address is set to
121
* the loopback address the default domain name comes from gethostname().
122
*
123
* The configuration file should always be used, since it is the only way
124
* to specify options and a default domain. If you are running a server
125
* on your local machine, you should say "nameserver 127.0.0.1" or
126
* "nameserver ::1" in the configuration file.
127
*
128
* Return 0 if completes successfully, -1 on error
129
*/
130
int
131
res_ninit(res_state statp) {
132
extern int __res_vinit(res_state, int);
133
134
return (__res_vinit(statp, 0));
135
}
136
137
/*% This function has to be reachable by res_data.c but not publicly. */
138
int
139
__res_vinit(res_state statp, int preinit) {
140
union res_sockaddr_union u[] = {
141
{ .sin = {
142
.sin_family = AF_INET,
143
#ifdef HAVE_SA_LEN
144
.sin_len = sizeof(struct sockaddr_in),
145
#endif
146
.sin_port = htons(NAMESERVER_PORT),
147
.sin_addr = { htonl(INADDR_LOOPBACK) },
148
} },
149
#ifdef HAS_INET6_STRUCTS
150
{ .sin6 = {
151
.sin6_family = AF_INET6,
152
#ifdef HAVE_SA_LEN
153
.sin6_len = sizeof(struct sockaddr_in6),
154
#endif
155
.sin6_port = htons(NAMESERVER_PORT),
156
.sin6_addr = IN6ADDR_LOOPBACK_INIT,
157
} },
158
#endif
159
};
160
FILE *fp;
161
char *cp, **pp;
162
int n;
163
char buf[BUFSIZ];
164
int nserv = 0; /*%< number of nameserver records read from file */
165
int haveenv = 0;
166
int havesearch = 0;
167
#ifdef RESOLVSORT
168
int nsort = 0;
169
char *net;
170
#endif
171
int dots;
172
int maxns = MAXNS;
173
174
RES_SET_H_ERRNO(statp, 0);
175
if (statp->_u._ext.ext != NULL)
176
res_ndestroy(statp);
177
178
if (!preinit) {
179
statp->retrans = RES_TIMEOUT;
180
statp->retry = RES_DFLRETRY;
181
statp->options = RES_DEFAULT;
182
}
183
184
statp->id = res_nrandomid(statp);
185
186
statp->nscount = 0;
187
statp->ndots = 1;
188
statp->pfcode = 0;
189
statp->_vcsock = -1;
190
statp->_flags = 0;
191
statp->qhook = NULL;
192
statp->rhook = NULL;
193
statp->_u._ext.nscount = 0;
194
statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext));
195
if (statp->_u._ext.ext != NULL) {
196
memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext));
197
statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr;
198
strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa");
199
strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int");
200
statp->_u._ext.ext->reload_period = 2;
201
} else {
202
/*
203
* Historically res_init() rarely, if at all, failed.
204
* Examples and applications exist which do not check
205
* our return code. Furthermore several applications
206
* simply call us to get the systems domainname. So
207
* rather then immediately fail here we store the
208
* failure, which is returned later, in h_errno. And
209
* prevent the collection of 'nameserver' information
210
* by setting maxns to 0. Thus applications that fail
211
* to check our return code wont be able to make
212
* queries anyhow.
213
*/
214
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
215
maxns = 0;
216
}
217
#ifdef RESOLVSORT
218
statp->nsort = 0;
219
#endif
220
res_setservers(statp, u, nitems(u));
221
222
#ifdef SOLARIS2
223
/*
224
* The old libresolv derived the defaultdomain from NIS/NIS+.
225
* We want to keep this behaviour
226
*/
227
{
228
char buf[sizeof(statp->defdname)], *cp;
229
int ret;
230
231
if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 &&
232
(unsigned int)ret <= sizeof(buf)) {
233
if (buf[0] == '+')
234
buf[0] = '.';
235
cp = strchr(buf, '.');
236
cp = (cp == NULL) ? buf : (cp + 1);
237
strncpy(statp->defdname, cp,
238
sizeof(statp->defdname) - 1);
239
statp->defdname[sizeof(statp->defdname) - 1] = '\0';
240
}
241
}
242
#endif /* SOLARIS2 */
243
244
/* Allow user to override the local domain definition */
245
if ((cp = secure_getenv("LOCALDOMAIN")) != NULL) {
246
(void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
247
statp->defdname[sizeof(statp->defdname) - 1] = '\0';
248
haveenv++;
249
250
/*
251
* Set search list to be blank-separated strings
252
* from rest of env value. Permits users of LOCALDOMAIN
253
* to still have a search list, and anyone to set the
254
* one that they want to use as an individual (even more
255
* important now that the rfc1535 stuff restricts searches)
256
*/
257
cp = statp->defdname;
258
pp = statp->dnsrch;
259
*pp++ = cp;
260
for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
261
if (*cp == '\n') /*%< silly backwards compat */
262
break;
263
else if (*cp == ' ' || *cp == '\t') {
264
*cp = 0;
265
n = 1;
266
} else if (n) {
267
*pp++ = cp;
268
n = 0;
269
havesearch = 1;
270
}
271
}
272
/* null terminate last domain if there are excess */
273
while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
274
cp++;
275
*cp = '\0';
276
*pp++ = NULL;
277
}
278
279
#define MATCH(line, name) \
280
(!strncmp(line, name, sizeof(name) - 1) && \
281
(line[sizeof(name) - 1] == ' ' || \
282
line[sizeof(name) - 1] == '\t'))
283
284
if ((fp = fopen(_PATH_RESCONF, "re")) != NULL) {
285
struct stat sb;
286
struct timespec now;
287
288
if (statp->_u._ext.ext != NULL) {
289
if (_fstat(fileno(fp), &sb) == 0) {
290
statp->_u._ext.ext->conf_mtim = sb.st_mtim;
291
if (clock_gettime(CLOCK_MONOTONIC_FAST, &now) == 0) {
292
statp->_u._ext.ext->conf_stat = now.tv_sec;
293
}
294
}
295
}
296
297
/* read the config file */
298
while (fgets(buf, sizeof(buf), fp) != NULL) {
299
/* skip comments */
300
if (*buf == ';' || *buf == '#')
301
continue;
302
/* read default domain name */
303
if (MATCH(buf, "domain")) {
304
if (haveenv) /*%< skip if have from environ */
305
continue;
306
cp = buf + sizeof("domain") - 1;
307
while (*cp == ' ' || *cp == '\t')
308
cp++;
309
if ((*cp == '\0') || (*cp == '\n'))
310
continue;
311
strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
312
statp->defdname[sizeof(statp->defdname) - 1] = '\0';
313
if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
314
*cp = '\0';
315
havesearch = 0;
316
continue;
317
}
318
/* set search list */
319
if (MATCH(buf, "search")) {
320
if (haveenv) /*%< skip if have from environ */
321
continue;
322
cp = buf + sizeof("search") - 1;
323
while (*cp == ' ' || *cp == '\t')
324
cp++;
325
if ((*cp == '\0') || (*cp == '\n'))
326
continue;
327
strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
328
statp->defdname[sizeof(statp->defdname) - 1] = '\0';
329
if ((cp = strchr(statp->defdname, '\n')) != NULL)
330
*cp = '\0';
331
/*
332
* Set search list to be blank-separated strings
333
* on rest of line.
334
*/
335
cp = statp->defdname;
336
pp = statp->dnsrch;
337
*pp++ = cp;
338
for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
339
if (*cp == ' ' || *cp == '\t') {
340
*cp = 0;
341
n = 1;
342
} else if (n) {
343
*pp++ = cp;
344
n = 0;
345
}
346
}
347
/* null terminate last domain if there are excess */
348
while (*cp != '\0' && *cp != ' ' && *cp != '\t')
349
cp++;
350
*cp = '\0';
351
*pp++ = NULL;
352
havesearch = 1;
353
continue;
354
}
355
/* read nameservers to query */
356
if (MATCH(buf, "nameserver") && nserv < maxns) {
357
struct addrinfo hints, *ai;
358
char sbuf[NI_MAXSERV];
359
const size_t minsiz =
360
sizeof(statp->_u._ext.ext->nsaddrs[0]);
361
362
cp = buf + sizeof("nameserver") - 1;
363
while (*cp == ' ' || *cp == '\t')
364
cp++;
365
cp[strcspn(cp, ";# \t\n")] = '\0';
366
if ((*cp != '\0') && (*cp != '\n')) {
367
memset(&hints, 0, sizeof(hints));
368
hints.ai_family = PF_UNSPEC;
369
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
370
hints.ai_flags = AI_NUMERICHOST;
371
sprintf(sbuf, "%u", NAMESERVER_PORT);
372
if (getaddrinfo(cp, sbuf, &hints, &ai) == 0) {
373
if (ai->ai_addrlen <= minsiz) {
374
if (statp->_u._ext.ext != NULL) {
375
memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
376
ai->ai_addr, ai->ai_addrlen);
377
}
378
if (ai->ai_addrlen <=
379
sizeof(statp->nsaddr_list[nserv])) {
380
memcpy(&statp->nsaddr_list[nserv],
381
ai->ai_addr, ai->ai_addrlen);
382
} else
383
statp->nsaddr_list[nserv].sin_family = 0;
384
nserv++;
385
}
386
freeaddrinfo(ai);
387
}
388
}
389
continue;
390
}
391
#ifdef RESOLVSORT
392
if (MATCH(buf, "sortlist")) {
393
struct in_addr a;
394
struct in6_addr a6;
395
int m, i;
396
u_char *u;
397
struct __res_state_ext *ext = statp->_u._ext.ext;
398
399
cp = buf + sizeof("sortlist") - 1;
400
while (nsort < MAXRESOLVSORT) {
401
while (*cp == ' ' || *cp == '\t')
402
cp++;
403
if (*cp == '\0' || *cp == '\n' || *cp == ';')
404
break;
405
net = cp;
406
while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
407
isascii(*cp) && !isspace((unsigned char)*cp))
408
cp++;
409
n = *cp;
410
*cp = 0;
411
if (inet_aton(net, &a)) {
412
statp->sort_list[nsort].addr = a;
413
if (ISSORTMASK(n)) {
414
*cp++ = n;
415
net = cp;
416
while (*cp && *cp != ';' &&
417
isascii(*cp) &&
418
!isspace((unsigned char)*cp))
419
cp++;
420
n = *cp;
421
*cp = 0;
422
if (inet_aton(net, &a)) {
423
statp->sort_list[nsort].mask = a.s_addr;
424
} else {
425
statp->sort_list[nsort].mask =
426
net_mask(statp->sort_list[nsort].addr);
427
}
428
} else {
429
statp->sort_list[nsort].mask =
430
net_mask(statp->sort_list[nsort].addr);
431
}
432
ext->sort_list[nsort].af = AF_INET;
433
ext->sort_list[nsort].addr.ina =
434
statp->sort_list[nsort].addr;
435
ext->sort_list[nsort].mask.ina.s_addr =
436
statp->sort_list[nsort].mask;
437
nsort++;
438
}
439
else if (inet_pton(AF_INET6, net, &a6) == 1) {
440
441
ext->sort_list[nsort].af = AF_INET6;
442
ext->sort_list[nsort].addr.in6a = a6;
443
u = (u_char *)&ext->sort_list[nsort].mask.in6a;
444
*cp++ = n;
445
net = cp;
446
while (*cp && *cp != ';' &&
447
isascii(*cp) && !isspace(*cp))
448
cp++;
449
m = n;
450
n = *cp;
451
*cp = 0;
452
switch (m) {
453
case '/':
454
m = atoi(net);
455
break;
456
case '&':
457
if (inet_pton(AF_INET6, net, u) == 1) {
458
m = -1;
459
break;
460
}
461
/*FALLTHROUGH*/
462
default:
463
m = sizeof(struct in6_addr) * CHAR_BIT;
464
break;
465
}
466
if (m >= 0) {
467
for (i = 0; i < sizeof(struct in6_addr); i++) {
468
if (m <= 0) {
469
*u = 0;
470
} else {
471
m -= CHAR_BIT;
472
*u = (u_char)~0;
473
if (m < 0)
474
*u <<= -m;
475
}
476
u++;
477
}
478
}
479
statp->sort_list[nsort].addr.s_addr =
480
(u_int32_t)0xffffffff;
481
statp->sort_list[nsort].mask =
482
(u_int32_t)0xffffffff;
483
nsort++;
484
}
485
*cp = n;
486
}
487
continue;
488
}
489
#endif
490
if (MATCH(buf, "options")) {
491
res_setoptions(statp, buf + sizeof("options") - 1, "conf");
492
continue;
493
}
494
}
495
if (nserv > 0)
496
statp->nscount = nserv;
497
#ifdef RESOLVSORT
498
statp->nsort = nsort;
499
#endif
500
(void) fclose(fp);
501
}
502
503
/* guess default domain if not set */
504
if (statp->defdname[0] == 0 &&
505
gethostname(buf, sizeof(statp->defdname) - 1) == 0 &&
506
(cp = strchr(buf, '.')) != NULL)
507
strcpy(statp->defdname, cp + 1);
508
509
/* find components of local domain that might be searched */
510
if (havesearch == 0) {
511
pp = statp->dnsrch;
512
*pp++ = statp->defdname;
513
*pp = NULL;
514
515
dots = 0;
516
for (cp = statp->defdname; *cp; cp++)
517
dots += (*cp == '.');
518
519
cp = statp->defdname;
520
while (pp < statp->dnsrch + MAXDFLSRCH) {
521
if (dots < LOCALDOMAINPARTS)
522
break;
523
cp = strchr(cp, '.') + 1; /*%< we know there is one */
524
*pp++ = cp;
525
dots--;
526
}
527
*pp = NULL;
528
#ifdef DEBUG
529
if (statp->options & RES_DEBUG) {
530
printf(";; res_init()... default dnsrch list:\n");
531
for (pp = statp->dnsrch; *pp; pp++)
532
printf(";;\t%s\n", *pp);
533
printf(";;\t..END..\n");
534
}
535
#endif
536
}
537
538
if (issetugid())
539
statp->options |= RES_NOALIASES;
540
else if ((cp = getenv("RES_OPTIONS")) != NULL)
541
res_setoptions(statp, cp, "env");
542
statp->options |= RES_INIT;
543
return (statp->res_h_errno);
544
}
545
546
static void
547
res_setoptions(res_state statp, const char *options, const char *source)
548
{
549
const char *cp = options;
550
int i;
551
struct __res_state_ext *ext = statp->_u._ext.ext;
552
553
#ifdef DEBUG
554
if (statp->options & RES_DEBUG)
555
printf(";; res_setoptions(\"%s\", \"%s\")...\n",
556
options, source);
557
#endif
558
while (*cp) {
559
/* skip leading and inner runs of spaces */
560
while (*cp == ' ' || *cp == '\t')
561
cp++;
562
/* search for and process individual options */
563
if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
564
i = atoi(cp + sizeof("ndots:") - 1);
565
if (i <= RES_MAXNDOTS)
566
statp->ndots = i;
567
else
568
statp->ndots = RES_MAXNDOTS;
569
#ifdef DEBUG
570
if (statp->options & RES_DEBUG)
571
printf(";;\tndots=%d\n", statp->ndots);
572
#endif
573
} else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
574
i = atoi(cp + sizeof("timeout:") - 1);
575
if (i <= RES_MAXRETRANS)
576
statp->retrans = i;
577
else
578
statp->retrans = RES_MAXRETRANS;
579
#ifdef DEBUG
580
if (statp->options & RES_DEBUG)
581
printf(";;\ttimeout=%d\n", statp->retrans);
582
#endif
583
#ifdef SOLARIS2
584
} else if (!strncmp(cp, "retrans:", sizeof("retrans:") - 1)) {
585
/*
586
* For backward compatibility, 'retrans' is
587
* supported as an alias for 'timeout', though
588
* without an imposed maximum.
589
*/
590
statp->retrans = atoi(cp + sizeof("retrans:") - 1);
591
} else if (!strncmp(cp, "retry:", sizeof("retry:") - 1)){
592
/*
593
* For backward compatibility, 'retry' is
594
* supported as an alias for 'attempts', though
595
* without an imposed maximum.
596
*/
597
statp->retry = atoi(cp + sizeof("retry:") - 1);
598
#endif /* SOLARIS2 */
599
} else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
600
i = atoi(cp + sizeof("attempts:") - 1);
601
if (i <= RES_MAXRETRY)
602
statp->retry = i;
603
else
604
statp->retry = RES_MAXRETRY;
605
#ifdef DEBUG
606
if (statp->options & RES_DEBUG)
607
printf(";;\tattempts=%d\n", statp->retry);
608
#endif
609
} else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
610
#ifdef DEBUG
611
if (!(statp->options & RES_DEBUG)) {
612
printf(";; res_setoptions(\"%s\", \"%s\")..\n",
613
options, source);
614
statp->options |= RES_DEBUG;
615
}
616
printf(";;\tdebug\n");
617
#endif
618
} else if (!strncmp(cp, "no_tld_query",
619
sizeof("no_tld_query") - 1) ||
620
!strncmp(cp, "no-tld-query",
621
sizeof("no-tld-query") - 1)) {
622
statp->options |= RES_NOTLDQUERY;
623
} else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
624
statp->options |= RES_USE_INET6;
625
} else if (!strncmp(cp, "insecure1", sizeof("insecure1") - 1)) {
626
statp->options |= RES_INSECURE1;
627
} else if (!strncmp(cp, "insecure2", sizeof("insecure2") - 1)) {
628
statp->options |= RES_INSECURE2;
629
} else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
630
statp->options |= RES_ROTATE;
631
} else if (!strncmp(cp, "usevc", sizeof("usevc") - 1)) {
632
statp->options |= RES_USEVC;
633
} else if (!strncmp(cp, "no-check-names",
634
sizeof("no-check-names") - 1)) {
635
statp->options |= RES_NOCHECKNAME;
636
} else if (!strncmp(cp, "reload-period:",
637
sizeof("reload-period:") - 1)) {
638
if (ext != NULL) {
639
ext->reload_period = (u_short)
640
atoi(cp + sizeof("reload-period:") - 1);
641
}
642
}
643
#ifdef RES_USE_EDNS0
644
else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
645
statp->options |= RES_USE_EDNS0;
646
}
647
#endif
648
#ifndef _LIBC
649
else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
650
statp->options |= RES_USE_DNAME;
651
}
652
else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) {
653
if (ext == NULL)
654
goto skip;
655
cp += sizeof("nibble:") - 1;
656
i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1);
657
strncpy(ext->nsuffix, cp, i);
658
ext->nsuffix[i] = '\0';
659
}
660
else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) {
661
if (ext == NULL)
662
goto skip;
663
cp += sizeof("nibble2:") - 1;
664
i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1);
665
strncpy(ext->nsuffix2, cp, i);
666
ext->nsuffix2[i] = '\0';
667
}
668
else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) {
669
cp += sizeof("v6revmode:") - 1;
670
/* "nibble" and "bitstring" used to be valid */
671
if (!strncmp(cp, "single", sizeof("single") - 1)) {
672
statp->options |= RES_NO_NIBBLE2;
673
} else if (!strncmp(cp, "both", sizeof("both") - 1)) {
674
statp->options &=
675
~RES_NO_NIBBLE2;
676
}
677
}
678
#endif
679
else {
680
/* XXX - print a warning here? */
681
}
682
#ifndef _LIBC
683
skip:
684
#endif
685
/* skip to next run of spaces */
686
while (*cp && *cp != ' ' && *cp != '\t')
687
cp++;
688
}
689
}
690
691
#ifdef RESOLVSORT
692
/* XXX - should really support CIDR which means explicit masks always. */
693
static u_int32_t
694
net_mask(struct in_addr in) /*!< XXX - should really use system's version of this */
695
{
696
u_int32_t i = ntohl(in.s_addr);
697
698
if (IN_CLASSA(i))
699
return (htonl(IN_CLASSA_NET));
700
else if (IN_CLASSB(i))
701
return (htonl(IN_CLASSB_NET));
702
return (htonl(IN_CLASSC_NET));
703
}
704
#endif
705
706
void
707
freebsd15_res_rndinit(res_state statp)
708
{
709
(void)statp;
710
}
711
__sym_compat(__res_rndinit, freebsd15_res_rndinit, FBSD_1.4);
712
713
u_int
714
res_nrandomid(res_state statp) {
715
(void) statp;
716
717
return ((u_int)(arc4random() & 0xffff));
718
}
719
720
/*%
721
* This routine is for closing the socket if a virtual circuit is used and
722
* the program wants to close it. This provides support for endhostent()
723
* which expects to close the socket.
724
*
725
* This routine is not expected to be user visible.
726
*/
727
void
728
res_nclose(res_state statp) {
729
int ns;
730
731
if (statp->_vcsock >= 0) {
732
(void) _close(statp->_vcsock);
733
statp->_vcsock = -1;
734
statp->_flags &= ~(RES_F_VC | RES_F_CONN);
735
}
736
for (ns = 0; ns < statp->_u._ext.nscount; ns++) {
737
if (statp->_u._ext.nssocks[ns] != -1) {
738
(void) _close(statp->_u._ext.nssocks[ns]);
739
statp->_u._ext.nssocks[ns] = -1;
740
}
741
}
742
}
743
744
void
745
res_ndestroy(res_state statp) {
746
res_nclose(statp);
747
if (statp->_u._ext.ext != NULL) {
748
free(statp->_u._ext.ext);
749
statp->_u._ext.ext = NULL;
750
}
751
statp->options &= ~RES_INIT;
752
}
753
754
#ifndef _LIBC
755
const char *
756
res_get_nibblesuffix(res_state statp) {
757
if (statp->_u._ext.ext)
758
return (statp->_u._ext.ext->nsuffix);
759
return ("ip6.arpa");
760
}
761
762
const char *
763
res_get_nibblesuffix2(res_state statp) {
764
if (statp->_u._ext.ext)
765
return (statp->_u._ext.ext->nsuffix2);
766
return ("ip6.int");
767
}
768
#endif
769
770
void
771
res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
772
int i, nserv;
773
size_t size;
774
775
/* close open servers */
776
res_nclose(statp);
777
778
/* cause rtt times to be forgotten */
779
statp->_u._ext.nscount = 0;
780
781
nserv = 0;
782
for (i = 0; i < cnt && nserv < MAXNS; i++) {
783
switch (set->sin.sin_family) {
784
case AF_INET:
785
size = sizeof(set->sin);
786
if (statp->_u._ext.ext)
787
memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
788
&set->sin, size);
789
if (size <= sizeof(statp->nsaddr_list[nserv]))
790
memcpy(&statp->nsaddr_list[nserv],
791
&set->sin, size);
792
else
793
statp->nsaddr_list[nserv].sin_family = 0;
794
nserv++;
795
break;
796
797
#ifdef HAS_INET6_STRUCTS
798
case AF_INET6:
799
size = sizeof(set->sin6);
800
if (statp->_u._ext.ext)
801
memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
802
&set->sin6, size);
803
if (size <= sizeof(statp->nsaddr_list[nserv]))
804
memcpy(&statp->nsaddr_list[nserv],
805
&set->sin6, size);
806
else
807
statp->nsaddr_list[nserv].sin_family = 0;
808
nserv++;
809
break;
810
#endif
811
812
default:
813
break;
814
}
815
set++;
816
}
817
statp->nscount = nserv;
818
819
}
820
821
int
822
res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) {
823
int i;
824
size_t size;
825
u_int16_t family;
826
827
for (i = 0; i < statp->nscount && i < cnt; i++) {
828
if (statp->_u._ext.ext)
829
family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family;
830
else
831
family = statp->nsaddr_list[i].sin_family;
832
833
switch (family) {
834
case AF_INET:
835
size = sizeof(set->sin);
836
if (statp->_u._ext.ext)
837
memcpy(&set->sin,
838
&statp->_u._ext.ext->nsaddrs[i],
839
size);
840
else
841
memcpy(&set->sin, &statp->nsaddr_list[i],
842
size);
843
break;
844
845
#ifdef HAS_INET6_STRUCTS
846
case AF_INET6:
847
size = sizeof(set->sin6);
848
if (statp->_u._ext.ext)
849
memcpy(&set->sin6,
850
&statp->_u._ext.ext->nsaddrs[i],
851
size);
852
else
853
memcpy(&set->sin6, &statp->nsaddr_list[i],
854
size);
855
break;
856
#endif
857
858
default:
859
set->sin.sin_family = 0;
860
break;
861
}
862
set++;
863
}
864
return (statp->nscount);
865
}
866
867
/*! \file */
868
869