From 94a83d126fc24ce50f51b4a6c1cc0bd8b106f054 Mon Sep 17 00:00:00 2001 From: Vladimir Dubrovin <3proxy@3proxy.ru> Date: Thu, 22 Oct 2026 12:04:18 +0300 Subject: [PATCH] dnspr: only the answer to the query asked is relayed dnspr relayed to the client whatever came first to the socket it asked the name server from, from any address, under any id. Now: - the query goes to the name server under a random id of its own, the client's put back in what is relayed to it; - an answer over UDP is taken only from the address and port of the name server asked, anything else read past until DNS_TO runs out; - the answer must have that id, be a response, and carry the question asked byte for byte, over UDP and TCP alike (a TCP answer that does not is error 834). Co-Authored-By: Claude Opus 5.5 --- src/dnspr.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/src/dnspr.c b/src/dnspr.c index 6e0f917..0b54435 100644 --- a/src/dnspr.c +++ b/src/dnspr.c @@ -15,6 +15,12 @@ #define BUFSIZE 16384 +/* An answer to the query asked: our id, a response, and the question + byte for byte. */ +static int dnsanswer(const unsigned char *buf, int len, const unsigned char *q, int qend){ + return len >= qend && buf[0] == q[0] && buf[1] == q[1] && (buf[2] & 0x80) && + buf[4] == q[4] && buf[5] == q[5] && !memcmp(buf + 12, q + 12, qend - 12); +} void * dnsprchild(struct clientparam* param) { uint32_t ip = 0; @@ -146,6 +152,20 @@ void * dnsprchild(struct clientparam* param) { else ip = 0; } if(!ip && numservers){ + /* the question, to check the answer against; the name server is + asked under an id of our own, the client's put back in its answer */ + unsigned char question[1024], cid[2]; + int qend = (len < i)? len : i; + unsigned short id = (unsigned short)myrand(); + PROXYSOCKADDRTYPE from; + time_t deadline; + int to; + + cid[0] = buf[0]; + cid[1] = buf[1]; + buf[0] = (unsigned char)(id >> 8); + buf[1] = (unsigned char)(id & 0xff); + memcpy(question, buf, qend); if((param->remsock=param->srv->so._socket(param->sostate, SASOCK(&nservers[0].addr), nservers[0].usetcp? SOCK_STREAM:SOCK_DGRAM, nservers[0].usetcp?IPPROTO_TCP:IPPROTO_UDP)) == INVALID_SOCKET) { RETURN(818); } @@ -174,9 +194,21 @@ void * dnsprchild(struct clientparam* param) { } param->statscli64 += i; param->nwrites++; - len = sockrecvfrom(param, param->remsock, (struct sockaddr *)¶m->sinsr, buf, BUFSIZE, conf.timeouts[DNS_TO]*1000); - if(len <= 13) { - RETURN(821); + /* over UDP only an answer from the name server asked is taken, any + other read past while the time for it lasts */ + deadline = time(NULL) + conf.timeouts[DNS_TO]; + for(;;){ + to = (int)(deadline - time(NULL)); + if(to <= 0) RETURN(821); + len = sockrecvfrom(param, param->remsock, (struct sockaddr *)&from, buf, BUFSIZE, to*1000); + if(len <= 13) { + RETURN(821); + } + if(nservers[0].usetcp) break; + if(*SAFAMILY(&from) == *SAFAMILY(¶m->sinsr) && + !memcmp(SAADDR(&from), SAADDR(¶m->sinsr), SAADDRLEN(¶m->sinsr)) && + *SAPORT(&from) == *SAPORT(¶m->sinsr) && + dnsanswer(buf, len, question, qend)) break; } param->statssrv64 += len; param->nreads++; @@ -188,7 +220,10 @@ void * dnsprchild(struct clientparam* param) { len -= 2; if(len < us) len += sockgetlinebuf(param, SERVER, buf+len, us - len, 0, conf.timeouts[SINGLEBYTE_L]); if(len != us) RETURN(832); + if(!dnsanswer(buf, len, question, qend)) RETURN(834); } + buf[0] = cid[0]; + buf[1] = cid[1]; if(buf[6] || buf[7]){ if(socksendto(param, param->clisock, (struct sockaddr *)¶m->sincr, buf, len, conf.timeouts[SINGLEBYTE_L]*1000) != len){ RETURN(822);