/* 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