Ejemplo n.º 1
0
// 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
}
Ejemplo n.º 2
0
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}
}
Ejemplo n.º 3
0
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
}
Ejemplo n.º 4
0
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
}
Ejemplo n.º 5
0
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
	}
}
Ejemplo n.º 6
0
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
}
Ejemplo n.º 7
0
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
}
Ejemplo n.º 8
0
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
}
Ejemplo n.º 9
0
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
}
Ejemplo n.º 10
0
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
			}
		}
	}
}
Ejemplo n.º 11
0
// 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
}