LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
楼主: kj501

试着编写了一个客户-服务器程序

[复制链接]
 楼主| 发表于 2003-4-15 20:13:44 | 显示全部楼层
几日不见,viper兄又进步了,呵呵。。。
能看看你的源代码吗?
发表于 2003-4-15 22:34:12 | 显示全部楼层
C++ 写的,源码有些乱,还在整理中。不好意思的是我的 SOCKS5 那里居然还不支持 SOCKS4。现在这东西既然能工作,我就懒的改了。:)

这里是一个旧的,现在我已经改成用 thread pool 的。但是就变成了好几个文件,贴出来太麻烦了。
发表于 2003-4-15 22:36:27 | 显示全部楼层

  1. /*
  2. * $author$
  3. * $revision$
  4. */

  5. /*
  6. * copyright (c)
  7. */

  8. /*
  9. *
  10. * TODO:
  11. *
  12. * Access control
  13. *
  14. * Add username/password authentication
  15. *
  16. * Add GSS-API authentication
  17. *
  18. * PackUDPData() should check the the system buffer size as well!
  19. *
  20. */

  21. #include <sys/types.h>
  22. #include <sys/socket.h>
  23. #include <netinet/in.h>
  24. #include <arpa/inet.h>
  25. #include <string.h>
  26. #include <pthread.h>
  27. #include <unistd.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <sys/time.h>
  31. #include <netdb.h>

  32. #include <assert.h>
  33. #include <errno.h>
  34. #include <sys/signal.h>
  35. #include <sys/stat.h>
  36. #include <syslog.h>
  37. #include <stdarg.h>

  38. class System
  39. {
  40. protected:
  41.         static int isDaemon;
  42. public:
  43.         static void Daemonize (const char* progname, int facility);
  44.         static int  LogInfo (int level, const char* fmt, ...);
  45.         static void Cleanup (void);
  46. };

  47. class Exception
  48. {
  49. public:
  50.         typedef enum {
  51.                 E_OK,
  52.                 E_SOCK, E_BIND, E_LISTEN, E_ACCEPT,
  53.                 E_RECV, E_SEND, E_RECVFROM, E_SENDTO, E_CONNECT,
  54.                 E_ILL_IPSTR, E_MEM, E_BADADDR, E_GETSOCKNAME, E_GETPEERNAME,
  55.                 E_UNKNOWN_PROTO_VER, E_PROTO_FAIL,
  56.                 E_AUTHENTICATE, E_AUTHORIZE,
  57.                 E_NONEXPUDPDATA,
  58.                 E_THREAD,
  59.                 E_NOT_IMPLEMENTED
  60.         } ExceptionCode;

  61. protected:
  62.         int type;

  63. public:
  64.         Exception (ExceptionCode n) : type(n) {};
  65.         const char* ToString ();
  66.         int GetType ()
  67.                 { return type; };
  68. };

  69. const char*
  70. Exception::ToString()
  71. {
  72. const char* result;

  73.         switch (type)
  74.         {
  75.                 case E_SOCK:
  76.                                 result = "Cannot create socket."; break;
  77.                 case E_LISTEN:
  78.                                 result = "Failed to listen."; break;
  79.                 case E_ACCEPT:
  80.                                 result = "Error accept connection."; break;
  81.                 case E_RECV:
  82.                                 result = "Error recieve network data."; break;
  83.                 case E_SEND:
  84.                                 result = "Error send network data."; break;
  85.                 case E_RECVFROM:
  86.                                 result = "Error recieve UDP data."; break;
  87.                 case E_SENDTO:
  88.                                 result = "Error send UDP data."; break;
  89.                 case E_CONNECT:
  90.                                 result = "Error connect to remote host."; break;
  91.                 case E_ILL_IPSTR:
  92.                                 result = "Illegal IP address string."; break;
  93.                 case E_MEM:
  94.                                 result = "Can not allocate memory."; break;
  95.                 case E_BADADDR:
  96.                                 result = "Bad address data recieved."; break;
  97.                 case E_GETSOCKNAME:
  98.                                 result = "Failed to get socket name."; break;
  99.                 case E_GETPEERNAME:
  100.                                 result = "Failed to get peer name."; break;
  101.                 case E_UNKNOWN_PROTO_VER:
  102.                                 result = "Unknow SOCKS protocol version."; break;
  103.                 case E_PROTO_FAIL:
  104.                                 result = "Protocol fail."; break;
  105.                 case E_THREAD:
  106.                                 result = "Failed create thread."; break;
  107.                 case E_AUTHENTICATE:
  108.                                 result = "Client is not authenticated."; break;
  109.                 case E_AUTHORIZE:
  110.                                 result = "Client is not authorized."; break;
  111.                 case E_NONEXPUDPDATA:
  112.                                 result = "UDP data not from the address of client."; break;
  113.                 case E_NOT_IMPLEMENTED:
  114.                                 result = "Featrure not implemented yet."; break;
  115.                 default:
  116.                                 result = "Unknown Exception";
  117.                                 break;
  118.         }
  119.         return result;
  120. }


  121. /*
  122. * the proxy
  123. */
  124. class SocksProxy
  125. {
  126. public:
  127.         static const char METHOD_NOAUTH = '\x0';
  128.         static const char METHOD_GSSAPI = '\x1';
  129.         static const char METHOD_PASSWD = '\x2';
  130.         static const char METHOD_NONE   = '\xFF';

  131.         static const char COMMAND_CONNECT = '\x1';
  132.         static const char COMMAND_BIND = '\x2';
  133.         static const char COMMAND_UDP = '\x3';

  134. protected:
  135.         static int maxNumOfThreads;
  136.         static int numOfThreads;

  137.         static int Socket (int domain, int type, int protocol)
  138.                         throw (Exception);
  139.         static int Bind (int sockfd, struct sockaddr *addr, socklen_t addrlen)
  140.                         throw (Exception);
  141.         static int Listen (int sockfd, int backlog)
  142.                         throw (Exception);
  143.         static int Accept (int s, struct sockaddr *addr, socklen_t *addrlen)
  144.                         throw (Exception);
  145.         static int Connect(int sockfd, const struct sockaddr *addr,
  146.                                         socklen_t addrlen)
  147.                         throw (Exception);
  148.         static int Recv (int s, void *buf, size_t len, int flags)
  149.                         throw (Exception);
  150.         static int Recvfrom (int s, void *buf, size_t len, int flags,
  151.                                         struct sockaddr *from, socklen_t *fromlen)
  152.                         throw (Exception);
  153.         static int Send (int s, const void *msg, size_t len, int flags)
  154.                         throw (Exception);
  155.         static int Sendto (int s, const void *msg, size_t len, int flags,
  156.                                         const struct sockaddr *to, socklen_t tolen)
  157.                         throw (Exception);
  158.         static int Getsockname (int s, struct sockaddr* name, socklen_t* namelen)
  159.                         throw (Exception);
  160.         static int Getpeername (int s, struct sockaddr* name, socklen_t* namelen)
  161.                         throw (Exception);

  162.         static int InitThreadSystem ();
  163.         static void TermThreadSystem ();
  164.         static int CreateWorkerThread (int connectionSocket)
  165.                         throw (Exception);

  166.         int    enableAnonymous;
  167.         int    enableGSSAPI;
  168.         int    enableUserPassword;

  169.         int socketToClient; // accept client connection
  170.         int socketToRemote; // connect to a remote host
  171.         int socketUDP;      // for UDP associate

  172.         struct sockaddr_in udpClientAddr;
  173.         // the port UDP client recieve msg, network byte order
  174.         //short portUDPClient;

  175.         int EstablishService ();
  176.         int Authenticate ();
  177.         int AuthenticateV5 (char* buf);
  178.         int ProcessRequest ();
  179.         int ProcessRequestV5 (char* msg);
  180.         int OpenTCPConnection (const struct sockaddr* addr, socklen_t len,
  181.                                 char* reply, int* reply_length);
  182.         int OpenUDPAssociate (struct sockaddr* addr,
  183.                                 char* reply, int* reply_length);

  184.         int TransportData ();
  185.         int CopyClientUDPToRemote ();
  186.         void CloseAllSockets ();

  187.         int UDPRelayIn (char* buf, const size_t bufsize);
  188.         int UDPRelayOut(char* buf, const size_t bufsize);
  189.         char* UnpackUDPData (char* buf, const size_t bufsize,
  190.                                 struct sockaddr_in* addr, socklen_t *plen);
  191.         char* PackUDPData (char* buf, int *datalen, size_t bufsize,
  192.                                 struct sockaddr_in* addr, socklen_t socklen);

  193.         int SocksProxy::ParseRequestAddress (const char* buf,
  194.                                 struct sockaddr_in *addr, socklen_t *plen);

  195. public:
  196.         SocksProxy();
  197.         ~SocksProxy();
  198.         static int Run (const char* host, int port);
  199.         static void* StartWorker (SocksProxy *);

  200. };

  201. /* global variables */
  202. static pthread_mutex_t lockNumOfThreads;
  203. static pthread_attr_t  threadAttr;
  204. static pthread_t       *threadIDs;

  205. int SocksProxy::maxNumOfThreads = 10;
  206. int SocksProxy::numOfThreads = 0;

  207. // constructor of class
  208. SocksProxy::SocksProxy ()
  209. {
  210.         // enable anonymous by default
  211.         enableAnonymous = 1;
  212.         // disable GSSAPI as this is not implemented
  213.         enableGSSAPI = 0;
  214.         // disable username and password, as not implemented
  215.         enableUserPassword = 0;

  216.         // all the unused sockets should be -1
  217.         socketToClient = -1;
  218.         socketToRemote = -1;
  219.         socketUDP = -1;
  220. }

  221. SocksProxy::~SocksProxy ()
  222. {
  223.         CloseAllSockets();
  224. }

  225. int
  226. SocksProxy::Socket (int domain, int type, int protocol) throw (Exception)
  227. {
  228.         int s = ::socket (domain, type, protocol);
  229.         if ( -1 == s )
  230.                 throw Exception(Exception::E_SOCK);
  231.         return s;
  232. }

  233. int
  234. SocksProxy::Bind (int sockfd, struct sockaddr *addr, socklen_t addrlen)
  235.                 throw (Exception)
  236. {
  237.         int n = ::bind (sockfd, addr, addrlen);
  238.         if ( n < 0 )
  239.                 throw Exception(Exception::E_BIND);
  240.         return n;
  241. }

  242. int
  243. SocksProxy::Listen (int sockfd, int backlog)
  244.                 throw (Exception)
  245. {
  246.         int n = ::listen (sockfd, backlog);
  247.         if ( n < 0 )
  248.                 throw Exception(Exception::E_LISTEN);
  249.         return n;
  250. }

  251. int
  252. SocksProxy::Accept (int s, struct sockaddr *addr, socklen_t *addrlen)
  253.                 throw (Exception)
  254. {
  255.         int n = ::accept (s, addr, addrlen);
  256.         if (n < 0)
  257.                 throw Exception (Exception::E_LISTEN);
  258.         return n;
  259. }

  260. int
  261. SocksProxy::Connect(int sockfd, const struct sockaddr *addr,
  262.                                         socklen_t addrlen)
  263.                 throw (Exception)
  264. {
  265.         int n = ::connect (sockfd, addr, addrlen);
  266.         if (n == -1)
  267.                 throw Exception(Exception::E_CONNECT);
  268.         return -1;
  269. }

  270. int
  271. SocksProxy::Recv (int s, void *buf, size_t len, int flags)
  272.                 throw (Exception)
  273. {
  274.         int n = ::recv (s, buf, len, flags);
  275.         if ( n < 0 )
  276.                 throw Exception(Exception::E_RECV);
  277.         return n;
  278. }

  279. int
  280. SocksProxy::Recvfrom (int s, void *buf, size_t len, int flags,
  281.                                         struct sockaddr *from, socklen_t *fromlen)
  282.                 throw (Exception)
  283. {
  284.         int n = ::recvfrom (s, buf, len, flags, from, fromlen);
  285.         if ( n == -1 )
  286.                 throw Exception(Exception::E_RECVFROM);
  287.         return n;
  288. }

  289. int
  290. SocksProxy::Send (int s, const void *msg, size_t len, int flags)
  291.                 throw (Exception)
  292. {
  293.         int n = ::send (s, msg, len, flags);
  294.         if ( n == -1 )
  295.                 throw Exception(Exception::E_SEND);
  296.         return n;
  297. }

  298. int
  299. SocksProxy::Sendto (int s, const void *msg, size_t len, int flags,
  300.                                         const struct sockaddr *to, socklen_t tolen)
  301.                 throw (Exception)
  302. {
  303.         int n = ::sendto (s, msg, len, flags, to, tolen);
  304.         if ( n == -1)
  305.                 throw Exception(Exception::E_SENDTO);
  306.         return n;
  307. }

  308. int
  309. SocksProxy::Getsockname (int s, struct sockaddr* name, socklen_t* namelen)
  310.                 throw (Exception)
  311. {
  312.         int n = ::getsockname(s, name, namelen);
  313.         if (n!=0)
  314.                 throw Exception(Exception::E_GETSOCKNAME);
  315.         return n;
  316. }

  317. int
  318. SocksProxy::Getpeername (int s, struct sockaddr* name, socklen_t* namelen)
  319.                         throw (Exception)
  320. {
  321.         int n = ::getpeername (s, name, namelen);
  322.         if (n!=0)
  323.                 throw Exception (Exception::E_GETPEERNAME);
  324.         return n;
  325. }

  326. int
  327. SocksProxy::InitThreadSystem ()
  328. {
  329.         // initialize the pthread
  330.         pthread_attr_init (&threadAttr);
  331.         pthread_mutex_init (&lockNumOfThreads, NULL);
  332.         threadIDs = new pthread_t [maxNumOfThreads];

  333.         return 0;
  334. }

  335. void
  336. SocksProxy::TermThreadSystem()
  337. {
  338.         delete threadIDs;
  339.         threadIDs = NULL;
  340. }

  341. /* run the socks proxy */
  342. int
  343. SocksProxy::Run(const char* host, int port)
  344. {
  345. struct sockaddr_in listenAddr;

  346.         try {
  347.                 struct in_addr addr;
  348.                 int listenSocket = Socket(AF_INET, SOCK_STREAM, 0);
  349.                 memset (&listenAddr, 0, sizeof(listenAddr));
  350.                 listenAddr.sin_family = AF_INET;
  351.                 if (host==NULL)
  352.                         listenAddr.sin_addr.s_addr = htonl (INADDR_ANY);
  353.                 else
  354.                 {
  355.                         if ( 0 >= inet_pton(PF_INET, host, &addr))
  356.                                 throw Exception(Exception::E_ILL_IPSTR);
  357.                         listenAddr.sin_addr = addr;
  358.                 }

  359.                 //listenAddr.sin_addr.s_addr = addr;
  360.                 listenAddr.sin_port = htons(port);
  361.                 Bind (listenSocket, (struct sockaddr*)&listenAddr, sizeof(listenAddr));
  362.                 Listen (listenSocket, 5);
  363.                 System::LogInfo (6, "Start listening\n");

  364.                 InitThreadSystem ();

  365.                 while (1)
  366.                 {
  367.                         struct sockaddr_in clientAddr;
  368.                         char   buf[64];
  369.                         socklen_t len = sizeof(clientAddr);
  370.                         int    connectSocket;
  371.                         connectSocket =
  372.                                         Accept(listenSocket, (struct sockaddr*)&clientAddr, &len);
  373.                         System::LogInfo(6, "Connetion from %s, port %d\n",
  374.                                         inet_ntop(AF_INET, &clientAddr.sin_addr, buf, sizeof(buf)),
  375.                                         ntohs(clientAddr.sin_port));
  376.                         // verify this is authorized client

  377.                         CreateWorkerThread(connectSocket);
  378.                 }
  379.                 close (listenSocket);
  380.                 TermThreadSystem ();
  381.         }
  382.         catch (Exception e)
  383.         {
  384.                 System::LogInfo (6, "%s\n", e.ToString());
  385.         }

  386.         return 0;
  387. }

  388. int
  389. SocksProxy::CreateWorkerThread (int connSocket)
  390.                 throw (Exception)
  391. {
  392. typedef void * (*func_t) (void *);

  393.         if (numOfThreads < maxNumOfThreads)
  394.         {
  395.                 SocksProxy *childProxy = new SocksProxy();
  396.                 if (childProxy==NULL)
  397.                         throw Exception(Exception::E_MEM);

  398.                 childProxy->socketToClient = connSocket;
  399.                 pthread_create( &(threadIDs[numOfThreads]),
  400.                                                 NULL,
  401.                                                 (func_t) StartWorker,
  402.                                                 childProxy);
  403.         }
  404.         else
  405.                 close (connSocket);

  406.         return 0;
  407. }

  408. void *
  409. SocksProxy::StartWorker(SocksProxy *p)
  410. {
  411.         pthread_mutex_lock(&lockNumOfThreads);
  412.         numOfThreads ++;
  413.         pthread_mutex_unlock(&lockNumOfThreads);

  414.         SocksProxy *childProxy = (SocksProxy*)p;
  415.         childProxy->EstablishService ();
  416.         delete childProxy;

  417.         pthread_mutex_lock(&lockNumOfThreads);
  418.         numOfThreads --;
  419.         pthread_mutex_unlock(&lockNumOfThreads);

  420.         return NULL;
  421. }

  422. int
  423. SocksProxy::EstablishService ()
  424. {
  425.         try {
  426.                 int clientVersion = Authenticate ();
  427.                 // we have done authentication, now process the request
  428.                 System::LogInfo (6, "authenticated client of version %d\n",
  429.                                                  clientVersion);
  430.                 // processing the connection request
  431.                 ProcessRequest();
  432.                 // keep relay data between client and the remote host
  433.                 TransportData();
  434.         }
  435.         catch (Exception e)
  436.         {
  437.                 System::LogInfo (6, e.ToString());
  438.         }

  439.         System::LogInfo (6, "terminate session.\n");
  440.         CloseAllSockets();

  441.         return 0;
  442. }

  443. //
  444. // on success, returns the version of the client
  445. // on fail, return -1
  446. //
  447. int
  448. SocksProxy::Authenticate ()
  449. {
  450.         // a authentication fram has max length of 1+1+255 = 257
  451.         char authFrame[260];
  452.         int authVersion = -1;
  453.         int num;

  454.         num = Recv (socketToClient, authFrame, sizeof(authFrame), 0);
  455.         System::LogInfo (6, "got authenticate msg length %d byte.\n", num);

  456.         // authFrame[0] is the protocol version
  457.         switch (authFrame[0])
  458.         {
  459.                 case 4:
  460.                         authVersion = 4;
  461.                         break;
  462.                 case 5:
  463.                         if (-1 == AuthenticateV5(authFrame) )
  464.                                 throw Exception(Exception::E_AUTHENTICATE);
  465.                         else
  466.                                 authVersion = 5;
  467.                         break;
  468.                 default:
  469.                         throw Exception(Exception::E_AUTHENTICATE);
  470.         }

  471.         return authVersion;
  472. }

  473. // buf holds the connection request
  474. // the frame is defined as:
  475. //   field:  ver nMethods Methods
  476. //   length: 1   1        1 to 255
  477. // returns:
  478. //   on success, return 0
  479. //   on fail, return -1
  480. int
  481. SocksProxy::AuthenticateV5(char* buf)
  482. {
  483.         // select an authentication method
  484.         char method = METHOD_NONE;

  485.         for (int i = 0; i<buf[1]; i++)
  486.         {
  487.                 System::LogInfo (6, "method[%d] = %x\n", i, buf[i+2]);
  488.                 if ((enableAnonymous==1)&&(buf[i+2] == METHOD_NOAUTH))
  489.                         method = METHOD_NOAUTH;
  490.                 // check if the method is accepted
  491.                 //if (buf[i+2])
  492.         }
  493.         if (method == METHOD_NONE)
  494.                 return -1;

  495.         char method_selection[2];
  496.         method_selection[0] = '\x5';
  497.         method_selection[1] = method;
  498.         Send (socketToClient, method_selection, sizeof(method_selection), 0);
  499.         System::LogInfo (6, "tell client to select method %d.\n", method);
  500.         if (method == METHOD_NOAUTH) {
  501.                 // don't need authentication, we are done here.
  502.                 return 0;
  503.         } else {
  504.                 // current username-password and GSSAPI authentication is not
  505.                 // implemented.
  506.                 throw Exception(Exception::E_NOT_IMPLEMENTED);
  507.         }
  508.        
  509.         return 0;
  510. }


  511. //
  512. // returns
  513. //   on success, return 0
  514. //   on fail, return -1
  515. //
  516. int SocksProxy::ProcessRequest()
  517. {
  518.         const int MAX_REQ_LEN = 256;
  519.         int result = -1;
  520.         try {
  521.                 char request[MAX_REQ_LEN];
  522.                 int  num;
  523.                 num = Recv(socketToClient, request, MAX_REQ_LEN, 0);
  524.                 System::LogInfo (6, "request recieved, %d byte.\n", num);
  525.                 // verify the protocol version
  526.                 switch (request[0])
  527.                 {
  528.                         case 4:
  529.                                 break;
  530.                         case 5:
  531.                                 result = ProcessRequestV5(request);
  532.                                 break;
  533.                         default:
  534.                                 throw Exception(Exception::E_UNKNOWN_PROTO_VER);
  535.                 }
  536.         }
  537.         catch (Exception e)
  538.         {
  539.                 throw;
  540.         }
  541.         return result;
  542. }


  543. //
  544. //  process a SOCKS 5 request
  545. //
  546. int
  547. SocksProxy::ProcessRequestV5 (char* msg)
  548. {
  549.         int result = -1;
  550.         // maxmum reply length, currently we only fill the ADDR part
  551.         // with IPv4 address, so 16 byte should be enough.
  552.         char reply[16];
  553.         int  reply_length = 3;
  554.         reply[0] = '\x5';
  555.         reply[1] = '\x1'; // initial the result field as fail.
  556.         reply[2] = '\0';  // the reserved field must be 0

  557.         try {
  558.                 struct sockaddr_in addr;
  559.                 socklen_t addrlen;

  560.                 if (msg[2]!='\x0')
  561.                         throw Exception(Exception::E_PROTO_FAIL);

  562.                 int byteused = ParseRequestAddress( msg, &addr, &addrlen);
  563.                 if (byteused < 0) {
  564.                         Send(socketToClient, reply, reply_length, 0);
  565.                         throw Exception(Exception::E_BADADDR);
  566.                 }

  567.                 switch (msg[1])
  568.                 {
  569.                         case COMMAND_CONNECT:
  570.                                         OpenTCPConnection(
  571.                                                         (struct sockaddr*)&addr, addrlen,
  572.                                                         reply, &reply_length);       
  573.                                         reply[1] = '\0';
  574.                                         break;
  575.                         case COMMAND_BIND:
  576.                                         // bind command is not supported
  577.                                         reply[1] = '\x7';
  578.                                         throw Exception (Exception::E_NOT_IMPLEMENTED);
  579.                                         break;
  580.                         case COMMAND_UDP:
  581.                                         OpenUDPAssociate (
  582.                                                         (struct sockaddr*)&addr,
  583.                                                         reply, &reply_length);
  584.                                         break;
  585.                         default:
  586.                                         throw Exception (Exception::E_PROTO_FAIL);
  587.                                         break;
  588.                 }
  589.                 // send the reply to client
  590.                 Send(socketToClient, reply, reply_length, 0);

  591.         } catch (Exception e)
  592.         {
  593.                 // we would like to send a message inform client the
  594.                 // error if we are not getting exception from sending
  595.                 // data to client
  596.                 if (e.GetType()!=Exception::E_SEND)
  597.                         Send(socketToClient, reply, reply_length, 0);
  598.                 throw;
  599.         }

  600.         return result;
  601. }


  602. // open a tcp connect to the remote host as client requested,
  603. // send the reply message to client with the result.
  604. // format of reply message
  605. // +---+----+-----+-----+----------+---------+
  606. // |ver| rep| rev | atyp| bnd.addr | bnd.port|
  607. // +---+----+-----+-----+----------+---------+
  608. // | 1 |  1 | 0x0 |  1  | variable |   2     |
  609. // +---+----+-----+-----+----------+---------+
  610. // input:
  611. //   msg, the connection request from client
  612. // return
  613. //   0  on success
  614. //   -1 on fail
  615. int
  616. SocksProxy::OpenTCPConnection (const struct sockaddr* addr,
  617.                                 socklen_t addrlen,
  618.                                 char* reply, int* reply_length)
  619. {
  620.         int result = -1;
  621.         //char reply [10];

  622.         // the socket to remote host should not be in use, or our
  623.         // program has bug
  624.         assert (socketToRemote==-1);
  625.        
  626.         // verify the client authorized to connect
  627.         //
  628.        
  629.         // connect to the remote host
  630.         try {
  631.                 struct sockaddr_in resultaddr;
  632.                 socklen_t resultlen = sizeof (resultaddr);
  633.                 char addrstr[INET_ADDRSTRLEN];

  634.                 socketToRemote = Socket (PF_INET, SOCK_STREAM, 0);
  635.                 Connect (socketToRemote, (struct sockaddr*)addr, addrlen);
  636.                 Getsockname (socketToRemote,
  637.                                          (struct sockaddr*)&resultaddr, &resultlen);
  638.                 memcpy (reply+4, &resultaddr.sin_addr, 4);
  639.                 System::LogInfo (6, "tell client our outbound addr is %s:%d\n",
  640.                                         inet_ntop(AF_INET, &(resultaddr.sin_addr),
  641.                                                         addrstr, INET_ADDRSTRLEN),
  642.                                         ntohs(resultaddr.sin_port)
  643.                                         );
  644.                 System::LogInfo (6, "TCP connection established.\n");
  645.                 result = 0;
  646.                 reply[1] = 0; // reply result
  647.                 reply[3] = 1; // IP v4
  648.                 memcpy(reply+4, &(resultaddr.sin_addr), 4);
  649.                 memcpy(reply+8, &(resultaddr.sin_port), 2);
  650.         }
  651.         catch (Exception e)
  652.         {
  653.                 System::LogInfo (6, "TCP connection failed.\n");
  654.                 reply[1] = 1; // general socks server failuer
  655.                 throw;
  656.         }

  657.         reply[0] = 5;
  658.         reply[2] = 0; // reserved, must be '\0'
  659.         *reply_length = 10;

  660.         return result;
  661. }

  662. // open a UDP association for the given address.
  663. int
  664. SocksProxy::OpenUDPAssociate( struct sockaddr *pRequestAddr,
  665.                                 char* reply, int* reply_length)
  666. {
  667.         int result = -1;
  668.         struct sockaddr_in addr;
  669.         socklen_t addr_len = sizeof(addr);

  670.         // we assume the socketUDP is not in use, or there must be
  671.         // a bug in the program.
  672.         assert (socketUDP==-1);

  673.         addr.sin_family = AF_INET;
  674.         addr.sin_addr.s_addr = INADDR_ANY;
  675.         // let the kernel assign port for us
  676.         addr.sin_port = 0;

  677.         try {
  678.                 socketUDP = Socket(AF_INET, SOCK_DGRAM, 0);
  679.                 Bind (socketUDP, (struct sockaddr *) &addr,
  680.                           sizeof(struct sockaddr));
  681.                 // open a socket to communicate with remote host
  682.                 socketToRemote = Socket(AF_INET, SOCK_DGRAM, 0);
  683.                 // if we reach here, that mean everything success
  684.                 result = 0;
  685.                 // send reply to our client, the reply format is
  686.                 // +---+---+---+----+--------+--------+
  687.                 // |ver|rep|rsv|atyp|bnd.addr|bnd.port|
  688.                 // +---+---+---+----+--------+--------+
  689.                 // | 1 | 1 |0x0| 1  |variable|   2    |
  690.                 // +---+-------+----+--------+--------+
  691.                 reply[0] = 5;  // version
  692.                 reply[1] = result;  // success or not
  693.                 reply[2] = 0;  // reserved, must be 0
  694.                 reply[3] = 1;  // IP v4, not support IPv6 yet
  695.                 if (result == 0)
  696.                 {
  697.                         char addrstr [INET_ADDRSTRLEN];
  698.                         // record the address UDP associate client
  699.                         Getsockname(socketToClient,
  700.                                                 (struct sockaddr*)&addr,
  701.                                                 &addr_len);
  702.                         // tell client to send UDP data to the address we are
  703.                         // currently serving it for the SOCKS request
  704.                         memcpy (reply+4, &addr.sin_addr, 4);
  705.                         System::LogInfo (6, "tell the send UDP to %s",
  706.                                         inet_ntop(AF_INET, &(addr.sin_addr),
  707.                                                         addrstr, INET_ADDRSTRLEN)
  708.                                         );

  709.                         // tell client the  UDP port kernel assigned to us
  710.                         addr_len = sizeof(addr);
  711.                         Getsockname(socketUDP, (struct sockaddr*)&addr, &addr_len);
  712.                         memcpy (reply+8, &addr.sin_port, 2);
  713.                         System::LogInfo (6, ":%d\n", ntohs(addr.sin_port));

  714.                         addr_len = sizeof (udpClientAddr);
  715.                         Getpeername(socketToClient,
  716.                                                 (struct sockaddr*)&udpClientAddr,
  717.                                                 &addr_len);
  718.                         // record the UDP port client want recieve msg
  719.                         udpClientAddr.sin_port =
  720.                                         ((struct sockaddr_in*)pRequestAddr)->sin_port;
  721.                         //portUDPClient = ((struct sockaddr_in*)pRequestAddr)->sin_port;
  722.                 }
  723.                 *reply_length = 10;
  724.         } catch (Exception e)
  725.         {
  726.                 if (socketUDP != -1)
  727.                 {
  728.                         close (socketUDP);
  729.                         socketUDP = -1;
  730.                 }
  731.                 throw;
  732.         }

  733.         return result;
  734. }


  735. // transport data between our client and the remote host.
  736. int SocksProxy::TransportData ()
  737. {
  738.         struct timeval time_out;
  739.         char * buf;
  740.         const size_t bufsize = 4096;

  741.         System::LogInfo(6, "relay data between client and server.\n");

  742.         try {
  743.                 // allocate buffer
  744.                 buf = new char [bufsize];
  745.                 if (buf==NULL)
  746.                         throw Exception(Exception::E_MEM);

  747.                 while (1)
  748.                 {
  749.                         fd_set checkfds;
  750.                         int    readyfd;
  751.                         int    maxfd;

  752.                         FD_ZERO (&checkfds);
  753.                         FD_SET (socketToClient, &checkfds);
  754.                         maxfd = socketToClient + 1;
  755.                         if (socketToRemote != -1)
  756.                         {
  757.                                 FD_SET (socketToRemote, &checkfds);
  758.                                 maxfd = maxfd > socketToRemote ? maxfd : socketToRemote + 1;
  759.                         }
  760.                         if (socketUDP != -1)
  761.                         {
  762.                                 FD_SET (socketUDP, &checkfds);
  763.                                 maxfd = maxfd > socketToClient ? maxfd : socketToClient + 1;
  764.                         }

  765.                         // set the timeout value
  766.                         time_out.tv_sec = 15;
  767.                         time_out.tv_usec = 0;
  768.                         readyfd = select (maxfd, &checkfds, NULL, NULL, &time_out);
  769.                         if (readyfd < 0)
  770.                                 break;

  771.                         if (FD_ISSET(socketToClient, &checkfds))
  772.                         {
  773.                         int num;
  774.                                 // client has data
  775.                                 num = Recv (socketToClient, buf, bufsize, 0);
  776.                                 // stop transfering data when there is any error
  777.                                 // or the client close the connection.
  778.                                 if (num <= 0)
  779.                                         break;
  780.                                 if (socketUDP==-1)
  781.                                         Send(socketToRemote, buf, num, 0);
  782.                         }
  783.                         if (socketToRemote != -1)
  784.                                 if (FD_ISSET(socketToRemote, &checkfds)) {
  785.                                         if ( socketUDP != -1 ) {
  786.                                                 // we are in UDP mode, relay UDP data to client
  787.                                                 UDPRelayIn (buf, bufsize);
  788.                                         } else {
  789.                                                 // we are in TCP mode
  790.                                                 int num = Recv (socketToRemote, buf, bufsize, 0);
  791.                                                 if (num <= 0)
  792.                                                         break;
  793.                                                 Send(socketToClient, buf, num, 0);
  794.                                         }
  795.                                 }
  796.                         if (socketUDP != -1)
  797.                                 if (FD_ISSET(socketUDP, &checkfds))
  798.                                 {
  799.                                         UDPRelayOut(buf, bufsize);
  800.                                 }
  801.                 }
  802.         } catch (Exception e)
  803.         {
  804.                 if (buf!=NULL)
  805.                 {
  806.                         delete buf;
  807.                         buf = NULL;
  808.                 }

  809.                 throw;
  810.         }

  811.         if (buf!=NULL){
  812.                 delete buf;
  813.                 buf = NULL;
  814.         }
  815.         return 0;
  816. }

  817. int
  818. SocksProxy::UDPRelayIn (char* buf, const size_t bufsize)
  819. {
  820.         int result = -1;

  821.         try {
  822.                 struct sockaddr_in addr;
  823.                 socklen_t socklen;
  824.                        
  825.                 int recieved = Recvfrom (socketToRemote, buf, bufsize, 0,
  826.                                                 (struct sockaddr*)&addr, &socklen);
  827.                 //System::LogInfo (6, "remote in %d byte ", recieved);
  828.                 if (NULL!=PackUDPData (buf, &recieved, bufsize, &addr, socklen))
  829.                 {
  830.                         //Getpeername(socketToClient, (struct sockaddr*)&addr, &socklen);
  831.                         //addr.sin_port = portUDPClient;
  832.                         socklen = sizeof (udpClientAddr);
  833.                         result = Sendto (socketUDP, buf, recieved, 0,
  834.                                                          (struct sockaddr*)&udpClientAddr,
  835.                                                          socklen);
  836.                         //System::LogInfo (6, "pass %d byte to client\n", recieved);
  837.                 }
  838.         }
  839.         catch (Exception e)
  840.         {
  841.                 throw;
  842.         }

  843.         return result;
  844. }

  845. //
  846. // get UDP data from the client, and send to remote host
  847. // for the client.
  848. // returns:
  849. //   bytes sent out
  850. //   or -1 on error
  851. //
  852. int
  853. SocksProxy::UDPRelayOut(char* buf, const size_t bufsize)
  854. {
  855.         int    result = -1;
  856.         struct sockaddr_in addr;
  857.         socklen_t len;
  858.         int    recieved;

  859.         try {
  860.                 recieved = Recvfrom (socketUDP, buf, bufsize, 0,
  861.                                         (struct sockaddr*)&addr, &len);
  862.                
  863.                 // we only accept data from our client
  864.                 if (addr.sin_addr.s_addr != udpClientAddr.sin_addr.s_addr) {
  865.                         throw Exception(Exception::E_NONEXPUDPDATA);
  866.                 }
  867.                 /*
  868.                 char addrstr[INET_ADDRSTRLEN];
  869.                 fprintf (stderr, "recieved %d byte from = %s:%d\n",
  870.                                 recieved,
  871.                                 inet_ntop(AF_INET, &(addr.sin_addr), addrstr, INET_ADDRSTRLEN),
  872.                                 ntohs(addr.sin_port)
  873.                                 );
  874.                 */
  875.                 if (recieved >= 6)
  876.                 {
  877.                         // unpack the UDP data from client
  878.                         char * data;
  879.                         data = UnpackUDPData (buf, recieved, &addr, &len);
  880.                         if (data!=NULL)
  881.                         {
  882.                                 int datalen;
  883.                                 datalen = recieved - (data - buf);
  884.                                 /*
  885.                                 fprintf (stderr, "relay %d byte to addr = %s:%d\n",
  886.                                                 datalen,
  887.                                                 inet_ntop(AF_INET, &(addr.sin_addr),
  888.                                                                 addrstr, INET_ADDRSTRLEN),
  889.                                                 ntohs(addr.sin_port)
  890.                                                 );
  891.                                 */
  892.        
  893.                                 result = Sendto (socketToRemote, data, datalen, 0,
  894.                                                 (struct sockaddr*)&addr, len);
  895.                         }
  896.                 }
  897.         } catch (Exception e)
  898.         {
  899.                 if (e.GetType() == Exception::E_NONEXPUDPDATA) {
  900.                         // we siliently drop the data not come from our client
  901.                         System::LogInfo (6, "%s\n", e.ToString() );
  902.                 }
  903.                 else
  904.                         throw;
  905.         }
  906.         return result;
  907. }

  908. //
  909. // put a UDP relay header and shift the data to behind the header,
  910. // ajust the datalen to origin length plus the length we add.
  911. // returns
  912. //   pointer of the buffer on success
  913. //   NULL if fail
  914. //
  915. char*
  916. SocksProxy::PackUDPData (char* buf, int *datalen, size_t bufsize,
  917.                                 struct sockaddr_in* addr, socklen_t socklen)
  918. {
  919.         if ( (bufsize - *datalen) < 10 )
  920.                 return NULL;
  921.         memmove (buf + 10, buf, *datalen);
  922.         buf[0] = 0;
  923.         buf[1] = 0;
  924.         buf[2] = 0;
  925.         buf[3] = 0x1; // IP v4
  926.         memcpy (buf+4, &addr->sin_addr, 4);
  927.         memcpy (buf+8, &addr->sin_port, 2);
  928.         *datalen += 10;
  929.         return buf;
  930. }

  931. //
  932. // Parse the address information from the SOCKS requests, put
  933. // result into the sockaddr structure
  934. // returns
  935. //   -1 on fail
  936. //   number of byte used in the address
  937. //
  938. int
  939. SocksProxy::ParseRequestAddress (const char* buf,
  940.                                 struct sockaddr_in *addr, socklen_t *plen)
  941. {
  942.         int byteused = -1;

  943.         switch (buf[3])
  944.         {
  945.                 case 1 : // a IP v4 address
  946.                         *plen = sizeof(struct sockaddr_in);
  947.                         memset (addr, 0, *plen);
  948.                         memcpy( &(addr->sin_addr), buf+4, 4);
  949.                         addr->sin_family = PF_INET;
  950.                         addr->sin_port = *(short*)(buf+8);
  951.                         byteused = 10;
  952.                         break;
  953.                 case 3 : // a domain name
  954.                         *plen = sizeof(struct sockaddr_in);
  955.                         memset (addr, 0, *plen);
  956.                         {
  957.                                 struct hostent *remotehost;
  958.                                 char hostname[256];
  959.                                 hostname[255] = '\0';
  960.                                 memcpy (hostname, buf + 5, buf[4]);
  961.                                 hostname[buf[4]] = '\0';
  962.                                 /*
  963.                                 System::LogInfo (6, "resolve domainname = %s\n", hostname);
  964.                                 */
  965.                                 remotehost = gethostbyname(hostname);
  966.                                 if (remotehost!=NULL)
  967.                                 {
  968.                                         memcpy( &(addr->sin_addr),
  969.                                                         remotehost->h_addr,
  970.                                                         remotehost->h_length);
  971.                                         byteused =  5 + buf[4] + 2;
  972.                                 }
  973.                                 addr->sin_family = PF_INET;
  974.                                 addr->sin_port = *(short*)(buf+5+buf[4]);
  975.                         }
  976.                         break;
  977.                 case 4 : // a IP v6 address
  978.                         addr->sin_family = PF_INET6;
  979.                         addr->sin_port = * ((short*) (buf + 10));
  980.                         // byteused = 12;
  981.                         throw Exception(Exception::E_NOT_IMPLEMENTED);
  982.                         break;
  983.         }

  984.         return byteused;
  985. }

  986. char*
  987. SocksProxy::UnpackUDPData (char* buf, const size_t bufsize,
  988.                                 struct sockaddr_in* addr, socklen_t *plen)
  989. {
  990.         char* result = NULL;
  991.         int byteused;

  992.         // SOCKS5 : the first 2 byte must be 00 00
  993.         if (buf[0]!='\0' || buf[1]!='\0')
  994.                 return result;
  995.         // we do not support fragment
  996.         if (buf[2]!='\0')
  997.                 return result;
  998.         byteused = ParseRequestAddress( buf, addr, plen);
  999.         if (byteused > 0)
  1000.                 result = buf + byteused;

  1001.         return result;
  1002. }

  1003. void
  1004. SocksProxy::CloseAllSockets()
  1005. {
  1006.         if (socketToClient != -1) {
  1007.                 close (socketToClient);
  1008.                 socketToClient = -1;
  1009.         }

  1010.         if (socketToRemote != -1) {
  1011.                 close (socketToRemote);
  1012.                 socketToRemote = -1;
  1013.         }

  1014.         if (socketUDP != -1) {
  1015.                 close (socketUDP);
  1016.                 socketUDP = -1;
  1017.         }
  1018. }

  1019. // default the program is not running as daemong
  1020. int System::isDaemon = 0;

  1021. // make this program a daemon
  1022. void System::Daemonize (const char* progname, int facility)
  1023. {
  1024.         int i;
  1025.         pid_t pid;

  1026.         pid = fork();
  1027.         if (pid!=0)
  1028.                 exit (0); // the parent process will exit

  1029.         // 1st child process goes on
  1030.         setsid(); // becomes a session leader
  1031.         signal (SIGHUP, SIG_IGN); // a daemon ignores the HUP signal
  1032.         pid = fork(); // folk again
  1033.         if (pid!=0)
  1034.                 exit (0); // 1st child terminates

  1035.         // 2nd child goes on
  1036.         // set the global flag indicate we are in deamon mode
  1037.         isDaemon = 1;
  1038.         chdir("/");  // change the working directory
  1039.         umask(0);

  1040.         // close all the file descriptors
  1041.         // assume max number of filedescriptor is 64 ???
  1042.         for (i=0; i < 64; i++)
  1043.                 close (i);

  1044.         // will log pid with each log message
  1045.         openlog (progname, LOG_PID, facility);
  1046. }

  1047. void System::Cleanup (void)
  1048. {
  1049.         if (isDaemon)
  1050.                 closelog();
  1051. }

  1052. int System::LogInfo (int level, const char* fmt, ...)
  1053. {
  1054.         char    logmsg[200];
  1055.         va_list ap;

  1056.         va_start (ap, fmt);
  1057.         vsnprintf(logmsg, 200, fmt, ap);

  1058.         if (isDaemon)
  1059.                 syslog (6, logmsg);
  1060.         else
  1061.                 fputs (logmsg, stderr);

  1062.         va_end (ap);
  1063.         return 0;
  1064. }

  1065. // print out the usage and then exit
  1066. void usage (void)
  1067. {
  1068.         puts ("usage:");
  1069.         puts ("  ezsocks [-d] [-a <addr>] [-p<port>]");
  1070.         puts ("  -d          deamon mode, run the proxy as a daemon.");
  1071.         puts ("  -a <addr>   listen on the given IP address.");
  1072.         puts ("  -p <port>   listen on the given port number.");
  1073.         exit (1);
  1074. }


  1075. //  program start point
  1076. int
  1077. main (int argc, char* argv[])
  1078. {
  1079. int argChecked;
  1080. int result = 0;
  1081. char* listenAddr = NULL;
  1082. int   listenPort = 1080;

  1083.         argChecked = 1;
  1084.         while (argChecked < argc )
  1085.         {
  1086.                 if (strcmp(argv[argChecked], "-d")==0) {
  1087.                         System::Daemonize ("SocksProxy", LOG_DAEMON);
  1088.                         argChecked ++;
  1089.                         continue;
  1090.                 }
  1091.                 if (strcmp(argv[argChecked], "-a")==0) {
  1092.                         argChecked ++;
  1093.                         if (argChecked < argc) {
  1094.                                 listenAddr = argv[argChecked];
  1095.                                 argChecked ++;
  1096.                         } else {
  1097.                                 usage();
  1098.                         }
  1099.                         continue;
  1100.                 }
  1101.                 if (strcmp(argv[argChecked], "-p")==0) {
  1102.                         argChecked ++;
  1103.                         if (argChecked < argc) {
  1104.                                 listenPort = atoi(argv[argChecked]);
  1105.                                 argChecked ++;
  1106.                                 if (listenPort==0)
  1107.                                         usage();
  1108.                         } else {
  1109.                                 usage();
  1110.                         }
  1111.                         continue;
  1112.                 }
  1113.                 usage();
  1114.         }

  1115.         result = SocksProxy::Run(listenAddr, listenPort);
  1116.         System::Cleanup();
  1117.         return result;
  1118. }
