示例#1
0
文件: chained.go 项目: shizhh/lantern
// 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) {
				conn.Close()
				return nil, fmt.Errorf("Server's certificate didn't match expected!")
			}
			return conn, err
		}
	}

	ccfg := chained.Config{
		DialServer: dial,
	}
	if s.AuthToken != "" {
		ccfg.OnRequest = func(req *http.Request) {
			req.Header.Set("X-LANTERN-AUTH-TOKEN", s.AuthToken)
		}
	}
	d := chained.NewDialer(ccfg)

	// Is this a trusted proxy that we could use for HTTP traffic?
	var trusted string
	if s.Trusted {
		trusted = "(trusted) "
	}

	return &balancer.Dialer{
		Label:   fmt.Sprintf("%schained proxy at %s", trusted, s.Addr),
		Weight:  s.Weight,
		QOS:     s.QOS,
		Trusted: s.Trusted,
		Dial: func(network, addr string) (net.Conn, error) {
			return withStats(d.Dial(network, addr))
		},
	}, nil
}
示例#2
0
文件: host.go 项目: 2722/lantern
// resetProxiedClient reconfigures the host so attempts to proxy through it,
// for the sake of checking whether it's up and serving, will use the given
// port.  Valid port values are "443", in which case we'll access the proxy
// through HTTPS, or "80", for an unencrypted connection.
//
// This is necessary because when peerscanner starts up and gets the list of
// hosts from the various DNS/CDN services, it has no way to know what port
// these servers are listening at.  So we want to try both until one works, or
// until the server first registers with peerscanner, advertising which port
// it uses.
func (h *host) resetProxiedClient(port string) {

	var dial func(addr string) (net.Conn, error)
	if port == "80" {
		dial = func(addr string) (net.Conn, error) {
			dialer := net.Dialer{Timeout: dialTimeout}
			return dialer.Dial("tcp", h.ip+":80")
		}
	} else if port == "443" {
		dial = func(addr string) (net.Conn, error) {
			return tlsdialer.DialWithDialer(&net.Dialer{
				Timeout: dialTimeout,
			}, "tcp", h.ip+":443", true, &tls.Config{
				InsecureSkipVerify: true,
				// Cache TLS sessions
				ClientSessionCache: tls.NewLRUClientSessionCache(1000),
			})
		}
	} else {
		log.Errorf("Unsupported port: %v", port)
		return
	}

	h.proxiedClient = &http.Client{
		Transport: &http.Transport{
			Dial: func(network, addr string) (net.Conn, error) {
				return enproxy.Dial(addr, &enproxy.Config{
					DialProxy: dial,
					NewRequest: func(upstreamHost string, method string, body io.Reader) (req *http.Request, err error) {
						return http.NewRequest(method, "http://"+h.ip+"/", body)
					},
					OnFirstResponse: func(resp *http.Response) {
						h.reportedHostMutex.Lock()
						h.reportedHost = resp.Header.Get(enproxy.X_ENPROXY_PROXY_HOST)
						h.reportedHostMutex.Unlock()
					},
				})
			},
			DisableKeepAlives: true,
		},
		Timeout: requestTimeout,
	}
}
示例#3
0
// Dialer creates a *balancer.Dialer backed by a chained server.
func (s *ChainedServerInfo) Dialer(deviceID string) (*balancer.Dialer, error) {
	netd := &net.Dialer{Timeout: chainedDialTimeout}

	forceProxy := ForceChainedProxyAddr != ""
	addr := s.Addr
	if forceProxy {
		log.Errorf("Forcing proxying to server at %v instead of configured server at %v", ForceChainedProxyAddr, s.Addr)
		addr = ForceChainedProxyAddr
	}

	var dial func() (net.Conn, error)
	if s.Cert == "" && !forceProxy {
		log.Error("No Cert configured for chained server, will dial with plain tcp")
		dial = func() (net.Conn, error) {
			return netd.Dial("tcp", 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", addr, false, &tls.Config{
				ClientSessionCache: sessionCache,
				InsecureSkipVerify: true,
			})
			if err != nil {
				return nil, err
			}
			if !forceProxy && !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, addr)

	ccfg := chained.Config{
		DialServer: dial,
		Label:      label,
	}

	authToken := s.AuthToken
	if ForceAuthToken != "" {
		authToken = ForceAuthToken
	}

	ccfg.OnRequest = func(req *http.Request) {
		if authToken != "" {
			req.Header.Set("X-LANTERN-AUTH-TOKEN", authToken)
		}
		req.Header.Set("X-LANTERN-DEVICE-ID", deviceID)
	}
	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 conn, nil
		},
		AuthToken: authToken,
	}, nil
}