3proxy/src/dnspr.c
Vladimir Dubrovin 3b2d664563 Keep the name servers and RADIUS servers in conf
nservers, numservers and authnserver (resolve.c, common.c) and
radiuslist, nradservers and radiussecret (authradius.c) were globals of
their own; they are configuration, set by nserver, authnserver and
radius, and now live in struct extparam with the rest of it.
MAXNSERVERS, MAXRADIUS and struct radserver move to structures.h, which
plugins include without proxy.h.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:39:37 +03:00

229 lines
6.0 KiB
C

/*
3APA3A simplest proxy server
(c) 2002-2026 by Vladimir Dubrovin <vlad@3proxy.org>
please read License Agreement
*/
#include "proxy.h"
#ifndef UDP
#define UDP
#endif
#define RETURN(xxx) { param->res = xxx; goto CLEANRET; }
#define BUFSIZE 16384
void * dnsprchild(struct clientparam* param) {
uint32_t ip = 0;
unsigned char *bbuf;
unsigned char *buf, *s1, *s2;
char * host = NULL;
unsigned char c;
SASIZETYPE size;
int res, i;
int len;
int semlocked = 1;
unsigned type=0;
uint32_t ttl;
unsigned char addr[16];
#ifdef _WIN32
unsigned long ul = 1;
#endif
if(!(bbuf = malloc(BUFSIZE+2))){
RETURN (21);
}
buf = bbuf+2;
size = sizeof(param->sinsl);
getsockname(param->srv->srvsock, (struct sockaddr *)&param->sincl, &size);
i = param->srv->udplen;
if(i > BUFSIZE) i = BUFSIZE;
memcpy(buf, param->srv->udpbuf, i);
_3proxy_sem_unlock(udpinit);
semlocked = 0;
#if defined(_WIN32) && !defined(SHARE_UDP_SOCKET)
if((param->clisock=nssocket(param->srv, &param->srv->so, param->sostate, NS_IN, AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
RETURN(818);
}
ioctlsocket(param->clisock, FIONBIO, &ul);
if(param->srv->so._setsockopt(param->sostate, param->clisock, SOL_SOCKET, SO_REUSEADDR, (char *)&ul, sizeof(int))) {RETURN(820);};
if(param->srv->so._bind(param->sostate, param->clisock,(struct sockaddr *)&param->sincl,SASIZE(&param->sincl))) {
RETURN(822);
}
#else
/* The reply has to come from the address the query was sent to, which
is the listening socket. */
param->clisock = param->srv->srvsock;
#endif
if(i < 0) {
RETURN(813);
}
buf[BUFSIZE - 1] = 0;
if(i<=13 || i>1000){
RETURN (814);
}
param->operation = DNSRESOLVE;
if((res = (*param->srv->authfunc)(param))) {RETURN(res);}
if(buf[4]!=0 || buf[5]!=1) RETURN(816);
for(len = 12; len<i; len+=(c+1)){
c = buf[len];
if(!c)break;
buf[len] = '.';
}
if(len > (i-4)) {RETURN(817);}
host = strdup((char *)buf+13);
if(!host) {RETURN(21);}
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;
type = ((unsigned)buf[len+1])*256 + (unsigned)buf[len+2];
if(type==0x01 && param->srv->fakeip){
ip = 1;
ttl = 3600;
*(uint32_t *)addr = param->srv->fakeip;
}
#ifndef NOIPV6
else if(type==0x1c && *(uint32_t *)param->srv->fakeip6){
ip = 1;
ttl = 3600;
memcpy(addr, param->srv->fakeip6, 16);
}
#endif
else if((type==0x01 || type==0x1c) && !param->srv->s_option){
ip = udpresolve((type==0x1c)?AF_INET6:AF_INET, (unsigned char *)host, addr, &ttl, param, 0);
}
len+=5;
if(ip){
buf[2] = 0x85;
buf[3] = 0x80;
buf[6] = 0;
buf[7] = 1;
buf[8] = buf[9] = buf[10] = buf[11] = 0;
memset(buf+len, 0, 16);
buf[len] = 0xc0;
buf[len+1] = 0x0c;
buf[len+3] = type;
buf[len+5] = 1;
ttl = htonl(ttl);
memcpy(buf + len + 6, &ttl, 4);
buf[len+11] = type==1? 4:16;
memcpy(buf+len+12,(void *)&addr,type==1? 4:16);
len+=(type==1?16:28);
}
else if(type == 0x0c) {
unsigned a = 0, b = 0, c = 0, d = 0;
if(sscanf(host, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) a = b = c = d = 0;
ip = htonl((d<<24) ^ (c<<16) ^ (b<<8) ^ a);
if(*SAFAMILY(&param->sincl) == AF_INET && ip == *(uint32_t *)SAADDR(&param->sincl)){
buf[2] = 0x85;
buf[3] = 0x80;
buf[6] = 0;
buf[7] = 1;
buf[8] = buf[9] = buf[10] = buf[11] = 0;
memset(buf+len, 0, 20);
buf[len] = 0xc0;
buf[len+1] = 0x0c;
buf[len+3] = 0x0c;
buf[len+5] = 1;
ttl = htonl(3600);
memcpy(buf + len + 6, &ttl, 4);
buf[len+11] = 7;
buf[len+12] = 6;
memcpy(buf+len+13,(void *)"3proxy",6);
len+=20;
}
else ip = 0;
}
if(!ip && conf.numservers){
if((param->remsock=param->srv->so._socket(param->sostate, SASOCK(&conf.nservers[0].addr), conf.nservers[0].usetcp? SOCK_STREAM:SOCK_DGRAM, conf.nservers[0].usetcp?IPPROTO_TCP:IPPROTO_UDP)) == INVALID_SOCKET) {
RETURN(818);
}
memset(&param->sinsl, 0, sizeof(param->sinsl));
*SAFAMILY(&param->sinsl) = *SAFAMILY(&conf.nservers[0].addr);
if(bindwithrange(param, param->remsock, &param->sinsl, param->extport)) {
RETURN(819);
}
param->sinsr = conf.nservers[0].addr;
if(conf.nservers[0].usetcp) {
if(connectwithpoll(param, param->remsock,(struct sockaddr *)&param->sinsr,SASIZE(&param->sinsr),param->srv->timeouts[CONNECT_TO])) RETURN(830);
buf-=2;
*(unsigned short*)buf = htons(i);
i+=2;
}
else {
#ifdef _WIN32
ioctlsocket(param->remsock, FIONBIO, &ul);
#else
fcntl(param->remsock, F_SETFL, O_NONBLOCK | fcntl(param->remsock, F_GETFL));
#endif
}
if(socksendto(param, param->remsock, (struct sockaddr *)&param->sinsr, buf, i, param->srv->timeouts[SINGLEBYTE_L]*1000) != i){
RETURN(820);
}
param->statscli64 += i;
param->nwrites++;
len = sockrecvfrom(param, param->remsock, (struct sockaddr *)&param->sinsr, buf, BUFSIZE, param->srv->timeouts[DNS_TO]*1000);
if(len <= 13) {
RETURN(821);
}
param->statssrv64 += len;
param->nreads++;
if(conf.nservers[0].usetcp) {
unsigned short us;
us = ntohs(*(unsigned short *)buf);
if(us > 4096) RETURN(833);
buf += 2;
len -= 2;
if(len < us) len += sockgetlinebuf(param, SERVER, buf+len, us - len, 0, param->srv->timeouts[SINGLEBYTE_L]);
if(len != us) RETURN(832);
}
if(buf[6] || buf[7]){
if(socksendto(param, param->clisock, (struct sockaddr *)&param->sincr, buf, len, param->srv->timeouts[SINGLEBYTE_L]*1000) != len){
RETURN(822);
}
RETURN(0);
}
}
if(!ip) {
buf[2] = 0x85;
buf[3] = 0x83;
}
res = socksendto(param, param->clisock, (struct sockaddr *)&param->sincr, buf, len, param->srv->timeouts[SINGLEBYTE_L]*1000);
if(res != len){RETURN(819);}
if(!ip) {RETURN(888);}
CLEANRET:
if(semlocked) _3proxy_sem_unlock(udpinit);
if(param->res!=813){
sprintf((char *)buf, "%04x/%s/",
(unsigned)type,
host?host:"");
if((ip && type == 0x01) || type == 0x1c){
myinet_ntop(type == 0x01? AF_INET:AF_INET6, addr, (char *)buf+strlen((char *)buf), 64);
}
dolog(param, buf);
}
if(bbuf)free(bbuf);
if(host)free(host);
#if !defined(_WIN32) || defined(SHARE_UDP_SOCKET)
/* The socket belongs to the service, so the caller must not close it. */
param->clisock = INVALID_SOCKET;
#endif
return (NULL);
}