|
|
@ -18,6 +18,7 @@ type socks5Conn struct {
|
|
|
|
|
|
|
|
|
|
|
|
func (s5 *socks5Conn) Serve() {
|
|
|
|
func (s5 *socks5Conn) Serve() {
|
|
|
|
defer s5.Close()
|
|
|
|
defer s5.Close()
|
|
|
|
|
|
|
|
|
|
|
|
if err := s5.handshake(); err != nil {
|
|
|
|
if err := s5.handshake(); err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
log.Println(err)
|
|
|
|
return
|
|
|
|
return
|
|
|
@ -34,6 +35,8 @@ func (s5 *socks5Conn) handshake() error {
|
|
|
|
// only process auth methods here
|
|
|
|
// only process auth methods here
|
|
|
|
|
|
|
|
|
|
|
|
buf := make([]byte, 258)
|
|
|
|
buf := make([]byte, 258)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// read auth methods
|
|
|
|
n, err := io.ReadAtLeast(s5.clientConn, buf, 1)
|
|
|
|
n, err := io.ReadAtLeast(s5.clientConn, buf, 1)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
return err
|
|
|
@ -41,6 +44,7 @@ func (s5 *socks5Conn) handshake() error {
|
|
|
|
|
|
|
|
|
|
|
|
l := int(buf[0]) + 1
|
|
|
|
l := int(buf[0]) + 1
|
|
|
|
if n < l {
|
|
|
|
if n < l {
|
|
|
|
|
|
|
|
// read remains data
|
|
|
|
_, err := io.ReadFull(s5.clientConn, buf[n:l])
|
|
|
|
_, err := io.ReadFull(s5.clientConn, buf[n:l])
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
return err
|
|
|
@ -55,22 +59,26 @@ func (s5 *socks5Conn) handshake() error {
|
|
|
|
|
|
|
|
|
|
|
|
func (s5 *socks5Conn) processRequest() error {
|
|
|
|
func (s5 *socks5Conn) processRequest() error {
|
|
|
|
buf := make([]byte, 258)
|
|
|
|
buf := make([]byte, 258)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// read header
|
|
|
|
n, err := io.ReadAtLeast(s5.clientConn, buf, 10)
|
|
|
|
n, err := io.ReadAtLeast(s5.clientConn, buf, 10)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if buf[0] != socks5Version {
|
|
|
|
if buf[0] != socks5Version {
|
|
|
|
return fmt.Errorf("error version %s", buf[0])
|
|
|
|
return fmt.Errorf("error version %d", buf[0])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// only support connect
|
|
|
|
// command only support connect
|
|
|
|
if buf[1] != cmdConnect {
|
|
|
|
if buf[1] != cmdConnect {
|
|
|
|
return fmt.Errorf("unsupported command %s", buf[1])
|
|
|
|
return fmt.Errorf("unsupported command %s", buf[1])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
hlen := 0
|
|
|
|
hlen := 0 // target address length
|
|
|
|
host := ""
|
|
|
|
host := "" // target address
|
|
|
|
msglen := 0
|
|
|
|
msglen := 0 // header length
|
|
|
|
|
|
|
|
|
|
|
|
switch buf[3] {
|
|
|
|
switch buf[3] {
|
|
|
|
case addrTypeIPv4:
|
|
|
|
case addrTypeIPv4:
|
|
|
|
hlen = 4
|
|
|
|
hlen = 4
|
|
|
@ -83,6 +91,7 @@ func (s5 *socks5Conn) processRequest() error {
|
|
|
|
msglen = 6 + hlen
|
|
|
|
msglen = 6 + hlen
|
|
|
|
|
|
|
|
|
|
|
|
if n < msglen {
|
|
|
|
if n < msglen {
|
|
|
|
|
|
|
|
// read remains header
|
|
|
|
_, err := io.ReadFull(s5.clientConn, buf[n:msglen])
|
|
|
|
_, err := io.ReadFull(s5.clientConn, buf[n:msglen])
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
return err
|
|
|
@ -97,15 +106,17 @@ func (s5 *socks5Conn) processRequest() error {
|
|
|
|
host = net.IP(addr).String()
|
|
|
|
host = net.IP(addr).String()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// get target port
|
|
|
|
port := binary.BigEndian.Uint16(buf[msglen-2 : msglen])
|
|
|
|
port := binary.BigEndian.Uint16(buf[msglen-2 : msglen])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// target address
|
|
|
|
target := net.JoinHostPort(host, fmt.Sprintf("%d", port))
|
|
|
|
target := net.JoinHostPort(host, fmt.Sprintf("%d", port))
|
|
|
|
|
|
|
|
|
|
|
|
// reply user with connect success
|
|
|
|
// reply user with connect success
|
|
|
|
// if dial to target failed, user will receive connection reset
|
|
|
|
// if dial to target failed, user will receive connection reset
|
|
|
|
s5.clientConn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01})
|
|
|
|
s5.clientConn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01})
|
|
|
|
|
|
|
|
|
|
|
|
log.Printf("connecing to %s", target)
|
|
|
|
//log.Printf("connecing to %s\r\n", target)
|
|
|
|
|
|
|
|
|
|
|
|
// connect to the target
|
|
|
|
// connect to the target
|
|
|
|
s5.serverConn, err = s5.dial("tcp", target)
|
|
|
|
s5.serverConn, err = s5.dial("tcp", target)
|
|
|
@ -120,8 +131,20 @@ func (s5 *socks5Conn) processRequest() error {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s5 *socks5Conn) forward() {
|
|
|
|
func (s5 *socks5Conn) forward() {
|
|
|
|
go io.Copy(s5.clientConn, s5.serverConn)
|
|
|
|
|
|
|
|
io.Copy(s5.serverConn, s5.clientConn)
|
|
|
|
c := make(chan int, 2)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
|
|
|
|
io.Copy(s5.clientConn, s5.serverConn)
|
|
|
|
|
|
|
|
c <- 1
|
|
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
|
|
|
|
io.Copy(s5.serverConn, s5.clientConn)
|
|
|
|
|
|
|
|
c < 1
|
|
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<-c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s5 *socks5Conn) Close() {
|
|
|
|
func (s5 *socks5Conn) Close() {
|
|
|
|