SOCKS'´┐Ża Firewall Realization on an Object-Oriented Basis

Environment: Windows NT/2000/XP

-->

Introduction

The SOCKS firewall is a program that is capable of secured proxying, being compatible with various authentcation levels. However, as described in RFC 1928, there is currently only basic authentication. In this conspect, we will try to compose the SOCKS model for proper implementation of firewall architecture design for both current standard and further developing.

Development

Figure 1 shows the hierarchy of SOCKS implementation. As can be seen, 'CSocks4' and 'CSocks5' inherit common connection-accept routines. The difference is how each type of firewall is proxying the incoming client request by virtual method 'CSocks::ForceConnection(u_int sock)'. To create multi-threaded applications using this class and maybe trace connections, the 'pNotifyProc' is defined; it is a pointer to the procedure of type u_int PSOCKSNOTIFYPROC(u_int sock). After the connection has come, the call traps to this procedure.

After client request has succeeded, the SOCKS firewall changes its state to the negotiation level using 'CSocks::SocksTCPTunneling' for TCP mode or 'CSocks::SocksUDPTunneling' for UDP-bound mode.

Further Improvement of the SOCKS Standard

For this time, SOCKS firewall can be compatible only with the basic authentication level. However, it's possible to introduce additional SASL layer(s) (for instance, OpenSSL).

Creating a Multi-Threaded SOCKS Firewall

In demo below, we will create a multi-threaded SOCKS server using a trace map by programming a notification procedure map. This demo works on Linux/SCO/NetBSD and, of course, Win32.

/*
 * Copyright 2003 © Alumni<alumni@ok.kz>,
 * A basic multi-threaded SOCKS firewall
 * Platforms: Win32, NetBSD
 * To compile on NetBSD: set '#define _NETBSD_SOCKS'
 */


#include "common.h"
#include "csocks4.h"
#include "csocks5.h"

#undef USE_SOCKS4
#undef USE_SOCKS5
#undef _SOCKS_MULTIHTREADED


#define USE_SOCKS5
#define _SOCKS_MULTITHREADED
#define MAX_THREAD_COUNT 17

#ifdef USE_SOCKS4
#define CSocksType CSocks4
#else
#define CSocksType CSocks5
#endif


#ifndef _SOCKS_MULTITHREADED
CSocksType* socks;

#elif defined(_WIN32_SOCKS) && defined(_SOCKS_MULTITHREADED)
CRITICAL_SECTION cs;
static u_int uTotalThreads;
static u_long uThreads[MAX_THREAD_COUNT];
static CSocksType* socks[MAX_THREAD_COUNT];

u_int GetFreeIndex();
u_int SocksSerialize();
u_long WINAPI SocksThread(LPVOID pParam);
bool DeleteThread(CSocksType* pSock);
u_int __stdcall NotifyProc(u_int sock);



u_int GetFreeIndex()
{
  for(u_int i=0;i<MAX_THREAD_COUNT;i++) if(socks[i]==NULL)
                                           return(i);
  return(-1);
}


u_int SocksSerialize()
{
  u_int i = GetFreeIndex();

  if(uTotalThreads>=MAX_THREAD_COUNT || i==-1) return(-1);
  try {
    socks[i] = new CSocksType();
    uTotalThreads++;
    socks[i]->pNotifyProc = socks[0]->pNotifyProc;
  }
  catch(...) {
    perror("Error during SOCKS serialization\n");
    return(-1);
  };

  return(i);
  


bool DeleteThread(CSocksType* pSock)
{
  u_int i;
  try {
    for(i=0;i<MAX_THREAD_COUNT;i++)
      if(socks[i]==pSock)
      {
        delete socks[i];
        socks[i] = NULL;
        return(true);
      }
  }
  catch(...) { return(false); };
  return(false);
}



u_long WINAPI SocksThread(LPVOID pParam)
{
  CSocksType* pSocks = (CSocksType*)pParam;

  try {
    pSocks->ForceConnection(pSocks->uAccept);
    closesock(pSocks->uAccept);
    if(pSocks->LastError!=SOCKS_ERROR_NONE)
       fprintf(stdout,"Error: %s\n",pSocks->GetLastError());
    EnterCriticalSection(&cs);
    DeleteThread(pSocks);
    LeaveCriticalSection(&cs);
  }
  catch(...) {
    perror("SocksThread caused exception\n");
  };

  EnterCriticalSection(&cs);
  uTotalThreads--;
  LeaveCriticalSection(&cs);
  return(1);
}


u_int __stdcall NotifyProc(u_int sock)
{
  register u_int i;
  HANDLE hThread;

  EnterCriticalSection(&cs);
  try {
    if((i = SocksSerialize())!=-1)
    {
      socks[i]->uAccept = sock;
      hThread = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)
                SocksThread, socks[i],CREATE_SUSPENDED,
               &uThreads[i]);
      if(hThread==NULL)
      {
        uTotalThreads--;
        delete socks[i];
        socks[i] = NULL;
      }
    }
    else closesock(sock);
  }
  catch(...)
  {
    perror("NotifyProc caused exception\n"); 
    closesock(sock);
  };
  LeaveCriticalSection(&cs);
  if(hThread) ResumeThread(hThread);
  return(1);
}
#elif defined(_NETBSD_SOCKS) && defined(_SOCKS_MULTITHREADED)
CSocksType socks;
u_int __stdcall NotifyProc(u_int sock);

u_int __stdcall NotifyProc(u_int sock)
{
  if(sock) socks.ForceConnection(sock);
  if(fork()==-1) exit(0);
  socks.PrepareListening();
  socks.StartChaining();
  exit(0);
  return(1);
}

#endif


int main(int argc, char** argv)
{
#ifdef _WIN32_SOCKS
  WSAData wsadata;
  if(WSAStartup(0x002,&wsadata)) exit(1);
#ifdef _SOCKS_MULTITHREADED
  InitializeCriticalSection(&cs);
  for(u_int i=0;i<MAX_THREAD_COUNT;i++) socks[i] = NULL;
  uTotalThreads = 0;
#endif    //_SOCKS_MULTITHREADED
#endif    //_WIN32_SOCKS


#ifndef _SOCKS_MULTITHREADED
  socks = new CSocksType();
  if(!socks->PrepareListening()) exit(1);
  for(;;)
  {
    try {
      socks->LastError = SOCKS_ERROR_NONE;
      socks->StartChaining();
      if(socks->LastError!=SOCKS_ERROR_NONE)
         fprintf(stdout,"Error: %s\n",socks->GetLastError());
      fprintf(stdout,"\n");
    }
    catch(...)
    {
      perror("Undefined exception handled: exitting abnormally\n");
      exit(1);
    };
  }
#elif defined(_WIN32_SOCKS)
  uTotalThreads = 1;
  socks[0] = new CSocksType();
  if(!socks[0]->PrepareListening()) exit(1);
  socks[0]->pNotifyProc = (PSOCKSNOTIFYPROC)NotifyProc;
  for(;;) socks[0]->StartChaining();
#elif defined(_NETBSD_SOCKS)
  try {
    socks.pNotifyProc = (PSOCKSNOTIFYPROC)NotifyProc;
    NotifyProc(0);
  }
  catch(...)
  {
    perror("Undefined exception handled: exiting abnormally\n");
    exit(1);
  }
#endif

  return(0);
}

Downloads

Download demo project - 29 Kb
Download source - 13 Kb