github.com/keysonzzz/kmg@v0.0.0-20151121023212-05317bfd7d39/kmgNet/kmgProxy/Socks4aDial.go (about)

     1  package kmgProxy
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"io"
     7  	"net"
     8  	"time"
     9  
    10  	"github.com/bronze1man/kmg/kmgNet"
    11  )
    12  
    13  func Socks4aDialTimeout(proxyAddr string, targetAddr string, timeout time.Duration) (conn net.Conn, err error) {
    14  	conn, err = net.DialTimeout("tcp", proxyAddr, timeout)
    15  	if err != nil {
    16  		return
    17  	}
    18  	err = socks4aConnect(conn, targetAddr)
    19  	if err != nil {
    20  		conn.Close()
    21  		return
    22  	}
    23  	return
    24  }
    25  func Socks4aDial(proxyAddr string, targetAddr string) (conn net.Conn, err error) {
    26  	return Socks4aDialTimeout(proxyAddr, targetAddr, 0)
    27  }
    28  
    29  func NewSocks4aDialer(proxyAddr string) kmgNet.Dialer {
    30  	return func(network, address string) (net.Conn, error) {
    31  		return Socks4aDialTimeout(proxyAddr, address, 0)
    32  	}
    33  }
    34  
    35  //按照socks4a接口,连接到那个地址去,后面可以当成这个连接已经连接到了对方主机,本实现没有用户密码功能
    36  func socks4aConnect(conn net.Conn, addr string) (err error) {
    37  	uaddr, err := ParseUnsolvedAddr(addr)
    38  	if err != nil {
    39  		return
    40  	}
    41  	toWriteHeader := []byte{4, 1, 0, 0, 0, 0, 0, 1, 0}
    42  	binary.BigEndian.PutUint16(toWriteHeader[2:4], uint16(uaddr.Port))
    43  	if uaddr.Ip != nil {
    44  		ip := uaddr.Ip.To4()
    45  		if ip == nil {
    46  			return fmt.Errorf("you can not connect to a ipv6 addr with socks4a")
    47  		}
    48  		copy(toWriteHeader[4:8], []byte(ip[:4]))
    49  	} else {
    50  		toWriteHeader = append(toWriteHeader, []byte(uaddr.Domain)...)
    51  		toWriteHeader = append(toWriteHeader, 0)
    52  	}
    53  	_, err = conn.Write(toWriteHeader)
    54  	if err != nil {
    55  		return
    56  	}
    57  	_, err = io.ReadFull(conn, toWriteHeader[:8])
    58  	if err != nil {
    59  		return
    60  	}
    61  	switch toWriteHeader[1] {
    62  	case 0x5a:
    63  	//ok
    64  	case 0x5b:
    65  		return fmt.Errorf("socks4a: request rejected or failed")
    66  	case 0x5c:
    67  		return fmt.Errorf("socks4a: request failed because client is not running identd (or not reachable from the server)")
    68  	case 0x5d:
    69  		return fmt.Errorf("socks4a: request failed because client is not running identd (or not reachable from the server)")
    70  	default:
    71  		return fmt.Errorf("socks4a: protoal error 1 %d", toWriteHeader[1])
    72  	}
    73  	return
    74  }