|
发表于 2003-4-15 22:36:27
|
显示全部楼层
- /*
- * $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 = "Protocol 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::ParseRequestAddress (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::Listen (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::LogInfo (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::LogInfo(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::LogInfo (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::LogInfo (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::LogInfo (6, e.ToString());
- }
- System::LogInfo (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::LogInfo (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::LogInfo (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::LogInfo (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::ProcessRequest()
- {
- 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::ProcessRequestV5 (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::PackUDPData (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::ParseRequestAddress (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::Daemonize ("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;
- }
复制代码 |
|