#include "socks++4.h"
#include "hosts.h"
#include <set>
namespace Security {
namespace IPPlusPlus {
namespace Socks4 {
void Server::connect(SocksClientSocket &me, const IPSockAddress &peer)
{
me.Socket::open(SOCK_STREAM);
me.Socket::connect(mServerAddress);
Message request(socksConnect, peer);
request.send(me, "nobody");
(Message(me)); me.mPeerAddress = peer; debug("socks", "%d socks4 connected to %s", me.fd(), string(peer).c_str());
}
void Server::connect(SocksClientSocket &me, const Host &host, IPPort port)
{
set<IPAddress> addrs = host.addresses();
for (set<IPAddress>::const_iterator it = addrs.begin(); it != addrs.end(); it++) {
try {
IPSockAddress addr(*it, port);
connect(me, addr);
return;
} catch (const UnixError &err) {
errno = err.error;
}
}
UnixError::throwMe();
}
void Server::bind(SocksServerSocket &me, const IPAddress &peer, IPPort port)
{
me.Socket::open(SOCK_STREAM);
me.Socket::connect(mServerAddress);
Message request(socksBind, IPSockAddress(peer, port));
request.send(me, "nobody");
Message reply(me);
me.mLocalAddress = reply.address().defaults(mServerAddress.address());
debug("socks", "%d socks4 bound to %s", me.fd(), string(me.mLocalAddress).c_str());
}
void Server::receive(SocksServerSocket &me, SocksClientSocket &receiver)
{
Message reply(me);
receiver.setFd(me.fd(), me.mLocalAddress, reply.address());
me.clear(); debug("socks", "%d socks4 inbound connect", receiver.fd());
}
Message::Message(Command cmd, const IPSockAddress &address)
: version(4), message(cmd), port(htons(address.port())), addr(address.address())
{
}
void Message::send(Socket &s, const char *userid)
{
if (s.write(this, sizeof(*this)) != sizeof(*this))
UnixError::throwMe();
size_t length = strlen(userid) + 1;
if (s.write(userid, length) != length) {
s.close();
UnixError::throwMe();
}
}
Message::Message(Socket &s)
{
if (s.read(this, sizeof(*this)) != sizeof(*this)) {
s.close();
UnixError::throwMe();
}
if (version != 0) {
s.close();
UnixError::throwMe(EPROTONOSUPPORT);
}
switch (message) {
case requestAccepted:
return;
default:
UnixError::throwMe(ECONNREFUSED); }
}
} } }