复制代码
发表于 2003-4-15 22:44:10 | 显示全部楼层
这个程序原来是 C 写的,本打算写一个尽可能短的能工作的就可以了。后来,就又想改成 C++ 。现在贴出来的是动手改 C++ 开始的那段时间的版本,程序基本结构还是 C 的。到了后来,文件就不止一个,越来越罗嗦了。:)
 楼主| 发表于 2003-4-16 09:04:16 | 显示全部楼层
收到,研究研究先。
发表于 2003-4-16 09:33:02 | 显示全部楼层
所有的东西全都是静态方法,真目不忍睹。:)
 楼主| 发表于 2003-4-16 13:26:04 | 显示全部楼层
加上缩进,好看一些。呵呵。。。
[php]最初由 viper 发布
/*
* $author$
* $revision$
*/

/*
* copyright (c)
*/

/*
*
* TODO:
*
* Access control
*
* Add username/password authentication
*
* Add GSS-API authentication
*
* PackUDPData() should check the the system buffer size as well!
*
*/

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <netdb.h>

#include <assert.h>
#include <errno.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <syslog.h>
#include <stdarg.h>

class System
{
protected:
        static int isDaemon;
public:
        static void Daemonize (const char* progname, int facility);
        static int  LogInfo (int level, const char* fmt, ...);
        static void Cleanup (void);
};

