diff options
Diffstat (limited to 'mdk-stage1/dietlibc/libcruft/dnscruft.c')
-rw-r--r-- | mdk-stage1/dietlibc/libcruft/dnscruft.c | 132 |
1 files changed, 99 insertions, 33 deletions
diff --git a/mdk-stage1/dietlibc/libcruft/dnscruft.c b/mdk-stage1/dietlibc/libcruft/dnscruft.c index d7a0efa50..bd8bee79a 100644 --- a/mdk-stage1/dietlibc/libcruft/dnscruft.c +++ b/mdk-stage1/dietlibc/libcruft/dnscruft.c @@ -7,51 +7,100 @@ #include <string.h> #include <ctype.h> #include <stdlib.h> +#include <resolv.h> +#include <net/if.h> +#include "dietfeatures.h" int __dns_fd=-1; +#ifdef WANT_IPV6_DNS +int __dns_fd6=-1; +#endif -void __dns_make_fd() { +/* the ad-hoc internal API from hell ;-) */ +void __dns_make_fd(void); +void __dns_make_fd6(void); +void __dns_readstartfiles(void); +int __dns_decodename(unsigned char *packet,unsigned int offset,unsigned char *dest, + unsigned int maxlen,unsigned char* behindpacket); + +void __dns_make_fd(void) { int tmp; struct sockaddr_in si; - if (__dns_fd>0) return; + if (__dns_fd>=0) return; tmp=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP); - if (tmp<0) { - perror("__dns_make_fd!socket"); - return; - } + if (tmp<0) return; si.sin_family=AF_INET; si.sin_port=0; si.sin_addr.s_addr=INADDR_ANY; - if (bind(tmp,(struct sockaddr*)&si,sizeof(si))) { - perror("__dns_make_fd!bind"); - return; - } + if (bind(tmp,(struct sockaddr*)&si,sizeof(si))) return; __dns_fd=tmp; } -int __dns_servers=0; -struct sockaddr __dns_server_ips[8]; +#ifdef WANT_IPV6_DNS +void __dns_make_fd6(void) { + int tmp; + struct sockaddr_in6 si; + if (__dns_fd6>=0) return; + tmp=socket(PF_INET6,SOCK_DGRAM,IPPROTO_UDP); + if (tmp<0) return; + si.sin6_family=AF_INET6; + si.sin6_port=0; + memset(&si.sin6_addr,0,16); + if (bind(tmp,(struct sockaddr*)&si,sizeof(si))) return; + __dns_fd6=tmp; +} +#endif -int __dns_search=0; +static int parsesockaddr(const char* c,void* x) { + struct sockaddr_in to; + if (inet_aton(c,&to.sin_addr)) { + to.sin_port=htons(53); + to.sin_family=AF_INET; + memmove(x,&to,sizeof(struct sockaddr_in_pad)); + return 1; +#ifdef WANT_IPV6_DNS + } else { + struct sockaddr_in6 to6; + char* d=strchr(c,'%'); + to6.sin6_flowinfo=to6.sin6_scope_id=0; + if (d) + to6.sin6_scope_id=if_nametoindex(d+1); + if (inet_pton(AF_INET6,c,&to6.sin6_addr)) { + to6.sin6_port=htons(53); + to6.sin6_family=AF_INET6; + memmove(x,&to6,sizeof(struct sockaddr_in_pad)); + return 1; + } +#endif + } + return 0; +} + +#ifdef WANT_FULL_RESOLV_CONF +int __dns_search; char *__dns_domains[8]; +#endif -void __dns_readstartfiles() { +void __dns_readstartfiles(void) { int fd; - char *buf=alloca(4096); + char __buf[4096]; + char *buf=__buf; int len; - if (__dns_servers>0) return; + if (_res.nscount>0) return; { struct sockaddr_in to; +#ifdef WANT_IPV6_DNS + struct sockaddr_in6 to6; +#endif char *cacheip=getenv("DNSCACHEIP"); - if (cacheip) { - to.sin_port=htons(53); - to.sin_family=AF_INET; - if (inet_aton(cacheip,&to.sin_addr)) { - memmove(__dns_server_ips,&to,sizeof(struct sockaddr)); - ++__dns_servers; - } - } +#ifdef WANT_FULL_RESOLV_CONF + __dns_search=0; +#endif + if (cacheip) + if (parsesockaddr(cacheip,_res.nsaddr_list)) + ++_res.nscount; } + _res.options=RES_RECURSE; if ((fd=open("/etc/resolv.conf",O_RDONLY))<0) return; len=read(fd,buf,4096); close(fd); @@ -65,21 +114,35 @@ void __dns_readstartfiles() { { char *tmp=buf; struct sockaddr_in i; + char save; while (buf<last && !isspace(*buf)) ++buf; if (buf>=last) break; + save=*buf; *buf=0; - if (inet_aton(tmp,&i.sin_addr)) { - i.sin_family=AF_INET; - i.sin_port=htons(53); - memmove(&__dns_server_ips[__dns_servers],&i,sizeof(struct sockaddr)); - if (__dns_servers<8) ++__dns_servers; - } + if (parsesockaddr(tmp,&_res.nsaddr_list[_res.nscount])) + if (_res.nscount<MAXNS) ++_res.nscount; + *buf=save; } } } - if (!strncmp(buf,"search",6) || !strncmp(buf,"domain",6)) { +#ifdef WANT_FULL_RESOLV_CONF + else if (!strncmp(buf,"search",6) || !strncmp(buf,"domain",6)) { buf+=6; + while (buf<last && *buf!='\n') { + char save; + while (buf<last && (*buf==',' || isblank(*buf))) ++buf; + __dns_domains[__dns_search]=buf; + while (buf<last && (*buf=='.' || *buf=='-' || isalnum(*buf))) ++buf; + save=*buf; + if (buf<last) *buf=0; + if (__dns_domains[__dns_search]<buf && + (__dns_domains[__dns_search]=strdup(__dns_domains[__dns_search]))) + ++__dns_search; + if (buf<last) *buf=save; + } + continue; } +#endif while (buf<last && *buf!='\n') ++buf; while (buf<last && *buf=='\n') ++buf; } @@ -87,21 +150,24 @@ void __dns_readstartfiles() { } /* return length of decoded data or -1 */ -int __dns_decodename(unsigned char *packet,int offset,unsigned char *dest,int maxlen) { +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>=offset) return -1; /* RFC1035: "pointer to a _prior_ occurrance" */ + 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; |