/* 3APA3A simplest proxy server (c) 2002-2026 by Vladimir Dubrovin please read License Agreement */ #include "proxy.h" #ifdef WITH_HTTPSRV #define RETURN(xxx) { param->res = xxx; goto CLEANRET; } #define LINESIZE 65536 FILE * confopen(); extern void decodeurl(unsigned char *s, int filter); struct printparam { char buf[1024]; int inbuf; struct clientparam *cp; }; static void stdpr(struct printparam* pp, char *buf, int inbuf){ if((pp->inbuf + inbuf > 1024) || !buf) { socksend(pp->cp, pp->cp->clisock, (unsigned char *)pp->buf, pp->inbuf, pp->cp->srv->timeouts[STRING_S]); pp->inbuf = 0; if(!buf) return; } if(inbuf >= 1000){ socksend(pp->cp, pp->cp->clisock, (unsigned char *)buf, inbuf, pp->cp->srv->timeouts[STRING_S]); } else { memcpy(pp->buf + pp->inbuf, buf, inbuf); pp->inbuf += inbuf; } } static void stdcbf(void *cb, char *buf, int inbuf){ int delay = 0; int i; for(i = 0; i < inbuf; i++){ switch(buf[i]){ case '&': if(delay){ stdpr((struct printparam*)cb, buf+i-delay, delay); delay = 0; } stdpr((struct printparam*)cb, "&", 5); break; case '<': if(delay){ stdpr((struct printparam*)cb, buf+i-delay, delay); delay = 0; } stdpr((struct printparam*)cb, "<", 4); break; case '>': if(delay){ stdpr((struct printparam*)cb, buf+i-delay, delay); delay = 0; } stdpr((struct printparam*)cb, ">", 4); break; default: delay++; break; } } if(delay){ stdpr((struct printparam*)cb, buf+i-delay, delay); } } /* static char * templateprint(struct printparam* pp, int *level, struct dictionary *dict, char * template){ char *s, *s2; for(; template && *template; ){ if(!( s = strchr(template, '<'))){ stdpr(pp, template, (int)strlen(template)); return template + strlen(template); } if(s[1] != '%' || s[2] == '%'){ stdpr(pp, template, (int)(s - template) + 1); template = s + 1; continue; } if(s[2] == '/' && (s2 = strchr(s + 2, '>')) && *(s2 - 1) == '%'){ if(--*level < 0) return NULL; return s2 + 1; } } return template; } */ static void printstr(struct printparam* pp, char* str){ stdpr(pp, str, str?(int)strlen(str):0); } static void printval(void *value, int type, int level, struct printparam* pp){ struct node pn, cn; struct property *p; int i, pi; pn.iteration = NULL; pn.parent = NULL; pn.type = type; pn.value = value; printstr(pp, ""); for(pi = 0; pi < (int)datatypes[type].properties_count; ) { p = datatypes[type].properties + pi; cn.iteration = NULL; cn.parent = &pn; cn.type = p->type; cn.value = (*p->e_f)(&pn); if(cn.value){ for(i = 0; i < level; i++) printstr(pp, "\t"); if(strcmp(p->name, "next")){ printstr(pp, ""); printstr(pp, ""); printstr(pp, p->name); printstr(pp, ""); printstr(pp, ""); printstr(pp, datatypes[p->type].type); printstr(pp, ""); printstr(pp, ""); printstr(pp, p->description); printstr(pp, ""); } if(datatypes[p->type].p_f){ printstr(pp, "type].p_f)(&cn, stdcbf, pp); printstr(pp, "]]>\n"); printstr(pp, ""); } else { if(!strcmp(p->name, "next")){ /* printstr(pp, "\n"); */ printstr(pp, "\n"); pi = 0; pn.value = value = cn.value; continue; } else { printstr(pp, "\n"); printval(cn.value, cn.type, level+1, pp); printstr(pp, ""); } } } pi++; } printstr(pp, ""); } char * admin_stringtable[]={ "HTTP/1.0 401 Authentication Required\r\n" "WWW-Authenticate: Basic realm=\"proxy\"\r\n" "Connection: close\r\n" "Content-type: text/html; charset=us-ascii\r\n" "\r\n" "401 Authentication Required\r\n" "

401 Authentication Required

Access to requested resource disallowed by administrator or you need valid username/password to use this resource

\r\n", "HTTP/1.0 200 OK\r\n" "Connection: close\r\n" "Expires: Thu, 01 Dec 1994 16:00:00 GMT\r\n" "Cache-Control: no-cache\r\n" "Content-type: text/html\r\n" "\r\n" "%s configuration page\r\n" "\r\n" "
\r\n" "

         " "         

\r\n" "Counters
\r\n" "Reload
\r\n" "Running Services\r\n" "
" "

%s %s configuration