class Exception
{
public:
        typedef enum {
                E_OK,
                E_SOCK, E_BIND, E_LISTEN, E_ACCEPT,
                E_RECV, E_SEND, E_RECVFROM, E_SENDTO, E_CONNECT,
                E_ILL_IPSTR, E_MEM, E_BADADDR, E_GETSOCKNAME, E_GETPEERNAME,
                E_UNKNOWN_PROTO_VER, E_PROTO_FAIL,
                E_AUTHENTICATE, E_AUTHORIZE,
                E_NONEXPUDPDATA,
                E_THREAD,
                E_NOT_IMPLEMENTED
        } ExceptionCode;

protected:
        int type;

public:
        Exception (ExceptionCode n) : type(n) {};
        const char* ToString ();
        int GetType ()
                { return type; };
};

const char*
Exception::ToString()
{
const char* result;

        switch (type)
        {
                case E_SOCK:
                                result = "Cannot create socket."; break;
                case E_LISTEN:
                                result = "Failed to listen."; break;
                case E_ACCEPT:
                                result = "Error accept connection."; break;
                case E_RECV:
                                result = "Error recieve network data."; break;
                case E_SEND:
                                result = "Error send network data."; break;
                case E_RECVFROM:
                                result = "Error recieve UDP data."; break;
                case E_SENDTO:
                                result = "Error send UDP data."; break;
                case E_CONNECT:
                                result = "Error connect to remote host."; break;
                case E_ILL_IPSTR:
                                result = "Illegal IP address string."; break;
                case E_MEM:
                                result = "Can not allocate memory."; break;
                case E_BADADDR:
                                result = "Bad address data recieved."; break;
                case E_GETSOCKNAME:
                                result = "Failed to get socket name."; break;
                case E_GETPEERNAME:
                                result = "Failed to get peer name."; break;
                case E_UNKNOWN_PROTO_VER:
                                result = "Unknow SOCKS protocol version."; break;
                case E_PROTO_FAIL:
                                result = "rotocol fail."; break;
                case E_THREAD:
                                result = "Failed create thread."; break;
                case E_AUTHENTICATE:
                                result = "Client is not authenticated."; break;
                case E_AUTHORIZE:
                                result = "Client is not authorized."; break;
                case E_NONEXPUDPDATA:
                                result = "UDP data not from the address of client."; break;
                case E_NOT_IMPLEMENTED:
                                result = "Featrure not implemented yet."; break;
                default:
                                result = "Unknown Exception";
                                break;
        }
        return result;
}


