mirror of
https://github.com/3proxy/3proxy.git
synced 2025-02-24 02:55:40 +08:00
355 lines
8.8 KiB
C
355 lines
8.8 KiB
C
/*
|
|
3APA3A simpliest proxy server
|
|
(c) 2002-2021 by Vladimir Dubrovin <3proxy@3proxy.org>
|
|
|
|
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 < 4000; 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
|
|
|