/* This is a very simple http proxy. It barely check the header to get the destination (The GET argument). From there it does a connection to an horizon using the proxy protocol. This ends up connecting with an HTTP server somewhere on the blackhole system. The URL (in the GET) is parsed and rewritten to identify the target. */ #include #include #include #include #include #include #include #include #include using namespace std; enum CLIENT_TYPE{ TYPE_UNKNOWN, TYPE_CLIENT, TYPE_PROXY, TYPE_CONTROL, }; struct CLIENT_INFO: public ARRAY_OBJ{ CLIENT_TYPE type; int copyto; string lastreq; // Last request CLIENT_INFO(){ type = TYPE_UNKNOWN; copyto = -1; } }; static int http_proxy_getvserver (const char *line, string &vserver, string &newline) { int ret = -1; const char *pt = str_skipword (line); pt = str_skip(pt); if (*pt == '/'){ const char *start = pt+1; const char *end = start; while (isalnum(*end)) end++; if (*end == '/'){ unsigned len = end-start; vserver = string(start,len); newline = line; // We blank the vserver part, so the header stay the same length for (unsigned i=pt-line; i static int http_proxy_connect( int fd, const char *horizon, const char *horizon_port, const string &vserver) { glocal int ret = -1; glocal const char *vserver = vserver.c_str(); (horizon,horizon_port,4); sendf("connect %s 80\n",glocal.vserver); debug_printf ("Receive from horizon: %s\n",line); if (strcmp(line,"Ok")==0){ debug_printf ("OK seen\n"); glocal.ret = dup(info.handle); } end = true; return glocal.ret; } static string http_proxy_firstline( const string &s) { for (unsigned i=0; i int main (int argc, char *argv[]) { glocal const char *pidfile = "/var/run/http_proxy.pid"; glocal const char *user = "blackhole"; glocal bool daemon = false; glocal const char *tcpport = "8081"; glocal const char *accept_from = "127.0.0.1"; glocal const char *connect_to = "192.168.2.1"; glocal const char *connect_port = "9000"; glocal const char *control = "/var/run/http_proxy.sock"; glocal int ret = -1; glocal.ret = (argc,argv); setproginfo ("http_proxy",VERSION,"Http to http, using blackhole\n"); setarg ('a',"accept_from","Accept connection from this IP only",glocal.accept_from,false); setarg ('p',"tcpport","Listen on this port",glocal.tcpport,false); setarg ('c',"connectto","Connect to the horizon",glocal.connect_to,false); setarg ('P',"proxyport","Proxy port on the horizon",glocal.connect_port,false); setgrouparg ("Misc."); setarg (' ',"daemon","Daemon mode",glocal.daemon,false); setarg (' ',"pidfile","Pid file for daemon mode",glocal.pidfile,false); setarg (' ',"user","Switch to this user in daemon mode",glocal.user,false); setarg (' ',"control","Unix socket to control this program",glocal.control,false); if (glocal.daemon) syslog(LOG_ERR,"%s",msg); fprintf (stderr,"%s\n",msg); int ret = -1; (glocal.tcpport,5); CLIENT_INFO *c = new CLIENT_INFO; if (strncmp(info.port,"unix:",5)==0){ c->type = TYPE_CONTROL; }else{ c->type = TYPE_CLIENT; } info.data = c; debug_printf ("newclient %d\n",no); CLIENT_INFO *c = (CLIENT_INFO*)info.data; if (c->type == TYPE_CLIENT){ debug_printf ("end client %d %d\n",no,c->copyto); closeclient (c->copyto); }else if (c->type == TYPE_PROXY){ debug_printf ("end proxy %d %d\n",no,c->copyto); closeclient (c->copyto); } CLIENT_INFO *c = (CLIENT_INFO*)info.data; if (c->type == TYPE_CLIENT){ debug_printf ("REC client %d -> %d \n",no,c->copyto); if (strncasecmp(line,"GET ",4)==0 || strncasecmp(line,"POST ",5)==0){ string newline,vserver; if (http_proxy_getvserver (line,vserver,newline)==-1){ endclient = true; }else{ c->lastreq = http_proxy_firstline (newline); if (c->copyto == -1){ int fd = http_proxy_connect (no,glocal.connect_to,glocal.connect_port,vserver); if (fd == -1){ endclient = true; }else{ c->copyto = fd; CLIENT_INFO *n = new CLIENT_INFO; n->type = TYPE_PROXY; n->copyto = no; debug_printf ("proxy %d for client %d\n",fd,no); inject (fd,n); sendto (fd,newline.c_str(),info.linelen); } }else{ sendto (c->copyto,newline.c_str(),info.linelen); } } }else{ sendto (c->copyto,line,info.linelen); } }else if (c->type == TYPE_PROXY){ debug_printf ("REC proxy %d -> %d\n",no,c->copyto); debug_printf ("\t"); const char *pt = line; while (*pt != '\0'){ if (*pt == '\n'){ debug_printf ("\n\t"); }else{ debug_printf ("%c",*pt); } pt++; } sendto (c->copyto,line,info.linelen); }else if (c->type == TYPE_CONTROL){ if (strcmp(line,"status\n")==0){ void *data; int fd = iter_init(data); while (fd != -1){ CLIENT_INFO *n = (CLIENT_INFO*)data; sendf ("Connection %d ",fd); if (n->type == TYPE_CONTROL){ send ("control"); }else if (n->type == TYPE_CLIENT){ sendf ("client copyto %d lastreq=%s",n->copyto,n->lastreq.c_str()); }else if (n->type == TYPE_PROXY){ sendf ("proxy copyto %d",n->copyto); } send ("\n"); fd = iter_next(data); } }else{ send ("Invalid command\n"); } send ("Ok\n"); endclient = true; } if (o.is_ok()){ string tmp = string("unix:") + glocal.control; if (o.listen("",tmp.c_str())==-1){ tlmp_error ("Can't setup the control socket %s\n",glocal.control); exit (-1); } ret = 0; if (glocal.daemon) daemon_init (glocal.pidfile,glocal.user); o.setrawmode (true); o.loop(); } return ret; return glocal.ret; }