/*
* the proxy
*/
class SocksProxy
{
public:
        static const char METHOD_NOAUTH = '\x0';
        static const char METHOD_GSSAPI = '\x1';
        static const char METHOD_PASSWD = '\x2';
        static const char METHOD_NONE   = '\xFF';

        static const char COMMAND_CONNECT = '\x1';
        static const char COMMAND_BIND = '\x2';
        static const char COMMAND_UDP = '\x3';

protected:
        static int maxNumOfThreads;
        static int numOfThreads;

        static int Socket (int domain, int type, int protocol)
                        throw (Exception);
        static int Bind (int sockfd, struct sockaddr *addr, socklen_t addrlen)
                        throw (Exception);
        static int Listen (int sockfd, int backlog)
                        throw (Exception);
        static int Accept (int s, struct sockaddr *addr, socklen_t *addrlen)
                        throw (Exception);
        static int Connect(int sockfd, const struct sockaddr *addr,
                                        socklen_t addrlen)
                        throw (Exception);
        static int Recv (int s, void *buf, size_t len, int flags)
                        throw (Exception);
        static int Recvfrom (int s, void *buf, size_t len, int flags,
                                        struct sockaddr *from, socklen_t *fromlen)
                        throw (Exception);
        static int Send (int s, const void *msg, size_t len, int flags)
                        throw (Exception);
        static int Sendto (int s, const void *msg, size_t len, int flags,
                                        const struct sockaddr *to, socklen_t tolen)
                        throw (Exception);

