diff options
Diffstat (limited to 'cpukit/libnetworking/libc/gethostnamadr.c')
-rw-r--r-- | cpukit/libnetworking/libc/gethostnamadr.c | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/cpukit/libnetworking/libc/gethostnamadr.c b/cpukit/libnetworking/libc/gethostnamadr.c new file mode 100644 index 0000000000..8d7dd0db62 --- /dev/null +++ b/cpukit/libnetworking/libc/gethostnamadr.c @@ -0,0 +1,429 @@ +/*- + * Copyright (c) 1994, Garrett Wollman + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#include <arpa/nameser.h> /* XXX hack for _res */ +#include <resolv.h> /* XXX hack for _res */ + +#define _PATH_HOSTCONF "/etc/host.conf" + +enum service_type { + SERVICE_NONE = 0, + SERVICE_BIND, + SERVICE_HOSTS, + SERVICE_NIS }; +#define SERVICE_MAX SERVICE_NIS + +static struct { + const char *name; + enum service_type type; +} service_names[] = { + { "hosts", SERVICE_HOSTS }, + { "/etc/hosts", SERVICE_HOSTS }, + { "hosttable", SERVICE_HOSTS }, + { "htable", SERVICE_HOSTS }, + { "bind", SERVICE_BIND }, + { "dns", SERVICE_BIND }, + { "domain", SERVICE_BIND }, + { "yp", SERVICE_NIS }, + { "yellowpages", SERVICE_NIS }, + { "nis", SERVICE_NIS }, + { 0, SERVICE_NONE } +}; + +static enum service_type service_order[SERVICE_MAX + 1]; +static int service_done = 0; + +static enum service_type +get_service_name(const char *name) { + int i; + for(i = 0; service_names[i].type != SERVICE_NONE; i++) { + if(!strcasecmp(name, service_names[i].name)) { + return service_names[i].type; + } + } + return SERVICE_NONE; +} + +static void +init_services(void) +{ + char *cp, *p, buf[BUFSIZ]; + register int cc = 0; + FILE *fd; + + if ((fd = (FILE *)fopen(_PATH_HOSTCONF, "r")) == NULL) { + /* make some assumptions */ + service_order[0] = SERVICE_BIND; + service_order[1] = SERVICE_HOSTS; + service_order[2] = SERVICE_NONE; + } else { + while (fgets(buf, BUFSIZ, fd) != NULL && cc < SERVICE_MAX) { + if(buf[0] == '#') + continue; + + p = buf; + while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0') + ; + if (cp == NULL) + continue; + do { + if (isalpha((unsigned char)cp[0])) { + service_order[cc] = get_service_name(cp); + if(service_order[cc] != SERVICE_NONE) + cc++; + } + while ((cp = strsep(&p, "\n \t,:;")) != NULL && *cp == '\0') + ; + } while(cp != NULL && cc < SERVICE_MAX); + } + service_order[cc] = SERVICE_NONE; + fclose(fd); + } + service_done = 1; +} + +struct hostent * +gethostbyname(const char *name) +{ + struct hostent *hp; + + if (_res.options & RES_USE_INET6) { /* XXX */ + hp = gethostbyname2(name, AF_INET6); /* XXX */ + if (hp) /* XXX */ + return (hp); /* XXX */ + } /* XXX */ + return (gethostbyname2(name, AF_INET)); +} + +struct hostent * +gethostbyname2(const char *name, int type) +{ + struct hostent *hp = 0; + int nserv = 0; + + if (!service_done) + init_services(); + + while (!hp) { + switch (service_order[nserv]) { + case SERVICE_NONE: + return NULL; + case SERVICE_HOSTS: + hp = _gethostbyhtname(name, type); + break; + case SERVICE_BIND: + hp = _gethostbydnsname(name, type); + break; + case SERVICE_NIS: + hp = _gethostbynisname(name, type); + break; + } + nserv++; + } + return hp; +} + +int gethostbyaddr_r(const void *addr, socklen_t len, int type, + struct hostent *ret, char *buf, size_t buflen, + struct hostent **result, int *h_errnop) +{ + #warning "implement a proper gethostbyaddr_r" + + *result = gethostbyaddr( addr, len, type ); + if ( *result ) + return 0; + return -1; +} + +struct hostent * +gethostbyaddr(const void *addr, socklen_t len, int type) +{ + struct hostent *hp = 0; + int nserv = 0; + + if (!service_done) + init_services(); + + while (!hp) { + switch (service_order[nserv]) { + case SERVICE_NONE: + return 0; + case SERVICE_HOSTS: + hp = _gethostbyhtaddr(addr, len, type); + break; + case SERVICE_BIND: + hp = _gethostbydnsaddr(addr, len, type); + break; + case SERVICE_NIS: + hp = _gethostbynisaddr(addr, len, type); + break; + } + nserv++; + } + return hp; +} + +void +sethostent(int stayopen) +{ + _sethosthtent(stayopen); + _sethostdnsent(stayopen); +} + +void +endhostent(void) +{ + _endhosthtent(); + _endhostdnsent(); +} + +#ifdef _THREAD_SAFE + +/* return length of decoded data or -1 */ +static int __dns_decodename(unsigned char *packet,unsigned int offset,unsigned char *dest, + unsigned int maxlen,unsigned char* behindpacket) { + unsigned char *tmp; + unsigned char *max=dest+maxlen; + unsigned char *after=packet+offset; + int ok=0; + for (tmp=after; maxlen>0&&*tmp; ) { + if (tmp>=behindpacket) return -1; + if ((*tmp>>6)==3) { /* goofy DNS decompression */ + unsigned int ofs=((unsigned int)(*tmp&0x3f)<<8)|*(tmp+1); + if (ofs>=(unsigned int)offset) return -1; /* RFC1035: "pointer to a _prior_ occurrance" */ + if (after<tmp+2) after=tmp+2; + tmp=packet+ofs; + ok=0; + } else { + unsigned int duh; + if (dest+*tmp+1>max) return -1; + if (tmp+*tmp+1>=behindpacket) return -1; + for (duh=*tmp; duh>0; --duh) + *dest++=*++tmp; + *dest++='.'; ok=1; + ++tmp; + if (tmp>after) { after=tmp; if (!*tmp) ++after; } + } + } + if (ok) --dest; + *dest=0; + return after-packet; +} + +static int __dns_gethostbyx_r( + const char* name, + struct hostent* result, + char *buf, size_t buflen, + struct hostent **RESULT, + int *h_errnop, + int lookfor) +{ + + int names,ips; + unsigned char *cur; + unsigned char *max; + unsigned char inpkg[1500]; + char* tmp; + int size; + + if (lookfor==1) { + result->h_addrtype=AF_INET; + result->h_length=4; + } else { + result->h_addrtype=AF_INET6; + result->h_length=16; + } + result->h_aliases=(char**)(buf+8*sizeof(char*)); + result->h_addr_list=(char**)buf; + result->h_aliases[0]=0; + + cur=(unsigned char*)buf+16*sizeof(char*); + max=(unsigned char*)buf+buflen; + names=ips=0; + + if ((size=res_query(name,C_IN,lookfor,inpkg,512))<0) { +invalidpacket: + *h_errnop=HOST_NOT_FOUND; + return -1; + } + { + tmp=(char*)inpkg+12; + { + char Name[257]; + unsigned short q=((unsigned short)inpkg[4]<<8)+inpkg[5]; + while (q>0) { + if (tmp>(char*)inpkg+size) goto invalidpacket; + while (*tmp) { tmp+=*tmp+1; if (tmp>(char*)inpkg+size) goto invalidpacket; } + tmp+=5; + --q; + } + if (tmp>(char*)inpkg+size) goto invalidpacket; + q=((unsigned short)inpkg[6]<<8)+inpkg[7]; + if (q<1) goto nodata; + while (q>0) { + int decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),(unsigned char*)Name,256,inpkg+size); + if (decofs<0) break; + tmp=(char*)inpkg+decofs; + --q; + if (tmp[0]!=0 || tmp[1]!=lookfor || /* TYPE != A */ + tmp[2]!=0 || tmp[3]!=1) { /* CLASS != IN */ + if (tmp[1]==5) { /* CNAME */ + tmp+=10; + decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),(unsigned char*)Name,256,inpkg+size); + if (decofs<0) break; + tmp=(char*)inpkg+decofs; + } else + break; + continue; + } + tmp+=10; /* skip type, class, TTL and length */ + { + int slen; + if (lookfor==1 || lookfor==28) /* A or AAAA*/ { + slen=strlen(Name); + if (cur+slen+8+(lookfor==28?12:0)>=max) { *h_errnop=NO_RECOVERY; return -1; } + } else if (lookfor==12) /* PTR */ { + decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),(unsigned char*)Name,256,inpkg+size); + if (decofs<0) break; + tmp=(char*)inpkg+decofs; + slen=strlen(Name); + } else + slen=strlen(Name); + strcpy((char*)cur,Name); + if (names==0) + result->h_name=(char*)cur; + else + result->h_aliases[names-1]=(char*)cur; + result->h_aliases[names]=0; + if (names<8) ++names; +/* cur+=slen+1; */ + cur+=(slen|3)+1; + result->h_addr_list[ips++] = (char*)cur; + if (lookfor==1) /* A */ { + *(int*)cur=*(int*)tmp; + cur+=4; + result->h_addr_list[ips]=0; + } else if (lookfor==28) /* AAAA */ { + { + int k; + for (k=0; k<16; ++k) cur[k]=tmp[k]; + } + cur+=16; + result->h_addr_list[ips]=0; + } + } +/* puts(Name); */ + } + } + } + if (!names) { +nodata: + *h_errnop=NO_DATA; + return -1; + } + *h_errnop=0; + *RESULT=result; + return 0; +} + + + + +int gethostbyname_r(const char* name, + struct hostent* result, + char *buf, + int buflen, + struct hostent **RESULT, + int *h_errnop) +{ + + size_t L=strlen(name); + result->h_name=buf; + if (buflen<L) { *h_errnop=ERANGE; return 1; } + strcpy(buf,name); + + result->h_addr_list=(char**)(buf+strlen(name)+1); + result->h_addr_list+=sizeof(char*)-((uintptr_t)(result->h_addr_list)&(sizeof(char*)-1)); + result->h_addr_list[0]=(char*)&result->h_addr_list[2]; + if (inet_pton(AF_INET,name,result->h_addr_list[0])) { + result->h_addrtype=AF_INET; + result->h_length=4; +commonip: + result->h_aliases=result->h_addr_list+2*sizeof(char**); + result->h_aliases[0]=0; + result->h_addr_list[1]=0; + *RESULT=result; + *h_errnop=0; + return 0; + } else if (inet_pton(AF_INET6,name,result->h_addr_list[0])) { + result->h_addrtype=AF_INET6; + result->h_length=16; + goto commonip; + } + + + { + struct hostent* r; + sethostent(0); + while ((r=gethostent_r(buf,buflen))) { + int i; + if (r->h_addrtype==AF_INET && !strcasecmp(r->h_name,name)) { /* found it! */ +found: + memmove(result,r,sizeof(struct hostent)); + *RESULT=result; + *h_errnop=0; + endhostent(); + return 0; + } + for (i=0; i<16; ++i) { + if (r->h_aliases[i]) { + if (!strcasecmp(r->h_aliases[i],name)) goto found; + } else break; + } + } + endhostent(); + } + + return __dns_gethostbyx_r(name,result,buf+L,buflen-L,RESULT,h_errnop,1); +} + +#endif + |