Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/net/getnetbydns.c
39530 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1985, 1988, 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
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
32
*
33
* Permission to use, copy, modify, and distribute this software for any
34
* purpose with or without fee is hereby granted, provided that the above
35
* copyright notice and this permission notice appear in all copies, and that
36
* the name of Digital Equipment Corporation not be used in advertising or
37
* publicity pertaining to distribution of the document or software without
38
* specific, written prior permission.
39
*
40
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
43
* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47
* SOFTWARE.
48
* -
49
* --Copyright--
50
*/
51
/* Portions Copyright (c) 1993 Carlos Leandro and Rui Salgueiro
52
* Dep. Matematica Universidade de Coimbra, Portugal, Europe
53
*
54
* Permission to use, copy, modify, and distribute this software for any
55
* purpose with or without fee is hereby granted, provided that the above
56
* copyright notice and this permission notice appear in all copies.
57
*/
58
59
#include <sys/param.h>
60
#include <sys/socket.h>
61
#include <netinet/in.h>
62
#include <arpa/inet.h>
63
#include <arpa/nameser.h>
64
65
#include <errno.h>
66
#include <stdio.h>
67
#include <stdlib.h>
68
#include <netdb.h>
69
#include <resolv.h>
70
#include <ctype.h>
71
#include <string.h>
72
#include <unistd.h>
73
#include <syslog.h>
74
#include <stdarg.h>
75
#include <nsswitch.h>
76
77
#include "netdb_private.h"
78
#include "res_config.h"
79
80
#define BYADDR 0
81
#define BYNAME 1
82
83
#define MAXPACKET (64*1024)
84
85
typedef union {
86
HEADER hdr;
87
u_char buf[MAXPACKET];
88
} querybuf;
89
90
typedef union {
91
long al;
92
char ac;
93
} align;
94
95
/*
96
* Reverse the order of first four dotted entries of in.
97
* Out must contain space for at least strlen(in) characters.
98
* The result does not include any leading 0s of in.
99
*/
100
static void
101
ipreverse(char *in, char *out)
102
{
103
char *pos[4];
104
int len[4];
105
char *p, *start;
106
int i = 0;
107
int leading = 1;
108
109
/* Fill-in element positions and lengths: pos[], len[]. */
110
start = p = in;
111
for (;;) {
112
if (*p == '.' || *p == '\0') {
113
/* Leading 0? */
114
if (leading && p - start == 1 && *start == '0')
115
len[i] = 0;
116
else {
117
len[i] = p - start;
118
leading = 0;
119
}
120
pos[i] = start;
121
start = p + 1;
122
i++;
123
}
124
if (i == 4)
125
break;
126
if (*p == 0) {
127
for (; i < 4; i++) {
128
pos[i] = p;
129
len[i] = 0;
130
}
131
break;
132
}
133
p++;
134
}
135
136
/* Copy the entries in reverse order */
137
p = out;
138
leading = 1;
139
for (i = 3; i >= 0; i--) {
140
memcpy(p, pos[i], len[i]);
141
if (len[i])
142
leading = 0;
143
p += len[i];
144
/* Need a . separator? */
145
if (!leading && i > 0 && len[i - 1])
146
*p++ = '.';
147
}
148
*p = '\0';
149
}
150
151
static int
152
getnetanswer(querybuf *answer, int anslen, int net_i, struct netent *ne,
153
struct netent_data *ned, res_state statp)
154
{
155
156
HEADER *hp;
157
u_char *cp;
158
int n;
159
u_char *eom;
160
int type, class, ancount, qdcount, haveanswer;
161
char aux[MAXHOSTNAMELEN];
162
char ans[MAXHOSTNAMELEN];
163
char *in, *bp, *ep, **ap;
164
165
/*
166
* find first satisfactory answer
167
*
168
* answer --> +------------+ ( MESSAGE )
169
* | Header |
170
* +------------+
171
* | Question | the question for the name server
172
* +------------+
173
* | Answer | RRs answering the question
174
* +------------+
175
* | Authority | RRs pointing toward an authority
176
* | Additional | RRs holding additional information
177
* +------------+
178
*/
179
eom = answer->buf + anslen;
180
hp = &answer->hdr;
181
ancount = ntohs(hp->ancount); /* #/records in the answer section */
182
qdcount = ntohs(hp->qdcount); /* #/entries in the question section */
183
bp = ned->netbuf;
184
ep = ned->netbuf + sizeof(ned->netbuf);
185
cp = answer->buf + HFIXEDSZ;
186
if (!qdcount) {
187
if (hp->aa)
188
RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
189
else
190
RES_SET_H_ERRNO(statp, TRY_AGAIN);
191
return (-1);
192
}
193
while (qdcount-- > 0)
194
cp += __dn_skipname(cp, eom) + QFIXEDSZ;
195
ap = ned->net_aliases;
196
*ap = NULL;
197
ne->n_aliases = ned->net_aliases;
198
haveanswer = 0;
199
while (--ancount >= 0 && cp < eom) {
200
n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
201
if ((n < 0) || !res_dnok(bp))
202
break;
203
cp += n;
204
ans[0] = '\0';
205
(void)strncpy(&ans[0], bp, sizeof(ans) - 1);
206
ans[sizeof(ans) - 1] = '\0';
207
GETSHORT(type, cp);
208
GETSHORT(class, cp);
209
cp += INT32SZ; /* TTL */
210
GETSHORT(n, cp);
211
if (class == C_IN && type == T_PTR) {
212
n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
213
if ((n < 0) || !res_hnok(bp)) {
214
cp += n;
215
return (-1);
216
}
217
cp += n;
218
*ap++ = bp;
219
n = strlen(bp) + 1;
220
bp += n;
221
ne->n_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
222
haveanswer++;
223
}
224
}
225
if (haveanswer) {
226
*ap = NULL;
227
switch (net_i) {
228
case BYADDR:
229
ne->n_name = *ne->n_aliases;
230
ne->n_net = 0L;
231
break;
232
case BYNAME:
233
in = *ne->n_aliases;
234
n = strlen(ans) + 1;
235
if (ep - bp < n) {
236
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
237
errno = ENOBUFS;
238
return (-1);
239
}
240
strlcpy(bp, ans, ep - bp);
241
ne->n_name = bp;
242
if (strlen(in) + 1 > sizeof(aux)) {
243
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
244
errno = ENOBUFS;
245
return (-1);
246
}
247
ipreverse(in, aux);
248
ne->n_net = inet_network(aux);
249
break;
250
}
251
ne->n_aliases++;
252
return (0);
253
}
254
RES_SET_H_ERRNO(statp, TRY_AGAIN);
255
return (-1);
256
}
257
258
int
259
_dns_getnetbyaddr(void *rval, void *cb_data, va_list ap)
260
{
261
uint32_t net;
262
int net_type;
263
char *buffer;
264
size_t buflen;
265
int *errnop, *h_errnop;
266
struct netent *nptr, ne;
267
struct netent_data *ned;
268
unsigned int netbr[4];
269
int nn, anslen, error;
270
querybuf *buf;
271
char qbuf[MAXDNAME];
272
uint32_t net2;
273
res_state statp;
274
275
net = va_arg(ap, uint32_t);
276
net_type = va_arg(ap, int);
277
nptr = va_arg(ap, struct netent *);
278
buffer = va_arg(ap, char *);
279
buflen = va_arg(ap, size_t);
280
errnop = va_arg(ap, int *);
281
h_errnop = va_arg(ap, int *);
282
283
statp = __res_state();
284
if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
285
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
286
*h_errnop = statp->res_h_errno;
287
return (NS_UNAVAIL);
288
}
289
290
if ((ned = __netent_data_init()) == NULL) {
291
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
292
*h_errnop = statp->res_h_errno;
293
return (NS_UNAVAIL);
294
}
295
296
*((struct netent **)rval) = NULL;
297
298
if (net_type != AF_INET) {
299
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
300
*h_errnop = statp->res_h_errno;
301
return (NS_UNAVAIL);
302
}
303
304
for (nn = 4, net2 = net; net2; net2 >>= 8)
305
netbr[--nn] = net2 & 0xff;
306
switch (nn) {
307
case 3: /* Class A */
308
sprintf(qbuf, "0.0.0.%u.in-addr.arpa", netbr[3]);
309
break;
310
case 2: /* Class B */
311
sprintf(qbuf, "0.0.%u.%u.in-addr.arpa", netbr[3], netbr[2]);
312
break;
313
case 1: /* Class C */
314
sprintf(qbuf, "0.%u.%u.%u.in-addr.arpa", netbr[3], netbr[2],
315
netbr[1]);
316
break;
317
case 0: /* Class D - E */
318
sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa", netbr[3], netbr[2],
319
netbr[1], netbr[0]);
320
break;
321
}
322
if ((buf = malloc(sizeof(*buf))) == NULL) {
323
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
324
*h_errnop = statp->res_h_errno;
325
return (NS_NOTFOUND);
326
}
327
anslen = res_nquery(statp, qbuf, C_IN, T_PTR, (u_char *)buf,
328
sizeof(*buf));
329
if (anslen < 0) {
330
free(buf);
331
#ifdef DEBUG
332
if (statp->options & RES_DEBUG)
333
printf("res_nsearch failed\n");
334
#endif
335
*h_errnop = statp->res_h_errno;
336
return (NS_UNAVAIL);
337
} else if (anslen > sizeof(*buf)) {
338
free(buf);
339
#ifdef DEBUG
340
if (statp->options & RES_DEBUG)
341
printf("res_nsearch static buffer too small\n");
342
#endif
343
*h_errnop = statp->res_h_errno;
344
return (NS_UNAVAIL);
345
}
346
error = getnetanswer(buf, anslen, BYADDR, &ne, ned, statp);
347
free(buf);
348
if (error == 0) {
349
/* Strip trailing zeros */
350
while ((net & 0xff) == 0 && net != 0)
351
net >>= 8;
352
ne.n_net = net;
353
if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
354
*errnop = errno;
355
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
356
*h_errnop = statp->res_h_errno;
357
return (NS_RETURN);
358
}
359
*((struct netent **)rval) = nptr;
360
return (NS_SUCCESS);
361
}
362
*h_errnop = statp->res_h_errno;
363
return (NS_NOTFOUND);
364
}
365
366
int
367
_dns_getnetbyname(void *rval, void *cb_data, va_list ap)
368
{
369
const char *net;
370
char *buffer;
371
size_t buflen;
372
int *errnop, *h_errnop;
373
struct netent *nptr, ne;
374
struct netent_data *ned;
375
int anslen, error;
376
querybuf *buf;
377
char qbuf[MAXDNAME];
378
res_state statp;
379
380
net = va_arg(ap, const char *);
381
nptr = va_arg(ap, struct netent *);
382
buffer = va_arg(ap, char *);
383
buflen = va_arg(ap, size_t);
384
errnop = va_arg(ap, int *);
385
h_errnop = va_arg(ap, int *);
386
387
statp = __res_state();
388
if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
389
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
390
*h_errnop = statp->res_h_errno;
391
return (NS_UNAVAIL);
392
}
393
if ((ned = __netent_data_init()) == NULL) {
394
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
395
*h_errnop = statp->res_h_errno;
396
return (NS_UNAVAIL);
397
}
398
if ((buf = malloc(sizeof(*buf))) == NULL) {
399
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
400
*h_errnop = statp->res_h_errno;
401
return (NS_NOTFOUND);
402
}
403
404
*((struct netent **)rval) = NULL;
405
406
strncpy(qbuf, net, sizeof(qbuf) - 1);
407
qbuf[sizeof(qbuf) - 1] = '\0';
408
anslen = res_nsearch(statp, qbuf, C_IN, T_PTR, (u_char *)buf,
409
sizeof(*buf));
410
if (anslen < 0) {
411
free(buf);
412
#ifdef DEBUG
413
if (statp->options & RES_DEBUG)
414
printf("res_nsearch failed\n");
415
#endif
416
return (NS_UNAVAIL);
417
} else if (anslen > sizeof(*buf)) {
418
free(buf);
419
#ifdef DEBUG
420
if (statp->options & RES_DEBUG)
421
printf("res_search static buffer too small\n");
422
#endif
423
return (NS_UNAVAIL);
424
}
425
error = getnetanswer(buf, anslen, BYNAME, &ne, ned, statp);
426
free(buf);
427
if (error != 0) {
428
*h_errnop = statp->res_h_errno;
429
return (NS_NOTFOUND);
430
}
431
if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
432
*errnop = errno;
433
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
434
*h_errnop = statp->res_h_errno;
435
return (NS_RETURN);
436
}
437
*((struct netent **)rval) = nptr;
438
return (NS_SUCCESS);
439
}
440
441
void
442
_setnetdnsent(int stayopen)
443
{
444
res_state statp;
445
446
statp = __res_state();
447
if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1)
448
return;
449
if (stayopen)
450
statp->options |= RES_STAYOPEN | RES_USEVC;
451
}
452
453
void
454
_endnetdnsent(void)
455
{
456
res_state statp;
457
458
statp = __res_state();
459
statp->options &= ~(RES_STAYOPEN | RES_USEVC);
460
res_nclose(statp);
461
}
462
463