        static int Getsockname (int s, struct sockaddr* name, socklen_t* namelen)
                        throw (Exception);
        static int Getpeername (int s, struct sockaddr* name, socklen_t* namelen)
                        throw (Exception);

        static int InitThreadSystem ();
        static void TermThreadSystem ();
        static int CreateWorkerThread (int connectionSocket)
                        throw (Exception);

        int    enableAnonymous;
        int    enableGSSAPI;
        int    enableUserPassword;

        int socketToClient; // accept client connection
        int socketToRemote; // connect to a remote host
        int socketUDP;      // for UDP associate

        struct sockaddr_in udpClientAddr;
        // the port UDP client recieve msg, network byte order
        //short portUDPClient;

        int EstablishService ();
        int Authenticate ();
        int AuthenticateV5 (char* buf);
        int ProcessRequest ();
        int ProcessRequestV5 (char* msg);
        int OpenTCPConnection (const struct sockaddr* addr, socklen_t len,
                                char* reply, int* reply_length);
        int OpenUDPAssociate (struct sockaddr* addr,
                                char* reply, int* reply_length);

        int TransportData ();
        int CopyClientUDPToRemote ();
        void CloseAllSockets ();

        int UDPRelayIn (char* buf, const size_t bufsize);
        int UDPRelayOut(char* buf, const size_t bufsize);
        char* UnpackUDPData (char* buf, const size_t bufsize,
                                struct sockaddr_in* addr, socklen_t *plen);
        char* PackUDPData (char* buf, int *datalen, size_t bufsize,
                                struct sockaddr_in* addr, socklen_t socklen);

