]>
git.saurik.com Git - apple/security.git/blob - Security/libsecurity_utilities/lib/socks++5.cpp
2 * Copyright (c) 2000-2004,2011,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 // socks++int - internal Socks implementation
33 namespace IPPlusPlus
{
38 // Socks5 Protocol implementation
40 void Server::open(Socket
&s
, Support
&my
)
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
));
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]);
52 UnixError::throwMe(EPROTONOSUPPORT
);
56 void Server::connect(SocksClientSocket
&me
, const IPSockAddress
&peer
)
59 Message
request(socksConnect
, peer
.address(), peer
.port());
62 me
.mLocalAddress
= reply
.address();
63 me
.mPeerAddress
= peer
;
64 secdebug("socks", "%d socks connected to %s", me
.fd(), string(peer
).c_str());
67 void Server::connect(SocksClientSocket
&me
, const Host
&host
, IPPort port
)
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
++) {
75 IPSockAddress
addr(*it
, port
);
78 } catch (const UnixError
&err
) {
86 Message
request(socksConnect
, host
.name().c_str(), port
);
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());
96 void Server::bind(SocksServerSocket
&me
, const IPAddress
&peer
, IPPort port
)
99 Message
request(socksBind
, peer
, port
);
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());
107 void Server::receive(SocksServerSocket
&me
, SocksClientSocket
&receiver
)
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());
117 // Construct a request from an IPv4 address and port
119 Message::Message(Command cmd
, IPAddress addr
, IPPort port
)
124 addressType
= socksIPv4
;
126 this->port
= htons(port
);
127 length
= 4 + sizeof(this->addr
) + sizeof(this->port
);
132 // Construct a request from a hostname and port (server resolves name)
134 Message::Message(Command cmd
, const char *hostname
, IPPort port
)
139 addressType
= socksName
;
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
);
154 // Send a completed request message
156 void Message::send(Socket
&s
)
158 if (s
.write(this, length
) != length
) {
160 UnixError::throwMe(EIO
);
166 // Construct a reply object from a socket source.
167 // Throws exceptions if the reply is not successful and supported.
169 Message::Message(Socket
&socket
)
171 length
= 4 + sizeof(addr
) + sizeof(port
); //@@@ calculate if addrType != 1 supported
173 if (socket
.read(this, length
) != length
) {
175 UnixError::throwMe(EIO
);
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
);
197 UnixError::throwMe(EIO
); // what else? :-)
200 // can't deal with non-IPv4 address replies
201 if (addressType
!= socksIPv4
|| reserved
!= 0)
202 UnixError::throwMe(ENOTSUP
);
206 } // end namespace Socks
207 } // end namespace IPPlusPlus
208 } // end namespace Security