source: rtems/cpukit/libnetworking/libc/gethostnamadr.c @ 7cf4893

4.104.11
Last change on this file since 7cf4893 was 7cf4893, checked in by Ralf Corsepius <ralf.corsepius@…>, on May 29, 2010 at 4:32:39 AM

2010-05-29 Ralf Corsépius <ralf.corsepius@…>

  • libnetworking/libc/gethostnamadr.c: Cast addr to uintptr_t instead of size_t.
  • Property mode set to 100644
File size: 10.5 KB
Line 
1/*-
2 * Copyright (c) 1994, Garrett Wollman
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26#if HAVE_CONFIG_H
27#include "config.h"
28#endif
29
30#include <sys/param.h>
31#include <sys/socket.h>
32#include <netinet/in.h>
33#include <arpa/inet.h>
34#include <netdb.h>
35#include <stdio.h>
36#include <ctype.h>
37#include <errno.h>
38#include <string.h>
39#ifdef HAVE_STRINGS_H
40#include <strings.h>
41#endif
42#include <arpa/nameser.h>               /* XXX hack for _res */
43#include <resolv.h>                     /* XXX hack for _res */
44
45#define _PATH_HOSTCONF  "/etc/host.conf"
46
47enum service_type {
48  SERVICE_NONE = 0,
49  SERVICE_BIND,
50  SERVICE_HOSTS,
51  SERVICE_NIS };
52#define SERVICE_MAX     SERVICE_NIS
53
54static struct {
55  const char *name;
56  enum service_type type;
57} service_names[] = {
58  { "hosts", SERVICE_HOSTS },
59  { "/etc/hosts", SERVICE_HOSTS },
60  { "hosttable", SERVICE_HOSTS },
61  { "htable", SERVICE_HOSTS },
62  { "bind", SERVICE_BIND },
63  { "dns", SERVICE_BIND },
64  { "domain", SERVICE_BIND },
65  { "yp", SERVICE_NIS },
66  { "yellowpages", SERVICE_NIS },
67  { "nis", SERVICE_NIS },
68  { 0, SERVICE_NONE }
69};
70
71static enum service_type service_order[SERVICE_MAX + 1];
72static int service_done = 0;
73
74static enum service_type
75get_service_name(const char *name) {
76        int i;
77        for(i = 0; service_names[i].type != SERVICE_NONE; i++) {
78                if(!strcasecmp(name, service_names[i].name)) {
79                        return service_names[i].type;
80                }
81        }
82        return SERVICE_NONE;
83}
84
85static void
86init_services(void)
87{
88        char *cp, *p, buf[BUFSIZ];
89        register int cc = 0;
90        FILE *fd;
91
92        if ((fd = (FILE *)fopen(_PATH_HOSTCONF, "r")) == NULL) {
93                                /* make some assumptions */
94                service_order[0] = SERVICE_BIND;
95                service_order[1] = SERVICE_HOSTS;
96                service_order[2] = SERVICE_NONE;
97        } else {
98                while (fgets(buf, BUFSIZ, fd) != NULL && cc < SERVICE_MAX) {
99                        if(buf[0] == '#')
100                                continue;
101
102                        p = buf;
103                        while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
104                                ;
105                        if (cp == NULL)
106                                continue;
107                        do {
108                                if (isalpha((unsigned char)cp[0])) {
109                                        service_order[cc] = get_service_name(cp);
110                                        if(service_order[cc] != SERVICE_NONE)
111                                                cc++;
112                                }
113                                while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
114                                        ;
115                        } while(cp != NULL && cc < SERVICE_MAX);
116                }
117                service_order[cc] = SERVICE_NONE;
118                fclose(fd);
119        }
120        service_done = 1;
121}
122
123struct hostent *
124gethostbyname(const char *name)
125{
126        struct hostent *hp;
127
128        if (_res.options & RES_USE_INET6) {             /* XXX */
129                hp = gethostbyname2(name, AF_INET6);    /* XXX */
130                if (hp)                                 /* XXX */
131                        return (hp);                    /* XXX */
132        }                                               /* XXX */
133        return (gethostbyname2(name, AF_INET));
134}
135
136struct hostent *
137gethostbyname2(const char *name, int type)
138{
139        struct hostent *hp = 0;
140        int nserv = 0;
141
142        if (!service_done)
143                init_services();
144
145        while (!hp) {
146                switch (service_order[nserv]) {
147                      case SERVICE_NONE:
148                        return NULL;
149                      case SERVICE_HOSTS:
150                        hp = _gethostbyhtname(name, type);
151                        break;
152                      case SERVICE_BIND:
153                        hp = _gethostbydnsname(name, type);
154                        break;
155                      case SERVICE_NIS:
156                        hp = _gethostbynisname(name, type);
157                        break;
158                }
159                nserv++;
160        }
161        return hp;
162}
163
164int gethostbyaddr_r(const void *addr, socklen_t len, int type,
165               struct hostent *ret, char *buf, size_t buflen,
166               struct hostent **result, int *h_errnop)
167{
168  #warning "implement a proper gethostbyaddr_r"
169 
170  *result = gethostbyaddr( addr, len, type );
171  if ( *result ) 
172    return 0;
173  return -1;
174}
175
176struct hostent *
177gethostbyaddr(const void *addr, socklen_t len, int type)
178{
179        struct hostent *hp = 0;
180        int nserv = 0;
181
182        if (!service_done)
183                init_services();
184
185        while (!hp) {
186                switch (service_order[nserv]) {
187                      case SERVICE_NONE:
188                        return 0;
189                      case SERVICE_HOSTS:
190                        hp = _gethostbyhtaddr(addr, len, type);
191                        break;
192                      case SERVICE_BIND:
193                        hp = _gethostbydnsaddr(addr, len, type);
194                        break;
195                      case SERVICE_NIS:
196                        hp = _gethostbynisaddr(addr, len, type);
197                        break;
198                }
199                nserv++;
200        }
201        return hp;
202}
203
204void
205sethostent(int stayopen)
206{
207        _sethosthtent(stayopen);
208        _sethostdnsent(stayopen);
209}
210
211void
212endhostent(void)
213{
214        _endhosthtent();
215        _endhostdnsent();
216}
217
218#ifdef _THREAD_SAFE
219
220/* return length of decoded data or -1 */
221static int __dns_decodename(unsigned char *packet,unsigned int offset,unsigned char *dest,
222         unsigned int maxlen,unsigned char* behindpacket) {
223  unsigned char *tmp;
224  unsigned char *max=dest+maxlen;
225  unsigned char *after=packet+offset;
226  int ok=0;
227  for (tmp=after; maxlen>0&&*tmp; ) {
228    if (tmp>=behindpacket) return -1;
229    if ((*tmp>>6)==3) {   /* goofy DNS decompression */
230      unsigned int ofs=((unsigned int)(*tmp&0x3f)<<8)|*(tmp+1);
231      if (ofs>=(unsigned int)offset) return -1; /* RFC1035: "pointer to a _prior_ occurrance" */
232      if (after<tmp+2) after=tmp+2;
233      tmp=packet+ofs;
234      ok=0;
235    } else {
236      unsigned int duh;
237      if (dest+*tmp+1>max) return -1;
238      if (tmp+*tmp+1>=behindpacket) return -1;
239      for (duh=*tmp; duh>0; --duh)
240  *dest++=*++tmp;
241      *dest++='.'; ok=1;
242      ++tmp;
243      if (tmp>after) { after=tmp; if (!*tmp) ++after; }
244    }
245  }
246  if (ok) --dest;
247  *dest=0;
248  return after-packet;
249}
250
251static int __dns_gethostbyx_r(
252    const char* name, 
253    struct hostent* result,
254    char *buf, size_t buflen,
255    struct hostent **RESULT, 
256    int *h_errnop, 
257    int lookfor) 
258{
259
260  int names,ips;
261  unsigned char *cur;
262  unsigned char *max;
263  unsigned char inpkg[1500];
264  char* tmp;
265  int size;
266
267  if (lookfor==1) {
268    result->h_addrtype=AF_INET;
269    result->h_length=4;
270  } else {
271    result->h_addrtype=AF_INET6;
272    result->h_length=16;
273  }
274  result->h_aliases=(char**)(buf+8*sizeof(char*));
275  result->h_addr_list=(char**)buf;
276  result->h_aliases[0]=0;
277
278  cur=(unsigned char*)buf+16*sizeof(char*);
279  max=(unsigned char*)buf+buflen;
280  names=ips=0;
281
282  if ((size=res_query(name,C_IN,lookfor,inpkg,512))<0) {
283invalidpacket:
284    *h_errnop=HOST_NOT_FOUND;
285    return -1;
286  }
287  {
288    tmp=(char*)inpkg+12;
289    {
290      char Name[257];
291      unsigned short q=((unsigned short)inpkg[4]<<8)+inpkg[5];
292      while (q>0) {
293  if (tmp>(char*)inpkg+size) goto invalidpacket;
294  while (*tmp) { tmp+=*tmp+1; if (tmp>(char*)inpkg+size) goto invalidpacket; }
295  tmp+=5;
296  --q;
297      }
298      if (tmp>(char*)inpkg+size) goto invalidpacket;
299      q=((unsigned short)inpkg[6]<<8)+inpkg[7];
300      if (q<1) goto nodata;
301      while (q>0) {
302        int decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),(unsigned char*)Name,256,inpkg+size);
303  if (decofs<0) break;
304  tmp=(char*)inpkg+decofs;
305  --q;
306  if (tmp[0]!=0 || tmp[1]!=lookfor || /* TYPE != A */
307      tmp[2]!=0 || tmp[3]!=1) {   /* CLASS != IN */
308    if (tmp[1]==5) {  /* CNAME */
309      tmp+=10;
310      decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),(unsigned char*)Name,256,inpkg+size);
311      if (decofs<0) break;
312      tmp=(char*)inpkg+decofs;
313    } else
314      break;
315    continue;
316  }
317  tmp+=10;  /* skip type, class, TTL and length */
318  {
319    int slen;
320    if (lookfor==1 || lookfor==28) /* A or AAAA*/ {
321      slen=strlen(Name);
322      if (cur+slen+8+(lookfor==28?12:0)>=max) { *h_errnop=NO_RECOVERY; return -1; }
323    } else if (lookfor==12) /* PTR */ {
324      decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),(unsigned char*)Name,256,inpkg+size);
325      if (decofs<0) break;
326      tmp=(char*)inpkg+decofs;
327      slen=strlen(Name);
328    } else
329      slen=strlen(Name);
330    strcpy((char*)cur,Name);
331    if (names==0)
332      result->h_name=(char*)cur;
333    else
334      result->h_aliases[names-1]=(char*)cur;
335    result->h_aliases[names]=0;
336    if (names<8) ++names;
337/*    cur+=slen+1; */
338    cur+=(slen|3)+1;
339    result->h_addr_list[ips++] = (char*)cur;
340    if (lookfor==1) /* A */ {
341      *(int*)cur=*(int*)tmp;
342      cur+=4;
343      result->h_addr_list[ips]=0;
344    } else if (lookfor==28) /* AAAA */ {
345      {
346        int k;
347        for (k=0; k<16; ++k) cur[k]=tmp[k];
348      }
349      cur+=16;
350      result->h_addr_list[ips]=0;
351    }
352  }
353/*        puts(Name); */
354      }
355    }
356  }
357  if (!names) {
358nodata:
359    *h_errnop=NO_DATA;
360    return -1;
361  }
362  *h_errnop=0;
363  *RESULT=result;
364  return 0;
365}
366
367
368
369
370int gethostbyname_r(const char*      name, 
371        struct hostent*  result,
372        char            *buf, 
373        int              buflen,
374        struct hostent **RESULT, 
375        int             *h_errnop) 
376{
377       
378  size_t L=strlen(name);
379  result->h_name=buf;
380  if (buflen<L) { *h_errnop=ERANGE; return 1; }
381  strcpy(buf,name);
382
383  result->h_addr_list=(char**)(buf+strlen(name)+1);
384  result->h_addr_list+=sizeof(char*)-((uintptr_t)(result->h_addr_list)&(sizeof(char*)-1));
385  result->h_addr_list[0]=(char*)&result->h_addr_list[2];
386  if (inet_pton(AF_INET,name,result->h_addr_list[0])) {
387    result->h_addrtype=AF_INET;
388    result->h_length=4;
389commonip:
390    result->h_aliases=result->h_addr_list+2*sizeof(char**);
391    result->h_aliases[0]=0;
392    result->h_addr_list[1]=0;
393    *RESULT=result;
394    *h_errnop=0;
395    return 0;
396  } else if (inet_pton(AF_INET6,name,result->h_addr_list[0])) {
397    result->h_addrtype=AF_INET6;
398    result->h_length=16;
399    goto commonip;
400  }
401
402
403  {
404    struct hostent* r;
405    sethostent(0);
406    while ((r=gethostent_r(buf,buflen))) {
407      int i;
408      if (r->h_addrtype==AF_INET && !strcasecmp(r->h_name,name)) {  /* found it! */
409found:
410  memmove(result,r,sizeof(struct hostent));
411  *RESULT=result;
412  *h_errnop=0;
413  endhostent();
414  return 0;
415      }
416      for (i=0; i<16; ++i) {
417  if (r->h_aliases[i]) {
418    if (!strcasecmp(r->h_aliases[i],name)) goto found;
419  } else break;
420      }
421    }
422    endhostent();
423  }
424
425  return __dns_gethostbyx_r(name,result,buf+L,buflen-L,RESULT,h_errnop,1);
426}
427
428#endif
429
Note: See TracBrowser for help on using the repository browser.