        int SocksProxy:arseRequestAddress (const char* buf,
                                struct sockaddr_in *addr, socklen_t *plen);

public:
        SocksProxy();
        ~SocksProxy();
        static int Run (const char* host, int port);
        static void* StartWorker (SocksProxy *);

};

/* global variables */
static pthread_mutex_t lockNumOfThreads;
static pthread_attr_t  threadAttr;
static pthread_t       *threadIDs;

int SocksProxy::maxNumOfThreads = 10;
int SocksProxy::numOfThreads = 0;

// constructor of class
SocksProxy::SocksProxy ()
{
        // enable anonymous by default
        enableAnonymous = 1;
        // disable GSSAPI as this is not implemented
        enableGSSAPI = 0;
        // disable username and password, as not implemented
        enableUserPassword = 0;

        // all the unused sockets should be -1
        socketToClient = -1;
        socketToRemote = -1;
        socketUDP = -1;
}

SocksProxy::~SocksProxy ()
{
        CloseAllSockets();
}

int
SocksProxy::Socket (int domain, int type, int protocol) throw (Exception)
{
        int s = ::socket (domain, type, protocol);
        if ( -1 == s )
                throw Exception(Exception::E_SOCK);
        return s;
}

int
SocksProxy::Bind (int sockfd, struct sockaddr *addr, socklen_t addrlen)
                throw (Exception)
{
        int n = ::bind (sockfd, addr, addrlen);
        if ( n < 0 )
                throw Exception(Exception::E_BIND);
        return n;
}

int
SocksProxy:isten (int sockfd, int backlog)
                throw (Exception)
{
        int n = ::listen (sockfd, backlog);
        if ( n < 0 )
                throw Exception(Exception::E_LISTEN);
        return n;
}

int
SocksProxy::Accept (int s, struct sockaddr *addr, socklen_t *addrlen)
                throw (Exception)
{
        int n = ::accept (s, addr, addrlen);
        if (n < 0)
                throw Exception (Exception::E_LISTEN);
        return n;
}

int
SocksProxy::Connect(int sockfd, const struct sockaddr *addr,
                                        socklen_t addrlen)
                throw (Exception)
{
        int n = ::connect (sockfd, addr, addrlen);
        if (n == -1)
                throw Exception(Exception::E_CONNECT);
        return -1;
}

int
SocksProxy::Recv (int s, void *buf, size_t len, int flags)
                throw (Exception)
{
        int n = ::recv (s, buf, len, flags);
        if ( n < 0 )
                throw Exception(Exception::E_RECV);
        return n;
}

int
SocksProxy::Recvfrom (int s, void *buf, size_t len, int flags,
                                        struct sockaddr *from, socklen_t *fromlen)
                throw (Exception)
{
        int n = ::recvfrom (s, buf, len, flags, from, fromlen);
        if ( n == -1 )
                throw Exception(Exception::E_RECVFROM);
        return n;
}

int
SocksProxy::Send (int s, const void *msg, size_t len, int flags)
                throw (Exception)
{
        int n = ::send (s, msg, len, flags);
        if ( n == -1 )
                throw Exception(Exception::E_SEND);
        return n;
}

int
SocksProxy::Sendto (int s, const void *msg, size_t len, int flags,
                                        const struct sockaddr *to, socklen_t tolen)
                throw (Exception)
{
        int n = ::sendto (s, msg, len, flags, to, tolen);
        if ( n == -1)
                throw Exception(Exception::E_SENDTO);
        return n;
}

int
SocksProxy::Getsockname (int s, struct sockaddr* name, socklen_t* namelen)
                throw (Exception)
{
        int n = ::getsockname(s, name, namelen);
        if (n!=0)
                throw Exception(Exception::E_GETSOCKNAME);
        return n;
}

int
SocksProxy::Getpeername (int s, struct sockaddr* name, socklen_t* namelen)
                        throw (Exception)
{
        int n = ::getpeername (s, name, namelen);
        if (n!=0)
                throw Exception (Exception::E_GETPEERNAME);
        return n;
}

int
SocksProxy::InitThreadSystem ()
{
        // initialize the pthread
        pthread_attr_init (&threadAttr);
        pthread_mutex_init (&lockNumOfThreads, NULL);
        threadIDs = new pthread_t [maxNumOfThreads];

        return 0;
}

void
SocksProxy::TermThreadSystem()
{
        delete threadIDs;
        threadIDs = NULL;
}

/* run the socks proxy */
int
SocksProxy::Run(const char* host, int port)
{
struct sockaddr_in listenAddr;

        try {
                struct in_addr addr;
                int listenSocket = Socket(AF_INET, SOCK_STREAM, 0);
                memset (&listenAddr, 0, sizeof(listenAddr));
                listenAddr.sin_family = AF_INET;
                if (host==NULL)
                        listenAddr.sin_addr.s_addr = htonl (INADDR_ANY);
                else
                {
                        if ( 0 >= inet_pton(PF_INET, host, &addr))
                                throw Exception(Exception::E_ILL_IPSTR);
                        listenAddr.sin_addr = addr;
                }

                //listenAddr.sin_addr.s_addr = addr;
                listenAddr.sin_port = htons(port);
                Bind (listenSocket, (struct sockaddr*)&listenAddr, sizeof(listenAddr));
                Listen (listenSocket, 5);
                System:ogInfo (6, "Start listening\n");

                InitThreadSystem ();

                while (1)
                {
                        struct sockaddr_in clientAddr;
                        char   buf[64];
                        socklen_t len = sizeof(clientAddr);
                        int    connectSocket;
                        connectSocket =
                                        Accept(listenSocket, (struct sockaddr*)&clientAddr, &len);
                        System:ogInfo(6, "Connetion from %s, port %d\n",
                                        inet_ntop(AF_INET, &clientAddr.sin_addr, buf, sizeof(buf)),
                                        ntohs(clientAddr.sin_port));
                        // verify this is authorized client

                        CreateWorkerThread(connectSocket);
                }
                close (listenSocket);
                TermThreadSystem ();
        }
        catch (Exception e)
        {
                System:ogInfo (6, "%s\n", e.ToString());
        }

        return 0;
}

int
SocksProxy::CreateWorkerThread (int connSocket)
                throw (Exception)
{
typedef void * (*func_t) (void *);

        if (numOfThreads < maxNumOfThreads)
        {
                SocksProxy *childProxy = new SocksProxy();
                if (childProxy==NULL)
                        throw Exception(Exception::E_MEM);

                childProxy->socketToClient = connSocket;
                pthread_create( &(threadIDs[numOfThreads]),
                                                NULL,
                                                (func_t) StartWorker,
                                                childProxy);
        }
        else
                close (connSocket);

        return 0;
}

void *
SocksProxy::StartWorker(SocksProxy *p)
{
        pthread_mutex_lock(&lockNumOfThreads);
        numOfThreads ++;
        pthread_mutex_unlock(&lockNumOfThreads);

        SocksProxy *childProxy = (SocksProxy*)p;
        childProxy->EstablishService ();
        delete childProxy;

        pthread_mutex_lock(&lockNumOfThreads);
        numOfThreads --;
        pthread_mutex_unlock(&lockNumOfThreads);

        return NULL;
}

int
SocksProxy::EstablishService ()
{
        try {
                int clientVersion = Authenticate ();
                // we have done authentication, now process the request
                System:ogInfo (6, "authenticated client of version %d\n",
                                                 clientVersion);
                // processing the connection request
                ProcessRequest();
                // keep relay data between client and the remote host
                TransportData();
        }
        catch (Exception e)
        {
                System:ogInfo (6, e.ToString());
        }

        System:ogInfo (6, "terminate session.\n");
        CloseAllSockets();

        return 0;
}

//
// on success, returns the version of the client
// on fail, return -1
//
int
SocksProxy::Authenticate ()
{
        // a authentication fram has max length of 1+1+255 = 257
        char authFrame[260];
        int authVersion = -1;
        int num;

        num = Recv (socketToClient, authFrame, sizeof(authFrame), 0);
        System:ogInfo (6, "got authenticate msg length %d byte.\n", num);

        // authFrame[0] is the protocol version
        switch (authFrame[0])
        {
                case 4:
                        authVersion = 4;
                        break;
                case 5:
                        if (-1 == AuthenticateV5(authFrame) )
                                throw Exception(Exception::E_AUTHENTICATE);
                        else
                                authVersion = 5;
                        break;
                default:
                        throw Exception(Exception::E_AUTHENTICATE);
        }

        return authVersion;
}

// buf holds the connection request
// the frame is defined as:
//   field:  ver nMethods Methods
//   length: 1   1        1 to 255
// returns:
//   on success, return 0
//   on fail, return -1
int
SocksProxy::AuthenticateV5(char* buf)
{
        // select an authentication method
        char method = METHOD_NONE;

        for (int i = 0; i<buf[1]; i++)
        {
                System:ogInfo (6, "method[%d] = %x\n", i, buf[i+2]);
                if ((enableAnonymous==1)&&(buf[i+2] == METHOD_NOAUTH))
                        method = METHOD_NOAUTH;
                // check if the method is accepted
                //if (buf[i+2])
        }
        if (method == METHOD_NONE)
                return -1;

        char method_selection[2];
        method_selection[0] = '\x5';
        method_selection[1] = method;
        Send (socketToClient, method_selection, sizeof(method_selection), 0);
        System:ogInfo (6, "tell client to select method %d.\n", method);
        if (method == METHOD_NOAUTH) {
                // don't need authentication, we are done here.
                return 0;
        } else {
                // current username-password and GSSAPI authentication is not
                // implemented.
                throw Exception(Exception::E_NOT_IMPLEMENTED);
        }
       
        return 0;
}


