1package socks 2 3import ( 4 "errors" 5 "net" 6 "time" 7) 8 9func (cfg *config) dialSocks4(targetAddr string) (_ net.Conn, err error) { 10 socksType := cfg.Proto 11 proxy := cfg.Host 12 13 // dial TCP 14 conn, err := net.Dial("tcp", proxy) 15 if err != nil { 16 return nil, err 17 } 18 defer func() { 19 if err != nil { 20 conn.Close() 21 } 22 }() 23 24 // connection request 25 host, port, err := splitHostPort(targetAddr) 26 if err != nil { 27 return nil, err 28 } 29 ip := net.IPv4(0, 0, 0, 1).To4() 30 if socksType == SOCKS4 { 31 ip, err = lookupIPv4(host) 32 if err != nil { 33 return nil, err 34 } 35 } 36 req := []byte{ 37 4, // version number 38 1, // command CONNECT 39 byte(port >> 8), // higher byte of destination port 40 byte(port), // lower byte of destination port (big endian) 41 ip[0], ip[1], ip[2], ip[3], // special invalid IP address to indicate the host name is provided 42 0, // user id is empty, anonymous proxy only 43 } 44 if socksType == SOCKS4A { 45 req = append(req, []byte(host+"\x00")...) 46 } 47 48 resp, err := cfg.sendReceive(conn, req) 49 if err != nil { 50 return nil, err 51 } else if len(resp) != 8 { 52 return nil, errors.New("server does not respond properly") 53 } 54 switch resp[1] { 55 case 90: 56 // request granted 57 case 91: 58 return nil, errors.New("socks connection request rejected or failed") 59 case 92: 60 return nil, errors.New("socks connection request rejected because SOCKS server cannot connect to identd on the client") 61 case 93: 62 return nil, errors.New("socks connection request rejected because the client program and identd report different user-ids") 63 default: 64 return nil, errors.New("socks connection request failed, unknown error") 65 } 66 // clear the deadline before returning 67 if err := conn.SetDeadline(time.Time{}); err != nil { 68 return nil, err 69 } 70 return conn, nil 71} 72