1/* 2 * Copyright (c) 2000-2004,2011,2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25// 26// socks++int - internal Socks implementation 27// 28#include "socks++5.h" 29#include "hosts.h" 30 31 32namespace Security { 33namespace IPPlusPlus { 34namespace Socks5 { 35 36 37// 38// Socks5 Protocol implementation 39// 40void Server::open(Socket &s, Support &my) 41{ 42 s.open(SOCK_STREAM); 43 s.connect(my.mServer->address()); 44 secdebug("socks", "%d connected to server %s", s.fd(), string(my.mServer->address()).c_str()); 45 Byte request[] = { 5, 1, socksAuthPublic }; 46 s.write(request, sizeof(request)); 47 Byte reply[2]; 48 s.read(reply, sizeof(reply)); 49 if (reply[0] != 5 || reply[1] != socksAuthPublic) { 50 secdebug("socks", "%d server failed (v%d auth=%d)", s.fd(), reply[0], reply[1]); 51 s.close(); 52 UnixError::throwMe(EPROTONOSUPPORT); 53 } 54} 55 56void Server::connect(SocksClientSocket &me, const IPSockAddress &peer) 57{ 58 open(me, me); 59 Message request(socksConnect, peer.address(), peer.port()); 60 request.send(me); 61 Message reply(me); 62 me.mLocalAddress = reply.address(); 63 me.mPeerAddress = peer; 64 secdebug("socks", "%d socks connected to %s", me.fd(), string(peer).c_str()); 65} 66 67void Server::connect(SocksClientSocket &me, const Host &host, IPPort port) 68{ 69#if 1 70 //@@@ should be using Hostname (server resolution) mode, but this won't get us 71 //@@@ any useful peer address to use for bind relaying. Need to rethink this scenario. 72 set<IPAddress> addrs = host.addresses(); 73 for (set<IPAddress>::const_iterator it = addrs.begin(); it != addrs.end(); it++) { 74 try { 75 IPSockAddress addr(*it, port); 76 connect(me, addr); 77 return; 78 } catch (const UnixError &err) { 79 errno = err.error; 80 } 81 } 82 // exhausted 83 UnixError::throwMe(); 84#else 85 open(me, me); 86 Message request(socksConnect, host.name().c_str(), port); 87 request.send(me); 88 Message reply(me); 89 me.mLocalAddress = reply.address(); 90 //me.mPeerAddress = not provided by Socks5 protocol; 91 secdebug("socks", "%d socks connected to %s", me.fd(), host.name().c_str()); 92#endif 93} 94 95 96void Server::bind(SocksServerSocket &me, const IPAddress &peer, IPPort port) 97{ 98 open(me, me); 99 Message request(socksBind, peer, port); 100 request.send(me); 101 Message reply(me); 102 me.mLocalAddress = reply.address(); 103 //me.mPeerAddress not available yet; 104 secdebug("socks", "%d socks bound to %s", me.fd(), string(me.mLocalAddress).c_str()); 105} 106 107void Server::receive(SocksServerSocket &me, SocksClientSocket &receiver) 108{ 109 Message reply(me); 110 receiver.setFd(me.fd(), me.mLocalAddress, reply.address()); 111 me.clear(); // clear our own (don't close on destruction) 112 secdebug("socks", "%d socks received from %s", receiver.fd(), string(reply.address()).c_str()); 113} 114 115 116// 117// Construct a request from an IPv4 address and port 118// 119Message::Message(Command cmd, IPAddress addr, IPPort port) 120{ 121 version = 5; 122 message = cmd; 123 reserved = 0; 124 addressType = socksIPv4; 125 this->addr = addr; 126 this->port = htons(port); 127 length = 4 + sizeof(this->addr) + sizeof(this->port); 128} 129 130 131// 132// Construct a request from a hostname and port (server resolves name) 133// 134Message::Message(Command cmd, const char *hostname, IPPort port) 135{ 136 version = 5; 137 message = cmd; 138 reserved = 0; 139 addressType = socksName; 140 141 size_t nameLength = strlen(hostname); 142 if (nameLength > 255) 143 UnixError::throwMe(ENAMETOOLONG); 144 char *addrp = reinterpret_cast<char *>(&addr); 145 addrp[0] = nameLength; 146 memcpy(addrp + 1, hostname, nameLength); 147 IPPort nboPort = htons(port); 148 memcpy(addrp + 1 + nameLength, &nboPort, sizeof(nboPort)); 149 length = 4 + 1 + nameLength + sizeof(nboPort); 150} 151 152 153// 154// Send a completed request message 155// 156void Message::send(Socket &s) 157{ 158 if (s.write(this, length) != length) { 159 s.close(); 160 UnixError::throwMe(EIO); 161 } 162} 163 164 165// 166// Construct a reply object from a socket source. 167// Throws exceptions if the reply is not successful and supported. 168// 169Message::Message(Socket &socket) 170{ 171 length = 4 + sizeof(addr) + sizeof(port); //@@@ calculate if addrType != 1 supported 172 173 if (socket.read(this, length) != length) { 174 socket.close(); 175 UnixError::throwMe(EIO); 176 } 177 178 // check error code 179 switch (message) { 180 case socksSuccess: 181 break; 182 case socksDenied: 183 UnixError::throwMe(EPERM); 184 case socksNetUnreach: 185 UnixError::throwMe(ENETUNREACH); 186 case socksHostUnreach: 187 UnixError::throwMe(EHOSTUNREACH); 188 case socksConRefused: 189 UnixError::throwMe(ECONNREFUSED); 190 case socksTTLExpired: 191 UnixError::throwMe(ETIMEDOUT); // not really, but what's better? 192 case socksUnsupported: 193 UnixError::throwMe(EOPNOTSUPP); 194 case socksAddressNotSupported: 195 UnixError::throwMe(EADDRNOTAVAIL); 196 default: 197 UnixError::throwMe(EIO); // what else? :-) 198 } 199 200 // can't deal with non-IPv4 address replies 201 if (addressType != socksIPv4 || reserved != 0) 202 UnixError::throwMe(ENOTSUP); 203} 204 205 206} // end namespace Socks 207} // end namespace IPPlusPlus 208} // end namespace Security 209