//
// returns
//   on success, return 0
//   on fail, return -1
//
int SocksProxy:rocessRequest()
{
        const int MAX_REQ_LEN = 256;
        int result = -1;
        try {
                char request[MAX_REQ_LEN];
                int  num;
                num = Recv(socketToClient, request, MAX_REQ_LEN, 0);
                System::LogInfo (6, "request recieved, %d byte.\n", num);
                // verify the protocol version
                switch (request[0])
                {
                        case 4:
                                break;
                        case 5:
                                result = ProcessRequestV5(request);
                                break;
                        default:
                                throw Exception(Exception::E_UNKNOWN_PROTO_VER);
                }
        }
        catch (Exception e)
        {
                throw;
        }
        return result;
}


//
//  process a SOCKS 5 request
//
int
SocksProxy:rocessRequestV5 (char* msg)
{
        int result = -1;
        // maxmum reply length, currently we only fill the ADDR part
        // with IPv4 address, so 16 byte should be enough.
        char reply[16];
        int  reply_length = 3;
        reply[0] = '\x5';
        reply[1] = '\x1'; // initial the result field as fail.
        reply[2] = '\0';  // the reserved field must be 0

        try {
                struct sockaddr_in addr;
                socklen_t addrlen;

                if (msg[2]!='\x0')
                        throw Exception(Exception::E_PROTO_FAIL);

                int byteused = ParseRequestAddress( msg, &addr, &addrlen);
                if (byteused < 0) {
                        Send(socketToClient, reply, reply_length, 0);
                        throw Exception(Exception::E_BADADDR);
                }

                switch (msg[1])
                {
                        case COMMAND_CONNECT:
                                        OpenTCPConnection(
                                                        (struct sockaddr*)&addr, addrlen,
                                                        reply, &reply_length);       
                                        reply[1] = '\0';
                                        break;
                        case COMMAND_BIND:
                                        // bind command is not supported
                                        reply[1] = '\x7';
                                        throw Exception (Exception::E_NOT_IMPLEMENTED);
                                        break;
                        case COMMAND_UDP:
                                        OpenUDPAssociate (
                                                        (struct sockaddr*)&addr,
                                                        reply, &reply_length);
                                        break;
                        default:
                                        throw Exception (Exception::E_PROTO_FAIL);
                                        break;
                }
                // send the reply to client
                Send(socketToClient, reply, reply_length, 0);

        } catch (Exception e)
        {
                // we would like to send a message inform client the
                // error if we are not getting exception from sending
                // data to client
                if (e.GetType()!=Exception::E_SEND)
                        Send(socketToClient, reply, reply_length, 0);
                throw;
        }

        return result;
}


// open a tcp connect to the remote host as client requested,
// send the reply message to client with the result.
// format of reply message
// +---+----+-----+-----+----------+---------+
// |ver| rep| rev | atyp| bnd.addr | bnd.port|
// +---+----+-----+-----+----------+---------+
// | 1 |  1 | 0x0 |  1  | variable |   2     |
// +---+----+-----+-----+----------+---------+
// input:
//   msg, the connection request from client
// return
//   0  on success
//   -1 on fail
int
SocksProxy::OpenTCPConnection (const struct sockaddr* addr,
                                socklen_t addrlen,
                                char* reply, int* reply_length)
{
        int result = -1;
        //char reply [10];

        // the socket to remote host should not be in use, or our
        // program has bug
        assert (socketToRemote==-1);
       
        // verify the client authorized to connect
        //
       
        // connect to the remote host
        try {
                struct sockaddr_in resultaddr;
                socklen_t resultlen = sizeof (resultaddr);
                char addrstr[INET_ADDRSTRLEN];

                socketToRemote = Socket (PF_INET, SOCK_STREAM, 0);
                Connect (socketToRemote, (struct sockaddr*)addr, addrlen);
                Getsockname (socketToRemote,
                                         (struct sockaddr*)&resultaddr, &resultlen);
                memcpy (reply+4, &resultaddr.sin_addr, 4);
                System::LogInfo (6, "tell client our outbound addr is %s:%d\n",
                                        inet_ntop(AF_INET, &(resultaddr.sin_addr),
                                                        addrstr, INET_ADDRSTRLEN),
                                        ntohs(resultaddr.sin_port)
                                        );
                System::LogInfo (6, "TCP connection established.\n");
                result = 0;
                reply[1] = 0; // reply result
                reply[3] = 1; // IP v4
                memcpy(reply+4, &(resultaddr.sin_addr), 4);
                memcpy(reply+8, &(resultaddr.sin_port), 2);
        }
        catch (Exception e)
        {
                System::LogInfo (6, "TCP connection failed.\n");
                reply[1] = 1; // general socks server failuer
                throw;
        }

        reply[0] = 5;
        reply[2] = 0; // reserved, must be '\0'
        *reply_length = 10;

        return result;
}

// open a UDP association for the given address.
int
SocksProxy::OpenUDPAssociate( struct sockaddr *pRequestAddr,
                                char* reply, int* reply_length)
{
        int result = -1;
        struct sockaddr_in addr;
        socklen_t addr_len = sizeof(addr);

        // we assume the socketUDP is not in use, or there must be
        // a bug in the program.
        assert (socketUDP==-1);

        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = INADDR_ANY;
        // let the kernel assign port for us
        addr.sin_port = 0;

        try {
                socketUDP = Socket(AF_INET, SOCK_DGRAM, 0);
                Bind (socketUDP, (struct sockaddr *) &addr,
                          sizeof(struct sockaddr));
                // open a socket to communicate with remote host
                socketToRemote = Socket(AF_INET, SOCK_DGRAM, 0);
                // if we reach here, that mean everything success
                result = 0;
                // send reply to our client, the reply format is
                // +---+---+---+----+--------+--------+
                // |ver|rep|rsv|atyp|bnd.addr|bnd.port|
                // +---+---+---+----+--------+--------+
                // | 1 | 1 |0x0| 1  |variable|   2    |
                // +---+-------+----+--------+--------+
                reply[0] = 5;  // version
                reply[1] = result;  // success or not
                reply[2] = 0;  // reserved, must be 0
                reply[3] = 1;  // IP v4, not support IPv6 yet
                if (result == 0)
                {
                        char addrstr [INET_ADDRSTRLEN];
                        // record the address UDP associate client
                        Getsockname(socketToClient,
                                                (struct sockaddr*)&addr,
                                                &addr_len);
                        // tell client to send UDP data to the address we are
                        // currently serving it for the SOCKS request
                        memcpy (reply+4, &addr.sin_addr, 4);
                        System::LogInfo (6, "tell the send UDP to %s",
                                        inet_ntop(AF_INET, &(addr.sin_addr),
                                                        addrstr, INET_ADDRSTRLEN)
                                        );

                        // tell client the  UDP port kernel assigned to us
                        addr_len = sizeof(addr);
                        Getsockname(socketUDP, (struct sockaddr*)&addr, &addr_len);
                        memcpy (reply+8, &addr.sin_port, 2);
                        System::LogInfo (6, ":%d\n", ntohs(addr.sin_port));

                        addr_len = sizeof (udpClientAddr);
                        Getpeername(socketToClient,
                                                (struct sockaddr*)&udpClientAddr,
                                                &addr_len);
                        // record the UDP port client want recieve msg
                        udpClientAddr.sin_port =
                                        ((struct sockaddr_in*)pRequestAddr)->sin_port;
                        //portUDPClient = ((struct sockaddr_in*)pRequestAddr)->sin_port;
                }
                *reply_length = 10;
        } catch (Exception e)
        {
                if (socketUDP != -1)
                {
                        close (socketUDP);
                        socketUDP = -1;
                }
                throw;
        }

        return result;
}


// transport data between our client and the remote host.
int SocksProxy::TransportData ()
{
        struct timeval time_out;
        char * buf;
        const size_t bufsize = 4096;

        System::LogInfo(6, "relay data between client and server.\n");

        try {
                // allocate buffer
                buf = new char [bufsize];
                if (buf==NULL)
                        throw Exception(Exception::E_MEM);

                while (1)
                {
                        fd_set checkfds;
                        int    readyfd;
                        int    maxfd;

                        FD_ZERO (&checkfds);
                        FD_SET (socketToClient, &checkfds);
                        maxfd = socketToClient + 1;
                        if (socketToRemote != -1)
                        {
                                FD_SET (socketToRemote, &checkfds);
                                maxfd = maxfd > socketToRemote ? maxfd : socketToRemote + 1;
                        }
                        if (socketUDP != -1)
                        {
                                FD_SET (socketUDP, &checkfds);
                                maxfd = maxfd > socketToClient ? maxfd : socketToClient + 1;
                        }

                        // set the timeout value
                        time_out.tv_sec = 15;
                        time_out.tv_usec = 0;
                        readyfd = select (maxfd, &checkfds, NULL, NULL, &time_out);
                        if (readyfd < 0)
                                break;

                        if (FD_ISSET(socketToClient, &checkfds))
                        {
                        int num;
                                // client has data
                                num = Recv (socketToClient, buf, bufsize, 0);
                                // stop transfering data when there is any error
                                // or the client close the connection.
                                if (num <= 0)
                                        break;
                                if (socketUDP==-1)
                                        Send(socketToRemote, buf, num, 0);
                        }
                        if (socketToRemote != -1)
                                if (FD_ISSET(socketToRemote, &checkfds)) {
                                        if ( socketUDP != -1 ) {
                                                // we are in UDP mode, relay UDP data to client
                                                UDPRelayIn (buf, bufsize);
                                        } else {
                                                // we are in TCP mode
                                                int num = Recv (socketToRemote, buf, bufsize, 0);
                                                if (num <= 0)
                                                        break;
                                                Send(socketToClient, buf, num, 0);
                                        }
                                }
                        if (socketUDP != -1)
                                if (FD_ISSET(socketUDP, &checkfds))
                                {
                                        UDPRelayOut(buf, bufsize);
                                }
                }
        } catch (Exception e)
        {
                if (buf!=NULL)
                {
                        delete buf;
                        buf = NULL;
                }

                throw;
        }

        if (buf!=NULL){
                delete buf;
                buf = NULL;
        }
        return 0;
}

