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


Comments

  • don't know how to Run

    Posted by Legacy on 10/06/2003 12:00am

    Originally posted by: priyanjith


    Please tell me how run and what are the parameters i have to give to run this code. When I try to run this code it gives "TC: _ " in a doc prompt I don't know what to do.

    Please help me.

    Priyanjith

    Reply
  • ftp doesnt work?

    Posted by Legacy on 07/27/2003 12:00am

    Originally posted by: donga

    thanks for sources,
    but i found that ftp doesn't work (PASV)
    http/https works fine, but ftp doesnt.

    what is needed to make it wotk?
    any ideas?

    :((

    Reply
  • Great article, but the term "Firewall" is.... at least confusing

    Posted by Legacy on 07/26/2003 12:00am

    Originally posted by: Christoph


    Hi,

    first of all, please let me say that I really, really appreciate your article. It's great to see someone working on REAL-WORLD applications, not the hyped .NET stuff all the time ;-)

    It's also relief to see that I'm not the only one who has to develop for other operating systems than Win32. Although this web site primarily targets Windows development, one should always have an open mind for other environments, too.


    The first thing I was actually confused about is your usage of the term "Firewall". Yes, I know that the SOCKS protocol refers to that same term. A TCP- or UDP-Listener, that runs on one specific port and either transparently tunnels connections or implements a protocol (like SOCKS) for handshake, and then tunnels traffic, is a Proxy server. Ok, a Proxy server with authentication capabilities.

    A firewall operates on lower OSI levels to intercept ANY package that comes to the server. With a firewall, I can deny any traffic on certain ports, while allowing other ports like 80, 22 and the like. But surely this is not possible to implement in a user mode application, and that's were all portability ends. On Windows, one would have to work on the NDIS layer, on Unix, maybe libpcap could help. I know that this wouldn't be a topic for CodeGuru; I just want to say that the term "Firewall" for a Proxy application is confusing. Nothing more.


    Another thing that surprised me is your usage of the select() call. Though I do not know on which Unices you tested your application, but

    FD_SET(sres, &fd);
    FD_SET(sdest, &fd);
    select (2, &fd, NULL, NULL, &tv);

    is not portable. At least not on Linux, and not on Solaris ( I had the same problem when porting an app from Windows ;-) ). The first argument must be the maximum file descriptor, plus 1. So your code should look like

    FD_SET(sres, &fd);
    FD_SET(sdest, &fd);
    select (max (sres, sdest) + 1, &fd, NULL, NULL, &tv);


    Finally, please keep on the good work. CodeGuru needs much more articles of the quality that you have provided. Within the last months, many articles regarding "How can I change the background color of a button", "How can I move my text 2 pixels to the left" and the like were published here... Although these topics had been discussed years ago, when MFC was all new and sexy, some people like to repeat topics that had been discussed long before :-(


    Thanks for your great article!

    - Christoph

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • Hundreds of millions of users have adopted public cloud storage solutions to satisfy their Private Online File Sharing and Collaboration (OFS) needs. With new headlines on cloud privacy issues appearing almost daily, the need to explore private alternatives has never been stronger. Join ESG Senior Analyst Terri McClure and Connected Data in this on-demand webinar to take a look at the business drivers behind OFS adoption, how organizations can benefit from on-premise deployments, and emerging private OFS …

Most Popular Programming Stories

More for Developers

RSS Feeds