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

     1  package socks
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/AntonOrnatskyi/goproxy/utils"
    10  )
    11  
    12  const (
    13  	Method_NO_AUTH         = uint8(0x00)
    14  	Method_GSSAPI          = uint8(0x01)
    15  	Method_USER_PASS       = uint8(0x02)
    16  	Method_IANA            = uint8(0x7F)
    17  	Method_RESVERVE        = uint8(0x80)
    18  	Method_NONE_ACCEPTABLE = uint8(0xFF)
    19  	VERSION_V5             = uint8(0x05)
    20  	CMD_CONNECT            = uint8(0x01)
    21  	CMD_BIND               = uint8(0x02)
    22  	CMD_ASSOCIATE          = uint8(0x03)
    23  	ATYP_IPV4              = uint8(0x01)
    24  	ATYP_DOMAIN            = uint8(0x03)
    25  	ATYP_IPV6              = uint8(0x04)
    26  	REP_SUCCESS            = uint8(0x00)
    27  	REP_REQ_FAIL           = uint8(0x01)
    28  	REP_RULE_FORBIDDEN     = uint8(0x02)
    29  	REP_NETWOR_UNREACHABLE = uint8(0x03)
    30  	REP_HOST_UNREACHABLE   = uint8(0x04)
    31  	REP_CONNECTION_REFUSED = uint8(0x05)
    32  	REP_TTL_TIMEOUT        = uint8(0x06)
    33  	REP_CMD_UNSUPPORTED    = uint8(0x07)
    34  	REP_ATYP_UNSUPPORTED   = uint8(0x08)
    35  	REP_UNKNOWN            = uint8(0x09)
    36  	RSV                    = uint8(0x00)
    37  )
    38  
    39  var (
    40  	ZERO_IP   = []byte{0x00, 0x00, 0x00, 0x00}
    41  	ZERO_PORT = []byte{0x00, 0x00}
    42  )
    43  
    44  type ServerConn struct {
    45  	target   string
    46  	user     string
    47  	password string
    48  	conn     *net.Conn
    49  	timeout  time.Duration
    50  	auth     *utils.BasicAuth
    51  	header   []byte
    52  	ver      uint8
    53  	//method
    54  	methodsCount uint8
    55  	methods      []uint8
    56  	method       uint8
    57  	//request
    58  	cmd             uint8
    59  	reserve         uint8
    60  	addressType     uint8
    61  	dstAddr         string
    62  	dstPort         string
    63  	dstHost         string
    64  	UDPConnListener *net.UDPConn
    65  	enableUDP       bool
    66  	udpIP           string
    67  }
    68  
    69  func NewServerConn(conn *net.Conn, timeout time.Duration, auth *utils.BasicAuth, enableUDP bool, udpHost string, header []byte) *ServerConn {
    70  
    71  	s := &ServerConn{
    72  		conn:      conn,
    73  		timeout:   timeout,
    74  		auth:      auth,
    75  		header:    header,
    76  		ver:       VERSION_V5,
    77  		enableUDP: enableUDP,
    78  		udpIP:     udpHost,
    79  	}
    80  	return s
    81  
    82  }
    83  func (s *ServerConn) Close() {
    84  	utils.CloseConn(s.conn)
    85  }
    86  func (s *ServerConn) AuthData() Auth {
    87  	return Auth{s.user, s.password}
    88  }
    89  func (s *ServerConn) IsUDP() bool {
    90  	return s.cmd == CMD_ASSOCIATE
    91  }
    92  func (s *ServerConn) IsTCP() bool {
    93  	return s.cmd == CMD_CONNECT
    94  }
    95  func (s *ServerConn) Method() uint8 {
    96  	return s.method
    97  }
    98  func (s *ServerConn) Target() string {
    99  	return s.target
   100  }
   101  func (s *ServerConn) Host() string {
   102  	return s.dstHost
   103  }
   104  func (s *ServerConn) Port() string {
   105  	return s.dstPort
   106  }
   107  func (s *ServerConn) Handshake() (err error) {
   108  	remoteAddr := (*s.conn).RemoteAddr()
   109  	localAddr := (*s.conn).LocalAddr()
   110  	//协商开始
   111  	//method select request
   112  	var methodReq MethodsRequest
   113  	(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
   114  
   115  	methodReq, e := NewMethodsRequest((*s.conn), s.header)
   116  	(*s.conn).SetReadDeadline(time.Time{})
   117  	if e != nil {
   118  		(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
   119  		methodReq.Reply(Method_NONE_ACCEPTABLE)
   120  		(*s.conn).SetReadDeadline(time.Time{})
   121  		err = fmt.Errorf("new methods request fail,ERR: %s", e)
   122  		return
   123  	}
   124  	//log.Printf("%v,s.auth == %v && methodReq.Select(Method_NO_AUTH) %v", methodReq.methods, s.auth, methodReq.Select(Method_NO_AUTH))
   125  	if s.auth == nil && methodReq.Select(Method_NO_AUTH) && !methodReq.Select(Method_USER_PASS) {
   126  		// if !methodReq.Select(Method_NO_AUTH) {
   127  		// 	(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
   128  		// 	methodReq.Reply(Method_NONE_ACCEPTABLE)
   129  		// 	(*s.conn).SetReadDeadline(time.Time{})
   130  		// 	err = fmt.Errorf("none method found : Method_NO_AUTH")
   131  		// 	return
   132  		// }
   133  		s.method = Method_NO_AUTH
   134  		//method select reply
   135  		(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
   136  		err = methodReq.Reply(Method_NO_AUTH)
   137  		(*s.conn).SetReadDeadline(time.Time{})
   138  		if err != nil {
   139  			err = fmt.Errorf("reply answer data fail,ERR: %s", err)
   140  			return
   141  		}
   142  		// err = fmt.Errorf("% x", methodReq.Bytes())
   143  	} else {
   144  		//auth
   145  		if !methodReq.Select(Method_USER_PASS) {
   146  			(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
   147  			methodReq.Reply(Method_NONE_ACCEPTABLE)
   148  			(*s.conn).SetReadDeadline(time.Time{})
   149  			err = fmt.Errorf("none method found : Method_USER_PASS")
   150  			return
   151  		}
   152  		s.method = Method_USER_PASS
   153  		//method reply need auth
   154  		(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
   155  		err = methodReq.Reply(Method_USER_PASS)
   156  		(*s.conn).SetReadDeadline(time.Time{})
   157  		if err != nil {
   158  			err = fmt.Errorf("reply answer data fail,ERR: %s", err)
   159  			return
   160  		}
   161  		//read auth
   162  		buf := make([]byte, 500)
   163  		var n int
   164  		(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
   165  		n, err = (*s.conn).Read(buf)
   166  		(*s.conn).SetReadDeadline(time.Time{})
   167  		if err != nil {
   168  			err = fmt.Errorf("read auth info fail,ERR: %s", err)
   169  			return
   170  		}
   171  		r := buf[:n]
   172  		s.user = string(r[2 : r[1]+2])
   173  		s.password = string(r[2+r[1]+1:])
   174  		//err = fmt.Errorf("user:%s,pass:%s", user, pass)
   175  		//auth
   176  		_userAddr := strings.Split(remoteAddr.String(), ":")
   177  		_localAddr := strings.Split(localAddr.String(), ":")
   178  		if s.auth == nil || s.auth.CheckUserPass(s.user, s.password, _userAddr[0], _localAddr[0], "") {
   179  			(*s.conn).SetDeadline(time.Now().Add(s.timeout))
   180  			_, err = (*s.conn).Write([]byte{0x01, 0x00})
   181  			(*s.conn).SetDeadline(time.Time{})
   182  			if err != nil {
   183  				err = fmt.Errorf("answer auth success to %s fail,ERR: %s", remoteAddr, err)
   184  				return
   185  			}
   186  		} else {
   187  			(*s.conn).SetDeadline(time.Now().Add(s.timeout))
   188  			_, err = (*s.conn).Write([]byte{0x01, 0x01})
   189  			(*s.conn).SetDeadline(time.Time{})
   190  			if err != nil {
   191  				err = fmt.Errorf("answer auth fail to %s fail,ERR: %s", remoteAddr, err)
   192  				return
   193  			}
   194  			err = fmt.Errorf("auth fail from %s", remoteAddr)
   195  			return
   196  		}
   197  	}
   198  	//request detail
   199  	(*s.conn).SetReadDeadline(time.Now().Add(s.timeout))
   200  	request, e := NewRequest(*s.conn)
   201  	(*s.conn).SetReadDeadline(time.Time{})
   202  	if e != nil {
   203  		err = fmt.Errorf("read request data fail,ERR: %s", e)
   204  		return
   205  	}
   206  	//协商结束
   207  
   208  	switch request.CMD() {
   209  	case CMD_BIND:
   210  		err = request.TCPReply(REP_UNKNOWN)
   211  		if err != nil {
   212  			err = fmt.Errorf("TCPReply REP_UNKNOWN to %s fail,ERR: %s", remoteAddr, err)
   213  			return
   214  		}
   215  		err = fmt.Errorf("cmd bind not supported, form: %s", remoteAddr)
   216  		return
   217  	case CMD_CONNECT:
   218  		err = request.TCPReply(REP_SUCCESS)
   219  		if err != nil {
   220  			err = fmt.Errorf("TCPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err)
   221  			return
   222  		}
   223  	case CMD_ASSOCIATE:
   224  		if !s.enableUDP {
   225  			request.UDPReply(REP_UNKNOWN, "0.0.0.0:0")
   226  			if err != nil {
   227  				err = fmt.Errorf("UDPReply REP_UNKNOWN to %s fail,ERR: %s", remoteAddr, err)
   228  				return
   229  			}
   230  			err = fmt.Errorf("cmd associate not supported, form: %s", remoteAddr)
   231  			return
   232  		}
   233  		a, _ := net.ResolveUDPAddr("udp", ":0")
   234  		s.UDPConnListener, err = net.ListenUDP("udp", a)
   235  		if err != nil {
   236  			request.UDPReply(REP_UNKNOWN, "0.0.0.0:0")
   237  			err = fmt.Errorf("udp bind fail,ERR: %s , for %s", err, remoteAddr)
   238  			return
   239  		}
   240  		_, port, _ := net.SplitHostPort(s.UDPConnListener.LocalAddr().String())
   241  		err = request.UDPReply(REP_SUCCESS, net.JoinHostPort(s.udpIP, port))
   242  		if err != nil {
   243  			err = fmt.Errorf("UDPReply REP_SUCCESS to %s fail,ERR: %s", remoteAddr, err)
   244  			return
   245  		}
   246  
   247  	}
   248  
   249  	//fill socks info
   250  	s.target = request.Addr()
   251  	s.methodsCount = methodReq.MethodsCount()
   252  	s.methods = methodReq.Methods()
   253  	s.cmd = request.CMD()
   254  	s.reserve = request.reserve
   255  	s.addressType = request.addressType
   256  	s.dstAddr = request.dstAddr
   257  	s.dstHost = request.dstHost
   258  	s.dstPort = request.dstPort
   259  	return
   260  }