orgcandman |
02-04-2011 04:16 PM |
Quote:
Originally Posted by dwhitney67
(Post 4244880)
If you are indeed programming in C++, you could consider defining an object that represents the Socks5 packet that you require. Consider the following (untested) code. Btw, I haven't a clue about Sock5 (documentation is scant on the low-level API, and Wiki is of no real help), so I may have made some bad assumptions below; use at your own risk.
...
|
Your example is not the best. You have no idea how the compiler will structure "packet." And by that, I mean, you don't know if it's aligned properly (likely, it won't be with those unsigned chars) and you also have a "random" 255 byte structure in there.
An even better approach would be to modify your Sock5_packet structure to be a class with a serialize() / deserialize() interface, which takes a uint8_t * and a uint32_t reference. I'm envisioning the following:
Code:
#include <string>
#include <iostream>
#include <cassert>
#include <arpa/inet.h>
#include <string.h>
extern int Send(const void* data, const size_t size);
class Sock5_Packet
{
public:
enum Status { REQUEST=0, GEN_FAILURE, CONN_NOT_ALLOWED, NETWORK_UNREACHABLE, HOST_UNREACHABLE, CONN_REFUSED, TTL_EXPIRED, CMD_NOT_SUPPORTED, ADDR_NOT_SUPPORTED, UNKNOWN_STATUS };
enum AddrType { UNKNOWN_TYPE=0, IPV4 = 1, DOMAIN = 3, IPV6 = 4 };
Sock5_Packet();
virtual ~Sock5_Packet();
inline void setStatus(Status status) { m_Status = status; }
inline void setPort(uint16_t port) { m_Port = htons(port); }
int32_t setDestAddr(AddrType type, const uint8_t *bytes, uint32_t length);
inline const uint16_t getPort() const { return (const uint16_t)ntohs(m_Port); }
inline const Status getStatus() const { return (const Status)m_Status; }
void getDestAddr(AddrType &type, uint8_t *bytes, uint32_t &length) const;
int32_t serialize(uint8_t *, uint32_t &);
int32_t deserialize(uint8_t *, uint32_t &);
private:
Status m_Status;
AddrType m_AddrType;
uint8_t *m_DestAddrBytes;
uint32_t m_DestAddrBytesLen;
uint16_t m_Port;
};
Sock5_Packet :: Sock5_Packet() : m_Status(UNKNOWN_STATUS), m_AddrType(UNKNOWN_TYPE), m_DestAddrBytes(0), m_DestAddrBytesLen(0), m_Port(0)
{
}
Sock5_Packet :: ~Sock5_Packet()
{
if(m_DestAddrBytes) delete [] m_DestAddrBytes;
}
int32_t
Sock5_Packet :: setDestAddr(AddrType type, const uint8_t *bytes,
uint32_t length)
{
uint8_t *oldBytes = m_DestAddrBytes;
if(!bytes || !length) return -1;
switch(type)
{
case IPV4:
if(length != 4) return -1;
m_DestAddrBytes = new uint8_t[4];
*((uint32_t*)m_DestAddrBytes) = htonl(*((uint32_t*)bytes));
break;
case DOMAIN:
if(length > 255) return -1;
m_DestAddrBytes = new uint8_t[length];
strncpy((char *)m_DestAddrBytes, (char *)bytes, length);
m_DestAddrBytes[length - 1] = 0;
break;
case IPV6:
if(length != 16) return -1;
m_DestAddrBytes = new uint8_t[16];
memcpy(m_DestAddrBytes, bytes, 16);
break;
default:
return -1;
}
m_AddrType = type;
m_DestAddrBytesLen = length;
delete [] oldBytes;
return 0;
}
void
Sock5_Packet :: getDestAddr(AddrType &type, uint8_t *bytes, uint32_t &length) const
{
type = UNKNOWN_TYPE;
if(m_AddrType == type) return;
if(length < m_DestAddrBytesLen) return;
if(!bytes) return;
memcpy(bytes, m_DestAddrBytes, m_DestAddrBytesLen);
length = m_DestAddrBytesLen;
type = m_AddrType;
}
int32_t
Sock5_Packet :: serialize(uint8_t *out_bytes, uint32_t &out_byte_len)
{
//256 is "magic" and should really be changed
uint8_t buf[256] = {0};
if(!out_bytes) return -1;
// total size needed to serialize the packet ...
uint32_t nTotalSizeNeeded = 6; // 6 is "magic" since it's less than the minimum size
switch(m_AddrType)
{
case IPV4:
nTotalSizeNeeded += 4;
memcpy(buf, m_DestAddrBytes, m_DestAddrBytesLen);
break;
case DOMAIN:
nTotalSizeNeeded += 1 + m_DestAddrBytesLen;
buf[0] = (uint8_t)m_DestAddrBytesLen;
memcpy(buf+1, m_DestAddrBytes, m_DestAddrBytesLen);
break;
case IPV6:
nTotalSizeNeeded += 16;
memcpy(buf, m_DestAddrBytes, m_DestAddrBytesLen);
break;
default:
return -1;
}
if(out_byte_len < nTotalSizeNeeded) return -1;
out_bytes[0] = 5;
out_bytes[1] = (uint8_t)m_Status;
out_bytes[2] = 0x00;
out_bytes[3] = (uint8_t)m_AddrType;
memcpy(out_bytes+3, buf, nTotalSizeNeeded - 6);
*((uint16_t*)(out_bytes + nTotalSizeNeeded - 4)) = m_Port;
out_byte_len = nTotalSizeNeeded;
return 0;
}
int32_t
Sock5_Packet :: deserialize(uint8_t *, uint32_t &)
{
return -1; // exercise for the reader ....
}
int main()
{
const std::string domain("www.google.com");
const unsigned short port = 80;
uint8_t outbuf[1024] = {0};
uint32_t outbuflen = 1024;
assert(domain.size() <= 255);
Sock5_Packet packet;
packet.setStatus(Sock5_Packet::REQUEST);
packet.setPort(80);
packet.setDestAddr(Sock5_Packet::DOMAIN, (const uint8_t *)domain.c_str(), domain.size());
if(packet.serialize(outbuf, outbuflen) < 0) cout << "Failed to serialize\n";
Send(outbuf, outbuflen);
// ...
}
|