summaryrefslogtreecommitdiffstats
path: root/mdk-stage1/dietlibc/libcruft/dnscruft.c
blob: d7a0efa50a75c183d2e851d298cf784abd572fb8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

int __dns_fd=-1;

void __dns_make_fd() {
  int tmp;
  struct sockaddr_in si;
  if (__dns_fd>0) return;
  tmp=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
  if (tmp<0) {
	  perror("__dns_make_fd!socket");
	  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;
  }
  __dns_fd=tmp;
}

int __dns_servers=0;
struct sockaddr __dns_server_ips[8];

int __dns_search=0;
char *__dns_domains[8];

void __dns_readstartfiles() {
  int fd;
  char *buf=alloca(4096);
  int len;
  if (__dns_servers>0) return;
  {
    struct sockaddr_in to;
    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;
      }
    }
  }
  if ((fd=open("/etc/resolv.conf",O_RDONLY))<0) return;
  len=read(fd,buf,4096);
  close(fd);
  {
    char *last=buf+len;
    for (; buf<last;) {
      if (!strncmp(buf,"nameserver",10)) {
	buf+=10;
	while (buf<last && *buf!='\n') {
	  while (buf<last && isblank(*buf)) ++buf;
	  {
	    char *tmp=buf;
	    struct sockaddr_in i;
	    while (buf<last && !isspace(*buf)) ++buf;
	    if (buf>=last) break;
	    *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 (!strncmp(buf,"search",6) || !strncmp(buf,"domain",6)) {
	buf+=6;
      }
      while (buf<last && *buf!='\n') ++buf;
      while (buf<last && *buf=='\n') ++buf;
    }
  }
}

/* return length of decoded data or -1 */
int __dns_decodename(unsigned char *packet,int offset,unsigned char *dest,int maxlen) {
  unsigned char *tmp;
  unsigned char *max=dest+maxlen;
  unsigned char *after=packet+offset;
  int ok=0;
  for (tmp=after; maxlen>0&&*tmp; ) {
    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 (after<tmp+2) after=tmp+2;
      tmp=packet+ofs;
      ok=0;
    } else {
      unsigned int duh;
      if (dest+*tmp+1>max) 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;
}