// Dial creates a Conn, opens a connection to the proxy and starts processing // writes and reads on the Conn. // // addr: the host:port of the destination server that we're trying to reach // // config: configuration for this Conn func Dial(addr string, config *Config) (net.Conn, error) { c := &conn{ id: uuid.NewRandom().String(), addr: addr, config: config, } c.initDefaults() c.makeChannels() c.initRequestStrategy() // Dial proxy proxyConn, err := c.dialProxy() if err != nil { return nil, fmt.Errorf("Unable to dial proxy to %s: %s", addr, err) } go c.processWrites() go c.processReads() go c.processRequests(proxyConn) increment(&open) return idletiming.Conn(c, c.config.IdleTimeout, func() { log.Debugf("Proxy connection to %s via %s idle for %v, closing", addr, proxyConn.conn.RemoteAddr(), c.config.IdleTimeout) if err := c.Close(); err != nil { log.Debugf("Unable to close connection: %v", err) } // Close the initial proxyConn just in case if err := proxyConn.conn.Close(); err != nil { log.Debugf("Unable to close proxy connection: %v", err) } }), nil }
func New(opts *Options) filters.Filter { if opts.Rewriter == nil { opts.Rewriter = &HeaderRewriter{ TrustForwardHeader: true, Hostname: "", } } if opts.Dialer == nil { opts.Dialer = func(network, addr string) (net.Conn, error) { return net.DialTimeout(network, addr, time.Second*30) } } if opts.RoundTripper == nil { dialerFunc := func(network, addr string) (net.Conn, error) { conn, err := opts.Dialer(network, addr) if err != nil { return nil, err } idleConn := idletiming.Conn(conn, opts.IdleTimeout, nil) return idleConn, err } timeoutTransport := &http.Transport{ Dial: dialerFunc, TLSHandshakeTimeout: 10 * time.Second, IdleConnTimeout: opts.IdleTimeout, // remove idle keep-alive connections to avoid leaking memory } opts.RoundTripper = timeoutTransport } return &forwarder{opts} }
func (l *lazyConn) get() (conn net.Conn, err error) { l.mutex.Lock() defer l.mutex.Unlock() if l.err != nil { // If dial already resulted in an error, return that return nil, err } if l.connOut == nil { // Lazily dial out conn, err := l.p.Dial(l.addr) if err != nil { l.err = fmt.Errorf("Unable to dial out to %s: %s", l.addr, err) return nil, l.err } // Wrap the connection in an idle timing one l.connOut = idletiming.Conn(conn, l.p.IdleTimeout, func() { l.p.connMapMutex.Lock() defer l.p.connMapMutex.Unlock() delete(l.p.connMap, l.id) }) } return l.connOut, l.err }
func (f *httpConnectHandler) dial(network, addr string) (net.Conn, error) { conn, dialErr := f.Dialer(network, addr) if dialErr != nil { return nil, errors.New("Unable to dial %v: %v", addr, dialErr) } conn = idletiming.Conn(conn, f.IdleTimeout, nil) return conn, nil }
func timeoutDialer(cTimeout time.Duration, rwTimeout time.Duration) func(net, addr string) (net.Conn, error) { return func(netw, addr string) (net.Conn, error) { conn, err := net.DialTimeout(netw, addr, cTimeout) if err != nil { return nil, errors.Wrap(err, 1) } idleConn := idletiming.Conn(conn, rwTimeout, func() { conn.Close() }) return idleConn, nil } }
func (l *idleConnListener) Accept() (c net.Conn, err error) { conn, err := l.Listener.Accept() if err != nil { return nil, err } iConn := idletiming.Conn(conn, l.idleTimeout, nil) sac, _ := conn.(WrapConnEmbeddable) return &idleConn{ WrapConnEmbeddable: sac, Conn: iConn, }, err }
func (c *Conn) dialProxy() (*connInfo, error) { conn, err := c.Config.DialProxy(c.Addr) if err != nil { return nil, fmt.Errorf("Unable to dial proxy: %s", err) } proxyConn := &connInfo{ bufReader: bufio.NewReader(conn), } proxyConn.conn = idletiming.Conn(conn, c.Config.IdleTimeout, func() { // When the underlying connection times out, mark the connInfo closed proxyConn.closedMutex.Lock() defer proxyConn.closedMutex.Unlock() proxyConn.closed = true }) return proxyConn, nil }
func (f *HTTPConnectHandler) intercept(w http.ResponseWriter, req *http.Request) (err error) { utils.RespondOK(w, req) clientConn, _, err := w.(http.Hijacker).Hijack() if err != nil { utils.RespondBadGateway(w, req, fmt.Sprintf("Unable to hijack connection: %s", err)) return } connOutRaw, err := net.Dial("tcp", req.Host) if err != nil { return } connOut := idletiming.Conn(connOutRaw, f.idleTimeout, func() { if connOutRaw != nil { connOutRaw.Close() } }) // Pipe data through CONNECT tunnel closeConns := func() { if clientConn != nil { if err := clientConn.Close(); err != nil { log.Debugf("Error closing the out connection: %s", err) } } if connOut != nil { if err := connOut.Close(); err != nil { log.Debugf("Error closing the client connection: %s", err) } } } var closeOnce sync.Once go func() { if _, err := io.Copy(connOut, clientConn); err != nil { log.Debug(err) } closeOnce.Do(closeConns) }() if _, err := io.Copy(clientConn, connOut); err != nil { log.Debug(err) } closeOnce.Do(closeConns) return }
func New(next http.Handler, setters ...optSetter) (*Forwarder, error) { idleTimeoutPtr := new(time.Duration) dialerFunc := func(network, addr string) (conn net.Conn, err error) { conn, err = net.DialTimeout(network, addr, time.Second*30) if err != nil { return } idleConn := idletiming.Conn(conn, *idleTimeoutPtr, func() { if conn != nil { conn.Close() } }) return idleConn, err } var timeoutTransport http.RoundTripper = &http.Transport{ Dial: dialerFunc, TLSHandshakeTimeout: 10 * time.Second, } f := &Forwarder{ errHandler: utils.DefaultHandler, roundTripper: timeoutTransport, next: next, idleTimeout: 30 * time.Second, } for _, s := range setters { if err := s(f); err != nil { return nil, err } } // Make sure we update the timeout that dialer is going to use *idleTimeoutPtr = f.idleTimeout if f.rewriter == nil { f.rewriter = &HeaderRewriter{ TrustForwardHeader: true, Hostname: "", } } return f, nil }
func (d *direct) dialWith(in chan *Masquerade, network, addr string) (net.Conn, bool, error) { retryLater := make([]*Masquerade, 0) defer func() { for _, m := range retryLater { in <- m } }() for { var m *Masquerade select { case m = <-in: log.Trace("Got vetted masquerade") default: log.Trace("No vetted masquerade found, falling back to unvetted candidate") select { case m = <-d.candidates: log.Trace("Got unvetted masquerade") default: return nil, false, errors.New("Could not dial any masquerade?") } } log.Debugf("Dialing to %v", m) // We do the full TLS connection here because in practice the domains at a given IP // address can change frequently on CDNs, so the certificate may not match what // we expect. if conn, err := d.dialServerWith(m); err != nil { log.Debugf("Could not dial to %v, %v", m.IpAddress, err) // Don't re-add this candidate if it's any certificate error, as that // will just keep failing and will waste connections. We can't access the underlying // error at this point so just look for "certificate" and "handshake". if strings.Contains(err.Error(), "certificate") || strings.Contains(err.Error(), "handshake") { log.Debugf("Not re-adding candidate that failed on error '%v'", err.Error()) } else { log.Debugf("Unexpected error dialing, keeping masquerade: %v", err) retryLater = append(retryLater, m) } } else { log.Debugf("Got successful connection to: %v", m) if err := d.headCheck(m); err != nil { log.Debugf("Could not perform successful head request: %v", err) } else { // Requeue the working connection to masquerades d.masquerades <- m idleTimeout := 70 * time.Second log.Debug("Wrapping connecting in idletiming connection") conn = idletiming.Conn(conn, idleTimeout, func() { log.Debugf("Connection to %s via %s idle for %v, closing", addr, conn.RemoteAddr(), idleTimeout) if err := conn.Close(); err != nil { log.Debugf("Unable to close connection: %v", err) } }) log.Debug("Returning connection") return conn, true, nil } } } }
// Dialer creates a *balancer.Dialer backed by a chained server. func (s *ChainedServerInfo) Dialer() (*balancer.Dialer, error) { netd := &net.Dialer{Timeout: chainedDialTimeout} var dial func() (net.Conn, error) if s.Cert == "" { log.Error("No Cert configured for chained server, will dial with plain tcp") dial = func() (net.Conn, error) { return netd.Dial("tcp", s.Addr) } } else { log.Trace("Cert configured for chained server, will dial with tls over tcp") cert, err := keyman.LoadCertificateFromPEMBytes([]byte(s.Cert)) if err != nil { return nil, fmt.Errorf("Unable to parse certificate: %s", err) } x509cert := cert.X509() sessionCache := tls.NewLRUClientSessionCache(1000) dial = func() (net.Conn, error) { conn, err := tlsdialer.DialWithDialer(netd, "tcp", s.Addr, false, &tls.Config{ ClientSessionCache: sessionCache, InsecureSkipVerify: true, }) if err != nil { return nil, err } if !conn.ConnectionState().PeerCertificates[0].Equal(x509cert) { if err := conn.Close(); err != nil { log.Debugf("Error closing chained server connection: %s", err) } return nil, fmt.Errorf("Server's certificate didn't match expected!") } return conn, err } } // Is this a trusted proxy that we could use for HTTP traffic? var trusted string if s.Trusted { trusted = "(trusted) " } label := fmt.Sprintf("%schained proxy at %s", trusted, s.Addr) ccfg := chained.Config{ DialServer: dial, Label: label, } if s.AuthToken != "" { ccfg.OnRequest = func(req *http.Request) { req.Header.Set("X-LANTERN-AUTH-TOKEN", s.AuthToken) } } d := chained.NewDialer(ccfg) return &balancer.Dialer{ Label: label, Weight: s.Weight, QOS: s.QOS, Trusted: s.Trusted, Dial: func(network, addr string) (net.Conn, error) { conn, err := d.Dial(network, addr) if err != nil { return conn, err } conn = idletiming.Conn(conn, idleTimeout, func() { log.Debugf("Proxy connection to %s via %s idle for %v, closing", addr, conn.RemoteAddr(), idleTimeout) if err := conn.Close(); err != nil { log.Debugf("Unable to close connection: %v", err) } }) return withStats(conn, err) }, }, nil }