(getnetbyname): Arg is always const, regardless of [sun].
[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 struct netent *_getnetbyname __P((const char *name));
63
64 #define BYADDR 0
65 #define BYNAME 1
66 #define MAXALIASES      35
67
68 #if PACKETSZ > 1024
69 #define MAXPACKET       PACKETSZ
70 #else
71 #define MAXPACKET       1024
72 #endif
73
74 typedef union {
75         HEADER  hdr;
76         u_char  buf[MAXPACKET];
77 } querybuf;
78
79 typedef union {
80         long    al;
81         char    ac;
82 } align;
83
84 static struct netent *
85 getnetanswer(answer, anslen, net_i)
86         querybuf *answer;
87         int anslen;
88         int net_i;
89 {
90
91         register HEADER *hp;
92         register u_char *cp;
93         register int    n;
94         u_char          *eom;
95         int             type, class, buflen, ancount, qdcount,
96                         haveanswer, i, nchar,
97                         getclass = C_ANY,
98                         net_length = 0;
99         char            aux1[30], aux2[30], ans[30],
100                         *in, *st, *pauxt, *bp, **ap,
101                         *paux1 = &aux1[0],
102                         *paux2 = &aux2[0],
103                         flag = 0;
104 static  struct netent   net_entry;
105 static  char            *net_aliases[MAXALIASES],
106                         netbuf[BUFSIZ+1];
107
108         /*
109          * find first satisfactory answer
110          *
111          *      answer --> +------------+  ( MESSAGE )
112          *                 |   Header   |
113          *                 +------------+
114          *                 |  Question  | the question for the name server
115          *                 +------------+
116          *                 |   Answer   | RRs answering the question
117          *                 +------------+
118          *                 | Authority  | RRs pointing toward an authority
119          *                 | Additional | RRs holding additional information
120          *                 +------------+
121          */
122         eom = answer->buf + anslen;
123         hp = &answer->hdr;
124         ancount = ntohs(hp->ancount); /* #/records in the answer section */
125         qdcount = ntohs(hp->qdcount); /* #/entries in the question section */
126         bp = netbuf;
127         buflen = sizeof(netbuf);
128         cp = answer->buf + HFIXEDSZ;
129         if (!qdcount) {
130                 if (hp->aa)
131                         h_errno = HOST_NOT_FOUND;
132                 else
133                         h_errno = TRY_AGAIN;
134
135                 return ((struct netent *) NULL);
136         }
137         while (qdcount-- > 0){
138                 cp += __dn_skipname(cp, eom) + QFIXEDSZ;
139         }
140         ap = net_aliases;
141         *ap = NULL;
142         net_entry.n_aliases = net_aliases;
143         haveanswer = 0;
144         while (--ancount >= 0 && cp < eom) {
145                 n = dn_expand(answer->buf, eom, cp, bp, buflen);
146                 if (n < 0)
147                         break;
148                 cp += n;
149                 ans[0] = '\0';
150                 (void)strcpy(&ans[0], bp);
151                 GETSHORT(type, cp);
152                 GETSHORT(class, cp);
153                 cp += INT32SZ;          /* TTL */
154                 GETSHORT(n, cp);
155                 if (class == C_IN && type == T_PTR) {
156                         n = dn_expand(answer->buf, eom, cp, bp, buflen);
157                         if (n < 0) {
158                                 cp += n;
159                                 return (NULL);
160                         }
161                         cp += n; 
162                         *ap++ = bp;
163                         bp += (strlen(bp) + 1);
164                         net_entry.n_addrtype = (class == C_IN)
165                                                 ? AF_INET
166                                                 : AF_UNSPEC;
167                         haveanswer++;
168                 }
169         }
170         if (haveanswer) {
171                 *ap = NULL;
172                 switch (net_i) {
173                    case BYADDR :
174                         net_entry.n_name = *net_entry.n_aliases;
175                         net_entry.n_net = 0L;
176                         break;
177                    case BYNAME :
178                         in = *net_entry.n_aliases;
179                         net_entry.n_name = &ans[0];
180                         aux2[0] = '\0';
181                         for (i = 0;  i < 4;  i++) {
182                                 for (st = in, nchar = 0;
183                                      *st != '.';
184                                      st++, nchar++)
185                                         ;
186                                 if (nchar != 1 || *in != '0' || flag) {
187                                         flag = 1;
188                                         (void)strncpy(paux1,
189                                                       (i==0) ?in :in-1,
190                                                       (i==0) ?nchar :nchar+1);
191                                         paux1[(i==0) ?nchar :nchar+1] = '\0';
192                                         pauxt = paux2;
193                                         paux2 = strcat(paux1, paux2);
194                                         paux1 = pauxt;
195                                 }
196                                 in = ++st;
197                         }                 
198                         net_entry.n_net = inet_network(paux2);
199                 }
200                 net_entry.n_aliases++;
201                 return (&net_entry);
202         } else {
203                 h_errno = TRY_AGAIN;
204                 return ((struct netent *) NULL);
205         }
206 }
207
208 struct netent *
209 getnetbyaddr(net, net_type)
210         register long net;
211         register int net_type;
212 {
213         unsigned int    netbr[4];
214         int             nn, anslen;
215         querybuf        buf;
216         char            qbuf[MAXDNAME];
217         unsigned long   net2;
218         struct netent   *net_entry;
219
220         if (net_type != AF_INET)
221                 return (_getnetbyaddr(net, net_type));
222
223         for (nn = 4, net2 = net;  net2;  net2 >>= 8) {
224                 netbr[--nn] = net2 & 0xff;
225         }
226         switch (nn) {
227                 case 3:         /* Class A */
228                         (void)sprintf(qbuf, "0.0.0.%u.in-addr.arpa",
229                                       netbr[3]);
230                         break;
231                 case 2:         /* Class B */
232                         (void)sprintf(qbuf, "0.0.%u.%u.in-addr.arpa",
233                                       netbr[3], netbr[2]);
234                         break;
235                 case 1:         /* Class C */
236                         (void)sprintf(qbuf, "0.%u.%u.%u.in-addr.arpa",
237                                       netbr[3], netbr[2], netbr[1]);
238                         break;
239                 case 0:         /* Class D - E */
240                         (void)sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
241                                       netbr[3], netbr[2], netbr[1], netbr[0]);
242                         break;
243         }
244         anslen = res_query(qbuf, C_IN, T_PTR, buf.buf, sizeof buf.buf);
245         if (anslen < 0) {
246 #ifdef DEBUG
247                 if (_res.options & RES_DEBUG)
248                         printf("res_query failed\n");
249 #endif
250                 if (errno == ECONNREFUSED)
251                         return (_getnetbyaddr(net, net_type));
252                 return (_getnetbyaddr(net, net_type));
253         }
254         net_entry = getnetanswer(&buf, anslen, BYADDR);
255         if (net_entry) {
256                 unsigned u_net = net;   /* maybe net should be unsigned ? */
257
258                 /* Strip trailing zeros */
259                 while ((u_net & 0xff) == 0 && u_net != 0) {
260                         u_net >>= 8;
261                 }
262                 net_entry->n_net = u_net;
263                 return (net_entry);
264         } else {
265                 return (_getnetbyaddr(net, net_type));
266         }
267 }
268
269 struct netent *
270 getnetbyname(net)
271         register const char *net;
272 {
273         unsigned int    netbr[4];
274         int             anslen;
275         querybuf        buf;
276         char            qbuf[MAXDNAME];
277         struct netent   *net_entry;
278        
279         (void)strcpy(&qbuf[0],net);
280         anslen = res_search(qbuf, C_IN, T_PTR, buf.buf, sizeof buf.buf);
281         if (anslen < 0) {
282 #ifdef DEBUG
283                 if (_res.options & RES_DEBUG)
284                         printf("res_query failed\n");
285 #endif
286                 if (errno == ECONNREFUSED)
287                         return (_getnetbyname(net));
288                 return (_getnetbyname(net));
289         }
290         net_entry = getnetanswer(&buf, anslen, BYNAME);
291         if (net_entry)
292                 return (net_entry);
293         else
294                 return (_getnetbyname(net));
295 }