1/* 2 * Copyright (c) 2000-2004 Apple Computer, 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++4.h" 29#include "hosts.h" 30#include <set> 31 32 33namespace Security { 34namespace IPPlusPlus { 35namespace Socks4 { 36 37 38 39// 40// Socks4 Protocol implementation 41// 42void Server::connect(SocksClientSocket &me, const IPSockAddress &peer) 43{ 44 me.Socket::open(SOCK_STREAM); 45 me.Socket::connect(mServerAddress); 46 Message request(socksConnect, peer); 47 request.send(me, "nobody"); 48 (Message(me)); // read and check reply message 49 me.mPeerAddress = peer; // best guess, Mr. Sulu 50 secdebug("socks", "%d socks4 connected to %s", me.fd(), string(peer).c_str()); 51} 52 53void Server::connect(SocksClientSocket &me, const Host &host, IPPort port) 54{ 55 // Socks4 has no name resolution support. Do it here 56 //@@@ error reporting sucks here 57 set<IPAddress> addrs = host.addresses(); 58 for (set<IPAddress>::const_iterator it = addrs.begin(); it != addrs.end(); it++) { 59 try { 60 IPSockAddress addr(*it, port); 61 connect(me, addr); 62 return; 63 } catch (const UnixError &err) { 64 errno = err.error; 65 } 66 } 67 // exhausted 68 UnixError::throwMe(); 69} 70 71 72void Server::bind(SocksServerSocket &me, const IPAddress &peer, IPPort port) 73{ 74 me.Socket::open(SOCK_STREAM); 75 me.Socket::connect(mServerAddress); 76 Message request(socksBind, IPSockAddress(peer, port)); 77 request.send(me, "nobody"); 78 Message reply(me); 79 me.mLocalAddress = reply.address().defaults(mServerAddress.address()); 80 secdebug("socks", "%d socks4 bound to %s", me.fd(), string(me.mLocalAddress).c_str()); 81} 82 83void Server::receive(SocksServerSocket &me, SocksClientSocket &receiver) 84{ 85 Message reply(me); 86 receiver.setFd(me.fd(), me.mLocalAddress, reply.address()); 87 me.clear(); // clear our own (don't close on destruction) 88 secdebug("socks", "%d socks4 inbound connect", receiver.fd()); 89} 90 91 92// 93// Message properties 94// 95Message::Message(Command cmd, const IPSockAddress &address) 96 : version(4), message(cmd), port(htons(address.port())), addr(address.address()) 97{ 98} 99 100 101void Message::send(Socket &s, const char *userid) 102{ 103 if (s.write(this, sizeof(*this)) != sizeof(*this)) 104 UnixError::throwMe(); 105 // now append zero-terminated userid (what a crock) 106 size_t length = strlen(userid) + 1; 107 if (s.write(userid, length) != length) { 108 s.close(); 109 UnixError::throwMe(); 110 } 111} 112 113Message::Message(Socket &s) 114{ 115 if (s.read(this, sizeof(*this)) != sizeof(*this)) { 116 s.close(); 117 UnixError::throwMe(); 118 } 119 if (version != 0) { 120 s.close(); 121 UnixError::throwMe(EPROTONOSUPPORT); 122 } 123 switch (message) { 124 case requestAccepted: 125 return; 126 default: 127 UnixError::throwMe(ECONNREFUSED); //@@@ hardly any diagnostics here 128 } 129} 130 131 132} // end namespace Socks 133} // end namespace IPPlusPlus 134} // end namespace Security 135