]> git.saurik.com Git - apple/security.git/blame - cdsa/cdsa_utilities/socks++.h
Security-30.1.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / socks++.h
CommitLineData
bac41a7b
A
1/*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19//
20// socks - socks version of IP sockets
21//
22// This Socks implementation replaces the TCP-functional layer of the socket interface
23// (TCPClientSocket and TCPServerSocket), not the raw Socket layer. Remember what
24// Socks was invented for -- it's NOT a generic socket abstraction layer, valiant efforts
25// of the various -lsocks libraries nonwithstanding.
26// Do note that these are not virtual overrides, but textual replacements.
27//
28// This implementation supports Socks versions 4 and 5, as well as direct (un-socksed) sockets.
29// The choice is per socket object.
30//
31// API Synopsis:
32// SocksServer *server = SocksServer::make(version, IP-address);
33// SocksServer::defaultServer(server); // for new sockets
34// SocksClientSocket clientSocket(...);
35// clientSocket.server(server); // for this socket
36// SocksServerSocket serverSocket(...); // only supports .receive()
37// Otherwise, Socks{Client,Server}Socket is functionally equivalent to {Client,Server}Socket.
38// Sockets without a Server (explicit or by default) are direct.
39//
40// Minimum replacement strategy:
41// #define TCPClientSocket SocksClientSocket
42// #define TCPServerSocket SocksServerSocket
43// SocksServer::defaultServer(SocksServer::make(...));
44//
45// Limitations:
46// There is no UDP Socks support.
47// @@@ Nonblocking sockets may not work quite right.
48//
49#ifndef _H_SOCKSPLUSPLUS
50#define _H_SOCKSPLUSPLUS
51
52#include "ip++.h"
53#include <Security/threading.h>
54#include <Security/globalizer.h>
55
56
57using namespace UnixPlusPlus;
58
59
60namespace Security {
61namespace IPPlusPlus {
62
63
64class SocksServerSocket;
65class SocksClientSocket;
66
67
68//
69// A particular Socks server and version. Get one by calling SocksServer::make().
70// You can express "no socks server" (direct connect) with a NULL pointer (or version==0).
71//
72class SocksServer {
73 class Support; friend class Support;
74
75private:
76 struct Global {
77 mutable Mutex lock; // lock for mGlobalServerAddress
78 SocksServer *mServer; // global default server
79 ThreadNexus<IPAddress> lastConnected; // last address connected to (for aux. bind)
80
81 Global() : mServer(NULL) { }
82
83 void server(SocksServer *srv) { StLock<Mutex> _(lock); mServer = srv; }
84 SocksServer *server() const { StLock<Mutex> _(lock); return mServer; }
85 };
86 static ModuleNexus<Global> global; // global state
87
88public:
89 typedef unsigned int Version;
90
91 static SocksServer *make(Version version, const IPSockAddress &addr);
92
93 const IPSockAddress &address() const { return mServerAddress; }
94 Version version() const { return mVersion; }
95
96public:
97 static SocksServer *defaultServer() { return global().server(); }
98 static void defaultServer(SocksServer *server) { global().server(server); }
99
100protected:
101 virtual void connect(SocksClientSocket &me, const IPSockAddress &peer) = 0;
102 virtual void connect(SocksClientSocket &me, const Host &host, IPPort port) = 0;
103 virtual void bind(SocksServerSocket &me, const IPAddress &peer, IPPort port) = 0;
104 virtual void receive(SocksServerSocket &me, SocksClientSocket &receiver) = 0;
105
106 SocksServer(Version v, const IPSockAddress &addr) : mVersion(v), mServerAddress(addr) { }
107
108protected:
109 Version mVersion;
110 IPSockAddress mServerAddress;
111
112protected:
113 class Support {
114 public:
115 SocksServer *server() const { return mServer; }
116 void server(SocksServer *srv) { mServer = srv; }
117
118 IPSockAddress localAddress(const Socket &me) const;
119 IPSockAddress peerAddress(const Socket &me) const;
120
121 protected:
122 Support() : mServer(defaultServer()) { }
123
124 void connect(SocksClientSocket &me, const IPSockAddress &peer)
125 { mServer->connect(me, peer); }
126 void connect(SocksClientSocket &me, const Host &host, IPPort port)
127 { mServer->connect(me, host, port); }
128 void bind(SocksServerSocket &me, const IPAddress &peer, IPPort port)
129 { mServer->bind(me, peer, port); }
130 void receive(SocksServerSocket &me, SocksClientSocket &receiver)
131 { mServer->receive(me, receiver); }
132
133 void lastConnected(IPAddress addr) { global().lastConnected() = addr; }
134 IPAddress lastConnected() const { return global().lastConnected(); }
135
136 public:
137 SocksServer *mServer; // server for this socket
138 IPSockAddress mLocalAddress; // my own address, as reported by server
139 IPSockAddress mPeerAddress; // peer address
140 };
141};
142
143
144//
145// The Socks version of a TCPClientSocket
146//
147class SocksClientSocket : public TCPClientSocket, public SocksServer::Support {
148public:
149 SocksClientSocket() { }
150 SocksClientSocket(const IPSockAddress &peer) { open(peer); }
151 SocksClientSocket(const IPAddress &addr, IPPort port) { open(addr, port); }
152 SocksClientSocket(const Host &host, IPPort port) { open(host, port); }
153
154 void open(const IPSockAddress &peer);
155 void open(const IPAddress &addr, IPPort port);
156 void open(const Host &host, IPPort port);
157
158 IPSockAddress localAddress() const { return Support::localAddress(*this); }
159 IPSockAddress peerAddress() const { return Support::peerAddress(*this); }
160
161public:
162 void setFd(int fd, const IPSockAddress &local, const IPSockAddress &peer);
163};
164
165
166//
167// The Socks version of a TCPServerSocket.
168// Note that this version only supports the receive() access method.
169// By the nature of things, the queue-length argument is ignored (it's always 1).
170//
171// A note about setMainConnection: There is a structural problem
172// with the Socks protocol. When a SocksServerSocket goes active,
173// the protocol requires the IP address of the host the connection will be
174// coming from. Typical Socks library layers simply assume that this will
175// be the address of the last server connected to by another (TCP) socket.
176// We do this heuristic too, but it's unreliable: it's a per-thread global, and will
177// fail if you interleave multiple socks "sessions" in the same thread. For this
178// case (or if you just want to be safe and explicit), you can call setMainConnection to
179// explicitly link this socket to a TCPClientSocket whose peer we should use.
180// Do note that this call does not exist in the plain (non-socks) socket layer.
181//
182class SocksServerSocket : public TCPServerSocket, public SocksServer::Support {
183public:
184 SocksServerSocket() { }
185 SocksServerSocket(const IPSockAddress &local, int = 1) { open(local); }
186 SocksServerSocket(IPPort port, int = 1) { open(port); }
187
188 void open(const IPSockAddress &local, int = 1);
189 void open(IPPort port = 0, int = 1)
190 { open(IPSockAddress(IPAddress::any, port)); }
191
192 void receive(SocksClientSocket &client); // accept incoming and close listener
193
194 IPSockAddress localAddress() const { return Support::localAddress(*this); }
195 IPSockAddress peerAddress() const { return Support::peerAddress(*this); }
196
197 // this special call is not an overlay of TCPServerSocket - it exists only for Socks
198 void setMainConnection(TCPClientSocket &main)
199 { mConnectionPeer = main.peerAddress().address(); }
200
201private:
202 IPAddress mConnectionPeer; // address to say we're peered with
203
204private:
205 void operator () (TCPClientSocket &newClient); // not supported by Socks
206};
207
208
209} // end namespace IPPlusPlus
210} // end namespace Security
211
212
213#endif //_H_IPPLUSPLUS