mirror of
https://github.com/3proxy/3proxy.git
synced 2025-04-21 11:42:09 +08:00

- sockmapping rewritten from stratch to minimilse polling. poll() is now only called if blocking is actually expected, splice pipes are now polled if splice fails, buffers flushing is much more accurate. - logging code moved to separate files - signal masks added to client threads to prevent unneeded interruptions - bandwidth limitation will not delay the thread after client or server shutdown
355 lines
8.8 KiB
C
355 lines
8.8 KiB
C
/*
|
|
3APA3A simpliest proxy server
|
|
(c) 2002-2020 by Vladimir Dubrovin <3proxy@3proxy.ru>
|
|
|
|
please read License Agreement
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "proxy.h"
|
|
pthread_mutex_t log_mutex;
|
|
int havelog = 0;
|
|
|
|
|
|
struct clientparam logparam;
|
|
struct srvparam logsrv;
|
|
|
|
|
|
|
|
void dolog(struct clientparam * param, const unsigned char *s){
|
|
static int init = 0;
|
|
|
|
if(param)param->srv->logfunc(param, s);
|
|
else {
|
|
if(!init){
|
|
srvinit(&logsrv, &logparam);
|
|
init = 1;
|
|
}
|
|
logstdout(&logparam, s);
|
|
}
|
|
}
|
|
|
|
|
|
void clearstat(struct clientparam * param) {
|
|
|
|
#ifdef _WIN32
|
|
struct timeb tb;
|
|
|
|
ftime(&tb);
|
|
param->time_start = (time_t)tb.time;
|
|
param->msec_start = (unsigned)tb.millitm;
|
|
|
|
#else
|
|
struct timeval tv;
|
|
struct timezone tz;
|
|
gettimeofday(&tv, &tz);
|
|
|
|
param->time_start = (time_t)tv.tv_sec;
|
|
param->msec_start = (tv.tv_usec / 1000);
|
|
#endif
|
|
param->statscli64 = param->statssrv64 = param->nreads = param->nwrites =
|
|
param->nconnects = 0;
|
|
}
|
|
|
|
|
|
char months[12][4] = {
|
|
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
|
};
|
|
|
|
|
|
int dobuf2(struct clientparam * param, unsigned char * buf, const unsigned char *s, const unsigned char * doublec, struct tm* tm, char * format){
|
|
int i, j;
|
|
int len;
|
|
time_t sec;
|
|
unsigned msec;
|
|
|
|
long timezone;
|
|
unsigned delay;
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
struct timeb tb;
|
|
|
|
ftime(&tb);
|
|
sec = (time_t)tb.time;
|
|
msec = (unsigned)tb.millitm;
|
|
timezone = tm->tm_isdst*60 - tb.timezone;
|
|
|
|
#else
|
|
struct timeval tv;
|
|
struct timezone tz;
|
|
gettimeofday(&tv, &tz);
|
|
|
|
sec = (time_t)tv.tv_sec;
|
|
msec = tv.tv_usec / 1000;
|
|
#ifdef _SOLARIS
|
|
timezone = -altzone / 60;
|
|
#else
|
|
timezone = tm->tm_gmtoff / 60;
|
|
#endif
|
|
#endif
|
|
|
|
delay = param->time_start?((unsigned) ((sec - param->time_start))*1000 + msec) - param->msec_start : 0;
|
|
*buf = 0;
|
|
for(i=0, j=0; format[j] && i < 4040; j++){
|
|
if(format[j] == '%' && format[j+1]){
|
|
j++;
|
|
switch(format[j]){
|
|
case '%':
|
|
buf[i++] = '%';
|
|
break;
|
|
case 'y':
|
|
sprintf((char *)buf+i, "%.2d", tm->tm_year%100);
|
|
i+=2;
|
|
break;
|
|
case 'Y':
|
|
sprintf((char *)buf+i, "%.4d", tm->tm_year+1900);
|
|
i+=4;
|
|
break;
|
|
case 'm':
|
|
sprintf((char *)buf+i, "%.2d", tm->tm_mon+1);
|
|
i+=2;
|
|
break;
|
|
case 'o':
|
|
sprintf((char *)buf+i, "%s", months[tm->tm_mon]);
|
|
i+=3;
|
|
break;
|
|
case 'd':
|
|
sprintf((char *)buf+i, "%.2d", tm->tm_mday);
|
|
i+=2;
|
|
break;
|
|
case 'H':
|
|
sprintf((char *)buf+i, "%.2d", tm->tm_hour);
|
|
i+=2;
|
|
break;
|
|
case 'M':
|
|
sprintf((char *)buf+i, "%.2d", tm->tm_min);
|
|
i+=2;
|
|
break;
|
|
case 'S':
|
|
sprintf((char *)buf+i, "%.2d", tm->tm_sec);
|
|
i+=2;
|
|
break;
|
|
case 't':
|
|
sprintf((char *)buf+i, "%.10u", (unsigned)sec);
|
|
i+=10;
|
|
break;
|
|
case 'b':
|
|
i+=sprintf((char *)buf+i, "%u", delay?(unsigned)(param->statscli64 * 1000./delay):0);
|
|
break;
|
|
case 'B':
|
|
i+=sprintf((char *)buf+i, "%u", delay?(unsigned)(param->statssrv64 * 1000./delay):0);
|
|
break;
|
|
case 'D':
|
|
i+=sprintf((char *)buf+i, "%u", delay);
|
|
break;
|
|
case '.':
|
|
sprintf((char *)buf+i, "%.3u", msec);
|
|
i+=3;
|
|
break;
|
|
case 'z':
|
|
sprintf((char *)buf+i, "%+.2ld%.2u", timezone / 60, (unsigned)(timezone%60));
|
|
i+=5;
|
|
break;
|
|
case 'U':
|
|
if(param->username && *param->username){
|
|
for(len = 0; i< 4000 && param->username[len]; len++){
|
|
buf[i] = param->username[len];
|
|
if(param->srv->nonprintable && (buf[i] < 0x20 || strchr((char *)param->srv->nonprintable, buf[i]))) buf[i] = param->srv->replace;
|
|
if(doublec && strchr((char *)doublec, buf[i])) {
|
|
buf[i+1] = buf[i];
|
|
i++;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
else {
|
|
buf[i++] = '-';
|
|
}
|
|
break;
|
|
case 'n':
|
|
len = param->hostname? (int)strlen((char *)param->hostname) : 0;
|
|
if (len > 0 && !strchr((char *)param->hostname, ':')) for(len = 0; param->hostname[len] && i < 256; len++, i++){
|
|
buf[i] = param->hostname[len];
|
|
if(param->srv->nonprintable && (buf[i] < 0x20 || strchr((char *)param->srv->nonprintable, buf[i]))) buf[i] = param->srv->replace;
|
|
if(doublec && strchr((char *)doublec, buf[i])) {
|
|
buf[i+1] = buf[i];
|
|
i++;
|
|
}
|
|
}
|
|
else {
|
|
buf[i++] = '[';
|
|
i += myinet_ntop(*SAFAMILY(¶m->req), SAADDR(¶m->req), (char *)buf + i, 64);
|
|
buf[i++] = ']';
|
|
}
|
|
break;
|
|
|
|
case 'N':
|
|
if(param->service < 15) {
|
|
len = (conf.stringtable)? (int)strlen((char *)conf.stringtable[SERVICES + param->service]) : 0;
|
|
if(len > 20) len = 20;
|
|
memcpy(buf+i, (len)?conf.stringtable[SERVICES + param->service]:(unsigned char*)"-", (len)?len:1);
|
|
i += (len)?len:1;
|
|
}
|
|
break;
|
|
case 'E':
|
|
sprintf((char *)buf+i, "%.05d", param->res);
|
|
i += 5;
|
|
break;
|
|
case 'T':
|
|
if(s){
|
|
for(len = 0; i<4000 && s[len]; len++){
|
|
buf[i] = s[len];
|
|
if(param->srv->nonprintable && (buf[i] < 0x20 || strchr((char *)param->srv->nonprintable, buf[i]))) buf[i] = param->srv->replace;
|
|
if(doublec && strchr((char *)doublec, buf[i])) {
|
|
buf[i+1] = buf[i];
|
|
i++;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
break;
|
|
case 'e':
|
|
i += myinet_ntop(*SAFAMILY(¶m->sinsl), SAADDR(¶m->sinsl), (char *)buf + i, 64);
|
|
break;
|
|
case 'i':
|
|
i += myinet_ntop(*SAFAMILY(¶m->sincl), SAADDR(¶m->sincl), (char *)buf + i, 64);
|
|
break;
|
|
case 'C':
|
|
i += myinet_ntop(*SAFAMILY(¶m->sincr), SAADDR(¶m->sincr), (char *)buf + i, 64);
|
|
break;
|
|
case 'R':
|
|
i += myinet_ntop(*SAFAMILY(¶m->sinsr), SAADDR(¶m->sinsr), (char *)buf + i, 64);
|
|
break;
|
|
case 'Q':
|
|
i += myinet_ntop(*SAFAMILY(¶m->req), SAADDR(¶m->req), (char *)buf + i, 64);
|
|
break;
|
|
case 'p':
|
|
sprintf((char *)buf+i, "%hu", ntohs(*SAPORT(¶m->srv->intsa)));
|
|
i += (int)strlen((char *)buf+i);
|
|
break;
|
|
case 'c':
|
|
sprintf((char *)buf+i, "%hu", ntohs(*SAPORT(¶m->sincr)));
|
|
i += (int)strlen((char *)buf+i);
|
|
break;
|
|
case 'r':
|
|
sprintf((char *)buf+i, "%hu", ntohs(*SAPORT(¶m->sinsr)));
|
|
i += (int)strlen((char *)buf+i);
|
|
break;
|
|
case 'q':
|
|
sprintf((char *)buf+i, "%hu", ntohs(*SAPORT(¶m->req)));
|
|
i += (int)strlen((char *)buf+i);
|
|
break;
|
|
case 'L':
|
|
sprintf((char *)buf+i, "%"PRINTF_INT64_MODIFIER"u", param->cycles);
|
|
i += (int)strlen((char *)buf+i);
|
|
break;
|
|
case 'I':
|
|
sprintf((char *)buf+i, "%"PRINTF_INT64_MODIFIER"u", param->statssrv64);
|
|
i += (int)strlen((char *)buf+i);
|
|
break;
|
|
case 'O':
|
|
sprintf((char *)buf+i, "%"PRINTF_INT64_MODIFIER"u", param->statscli64);
|
|
i += (int)strlen((char *)buf+i);
|
|
break;
|
|
case 'h':
|
|
sprintf((char *)buf+i, "%d", param->redirected);
|
|
i += (int)strlen((char *)buf+i);
|
|
break;
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
{
|
|
int k, pmin=0, pmax=0;
|
|
for (k = j; isnumber(format[k]); k++);
|
|
if(format[k] == '-' && isnumber(format[k+1])){
|
|
pmin = atoi(format + j) - 1;
|
|
k++;
|
|
pmax = atoi(format + k) -1;
|
|
for (; isnumber(format[k]); k++);
|
|
j = k;
|
|
}
|
|
if(!s || format[k]!='T') break;
|
|
for(k = 0, len = 0; s[len] && i < 4000; len++){
|
|
if(isspace(s[len])){
|
|
k++;
|
|
while(isspace(s[len+1]))len++;
|
|
if(k == pmin) continue;
|
|
}
|
|
if(k>=pmin && k<=pmax) {
|
|
buf[i] = s[len];
|
|
if(param->srv->nonprintable && (buf[i] < 0x20 || strchr((char *)param->srv->nonprintable, buf[i]))) buf[i] = param->srv->replace;
|
|
if(doublec && strchr((char *)doublec, buf[i])) {
|
|
buf[i+1] = buf[i];
|
|
i++;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
default:
|
|
buf[i++] = format[j];
|
|
}
|
|
}
|
|
else buf[i++] = format[j];
|
|
}
|
|
buf[i] = 0;
|
|
return i;
|
|
}
|
|
|
|
int dobuf(struct clientparam * param, unsigned char * buf, const unsigned char *s, const unsigned char * doublec){
|
|
struct tm* tm;
|
|
int i;
|
|
char * format;
|
|
time_t t;
|
|
|
|
time(&t);
|
|
if(!param) return 0;
|
|
if(param->trafcountfunc)(*param->trafcountfunc)(param);
|
|
format = param->srv->logformat?(char *)param->srv->logformat : DEFLOGFORMAT;
|
|
tm = (*format == 'G' || *format == 'g')?
|
|
gmtime(&t) : localtime(&t);
|
|
i = dobuf2(param, buf, s, doublec, tm, format + 1);
|
|
clearstat(param);
|
|
return i;
|
|
}
|
|
|
|
void lognone(struct clientparam * param, const unsigned char *s) {
|
|
if(param->trafcountfunc)(*param->trafcountfunc)(param);
|
|
clearstat(param);
|
|
}
|
|
|
|
void logstdout(struct clientparam * param, const unsigned char *s) {
|
|
FILE *log;
|
|
unsigned char tmpbuf[8192];
|
|
|
|
dobuf(param, tmpbuf, s, NULL);
|
|
log = param->srv->stdlog?param->srv->stdlog:conf.stdlog?conf.stdlog:stdout;
|
|
if(!param->nolog)if(fprintf(log, "%s\n", tmpbuf) < 0) {
|
|
perror("printf()");
|
|
};
|
|
if(log != conf.stdlog)fflush(log);
|
|
}
|
|
#ifndef _WIN32
|
|
void logsyslog(struct clientparam * param, const unsigned char *s) {
|
|
|
|
unsigned char tmpbuf[8192];
|
|
dobuf(param, tmpbuf, s, NULL);
|
|
if(!param->nolog)syslog(LOG_INFO, "%s", tmpbuf);
|
|
}
|
|
#endif
|
|
|