github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/apps/mixnet/socks5.go (about) 1 // Copyright (c) 2015, Google Inc. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package mixnet 16 17 import ( 18 "errors" 19 "net" 20 "strconv" 21 ) 22 23 // Codes used in the RFC standard of SOCKS version 5. 24 const ( 25 SocksVersion = 0x05 26 SocksMethodNoAuth = 0x00 27 SocksNoAcceptableMethod = 0xff 28 SocksCmdConnect = 0x01 29 SocksAtypIPv4 = 0x01 30 SocksRepSuccess = 0x00 31 SocksRepFailure = 0x01 32 SocksRepUnsupported = 0x07 33 ) 34 35 // SocksConn implements the net.Conn interface and contains a destination 36 // network and address for the proxy. 37 type SocksConn struct { 38 net.Conn 39 network, dstAddr string // Destination network and address. 40 } 41 42 // DestinationAddr returns the destination address negotiated in the SOCKS 43 // protocol. 44 func (c *SocksConn) DestinationAddr() string { 45 return c.dstAddr 46 } 47 48 // SocksListener implements the net.Listener interface as a SOCKS server. This 49 // program partially implements the server role in version 5 of the SOCKS 50 // protocol specified in RFC 1928. In particular, it only supports TCP clients 51 // with no authentication who request CONNECT to IPv4 addresses; neither BIND 52 // nor UDP ASSOCIATE are supported. 53 type SocksListener struct { 54 net.Listener 55 network string // Network protocol for proxying, e.g. "tcp". 56 } 57 58 // SocksListen binds an address to a socket and returns a 59 // SocksListener for serving SOCKS clients. 60 func SocksListen(network, addr string) (net.Listener, error) { 61 l, err := net.Listen(network, addr) 62 if err != nil { 63 return nil, err 64 } 65 return &SocksListener{l, network}, nil 66 } 67 68 // Accept exposes the SOCKS5 protocol to connecting client. Return the 69 // connection and the requested destination address. 70 func (l *SocksListener) Accept() (net.Conn, error) { 71 c, err := l.Listener.Accept() 72 if err != nil { 73 return nil, err 74 } 75 76 // First, wait for greeting from client containing the SOCKS version and 77 // requested methods. 78 msg := make([]byte, MaxMsgBytes) 79 reply := make([]byte, MaxMsgBytes) 80 bytes, err := c.Read(msg) 81 if err != nil { 82 c.Close() 83 return nil, err 84 } 85 86 // Parse client's greeting, making sure that it is the proper length. 87 // Only the NO AUTHENTICATION REQUIRED method is allowed. Note that this 88 // makes the server non-compliant since GSSAPI is not allowed. 89 ok := false 90 var ver, nmethods int 91 if bytes > 2 { 92 ver = int(msg[0]) 93 nmethods = int(msg[1]) 94 if bytes >= 2+nmethods { 95 for _, method := range msg[2 : 2+nmethods] { 96 if method == SocksMethodNoAuth { 97 ok = true 98 break 99 } 100 } 101 } 102 } 103 104 // Second, reply with selected method. 105 reply[0] = SocksVersion 106 if ok { 107 reply[1] = SocksMethodNoAuth 108 } else { 109 reply[1] = SocksNoAcceptableMethod 110 } 111 112 if _, err = c.Write(reply[:2]); err != nil { 113 c.Close() 114 return nil, err 115 } 116 117 // If NO ACCEPTABLE METHOD, the client closes the connection. 118 if !ok { 119 c.Close() 120 return nil, errors.New("socks: client did not provide acceptable method") 121 } 122 123 // Third, wait for command from client. 124 bytes, err = c.Read(msg) 125 if err != nil { 126 c.Close() 127 return nil, err 128 } 129 130 // Test that client's command is long enough. It must be at least 6 bytes long 131 // to accomadate the version, command, reserved byte, address type, and 132 // destination port. 133 if bytes < 6 { 134 reply[0] = SocksVersion 135 reply[1] = SocksRepFailure 136 for i := 2; i < 6; i++ { 137 reply[i] = 0x00 138 } 139 defer c.Close() 140 if _, err = c.Write(reply[:6]); err != nil { 141 return nil, err 142 } 143 return nil, errors.New("socks: client sent a malformed command") 144 } 145 146 ver = int(msg[0]) 147 cmd := msg[1] 148 // msg[2] is a reserved byte in the protocol. 149 atyp := msg[3] 150 151 // Only CONNECT to IPv4 addresses is allowed. Since traffic will be proxied 152 // over the mixnet, don't connect to the intended host just yet. Reply to 153 // the client. 154 copy(reply, msg[:bytes]) 155 if ver == SocksVersion && cmd == SocksCmdConnect /* CONNECT */ && atyp == SocksAtypIPv4 /* IPv4 */ { 156 reply[1] = SocksRepSuccess 157 } else { 158 reply[1] = SocksRepUnsupported 159 } 160 if _, err = c.Write(reply[:bytes]); err != nil { 161 c.Close() 162 return nil, err 163 } 164 165 // dstAddr specifies the destination of the client. At this point the 166 // proxy is ready to construct a circuit and relay a message on behalf of 167 // the client. 168 port := strconv.Itoa((int(msg[bytes-2]) << 8) + int(msg[bytes-1])) 169 dstAddr := strconv.Itoa(int(msg[4])) + "." + 170 strconv.Itoa(int(msg[5])) + "." + 171 strconv.Itoa(int(msg[6])) + "." + 172 strconv.Itoa(int(msg[7])) + ":" + port 173 174 return &SocksConn{c, l.network, dstAddr}, nil 175 }