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

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