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

5
Last change on this file since 7e6f235 was 7e6f235, checked in by Christian Mauderer <Christian.Mauderer@…>, on 04/22/16 at 08:06:16

libnetworking: Add <rtems/rtems_netdb.h>

Move prototypes of non-portable _get*by*name/addr and _set/end*ent
functions. This makes it easier to update <netdb.h>.

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