]>
git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/socks++5.cpp
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 // socks++int - internal Socks implementation
27 namespace IPPlusPlus
{
32 // Socks5 Protocol implementation
34 void Server::open(Socket
&s
, Support
&my
)
37 s
.connect(my
.mServer
->address());
38 debug("socks", "%d connected to server %s", s
.fd(), string(my
.mServer
->address()).c_str());
39 Byte request
[] = { 5, 1, socksAuthPublic
};
40 s
.write(request
, sizeof(request
));
42 s
.read(reply
, sizeof(reply
));
43 if (reply
[0] != 5 || reply
[1] != socksAuthPublic
) {
44 debug("socks", "%d server failed (v%d auth=%d)", s
.fd(), reply
[0], reply
[1]);
46 UnixError::throwMe(EPROTONOSUPPORT
);
50 void Server::connect(SocksClientSocket
&me
, const IPSockAddress
&peer
)
53 Message
request(socksConnect
, peer
.address(), peer
.port());
56 me
.mLocalAddress
= reply
.address();
57 me
.mPeerAddress
= peer
;
58 debug("socks", "%d socks connected to %s", me
.fd(), string(peer
).c_str());
61 void Server::connect(SocksClientSocket
&me
, const Host
&host
, IPPort port
)
64 //@@@ should be using Hostname (server resolution) mode, but this won't get us
65 //@@@ any useful peer address to use for bind relaying. Need to rethink this scenario.
66 set
<IPAddress
> addrs
= host
.addresses();
67 for (set
<IPAddress
>::const_iterator it
= addrs
.begin(); it
!= addrs
.end(); it
++) {
69 IPSockAddress
addr(*it
, port
);
72 } catch (const UnixError
&err
) {
80 Message
request(socksConnect
, host
.name().c_str(), port
);
83 me
.mLocalAddress
= reply
.address();
84 //me.mPeerAddress = not provided by Socks5 protocol;
85 debug("socks", "%d socks connected to %s", me
.fd(), host
.name().c_str());
90 void Server::bind(SocksServerSocket
&me
, const IPAddress
&peer
, IPPort port
)
93 Message
request(socksBind
, peer
, port
);
96 me
.mLocalAddress
= reply
.address();
97 //me.mPeerAddress not available yet;
98 debug("socks", "%d socks bound to %s", me
.fd(), string(me
.mLocalAddress
).c_str());
101 void Server::receive(SocksServerSocket
&me
, SocksClientSocket
&receiver
)
104 receiver
.setFd(me
.fd(), me
.mLocalAddress
, reply
.address());
105 me
.clear(); // clear our own (don't close on destruction)
106 debug("socks", "%d socks received from %s", receiver
.fd(), string(reply
.address()).c_str());
111 // Construct a request from an IPv4 address and port
113 Message::Message(Command cmd
, IPAddress addr
, IPPort port
)
118 addressType
= socksIPv4
;
120 this->port
= htons(port
);
121 length
= 4 + sizeof(this->addr
) + sizeof(this->port
);
126 // Construct a request from a hostname and port (server resolves name)
128 Message::Message(Command cmd
, const char *hostname
, IPPort port
)
133 addressType
= socksName
;
135 size_t nameLength
= strlen(hostname
);
136 if (nameLength
> 255)
137 UnixError::throwMe(ENAMETOOLONG
);
138 char *addrp
= reinterpret_cast<char *>(&addr
);
139 addrp
[0] = nameLength
;
140 memcpy(addrp
+ 1, hostname
, nameLength
);
141 IPPort nboPort
= htons(port
);
142 memcpy(addrp
+ 1 + nameLength
, &nboPort
, sizeof(nboPort
));
143 length
= 4 + 1 + nameLength
+ sizeof(nboPort
);
148 // Send a completed request message
150 void Message::send(Socket
&s
)
152 if (s
.write(this, length
) != length
) {
154 UnixError::throwMe(EIO
);
160 // Construct a reply object from a socket source.
161 // Throws exceptions if the reply is not successful and supported.
163 Message::Message(Socket
&socket
)
165 length
= 4 + sizeof(addr
) + sizeof(port
); //@@@ calculate if addrType != 1 supported
167 if (socket
.read(this, length
) != length
) {
169 UnixError::throwMe(EIO
);
177 UnixError::throwMe(EPERM
);
178 case socksNetUnreach
:
179 UnixError::throwMe(ENETUNREACH
);
180 case socksHostUnreach
:
181 UnixError::throwMe(EHOSTUNREACH
);
182 case socksConRefused
:
183 UnixError::throwMe(ECONNREFUSED
);
184 case socksTTLExpired
:
185 UnixError::throwMe(ETIMEDOUT
); // not really, but what's better?
186 case socksUnsupported
:
187 UnixError::throwMe(EOPNOTSUPP
);
188 case socksAddressNotSupported
:
189 UnixError::throwMe(EADDRNOTAVAIL
);
191 UnixError::throwMe(EIO
); // what else? :-)
194 // can't deal with non-IPv4 address replies
195 if (addressType
!= socksIPv4
|| reserved
!= 0)
196 UnixError::throwMe(ENOTSUP
);
200 } // end namespace Socks
201 } // end namespace IPPlusPlus
202 } // end namespace Security