mirror of
https://github.com/3proxy/3proxy.git
synced 2026-10-16 00:25:48 +08:00
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>
229 lines
6.0 KiB
C
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 *)¶m->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, ¶m->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 *)¶m->sincl,SASIZE(¶m->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(¶m->sincl) == AF_INET && ip == *(uint32_t *)SAADDR(¶m->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(¶m->sinsl, 0, sizeof(param->sinsl));
|
|
*SAFAMILY(¶m->sinsl) = *SAFAMILY(&conf.nservers[0].addr);
|
|
if(bindwithrange(param, param->remsock, ¶m->sinsl, param->extport)) {
|
|
RETURN(819);
|
|
}
|
|
param->sinsr = conf.nservers[0].addr;
|
|
if(conf.nservers[0].usetcp) {
|
|
if(connectwithpoll(param, param->remsock,(struct sockaddr *)¶m->sinsr,SASIZE(¶m->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 *)¶m->sinsr, buf, i, param->srv->timeouts[SINGLEBYTE_L]*1000) != i){
|
|
RETURN(820);
|
|
}
|
|
param->statscli64 += i;
|
|
param->nwrites++;
|
|
len = sockrecvfrom(param, param->remsock, (struct sockaddr *)¶m->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 *)¶m->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 *)¶m->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);
|
|
}
|
|
|