github.com/AntonOrnatskyi/goproxy@v0.0.0-20190205095733-4526a9fa18b4/services/http/http.go (about)

     1  package http
     2  
     3  import (
     4  	"crypto/tls"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	logger "log"
     9  	"net"
    10  	"runtime/debug"
    11  	"strconv"
    12  	"strings"
    13  	"time"
    14  
    15  	server "github.com/AntonOrnatskyi/goproxy/core/cs/server"
    16  	"github.com/AntonOrnatskyi/goproxy/core/lib/kcpcfg"
    17  	"github.com/AntonOrnatskyi/goproxy/services"
    18  	"github.com/AntonOrnatskyi/goproxy/utils/datasize"
    19  	"github.com/AntonOrnatskyi/goproxy/utils/dnsx"
    20  	"github.com/AntonOrnatskyi/goproxy/utils/iolimiter"
    21  	"github.com/AntonOrnatskyi/goproxy/utils/jumper"
    22  	"github.com/AntonOrnatskyi/goproxy/utils/lb"
    23  	"github.com/AntonOrnatskyi/goproxy/utils/mapx"
    24  
    25  	"github.com/AntonOrnatskyi/goproxy/utils"
    26  	"github.com/AntonOrnatskyi/goproxy/utils/conncrypt"
    27  
    28  	"golang.org/x/crypto/ssh"
    29  )
    30  
    31  type HTTPArgs struct {
    32  	Parent                *[]string
    33  	CertFile              *string
    34  	KeyFile               *string
    35  	CaCertFile            *string
    36  	CaCertBytes           []byte
    37  	CertBytes             []byte
    38  	KeyBytes              []byte
    39  	Local                 *string
    40  	Always                *bool
    41  	HTTPTimeout           *int
    42  	Interval              *int
    43  	Blocked               *string
    44  	Direct                *string
    45  	AuthFile              *string
    46  	Auth                  *[]string
    47  	AuthURL               *string
    48  	AuthURLOkCode         *int
    49  	AuthURLTimeout        *int
    50  	AuthURLRetry          *int
    51  	ParentType            *string
    52  	LocalType             *string
    53  	Timeout               *int
    54  	CheckParentInterval   *int
    55  	SSHKeyFile            *string
    56  	SSHKeyFileSalt        *string
    57  	SSHPassword           *string
    58  	SSHUser               *string
    59  	SSHKeyBytes           []byte
    60  	SSHAuthMethod         ssh.AuthMethod
    61  	KCP                   kcpcfg.KCPConfigArgs
    62  	LocalIPS              *[]string
    63  	DNSAddress            *string
    64  	DNSTTL                *int
    65  	LocalKey              *string
    66  	ParentKey             *string
    67  	LocalCompress         *bool
    68  	ParentCompress        *bool
    69  	Intelligent           *string
    70  	LoadBalanceMethod     *string
    71  	LoadBalanceTimeout    *int
    72  	LoadBalanceRetryTime  *int
    73  	LoadBalanceHashTarget *bool
    74  	LoadBalanceOnlyHA     *bool
    75  
    76  	RateLimit      *string
    77  	RateLimitBytes float64
    78  	BindListen     *bool
    79  	Debug          *bool
    80  	Jumper         *string
    81  }
    82  type HTTP struct {
    83  	cfg            HTTPArgs
    84  	checker        utils.Checker
    85  	basicAuth      utils.BasicAuth
    86  	sshClient      *ssh.Client
    87  	lockChn        chan bool
    88  	domainResolver dnsx.DomainResolver
    89  	isStop         bool
    90  	serverChannels []*server.ServerChannel
    91  	userConns      mapx.ConcurrentMap
    92  	log            *logger.Logger
    93  	lb             *lb.Group
    94  	jumper         *jumper.Jumper
    95  }
    96  
    97  func NewHTTP() services.Service {
    98  	return &HTTP{
    99  		cfg:            HTTPArgs{},
   100  		checker:        utils.Checker{},
   101  		basicAuth:      utils.BasicAuth{},
   102  		lockChn:        make(chan bool, 1),
   103  		isStop:         false,
   104  		serverChannels: []*server.ServerChannel{},
   105  		userConns:      mapx.NewConcurrentMap(),
   106  	}
   107  }
   108  func (s *HTTP) CheckArgs() (err error) {
   109  
   110  	if len(*s.cfg.Parent) == 1 && (*s.cfg.Parent)[0] == "" {
   111  		(*s.cfg.Parent) = []string{}
   112  	}
   113  	if len(*s.cfg.Parent) > 0 && *s.cfg.ParentType == "" {
   114  		err = fmt.Errorf("parent type unkown,use -T <tls|tcp|ssh|kcp>")
   115  		return
   116  	}
   117  	if *s.cfg.ParentType == "tls" || *s.cfg.LocalType == "tls" {
   118  		s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
   119  		if err != nil {
   120  			return
   121  		}
   122  		if *s.cfg.CaCertFile != "" {
   123  			s.cfg.CaCertBytes, err = ioutil.ReadFile(*s.cfg.CaCertFile)
   124  			if err != nil {
   125  				err = fmt.Errorf("read ca file error,ERR:%s", err)
   126  				return
   127  			}
   128  		}
   129  	}
   130  	if *s.cfg.ParentType == "ssh" {
   131  		if *s.cfg.SSHUser == "" {
   132  			err = fmt.Errorf("ssh user required")
   133  			return
   134  		}
   135  		if *s.cfg.SSHKeyFile == "" && *s.cfg.SSHPassword == "" {
   136  			err = fmt.Errorf("ssh password or key required")
   137  			return
   138  		}
   139  
   140  		if *s.cfg.SSHPassword != "" {
   141  			s.cfg.SSHAuthMethod = ssh.Password(*s.cfg.SSHPassword)
   142  		} else {
   143  			var SSHSigner ssh.Signer
   144  			s.cfg.SSHKeyBytes, err = ioutil.ReadFile(*s.cfg.SSHKeyFile)
   145  			if err != nil {
   146  				err = fmt.Errorf("read key file ERR: %s", err)
   147  				return
   148  			}
   149  			if *s.cfg.SSHKeyFileSalt != "" {
   150  				SSHSigner, err = ssh.ParsePrivateKeyWithPassphrase(s.cfg.SSHKeyBytes, []byte(*s.cfg.SSHKeyFileSalt))
   151  			} else {
   152  				SSHSigner, err = ssh.ParsePrivateKey(s.cfg.SSHKeyBytes)
   153  			}
   154  			if err != nil {
   155  				err = fmt.Errorf("parse ssh private key fail,ERR: %s", err)
   156  				return
   157  			}
   158  			s.cfg.SSHAuthMethod = ssh.PublicKeys(SSHSigner)
   159  		}
   160  	}
   161  	if *s.cfg.RateLimit != "0" && *s.cfg.RateLimit != "" {
   162  		var size uint64
   163  		size, err = datasize.Parse(*s.cfg.RateLimit)
   164  		if err != nil {
   165  			err = fmt.Errorf("parse rate limit size error,ERR:%s", err)
   166  			return
   167  		}
   168  		s.cfg.RateLimitBytes = float64(size)
   169  	}
   170  	if *s.cfg.Jumper != "" {
   171  		if *s.cfg.ParentType != "tls" && *s.cfg.ParentType != "tcp" {
   172  			err = fmt.Errorf("jumper only worked of -T is tls or tcp")
   173  			return
   174  		}
   175  		var j jumper.Jumper
   176  		j, err = jumper.New(*s.cfg.Jumper, time.Millisecond*time.Duration(*s.cfg.Timeout))
   177  		if err != nil {
   178  			err = fmt.Errorf("parse jumper fail, err %s", err)
   179  			return
   180  		}
   181  		s.jumper = &j
   182  	}
   183  	return
   184  }
   185  func (s *HTTP) InitService() (err error) {
   186  	s.InitBasicAuth()
   187  	//init lb
   188  	if len(*s.cfg.Parent) > 0 {
   189  		s.checker = utils.NewChecker(*s.cfg.HTTPTimeout, int64(*s.cfg.Interval), *s.cfg.Blocked, *s.cfg.Direct, s.log, *s.cfg.Intelligent)
   190  		s.InitLB()
   191  	}
   192  	if *s.cfg.DNSAddress != "" {
   193  		s.domainResolver = dnsx.NewDomainResolver(*s.cfg.DNSAddress, *s.cfg.DNSTTL, s.log)
   194  	}
   195  	if *s.cfg.ParentType == "ssh" {
   196  		err = s.ConnectSSH()
   197  		if err != nil {
   198  			err = fmt.Errorf("init service fail, ERR: %s", err)
   199  			return
   200  		}
   201  		go func() {
   202  			defer func() {
   203  				if e := recover(); e != nil {
   204  					fmt.Printf("crashed, err: %s\nstack:%s", e, string(debug.Stack()))
   205  				}
   206  			}()
   207  			//循环检查ssh网络连通性
   208  			for {
   209  				if s.isStop {
   210  					return
   211  				}
   212  				conn, err := utils.ConnectHost(s.Resolve(s.lb.Select("", *s.cfg.LoadBalanceOnlyHA)), *s.cfg.Timeout*2)
   213  				if err == nil && conn != nil {
   214  					conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
   215  					_, err = conn.Write([]byte{0})
   216  					conn.SetDeadline(time.Time{})
   217  				}
   218  				if err != nil {
   219  					if s.sshClient != nil {
   220  						s.sshClient.Close()
   221  						if s.sshClient.Conn != nil {
   222  							s.sshClient.Conn.Close()
   223  						}
   224  					}
   225  					s.log.Printf("ssh offline, retrying...")
   226  					s.ConnectSSH()
   227  				} else {
   228  					conn.Close()
   229  				}
   230  				time.Sleep(time.Second * 3)
   231  			}
   232  		}()
   233  	}
   234  	return
   235  }
   236  func (s *HTTP) StopService() {
   237  	defer func() {
   238  		e := recover()
   239  		if e != nil {
   240  			s.log.Printf("stop http(s) service crashed,%s", e)
   241  		} else {
   242  			s.log.Printf("service http(s) stopped")
   243  		}
   244  		s.basicAuth = utils.BasicAuth{}
   245  		s.cfg = HTTPArgs{}
   246  		s.checker = utils.Checker{}
   247  		s.domainResolver = dnsx.DomainResolver{}
   248  		s.lb = nil
   249  		s.lockChn = nil
   250  		s.log = nil
   251  		s.jumper = nil
   252  		s.serverChannels = nil
   253  		s.sshClient = nil
   254  		s.userConns = nil
   255  		s = nil
   256  	}()
   257  	s.isStop = true
   258  	if len(*s.cfg.Parent) > 0 {
   259  		s.checker.Stop()
   260  	}
   261  	if s.sshClient != nil {
   262  		s.sshClient.Close()
   263  	}
   264  	for _, sc := range s.serverChannels {
   265  		if sc.Listener != nil && *sc.Listener != nil {
   266  			(*sc.Listener).Close()
   267  		}
   268  		if sc.UDPListener != nil {
   269  			(*sc.UDPListener).Close()
   270  		}
   271  	}
   272  	if s.lb != nil {
   273  		s.lb.Stop()
   274  	}
   275  }
   276  func (s *HTTP) Start(args interface{}, log *logger.Logger) (err error) {
   277  	s.log = log
   278  	s.cfg = args.(HTTPArgs)
   279  	if err = s.CheckArgs(); err != nil {
   280  		return
   281  	}
   282  
   283  	if err = s.InitService(); err != nil {
   284  		return
   285  	}
   286  
   287  	if len(*s.cfg.Parent) > 0 {
   288  		s.log.Printf("use %s parent %v [ %s ]", *s.cfg.ParentType, *s.cfg.Parent, strings.ToUpper(*s.cfg.LoadBalanceMethod))
   289  	}
   290  
   291  	for _, addr := range strings.Split(*s.cfg.Local, ",") {
   292  		if addr != "" {
   293  			host, port, _ := net.SplitHostPort(addr)
   294  			p, _ := strconv.Atoi(port)
   295  			sc := server.NewServerChannel(host, p, s.log)
   296  			if *s.cfg.LocalType == "tcp" {
   297  				err = sc.ListenTCP(s.callback)
   298  			} else if *s.cfg.LocalType == "tls" {
   299  				err = sc.ListenTLS(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes, s.callback)
   300  			} else if *s.cfg.LocalType == "kcp" {
   301  				err = sc.ListenKCP(s.cfg.KCP, s.callback, s.log)
   302  			}
   303  			if err != nil {
   304  				return
   305  			}
   306  			s.log.Printf("%s http(s) proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
   307  			s.serverChannels = append(s.serverChannels, &sc)
   308  		}
   309  	}
   310  	return
   311  }
   312  
   313  func (s *HTTP) Clean() {
   314  	s.StopService()
   315  }
   316  func (s *HTTP) callback(inConn net.Conn) {
   317  	defer func() {
   318  		if err := recover(); err != nil {
   319  			s.log.Printf("http(s) conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
   320  		}
   321  	}()
   322  	if *s.cfg.LocalCompress {
   323  		inConn = utils.NewCompConn(inConn)
   324  	}
   325  	if *s.cfg.LocalKey != "" {
   326  		inConn = conncrypt.New(inConn, &conncrypt.Config{
   327  			Password: *s.cfg.LocalKey,
   328  		})
   329  	}
   330  	var err interface{}
   331  	var req utils.HTTPRequest
   332  	req, err = utils.NewHTTPRequest(&inConn, 4096, s.IsBasicAuth(), &s.basicAuth, s.log)
   333  	if err != nil {
   334  		if err != io.EOF {
   335  			s.log.Printf("decoder error , from %s, ERR:%s", inConn.RemoteAddr(), err)
   336  		}
   337  		utils.CloseConn(&inConn)
   338  		return
   339  	}
   340  	address := req.Host
   341  	host, _, _ := net.SplitHostPort(address)
   342  	useProxy := false
   343  	if !utils.IsInternalIP(host, *s.cfg.Always) {
   344  		useProxy = true
   345  		if len(*s.cfg.Parent) == 0 {
   346  			useProxy = false
   347  		} else if *s.cfg.Always {
   348  			useProxy = true
   349  		} else {
   350  			var isInMap bool
   351  			useProxy, isInMap, _, _ = s.checker.IsBlocked(address)
   352  			if !isInMap {
   353  				s.checker.Add(address, s.Resolve(address))
   354  			}
   355  			//s.log.Printf("blocked ? : %v, %s , fail:%d ,success:%d", useProxy, address, n, m)
   356  		}
   357  	}
   358  
   359  	s.log.Printf("use proxy : %v, %s", useProxy, address)
   360  
   361  	lbAddr, err := s.OutToTCP(useProxy, address, &inConn, &req)
   362  	if err != nil {
   363  		if len(*s.cfg.Parent) == 0 {
   364  			s.log.Printf("connect to %s fail, ERR:%s", address, err)
   365  		} else {
   366  			s.log.Printf("connect to %s parent %v fail", *s.cfg.ParentType, lbAddr)
   367  		}
   368  		utils.CloseConn(&inConn)
   369  	}
   370  }
   371  func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *utils.HTTPRequest) (lbAddr string, err interface{}) {
   372  	inAddr := (*inConn).RemoteAddr().String()
   373  	inLocalAddr := (*inConn).LocalAddr().String()
   374  	//防止死循环
   375  	if s.IsDeadLoop(inLocalAddr, req.Host) {
   376  		utils.CloseConn(inConn)
   377  		err = fmt.Errorf("dead loop detected , %s", req.Host)
   378  		return
   379  	}
   380  	var outConn net.Conn
   381  	tryCount := 0
   382  	maxTryCount := 5
   383  	for {
   384  		if s.isStop {
   385  			return
   386  		}
   387  		if useProxy {
   388  			// s.log.Printf("%v", s.outPool)
   389  			if *s.cfg.ParentType == "ssh" {
   390  				outConn, err = s.getSSHConn(address)
   391  			} else {
   392  				selectAddr := (*inConn).RemoteAddr().String()
   393  				if utils.LBMethod(*s.cfg.LoadBalanceMethod) == lb.SELECT_HASH && *s.cfg.LoadBalanceHashTarget {
   394  					selectAddr = address
   395  				}
   396  				lbAddr = s.lb.Select(selectAddr, *s.cfg.LoadBalanceOnlyHA)
   397  				outConn, err = s.GetParentConn(lbAddr)
   398  			}
   399  
   400  		} else {
   401  			outConn, err = s.GetDirectConn(s.Resolve(address), inLocalAddr)
   402  		}
   403  		tryCount++
   404  		if err == nil || tryCount > maxTryCount {
   405  			break
   406  		} else {
   407  			s.log.Printf("connect to %s , err:%s,retrying...", lbAddr, err)
   408  			time.Sleep(time.Second * 2)
   409  		}
   410  	}
   411  	if err != nil {
   412  		s.log.Printf("connect to %s , err:%s", lbAddr, err)
   413  		utils.CloseConn(inConn)
   414  		return
   415  	}
   416  	if *s.cfg.ParentCompress {
   417  		outConn = utils.NewCompConn(outConn)
   418  	}
   419  	if useProxy && *s.cfg.ParentKey != "" {
   420  		outConn = conncrypt.New(outConn, &conncrypt.Config{
   421  			Password: *s.cfg.ParentKey,
   422  		})
   423  	}
   424  
   425  	outAddr := outConn.RemoteAddr().String()
   426  	//outLocalAddr := outConn.LocalAddr().String()
   427  	if req.IsHTTPS() && (!useProxy || *s.cfg.ParentType == "ssh") {
   428  		//https无上级或者上级非代理,proxy需要响应connect请求,并直连目标
   429  		err = req.HTTPSReply()
   430  	} else {
   431  		//https或者http,上级是代理,proxy需要转发
   432  		outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
   433  		//直连目标或上级非代理或非SNI,,清理HTTP头部的代理头信息
   434  		if (!useProxy || *s.cfg.ParentType == "ssh") && !req.IsSNI {
   435  			_, err = outConn.Write(utils.RemoveProxyHeaders(req.HeadBuf))
   436  		} else {
   437  			_, err = outConn.Write(req.HeadBuf)
   438  		}
   439  		outConn.SetDeadline(time.Time{})
   440  		if err != nil {
   441  			s.log.Printf("write to %s , err:%s", lbAddr, err)
   442  			utils.CloseConn(inConn)
   443  			return
   444  		}
   445  	}
   446  
   447  	if s.cfg.RateLimitBytes > 0 {
   448  		outConn = iolimiter.NewReaderConn(outConn, s.cfg.RateLimitBytes)
   449  	}
   450  
   451  	utils.IoBind((*inConn), outConn, func(err interface{}) {
   452  		s.log.Printf("conn %s - %s released [%s]", inAddr, outAddr, req.Host)
   453  		s.userConns.Remove(inAddr)
   454  		if len(*s.cfg.Parent) > 0 {
   455  			s.lb.DecreaseConns(lbAddr)
   456  		}
   457  	}, s.log)
   458  	s.log.Printf("conn %s - %s connected [%s]", inAddr, outAddr, req.Host)
   459  	if c, ok := s.userConns.Get(inAddr); ok {
   460  		(*c.(*net.Conn)).Close()
   461  	}
   462  	s.userConns.Set(inAddr, inConn)
   463  	if len(*s.cfg.Parent) > 0 {
   464  		s.lb.IncreasConns(lbAddr)
   465  	}
   466  	return
   467  }
   468  
   469  func (s *HTTP) getSSHConn(host string) (outConn net.Conn, err interface{}) {
   470  	maxTryCount := 1
   471  	tryCount := 0
   472  RETRY:
   473  	if tryCount >= maxTryCount || s.isStop {
   474  		return
   475  	}
   476  	wait := make(chan bool, 1)
   477  	go func() {
   478  		defer func() {
   479  			if err == nil {
   480  				err = recover()
   481  			}
   482  			wait <- true
   483  		}()
   484  		outConn, err = s.sshClient.Dial("tcp", host)
   485  	}()
   486  	select {
   487  	case <-wait:
   488  	case <-time.After(time.Second * 5):
   489  		err = fmt.Errorf("ssh dial %s timeout", host)
   490  	}
   491  	if err != nil {
   492  		s.log.Printf("connect ssh fail, ERR: %s, retrying...", err)
   493  		e := s.ConnectSSH()
   494  		if e == nil {
   495  			tryCount++
   496  			time.Sleep(time.Second * 3)
   497  			goto RETRY
   498  		} else {
   499  			err = e
   500  		}
   501  	}
   502  	return
   503  }
   504  func (s *HTTP) ConnectSSH() (err error) {
   505  	select {
   506  	case s.lockChn <- true:
   507  	default:
   508  		err = fmt.Errorf("can not connect at same time")
   509  		return
   510  	}
   511  	config := ssh.ClientConfig{
   512  		Timeout: time.Duration(*s.cfg.Timeout) * time.Millisecond,
   513  		User:    *s.cfg.SSHUser,
   514  		Auth:    []ssh.AuthMethod{s.cfg.SSHAuthMethod},
   515  		HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
   516  			return nil
   517  		},
   518  	}
   519  	if s.sshClient != nil {
   520  		s.sshClient.Close()
   521  	}
   522  	s.sshClient, err = ssh.Dial("tcp", s.Resolve(s.lb.Select("", *s.cfg.LoadBalanceOnlyHA)), &config)
   523  	if err != nil {
   524  		s.log.Printf("connect to ssh %s fail", s.cfg.Parent)
   525  	}
   526  	<-s.lockChn
   527  	return
   528  }
   529  
   530  func (s *HTTP) InitBasicAuth() (err error) {
   531  	if *s.cfg.DNSAddress != "" {
   532  		s.basicAuth = utils.NewBasicAuth(&(*s).domainResolver, s.log)
   533  	} else {
   534  		s.basicAuth = utils.NewBasicAuth(nil, s.log)
   535  	}
   536  	if *s.cfg.AuthURL != "" {
   537  		s.basicAuth.SetAuthURL(*s.cfg.AuthURL, *s.cfg.AuthURLOkCode, *s.cfg.AuthURLTimeout, *s.cfg.AuthURLRetry)
   538  		s.log.Printf("auth from %s", *s.cfg.AuthURL)
   539  	}
   540  	if *s.cfg.AuthFile != "" {
   541  		var n = 0
   542  		n, err = s.basicAuth.AddFromFile(*s.cfg.AuthFile)
   543  		if err != nil {
   544  			err = fmt.Errorf("auth-file ERR:%s", err)
   545  			return
   546  		}
   547  		s.log.Printf("auth data added from file %d , total:%d", n, s.basicAuth.Total())
   548  	}
   549  	if len(*s.cfg.Auth) > 0 {
   550  		n := s.basicAuth.Add(*s.cfg.Auth)
   551  		s.log.Printf("auth data added %d, total:%d", n, s.basicAuth.Total())
   552  	}
   553  	return
   554  }
   555  func (s *HTTP) InitLB() {
   556  	configs := lb.BackendsConfig{}
   557  	for _, addr := range *s.cfg.Parent {
   558  		_addrInfo := strings.Split(addr, "@")
   559  		_addr := _addrInfo[0]
   560  		weight := 1
   561  		if len(_addrInfo) == 2 {
   562  			weight, _ = strconv.Atoi(_addrInfo[1])
   563  		}
   564  		configs = append(configs, &lb.BackendConfig{
   565  			Address:       _addr,
   566  			Weight:        weight,
   567  			ActiveAfter:   1,
   568  			InactiveAfter: 2,
   569  			Timeout:       time.Duration(*s.cfg.LoadBalanceTimeout) * time.Millisecond,
   570  			RetryTime:     time.Duration(*s.cfg.LoadBalanceRetryTime) * time.Millisecond,
   571  		})
   572  	}
   573  	LB := lb.NewGroup(utils.LBMethod(*s.cfg.LoadBalanceMethod), configs, &s.domainResolver, s.log, *s.cfg.Debug)
   574  	s.lb = &LB
   575  }
   576  func (s *HTTP) IsBasicAuth() bool {
   577  	return *s.cfg.AuthFile != "" || len(*s.cfg.Auth) > 0 || *s.cfg.AuthURL != ""
   578  }
   579  func (s *HTTP) IsDeadLoop(inLocalAddr string, host string) bool {
   580  	inIP, inPort, err := net.SplitHostPort(inLocalAddr)
   581  	if err != nil {
   582  		return false
   583  	}
   584  	outDomain, outPort, err := net.SplitHostPort(host)
   585  	if err != nil {
   586  		return false
   587  	}
   588  	if inPort == outPort {
   589  		var outIPs []net.IP
   590  		if *s.cfg.DNSAddress != "" {
   591  			outIPs = []net.IP{net.ParseIP(s.Resolve(outDomain))}
   592  		} else {
   593  			outIPs, err = utils.LookupIP(outDomain)
   594  		}
   595  		if err == nil {
   596  			for _, ip := range outIPs {
   597  				if ip.String() == inIP {
   598  					return true
   599  				}
   600  			}
   601  		}
   602  		interfaceIPs, err := utils.GetAllInterfaceAddr()
   603  		for _, ip := range *s.cfg.LocalIPS {
   604  			interfaceIPs = append(interfaceIPs, net.ParseIP(ip).To4())
   605  		}
   606  		if err == nil {
   607  			for _, localIP := range interfaceIPs {
   608  				for _, outIP := range outIPs {
   609  					if localIP.Equal(outIP) {
   610  						return true
   611  					}
   612  				}
   613  			}
   614  		}
   615  	}
   616  	return false
   617  }
   618  func (s *HTTP) Resolve(address string) string {
   619  	if *s.cfg.DNSAddress == "" {
   620  		return address
   621  	}
   622  	ip, err := s.domainResolver.Resolve(address)
   623  	if err != nil {
   624  		s.log.Printf("dns error %s , ERR:%s", address, err)
   625  		return address
   626  	}
   627  	return ip
   628  }
   629  func (s *HTTP) GetParentConn(address string) (conn net.Conn, err error) {
   630  	if *s.cfg.ParentType == "tls" {
   631  		if s.jumper == nil {
   632  			var _conn tls.Conn
   633  			_conn, err = utils.TlsConnectHost(address, *s.cfg.Timeout, s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes)
   634  			if err == nil {
   635  				conn = net.Conn(&_conn)
   636  			}
   637  		} else {
   638  			conf, err := utils.TlsConfig(s.cfg.CertBytes, s.cfg.KeyBytes, s.cfg.CaCertBytes)
   639  			if err != nil {
   640  				return nil, err
   641  			}
   642  			var _c net.Conn
   643  			_c, err = s.jumper.Dial(address, time.Millisecond*time.Duration(*s.cfg.Timeout))
   644  			if err == nil {
   645  				conn = net.Conn(tls.Client(_c, conf))
   646  			}
   647  		}
   648  
   649  	} else if *s.cfg.ParentType == "kcp" {
   650  		conn, err = utils.ConnectKCPHost(address, s.cfg.KCP)
   651  	} else if *s.cfg.ParentType == "ssh" {
   652  		var e interface{}
   653  		conn, e = s.getSSHConn(address)
   654  		if e != nil {
   655  			err = fmt.Errorf("%s", e)
   656  		}
   657  	} else {
   658  		if s.jumper == nil {
   659  			conn, err = utils.ConnectHost(address, *s.cfg.Timeout)
   660  		} else {
   661  			conn, err = s.jumper.Dial(address, time.Millisecond*time.Duration(*s.cfg.Timeout))
   662  		}
   663  	}
   664  	return
   665  }
   666  func (s *HTTP) GetDirectConn(address string, localAddr string) (conn net.Conn, err error) {
   667  	if !*s.cfg.BindListen {
   668  		return utils.ConnectHost(address, *s.cfg.Timeout)
   669  	}
   670  	ip, _, _ := net.SplitHostPort(localAddr)
   671  	if utils.IsInternalIP(ip, false) {
   672  		return utils.ConnectHost(address, *s.cfg.Timeout)
   673  	}
   674  	local, _ := net.ResolveTCPAddr("tcp", ip+":0")
   675  	d := net.Dialer{
   676  		Timeout:   time.Millisecond * time.Duration(*s.cfg.Timeout),
   677  		LocalAddr: local,
   678  	}
   679  	conn, err = d.Dial("tcp", address)
   680  	return
   681  }