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 - socks version of IP sockets 27// 28// This Socks implementation replaces the TCP-functional layer of the socket interface 29// (TCPClientSocket and TCPServerSocket), not the raw Socket layer. Remember what 30// Socks was invented for -- it's NOT a generic socket abstraction layer, valiant efforts 31// of the various -lsocks libraries nonwithstanding. 32// Do note that these are not virtual overrides, but textual replacements. 33// 34// This implementation supports Socks versions 4 and 5, as well as direct (un-socksed) sockets. 35// The choice is per socket object. 36// 37// API Synopsis: 38// SocksServer *server = SocksServer::make(version, IP-address); 39// SocksServer::defaultServer(server); // for new sockets 40// SocksClientSocket clientSocket(...); 41// clientSocket.server(server); // for this socket 42// SocksServerSocket serverSocket(...); // only supports .receive() 43// Otherwise, Socks{Client,Server}Socket is functionally equivalent to {Client,Server}Socket. 44// Sockets without a Server (explicit or by default) are direct. 45// 46// Minimum replacement strategy: 47// #define TCPClientSocket SocksClientSocket 48// #define TCPServerSocket SocksServerSocket 49// SocksServer::defaultServer(SocksServer::make(...)); 50// 51// Limitations: 52// There is no UDP Socks support. 53// @@@ Nonblocking sockets may not work quite right. 54// 55#ifndef _H_SOCKSPLUSPLUS 56#define _H_SOCKSPLUSPLUS 57 58#include "ip++.h" 59#include <security_utilities/threading.h> 60#include <security_utilities/globalizer.h> 61 62 63using namespace UnixPlusPlus; 64 65 66namespace Security { 67namespace IPPlusPlus { 68 69 70class SocksServerSocket; 71class SocksClientSocket; 72 73 74// 75// A particular Socks server and version. Get one by calling SocksServer::make(). 76// You can express "no socks server" (direct connect) with a NULL pointer (or version==0). 77// 78class SocksServer { 79public: 80 class Support; friend class Support; 81 82private: 83 struct Global { 84 mutable Mutex lock; // lock for mGlobalServerAddress 85 SocksServer *mServer; // global default server 86 ThreadNexus<IPAddress> lastConnected; // last address connected to (for aux. bind) 87 88 Global() : mServer(NULL) { } 89 90 void server(SocksServer *srv) { StLock<Mutex> _(lock); mServer = srv; } 91 SocksServer *server() const { StLock<Mutex> _(lock); return mServer; } 92 }; 93 static ModuleNexus<Global> global; // global state 94 95public: 96 typedef unsigned int Version; 97 98 static SocksServer *make(Version version, const IPSockAddress &addr); 99 100 const IPSockAddress &address() const { return mServerAddress; } 101 Version version() const { return mVersion; } 102 103public: 104 static SocksServer *defaultServer() { return global().server(); } 105 static void defaultServer(SocksServer *server) { global().server(server); } 106 107protected: 108 virtual ~SocksServer(); 109 110 virtual void connect(SocksClientSocket &me, const IPSockAddress &peer) = 0; 111 virtual void connect(SocksClientSocket &me, const Host &host, IPPort port) = 0; 112 virtual void bind(SocksServerSocket &me, const IPAddress &peer, IPPort port) = 0; 113 virtual void receive(SocksServerSocket &me, SocksClientSocket &receiver) = 0; 114 115 SocksServer(Version v, const IPSockAddress &addr) : mVersion(v), mServerAddress(addr) { } 116 117protected: 118 Version mVersion; 119 IPSockAddress mServerAddress; 120 121public: 122 class Support { 123 public: 124 SocksServer *server() const { return mServer; } 125 void server(SocksServer *srv) { mServer = srv; } 126 127 IPSockAddress localAddress(const Socket &me) const; 128 IPSockAddress peerAddress(const Socket &me) const; 129 130 protected: 131 Support() : mServer(defaultServer()) { } 132 133 void connect(SocksClientSocket &me, const IPSockAddress &peer) 134 { mServer->connect(me, peer); } 135 void connect(SocksClientSocket &me, const Host &host, IPPort port) 136 { mServer->connect(me, host, port); } 137 void bind(SocksServerSocket &me, const IPAddress &peer, IPPort port) 138 { mServer->bind(me, peer, port); } 139 void receive(SocksServerSocket &me, SocksClientSocket &receiver) 140 { mServer->receive(me, receiver); } 141 142 void lastConnected(IPAddress addr) { global().lastConnected() = addr; } 143 IPAddress lastConnected() const { return global().lastConnected(); } 144 145 public: 146 SocksServer *mServer; // server for this socket 147 IPSockAddress mLocalAddress; // my own address, as reported by server 148 IPSockAddress mPeerAddress; // peer address 149 }; 150}; 151 152 153// 154// The Socks version of a TCPClientSocket 155// 156class SocksClientSocket : public TCPClientSocket, public SocksServer::Support { 157public: 158 SocksClientSocket() { } 159 SocksClientSocket(const IPSockAddress &peer) { open(peer); } 160 SocksClientSocket(const IPAddress &addr, IPPort port) { open(addr, port); } 161 SocksClientSocket(const Host &host, IPPort port) { open(host, port); } 162 163 void open(const IPSockAddress &peer); 164 void open(const IPAddress &addr, IPPort port); 165 void open(const Host &host, IPPort port); 166 167 IPSockAddress localAddress() const { return Support::localAddress(*this); } 168 IPSockAddress peerAddress() const { return Support::peerAddress(*this); } 169 170public: 171 void setFd(int fd, const IPSockAddress &local, const IPSockAddress &peer); 172}; 173 174 175// 176// The Socks version of a TCPServerSocket. 177// Note that this version only supports the receive() access method. 178// By the nature of things, the queue-length argument is ignored (it's always 1). 179// 180// A note about setMainConnection: There is a structural problem 181// with the Socks protocol. When a SocksServerSocket goes active, 182// the protocol requires the IP address of the host the connection will be 183// coming from. Typical Socks library layers simply assume that this will 184// be the address of the last server connected to by another (TCP) socket. 185// We do this heuristic too, but it's unreliable: it's a per-thread global, and will 186// fail if you interleave multiple socks "sessions" in the same thread. For this 187// case (or if you just want to be safe and explicit), you can call setMainConnection to 188// explicitly link this socket to a TCPClientSocket whose peer we should use. 189// Do note that this call does not exist in the plain (non-socks) socket layer. 190// 191class SocksServerSocket : public TCPServerSocket, public SocksServer::Support { 192public: 193 SocksServerSocket() { } 194 SocksServerSocket(const IPSockAddress &local, int = 1) { open(local); } 195 SocksServerSocket(IPPort port, int = 1) { open(port); } 196 197 void open(const IPSockAddress &local, int = 1); 198 void open(IPPort port = 0, int = 1) 199 { open(IPSockAddress(IPAddress::any, port)); } 200 201 void receive(SocksClientSocket &client); // accept incoming and close listener 202 203 IPSockAddress localAddress() const { return Support::localAddress(*this); } 204 IPSockAddress peerAddress() const { return Support::peerAddress(*this); } 205 206 // this special call is not an overlay of TCPServerSocket - it exists only for Socks 207 void setMainConnection(TCPClientSocket &main) 208 { mConnectionPeer = main.peerAddress().address(); } 209 210private: 211 IPAddress mConnectionPeer; // address to say we're peered with 212 213private: 214 void operator () (TCPClientSocket &newClient); // not supported by Socks 215}; 216 217 218} // end namespace IPPlusPlus 219} // end namespace Security 220 221 222#endif //_H_IPPLUSPLUS 223