Example #1
0
func NewHTTPClient(conf *ProxyChannelConfig) (*http.Client, error) {
	localDial := func(network, addr string) (net.Conn, error) {
		host, port, _ := net.SplitHostPort(addr)
		if port == "443" && len(conf.SNIProxy) > 0 && hosts.InHosts(conf.SNIProxy) {
			addr = hosts.GetAddr(conf.SNIProxy, "443")
			host, _, _ = net.SplitHostPort(addr)
		}
		if net.ParseIP(host) == nil {
			iphost, err := DnsGetDoaminIP(host)
			if nil != err {
				return nil, err
			}
			addr = net.JoinHostPort(iphost, port)
		}
		dailTimeout := conf.DialTimeout
		if 0 == dailTimeout {
			dailTimeout = 5
		}
		log.Printf("[Proxy]Connect %s", addr)
		return netx.DialTimeout(network, addr, time.Duration(dailTimeout)*time.Second)
	}
	readTimeout := conf.ReadTimeout
	if 0 == readTimeout {
		readTimeout = 30
	}
	tr := &http.Transport{
		Dial:                  localDial,
		DisableCompression:    true,
		MaxIdleConnsPerHost:   2 * int(conf.ConnsPerServer),
		ResponseHeaderTimeout: time.Duration(readTimeout) * time.Second,
	}
	if len(conf.SNI) > 0 {
		tlscfg := &tls.Config{}
		tlscfg.InsecureSkipVerify = true
		tlscfg.ServerName = conf.SNI[0]
		tr.TLSClientConfig = tlscfg
	}
	if len(conf.Proxy) > 0 {
		proxyUrl, err := url.Parse(conf.Proxy)
		if nil != err {
			log.Printf("[ERROR]Invalid proxy url:%s to create http client.", conf.Proxy)
			return nil, err
		}
		tr.Proxy = http.ProxyURL(proxyUrl)
	}
	hc := &http.Client{}
	hc.Timeout = tr.ResponseHeaderTimeout
	hc.Transport = tr
	return hc, nil
}
Example #2
0
func (tc *tcpChannel) Open() error {
	dailTimeout := tc.conf.DialTimeout
	if 0 == dailTimeout {
		dailTimeout = 5
	}
	var tlscfg *tls.Config
	hostport := tc.rurl.Host
	vpsHost, vpsPort, _ := net.SplitHostPort(hostport)
	if strings.EqualFold(tc.rurl.Scheme, "tls") {
		tlscfg = &tls.Config{}
		tlscfg.ServerName = vpsHost
		if len(tc.conf.SNIProxy) > 0 && vpsPort == "443" && hosts.InHosts(tc.conf.SNIProxy) {
			hostport = hosts.GetAddr(tc.conf.SNIProxy, "443")
			vpsHost, _, _ = net.SplitHostPort(hostport)
			tc.useSNIProxy = true
			log.Printf("VPS channel select SNIProxy %s to connect", hostport)
		}
	}

	if net.ParseIP(vpsHost) == nil {
		iphost, err := proxy.DnsGetDoaminIP(vpsHost)
		if nil != err {
			return err
		}
		hostport = net.JoinHostPort(iphost, vpsPort)
	}
	//log.Printf("######%s %s", vpsHost, tc.hostport)
	timeout := time.Duration(dailTimeout) * time.Second
	var c net.Conn
	var err error
	if len(tc.conf.Proxy) > 0 {
		c, err = helper.HTTPProxyDial(tc.conf.Proxy, hostport, timeout)
	} else {
		c, err = netx.DialTimeout("tcp", hostport, timeout)
	}
	if nil != tlscfg && nil == err {
		c = tls.Client(c, tlscfg)
	}
	if err != nil {
		if tc.rurl.String() != tc.originAddr {
			tc.rurl, _ = url.Parse(tc.originAddr)
			tc.proxyChannel.Addr = tc.rurl.String()
		}
		log.Printf("###Failed to connect %s with err:%v", hostport, err)
		return err
	}
	tc.conn = c
	return nil
}
Example #3
0
func Socks5ProxyDial(proxyURL string, addr string, timeout time.Duration) (net.Conn, error) {
	u, err := url.Parse(proxyURL)
	if nil != err {
		return nil, err
	}
	c, err := netx.DialTimeout("tcp", u.Host, timeout)
	if err != nil {
		return nil, err
	}
	err = Socks5ProxyConnect(u, c, addr)
	if nil != err {
		c.Close()
		return nil, err
	}
	return c, nil
}
Example #4
0
func dnsQuery(r *dns.Msg) (*dns.Msg, error) {
	dnsServers := GConf.LocalDNS.TrustedDNS
	var record *dnsCacheRecord
	var domain string
	useTrustedDNS := true
	if len(r.Question) == 1 && dns.IsFqdn(r.Question[0].Name) {
		domain = r.Question[0].Name
		domain = domain[0 : len(domain)-1]
		if nil != dnsCache {
			item, exist := dnsCache.Get(domain)
			if exist {
				record = item.(*dnsCacheRecord)
				if time.Now().After(record.expireAt) {
					record = nil
					dnsCache.Remove(domain)
				} else {
					if r.Question[0].Qtype == dns.TypeA && nil != record.ipv4Res {
						return record.ipv4Res, nil
					} else if r.Question[0].Qtype == dns.TypeAAAA && nil != record.ipv6Res {
						return record.ipv6Res, nil
					}
				}
			}
		}
		if nil != mygfwlist {
			connReq, _ := http.NewRequest("CONNECT", "https://"+domain, nil)
			isBlocked, _ := mygfwlist.FastMatchDoamin(connReq)
			if !isBlocked {
				dnsServers = GConf.LocalDNS.FastDNS
				useTrustedDNS = false
			}
		}
	} else {
		log.Printf("###DNS with %v", r.Question)
	}
	if len(dnsServers) == 0 {
		dnsServers = GConf.LocalDNS.TrustedDNS
		useTrustedDNS = true
	}
	if len(dnsServers) == 0 {
		log.Printf("At least one DNS server need to be configured in 'FastDNS/TrustedDNS'")
		return nil, errNoDNServer
	}
	server := selectDNSServer(dnsServers)
	network := "udp"
	if GConf.LocalDNS.TCPConnect && useTrustedDNS {
		network = "tcp"
	}
	log.Printf("DNS query %s to %s", domain, server)
	for retry := 0; retry < 3; retry++ {
		c, err := netx.DialTimeout(network, server, 1*time.Second)
		if nil != err {
			return nil, err
		}
		dnsConn := new(dns.Conn)
		if pc, ok := c.(getConnIntf); ok {
			c = pc.GetConn()
		}
		dnsConn.Conn = c
		dnsConn.WriteMsg(r)
		dnsConn.SetReadDeadline(time.Now().Add(1 * time.Second))
		res, err1 := dnsConn.ReadMsg()
		if nil == err1 && nil != dnsCache && len(domain) > 0 {
			record = newDNSCacheRecord(record, res)
			dnsCache.Add(domain, record)
		}
		c.Close()
		if nil == err1 {
			return res, nil
		}
	}
	return nil, errDNSQuryFail
}
Example #5
0
func newDirectChannel(ev event.Event, conf *proxy.ProxyChannelConfig) (*directChannel, error) {
	host := ""
	port := ""
	network := "tcp"
	needHttpsConnect := false
	switch ev.(type) {
	case *event.UDPEvent:
		network = "udp"
		host = ev.(*event.UDPEvent).Addr
	case *event.TCPOpenEvent:
		host = ev.(*event.TCPOpenEvent).Addr
		needHttpsConnect = true
	case *event.HTTPRequestEvent:
		req := ev.(*event.HTTPRequestEvent)
		host = req.Headers.Get("Host")
		needHttpsConnect = strings.EqualFold(req.Method, "Connect")
	default:
		return nil, fmt.Errorf("Can NOT create direct channel by event:%T", ev)
	}
	//log.Printf("Session:%d enter direct with host %s & event:%T", ev.GetId(), host, ev)
	if len(host) == 0 {
		return nil, fmt.Errorf("Empty remote addr in event")
	}
	if strings.Contains(host, ":") {
		host, port, _ = net.SplitHostPort(host)
	} else {
		if needHttpsConnect {
			port = "443"
		} else {
			port = "80"
		}
	}

	if len(conf.SNIProxy) > 0 && port == "443" && network == "tcp" && hosts.InHosts(conf.SNIProxy) {
		host = conf.SNIProxy
	}
	isIP := net.ParseIP(host) != nil
	useTLS := false
	if conf.ForceTLS && port == "80" && hosts.InHosts(host) {
		useTLS = true
	} else {
		useTLS = false
	}
	if !isIP {
		host = hosts.GetHost(host)
	}

	//log.Printf("Session:%d get host:%s", ev.GetId(), host)
	addr := ""
	if nil == conf.ProxyURL() {
		if useTLS {
			addr = host + ":443"
		} else {
			if len(port) > 0 {
				addr = host + ":" + port
			} else {
				if needHttpsConnect {
					addr = host + ":443"
				} else {
					addr = host + ":80"
				}
			}
		}
	} else {
		addr = conf.ProxyURL().Host
	}
	connectHost, connectPort, _ := net.SplitHostPort(addr)
	if net.ParseIP(connectHost) == nil {
		iphost, err := proxy.DnsGetDoaminIP(connectHost)
		if nil != err {
			return nil, err
		}
		addr = net.JoinHostPort(iphost, connectPort)
	}
	dailTimeout := conf.DialTimeout
	if 0 == dailTimeout {
		dailTimeout = 5
	}
	//log.Printf("Session:%d connect %s:%s for %s %T %v %v %s", ev.GetId(), network, addr, host, ev, needHttpsConnect, conf.ProxyURL(), net.JoinHostPort(host, port))
	c, err := netx.DialTimeout(network, addr, time.Duration(dailTimeout)*time.Second)
	if nil != conf.ProxyURL() && nil == err {
		if strings.HasPrefix(conf.ProxyURL().Scheme, "socks") {
			err = helper.Socks5ProxyConnect(conf.ProxyURL(), c, net.JoinHostPort(host, port))
		} else {
			if needHttpsConnect {
				err = helper.HTTPProxyConnect(conf.ProxyURL(), c, "https://"+net.JoinHostPort(host, port))
			}
		}
	}
	if nil != err {
		log.Printf("Failed to connect %s for %s with error:%v", addr, host, err)
		return nil, err
	}
	d := &directChannel{ev.GetId(), c, needHttpsConnect, network == "udp", conf, addr}
	//d := &directChannel{ev.GetId(), c, fromHttpsConnect, network == "udp", toReplaceSNI, false, nil}
	if useTLS {
		tlcfg := &tls.Config{}
		tlcfg.InsecureSkipVerify = true
		sniLen := len(conf.SNI)
		if sniLen > 0 {
			tlcfg.ServerName = conf.SNI[rand.Intn(sniLen)]
		}
		tlsconn := tls.Client(c, tlcfg)
		err = tlsconn.Handshake()
		if nil != err {
			log.Printf("Failed to handshake with %s", addr)
		}
		d.conn = tlsconn
	}
	go d.read()
	return d, nil
}