mirror of
https://github.com/3proxy/3proxy.git
synced 2026-10-24 12:05:47 +08:00
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 <noreply@anthropic.com>
This commit is contained in:
parent
4edb94d09e
commit
94a83d126f
37
src/dnspr.c
37
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,10 +194,22 @@ 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);
|
||||
/* 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++;
|
||||
if(nservers[0].usetcp) {
|
||||
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user