ba720b1999-11-12Francesco Chemolli inherit "module"; inherit "socket";
257c8d2000-07-21Honza Petrous #include <module.h>
ba720b1999-11-12Francesco Chemolli  /*
1f5d642009-05-26Martin Stjernholm  * This software is (C) 1998 Francesco Chemolli. * See COPYING in the server directory for license information.
ba720b1999-11-12Francesco Chemolli  * This software comes with NO WARRANTY of ANY KIND, EITHER IMPLICIT * OR EXPLICIT. Use at your own risk. * * This is a TCP port forwarding module for the Roxen webserver. * Using it is very simple, just add it to your virtual server of choice. */ //#define TCPFORWARDER_DEBUG /* * Define this to enable debugging. It will also be turned on if DEBUGLVL is * >= 22 (the same as http proxy) */ /* * Notice that Connection is not a class proper, as the module accesses its * variables directly. But it's not worth the effort for such a simple * thing... */
0917d32013-03-04Anders Johansson constant cvs_version="$Id$";
8591b92000-11-02Per Hedbor  constant module_type = MODULE_ZERO;
6c0a9f2002-03-05Honza Petrous constant module_name = "TCP Port Forwarder: ";
8591b92000-11-02Per Hedbor constant module_doc = "A basic port-forwarder" "&copy; 1998 Francesco Chemolli "
1f5d642009-05-26Martin Stjernholm  "&lt;;,<br />\n" "See COPYING in the server directory for license information.";
896d4a2001-10-29Honza Petrous constant module_unique = 0;
8591b92000-11-02Per Hedbor  multiset(Connection) connections=(<>); int total_connections_number=0, total_transferred_kb=0;
ba720b1999-11-12Francesco Chemolli  #if DEBUG > 22 #define TCPFORWARDER_DEBUG #endif #ifdef TCPFORWARDER_DEBUG
da7a8c2003-04-01Anders Johansson #define debug_perror report_debug
ba720b1999-11-12Francesco Chemolli #else
28ebd52000-02-06Francesco Chemolli #define debug_perror
ba720b1999-11-12Francesco Chemolli #endif #define THROW(X) throw( ({X,backtrace()}) )
8591b92000-11-02Per Hedbor Stdio.Port accept_port; constant no_delayed_load = 1;
ba720b1999-11-12Francesco Chemolli  /* * A bidirectional pipe over HTTP. */ class Connection {
8591b92000-11-02Per Hedbor  array(object) fdescs; mapping buffer; object mastermodule, master_id; int traffic=0; object otherfd (object fd) { if (fd==fdescs[0]) return fdescs[1]; else return fdescs[0]; } void send(object to_fd, string data) { int sent=0; debug_perror("Connection::send("+data+")\n"); if(!strlen(buffer[to_fd])) buffer[to_fd] = data[(sent=to_fd->write(data))..]; else buffer[to_fd] += data; traffic += sent; } void got_data(object f, string data) {
28ebd52000-02-06Francesco Chemolli  debug_perror ("Got data from "+(f?f->query_address():"unknown")+": "+data+"\n");
8591b92000-11-02Per Hedbor  send(otherfd(f),data); }
ba720b1999-11-12Francesco Chemolli 
8591b92000-11-02Per Hedbor  void client_closed() { debug_perror("Connection: Client closed connection.\n"); destruct(this_object()); }
ba720b1999-11-12Francesco Chemolli 
8591b92000-11-02Per Hedbor  void write_more(object f) {
28ebd52000-02-06Francesco Chemolli  debug_perror("Write_more..\n");
8591b92000-11-02Per Hedbor  if(strlen(buffer[f])) { int written = otherfd(f)->write(buffer[f]); traffic += written; debug_perror((string)written); if(written == 0) client_closed(); else buffer[f] = (buffer[f])[written..]; }
28ebd52000-02-06Francesco Chemolli  debug_perror("\n");
8591b92000-11-02Per Hedbor  }
ba720b1999-11-12Francesco Chemolli  //s=source filedes, d=dest filedes, m=the instantiating object
8591b92000-11-02Per Hedbor  void create(object s, object d, object m) { fdescs=({s,d}); buffer=([s:"",d:""]); s->set_nonblocking(lambda( mixed a, string d ) { got_data( s, d ); }, lambda(){ write_more(s); }, client_closed ); d->set_nonblocking(lambda( mixed a, string b ) { got_data( d, b ); }, lambda(){ write_more(d); }, client_closed ); mastermodule=m; debug_perror("Got connection from "+s->query_address()+ " to " + d->query_address()+"\n"); } void destroy() { debug_perror("Destroying connection\n"); fdescs[0]->close(); fdescs[1]->close(); mastermodule->connections-=(<this_object()>); mastermodule->total_transferred_kb+=(traffic/1024); }
ba720b1999-11-12Francesco Chemolli }; string status() {
8591b92000-11-02Per Hedbor  object req; string retval;
da7a8c2003-04-01Anders Johansson  if (!accept_port) { retval="<B>No port open</B><br>"; } else if (!sizeof(connections)) {
8591b92000-11-02Per Hedbor  retval="<B>No connections</B><br>"; } else { retval="<B>"+sizeof(connections)+" connections</B><BR>\n";
da7a8c2003-04-01Anders Johansson  retval += "<TABLE border=1 cellpadding=\"10\"><TR><TH align=center>From</TH><TH>To</TH><TH>Traffic</TH></TR>";
8591b92000-11-02Per Hedbor  foreach(indices(connections),req) {
da7a8c2003-04-01Anders Johansson  retval+=sprintf("<TR><TD>%s</TD><TD>%s</TD><TD>%d</TD></TR>",
8591b92000-11-02Per Hedbor  req->fdescs[0]->query_address(), req->fdescs[1]->query_address(), req->traffic ); } retval += "</TABLE>"; } retval +="I've managed "+total_connections_number+" connections, " "transferring about "+total_transferred_kb+" Kb."; return retval;
ba720b1999-11-12Francesco Chemolli } void create() { defvar("port", 4711, "Port", TYPE_INT, "The port to wait for connections on."); defvar("host", "localhost", "Remote Host", TYPE_STRING, "The hostname to forward connections to."); defvar("r_port", 4711, "Remote Port", TYPE_INT, "The port on the remote host to connect to."); }
8591b92000-11-02Per Hedbor void start() { object privs; int port;
28ebd52000-02-06Francesco Chemolli 
8591b92000-11-02Per Hedbor  port=query("port");
ba720b1999-11-12Francesco Chemolli  if (accept_port) //I wonder why (at least on my setup) stop isn't called.. stop();
28ebd52000-02-06Francesco Chemolli  debug_perror("Opening port "+port+"\n");
ba720b1999-11-12Francesco Chemolli  accept_port=Stdio.Port(); if (!accept_port) THROW("Can't create a port to listen on");
8591b92000-11-02Per Hedbor  if (port<1024) privs=Privs("Opening forwarded port");
28ebd52000-02-06Francesco Chemolli  if (!(accept_port->bind(port,got_connection)))
da7a8c2003-04-01Anders Johansson  { int err_no = accept_port->errno(); string err = strerror(accept_port->errno()); destruct(accept_port); accept_port = 0; report_error("Can't bind (errno="+err_no+": \""+err+"\")\n");; }
8591b92000-11-02Per Hedbor  privs=0;
ba720b1999-11-12Francesco Chemolli }
8591b92000-11-02Per Hedbor void stop() {
28ebd52000-02-06Francesco Chemolli  debug_perror("Stopping module\n");
da7a8c2003-04-01Anders Johansson  if (accept_port) destruct(accept_port);
ba720b1999-11-12Francesco Chemolli  accept_port=0; //double-check there's no more references foreach(indices(connections),object foo) destruct(foo); } void got_connection (mixed port) { object in;
8591b92000-11-02Per Hedbor  in=accept_port->accept();
ba720b1999-11-12Francesco Chemolli  if (!in) THROW("Couldn't accept connection");
8591b92000-11-02Per Hedbor  total_connections_number++;
e9f4092000-07-03Martin Nilsson  async_connect(query("host"),query("r_port"),connected,in);
ba720b1999-11-12Francesco Chemolli }
8591b92000-11-02Per Hedbor void connected (object out, object in) { if( out ) connections[ Connection(in,out,this_object()) ] = 1; else report_debug("Cannot connect to "+query("host")+":"+query("r_port") );
ba720b1999-11-12Francesco Chemolli }
6c0a9f2002-03-05Honza Petrous  string query_name() { return sprintf("%d to %s/%d", query("port"), query("host"), query("r_port")); }