]> git.ipfire.org Git - thirdparty/glibc.git/blame - resolv/nss_dns/dns-network.c
Update.
[thirdparty/glibc.git] / resolv / nss_dns / dns-network.c
CommitLineData
8d8c6efa 1/* Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
84384f5b
UD
2 This file is part of the GNU C Library.
3 Extended from original form by Ulrich Drepper <drepper@cygnus.com>, 1996.
5f0e6fc7 4
84384f5b
UD
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
5f0e6fc7 9
84384f5b
UD
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
5f0e6fc7 14
84384f5b
UD
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
5f0e6fc7
RM
19
20/* Parts of this file are plain copies of the file `getnetnamadr.c' from
21 the bind package and it has the following copyright. */
22
23/* Copyright (c) 1993 Carlos Leandro and Rui Salgueiro
24 * Dep. Matematica Universidade de Coimbra, Portugal, Europe
25 *
26 * Permission to use, copy, modify, and distribute this software for any
27 * purpose with or without fee is hereby granted, provided that the above
28 * copyright notice and this permission notice appear in all copies.
29 */
30/*
31 * Copyright (c) 1983, 1993
32 * The Regents of the University of California. All rights reserved.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
5f0e6fc7
RM
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 */
58
59#include <ctype.h>
60#include <errno.h>
61#include <netdb.h>
62#include <stdio.h>
63#include <stdlib.h>
64#include <string.h>
65
66#include "nsswitch.h"
67#include <arpa/inet.h>
68
69/* Maximum number of aliases we allow. */
70#define MAX_NR_ALIASES 48
71
72
73#if PACKETSZ > 1024
74#define MAXPACKET PACKETSZ
75#else
76#define MAXPACKET 1024
77#endif
78
79
80typedef enum
81{
82 BYADDR,
83 BYNAME
84} lookup_method;
85
86
87/* We need this time later. */
88typedef union querybuf
89{
90 HEADER hdr;
91 u_char buf[MAXPACKET];
92} querybuf;
93
8d8c6efa
UD
94/* These functions are defined in res_comp.c. */
95#define NS_MAXCDNAME 255 /* maximum compressed domain name */
96extern int __ns_name_ntop __P ((const u_char *, char *, size_t));
97extern int __ns_name_unpack __P ((const u_char *, const u_char *,
98 const u_char *, u_char *, size_t));
99
5f0e6fc7 100
6d52618b 101/* Prototypes for local functions. */
84384f5b
UD
102static enum nss_status getanswer_r (const querybuf *answer, int anslen,
103 struct netent *result, char *buffer,
df4ef2ab 104 size_t buflen, lookup_method net_i);
5f0e6fc7
RM
105
106
84384f5b 107enum nss_status
5f0e6fc7 108_nss_dns_getnetbyname_r (const char *name, struct netent *result,
67479a70 109 char *buffer, size_t buflen, int *errnop)
5f0e6fc7
RM
110{
111 /* Return entry for network with NAME. */
112 querybuf net_buffer;
113 int anslen;
114 char *qbuf;
115
116 qbuf = strdupa (name);
117 anslen = res_search (qbuf, C_IN, T_PTR, (u_char *) &net_buffer,
118 sizeof (querybuf));
119 if (anslen < 0)
67479a70
UD
120 {
121 /* Nothing found. */
122 *errnop = errno;
123 return (errno == ECONNREFUSED
124 || errno == EPFNOSUPPORT
125 || errno == EAFNOSUPPORT)
126 ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
127 }
5f0e6fc7
RM
128
129 return getanswer_r (&net_buffer, anslen, result, buffer, buflen, BYNAME);
130}
131
132
84384f5b 133enum nss_status
5f0e6fc7 134_nss_dns_getnetbyaddr_r (long net, int type, struct netent *result,
67479a70 135 char *buffer, size_t buflen, int *errnop)
5f0e6fc7
RM
136{
137 /* Return entry for network with NAME. */
84384f5b 138 enum nss_status status;
5f0e6fc7
RM
139 querybuf net_buffer;
140 unsigned int net_bytes[4];
141 char qbuf[MAXDNAME];
142 int cnt, anslen;
143 u_int32_t net2;
144
145 /* No net address lookup for IPv6 yet. */
146 if (type != AF_INET)
147 return NSS_STATUS_UNAVAIL;
148
149 net2 = (u_int32_t) net;
150 for (cnt = 4; net2 != 0; net2 >>= 8)
151 net_bytes[--cnt] = net2 & 0xff;
152
153 switch (cnt)
154 {
155 case 3:
156 /* Class A network. */
157 sprintf (qbuf, "0.0.0.%u.in-addr.arpa", net_bytes[3]);
158 break;
159 case 2:
160 /* Class B network. */
161 sprintf (qbuf, "0.0.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2]);
162 break;
163 case 1:
164 /* Class C network. */
165 sprintf (qbuf, "0.%u.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2],
166 net_bytes[1]);
167 break;
168 case 0:
169 /* Class D - E network. */
170 sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2],
171 net_bytes[1], net_bytes[0]);
172 break;
173 }
174
175 anslen = res_query (qbuf, C_IN, T_PTR, (u_char *) &net_buffer,
176 sizeof (querybuf));
177 if (anslen < 0)
67479a70
UD
178 {
179 /* Nothing found. */
180 *errnop = errno;
181 return (errno == ECONNREFUSED
182 || errno == EPFNOSUPPORT
183 || errno == EAFNOSUPPORT)
184 ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
185 }
5f0e6fc7
RM
186
187 status = getanswer_r (&net_buffer, anslen, result, buffer, buflen, BYADDR);
188 if (status == NSS_STATUS_SUCCESS)
189 {
190 /* Strip trailing zeros. */
191 unsigned int u_net = net; /* Maybe net should be unsigned? */
192
193 while ((u_net & 0xff) == 0 && u_net != 0)
194 u_net >>= 8;
195 result->n_net = u_net;
196 }
197
198 return status;
199}
200
201
202#undef offsetof
203#define offsetof(Type, Member) ((size_t) &((Type *) NULL)->Member)
204
84384f5b 205static enum nss_status
5f0e6fc7 206getanswer_r (const querybuf *answer, int anslen, struct netent *result,
df4ef2ab 207 char *buffer, size_t buflen, lookup_method net_i)
5f0e6fc7
RM
208{
209 /*
210 * Find first satisfactory answer
211 *
212 * answer --> +------------+ ( MESSAGE )
213 * | Header |
214 * +------------+
215 * | Question | the question for the name server
216 * +------------+
217 * | Answer | RRs answering the question
218 * +------------+
219 * | Authority | RRs pointing toward an authority
220 * | Additional | RRs holding additional information
221 * +------------+
222 */
223 struct net_data
224 {
225 char *aliases[MAX_NR_ALIASES];
226 char linebuffer[0];
227 } *net_data = (struct net_data *) buffer;
228 int linebuflen = buflen - offsetof (struct net_data, linebuffer);
229 const char *end_of_message = &answer->buf[anslen];
230 const HEADER *header_pointer = &answer->hdr;
231 /* #/records in the answer section. */
232 int answer_count = ntohs (header_pointer->ancount);
233 /* #/entries in the question section. */
234 int question_count = ntohs (header_pointer->qdcount);
235 char *bp = net_data->linebuffer;
236 const char *cp = &answer->buf[HFIXEDSZ];
237 char **alias_pointer;
238 int have_answer;
239 char *ans;
8d8c6efa 240 u_char packtmp[NS_MAXCDNAME];
5f0e6fc7
RM
241
242 if (question_count == 0)
7ef90c15
UD
243 {
244 /* FIXME: the Sun version uses for host name lookup an additional
245 parameter for pointing to h_errno. this is missing here.
246 OSF/1 has a per-thread h_errno variable. */
247 if (header_pointer->aa != 0)
248 {
249 __set_h_errno (HOST_NOT_FOUND);
250 return NSS_STATUS_NOTFOUND;
251 }
252 else
253 {
254 __set_h_errno (TRY_AGAIN);
255 return NSS_STATUS_TRYAGAIN;
256 }
257 }
5f0e6fc7
RM
258
259 /* Skip the question part. */
260 while (question_count-- > 0)
261 cp += __dn_skipname (cp, end_of_message) + QFIXEDSZ;
262
263 alias_pointer = result->n_aliases = &net_data->aliases[0];
264 *alias_pointer = NULL;
265 have_answer = 0;
266 ans = NULL;
267
268 while (--answer_count >= 0 && cp < end_of_message)
269 {
270 int n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen);
271 int type, class;
272
8d8c6efa
UD
273 n = __ns_name_unpack (answer->buf, end_of_message, cp,
274 packtmp, sizeof packtmp);
275 if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
276 {
277 if (errno == EMSGSIZE)
278 {
279 errno = ERANGE;
280 return NSS_STATUS_TRYAGAIN;
281 }
282
283 n = -1;
284 }
285
286 if (n > 0 && bp[0] == '.')
287 bp[0] = '\0';
288
5f0e6fc7
RM
289 if (n < 0 || res_dnok (bp) == 0)
290 break;
291 cp += n;
292 ans = strdupa (bp);
293 GETSHORT (type, cp);
294 GETSHORT (class, cp);
295 cp += INT32SZ; /* TTL */
296 GETSHORT (n, cp);
297
298 if (class == C_IN && type == T_PTR)
299 {
8d8c6efa
UD
300 n = __ns_name_unpack (answer->buf, end_of_message, cp,
301 packtmp, sizeof packtmp);
302 if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
303 {
304 if (errno == EMSGSIZE)
305 {
306 errno = ERANGE;
307 return NSS_STATUS_TRYAGAIN;
308 }
309
310 n = -1;
311 }
312
5f0e6fc7
RM
313 if (n < 0 || !res_hnok (bp))
314 {
315 /* XXX What does this mean? The original form from bind
316 returns NULL. Incrementing cp has no effect in any case.
317 What should I return here. ??? */
318 cp += n;
319 return NSS_STATUS_UNAVAIL;
320 }
321 cp += n;
322 *alias_pointer++ = bp;
323 bp += strlen (bp) + 1;
324 result->n_addrtype = class == C_IN ? AF_INET : AF_UNSPEC;
325 ++have_answer;
326 }
327 }
328
329 if (have_answer)
330 {
331 char *tmp;
332 int len;
333 char *in, *cp, *rp, *wp;
334 int cnt, first_flag;
335
336 *alias_pointer = NULL;
337 switch (net_i)
338 {
339 case BYADDR:
340 result->n_name = result->n_aliases[0];
341 result->n_net = 0L;
342 break;
343 case BYNAME:
344 len = strlen (result->n_aliases[0]);
345 tmp = (char *) alloca (len + 1);
346 tmp[len] = 0;
347 wp = &tmp[len - 1];
348
349 rp = in = result->n_aliases[0];
350 result->n_name = ans;
351
352 first_flag = 1;
353 for (cnt = 0; cnt < 4; ++cnt)
354 {
355 char *startp;
356
357 startp = rp;
358 while (*rp != '.')
359 ++rp;
360 if (rp - startp > 1 || *startp != '0' || !first_flag)
361 {
362 first_flag = 0;
363 if (cnt > 0)
364 *wp-- = '.';
365 cp = rp;
366 while (cp > startp)
367 *wp-- = *--cp;
368 }
369 in = rp + 1;
370 }
371
372 result->n_net = inet_network (wp);
373 break;
374 }
375
376 ++result->n_aliases;
377 return NSS_STATUS_SUCCESS;
378 }
379
a68b0d31 380 __set_h_errno (TRY_AGAIN);
5f0e6fc7
RM
381 return NSS_STATUS_TRYAGAIN;
382}