Monday, October 27, 2014

SOCKS proxy client socket sample

I was shocked at the almost complete lack of code samples for establishing connections through a SOCKS proxy with network sockets in C. SOCKS protocol is specified in RFC 1928.

Here is code I have used successfully to connect to a locally installed Tor SOCKS proxy:


fd = socket(AF_INET, SOCK_STREAM, 0);

if (fd < 0)
{
 exit(1);
}

struct sockaddr_in s;

s.sin_family = AF_INET;

s.sin_port = htons(9050);
s.sin_addr.s_addr = inet_addr("127.0.0.1");

eid = connect(fd, (struct sockaddr *) &s, sizeof s); //Connect to Tor Proxy
if (eid < 0)
{
 exit(3);
}

//SOCKS 5 protocol stuff starts here
////////////////////////////////////////////////////////////////////////////////////////////////
char sbuffer[256];
char *ptrBuff;

ptrBuff = sbuffer;

*(ptrBuff++) = 0x05;          //socks protocol version 5

*(ptrBuff++) = 0x01;          // supporting 1 auth method, 1) no auth 2) user pass auth

*(ptrBuff++) = 0x00;


send(fd, sbuffer, ptrBuff - sbuffer, 0);

recv(fd, sbuffer, 2, 0);

if (sbuffer[1] == 0xFF || sbuffer[1] != 0x00)
{
 exit(1);
}

ptrBuff = sbuffer;
*(ptrBuff++) = 0x05;      // socks version
*(ptrBuff++) = 0x01;      // sending CONNECT command
*(ptrBuff++) = 0x00;      // Reserved
*(ptrBuff++) = 0x03;      // address type - 1 for IPV4, 3 for domain name

char* dest_addr = "irc.whatever.com";

*(ptrBuff++) = strlen(dest_addr); //first byte records length of domain name string (without the terminating NULL)

memcpy(ptrBuff, dest_addr, strlen(dest_addr));
ptrBuff += strlen(dest_addr);

unsigned int dest_port = 6667;

*(ptrBuff++) = (dest_port >> 8); //port in network byte order - reverse lil endian bytes in int
*(ptrBuff++) = (dest_port & 0xFF);
 

send(fd, sbuffer, ptrBuff - sbuffer, 0);

recv(fd, sbuffer, 3, 0);

if (sbuffer[1] != 0x00)
{
 exit(2);
}

//////////////////////////////////////////////////////////////////////////////////
// From here on write/read from the socket as if you were directly connected to
// the desired server