", "HTTP/1.0 200 OK\r\n" "Connection: close\r\n" "Cache-Control: no-cache\r\n" "Content-type: text/xml; charset=utf-8\r\n" "Content-disposition: inline; filename=running.xml\r\n" "\r\n" "\r\n" "\r\n" "\r\n" "Services currently running and connected clients\r\n", "\r\n", "HTTP/1.0 200 OK\r\n" "Connection: close\r\n" "Cache-Control: no-cache\r\n" "Content-type: text/css\r\n" "\r\n" "services {\r\n" " display: block;\r\n" " margin: 10px auto 10px auto;\r\n" " width: 80%;\r\n" " background: black;\r\n" " font-family: sans-serif;\r\n" " font-size: small;\r\n" " color: silver;\r\n" " }\r\n" "item {\r\n" " display: block;\r\n" " margin-bottom: 10px;\r\n" " border: 2px solid #CCC;\r\n" " padding: 10px;\r\n" " spacing: 2px;\r\n" " }\r\n" "parameter {\r\n" " display: block;\r\n" " padding: 2px;\r\n" " margin-top: 10px;\r\n" " border: 1px solid grey;\r\n" " background: #EEE;\r\n" " color: black;\r\n" " }\r\n" "name {\r\n" " display: inline;\r\n" " float: left;\r\n" " margin-right: 5px;\r\n" " font-weight: bold;\r\n" " }\r\n" "type {\r\n" " display: inline;\r\n" " font-size: x-small;\r\n" " margin-right: 5px;\r\n" " color: #666;\r\n" " white-space: nowrap;\r\n" " font-style: italic;\r\n" " }\r\n" "description {\r\n" " display: inline;\r\n" " margin-right: 5px;\r\n" " white-space: nowrap;\r\n" " }\r\n" "value {\r\n" " display: block;\r\n" " margin-right: 5px;\r\n" " }\r\n", "










\r\n" "
"
	COPYRIGHT
	"\r\n"
	"
", "

Counters

\r\n" "\r\n" "" "" "" "" "\r\n", "
Action#/DescActiveUsersSource AddressDestination AddressPortLimitUnitsValueResetUpdatedPosition
\r\n", NULL }; #define authreq admin_stringtable[0] #define ok admin_stringtable[1] #define xml admin_stringtable[2] #define postxml admin_stringtable[3] #define style admin_stringtable[4] #define tail admin_stringtable[5] #define counters admin_stringtable[6] #define counterstail admin_stringtable[7] static int printportlist(char *buf, int bufsize, struct portlist* pl, char * delim){ int printed = 0; for(; pl; pl = pl->next){ if(printed > (bufsize - 64)) break; if(pl->startport != pl->endport) printed += sprintf(buf+printed, "%hu-%hu%s", pl->startport, pl->endport, pl->next?delim:""); else { /* struct servent *se=NULL; if(pl->startport)se = getservbyport((int)ntohs(pl->startport), NULL); printed += sprintf(buf+printed, "%hu(%s)%s", pl->startport, se?se->s_name:"unknown", pl->next?delim:""); */ printed += sprintf(buf+printed, "%hu%s", pl->startport, pl->next?delim:""); } if(printed > (bufsize - 64)) { printed += sprintf(buf+printed, "..."); break; } } return printed; } static int printuserlist(char *buf, int bufsize, struct userlist* ul, char * delim){ int printed = 0; for(; ul; ul = ul->next){ if(printed > (bufsize - 64)) break; printed += sprintf(buf+printed, "%s%s", ul->user, ul->next?delim:""); if(printed > (bufsize - 64)) { printed += sprintf(buf+printed, "..."); break; } } return printed; } int printiple(char *buf, struct iplist* ipl); static int printiplist(char *buf, int bufsize, struct iplist* ipl, char * delim){ int printed = 0; for(; ipl; ipl = ipl->next){ if(printed > (bufsize - 128)) break; printed += printiple(buf+printed, ipl); if(printed > (bufsize - 128)) { printed += sprintf(buf+printed, "..."); break; } } return printed; } /* The admin pages are http operations: the service, request parsing and authorization belong to httpsrv, and what is left here is the page itself. A star in the url carries the selector the pages used to read out of the path, so /C with a star gives D2 or S2 to disable or enable a counter. */ static char * admin_open(struct printparam *pp, struct clientparam *param) { char *buf; pp->inbuf = 0; pp->cp = param; buf = malloc(LINESIZE); if(!buf) return NULL; sprintf(buf, ok, conf.stringtable?(char *)conf.stringtable[2]:"3proxy", conf.stringtable?(char *)conf.stringtable[2]:"3[APA3A] tiny proxy", conf.stringtable?(char *)conf.stringtable[3]:""); printstr(pp, buf); return buf; } static void admin_close(struct printparam *pp, char *buf) { printstr(pp, tail); printstr(pp, NULL); if(buf) free(buf); } int op_admin(struct httpreq *r, const unsigned char *params) { struct printparam pp; char *buf; buf = admin_open(&pp, r->param); if(!buf) return 1; printstr(&pp, (char *)conf.stringtable[WEBBANNERS]); admin_close(&pp, buf); return 0; } int op_admin_counters(struct httpreq *r, const unsigned char *params) { struct clientparam *param = r->param; struct printparam pp; char *buf; const char *sel; int limited; limited = param->srv->s_option; /* In limited mode a counter may be looked at but not switched. */ sel = limited? "" : r->path + r->globstart; buf = admin_open(&pp, param); if(!buf) return 1; printstr(&pp, counters); { struct trafcount *cp; int num = 0; for(cp = conf.trafcounter; cp; cp = cp->next, num++){ int inbuf = 0; if(cp->ace && (limited || param->redirected)){ if(!ACLmatches(cp->ace, param))continue; } if(sel[0] == 'S' && atoi(sel+1) == num) cp->disabled=0; if(sel[0] == 'D' && atoi(sel+1) == num) cp->disabled=1; inbuf += sprintf(buf, "%s", cp->ace?aceaction(cp->ace->action):"-"); if(cp->number || cp->comment) inbuf += sprintf(buf+inbuf, "%d/%s" , cp->number, (cp->comment)?cp->comment:" "); else inbuf += sprintf(buf+inbuf, " - "); inbuf += sprintf(buf+inbuf, "%s", (cp->disabled)?'S':'D', num, (cp->disabled)?"NO":"YES" ); if(!cp->ace || !cp->ace->users){ inbuf += sprintf(buf+inbuf, "
ANY
"); } else { inbuf += printuserlist(buf+inbuf, LINESIZE-800, cp->ace->users, ",
\r\n"); } inbuf += sprintf(buf+inbuf, ""); if(!cp->ace || !cp->ace->src){ inbuf += sprintf(buf+inbuf, "
ANY
"); } else { inbuf += printiplist(buf+inbuf, LINESIZE-512, cp->ace->src, ",
\r\n"); } inbuf += sprintf(buf+inbuf, ""); if(!cp->ace || !cp->ace->dst){ inbuf += sprintf(buf+inbuf, "
ANY
"); } else { inbuf += printiplist(buf+inbuf, LINESIZE-512, cp->ace->dst, ",
\r\n"); } inbuf += sprintf(buf+inbuf, ""); if(!cp->ace || !cp->ace->ports){ inbuf += sprintf(buf+inbuf, "
ANY
"); } else { inbuf += printportlist(buf+inbuf, LINESIZE-128, cp->ace->ports, ",
\r\n"); } if(cp->ace && (cp->ace->action == NOCOUNTIN || cp->ace->action == NOCOUNTOUT || cp->ace->action == NOCOUNTALL)) { inbuf += sprintf(buf+inbuf, "exclude from limitation\r\n" ); } else { inbuf += sprintf(buf+inbuf, "%"PRIu64"" "MB%s" "%"PRIu64".%"PRIu64"" "%s", cp->traflim64 / (1024 * 1024), rotations[cp->type], cp->traf64 / (1024 * 1024), (((cp->traf64/16) *10) / (64*1024))%10, cp->cleared?ctime(&cp->cleared):"never" ); inbuf += sprintf(buf + inbuf, "%s" "%i" "\r\n", cp->updated?ctime(&cp->updated):"never", cp->number ); } printstr(&pp, buf); } } printstr(&pp, counterstail); admin_close(&pp, buf); return 0; } int op_admin_reload(struct httpreq *r, const unsigned char *params) { struct printparam pp; char *buf; buf = admin_open(&pp, r->param); if(!buf) return 1; if(r->param->srv->s_option) printstr(&pp, (char *)conf.stringtable[WEBBANNERS]); else { conf.needreload = 1; printstr(&pp, "

Reload scheduled

"); } admin_close(&pp, buf); return 0; } int op_admin_services(struct httpreq *r, const unsigned char *params) { struct clientparam *param = r->param; struct printparam pp; char *buf; const char *sel; if(param->srv->s_option) return op_admin(r, params); sel = r->path + r->globstart; /* This page is xml, so it carries its own headers instead of the html wrapper the other pages share. */ pp.inbuf = 0; pp.cp = param; buf = NULL; if(sel[0] == 'X') printstr(&pp, style); else { printstr(&pp, xml); printstr(&pp, ""); printval(&tpool, TYPE_THREADPOOL, 0, &pp); printstr(&pp, "\r\n"); printval(conf.services, TYPE_SERVER, 0, &pp); printstr(&pp, postxml); } printstr(&pp, NULL); return 0; } #endif