source: rtems/cpukit/libnetworking/libc/gethostnamadr.c @ 1fbd0baf

4.104.114.95
Last change on this file since 1fbd0baf was 1fbd0baf, checked in by Joel Sherrill <joel.sherrill@…>, on Jul 2, 2008 at 1:40:19 PM

2008-07-02 Joel Sherrill <joel.sherrill@…>

  • libnetworking/Makefile.am, libnetworking/libc/gethostnamadr.c, libnetworking/libc/getservbyname.c, libnetworking/libc/getservbyport.c: Add initial versions of getservbyport_r(), gethostbyaddr_r(), and getservbyport_r(). At this point they are just simple weappers for the version without the _r in the name.
  • Property mode set to 100644
File size: 10.3 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#include <arpa/nameser.h>               /* XXX hack for _res */
40#include <resolv.h>                     /* XXX hack for _res */
41
42#define _PATH_HOSTCONF  "/etc/host.conf"
43
44enum service_type {
45  SERVICE_NONE = 0,
46  SERVICE_BIND,
47  SERVICE_HOSTS,
48  SERVICE_NIS };
49#define SERVICE_MAX     SERVICE_NIS
50
51static struct {
52  const char *name;
53  enum service_type type;
54} service_names[] = {
55  { "hosts", SERVICE_HOSTS },
56  { "/etc/hosts", SERVICE_HOSTS },
57  { "hosttable", SERVICE_HOSTS },
58  { "htable", SERVICE_HOSTS },
59  { "bind", SERVICE_BIND },
60  { "dns", SERVICE_BIND },
61  { "domain", SERVICE_BIND },
62  { "yp", SERVICE_NIS },
63  { "yellowpages", SERVICE_NIS },
64  { "nis", SERVICE_NIS },
65  { 0, SERVICE_NONE }
66};
67
68static enum service_type service_order[SERVICE_MAX + 1];
69static int service_done = 0;
70
71static enum service_type
72get_service_name(const char *name) {
73        int i;
74        for(i = 0; service_names[i].type != SERVICE_NONE; i++) {
75                if(!strcasecmp(name, service_names[i].name)) {
76                        return service_names[i].type;
77                }
78        }
79        return SERVICE_NONE;
80}
81
82static void
83init_services()
84{
85        char *cp, *p, buf[BUFSIZ];
86        register int cc = 0;
87        FILE *fd;
88
89        if ((fd = (FILE *)fopen(_PATH_HOSTCONF, "r")) == NULL) {
90                                /* make some assumptions */
91                service_order[0] = SERVICE_BIND;
92                service_order[1] = SERVICE_HOSTS;
93                service_order[2] = SERVICE_NONE;
94        } else {
95                while (fgets(buf, BUFSIZ, fd) != NULL && cc < SERVICE_MAX) {
96                        if(buf[0] == '#')
97                                continue;
98
99                        p = buf;
100                        while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
101                                ;
102                        if (cp == NULL)
103                                continue;
104                        do {
105                                if (isalpha((int)cp[0])) {
106                                        service_order[cc] = get_service_name(cp);
107                                        if(service_order[cc] != SERVICE_NONE)
108                                                cc++;
109                                }
110                                while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0')
111                                        ;
112                        } while(cp != NULL && cc < SERVICE_MAX);
113                }
114                service_order[cc] = SERVICE_NONE;
115                fclose(fd);
116        }
117        service_done = 1;
118}
119
120struct hostent *
121gethostbyname(const char *name)
122{
123        struct hostent *hp;
124
125        if (_res.options & RES_USE_INET6) {             /* XXX */
126                hp = gethostbyname2(name, AF_INET6);    /* XXX */
127                if (hp)                                 /* XXX */
128                        return (hp);                    /* XXX */
129        }                                               /* XXX */
130        return (gethostbyname2(name, AF_INET));
131}
132
133struct hostent *
134gethostbyname2(const char *name, int type)
135{
136        struct hostent *hp = 0;
137        int nserv = 0;
138
139        if (!service_done)
140                init_services();
141
142        while (!hp) {
143                switch (service_order[nserv]) {
144                      case SERVICE_NONE:
145                        return NULL;
146                      case SERVICE_HOSTS:
147                        hp = _gethostbyhtname(name, type);
148                        break;
149                      case SERVICE_BIND:
150                        hp = _gethostbydnsname(name, type);
151                        break;
152                      case SERVICE_NIS:
153                        hp = _gethostbynisname(name, type);
154                        break;
155                }
156                nserv++;
157        }
158        return hp;
159}
160
161int gethostbyaddr_r(const void *addr, socklen_t len, int type,
162               struct hostent *ret, char *buf, size_t buflen,
163               struct hostent **result, int *h_errnop)
164{
165  #warning "implement a proper gethostbyaddr_r"
166 
167  *result = gethostbyaddr( addr, len, type );
168  if ( *result ) 
169    return 0;
170  return -1;
171}
172
173struct hostent *
174gethostbyaddr(const void *addr, socklen_t len, int type)
175{
176        struct hostent *hp = 0;
177        int nserv = 0;
178
179        if (!service_done)
180                init_services();
181
182        while (!hp) {
183                switch (service_order[nserv]) {
184                      case SERVICE_NONE:
185                        return 0;
186                      case SERVICE_HOSTS:
187                        hp = _gethostbyhtaddr(addr, len, type);
188                        break;
189                      case SERVICE_BIND:
190                        hp = _gethostbydnsaddr(addr, len, type);
191                        break;
192                      case SERVICE_NIS:
193                        hp = _gethostbynisaddr(addr, len, type);
194                        break;
195                }
196                nserv++;
197        }
198        return hp;
199}
200
201void
202sethostent(stayopen)
203        int stayopen;
204{
205        _sethosthtent(stayopen);
206        _sethostdnsent(stayopen);
207}
208
209void
210endhostent()
211{
212        _endhosthtent();
213        _endhostdnsent();
214}
215
216#ifdef _THREAD_SAFE
217
218/* return length of decoded data or -1 */
219static int __dns_decodename(unsigned char *packet,unsigned int offset,unsigned char *dest,
220         unsigned int maxlen,unsigned char* behindpacket) {
221  unsigned char *tmp;
222  unsigned char *max=dest+maxlen;
223  unsigned char *after=packet+offset;
224  int ok=0;
225  for (tmp=after; maxlen>0&&*tmp; ) {
226    if (tmp>=behindpacket) return -1;
227    if ((*tmp>>6)==3) {   /* goofy DNS decompression */
228      unsigned int ofs=((unsigned int)(*tmp&0x3f)<<8)|*(tmp+1);
229      if (ofs>=(unsigned int)offset) return -1; /* RFC1035: "pointer to a _prior_ occurrance" */
230      if (after<tmp+2) after=tmp+2;
231      tmp=packet+ofs;
232      ok=0;
233    } else {
234      unsigned int duh;
235      if (dest+*tmp+1>max) return -1;
236      if (tmp+*tmp+1>=behindpacket) return -1;
237      for (duh=*tmp; duh>0; --duh)
238  *dest++=*++tmp;
239      *dest++='.'; ok=1;
240      ++tmp;
241      if (tmp>after) { after=tmp; if (!*tmp) ++after; }
242    }
243  }
244  if (ok) --dest;
245  *dest=0;
246  return after-packet;
247}
248
249static int __dns_gethostbyx_r(const char* name, struct hostent* result,
250      char *buf, size_t buflen,
251      struct hostent **RESULT, int *h_errnop, int lookfor) {
252
253  int names,ips;
254  unsigned char *cur;
255  unsigned char *max;
256  unsigned char inpkg[1500];
257  char* tmp;
258  int size;
259
260  if (lookfor==1) {
261    result->h_addrtype=AF_INET;
262    result->h_length=4;
263  } else {
264    result->h_addrtype=AF_INET6;
265    result->h_length=16;
266  }
267  result->h_aliases=(char**)(buf+8*sizeof(char*));
268  result->h_addr_list=(char**)buf;
269  result->h_aliases[0]=0;
270
271  cur=buf+16*sizeof(char*);
272  max=buf+buflen;
273  names=ips=0;
274
275  if ((size=res_query(name,C_IN,lookfor,inpkg,512))<0) {
276invalidpacket:
277    *h_errnop=HOST_NOT_FOUND;
278    return -1;
279  }
280  {
281    tmp=inpkg+12;
282    {
283      char Name[257];
284      unsigned short q=((unsigned short)inpkg[4]<<8)+inpkg[5];
285      while (q>0) {
286  if (tmp>(char*)inpkg+size) goto invalidpacket;
287  while (*tmp) { tmp+=*tmp+1; if (tmp>(char*)inpkg+size) goto invalidpacket; }
288  tmp+=5;
289  --q;
290      }
291      if (tmp>(char*)inpkg+size) goto invalidpacket;
292      q=((unsigned short)inpkg[6]<<8)+inpkg[7];
293      if (q<1) goto nodata;
294      while (q>0) {
295  int decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),Name,256,inpkg+size);
296  if (decofs<0) break;
297  tmp=inpkg+decofs;
298  --q;
299  if (tmp[0]!=0 || tmp[1]!=lookfor || /* TYPE != A */
300      tmp[2]!=0 || tmp[3]!=1) {   /* CLASS != IN */
301    if (tmp[1]==5) {  /* CNAME */
302      tmp+=10;
303      decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),Name,256,inpkg+size);
304      if (decofs<0) break;
305      tmp=inpkg+decofs;
306    } else
307      break;
308    continue;
309  }
310  tmp+=10;  /* skip type, class, TTL and length */
311  {
312    int slen;
313    if (lookfor==1 || lookfor==28) /* A or AAAA*/ {
314      slen=strlen(Name);
315      if (cur+slen+8+(lookfor==28?12:0)>=max) { *h_errnop=NO_RECOVERY; return -1; }
316    } else if (lookfor==12) /* PTR */ {
317      decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),Name,256,inpkg+size);
318      if (decofs<0) break;
319      tmp=inpkg+decofs;
320      slen=strlen(Name);
321    } else
322      slen=strlen(Name);
323    strcpy(cur,Name);
324    if (names==0)
325      result->h_name=cur;
326    else
327      result->h_aliases[names-1]=cur;
328    result->h_aliases[names]=0;
329    if (names<8) ++names;
330/*    cur+=slen+1; */
331    cur+=(slen|3)+1;
332    result->h_addr_list[ips++] = cur;
333    if (lookfor==1) /* A */ {
334      *(int*)cur=*(int*)tmp;
335      cur+=4;
336      result->h_addr_list[ips]=0;
337    } else if (lookfor==28) /* AAAA */ {
338      {
339        int k;
340        for (k=0; k<16; ++k) cur[k]=tmp[k];
341      }
342      cur+=16;
343      result->h_addr_list[ips]=0;
344    }
345  }
346/*        puts(Name); */
347      }
348    }
349  }
350  if (!names) {
351nodata:
352    *h_errnop=NO_DATA;
353    return -1;
354  }
355  *h_errnop=0;
356  *RESULT=result;
357  return 0;
358}
359
360
361
362
363int gethostbyname_r(const char*      name, 
364        struct hostent*  result,
365        char            *buf, 
366        int              buflen,
367        struct hostent **RESULT, 
368        int             *h_errnop) 
369{
370       
371  size_t L=strlen(name);
372  result->h_name=buf;
373  if (buflen<L) { *h_errnop=ERANGE; return 1; }
374  strcpy(buf,name);
375
376  result->h_addr_list=(char**)(buf+strlen(name)+1);
377  result->h_addr_list+=sizeof(unsigned long)-((unsigned long)(result->h_addr_list)&(sizeof(unsigned long)-1));
378  result->h_addr_list[0]=(char*)&result->h_addr_list[2];
379  if (inet_pton(AF_INET,name,result->h_addr_list[0])) {
380    result->h_addrtype=AF_INET;
381    result->h_length=4;
382commonip:
383    result->h_aliases=result->h_addr_list+2*sizeof(char**);
384    result->h_aliases[0]=0;
385    result->h_addr_list[1]=0;
386    *RESULT=result;
387    *h_errnop=0;
388    return 0;
389  } else if (inet_pton(AF_INET6,name,result->h_addr_list[0])) {
390    result->h_addrtype=AF_INET6;
391    result->h_length=16;
392    goto commonip;
393  }
394
395
396  {
397    struct hostent* r;
398    sethostent(0);
399    while ((r=gethostent_r(buf,buflen))) {
400      int i;
401      if (r->h_addrtype==AF_INET && !strcasecmp(r->h_name,name)) {  /* found it! */
402found:
403  memmove(result,r,sizeof(struct hostent));
404  *RESULT=result;
405  *h_errnop=0;
406  endhostent();
407  return 0;
408      }
409      for (i=0; i<16; ++i) {
410  if (r->h_aliases[i]) {
411    if (!strcasecmp(r->h_aliases[i],name)) goto found;
412  } else break;
413      }
414    }
415    endhostent();
416  }
417
418  return __dns_gethostbyx_r(name,result,buf+L,buflen-L,RESULT,h_errnop,1);
419}
420
421#endif
422
Note: See TracBrowser for help on using the repository browser.