func fwdRequest(conn net.Conn) { l.Log("Request: ", connStr(conn)) hcon := httpheadreader.NewHTTPHeadReader(conn) l.Log("Request: host:", hcon.Host()) if hcon.Host() == *externAddr || hcon.Host() == "www."+*externAddr { conn.Write([]byte(defaultMsg)) conn.Close() return } // if host is '.m.'+*externAddr then fwd it to a redis server // or something. p, ok := router.GetProxy(hcon.Host()) if !ok { l.Log("Request: coundn't find proxy for", hcon.Host()) conn.Write([]byte(fmt.Sprintf("Couldn't fine proxy for <%s>", hcon.Host()))) conn.Close() return } proto.SendConnRequest(p.Admin) p.Proxy.Forward(hcon) }
// https://groups.google.com/d/topic/golang-nuts/e8sUeulwD3c/discussion func isAlive(c net.Conn) (ret bool) { ret = false defer func() { if r := recover(); r != nil { l.Log("isAlive: Recovering from f", r) ret = false } }() one := make([]byte, 10) c.SetReadDeadline(time.Now().Add(10 * time.Second)) n, err := c.Read(one) // l.Log("isAlive: read %v - %v", len(one), string(one)) if err == io.EOF { l.Log("isAlive: %s detected closed LAN connection", c) c.Close() c = nil return } if n == 0 { l.Log("isAlive: read 0 bytes. Probably client out of reach") return } c.SetReadDeadline(time.Time{}) ret = true return }
func (p *ProxyClient) accept() { for { backconn, err := p.listenServer.Accept() l.Log("New connection from backend ") if err != nil { l.Log("some problem %v", err) } p.conn <- backconn } }
func (c *HTTPHeadReader) regexpHost() string { // TODO: make this generic reg, err := regexp.Compile(`(\w*\.localtunnel\.net)`) if err != nil { l.Log("H: couldn't find host") return "" } if reg.Match(c.buf[0:]) { l.Log("H: found host: ", reg.FindString(string(c.buf[0:]))) return reg.FindString(string(c.buf[0:])) } return "" }
// given a connection, figures out the subdomain and gives respective // proxy. func (r *TCPRouter) GetProxy(host string) (*Proxy, bool) { id, ok := IdForHost(host) if !ok { l.Log("Router: Couldn't find the subdomain for the request", host) return nil, false } l.Log("Router: for id: ", id, r.String()) if proxy, ok := r.proxies[id]; ok { l.Log("Router: found proxy") return proxy, true } return nil, false }
func (c *HTTPHeadReader) parseHeaders() (err error) { var buf [http.DefaultMaxHeaderBytes]byte n, err := c.conn.Read(buf[0:]) if err != nil { l.Log("H: error while reading", err) return err } l.Log("H: bytes", n) c.buf = make([]byte, n) copy(c.buf, buf[0:n]) c.req, err = http.ReadRequest(bufio.NewReader(bytes.NewReader(c.buf[0:n]))) if err != nil { l.Log("H: error while parsing header") return err } return nil }
func setupClient(eaddr, port string, adminc net.Conn) { id := proto.ReceiveSubRequest(adminc) l.Log("Client: asked for ", connStr(adminc), id) proxy := router.Register(adminc, id) requestURL, backendURL := proxy.FrontHost(eaddr, port), proxy.BackendHost(eaddr) l.Log("Client: --- sending %v %v", requestURL, backendURL) proto.SendProxyInfo(adminc, requestURL, backendURL) for { time.Sleep(2 * time.Second) if !isAlive(adminc) { router.Deregister(proxy) break } } l.Log("Client: closing backend connection") }
func (c *HTTPHeadReader) Read(b []byte) (int, error) { // read from internal buffer if c.err != nil { return 0, c.err } if len(c.buf) != 0 { n := copy(b, c.buf) c.buf = c.buf[n:] l.Log("copied: %d - remaining %d ", n, len(c.buf)) return n, nil } return c.conn.Read(b) }
func SetupClient(port, remote, subdomain string, servInfo chan string) bool { localServer := net.JoinHostPort("127.0.0.1", port) // if !ensureServer(localServer) { // return false // } req, quit, conn := make(chan bool), make(chan bool), make(chan string) // fmt.Printf("Setting Gotunnel server %s with local server on %s\n\n", remote, port) go setupCommandChannel(remote, subdomain, req, quit, conn, servInfo) remoteProxy := <-conn // l.Log("remote proxy: %v", remoteProxy) for { select { case <-req: // fmt.Printf("New link b/w %s and %s\n", remoteProxy, localServer) rp, err := net.Dial("tcp", remoteProxy) if err != nil { l.Log("Coundn't connect to remote clientproxy", err) return false } lp, err := net.Dial("tcp", localServer) if err != nil { l.Log("Couldn't connect to localserver", err) return false } go rwtunnel.NewRWTunnel(rp, lp) case <-quit: return true } } return true }
func setupHeartbeat(c net.Conn) { for { time.Sleep(1 * time.Second) c.SetWriteDeadline(time.Now().Add(3 * time.Second)) _, err := c.Write([]byte("ping")) if err != nil { l.Log("Couldn't connect to server. Check your network connection, and run client again.") os.Exit(1) } } }
func (c *HTTPHeadReader) Host() string { if c.req != nil { return c.req.Host } err := c.parseHeaders() if err != nil { l.Log("H: error", err) return c.regexpHost() } return c.req.Host }
func (r *TCPRouter) Register(ac net.Conn, suggestedId string) (proxy *Proxy) { // check if its suggestedId is already registered. proxyClient := r.setupClientCommChan(suggestedId) id := suggestedId for _, ok := r.proxies[id]; ok || id == ""; _, ok = r.proxies[id] { id = newRandString() } l.Log("Router: registering with (%s)", id) r.proxies[id] = &Proxy{Proxy: proxyClient, Admin: ac, id: id} return r.proxies[id] }
// https://groups.google.com/d/topic/golang-nuts/e8sUeulwD3c/discussion func isAlive(c net.Conn) bool { one := []byte{0} c.SetReadDeadline(time.Now()) _, err := c.Read(one) if err == io.EOF { l.Log("%s detected closed LAN connection", c) c.Close() c = nil return false } c.SetReadDeadline(time.Time{}) return true }
func IdForHost(host string) (string, bool) { h, _, err := net.SplitHostPort(host) if h == "" { // assumes host:port or host as parameter h = host } reg, err := regexp.Compile(`^([A-Za-z]*)`) if err != nil { return "", false } if reg.Match([]byte(host)) { l.Log("Router: id for host", reg.FindString(h), host) return reg.FindString(host), true } return "", false }
func copypaste(in, out io.ReadWriteCloser, close_in bool, msg string) { var buf [512]byte defer func() { if close_in { l.Log("eof closing connection") in.Close() out.Close() } }() for { n, err := in.Read(buf[0:]) // on readerror, only bail if no other choice. if err == io.EOF { l.Log("msg: ", msg) // fmt.Print(msg) // time.Sleep(1e9) l.Log("eof", msg) return } l.Log("-- read ", n) if err != nil { l.Log("something wrong while copying in ot out ", msg) l.Log("error: ", err) return } // if n < 1 { // fmt.Println("nothign to read") // return // } l.Log("-- wrote msg bytes", n) _, err = out.Write(buf[0:n]) if err != nil { l.Log("something wrong while copying out to in ") // l.Fatal("something wrong while copying out to in", err) return } } }
func main() { flag.Usage = Usage flag.Parse() if *port == "" || *backproxyAdd == "" || *externAddr == "" { flag.Usage() os.Exit(1) } // new clients go func() { backproxy, err := net.Listen("tcp", *backproxyAdd) if err != nil { l.Fatal("Client: Coundn't start server to connect clients", err) } for { adminc, err := backproxy.Accept() if err != nil { l.Fatal("Client: Problem accepting new client", err) } go setupClient(*externAddr, *port, adminc) } }() // new request server, err := net.Listen("tcp", net.JoinHostPort("0.0.0.0", *port)) if server == nil { l.Fatal("Request: cannot listen: %v", err) } l.Log("Listening at: %s", *port) for { conn, err := server.Accept() if err != nil { l.Fatal("Request: failed to accept new request: ", err) } go fwdRequest(conn) } }
// connect to server: // - send the requested subdomain to server. // - server replies back with a port to setup command channel on. // - it also replies with the server address that users can access the site on. func setupCommandChannel(addr, sub string, req, quit chan bool, conn, servInfo chan string) { backproxy, err := net.Dial("tcp", addr) if err != nil { l.Log("CMD: Couldn't connect to ", addr, "err: ", err) quit <- true return } defer backproxy.Close() proto.SendSubRequest(backproxy, sub) // the port to connect on serverat, conn_to, _ := proto.ReceiveProxyInfo(backproxy) conn <- conn_to servInfo <- serverat go setupHeartbeat(backproxy) for { req <- proto.ReceiveConnRequest(backproxy) } }
func (p *ProxyClient) Forward(c io.ReadWriteCloser) error { bc := <-p.conn l.Log("Received new connection. Fowarding.. ") rwtunnel.NewRWTunnel(c, bc) return nil }