acb958cbeb7e33697f7a4f8e014674e21af2e5f9
[kopensolaris-gnu/glibc.git] / resolv / getnetnamadr.c
1 /* Copyright (c) 1993 Carlos Leandro and Rui Salgueiro
2  *      Dep. Matematica Universidade de Coimbra, Portugal, Europe
3  */
4 /*
5  * Copyright (c) 1983 Regents of the University of California.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 #if defined(LIBC_SCCS) && !defined(lint)
38 static char sccsid[] = "@(#)getnetnamadr.c      1.4 (Coimbra) 93/06/03";
39 static char rcsid[] = "$Id$";
40 #endif /* LIBC_SCCS and not lint */
41
42 #include <sys/param.h>
43 #include <sys/socket.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
46 #include <arpa/nameser.h>
47
48 #include <stdio.h>
49 #include <netdb.h>
50 #include <resolv.h>
51 #include <ctype.h>
52 #include <errno.h>
53 #include <string.h>
54
55 extern int h_errno;
56
57 #if defined(mips) && defined(SYSTYPE_BSD43)
58 extern int errno;
59 #endif
60
61 struct netent *_getnetbyaddr __P((long net, int type));
62 #if defined(sun)
63 struct netent *_getnetbyname __P((char *name));
64 #else
65 struct netent *_getnetbyname __P((const char *name));
66 #endif
67
68 #define BYADDR 0
69 #define BYNAME 1
70 #define MAXALIASES      35
71
72 #if PACKETSZ > 1024
73 #define MAXPACKET       PACKETSZ
74 #else
75 #define MAXPACKET       1024
76 #endif
77
78 typedef union {
79         HEADER  hdr;
80         u_char  buf[MAXPACKET];
81 } querybuf;
82
83 typedef union {
84         long    al;
85         char    ac;
86 } align;
87
88 static struct netent *
89 getnetanswer(answer, anslen, net_i)
90         querybuf *answer;
91         int anslen;
92         int net_i;
93 {
94
95         register HEADER *hp;
96         register u_char *cp;
97         register int    n;
98         u_char          *eom;
99         int             type, class, buflen, ancount, qdcount,
100                         haveanswer, i, nchar,
101                         getclass = C_ANY,
102                         net_length = 0;
103         char            aux1[30], aux2[30], ans[30],
104                         *in, *st, *pauxt, *bp, **ap,
105                         *paux1 = &aux1[0],
106                         *paux2 = &aux2[0],
107                         flag = 0;
108 static  struct netent   net_entry;
109 static  char            *net_aliases[MAXALIASES],
110                         netbuf[BUFSIZ+1];
111
112         /*
113          * find first satisfactory answer
114          *
115          *      answer --> +------------+  ( MESSAGE )
116          *                 |   Header   |
117          *                 +------------+
118          *                 |  Question  | the question for the name server
119          *                 +------------+
120          *                 |   Answer   | RRs answering the question
121          *                 +------------+
122          *                 | Authority  | RRs pointing toward an authority
123          *                 | Additional | RRs holding additional information
124          *                 +------------+
125          */
126         eom = answer->buf + anslen;
127         hp = &answer->hdr;
128         ancount = ntohs(hp->ancount); /* #/records in the answer section */
129         qdcount = ntohs(hp->qdcount); /* #/entries in the question section */
130         bp = netbuf;
131         buflen = sizeof(netbuf);
132         cp = answer->buf + HFIXEDSZ;
133         if (!qdcount) {
134                 if (hp->aa)
135                         h_errno = HOST_NOT_FOUND;
136                 else
137                         h_errno = TRY_AGAIN;
138
139                 return ((struct netent *) NULL);
140         }
141         while (qdcount-- > 0){
142                 cp += __dn_skipname(cp, eom) + QFIXEDSZ;
143         }
144         ap = net_aliases;
145         *ap = NULL;
146         net_entry.n_aliases = net_aliases;
147         haveanswer = 0;
148         while (--ancount >= 0 && cp < eom) {
149                 n = dn_expand(answer->buf, eom, cp, bp, buflen);
150                 if (n < 0)
151                         break;
152                 cp += n;
153                 ans[0] = '\0';
154                 (void)strcpy(&ans[0], bp);
155                 GETSHORT(type, cp);
156                 GETSHORT(class, cp);
157                 cp += INT32SZ;          /* TTL */
158                 GETSHORT(n, cp);
159                 if (class == C_IN && type == T_PTR) {
160                         n = dn_expand(answer->buf, eom, cp, bp, buflen);
161                         if (n < 0) {
162                                 cp += n;
163                                 return (NULL);
164                         }
165                         cp += n; 
166                         *ap++ = bp;
167                         bp += (strlen(bp) + 1);
168                         net_entry.n_addrtype = (class == C_IN)
169                                                 ? AF_INET
170                                                 : AF_UNSPEC;
171                         haveanswer++;
172                 }
173         }
174         if (haveanswer) {
175                 *ap = NULL;
176                 switch (net_i) {
177                    case BYADDR :
178                         net_entry.n_name = *net_entry.n_aliases;
179                         net_entry.n_net = 0L;
180                         break;
181                    case BYNAME :
182                         in = *net_entry.n_aliases;
183                         net_entry.n_name = &ans[0];
184                         aux2[0] = '\0';
185                         for (i = 0;  i < 4;  i++) {
186                                 for (st = in, nchar = 0;
187                                      *st != '.';
188                                      st++, nchar++)
189                                         ;
190                                 if (nchar != 1 || *in != '0' || flag) {
191                                         flag = 1;
192                                         (void)strncpy(paux1,
193                                                       (i==0) ?in :in-1,
194                                                       (i==0) ?nchar :nchar+1);
195                                         paux1[(i==0) ?nchar :nchar+1] = '\0';
196                                         pauxt = paux2;
197                                         paux2 = strcat(paux1, paux2);
198                                         paux1 = pauxt;
199                                 }
200                                 in = ++st;
201                         }                 
202                         net_entry.n_net = inet_network(paux2);
203                 }
204                 net_entry.n_aliases++;
205                 return (&net_entry);
206         } else {
207                 h_errno = TRY_AGAIN;
208                 return ((struct netent *) NULL);
209         }
210 }
211
212 struct netent *
213 getnetbyaddr(net, net_type)
214         register long net;
215         register int net_type;
216 {
217         unsigned int    netbr[4];
218         int             nn, anslen;
219         querybuf        buf;
220         char            qbuf[MAXDNAME];
221         unsigned long   net2;
222         struct netent   *net_entry;
223
224         if (net_type != AF_INET)
225                 return (_getnetbyaddr(net, net_type));
226
227         for (nn = 4, net2 = net;  net2;  net2 >>= 8) {
228                 netbr[--nn] = net2 & 0xff;
229         }
230         switch (nn) {
231                 case 3:         /* Class A */
232                         (void)sprintf(qbuf, "0.0.0.%u.in-addr.arpa",
233                                       netbr[3]);
234                         break;
235                 case 2:         /* Class B */
236                         (void)sprintf(qbuf, "0.0.%u.%u.in-addr.arpa",
237                                       netbr[3], netbr[2]);
238                         break;
239                 case 1:         /* Class C */
240                         (void)sprintf(qbuf, "0.%u.%u.%u.in-addr.arpa",
241                                       netbr[3], netbr[2], netbr[1]);
242                         break;
243                 case 0:         /* Class D - E */
244                         (void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
245                                       netbr[3], netbr[2], netbr[1], netbr[0]);
246                         break;
247         }
248         anslen = res_query(qbuf, C_IN, T_PTR, buf.buf, sizeof buf.buf);
249         if (anslen < 0) {
250 #ifdef DEBUG
251                 if (_res.options & RES_DEBUG)
252                         printf("res_query failed\n");
253 #endif
254                 if (errno == ECONNREFUSED)
255                         return (_getnetbyaddr(net, net_type));
256                 return (_getnetbyaddr(net, net_type));
257         }
258         net_entry = getnetanswer(&buf, anslen, BYADDR);
259         if (net_entry) {
260                 unsigned u_net = net;   /* maybe net should be unsigned ? */
261
262                 /* Strip trailing zeros */
263                 while ((u_net & 0xff) == 0 && u_net != 0) {
264                         u_net >>= 8;
265                 }
266                 net_entry->n_net = u_net;
267                 return (net_entry);
268         } else {
269                 return (_getnetbyaddr(net, net_type));
270         }
271 }
272
273 struct netent *
274 getnetbyname(net)
275 #if defined(sun)
276         register char *net;
277 #else
278         register const char *net;
279 #endif
280 {
281         unsigned int    netbr[4];
282         int             anslen;
283         querybuf        buf;
284         char            qbuf[MAXDNAME];
285         struct netent   *net_entry;
286        
287         (void)strcpy(&qbuf[0],net);
288         anslen = res_search(qbuf, C_IN, T_PTR, buf.buf, sizeof buf.buf);
289         if (anslen < 0) {
290 #ifdef DEBUG
291                 if (_res.options & RES_DEBUG)
292                         printf("res_query failed\n");
293 #endif
294                 if (errno == ECONNREFUSED)
295                         return (_getnetbyname(net));
296                 return (_getnetbyname(net));
297         }
298         net_entry = getnetanswer(&buf, anslen, BYNAME);
299         if (net_entry)
300                 return (net_entry);
301         else
302                 return (_getnetbyname(net));
303 }