--- /dev/null
+/*
+ * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+//
+// socks - socks version of IP sockets
+//
+// This Socks implementation replaces the TCP-functional layer of the socket interface
+// (TCPClientSocket and TCPServerSocket), not the raw Socket layer. Remember what
+// Socks was invented for -- it's NOT a generic socket abstraction layer, valiant efforts
+// of the various -lsocks libraries nonwithstanding.
+// Do note that these are not virtual overrides, but textual replacements.
+//
+// This implementation supports Socks versions 4 and 5, as well as direct (un-socksed) sockets.
+// The choice is per socket object.
+//
+// API Synopsis:
+// SocksServer *server = SocksServer::make(version, IP-address);
+// SocksServer::defaultServer(server); // for new sockets
+// SocksClientSocket clientSocket(...);
+// clientSocket.server(server); // for this socket
+// SocksServerSocket serverSocket(...); // only supports .receive()
+// Otherwise, Socks{Client,Server}Socket is functionally equivalent to {Client,Server}Socket.
+// Sockets without a Server (explicit or by default) are direct.
+//
+// Minimum replacement strategy:
+// #define TCPClientSocket SocksClientSocket
+// #define TCPServerSocket SocksServerSocket
+// SocksServer::defaultServer(SocksServer::make(...));
+//
+// Limitations:
+// There is no UDP Socks support.
+// @@@ Nonblocking sockets may not work quite right.
+//
+#ifndef _H_SOCKSPLUSPLUS
+#define _H_SOCKSPLUSPLUS
+
+#include "ip++.h"
+#include <security_utilities/threading.h>
+#include <security_utilities/globalizer.h>
+
+
+using namespace UnixPlusPlus;
+
+
+namespace Security {
+namespace IPPlusPlus {
+
+
+class SocksServerSocket;
+class SocksClientSocket;
+
+
+//
+// A particular Socks server and version. Get one by calling SocksServer::make().
+// You can express "no socks server" (direct connect) with a NULL pointer (or version==0).
+//
+class SocksServer {
+public:
+ class Support; friend class Support;
+
+private:
+ struct Global {
+ mutable Mutex lock; // lock for mGlobalServerAddress
+ SocksServer *mServer; // global default server
+ ThreadNexus<IPAddress> lastConnected; // last address connected to (for aux. bind)
+
+ Global() : mServer(NULL) { }
+
+ void server(SocksServer *srv) { StLock<Mutex> _(lock); mServer = srv; }
+ SocksServer *server() const { StLock<Mutex> _(lock); return mServer; }
+ };
+ static ModuleNexus<Global> global; // global state
+
+public:
+ typedef unsigned int Version;
+
+ static SocksServer *make(Version version, const IPSockAddress &addr);
+
+ const IPSockAddress &address() const { return mServerAddress; }
+ Version version() const { return mVersion; }
+
+public:
+ static SocksServer *defaultServer() { return global().server(); }
+ static void defaultServer(SocksServer *server) { global().server(server); }
+
+protected:
+ virtual ~SocksServer();
+
+ virtual void connect(SocksClientSocket &me, const IPSockAddress &peer) = 0;
+ virtual void connect(SocksClientSocket &me, const Host &host, IPPort port) = 0;
+ virtual void bind(SocksServerSocket &me, const IPAddress &peer, IPPort port) = 0;
+ virtual void receive(SocksServerSocket &me, SocksClientSocket &receiver) = 0;
+
+ SocksServer(Version v, const IPSockAddress &addr) : mVersion(v), mServerAddress(addr) { }
+
+protected:
+ Version mVersion;
+ IPSockAddress mServerAddress;
+
+public:
+ class Support {
+ public:
+ SocksServer *server() const { return mServer; }
+ void server(SocksServer *srv) { mServer = srv; }
+
+ IPSockAddress localAddress(const Socket &me) const;
+ IPSockAddress peerAddress(const Socket &me) const;
+
+ protected:
+ Support() : mServer(defaultServer()) { }
+
+ void connect(SocksClientSocket &me, const IPSockAddress &peer)
+ { mServer->connect(me, peer); }
+ void connect(SocksClientSocket &me, const Host &host, IPPort port)
+ { mServer->connect(me, host, port); }
+ void bind(SocksServerSocket &me, const IPAddress &peer, IPPort port)
+ { mServer->bind(me, peer, port); }
+ void receive(SocksServerSocket &me, SocksClientSocket &receiver)
+ { mServer->receive(me, receiver); }
+
+ void lastConnected(IPAddress addr) { global().lastConnected() = addr; }
+ IPAddress lastConnected() const { return global().lastConnected(); }
+
+ public:
+ SocksServer *mServer; // server for this socket
+ IPSockAddress mLocalAddress; // my own address, as reported by server
+ IPSockAddress mPeerAddress; // peer address
+ };
+};
+
+
+//
+// The Socks version of a TCPClientSocket
+//
+class SocksClientSocket : public TCPClientSocket, public SocksServer::Support {
+public:
+ SocksClientSocket() { }
+ SocksClientSocket(const IPSockAddress &peer) { open(peer); }
+ SocksClientSocket(const IPAddress &addr, IPPort port) { open(addr, port); }
+ SocksClientSocket(const Host &host, IPPort port) { open(host, port); }
+
+ void open(const IPSockAddress &peer);
+ void open(const IPAddress &addr, IPPort port);
+ void open(const Host &host, IPPort port);
+
+ IPSockAddress localAddress() const { return Support::localAddress(*this); }
+ IPSockAddress peerAddress() const { return Support::peerAddress(*this); }
+
+public:
+ void setFd(int fd, const IPSockAddress &local, const IPSockAddress &peer);
+};
+
+
+//
+// The Socks version of a TCPServerSocket.
+// Note that this version only supports the receive() access method.
+// By the nature of things, the queue-length argument is ignored (it's always 1).
+//
+// A note about setMainConnection: There is a structural problem
+// with the Socks protocol. When a SocksServerSocket goes active,
+// the protocol requires the IP address of the host the connection will be
+// coming from. Typical Socks library layers simply assume that this will
+// be the address of the last server connected to by another (TCP) socket.
+// We do this heuristic too, but it's unreliable: it's a per-thread global, and will
+// fail if you interleave multiple socks "sessions" in the same thread. For this
+// case (or if you just want to be safe and explicit), you can call setMainConnection to
+// explicitly link this socket to a TCPClientSocket whose peer we should use.
+// Do note that this call does not exist in the plain (non-socks) socket layer.
+//
+class SocksServerSocket : public TCPServerSocket, public SocksServer::Support {
+public:
+ SocksServerSocket() { }
+ SocksServerSocket(const IPSockAddress &local, int = 1) { open(local); }
+ SocksServerSocket(IPPort port, int = 1) { open(port); }
+
+ void open(const IPSockAddress &local, int = 1);
+ void open(IPPort port = 0, int = 1)
+ { open(IPSockAddress(IPAddress::any, port)); }
+
+ void receive(SocksClientSocket &client); // accept incoming and close listener
+
+ IPSockAddress localAddress() const { return Support::localAddress(*this); }
+ IPSockAddress peerAddress() const { return Support::peerAddress(*this); }
+
+ // this special call is not an overlay of TCPServerSocket - it exists only for Socks
+ void setMainConnection(TCPClientSocket &main)
+ { mConnectionPeer = main.peerAddress().address(); }
+
+private:
+ IPAddress mConnectionPeer; // address to say we're peered with
+
+private:
+ void operator () (TCPClientSocket &newClient); // not supported by Socks
+};
+
+
+} // end namespace IPPlusPlus
+} // end namespace Security
+
+
+#endif //_H_IPPLUSPLUS