├── src ├── basic.h ├── CMakeLists.txt ├── basic.cpp ├── message_log.h ├── proxy_server.h ├── dns_cache.h ├── dns_server.h ├── main.cpp ├── profile.h ├── assembly_line.h ├── dns_cache.cpp ├── message_log.cpp ├── connection.h ├── proxy_server.cpp ├── dns_server.cpp ├── profile.cpp ├── assembly_line.cpp └── connection.cpp ├── CMakeLists.txt ├── README.md └── doc ├── rfc1929.txt └── rfc1928.txt /src/basic.h: -------------------------------------------------------------------------------- 1 | #ifndef __BASIC_H__ 2 | #define __BASIC_H__ 3 | 4 | #include 5 | #include 6 | 7 | void SetIPv6AddrWithIPv4 (struct sockaddr_in6 *p_add, char *add); 8 | 9 | void SetIPv6AddrWithIPv6 (struct sockaddr_in6 *p_add, char *add); 10 | 11 | #define STEP_TIME_OUT 1000000 12 | 13 | #endif /*__BASIC_H__*/ 14 | 15 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | SET(SRC_LIST main.cpp 2 | connection.cpp 3 | assembly_line.cpp 4 | proxy_server.cpp 5 | message_log.cpp 6 | profile.cpp 7 | dns_server.cpp 8 | dns_cache.cpp 9 | basic.cpp 10 | ) 11 | 12 | ADD_EXECUTABLE(octopus-socks5 ${SRC_LIST}) 13 | 14 | TARGET_LINK_LIBRARIES(octopus-socks5 pthread) 15 | 16 | -------------------------------------------------------------------------------- /src/basic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "basic.h" 5 | 6 | void SetIPv6AddrWithIPv4 (struct sockaddr_in6 *p_add, char *add) 7 | { 8 | bzero (&p_add->sin6_addr.s6_addr[0], 10); 9 | memset (&p_add->sin6_addr.s6_addr[10], 0xff, 2); 10 | memcpy (&p_add->sin6_addr.s6_addr[12], add, 4); 11 | } 12 | 13 | void SetIPv6AddrWithIPv6 (struct sockaddr_in6 *p_add, char *add) 14 | { 15 | memcpy (&p_add->sin6_addr.s6_addr[0], add, 16); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/message_log.h: -------------------------------------------------------------------------------- 1 | #ifndef __MESSAGE_LOG_H__ 2 | #define __MESSAGE_LOG_H__ 3 | 4 | #include 5 | 6 | void log_printf(const char *format, ...)__attribute__((format(printf, 1, 2))); 7 | 8 | int LogInit (char *log_dir); 9 | 10 | void LogUninit (); 11 | 12 | /* 13 | * LOGE() 在任何情况下都输出,LOGI (只有定义DEBUG 才输出) 14 | */ 15 | #define LOGE(format, ...) log_printf(format, ##__VA_ARGS__) 16 | 17 | #ifdef DEBUG 18 | #define LOGI(format, ...) log_printf(format, ##__VA_ARGS__) 19 | #else 20 | #define LOGI(format, ...) 21 | #endif 22 | 23 | #endif /*__MESSAGE_LOG_H__*/ 24 | -------------------------------------------------------------------------------- /src/proxy_server.h: -------------------------------------------------------------------------------- 1 | #ifndef __CLASS_PROXY_SERVER__ 2 | #define __CLASS_PROXY_SERVER__ 3 | 4 | #include "assembly_line.h" 5 | #include "profile.h" 6 | #include "dns_server.h" 7 | 8 | class ProxyServer 9 | { 10 | public: 11 | ProxyServer (); 12 | virtual ~ProxyServer (); 13 | bool InitServer (Profile *p_profile); 14 | void Run (); 15 | void CleanUp (); 16 | 17 | private: 18 | int GetCpuSum (); 19 | void SignalHandlerInstall (); 20 | 21 | private: 22 | AssemblyLine *m_AssemblyLines; 23 | int m_AssemblyLineSum; 24 | int m_ListenPort; 25 | long m_HeartBeatCycle; 26 | 27 | DnsServer *m_DnsServer; 28 | 29 | }; 30 | 31 | #endif /*__CLASS_PROXY_SERVER__*/ 32 | -------------------------------------------------------------------------------- /src/dns_cache.h: -------------------------------------------------------------------------------- 1 | #ifndef __CLASS_DNS_CACHE__ 2 | #define __CLASS_DNS_CACHE__ 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | typedef struct DNS_NOOD_ 10 | { 11 | char ip_addr[16]; 12 | struct DNS_NOOD_ *next; 13 | }DNS_NOOD; 14 | 15 | typedef struct DNS_ROOT_ 16 | { 17 | DNS_NOOD *list; 18 | DNS_NOOD *current; 19 | }DNS_ROOT; 20 | 21 | class DnsCache 22 | { 23 | public: 24 | DnsCache (); 25 | ~DnsCache (); 26 | 27 | char *GetIpAddr (char *domainname); 28 | DNS_ROOT *GetDnsRoot (char *domainname); 29 | void AddDNS (char *domainname); 30 | 31 | private: 32 | void FreeNood (DNS_ROOT *p_root); 33 | 34 | private: 35 | map m_MapDNS; 36 | }; 37 | 38 | #endif /*__CLASS_DNS_CACHE__*/ 39 | -------------------------------------------------------------------------------- /src/dns_server.h: -------------------------------------------------------------------------------- 1 | #ifndef __CLASS_DNS_SERVER__ 2 | #define __CLASS_DNS_SERVER__ 3 | 4 | #include "connection.h" 5 | #include "dns_cache.h" 6 | 7 | class DnsServer 8 | { 9 | public: 10 | DnsServer (); 11 | virtual ~DnsServer (); 12 | 13 | bool StartServer (); 14 | bool StopServer (); 15 | static bool DoDNS (Connection *p_target); 16 | static bool UpdateDNS (char *p_address); 17 | 18 | private: 19 | friend void *dns_thread_main (void *p_date); 20 | void DoWork (); 21 | void DoOne (Connection *p_target); 22 | bool Cach (Connection *p_target); 23 | 24 | private: 25 | static int m_SigFd; 26 | static pthread_t m_ThreadID; 27 | static bool m_WorkON; 28 | 29 | DnsCache m_Cache; 30 | }; 31 | 32 | #endif /*__CLASS_DNS_SERVER__*/ 33 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "proxy_server.h" 4 | #include "message_log.h" 5 | #include "profile.h" 6 | 7 | int main (int argc, char*argv[]) 8 | { 9 | bool ret; 10 | Profile *p_Profile; 11 | ProxyServer *p_Sever; 12 | 13 | p_Profile = new Profile (argc, argv); 14 | 15 | LogInit (p_Profile->GetLogDir ()); 16 | 17 | p_Profile->ShowInfor (); 18 | 19 | p_Sever = new ProxyServer (); 20 | 21 | ret = p_Sever->InitServer (p_Profile); 22 | if (!ret) 23 | { 24 | LOGE ("ProxyServer::InitServer Fail!!\n"); 25 | } 26 | else 27 | { 28 | LOGE ("ProxyServer::Run\n"); 29 | p_Sever->Run (); 30 | } 31 | 32 | p_Sever->CleanUp (); 33 | 34 | delete p_Sever; 35 | p_Sever = NULL; 36 | 37 | delete p_Profile; 38 | p_Profile = NULL; 39 | 40 | LogUninit (); 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8) 2 | 3 | project (octopus-socks5) 4 | 5 | #set(CMAKE_CXX_FLAGS "-g -Wall -D DEBUG") 6 | set(CMAKE_CXX_FLAGS_DEBUG "-g -Wall -D DEBUG") 7 | set(CMAKE_CXX_FLAGS_RELEASE "-g -Wall") 8 | 9 | add_subdirectory(src bin) 10 | 11 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 12 | 13 | aux_source_directory (./src DIR_SRCS) 14 | 15 | install(PROGRAMS ${PROJECT_BINARY_DIR}/bin/octopus-socks5 DESTINATION bin) 16 | 17 | set(CPACK_PACKAGE_NAME "octopus-socks5") 18 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "socks5 proxy") 19 | set(CPACK_PACKAGE_VENDOR "NO") 20 | set(CPACK_PACKAGE_VERSION "1.0.0") 21 | set(CPACK_PACKAGE_VERSION_MAJOR "1") 22 | set(CPACK_PACKAGE_VERSION_MINOR "0") 23 | set(CPACK_PACKAGE_VERSION_PATCH "0") 24 | set(CPACK_RPM_PACKAGE_GROUP "octopus") 25 | set(CPACK_RPM_PACKAGE_URL "https://github.com/mgwang37/octopus") 26 | set(CPACK_RPM_PACKAGE_DESCRIPTION "a socks5 proxy") 27 | set(CPACK_PACKAGE_RELEASE 1) 28 | set(CPACK_RPM_PACKAGE_LICENSE "GPL") 29 | 30 | set(CPACK_GENERATOR "RPM") 31 | 32 | include(CPack) 33 | -------------------------------------------------------------------------------- /src/profile.h: -------------------------------------------------------------------------------- 1 | #ifndef __CLASS_PROFILE__ 2 | #define __CLASS_PROFILE__ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #define ADDR_LIST_MAX 16 10 | #define ADDR_LIST_STR_MAX 1024 11 | 12 | class Profile 13 | { 14 | public: 15 | Profile (int argc, char*argv[]); 16 | ~Profile (); 17 | void ShowInfor (); 18 | 19 | int GetListenPort (); 20 | int GetThreadSum (); 21 | char *GetLogDir (); 22 | int GetConnectionSum (); 23 | uint32_t GetHeartBeatCycle (); 24 | int GetAccessMethod (); 25 | char *GetUserListFile (); 26 | struct sockaddr_in6 *GetAddr(); 27 | 28 | private: 29 | void PrintfHelpInfo (); 30 | void GetAddrList (char *optarg); 31 | 32 | private: 33 | int m_ListenPort; 34 | int m_ThreadSum; 35 | char *m_LogDir; 36 | int m_ConnectionPerThread; 37 | uint32_t m_HeartBeatCycle; 38 | int m_AccessMethod; 39 | char *m_UserListFile; 40 | struct sockaddr_in6 m_addr_list[ADDR_LIST_MAX]; 41 | char m_AddrListStr[ADDR_LIST_STR_MAX]; 42 | int m_AddrListSum; 43 | int m_AddrListIndex; 44 | 45 | }; 46 | 47 | #endif /*__CLASS_PROFILE__*/ 48 | -------------------------------------------------------------------------------- /src/assembly_line.h: -------------------------------------------------------------------------------- 1 | #ifndef __CLASS_ASSEMBLY_LINE__ 2 | #define __CLASS_ASSEMBLY_LINE__ 3 | 4 | #include 5 | #include 6 | 7 | #include "connection.h" 8 | 9 | class ProxyServer; 10 | 11 | class AssemblyLine 12 | { 13 | public: 14 | AssemblyLine (); 15 | virtual ~AssemblyLine (); 16 | void Init (int Listen_port, int connect_sum, int wait_time, int method); 17 | void Start (int cpu_index); 18 | void Stop (); 19 | void Run (); 20 | 21 | private: 22 | friend class ProxyServer; 23 | static void HeartBeat (int cycle); 24 | void BindCPU (); 25 | void InitConnectionPool (); 26 | void FreeConnectionPool (); 27 | 28 | Connection *AllocConnection (uint64_t &index); 29 | void FreeConnection (Connection *p_tmp); 30 | 31 | void AddToUseList (Connection *p_tmp); 32 | 33 | int CreatListenSd (); 34 | void CloseListenSd (); 35 | 36 | int CreatEpollFd (); 37 | void CloseEpollFd (); 38 | 39 | void DoRecovery (); 40 | void DoWork (); 41 | void NewConnection (); 42 | 43 | private: 44 | Connection *m_ConnectionFreeList; 45 | Connection *m_ConnectionUseList; 46 | Connection *m_Connections; 47 | 48 | int m_ConnectSum; 49 | int m_ListenPort; 50 | int m_CpuId; 51 | static long m_HeartBeatTimes; 52 | long m_HeartBeatTimesLast; 53 | pthread_t m_ThreadID; 54 | bool m_WorkON; 55 | 56 | int m_ListenSd; 57 | int m_EpollFd; 58 | int m_EpollWaitTime; 59 | 60 | int m_client_sum; 61 | }; 62 | 63 | #endif /*__CLASS_ASSEMBLY_LINE__*/ 64 | -------------------------------------------------------------------------------- /src/dns_cache.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "dns_cache.h" 5 | #include "message_log.h" 6 | 7 | DnsCache::DnsCache () 8 | { 9 | } 10 | 11 | DnsCache::~DnsCache () 12 | { 13 | map::iterator iter; 14 | 15 | for(iter = m_MapDNS.begin(); iter != m_MapDNS.end(); iter++) 16 | { 17 | FreeNood (&iter->second); 18 | } 19 | 20 | } 21 | 22 | void DnsCache::FreeNood (DNS_ROOT *p_root) 23 | { 24 | DNS_NOOD *p_tmp; 25 | 26 | p_tmp = p_root->list; 27 | 28 | while (p_tmp) 29 | { 30 | DNS_NOOD *pp; 31 | pp = p_tmp; 32 | free (pp); 33 | p_tmp = p_tmp->next; 34 | } 35 | 36 | } 37 | 38 | char *DnsCache::GetIpAddr (char *domainname) 39 | { 40 | char ppp[128]; 41 | 42 | char *ret_val = NULL; 43 | DNS_ROOT * p_root; 44 | 45 | p_root = GetDnsRoot (domainname); 46 | 47 | if (p_root == NULL) 48 | { 49 | return NULL; 50 | } 51 | else 52 | { 53 | if (p_root->list == NULL) 54 | { 55 | return NULL; 56 | } 57 | 58 | if (p_root->current == NULL) 59 | { 60 | p_root->current = p_root->list; 61 | } 62 | 63 | ret_val = p_root->current->ip_addr; 64 | 65 | p_root->current = p_root->current->next; 66 | inet_ntop (AF_INET6, ret_val, ppp, 128); 67 | LOGI ("[%s]\n", ppp); 68 | return ret_val; 69 | } 70 | 71 | } 72 | 73 | void DnsCache::AddDNS (char *domainname) 74 | { 75 | DNS_ROOT p_tmp; 76 | 77 | p_tmp.list = NULL; 78 | p_tmp.current = NULL; 79 | 80 | m_MapDNS.insert(pair(domainname, p_tmp)); 81 | } 82 | 83 | DNS_ROOT *DnsCache::GetDnsRoot (char *domainname) 84 | { 85 | map::iterator iter; 86 | 87 | iter = m_MapDNS.find(domainname); 88 | 89 | if (iter != m_MapDNS.end()) 90 | { 91 | return &iter->second; 92 | } 93 | else 94 | { 95 | return NULL; 96 | } 97 | } 98 | 99 | -------------------------------------------------------------------------------- /src/message_log.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include /* for exit */ 10 | #include 11 | 12 | 13 | #include "message_log.h" 14 | 15 | #define LogFileName "Proxy" 16 | 17 | static pthread_spinlock_t log_lock; 18 | static char log_dir[512]; 19 | static FILE *f_output = NULL; 20 | 21 | static void update () 22 | { 23 | static int current_day = 0; 24 | struct tm gmtm; 25 | time_t curTime; 26 | char full_name[512]; 27 | 28 | if (log_dir[0] == 0) 29 | { 30 | return; 31 | } 32 | 33 | time(&curTime); 34 | localtime_r(&curTime, &gmtm); 35 | 36 | if ((f_output == NULL) || (current_day != gmtm.tm_mday)) 37 | { 38 | if (f_output) 39 | { 40 | fclose (f_output); 41 | f_output = NULL; 42 | } 43 | current_day = gmtm.tm_mday; 44 | sprintf (full_name, "%s/%s-%d-%04d-%02d-%02d.log", log_dir, LogFileName, getpid(), gmtm.tm_year+1900, gmtm.tm_mon+1, gmtm.tm_mday); 45 | 46 | f_output = fopen (full_name, "w+"); 47 | } 48 | fprintf (f_output, "[%04d-%02d-%02d %02d:%02d:%02d]:", gmtm.tm_year+1900, gmtm.tm_mon+1, gmtm.tm_mday, gmtm.tm_hour, gmtm.tm_min, gmtm.tm_sec); 49 | } 50 | 51 | void log_printf(const char *format, ...) 52 | { 53 | va_list ap; 54 | 55 | pthread_spin_lock(&log_lock); 56 | update (); 57 | va_start(ap, format); 58 | vfprintf (f_output, format, ap); 59 | va_end(ap); 60 | pthread_spin_unlock(&log_lock); 61 | } 62 | 63 | int LogInit (char *log_file_dir) 64 | { 65 | log_dir[0] = 0; 66 | 67 | if (log_file_dir == NULL) 68 | { 69 | f_output = stdout; 70 | } 71 | else 72 | { 73 | f_output = NULL; 74 | strcat (log_dir, log_file_dir); 75 | } 76 | 77 | pthread_spin_init(&log_lock, PTHREAD_PROCESS_PRIVATE); 78 | return 0; 79 | } 80 | 81 | void LogUninit () 82 | { 83 | pthread_spin_lock(&log_lock); 84 | 85 | if (log_dir[0] != 0) 86 | { 87 | if (f_output) 88 | { 89 | fclose (f_output); 90 | f_output = NULL; 91 | } 92 | } 93 | pthread_spin_unlock(&log_lock); 94 | 95 | pthread_spin_destroy(&log_lock); 96 | } 97 | 98 | -------------------------------------------------------------------------------- /src/connection.h: -------------------------------------------------------------------------------- 1 | #ifndef __CLASS_CONNECTION__ 2 | #define __CLASS_CONNECTION__ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "profile.h" 10 | 11 | #define BUFFER_LEN 2048 12 | 13 | #include 14 | #include 15 | 16 | using namespace std; 17 | 18 | class Connection 19 | { 20 | public: 21 | typedef enum 22 | { 23 | eStepNew, 24 | eStepGetMethod, 25 | eStepGetAccess, 26 | eStepGetProtocol, 27 | eStepTcpCreat, 28 | eStepTcpConnecting, 29 | eStepTcpConnected, 30 | eStepTcpClosing, 31 | eStepClosed, 32 | eStepFree, 33 | }WorkStep; 34 | 35 | typedef enum 36 | { 37 | eMethodNull = 0x0, 38 | eMethodGSSAPI = 0x1, 39 | eMethodUSERNAME_PASSWORD = 0x2, 40 | }Method; 41 | 42 | Connection (); 43 | virtual ~Connection (); 44 | void DoWork (int type, uint32_t mask, long p_time); 45 | void InitNewOne (int new_socket, long p_time, int epollfd); 46 | static void SetSocketAttr (int socket); 47 | static bool LoadUserList (char *file_name); 48 | static void SetProfile (Profile *file); 49 | 50 | private: 51 | void DoGetMethod (int type, uint32_t mask, long p_time); 52 | void DoGetAccess (int type, uint32_t mask, long p_time); 53 | void DoGetProtocol (int type, uint32_t mask, long p_time); 54 | void DoTcpCreat (int type, uint32_t mask, long p_time); 55 | void DoTcpConnecting (int type, uint32_t mask, long p_time); 56 | void DoTcpConnected (int type, uint32_t mask, long p_time); 57 | void DoTcpClosing (int type, uint32_t mask, long p_time); 58 | 59 | int AnalyzeProtocolRequests (char *p_mem, int length, int &cmd); 60 | 61 | private: 62 | friend class AssemblyLine; 63 | friend class DnsServer; 64 | WorkStep m_Step; 65 | 66 | static Method m_Method; 67 | static Profile *m_Profile; 68 | 69 | int m_ControlSd; 70 | int m_ConnectSd; 71 | 72 | int m_Epollfd; 73 | 74 | char m_OutBuffer[BUFFER_LEN]; 75 | int m_OutStart; 76 | int m_OutStop; 77 | 78 | char m_InBuffer[BUFFER_LEN]; 79 | int m_InStart; 80 | int m_InStop; 81 | 82 | long m_LastTime; 83 | 84 | bool m_ClientAddrOK; 85 | struct sockaddr_in6 m_ClientAddr; 86 | char m_Domainname[260]; 87 | 88 | static map m_UserList; 89 | 90 | int m_Index; 91 | Connection *m_next; 92 | }; 93 | 94 | #endif /*__CLASS_CONNECTION__*/ 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # octopus 2 | # 1、中文 3 | ## (1)特点 4 | 1. 支持TCP代理 5 | 1. 支持IPv6 6 | 1. 支持用户名密码验证 7 | 1. 支持DNS 8 | 1. 高并发高性能 9 | 10 | ## (2)编译 11 | * $ cd builder/ 12 | * $ cmake ../ -DCMAKE_BUILD_TYPE=Debug 或者 cmake ../ -DCMAKE_BUILD_TYPE=Release 13 | * $ make 14 | * $ cpack 15 | 16 | ## (3)运行 17 |  配置从命令行输入,详细参数可以使用帮助: 18 | 19 | ``` 20 |  $ octopus-socks5 -h 21 | --listen.port listen port 22 | --thread.sum thread sum 23 | --log.dir log output dir 24 | --thread.connections.sum the max connections of per thread 25 | --heartbeat.cycle heartbeat cycle microseconds (must small 1000000!) 26 | --access.method access method : 0 (anonymous), 2(USERNAME/PASSWORD) 27 | --userlist userlist file 28 |   --addr.list NIC address list, use like this --addr.list 192.168.1.1,192.168.1.2 29 | --help or -v this message 30 | 31 | ``` 32 | 33 | * --listen.port :监听的端口 34 | * --thread.sum :线程数量 35 | * --log.dir :log信息输出的路径 36 | * --thread.connections.sum :每个线程最大的连接数 37 | * --heartbeat.cycle  :超时心跳的间隔 38 | * --access.method :登录方法,0是匿名,2是用户名密码方式,用户名单用  --userlist  指定 39 | * --userlist :在 --access.method 为2时指定用户名单 40 | * --addr.list :在多网卡系统上可以指定数据从哪几个地址出去,这样可以增加整个系统的连接上限,使用方法:--addr.list 192.168.1.1,192.168.1.2 41 | * --help or -v :打印帮助信息 42 | 43 | ## (4)常见问题 44 | ### 1、连接数受限 45 | 1. #echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range 46 | 47 | 1. 添加 * - nofile 500000 到文件 /etc/security/limits.conf   48 | 49 | 50 | 51 | # 2、English 52 | ## (1) Features 53 | 1. Support TCP proxy 54 | 1. Support IPv6 55 | 1. Support user name and password verification 56 | 1. Support DNS 57 | 1. High concurrency and high performance 58 | 59 | ## (2)compile 60 | * $ cd builder / 61 | * $ cmake ../ -DCMAKE_BUILD_TYPE=Debug or cmake ../ -DCMAKE_BUILD_TYPE=Release 62 | * $ make 63 | * $ cpack 64 | 65 | ## (3)run 66 | Configuration input from the command line, detailed parameters can be used to help: 67 | 68 | ``` 69 |  $ octopus-socks5 -h 70 | --listen.port listen port 71 | --thread.sum thread sum 72 | --log.dir log output dir 73 | --thread.connections.sum the max connections of per thread 74 | --heartbeat.cycle heartbeat cycle microseconds (must small 1000000!) 75 | --access.method access method : 0 (anonymous), 2(USERNAME/PASSWORD) --userlist set the USERNAME/PASSWORD 76 | --userlist userlist file (see builder/userlist.txt) 77 | --addr.list NIC address list, use like this --addr.list 192.168.1.1,192.168.1.2 78 | --help or -v this message 79 | 80 | ``` 81 | 82 | ## (4)Question 83 | ### 1、connect limit 84 | 85 | 1. #echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range 86 | 87 | 1. add * - nofile 500000 to file /etc/security/limits.conf   88 | 89 | -------------------------------------------------------------------------------- /src/proxy_server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "proxy_server.h" 10 | #include "message_log.h" 11 | 12 | static bool m_WorkON = false; 13 | 14 | static void c_sigaction_fun (int sig) 15 | { 16 | m_WorkON = false; 17 | } 18 | 19 | ProxyServer::ProxyServer () 20 | { 21 | m_AssemblyLines = NULL; 22 | } 23 | 24 | int ProxyServer::GetCpuSum () 25 | { 26 | int ret; 27 | char p_mem[256]; 28 | FILE *p_sh = NULL; 29 | 30 | p_sh = popen ("cat /proc/cpuinfo|grep processor|wc -l", "r"); 31 | fread (p_mem, 1, 64, p_sh); 32 | ret = atoi (p_mem); 33 | pclose (p_sh); 34 | 35 | return ret; 36 | } 37 | 38 | ProxyServer::~ProxyServer () 39 | { 40 | } 41 | 42 | void ProxyServer::SignalHandlerInstall () 43 | { 44 | struct sigaction action; 45 | 46 | memset(&action, 0x00, sizeof(struct sigaction)); 47 | 48 | action.sa_handler = &c_sigaction_fun; 49 | sigemptyset(&(action.sa_mask)); 50 | sigaddset(&(action.sa_mask), SIGINT); 51 | action.sa_flags = 0; 52 | sigaction(SIGINT, &action, 0); 53 | } 54 | 55 | bool ProxyServer::InitServer (Profile *p_profile) 56 | { 57 | int p_cpu_sum; 58 | 59 | m_ListenPort = p_profile->GetListenPort (); 60 | m_AssemblyLineSum = p_profile->GetThreadSum (); 61 | m_HeartBeatCycle = p_profile->GetHeartBeatCycle (); 62 | 63 | Connection::SetProfile (p_profile); 64 | 65 | p_cpu_sum = GetCpuSum (); 66 | 67 | LOGE ("CPU sum :%d\n", p_cpu_sum); 68 | 69 | if (m_AssemblyLineSum > p_cpu_sum) 70 | { 71 | LOGE ("pthread-sum > CPU sum !!\n"); 72 | return false; 73 | } 74 | 75 | if (m_ListenPort ==0 || m_ListenPort > 65535) 76 | { 77 | LOGE ("m_ListenPort invalid !!\n"); 78 | return false; 79 | } 80 | 81 | if (p_profile->GetAccessMethod () == 0x02) 82 | { 83 | if (0 == Connection::LoadUserList (p_profile->GetUserListFile())) 84 | { 85 | LOGE ("load userlist file faile!!\n"); 86 | return false; 87 | } 88 | } 89 | 90 | m_AssemblyLines = new AssemblyLine[m_AssemblyLineSum]; 91 | 92 | for (int i = 0; i < m_AssemblyLineSum; i++) 93 | { 94 | m_AssemblyLines[i].Init (m_ListenPort, p_profile->GetConnectionSum(), m_HeartBeatCycle, p_profile->GetAccessMethod ()); 95 | } 96 | 97 | SignalHandlerInstall (); 98 | return true; 99 | } 100 | 101 | void ProxyServer::Run () 102 | { 103 | for (int i = 0; i < m_AssemblyLineSum; i++) 104 | { 105 | m_AssemblyLines[i].Start (i); 106 | } 107 | 108 | m_WorkON = true; 109 | 110 | m_DnsServer = new DnsServer (); 111 | 112 | m_DnsServer->StartServer (); 113 | 114 | while (m_WorkON) 115 | { 116 | usleep (m_HeartBeatCycle); 117 | AssemblyLine::HeartBeat (m_HeartBeatCycle); 118 | } 119 | 120 | m_DnsServer->StopServer (); 121 | delete m_DnsServer; 122 | m_DnsServer = NULL; 123 | 124 | for (int i = 0; i < m_AssemblyLineSum; i++) 125 | { 126 | m_AssemblyLines[i].Stop(); 127 | } 128 | 129 | sleep (1); 130 | } 131 | 132 | void ProxyServer::CleanUp () 133 | { 134 | delete [] m_AssemblyLines; 135 | m_AssemblyLines = NULL; 136 | } 137 | 138 | -------------------------------------------------------------------------------- /doc/rfc1929.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Network Working Group M. Leech 8 | Request for Comments: 1929 Bell-Northern Research Ltd 9 | Category: Standards Track March 1996 10 | 11 | 12 | Username/Password Authentication for SOCKS V5 13 | 14 | Status of this Memo 15 | 16 | This document specifies an Internet standards track protocol for the 17 | Internet community, and requests discussion and suggestions for 18 | improvements. Please refer to the current edition of the "Internet 19 | Official Protocol Standards" (STD 1) for the standardization state 20 | and status of this protocol. Distribution of this memo is unlimited. 21 | 22 | 1. Introduction 23 | 24 | The protocol specification for SOCKS Version 5 specifies a 25 | generalized framework for the use of arbitrary authentication 26 | protocols in the initial socks connection setup. This document 27 | describes one of those protocols, as it fits into the SOCKS Version 5 28 | authentication "subnegotiation". 29 | 30 | Note: 31 | 32 | Unless otherwise noted, the decimal numbers appearing in packet- 33 | format diagrams represent the length of the corresponding field, in 34 | octets. Where a given octet must take on a specific value, the 35 | syntax X'hh' is used to denote the value of the single octet in that 36 | field. When the word 'Variable' is used, it indicates that the 37 | corresponding field has a variable length defined either by an 38 | associated (one or two octet) length field, or by a data type field. 39 | 40 | 2. Initial negotiation 41 | 42 | Once the SOCKS V5 server has started, and the client has selected the 43 | Username/Password Authentication protocol, the Username/Password 44 | subnegotiation begins. This begins with the client producing a 45 | Username/Password request: 46 | 47 | +----+------+----------+------+----------+ 48 | |VER | ULEN | UNAME | PLEN | PASSWD | 49 | +----+------+----------+------+----------+ 50 | | 1 | 1 | 1 to 255 | 1 | 1 to 255 | 51 | +----+------+----------+------+----------+ 52 | 53 | 54 | 55 | 56 | 57 | 58 | Leech Standards Track [Page 1] 59 | 60 | RFC 1929 Username Authentication for SOCKS V5 March 1996 61 | 62 | 63 | The VER field contains the current version of the subnegotiation, 64 | which is X'01'. The ULEN field contains the length of the UNAME field 65 | that follows. The UNAME field contains the username as known to the 66 | source operating system. The PLEN field contains the length of the 67 | PASSWD field that follows. The PASSWD field contains the password 68 | association with the given UNAME. 69 | 70 | The server verifies the supplied UNAME and PASSWD, and sends the 71 | following response: 72 | 73 | +----+--------+ 74 | |VER | STATUS | 75 | +----+--------+ 76 | | 1 | 1 | 77 | +----+--------+ 78 | 79 | A STATUS field of X'00' indicates success. If the server returns a 80 | `failure' (STATUS value other than X'00') status, it MUST close the 81 | connection. 82 | 83 | 3. Security Considerations 84 | 85 | This document describes a subnegotiation that provides authentication 86 | services to the SOCKS protocol. Since the request carries the 87 | password in cleartext, this subnegotiation is not recommended for 88 | environments where "sniffing" is possible and practical. 89 | 90 | 4. Author's Address 91 | 92 | Marcus Leech 93 | Bell-Northern Research Ltd 94 | P.O. Box 3511, Station C 95 | Ottawa, ON 96 | CANADA K1Y 4H7 97 | 98 | Phone: +1 613 763 9145 99 | EMail: mleech@bnr.ca 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | Leech Standards Track [Page 2] 115 | 116 | -------------------------------------------------------------------------------- /src/dns_server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "dns_server.h" 16 | #include "message_log.h" 17 | #include "basic.h" 18 | 19 | #define PTHREAD_STACK_SIZE (1024*1024*80) 20 | 21 | int DnsServer::m_SigFd = -1; 22 | pthread_t DnsServer::m_ThreadID; 23 | bool DnsServer::m_WorkON = false; 24 | 25 | void *dns_thread_main (void *p_date) 26 | { 27 | DnsServer *p_server = (DnsServer*)p_date; 28 | 29 | p_server->DoWork (); 30 | return NULL; 31 | } 32 | 33 | DnsServer::DnsServer () 34 | { 35 | } 36 | 37 | DnsServer::~DnsServer () 38 | { 39 | } 40 | 41 | bool DnsServer::StartServer () 42 | { 43 | if (m_WorkON) 44 | { 45 | return false; 46 | } 47 | m_WorkON = true; 48 | 49 | pthread_attr_t s5thread_attribute; 50 | 51 | pthread_attr_init(&s5thread_attribute); 52 | pthread_attr_setstacksize(&s5thread_attribute, PTHREAD_STACK_SIZE); 53 | pthread_attr_setscope(&s5thread_attribute, PTHREAD_SCOPE_SYSTEM); 54 | pthread_attr_setdetachstate(&s5thread_attribute, PTHREAD_CREATE_DETACHED); 55 | 56 | if(pthread_create(&m_ThreadID, &s5thread_attribute, &dns_thread_main, this) < 0) 57 | { 58 | LOGE ("DnsServer pthread_create faile!!\n"); 59 | return false; 60 | } 61 | 62 | return true; 63 | } 64 | 65 | bool DnsServer::StopServer () 66 | { 67 | if (m_WorkON == false) 68 | { 69 | return false; 70 | } 71 | 72 | m_WorkON = false; 73 | 74 | DoDNS (NULL); 75 | 76 | return true; 77 | } 78 | 79 | bool DnsServer::UpdateDNS (char *p_address) 80 | { 81 | return true; 82 | } 83 | 84 | bool DnsServer::DoDNS (Connection *p_target) 85 | { 86 | union sigval ooo; 87 | int ret; 88 | int p_times = 300; 89 | 90 | ooo.sival_ptr = (void*)p_target; 91 | 92 | again: 93 | ret = pthread_sigqueue (m_ThreadID, 35, ooo); 94 | if (ret != 0 && p_times--) 95 | { 96 | usleep (1); 97 | goto again; 98 | } 99 | 100 | if (p_times > 0) 101 | { 102 | return true; 103 | } 104 | else 105 | { 106 | return false; 107 | } 108 | } 109 | 110 | bool DnsServer::Cach (Connection *p_target) 111 | { 112 | char *ip; 113 | 114 | ip = m_Cache.GetIpAddr (p_target->m_Domainname); 115 | 116 | if (ip) 117 | { 118 | SetIPv6AddrWithIPv6 (&p_target->m_ClientAddr, ip); 119 | p_target->m_ClientAddrOK = true; 120 | return true; 121 | } 122 | else 123 | { 124 | return false; 125 | } 126 | } 127 | 128 | void DnsServer::DoOne (Connection *p_target) 129 | { 130 | struct addrinfo *answer, hint, *curr; 131 | 132 | bzero(&hint, sizeof(hint)); 133 | hint.ai_family = AF_UNSPEC; 134 | hint.ai_socktype = SOCK_STREAM; 135 | hint.ai_protocol = 0; 136 | hint.ai_flags = AI_PASSIVE; 137 | 138 | answer = NULL; 139 | int ret = getaddrinfo(p_target->m_Domainname, NULL, &hint, &answer); 140 | if (ret != 0) 141 | { 142 | p_target->m_ClientAddrOK = false; 143 | freeaddrinfo(answer); 144 | return ; 145 | } 146 | 147 | m_Cache.AddDNS (p_target->m_Domainname); 148 | 149 | DNS_ROOT *p_dns_root; 150 | 151 | p_dns_root = m_Cache.GetDnsRoot (p_target->m_Domainname); 152 | 153 | for (curr = answer; curr != NULL; curr = curr->ai_next) 154 | { 155 | DNS_NOOD *p_dns_nood; 156 | 157 | p_dns_nood = (DNS_NOOD*)malloc (sizeof(DNS_NOOD)); 158 | p_dns_nood->next = p_dns_root->list; 159 | p_dns_root->list = p_dns_nood; 160 | 161 | if (curr->ai_family == AF_INET6) 162 | { 163 | 164 | p_target->m_ClientAddr.sin6_addr = ((struct sockaddr_in6 *)curr->ai_addr)->sin6_addr; 165 | 166 | } 167 | else if (curr->ai_family == AF_INET) 168 | { 169 | SetIPv6AddrWithIPv4 (&p_target->m_ClientAddr, (char*)&(((struct sockaddr_in *)(curr->ai_addr))->sin_addr)); 170 | } 171 | memcpy (p_dns_nood->ip_addr, &p_target->m_ClientAddr.sin6_addr, 16); 172 | //break; 173 | } 174 | 175 | freeaddrinfo(answer); 176 | p_target->m_ClientAddrOK = true; 177 | } 178 | 179 | void DnsServer::DoWork () 180 | { 181 | struct signalfd_siginfo p_mem[2000]; 182 | sigset_t sig_set; 183 | 184 | sigemptyset(&sig_set); 185 | sigaddset (&sig_set, 35); 186 | sigprocmask (SIG_BLOCK, &sig_set, 0); 187 | 188 | m_SigFd = signalfd (-1, &sig_set, 0); 189 | 190 | while (m_WorkON) 191 | { 192 | int ret_sum; 193 | 194 | ret_sum = read (m_SigFd, p_mem, sizeof(p_mem)); 195 | if (ret_sum <= 0) 196 | { 197 | continue; 198 | } 199 | ret_sum = ret_sum / sizeof(struct signalfd_siginfo); 200 | 201 | for (int i=0; i < ret_sum; i++) 202 | { 203 | Connection *p_node; 204 | 205 | p_node = (Connection*)p_mem[i].ssi_ptr; 206 | 207 | if (p_node == NULL) 208 | { 209 | continue; 210 | } 211 | 212 | if (Cach (p_node)) 213 | { 214 | continue; 215 | } 216 | else 217 | { 218 | DoOne (p_node); 219 | } 220 | } 221 | } 222 | 223 | close (m_SigFd); 224 | m_SigFd = -1; 225 | } 226 | 227 | -------------------------------------------------------------------------------- /src/profile.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include "profile.h" 9 | #include "message_log.h" 10 | 11 | void Profile::PrintfHelpInfo () 12 | { 13 | printf ("--listen.port listen port\n"); 14 | printf ("--thread.sum thread sum\n"); 15 | printf ("--log.dir log output dir\n"); 16 | printf ("--thread.connections.sum the max connections of per thread\n"); 17 | printf ("--heartbeat.cycle heartbeat cycle microseconds (must small 1000000!)\n"); 18 | printf ("--access.method access method : 0 (anonymous), 2(USERNAME/PASSWORD)\n"); 19 | printf ("--userlist userlist file \n"); 20 | printf ("--addr.list NIC address list, use like this --addr.list 192.168.1.1,192.168.1.2 \n"); 21 | printf ("--help or -v this message\n"); 22 | } 23 | 24 | Profile::Profile (int argc, char *argv[]):m_ListenPort(1024),m_ThreadSum(1),m_LogDir(NULL),m_ConnectionPerThread (1000), 25 | m_HeartBeatCycle(100000),m_AccessMethod (0) 26 | { 27 | int c; 28 | int option_index = 0; 29 | 30 | m_AddrListSum = 0; 31 | bzero (m_AddrListStr, ADDR_LIST_STR_MAX); 32 | 33 | struct option long_options[] = 34 | { 35 | {"listen.port", required_argument, 0, 0 }, 36 | {"thread.sum", required_argument, 0, 0 }, 37 | {"log.dir", required_argument, 0, 0 }, 38 | {"thread.connections.sum", required_argument, 0, 0 }, 39 | {"heartbeat.cycle", required_argument, 0, 0 }, 40 | {"access.method", required_argument, 0, 0 }, 41 | {"userlist", required_argument, 0, 0 }, 42 | {"help", no_argument, 0, 0 }, 43 | {"addr.list", required_argument, 0, 0 }, 44 | {0 , 0, 0, 0} 45 | }; 46 | 47 | while (1) 48 | { 49 | c = getopt_long(argc, argv, "h", long_options, &option_index); 50 | if (c == -1) 51 | { 52 | break; 53 | } 54 | 55 | if (c == 'h') 56 | { 57 | PrintfHelpInfo (); 58 | exit (0); 59 | } 60 | else if (c == 0) 61 | { 62 | switch (option_index) 63 | { 64 | case 0: 65 | m_ListenPort = atoi (optarg); 66 | break; 67 | case 1: 68 | m_ThreadSum = atoi (optarg); 69 | break; 70 | case 2: 71 | m_LogDir = strdup (optarg); 72 | break; 73 | case 3: 74 | m_ConnectionPerThread = atoi (optarg); 75 | break; 76 | case 4: 77 | m_HeartBeatCycle = atoi (optarg); 78 | break; 79 | case 5: 80 | m_AccessMethod = atoi (optarg); 81 | break; 82 | case 6: 83 | m_UserListFile = strdup (optarg); 84 | break; 85 | case 7: 86 | PrintfHelpInfo (); 87 | exit (0); 88 | case 8: 89 | GetAddrList (optarg); 90 | break; 91 | } 92 | } 93 | } 94 | 95 | } 96 | 97 | struct sockaddr_in6 *Profile::GetAddr() 98 | { 99 | if (m_AddrListSum == 0) 100 | { 101 | return NULL; 102 | } 103 | 104 | if (m_AddrListIndex >= m_AddrListSum) 105 | { 106 | m_AddrListIndex = 0; 107 | } 108 | 109 | LOGI ("m_AddrListIndex = %d\n", m_AddrListIndex); 110 | 111 | return &m_addr_list[m_AddrListIndex++]; 112 | } 113 | 114 | void Profile::GetAddrList (char *optarg) 115 | { 116 | char p_tmp[256]; 117 | char *p_str; 118 | int p_tmp_index = 0; 119 | 120 | m_AddrListStr[0] = 0; 121 | 122 | strcat (m_AddrListStr, optarg); 123 | 124 | p_str = &m_AddrListStr[0]; 125 | 126 | if (*p_str == 0) 127 | { 128 | return; 129 | } 130 | 131 | while (1) 132 | { 133 | if (*p_str == '\0') 134 | { 135 | p_tmp[p_tmp_index] = 0; 136 | p_tmp_index = 0; 137 | 138 | m_addr_list[m_AddrListSum].sin6_family = AF_INET6; 139 | m_addr_list[m_AddrListSum].sin6_port = 0; 140 | inet_pton (AF_INET6, p_tmp, m_addr_list[m_AddrListSum].sin6_addr.s6_addr); 141 | m_AddrListSum ++; 142 | break; 143 | } 144 | else if (*p_str == ',') 145 | { 146 | p_tmp[p_tmp_index] = 0; 147 | p_tmp_index = 0; 148 | 149 | m_addr_list[m_AddrListSum].sin6_family = AF_INET6; 150 | m_addr_list[m_AddrListSum].sin6_port = 0; 151 | inet_pton (AF_INET6, p_tmp, m_addr_list[m_AddrListSum].sin6_addr.s6_addr); 152 | m_AddrListSum ++; 153 | } 154 | else 155 | { 156 | p_tmp[p_tmp_index] = *p_str; 157 | } 158 | 159 | p_str ++; 160 | } 161 | } 162 | 163 | uint32_t Profile::GetHeartBeatCycle () 164 | { 165 | return m_HeartBeatCycle; 166 | } 167 | 168 | int Profile::GetConnectionSum () 169 | { 170 | return m_ConnectionPerThread; 171 | } 172 | 173 | void Profile::ShowInfor () 174 | { 175 | LOGE ("=========ProfileInfor=============\n"); 176 | LOGE (" m_LogDir = %s\n", m_LogDir); 177 | LOGE (" m_ListenPort = %d\n", m_ListenPort); 178 | LOGE (" m_ThreadSum = %d\n", m_ThreadSum); 179 | LOGE (" m_ConnectionPerThread = %d\n", m_ConnectionPerThread); 180 | LOGE (" m_HeartBeatCycle = %d\n", m_HeartBeatCycle); 181 | LOGE (" m_AccessMethod = %d\n", m_AccessMethod); 182 | LOGE (" m_UserListFile = %s\n", m_UserListFile); 183 | LOGE (" m_AddrListStr = %s\n", m_AddrListStr); 184 | LOGE ("==================================\n"); 185 | } 186 | 187 | Profile::~Profile () 188 | { 189 | free (m_LogDir); 190 | m_LogDir = NULL; 191 | free (m_UserListFile); 192 | m_UserListFile = NULL; 193 | } 194 | 195 | char *Profile::GetLogDir () 196 | { 197 | return m_LogDir; 198 | } 199 | 200 | char *Profile::GetUserListFile () 201 | { 202 | return m_UserListFile; 203 | } 204 | 205 | int Profile::GetListenPort () 206 | { 207 | return m_ListenPort; 208 | } 209 | 210 | int Profile::GetThreadSum () 211 | { 212 | return m_ThreadSum; 213 | } 214 | 215 | int Profile::GetAccessMethod () 216 | { 217 | return m_AccessMethod; 218 | } 219 | 220 | -------------------------------------------------------------------------------- /src/assembly_line.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "assembly_line.h" 11 | #include "message_log.h" 12 | 13 | #define PTHREAD_STACK_SIZE (1024*1024*10) 14 | 15 | #define MAX_EVENTS 512 16 | 17 | long AssemblyLine::m_HeartBeatTimes = 0; 18 | 19 | static void *AssemblyLinePthreadMain (void *p_date) 20 | { 21 | AssemblyLine *p_tmp = (AssemblyLine *)p_date; 22 | 23 | p_tmp->Run (); 24 | return NULL; 25 | } 26 | 27 | AssemblyLine::AssemblyLine () 28 | { 29 | m_ConnectionFreeList = NULL; 30 | m_ConnectionUseList = NULL; 31 | m_Connections = NULL; 32 | } 33 | 34 | AssemblyLine::~AssemblyLine () 35 | { 36 | } 37 | 38 | void AssemblyLine::DoRecovery () 39 | { 40 | Connection *p_current; 41 | Connection *p_prov; 42 | 43 | p_prov = NULL; 44 | p_current = m_ConnectionUseList; 45 | 46 | while (p_current) 47 | { 48 | 49 | if (p_current->m_Step == Connection::eStepClosed) 50 | { 51 | Connection *p_tmp; 52 | 53 | if (p_prov == NULL) 54 | { 55 | p_tmp = m_ConnectionUseList; 56 | m_ConnectionUseList = m_ConnectionUseList->m_next; 57 | FreeConnection (p_tmp); 58 | 59 | p_current = m_ConnectionUseList; 60 | p_prov = NULL; 61 | } 62 | else 63 | { 64 | p_tmp = p_current; 65 | 66 | p_current = p_current->m_next; 67 | p_prov->m_next = p_current; 68 | FreeConnection (p_tmp); 69 | } 70 | continue; 71 | } 72 | else 73 | { 74 | p_current->DoWork (0x03, 0x00, m_HeartBeatTimes); 75 | } 76 | 77 | p_prov = p_current; 78 | p_current = p_current->m_next; 79 | } 80 | } 81 | 82 | void AssemblyLine::NewConnection () 83 | { 84 | struct epoll_event ev; 85 | struct sockaddr_in6 client_addr; 86 | int new_socket; 87 | Connection *p_new_connect; 88 | uint64_t new_connect_id; 89 | socklen_t addrlen = sizeof(client_addr); 90 | 91 | new_socket = accept(m_ListenSd, (struct sockaddr *)&client_addr, &addrlen); 92 | 93 | Connection::SetSocketAttr (new_socket); 94 | 95 | p_new_connect = AllocConnection (new_connect_id); 96 | 97 | if (p_new_connect == NULL) 98 | { 99 | LOGE ("AllocConnection fail!!\n"); 100 | close (new_socket); 101 | return; 102 | } 103 | 104 | p_new_connect->InitNewOne (new_socket, m_HeartBeatTimes, m_EpollFd); 105 | 106 | AddToUseList (p_new_connect); 107 | 108 | ev.events = EPOLLIN|EPOLLRDHUP; 109 | ev.data.u64 = (new_connect_id << 32) | 0x01; 110 | 111 | if (epoll_ctl(m_EpollFd, EPOLL_CTL_ADD, new_socket, &ev) == -1) 112 | { 113 | LOGE ("NewConnection epoll_ctl fail!!\n"); 114 | exit(EXIT_FAILURE); 115 | } 116 | 117 | } 118 | 119 | void AssemblyLine::AddToUseList (Connection *p_tmp) 120 | { 121 | p_tmp->m_next = m_ConnectionUseList; 122 | m_ConnectionUseList = p_tmp; 123 | } 124 | 125 | void AssemblyLine::DoWork () 126 | { 127 | struct epoll_event events[MAX_EVENTS]; 128 | int nfds; 129 | 130 | nfds = epoll_wait(m_EpollFd, events, MAX_EVENTS, m_EpollWaitTime); 131 | if (nfds < 0) 132 | { 133 | return; 134 | } 135 | 136 | for (int i = 0; i < nfds; i++) 137 | { 138 | int p_fd, p_type; 139 | 140 | p_fd = events[i].data.u64 >> 32; 141 | p_type = events[i].data.u64 & 0xffffffff; 142 | 143 | if (p_fd == m_ListenSd && p_type == 0) 144 | { 145 | NewConnection (); 146 | } 147 | else 148 | { 149 | m_Connections[p_fd].DoWork (p_type, events[i].events, m_HeartBeatTimes); 150 | } 151 | 152 | } 153 | 154 | } 155 | 156 | void AssemblyLine::Run () 157 | { 158 | m_WorkON = true; 159 | 160 | BindCPU (); 161 | InitConnectionPool (); 162 | 163 | m_ListenSd = CreatListenSd (); 164 | m_EpollFd = CreatEpollFd (); 165 | 166 | while (m_WorkON) 167 | { 168 | DoWork (); 169 | if (m_HeartBeatTimes != m_HeartBeatTimesLast) 170 | { 171 | DoRecovery (); 172 | m_HeartBeatTimesLast = m_HeartBeatTimes; 173 | } 174 | } 175 | 176 | CloseEpollFd (); 177 | CloseListenSd (); 178 | FreeConnectionPool (); 179 | } 180 | 181 | void AssemblyLine::Start (int cpu_index) 182 | { 183 | pthread_attr_t s5thread_attribute; 184 | 185 | pthread_attr_init(&s5thread_attribute); 186 | pthread_attr_setstacksize(&s5thread_attribute, PTHREAD_STACK_SIZE); 187 | pthread_attr_setscope(&s5thread_attribute, PTHREAD_SCOPE_SYSTEM); 188 | pthread_attr_setdetachstate(&s5thread_attribute, PTHREAD_CREATE_DETACHED); 189 | 190 | m_CpuId = cpu_index; 191 | 192 | if(pthread_create(&m_ThreadID, &s5thread_attribute, &AssemblyLinePthreadMain, this) < 0) 193 | { 194 | LOGE ("pthread_create faile!!\n"); 195 | exit (-1); 196 | } 197 | } 198 | 199 | int AssemblyLine::CreatListenSd () 200 | { 201 | int p_sd; 202 | 203 | p_sd = socket (AF_INET6, SOCK_STREAM, 0); 204 | if (p_sd < 0) 205 | { 206 | LOGE ("CreatListenSd error !!\n"); 207 | exit (-1); 208 | } 209 | 210 | int opt = 1; 211 | if(setsockopt(p_sd, SOL_SOCKET, SO_REUSEPORT, (const void *)&opt, sizeof(opt)) == -1) 212 | { 213 | LOGE ("SO_REUSEPORT error !!\n"); 214 | exit (-1); 215 | } 216 | 217 | if(setsockopt(p_sd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(opt)) == -1) 218 | { 219 | LOGE ("SO_REUSEADDR, error !!\n"); 220 | exit (-1); 221 | } 222 | 223 | struct sockaddr_in6 addr; 224 | memset ((char*) &(addr),0, sizeof((addr))); 225 | addr.sin6_family = AF_INET6; 226 | addr.sin6_port = htons (m_ListenPort); 227 | addr.sin6_addr = in6addr_any; 228 | 229 | if (bind (p_sd, (struct sockaddr*)&addr, sizeof(addr)) != 0) 230 | { 231 | LOGE ("bind, error !!\n"); 232 | exit (-1); 233 | } 234 | 235 | if (listen (p_sd, 1024) == -1) 236 | { 237 | LOGE ("listen, error !!\n"); 238 | exit (-1); 239 | } 240 | 241 | return p_sd; 242 | } 243 | 244 | void AssemblyLine::CloseListenSd () 245 | { 246 | close (m_ListenSd); 247 | m_ListenSd = -1; 248 | } 249 | 250 | int AssemblyLine::CreatEpollFd () 251 | { 252 | struct epoll_event ev; 253 | int fd; 254 | uint64_t p_uin64; 255 | 256 | fd = epoll_create(MAX_EVENTS); 257 | 258 | if (fd == -1) 259 | { 260 | LOGE ("epoll_create error !!\n"); 261 | exit (-1); 262 | } 263 | 264 | ev.events = EPOLLIN; 265 | p_uin64 = m_ListenSd; 266 | ev.data.u64 = p_uin64 << 32; 267 | 268 | if (epoll_ctl(fd, EPOLL_CTL_ADD, m_ListenSd, &ev) == -1) 269 | { 270 | LOGE("epoll_ctl: listen_sock\n"); 271 | exit(EXIT_FAILURE); 272 | } 273 | 274 | return fd; 275 | } 276 | 277 | void AssemblyLine::CloseEpollFd () 278 | { 279 | close (m_EpollFd); 280 | m_EpollFd = -1; 281 | } 282 | 283 | void AssemblyLine::BindCPU () 284 | { 285 | int ret_val; 286 | 287 | cpu_set_t cpuset; 288 | 289 | CPU_ZERO (&cpuset); 290 | CPU_SET (m_CpuId, &cpuset); 291 | ret_val = pthread_setaffinity_np (m_ThreadID, sizeof(cpuset), &cpuset); 292 | 293 | if (ret_val == 0) 294 | { 295 | LOGE ("CPU[%d] BIND [OK] !\n", m_CpuId); 296 | } 297 | } 298 | 299 | void AssemblyLine::InitConnectionPool () 300 | { 301 | m_Connections = new Connection[m_ConnectSum](); 302 | 303 | for (int i =0; i < m_ConnectSum; i++) 304 | { 305 | FreeConnection (&m_Connections[i]); 306 | } 307 | m_client_sum = 0; 308 | } 309 | 310 | void AssemblyLine::FreeConnectionPool () 311 | { 312 | delete [] m_Connections; 313 | m_Connections = NULL; 314 | } 315 | 316 | Connection *AssemblyLine::AllocConnection (uint64_t &index) 317 | { 318 | Connection *p_tmp; 319 | 320 | p_tmp = m_ConnectionFreeList; 321 | 322 | if (p_tmp == NULL) 323 | { 324 | return NULL; 325 | } 326 | 327 | m_ConnectionFreeList = m_ConnectionFreeList->m_next; 328 | 329 | index = p_tmp - m_Connections; 330 | 331 | p_tmp->m_Index = index; 332 | p_tmp->m_Step = Connection::eStepNew; 333 | 334 | m_client_sum ++; 335 | LOGI ("++thread %d sum %d\n", m_CpuId, m_client_sum); 336 | 337 | return p_tmp; 338 | } 339 | 340 | void AssemblyLine::FreeConnection (Connection *p_tmp) 341 | { 342 | p_tmp->m_Step = Connection::eStepFree; 343 | p_tmp->m_next = m_ConnectionFreeList; 344 | m_ConnectionFreeList = p_tmp; 345 | 346 | m_client_sum --; 347 | LOGI ("--thread %d sum %d\n", m_CpuId, m_client_sum); 348 | } 349 | 350 | void AssemblyLine::Stop () 351 | { 352 | m_WorkON = false; 353 | } 354 | 355 | void AssemblyLine::Init (int Listen_port, int connect_sum, int wait_time, int method) 356 | { 357 | m_ListenPort = Listen_port; 358 | 359 | m_ConnectSum = connect_sum; 360 | 361 | m_EpollWaitTime = wait_time/1000; 362 | 363 | Connection::m_Method = (Connection::Method)method; 364 | } 365 | 366 | void AssemblyLine::HeartBeat (int cycle) 367 | { 368 | m_HeartBeatTimes += cycle; 369 | } 370 | 371 | -------------------------------------------------------------------------------- /src/connection.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "connection.h" 14 | #include "message_log.h" 15 | #include "dns_server.h" 16 | #include "basic.h" 17 | 18 | Connection::Method Connection::m_Method = Connection::eMethodNull; 19 | 20 | map Connection::m_UserList; 21 | 22 | Profile *Connection::m_Profile; 23 | 24 | void Connection::SetSocketAttr (int socket) 25 | { 26 | struct linger pp; 27 | 28 | pp.l_onoff = 1; 29 | pp.l_linger = 0; 30 | 31 | setsockopt (socket, SOL_SOCKET, SO_LINGER, &pp, sizeof(pp)); 32 | 33 | unsigned int timeout = STEP_TIME_OUT; 34 | 35 | setsockopt(socket, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout, sizeof(timeout)); 36 | 37 | int keep_alive = 1, keep_idle = 10, keep_interval = 1, keep_count = 5; 38 | 39 | setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &keep_alive, sizeof(keep_alive)); 40 | setsockopt(socket, IPPROTO_TCP, TCP_KEEPIDLE, &keep_idle, sizeof(keep_idle)); 41 | setsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL, &keep_interval, sizeof(keep_interval)); 42 | setsockopt(socket, IPPROTO_TCP, TCP_KEEPCNT, &keep_count, sizeof(keep_count)); 43 | } 44 | 45 | 46 | Connection::Connection () 47 | { 48 | m_Step = eStepNew; 49 | } 50 | 51 | Connection::~Connection () 52 | { 53 | if (m_ControlSd > 0) 54 | { 55 | close (m_ControlSd); 56 | m_ControlSd = -1; 57 | } 58 | 59 | if (m_ConnectSd > 0) 60 | { 61 | close (m_ConnectSd); 62 | m_ConnectSd = -1; 63 | } 64 | } 65 | 66 | void Connection::InitNewOne (int new_socket, long p_time, int epollfd) 67 | { 68 | m_ControlSd = new_socket; 69 | m_ConnectSd = -1;; 70 | m_Step = Connection::eStepGetMethod; 71 | m_OutStart = 0; 72 | m_OutStop = 0; 73 | m_InStart = 0; 74 | m_InStop = 0; 75 | m_LastTime = p_time; 76 | m_Epollfd = epollfd; 77 | } 78 | 79 | void Connection::DoWork (int type, uint32_t mask, long p_time) 80 | { 81 | switch (m_Step) 82 | { 83 | case eStepGetMethod: 84 | DoGetMethod (type, mask, p_time); 85 | break; 86 | case eStepGetAccess: 87 | DoGetAccess (type, mask, p_time); 88 | break; 89 | case eStepGetProtocol: 90 | DoGetProtocol (type, mask, p_time); 91 | break; 92 | case eStepTcpCreat: 93 | DoTcpCreat (type, mask, p_time); 94 | break; 95 | case eStepTcpConnecting: 96 | DoTcpConnecting (type, mask, p_time); 97 | break; 98 | case eStepTcpConnected: 99 | DoTcpConnected (type, mask, p_time); 100 | break; 101 | case eStepTcpClosing: 102 | DoTcpClosing (type, mask, p_time); 103 | break; 104 | default: 105 | LOGE ("Connection::DoWork switch (%d) type = %d !!\n", m_Step, type); 106 | } 107 | } 108 | 109 | void Connection::DoGetMethod (int type, uint32_t mask, long p_time) 110 | { 111 | //超时处理 112 | if (type != 1) 113 | { 114 | if (p_time - m_LastTime > STEP_TIME_OUT) 115 | { 116 | m_Step = eStepClosed; 117 | close (m_ControlSd); 118 | m_ControlSd = -1; 119 | LOGE ("[DoGetMethod] time out !!\n"); 120 | } 121 | return ; 122 | } 123 | 124 | /****/ 125 | m_OutStop = recv (m_ControlSd, m_OutBuffer, BUFFER_LEN, MSG_DONTWAIT); 126 | if (m_OutStop <= 0) 127 | { 128 | m_Step = eStepClosed; 129 | close (m_ControlSd); 130 | m_ControlSd = -1; 131 | return ; 132 | } 133 | 134 | if (!((m_OutBuffer[0] == 5) && (m_OutBuffer[1] == m_OutStop-2))) 135 | { 136 | m_Step = eStepClosed; 137 | close (m_ControlSd); 138 | m_ControlSd = -1; 139 | return ; 140 | } 141 | 142 | int p_method = -1; 143 | for (int i= 2; i < m_OutStop; i++) 144 | { 145 | if (m_OutBuffer[i] == m_Method) 146 | { 147 | p_method = m_Method; 148 | break; 149 | } 150 | } 151 | 152 | if (p_method == -1) 153 | { 154 | m_OutBuffer[0] = 0x05; 155 | m_OutBuffer[1] = 0xFF; 156 | send (m_ControlSd, m_OutBuffer, 2, MSG_DONTWAIT|MSG_NOSIGNAL); 157 | m_Step = eStepTcpClosing; 158 | m_LastTime = p_time; 159 | } 160 | else 161 | { 162 | m_OutBuffer[0] = 0x05; 163 | m_OutBuffer[1] = m_Method; 164 | send (m_ControlSd, m_OutBuffer, 2, MSG_DONTWAIT|MSG_NOSIGNAL); 165 | 166 | switch (m_Method) 167 | { 168 | case 0x00: 169 | m_Step = eStepGetProtocol; 170 | break; 171 | case 0x01: 172 | m_Step = eStepGetAccess; 173 | break; 174 | case 0x02: 175 | m_Step = eStepGetAccess; 176 | break; 177 | } 178 | m_LastTime = p_time; 179 | } 180 | 181 | } 182 | 183 | bool Connection::LoadUserList (char *file) 184 | { 185 | FILE *fp; 186 | char *line = NULL; 187 | int read; 188 | size_t len = 0; 189 | 190 | fp = fopen (file, "r"); 191 | if (NULL == fp) 192 | { 193 | return false; 194 | } 195 | 196 | while ((read = getline(&line, &len, fp)) != -1) 197 | { 198 | int rett; 199 | char name[256]; 200 | char password[256]; 201 | 202 | rett = sscanf (line, "%s %s", name, password); 203 | if (rett != 2) 204 | { 205 | fclose (fp); 206 | return false; 207 | } 208 | 209 | m_UserList.insert(pair(name, password)); 210 | } 211 | 212 | fclose (fp); 213 | return true; 214 | } 215 | 216 | int Connection::AnalyzeProtocolRequests (char *p_mem, int length, int &cmd) 217 | { 218 | if (p_mem[0] != 0x05) 219 | { 220 | return 1; 221 | } 222 | 223 | cmd = p_mem[1]; 224 | 225 | if (p_mem[2] != 0x00) 226 | { 227 | return 1; 228 | } 229 | 230 | int p_len ; 231 | switch (p_mem[3]) 232 | { 233 | case 0x01: 234 | m_ClientAddrOK = true; 235 | m_ClientAddr.sin6_family = AF_INET6; 236 | 237 | SetIPv6AddrWithIPv4 (&m_ClientAddr, &p_mem[4]); 238 | memcpy (&m_ClientAddr.sin6_port, &p_mem[8], 2); 239 | break; 240 | case 0x03: 241 | m_ClientAddrOK = false; 242 | p_len = p_mem[4]; 243 | memcpy (m_Domainname, &p_mem[5], p_len); 244 | m_Domainname[p_len] = 0; 245 | memcpy (&m_ClientAddr.sin6_port, &p_mem[5 + p_len], 2); 246 | DnsServer::DoDNS (this); 247 | m_ClientAddr.sin6_family = AF_INET6; 248 | break; 249 | case 0x04: 250 | m_ClientAddrOK = true; 251 | m_ClientAddr.sin6_family = AF_INET6; 252 | SetIPv6AddrWithIPv6 (&m_ClientAddr, &p_mem[4]); 253 | memcpy (&m_ClientAddr.sin6_port, &p_mem[20], 2); 254 | break; 255 | default: 256 | return 2; 257 | } 258 | 259 | return 0; 260 | } 261 | 262 | void Connection::DoGetProtocol (int type, uint32_t mask, long p_time) 263 | { 264 | //超时处理 265 | if (type != 1) 266 | { 267 | if (p_time - m_LastTime > STEP_TIME_OUT) 268 | { 269 | m_Step = eStepClosed; 270 | close (m_ControlSd); 271 | m_ControlSd = -1; 272 | LOGE ("[DoGetProtocol] time out !!\n"); 273 | } 274 | return ; 275 | } 276 | 277 | /****/ 278 | m_OutStop = recv (m_ControlSd, m_OutBuffer, BUFFER_LEN, MSG_DONTWAIT); 279 | if (m_OutStop <= 0) 280 | { 281 | m_Step = eStepClosed; 282 | close (m_ControlSd); 283 | m_ControlSd = -1; 284 | return ; 285 | } 286 | 287 | /****/ 288 | int p_cmd = -1; 289 | int b_ret; 290 | 291 | b_ret = AnalyzeProtocolRequests (m_OutBuffer, m_OutStop, p_cmd); 292 | 293 | if (b_ret == 1) 294 | { 295 | m_Step = eStepClosed; 296 | close (m_ControlSd); 297 | m_ControlSd = -1; 298 | return ; 299 | } 300 | else if (b_ret == 2) 301 | { 302 | m_OutBuffer[1] = 0x08; 303 | send (m_ControlSd, m_OutBuffer, m_OutStop, MSG_DONTWAIT|MSG_NOSIGNAL); 304 | m_Step = eStepTcpClosing; 305 | m_LastTime = p_time; 306 | return ; 307 | } 308 | 309 | switch (p_cmd) 310 | { 311 | case 0x01: 312 | if (m_ClientAddrOK == true) 313 | { 314 | m_Step = eStepTcpCreat; 315 | m_LastTime = p_time; 316 | DoWork (type, mask, p_time); 317 | } 318 | else 319 | { 320 | m_Step = eStepTcpCreat; 321 | m_LastTime = p_time; 322 | } 323 | break; 324 | case 0x02: 325 | break; 326 | case 0x03: 327 | break; 328 | default: 329 | m_OutBuffer[1] = 0x07; 330 | send (m_ControlSd, m_OutBuffer, m_OutStop, MSG_DONTWAIT|MSG_NOSIGNAL); 331 | m_Step = eStepTcpClosing; 332 | m_LastTime = p_time; 333 | return ; 334 | } 335 | 336 | } 337 | 338 | void Connection::DoGetAccess (int type, uint32_t mask, long p_time) 339 | { 340 | char user_name[256]; 341 | char pass_word[256]; 342 | int ULEN; 343 | int PLEN; 344 | 345 | m_OutStop = recv (m_ControlSd, m_OutBuffer, BUFFER_LEN, MSG_DONTWAIT); 346 | 347 | if (m_OutBuffer[0] != 1) 348 | { 349 | m_Step = eStepTcpClosing; 350 | return; 351 | } 352 | 353 | ULEN = m_OutBuffer[1]; 354 | 355 | if (ULEN >= m_OutStop) 356 | { 357 | m_Step = eStepTcpClosing; 358 | return; 359 | } 360 | 361 | bzero (user_name, 256); 362 | memcpy (user_name, &m_OutBuffer[2], ULEN); 363 | 364 | PLEN = m_OutBuffer[2 + ULEN]; 365 | 366 | if (m_OutStop != (ULEN + PLEN + 3)) 367 | { 368 | m_Step = eStepTcpClosing; 369 | return; 370 | } 371 | 372 | bzero (pass_word, 256); 373 | memcpy (pass_word, &m_OutBuffer[3 + ULEN], PLEN); 374 | 375 | map::iterator iter; 376 | 377 | iter = m_UserList.find (user_name); 378 | 379 | if (iter == m_UserList.end()) 380 | { 381 | m_OutBuffer[0] = 1; 382 | m_OutBuffer[1] = 1; 383 | m_Step = eStepTcpClosing; 384 | } 385 | else 386 | { 387 | if (iter->second == pass_word) 388 | { 389 | m_OutBuffer[0] = 1; 390 | m_OutBuffer[1] = 0; 391 | m_Step = eStepGetProtocol; 392 | } 393 | else 394 | { 395 | m_OutBuffer[0] = 1; 396 | m_OutBuffer[1] = 1; 397 | m_Step = eStepTcpClosing; 398 | } 399 | } 400 | 401 | send (m_ControlSd, m_OutBuffer, 2, MSG_DONTWAIT|MSG_NOSIGNAL); 402 | m_OutStart = 0; 403 | m_OutStop = 0; 404 | m_LastTime = p_time; 405 | } 406 | 407 | void Connection::DoTcpCreat (int type, uint32_t mask, long p_time) 408 | { 409 | if (false == m_ClientAddrOK) 410 | { 411 | if (p_time - m_LastTime > STEP_TIME_OUT*5) 412 | { 413 | m_OutBuffer[1] = 0x06; 414 | send (m_ControlSd, m_OutBuffer, m_OutStop, MSG_DONTWAIT|MSG_NOSIGNAL); 415 | m_Step = eStepTcpClosing; 416 | m_LastTime = p_time; 417 | LOGE ("[DoTcpCreat] time out !!\n"); 418 | } 419 | return; 420 | } 421 | 422 | m_ConnectSd = socket (AF_INET6, SOCK_STREAM|SOCK_NONBLOCK, 0); 423 | if (m_ConnectSd == -1) 424 | { 425 | m_OutBuffer[1] = 0x01; 426 | send (m_ControlSd, m_OutBuffer, m_OutStop, MSG_DONTWAIT|MSG_NOSIGNAL); 427 | m_Step = eStepTcpClosing; 428 | m_LastTime = p_time; 429 | LOGE ("DoTcpCreat !!\n"); 430 | return ; 431 | } 432 | 433 | SetSocketAttr (m_ConnectSd); 434 | 435 | struct sockaddr_in6 *p_ip_addr = m_Profile->GetAddr (); 436 | 437 | if (p_ip_addr) 438 | { 439 | int ret; 440 | 441 | ret = bind (m_ConnectSd, (const struct sockaddr *)p_ip_addr, sizeof(sockaddr_in6)); 442 | 443 | if (ret == -1) 444 | { 445 | close (m_ConnectSd); 446 | m_ConnectSd = -1; 447 | m_Step = eStepTcpClosing; 448 | LOGE ("TcpBind !!\n"); 449 | return; 450 | } 451 | LOGI ("bind OK!\n"); 452 | } 453 | 454 | connect (m_ConnectSd, (struct sockaddr *)&m_ClientAddr, sizeof(m_ClientAddr)); 455 | m_Step = eStepTcpConnecting; 456 | m_LastTime = p_time; 457 | } 458 | 459 | void Connection::DoTcpConnecting (int type, uint32_t mask, long p_time) 460 | { 461 | int p_err; 462 | socklen_t p_len; 463 | 464 | p_len = sizeof (int); 465 | getsockopt (m_ConnectSd, SOL_SOCKET, SO_ERROR, &p_err, &p_len); 466 | if (p_err == EINPROGRESS) 467 | { 468 | if (p_time - m_LastTime > STEP_TIME_OUT*4) 469 | { 470 | m_Step = eStepTcpClosing; 471 | m_LastTime = p_time; 472 | LOGE ("DoTcpConnecting:EINPROGRESS"); 473 | } 474 | return; 475 | } 476 | else if (p_err == ENETUNREACH) 477 | { 478 | m_OutBuffer[1] = 0x03; 479 | send (m_ControlSd, m_OutBuffer, m_OutStop, MSG_DONTWAIT|MSG_NOSIGNAL); 480 | m_Step = eStepTcpClosing; 481 | m_LastTime = p_time; 482 | LOGE ("DoTcpConnecting:ENETUNREACH"); 483 | return; 484 | } 485 | else if (p_err == ECONNREFUSED) 486 | { 487 | m_OutBuffer[1] = 0x05; 488 | send (m_ControlSd, m_OutBuffer, m_OutStop, MSG_DONTWAIT|MSG_NOSIGNAL); 489 | m_Step = eStepTcpClosing; 490 | m_LastTime = p_time; 491 | LOGE ("DoTcpConnecting:ECONNREFUSED"); 492 | return; 493 | } 494 | 495 | struct epoll_event ev; 496 | uint64_t p_64id = m_Index; 497 | 498 | ev.events = EPOLLRDHUP | EPOLLIN; 499 | ev.data.u64 = p_64id << 32 | 0x02; 500 | 501 | if (epoll_ctl(m_Epollfd, EPOLL_CTL_ADD, m_ConnectSd, &ev) == -1) 502 | { 503 | LOGE ("Connection::DoTcpConnecting epoll_ctl !!\n"); 504 | } 505 | 506 | m_OutBuffer[1] = 0; 507 | send (m_ControlSd, m_OutBuffer, m_OutStop, MSG_DONTWAIT|MSG_NOSIGNAL); 508 | 509 | m_Step = eStepTcpConnected; 510 | 511 | m_OutStart = 0; 512 | m_OutStop = 0; 513 | } 514 | 515 | void Connection::SetProfile (Profile *file) 516 | { 517 | m_Profile = file; 518 | } 519 | 520 | void Connection::DoTcpConnected (int type, uint32_t mask, long p_time) 521 | { 522 | if (m_OutStart == m_OutStop) 523 | { 524 | m_OutStart = 0; 525 | m_OutStop = 0; 526 | } 527 | 528 | if (m_InStart == m_InStop) 529 | { 530 | m_InStart = 0; 531 | m_InStop = 0; 532 | } 533 | 534 | if (m_ControlSd > 0 && BUFFER_LEN > m_OutStop) 535 | { 536 | int ret_sum; 537 | 538 | ret_sum = recv (m_ControlSd, &m_OutBuffer[m_OutStop], BUFFER_LEN - m_OutStop, MSG_DONTWAIT); 539 | if (ret_sum > 0) 540 | { 541 | m_OutStop += ret_sum; 542 | } 543 | else if (ret_sum == 0) 544 | { 545 | close (m_ControlSd); 546 | m_ControlSd = -1; 547 | m_Step = eStepTcpClosing; 548 | m_LastTime = p_time; 549 | } 550 | } 551 | 552 | if (m_ConnectSd > 0 && BUFFER_LEN > m_InStop) 553 | { 554 | int ret_sum; 555 | 556 | ret_sum = recv (m_ConnectSd, &m_InBuffer[m_InStop], BUFFER_LEN - m_InStop, MSG_DONTWAIT); 557 | if (ret_sum > 0) 558 | { 559 | m_InStop += ret_sum; 560 | } 561 | else if (ret_sum == 0) 562 | { 563 | close (m_ConnectSd); 564 | m_ConnectSd = -1; 565 | m_Step = eStepTcpClosing; 566 | m_LastTime = p_time; 567 | } 568 | } 569 | 570 | 571 | if (m_ControlSd > 0 && m_InStop > m_InStart) 572 | { 573 | int ret_sum; 574 | 575 | ret_sum = send (m_ControlSd, &m_InBuffer[m_InStart], m_InStop - m_InStart, MSG_DONTWAIT|MSG_NOSIGNAL); 576 | if (ret_sum > 0) 577 | { 578 | m_InStart += ret_sum; 579 | } 580 | else if (ret_sum < 0 && errno != EAGAIN) 581 | { 582 | close (m_ControlSd); 583 | m_ControlSd = -1; 584 | m_Step = eStepTcpClosing; 585 | m_LastTime = p_time; 586 | } 587 | } 588 | 589 | if (m_ConnectSd > 0 && m_OutStop > m_OutStart) 590 | { 591 | int ret_sum; 592 | 593 | ret_sum = send (m_ConnectSd, &m_OutBuffer[m_OutStart], m_OutStop - m_OutStart, MSG_DONTWAIT|MSG_NOSIGNAL); 594 | if (ret_sum > 0) 595 | { 596 | m_OutStart += ret_sum; 597 | } 598 | else if (ret_sum < 0 && errno != EAGAIN) 599 | { 600 | //perror ("send"); 601 | close (m_ConnectSd); 602 | m_ConnectSd = -1; 603 | m_Step = eStepTcpClosing; 604 | m_LastTime = p_time; 605 | } 606 | } 607 | 608 | if (mask & EPOLLRDHUP) 609 | { 610 | if (type == 1) 611 | { 612 | close (m_ControlSd); 613 | m_ControlSd = -1; 614 | m_Step = eStepTcpClosing; 615 | m_LastTime = p_time; 616 | } 617 | 618 | if (type == 2) 619 | { 620 | close (m_ConnectSd); 621 | m_ConnectSd = -1; 622 | m_Step = eStepTcpClosing; 623 | m_LastTime = p_time; 624 | } 625 | } 626 | 627 | } 628 | 629 | void Connection::DoTcpClosing (int type, uint32_t mask, long p_time) 630 | { 631 | 632 | if (p_time - m_LastTime > STEP_TIME_OUT*3) 633 | { 634 | if (m_ControlSd > 0) 635 | { 636 | close (m_ControlSd); 637 | m_ControlSd = -1; 638 | } 639 | 640 | if (m_ConnectSd > 0) 641 | { 642 | close (m_ConnectSd); 643 | m_ControlSd = -1; 644 | } 645 | } 646 | 647 | 648 | if (m_ControlSd > 0) 649 | { 650 | if (m_InStop - m_InStart > 0) 651 | { 652 | int ret_sum; 653 | 654 | ret_sum = send (m_ControlSd, &m_InBuffer[m_InStart], m_InStop - m_InStart, MSG_DONTWAIT|MSG_NOSIGNAL); 655 | if (ret_sum > 0) 656 | { 657 | m_InStart += ret_sum; 658 | } 659 | else if (ret_sum < 0 && errno != EAGAIN) 660 | { 661 | close (m_ControlSd); 662 | m_ControlSd = -1; 663 | } 664 | } 665 | else if (m_InStop == m_InStart) 666 | { 667 | close (m_ControlSd); 668 | m_ControlSd = -1; 669 | } 670 | } 671 | 672 | if (m_ConnectSd > 0) 673 | { 674 | if (m_OutStop > m_OutStart) 675 | { 676 | int ret_sum; 677 | 678 | ret_sum = send (m_ConnectSd, &m_OutBuffer[m_OutStart], m_OutStop - m_OutStart, MSG_DONTWAIT|MSG_NOSIGNAL); 679 | if (ret_sum > 0) 680 | { 681 | m_OutStart += ret_sum; 682 | } 683 | else if (ret_sum < 0 && errno != EAGAIN) 684 | { 685 | close (m_ConnectSd); 686 | m_ConnectSd = -1; 687 | } 688 | } 689 | else if (m_OutStop == m_OutStart) 690 | { 691 | close (m_ConnectSd); 692 | m_ConnectSd = -1; 693 | } 694 | } 695 | 696 | if (m_ConnectSd == -1 && m_ControlSd == -1) 697 | { 698 | m_Step = eStepClosed; 699 | } 700 | 701 | } 702 | 703 | -------------------------------------------------------------------------------- /doc/rfc1928.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Network Working Group M. Leech 8 | Request for Comments: 1928 Bell-Northern Research Ltd 9 | Category: Standards Track M. Ganis 10 | International Business Machines 11 | Y. Lee 12 | NEC Systems Laboratory 13 | R. Kuris 14 | Unify Corporation 15 | D. Koblas 16 | Independent Consultant 17 | L. Jones 18 | Hewlett-Packard Company 19 | March 1996 20 | 21 | 22 | SOCKS Protocol Version 5 23 | 24 | Status of this Memo 25 | 26 | This document specifies an Internet standards track protocol for the 27 | Internet community, and requests discussion and suggestions for 28 | improvements. Please refer to the current edition of the "Internet 29 | Official Protocol Standards" (STD 1) for the standardization state 30 | and status of this protocol. Distribution of this memo is unlimited. 31 | 32 | Acknowledgments 33 | 34 | This memo describes a protocol that is an evolution of the previous 35 | version of the protocol, version 4 [1]. This new protocol stems from 36 | active discussions and prototype implementations. The key 37 | contributors are: Marcus Leech: Bell-Northern Research, David Koblas: 38 | Independent Consultant, Ying-Da Lee: NEC Systems Laboratory, LaMont 39 | Jones: Hewlett-Packard Company, Ron Kuris: Unify Corporation, Matt 40 | Ganis: International Business Machines. 41 | 42 | 1. Introduction 43 | 44 | The use of network firewalls, systems that effectively isolate an 45 | organizations internal network structure from an exterior network, 46 | such as the INTERNET is becoming increasingly popular. These 47 | firewall systems typically act as application-layer gateways between 48 | networks, usually offering controlled TELNET, FTP, and SMTP access. 49 | With the emergence of more sophisticated application layer protocols 50 | designed to facilitate global information discovery, there exists a 51 | need to provide a general framework for these protocols to 52 | transparently and securely traverse a firewall. 53 | 54 | 55 | 56 | 57 | 58 | Leech, et al Standards Track [Page 1] 59 | 60 | RFC 1928 SOCKS Protocol Version 5 March 1996 61 | 62 | 63 | There exists, also, a need for strong authentication of such 64 | traversal in as fine-grained a manner as is practical. This 65 | requirement stems from the realization that client-server 66 | relationships emerge between the networks of various organizations, 67 | and that such relationships need to be controlled and often strongly 68 | authenticated. 69 | 70 | The protocol described here is designed to provide a framework for 71 | client-server applications in both the TCP and UDP domains to 72 | conveniently and securely use the services of a network firewall. 73 | The protocol is conceptually a "shim-layer" between the application 74 | layer and the transport layer, and as such does not provide network- 75 | layer gateway services, such as forwarding of ICMP messages. 76 | 77 | 2. Existing practice 78 | 79 | There currently exists a protocol, SOCKS Version 4, that provides for 80 | unsecured firewall traversal for TCP-based client-server 81 | applications, including TELNET, FTP and the popular information- 82 | discovery protocols such as HTTP, WAIS and GOPHER. 83 | 84 | This new protocol extends the SOCKS Version 4 model to include UDP, 85 | and extends the framework to include provisions for generalized 86 | strong authentication schemes, and extends the addressing scheme to 87 | encompass domain-name and V6 IP addresses. 88 | 89 | The implementation of the SOCKS protocol typically involves the 90 | recompilation or relinking of TCP-based client applications to use 91 | the appropriate encapsulation routines in the SOCKS library. 92 | 93 | Note: 94 | 95 | Unless otherwise noted, the decimal numbers appearing in packet- 96 | format diagrams represent the length of the corresponding field, in 97 | octets. Where a given octet must take on a specific value, the 98 | syntax X'hh' is used to denote the value of the single octet in that 99 | field. When the word 'Variable' is used, it indicates that the 100 | corresponding field has a variable length defined either by an 101 | associated (one or two octet) length field, or by a data type field. 102 | 103 | 3. Procedure for TCP-based clients 104 | 105 | When a TCP-based client wishes to establish a connection to an object 106 | that is reachable only via a firewall (such determination is left up 107 | to the implementation), it must open a TCP connection to the 108 | appropriate SOCKS port on the SOCKS server system. The SOCKS service 109 | is conventionally located on TCP port 1080. If the connection 110 | request succeeds, the client enters a negotiation for the 111 | 112 | 113 | 114 | Leech, et al Standards Track [Page 2] 115 | 116 | RFC 1928 SOCKS Protocol Version 5 March 1996 117 | 118 | 119 | authentication method to be used, authenticates with the chosen 120 | method, then sends a relay request. The SOCKS server evaluates the 121 | request, and either establishes the appropriate connection or denies 122 | it. 123 | 124 | Unless otherwise noted, the decimal numbers appearing in packet- 125 | format diagrams represent the length of the corresponding field, in 126 | octets. Where a given octet must take on a specific value, the 127 | syntax X'hh' is used to denote the value of the single octet in that 128 | field. When the word 'Variable' is used, it indicates that the 129 | corresponding field has a variable length defined either by an 130 | associated (one or two octet) length field, or by a data type field. 131 | 132 | The client connects to the server, and sends a version 133 | identifier/method selection message: 134 | 135 | +----+----------+----------+ 136 | |VER | NMETHODS | METHODS | 137 | +----+----------+----------+ 138 | | 1 | 1 | 1 to 255 | 139 | +----+----------+----------+ 140 | 141 | The VER field is set to X'05' for this version of the protocol. The 142 | NMETHODS field contains the number of method identifier octets that 143 | appear in the METHODS field. 144 | 145 | The server selects from one of the methods given in METHODS, and 146 | sends a METHOD selection message: 147 | 148 | +----+--------+ 149 | |VER | METHOD | 150 | +----+--------+ 151 | | 1 | 1 | 152 | +----+--------+ 153 | 154 | If the selected METHOD is X'FF', none of the methods listed by the 155 | client are acceptable, and the client MUST close the connection. 156 | 157 | The values currently defined for METHOD are: 158 | 159 | o X'00' NO AUTHENTICATION REQUIRED 160 | o X'01' GSSAPI 161 | o X'02' USERNAME/PASSWORD 162 | o X'03' to X'7F' IANA ASSIGNED 163 | o X'80' to X'FE' RESERVED FOR PRIVATE METHODS 164 | o X'FF' NO ACCEPTABLE METHODS 165 | 166 | The client and server then enter a method-specific sub-negotiation. 167 | 168 | 169 | 170 | Leech, et al Standards Track [Page 3] 171 | 172 | RFC 1928 SOCKS Protocol Version 5 March 1996 173 | 174 | 175 | Descriptions of the method-dependent sub-negotiations appear in 176 | separate memos. 177 | 178 | Developers of new METHOD support for this protocol should contact 179 | IANA for a METHOD number. The ASSIGNED NUMBERS document should be 180 | referred to for a current list of METHOD numbers and their 181 | corresponding protocols. 182 | 183 | Compliant implementations MUST support GSSAPI and SHOULD support 184 | USERNAME/PASSWORD authentication methods. 185 | 186 | 4. Requests 187 | 188 | Once the method-dependent subnegotiation has completed, the client 189 | sends the request details. If the negotiated method includes 190 | encapsulation for purposes of integrity checking and/or 191 | confidentiality, these requests MUST be encapsulated in the method- 192 | dependent encapsulation. 193 | 194 | The SOCKS request is formed as follows: 195 | 196 | +----+-----+-------+------+----------+----------+ 197 | |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | 198 | +----+-----+-------+------+----------+----------+ 199 | | 1 | 1 | X'00' | 1 | Variable | 2 | 200 | +----+-----+-------+------+----------+----------+ 201 | 202 | Where: 203 | 204 | o VER protocol version: X'05' 205 | o CMD 206 | o CONNECT X'01' 207 | o BIND X'02' 208 | o UDP ASSOCIATE X'03' 209 | o RSV RESERVED 210 | o ATYP address type of following address 211 | o IP V4 address: X'01' 212 | o DOMAINNAME: X'03' 213 | o IP V6 address: X'04' 214 | o DST.ADDR desired destination address 215 | o DST.PORT desired destination port in network octet 216 | order 217 | 218 | The SOCKS server will typically evaluate the request based on source 219 | and destination addresses, and return one or more reply messages, as 220 | appropriate for the request type. 221 | 222 | 223 | 224 | 225 | 226 | Leech, et al Standards Track [Page 4] 227 | 228 | RFC 1928 SOCKS Protocol Version 5 March 1996 229 | 230 | 231 | 5. Addressing 232 | 233 | In an address field (DST.ADDR, BND.ADDR), the ATYP field specifies 234 | the type of address contained within the field: 235 | 236 | o X'01' 237 | 238 | the address is a version-4 IP address, with a length of 4 octets 239 | 240 | o X'03' 241 | 242 | the address field contains a fully-qualified domain name. The first 243 | octet of the address field contains the number of octets of name that 244 | follow, there is no terminating NUL octet. 245 | 246 | o X'04' 247 | 248 | the address is a version-6 IP address, with a length of 16 octets. 249 | 250 | 6. Replies 251 | 252 | The SOCKS request information is sent by the client as soon as it has 253 | established a connection to the SOCKS server, and completed the 254 | authentication negotiations. The server evaluates the request, and 255 | returns a reply formed as follows: 256 | 257 | +----+-----+-------+------+----------+----------+ 258 | |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | 259 | +----+-----+-------+------+----------+----------+ 260 | | 1 | 1 | X'00' | 1 | Variable | 2 | 261 | +----+-----+-------+------+----------+----------+ 262 | 263 | Where: 264 | 265 | o VER protocol version: X'05' 266 | o REP Reply field: 267 | o X'00' succeeded 268 | o X'01' general SOCKS server failure 269 | o X'02' connection not allowed by ruleset 270 | o X'03' Network unreachable 271 | o X'04' Host unreachable 272 | o X'05' Connection refused 273 | o X'06' TTL expired 274 | o X'07' Command not supported 275 | o X'08' Address type not supported 276 | o X'09' to X'FF' unassigned 277 | o RSV RESERVED 278 | o ATYP address type of following address 279 | 280 | 281 | 282 | Leech, et al Standards Track [Page 5] 283 | 284 | RFC 1928 SOCKS Protocol Version 5 March 1996 285 | 286 | 287 | o IP V4 address: X'01' 288 | o DOMAINNAME: X'03' 289 | o IP V6 address: X'04' 290 | o BND.ADDR server bound address 291 | o BND.PORT server bound port in network octet order 292 | 293 | Fields marked RESERVED (RSV) must be set to X'00'. 294 | 295 | If the chosen method includes encapsulation for purposes of 296 | authentication, integrity and/or confidentiality, the replies are 297 | encapsulated in the method-dependent encapsulation. 298 | 299 | CONNECT 300 | 301 | In the reply to a CONNECT, BND.PORT contains the port number that the 302 | server assigned to connect to the target host, while BND.ADDR 303 | contains the associated IP address. The supplied BND.ADDR is often 304 | different from the IP address that the client uses to reach the SOCKS 305 | server, since such servers are often multi-homed. It is expected 306 | that the SOCKS server will use DST.ADDR and DST.PORT, and the 307 | client-side source address and port in evaluating the CONNECT 308 | request. 309 | 310 | BIND 311 | 312 | The BIND request is used in protocols which require the client to 313 | accept connections from the server. FTP is a well-known example, 314 | which uses the primary client-to-server connection for commands and 315 | status reports, but may use a server-to-client connection for 316 | transferring data on demand (e.g. LS, GET, PUT). 317 | 318 | It is expected that the client side of an application protocol will 319 | use the BIND request only to establish secondary connections after a 320 | primary connection is established using CONNECT. In is expected that 321 | a SOCKS server will use DST.ADDR and DST.PORT in evaluating the BIND 322 | request. 323 | 324 | Two replies are sent from the SOCKS server to the client during a 325 | BIND operation. The first is sent after the server creates and binds 326 | a new socket. The BND.PORT field contains the port number that the 327 | SOCKS server assigned to listen for an incoming connection. The 328 | BND.ADDR field contains the associated IP address. The client will 329 | typically use these pieces of information to notify (via the primary 330 | or control connection) the application server of the rendezvous 331 | address. The second reply occurs only after the anticipated incoming 332 | connection succeeds or fails. 333 | 334 | 335 | 336 | 337 | 338 | Leech, et al Standards Track [Page 6] 339 | 340 | RFC 1928 SOCKS Protocol Version 5 March 1996 341 | 342 | 343 | In the second reply, the BND.PORT and BND.ADDR fields contain the 344 | address and port number of the connecting host. 345 | 346 | UDP ASSOCIATE 347 | 348 | The UDP ASSOCIATE request is used to establish an association within 349 | the UDP relay process to handle UDP datagrams. The DST.ADDR and 350 | DST.PORT fields contain the address and port that the client expects 351 | to use to send UDP datagrams on for the association. The server MAY 352 | use this information to limit access to the association. If the 353 | client is not in possesion of the information at the time of the UDP 354 | ASSOCIATE, the client MUST use a port number and address of all 355 | zeros. 356 | 357 | A UDP association terminates when the TCP connection that the UDP 358 | ASSOCIATE request arrived on terminates. 359 | 360 | In the reply to a UDP ASSOCIATE request, the BND.PORT and BND.ADDR 361 | fields indicate the port number/address where the client MUST send 362 | UDP request messages to be relayed. 363 | 364 | Reply Processing 365 | 366 | When a reply (REP value other than X'00') indicates a failure, the 367 | SOCKS server MUST terminate the TCP connection shortly after sending 368 | the reply. This must be no more than 10 seconds after detecting the 369 | condition that caused a failure. 370 | 371 | If the reply code (REP value of X'00') indicates a success, and the 372 | request was either a BIND or a CONNECT, the client may now start 373 | passing data. If the selected authentication method supports 374 | encapsulation for the purposes of integrity, authentication and/or 375 | confidentiality, the data are encapsulated using the method-dependent 376 | encapsulation. Similarly, when data arrives at the SOCKS server for 377 | the client, the server MUST encapsulate the data as appropriate for 378 | the authentication method in use. 379 | 380 | 7. Procedure for UDP-based clients 381 | 382 | A UDP-based client MUST send its datagrams to the UDP relay server at 383 | the UDP port indicated by BND.PORT in the reply to the UDP ASSOCIATE 384 | request. If the selected authentication method provides 385 | encapsulation for the purposes of authenticity, integrity, and/or 386 | confidentiality, the datagram MUST be encapsulated using the 387 | appropriate encapsulation. Each UDP datagram carries a UDP request 388 | header with it: 389 | 390 | 391 | 392 | 393 | 394 | Leech, et al Standards Track [Page 7] 395 | 396 | RFC 1928 SOCKS Protocol Version 5 March 1996 397 | 398 | 399 | +----+------+------+----------+----------+----------+ 400 | |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | 401 | +----+------+------+----------+----------+----------+ 402 | | 2 | 1 | 1 | Variable | 2 | Variable | 403 | +----+------+------+----------+----------+----------+ 404 | 405 | The fields in the UDP request header are: 406 | 407 | o RSV Reserved X'0000' 408 | o FRAG Current fragment number 409 | o ATYP address type of following addresses: 410 | o IP V4 address: X'01' 411 | o DOMAINNAME: X'03' 412 | o IP V6 address: X'04' 413 | o DST.ADDR desired destination address 414 | o DST.PORT desired destination port 415 | o DATA user data 416 | 417 | When a UDP relay server decides to relay a UDP datagram, it does so 418 | silently, without any notification to the requesting client. 419 | Similarly, it will drop datagrams it cannot or will not relay. When 420 | a UDP relay server receives a reply datagram from a remote host, it 421 | MUST encapsulate that datagram using the above UDP request header, 422 | and any authentication-method-dependent encapsulation. 423 | 424 | The UDP relay server MUST acquire from the SOCKS server the expected 425 | IP address of the client that will send datagrams to the BND.PORT 426 | given in the reply to UDP ASSOCIATE. It MUST drop any datagrams 427 | arriving from any source IP address other than the one recorded for 428 | the particular association. 429 | 430 | The FRAG field indicates whether or not this datagram is one of a 431 | number of fragments. If implemented, the high-order bit indicates 432 | end-of-fragment sequence, while a value of X'00' indicates that this 433 | datagram is standalone. Values between 1 and 127 indicate the 434 | fragment position within a fragment sequence. Each receiver will 435 | have a REASSEMBLY QUEUE and a REASSEMBLY TIMER associated with these 436 | fragments. The reassembly queue must be reinitialized and the 437 | associated fragments abandoned whenever the REASSEMBLY TIMER expires, 438 | or a new datagram arrives carrying a FRAG field whose value is less 439 | than the highest FRAG value processed for this fragment sequence. 440 | The reassembly timer MUST be no less than 5 seconds. It is 441 | recommended that fragmentation be avoided by applications wherever 442 | possible. 443 | 444 | Implementation of fragmentation is optional; an implementation that 445 | does not support fragmentation MUST drop any datagram whose FRAG 446 | field is other than X'00'. 447 | 448 | 449 | 450 | Leech, et al Standards Track [Page 8] 451 | 452 | RFC 1928 SOCKS Protocol Version 5 March 1996 453 | 454 | 455 | The programming interface for a SOCKS-aware UDP MUST report an 456 | available buffer space for UDP datagrams that is smaller than the 457 | actual space provided by the operating system: 458 | 459 | o if ATYP is X'01' - 10+method_dependent octets smaller 460 | o if ATYP is X'03' - 262+method_dependent octets smaller 461 | o if ATYP is X'04' - 20+method_dependent octets smaller 462 | 463 | 8. Security Considerations 464 | 465 | This document describes a protocol for the application-layer 466 | traversal of IP network firewalls. The security of such traversal is 467 | highly dependent on the particular authentication and encapsulation 468 | methods provided in a particular implementation, and selected during 469 | negotiation between SOCKS client and SOCKS server. 470 | 471 | Careful consideration should be given by the administrator to the 472 | selection of authentication methods. 473 | 474 | 9. References 475 | 476 | [1] Koblas, D., "SOCKS", Proceedings: 1992 Usenix Security Symposium. 477 | 478 | Author's Address 479 | 480 | Marcus Leech 481 | Bell-Northern Research Ltd 482 | P.O. Box 3511, Stn. C, 483 | Ottawa, ON 484 | CANADA K1Y 4H7 485 | 486 | Phone: (613) 763-9145 487 | EMail: mleech@bnr.ca 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | Leech, et al Standards Track [Page 9] 507 | 508 | --------------------------------------------------------------------------------