#include "proxy.h" struct nserver nservers[MAXNSERVERS] = {{{0},0}, {{0},0}, {{0},0}, {{0},0}, {{0},0}}; struct nserver authnserver; uint32_t udpresolve(int af, unsigned char * name, unsigned char * value, uint32_t *retttl, struct clientparam* param, int makeauth){ int i,n; uint32_t retval; if((af == AF_INET) && (retval = hashresolv(&dns_table, name, value, retttl))) { return retval; } if((af == AF_INET6) && (retval = hashresolv(&dns6_table, name, value, retttl))) { return retval; } n = (makeauth && !SAISNULL(&authnserver.addr))? 1 : numservers; for(i=0; isinsl : &addr; sinsr = (param && !makeauth)? ¶m->sinsr : &addr; memset(sinsl, 0, sizeof(addr)); memset(sinsr, 0, sizeof(addr)); if(makeauth && !SAISNULL(&authnserver.addr)){ usetcp = authnserver.usetcp; *SAFAMILY(sinsl) = *SAFAMILY(&authnserver.addr); } else { usetcp = nservers[i].usetcp; *SAFAMILY(sinsl) = *SAFAMILY(&nservers[i].addr); } if((sock=so._socket(so.state, SASOCK(sinsl), usetcp?SOCK_STREAM:SOCK_DGRAM, usetcp?IPPROTO_TCP:IPPROTO_UDP)) == INVALID_SOCKET) break; if(so._bind(so.state, sock,(struct sockaddr *)sinsl,SASIZE(sinsl))){ so._shutdown(so.state, sock, SHUT_RDWR); so._closesocket(so.state, sock); break; } if(makeauth && !SAISNULL(&authnserver.addr)){ *sinsr = authnserver.addr; } else { *sinsr = nservers[i].addr; } if(usetcp){ if(connectwithpoll(NULL, sock,(struct sockaddr *)sinsr,SASIZE(sinsr),conf.timeouts[CONNECT_TO])) { so._shutdown(so.state, sock, SHUT_RDWR); so._closesocket(so.state, sock); break; } #ifdef TCP_NODELAY { int opt = 1; setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt)); } #endif } len = (int)strlen((char *)name); serial = myrand(name,len); *(unsigned short*)buf = serial; /* query id */ buf[2] = 1; /* recursive */ buf[3] = 0; buf[4] = 0; buf[5] = 1; /* 1 request */ buf[6] = buf[7] = 0; /* no replies */ buf[8] = buf[9] = 0; /* no ns count */ buf[10] = buf[11] = 0; /* no additional */ if(len > 255) { len = 255; } memcpy(buf + 13, name, len); len += 13; buf[len] = 0; for(s2 = buf + 12; (s1 = (unsigned char *)strchr((char *)s2 + 1, '.')); s2 = s1)*s2 = (unsigned char)((s1 - s2) - 1); *s2 = (len - (int)(s2 - buf)) - 1; len++; buf[len++] = 0; buf[len++] = (makeauth == 1)? 0x0c : (af==AF_INET6? 0x1c:0x01);/* PTR:host address */ buf[len++] = 0; buf[len++] = 1; /* INET */ if(usetcp){ buf-=2; *(unsigned short*)buf = htons(len); len+=2; } if(socksendto(NULL, sock, (struct sockaddr *)sinsr, buf, len, conf.timeouts[SINGLEBYTE_L]*1000) != len){ so._shutdown(so.state, sock, SHUT_RDWR); so._closesocket(so.state, sock); continue; } if(param) param->statscli64 += len; len = sockrecvfrom(NULL, sock, (struct sockaddr *)sinsr, buf, 4096, conf.timeouts[DNS_TO]*1000); so._shutdown(so.state, sock, SHUT_RDWR); so._closesocket(so.state, sock); if(len <= 13) { continue; } if(param) param->statssrv64 += len; if(usetcp){ unsigned short us; us = ntohs(*(unsigned short*)buf); len-=2; buf+=2; if(us > 4096 || us < len || (us > len && sockrecvfrom(NULL, sock, (struct sockaddr *)sinsr, buf+len, us-len, conf.timeouts[DNS_TO]*1000) != us-len)) { continue; } } if(*(unsigned short *)buf != serial)continue; if((na = buf[7] + (((unsigned short)buf[6])<<8)) < 1) { return 0; } nq = buf[5] + (((unsigned short)buf[4])<<8); if (nq != 1) { continue; /* we did only 1 request */ } for(k = 13; k= len) { continue; } k += 4; if(na > 255) na = 255; /* somebody is very evil */ for (j = 0; j < na; j++) { /* now there should be answers */ while(buf[k] < 192 && buf[k] !=0 && (k+buf[k]+14) < len) k+= (buf[k] + 1); if(!buf[k]) k--; if((k+(af == AF_INET6?28:16)) > len) { break; } flen = buf[k+11] + (((unsigned short)buf[k+10])<<8); if((k+12+flen) > len) { break; } if(makeauth != 1){ if(buf[k+2] != 0 || buf[k+3] != (af == AF_INET6?0x1c:0x1) || flen != (af == AF_INET6?16:4)) { k+= (12 + flen); continue; /* we need A IPv4 */ } ttl = ntohl(*(uint32_t *)(buf + k + 6)); memcpy(value, buf + k + 12, af == AF_INET6? 16:4); if(ttl < 0 || ttl > (3600*12)) ttl = 3600*12; if(!ttl) ttl = 1; hashadd(af == AF_INET6?&dns6_table:&dns_table, name, value, conf.time+ttl); if(retttl) *retttl = ttl; return 1; } else { if(buf[k+2] != 0 || buf[k+3] != 0x0c) { k+= (12 + flen); continue; /* we need A PTR */ } for (s2 = buf + k + 12; s2 < (buf + k + 12 + len) && *s2; ){ s1 = s2 + ((unsigned)*s2) + 1; *s2 = '.'; s2 = s1; } *s2 = 0; if(param->username)myfree(param->username); param->username = (unsigned char *)mystrdup ((char *)buf + k + 13); return udpresolve(af,param->username, value, NULL, NULL, 2); } } } return 0; } uint32_t myresolver(int af, unsigned char * name, unsigned char * value){ return udpresolve(af, name, value, NULL, NULL, 0); } uint32_t fakeresolver (int af, unsigned char *name, unsigned char * value){ memset(value, 0, af == AF_INET6? 16 : 4); if(af == AF_INET6){ memset(value, 0, 16); value[15] = 2; } else { value[0] = 127; value[1] = 0; value[2] = 0; value[3] = 2; } return 1; }