int
SocksProxy::UDPRelayIn (char* buf, const size_t bufsize)
{
        int result = -1;

        try {
                struct sockaddr_in addr;
                socklen_t socklen;
                       
                int recieved = Recvfrom (socketToRemote, buf, bufsize, 0,
                                                (struct sockaddr*)&addr, &socklen);
                //System::LogInfo (6, "remote in %d byte ", recieved);
                if (NULL!=PackUDPData (buf, &recieved, bufsize, &addr, socklen))
                {
                        //Getpeername(socketToClient, (struct sockaddr*)&addr, &socklen);
                        //addr.sin_port = portUDPClient;
                        socklen = sizeof (udpClientAddr);
                        result = Sendto (socketUDP, buf, recieved, 0,
                                                         (struct sockaddr*)&udpClientAddr,
                                                         socklen);
                        //System::LogInfo (6, "pass %d byte to client\n", recieved);
                }
        }
        catch (Exception e)
        {
                throw;
        }

        return result;
}

//
// get UDP data from the client, and send to remote host
// for the client.
// returns:
//   bytes sent out
//   or -1 on error
//
int
SocksProxy::UDPRelayOut(char* buf, const size_t bufsize)
{
        int    result = -1;
        struct sockaddr_in addr;
        socklen_t len;
        int    recieved;

        try {
                recieved = Recvfrom (socketUDP, buf, bufsize, 0,
                                        (struct sockaddr*)&addr, &len);
               
                // we only accept data from our client
                if (addr.sin_addr.s_addr != udpClientAddr.sin_addr.s_addr) {
                        throw Exception(Exception::E_NONEXPUDPDATA);
                }
                /*
                char addrstr[INET_ADDRSTRLEN];
                fprintf (stderr, "recieved %d byte from = %s:%d\n",
                                recieved,
                                inet_ntop(AF_INET, &(addr.sin_addr), addrstr, INET_ADDRSTRLEN),
                                ntohs(addr.sin_port)
                                );
                */
                if (recieved >= 6)
                {
                        // unpack the UDP data from client
                        char * data;
                        data = UnpackUDPData (buf, recieved, &addr, &len);
                        if (data!=NULL)
                        {
                                int datalen;
                                datalen = recieved - (data - buf);
                                /*
                                fprintf (stderr, "relay %d byte to addr = %s:%d\n",
                                                datalen,
                                                inet_ntop(AF_INET, &(addr.sin_addr),
                                                                addrstr, INET_ADDRSTRLEN),
                                                ntohs(addr.sin_port)
                                                );
                                */
       
                                result = Sendto (socketToRemote, data, datalen, 0,
                                                (struct sockaddr*)&addr, len);
                        }
                }
        } catch (Exception e)
        {
                if (e.GetType() == Exception::E_NONEXPUDPDATA) {
                        // we siliently drop the data not come from our client
                        System::LogInfo (6, "%s\n", e.ToString() );
                }
                else
                        throw;
        }
        return result;
}

//
// put a UDP relay header and shift the data to behind the header,
// ajust the datalen to origin length plus the length we add.
// returns
//   pointer of the buffer on success
//   NULL if fail
//
char*
SocksProxy:ackUDPData (char* buf, int *datalen, size_t bufsize,
                                struct sockaddr_in* addr, socklen_t socklen)
{
        if ( (bufsize - *datalen) < 10 )
                return NULL;
        memmove (buf + 10, buf, *datalen);
        buf[0] = 0;
        buf[1] = 0;
        buf[2] = 0;
        buf[3] = 0x1; // IP v4
        memcpy (buf+4, &addr->sin_addr, 4);
        memcpy (buf+8, &addr->sin_port, 2);
        *datalen += 10;
        return buf;
}

//
// Parse the address information from the SOCKS requests, put
// result into the sockaddr structure
// returns
//   -1 on fail
//   number of byte used in the address
//
int
SocksProxy:arseRequestAddress (const char* buf,
                                struct sockaddr_in *addr, socklen_t *plen)
{
        int byteused = -1;

        switch (buf[3])
        {
                case 1 : // a IP v4 address
                        *plen = sizeof(struct sockaddr_in);
                        memset (addr, 0, *plen);
                        memcpy( &(addr->sin_addr), buf+4, 4);
                        addr->sin_family = PF_INET;
                        addr->sin_port = *(short*)(buf+8);
                        byteused = 10;
                        break;
                case 3 : // a domain name
                        *plen = sizeof(struct sockaddr_in);
                        memset (addr, 0, *plen);
                        {
                                struct hostent *remotehost;
                                char hostname[256];
                                hostname[255] = '\0';
                                memcpy (hostname, buf + 5, buf[4]);
                                hostname[buf[4]] = '\0';
                                /*
                                System::LogInfo (6, "resolve domainname = %s\n", hostname);
                                */
                                remotehost = gethostbyname(hostname);
                                if (remotehost!=NULL)
                                {
                                        memcpy( &(addr->sin_addr),
                                                        remotehost->h_addr,
                                                        remotehost->h_length);
                                        byteused =  5 + buf[4] + 2;
                                }
                                addr->sin_family = PF_INET;
                                addr->sin_port = *(short*)(buf+5+buf[4]);
                        }
                        break;
                case 4 : // a IP v6 address
                        addr->sin_family = PF_INET6;
                        addr->sin_port = * ((short*) (buf + 10));
                        // byteused = 12;
                        throw Exception(Exception::E_NOT_IMPLEMENTED);
                        break;
        }

        return byteused;
}

char*
SocksProxy::UnpackUDPData (char* buf, const size_t bufsize,
                                struct sockaddr_in* addr, socklen_t *plen)
{
        char* result = NULL;
        int byteused;

        // SOCKS5 : the first 2 byte must be 00 00
        if (buf[0]!='\0' || buf[1]!='\0')
                return result;
        // we do not support fragment
        if (buf[2]!='\0')
                return result;
        byteused = ParseRequestAddress( buf, addr, plen);
        if (byteused > 0)
                result = buf + byteused;

        return result;
}

void
SocksProxy::CloseAllSockets()
{
        if (socketToClient != -1) {
                close (socketToClient);
                socketToClient = -1;
        }

        if (socketToRemote != -1) {
                close (socketToRemote);
                socketToRemote = -1;
        }

        if (socketUDP != -1) {
                close (socketUDP);
                socketUDP = -1;
        }
}

// default the program is not running as daemong
int System::isDaemon = 0;

// make this program a daemon
void System:: Daemonize (const char* progname, int facility)
{
        int i;
        pid_t pid;

        pid = fork();
        if (pid!=0)
                exit (0); // the parent process will exit

        // 1st child process goes on
        setsid(); // becomes a session leader
        signal (SIGHUP, SIG_IGN); // a daemon ignores the HUP signal
        pid = fork(); // folk again
        if (pid!=0)
                exit (0); // 1st child terminates

        // 2nd child goes on
        // set the global flag indicate we are in deamon mode
        isDaemon = 1;
        chdir("/");  // change the working directory
        umask(0);

        // close all the file descriptors
        // assume max number of filedescriptor is 64 ???
        for (i=0; i < 64; i++)
                close (i);

        // will log pid with each log message
        openlog (progname, LOG_PID, facility);
}

void System::Cleanup (void)
{
        if (isDaemon)
                closelog();
}

int System::LogInfo (int level, const char* fmt, ...)
{
        char    logmsg[200];
        va_list ap;

        va_start (ap, fmt);
        vsnprintf(logmsg, 200, fmt, ap);

        if (isDaemon)
                syslog (6, logmsg);
        else
                fputs (logmsg, stderr);

        va_end (ap);
        return 0;
}

// print out the usage and then exit
void usage (void)
{
        puts ("usage:");
        puts ("  ezsocks [-d] [-a <addr>] [-p<port>]");
        puts ("  -d          deamon mode, run the proxy as a daemon.");
        puts ("  -a <addr>   listen on the given IP address.");
        puts ("  -p <port>   listen on the given port number.");
        exit (1);
}


//  program start point
int
main (int argc, char* argv[])
{
int argChecked;
int result = 0;
char* listenAddr = NULL;
int   listenPort = 1080;

        argChecked = 1;
        while (argChecked < argc )
        {
                if (strcmp(argv[argChecked], "-d")==0) {
                        System:aemonize ("SocksProxy", LOG_DAEMON);
                        argChecked ++;
                        continue;
                }
                if (strcmp(argv[argChecked], "-a")==0) {
                        argChecked ++;
                        if (argChecked < argc) {
                                listenAddr = argv[argChecked];
                                argChecked ++;
                        } else {
                                usage();
                        }
                        continue;
                }
                if (strcmp(argv[argChecked], "-p")==0) {
                        argChecked ++;
                        if (argChecked < argc) {
                                listenPort = atoi(argv[argChecked]);
                                argChecked ++;
                                if (listenPort==0)
                                        usage();
                        } else {
                                usage();
                        }
                        continue;
                }
                usage();
        }

        result = SocksProxy::Run(listenAddr, listenPort);
        System::Cleanup();
        return result;
} [/php]
 楼主| 发表于 2003-4-16 15:14:10 | 显示全部楼层
我才刚开始学习C++,只是粗通语法。但个人感觉SocksProxy好象太庞杂了一点,而system类就很清晰。建议把线程处理的部分分隔开来。也可以单独封装一个socket类。main()函数中的命令行参数处理完全可以用getopt()函数,比自己处理字符串要方便。个人意见。
发表于 2003-4-16 21:59:20 | 显示全部楼层
是啊,我非常同意。实际上我也那么改了,可是就是程序从几百行变成了几千行了。:)学到不少东西。

getopt() 是不错,可是我只打算那么一个参数,所以懒惰到用。为了要用GNU的那个版本,还需要学习。
 楼主| 发表于 2003-4-17 07:25:33 | 显示全部楼层
我觉得从这件事我们也能得到一些启发:C++的面向对象机制是为了便于维护开发大型程序的开发而采用的。如果只是几百行的小程序,有时用C++的面向对象机制反而是画蛇添足。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表