1.客户机连接到服务器,发送一个版本标识/方法选择报文
VER 1 |
NMETHODS 1 |
METHODS 1 |
x’05’ |
n(1-255) |
methons |
mothons(选择n中):
X’00’ 无验证需求
X’01’ 通用安全服务应用程序接口(GSSAPI)
X’02’ 用户名/密码(USERNAME/PASSWORD)
X’03’ 至 X’7F’ IANA 分配(IANA ASSIGNED)
X’80’ 至 X’FE’ 私人方法保留(RESERVED FOR PRIVATE METHODS)
X’FF’ 无可接受方法(NO ACCEPTABLE METHODS)
2.服务器返回方法选择报文
ver1 |
methons1 |
x’05’ |
number |
3.客户端发送请求的详细的报文
VER1 |
CMD1 |
RSV1 |
ATYP1 |
DST.ADDR n |
DST.PORT2 |
05 |
CONNECT X=‘01’, BIND= X’02’ , UDP ASSOCIATE =X’03’ |
保留 |
IP V4 address: X’01’,DOMAINNAME: X’03’,IP V6 address: X’04’ |
|
|
4.服务器返回报文
VER 1 |
REP1 |
RSV1 |
ATYP1 |
BND.ADDRn |
BND.PORT2 |
05 |
o X’00’ succeeded o X’01’ general SOCKS server failure o X’02’ connection not allowed by ruleset o X’03’ Network unreachable o X’04’ Host unreachable o X’05’ Connection refused o X’06’ TTL expired o X’07’ Command not supported o X’08’ Address type not supported o X’09’ to X’FF’ unassigned |
X’00’ |
o IP V4 address: X’01’ o DOMAINNAME: X’03’ o IP V6 address: X’04’ |
|
|
BND.PORT和BND.ADDR域包含了欲连接主机的地址和端口号。
5.开始数据的传输
RSV |
FRAG |
ATYP |
DST.ADDR |
DST.PORT |
DATA |
X’0000’ |
Current fragment number |
o IP V4 address: X’01’ o DOMAINNAME: X’03’ o IP V6 address: X’04’ |
|
|
|
附加知识
大小端
端:即数据的存储的顺序,好比int =123
大端的存储的方式:0x00=1,0x01=2,0x03=3
小端的储存方式:0x00=3,0x01=2,0x03=1
#!usr/bin/evn python
#! -*- coding:utf8 -*-
import socket
import threading
import struct
import select
from datetime import datetime
import base64
Server_addr = "127.0.0.1"
Server_port = 1080
Server_listen = 5
Auth = False
def make_server():
"""
开启服务器,开始监听
:return: 服务器
"""
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# server.setblocking(False)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 开启端口服用
server.bind((Server_addr, Server_port)) #
server.listen(Server_listen)
return server
def base64_encrypt(content):
return base64.encodestring(content)
def base64_decrypt(content):
return base64.decodestring(content)
def recv_argue(conn, size):
"""
接收数据,最后判断数据是否接收完成
:param conn: socket
:param size: datas len
:return: 接收到的数据datas
"""
remain = size
datas = []
while remain > 0:
data = conn.recv(remain)
if len(data) == 0:
raise Exception("Connection end.")
remain -= len(data)
datas.append(data)
datas = "".join(datas)
if len(datas) != size:
raise Exception("Protocol error")
return datas
def authenticate(conn, auth):
"""
认证数据的正确性,用户名和密码,以及发送ver和mothod给client,让client知道相应的认证的方式
:param conn:
:param auth:
:return:
"""
req = recv_argue(conn, 3) # 这里接受到的数据req装这客户端的所有可接受的认证方式,但是服务器看不看是他的事。。。。。
if auth:
# nedd auth
conn.send("\x05\x02")
checkUserPassword(conn)
else:
# don't need auth
conn.send("\x05\x00")
return conn
def checkUserPassword(conn):
pass
def handleRemote(conn):
"""
此处接受client的报文(ver,cmd,rsv,atyp,dst.addr,dst.port),
处理报文,req[4]:0x01==ipv4,0x03==domainname,0x04==ipv6
:param conn:
:return:
"""
req = recv_argue(conn, 5)
if len(req) != 5:
raise Exception("1.request error")
if len(req) == 0:
raise Exception("Connection end.")
if ord(req[3]) == 1:
addr_ip = recv_argue(conn, 4)
addr = socket.inet_ntoa(addr_ip)
elif ord(req[3]) == 3:
addr_len = ord(req[4])
addr = recv_argue(conn, int(addr_len))
elif ord(req[3]) == 4:
addr_ip = recv_argue(conn, 16)
addr = socket.inet_ntop(socket.AF_INET6, addr_ip)
else:
raise Exception("addr type not support!")
port = struct.unpack(">H", recv_argue(conn, 2))[0] # port is 2 byte,因为python存储int为byte时有大小端的概念,所以...
print datetime.now(), addr, port
remote = socket.create_connection((addr, port))
return remote
def handleRequest(conn, remote):
"""
服务器返回报文(ver,rep,rsv,atyp,bnd.addr,bnd.port),rep==0x00 is succeed ,else fail
:param conn:
:param remote:
:return:
"""
if remote:
#success
reply = "\x05\x00\x00\x01"
else:
#faile
reply = "\x05\x01\x00\x01"
reply += socket.inet_aton(Server_addr) + struct.pack(">H", Server_port)
conn.send(reply)
return conn
def send_all(sock, data):
bytes_send = 0
while True:
res = sock.send(data[bytes_send:])
if res < 0:
return res
bytes_send += res
if bytes_send == len(data):
return bytes_send
def sofineConnRemote(conn, remote):
try:
sockset = [conn, remote]
while True:
r, w, e = select.select(sockset, [], [])
if conn in r:
data = conn.recv(4096)
if len(data) <= 0:
break
res = send_all(remote, data)
if res < len(data):
raise Exception("faile to send all data to remote")
if remote in r:
data = remote.recv(4096)
if len(data) <= 0:
break
res = send_all(conn, data)
if res < len(data):
raise Exception("failed to send all data to conn")
finally:
conn.close()
remote.close()
def sockets5_server(conn, tth):
conn = authenticate(conn, Auth) # 版本以及方法的选择,0x05是版本,Auth=0x00是无须认证,=0x02用户名以及密码
remote = handleRemote(conn)
conn = handleRequest(conn, remote)
sofineConnRemote(conn, remote)
if __name__ == '__main__':
server = make_server()
tth = 0
while True:
conn, addr = server.accept() # conn相当于一个建立好连接的socket
tth += 1
threading.Thread(target=sockets5_server, args=(conn, tth)).start()
整体的运行的过程
1.启动代理服务器proxy_server,一旦有client接入,启动ProxyThread线程函数
void StartProxy(u_short LisPort){
WSADATA WSAData;
if (WSAStartup(MAKEWORD(2, 2), &WSAData))return;
SOCKET sProxy = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sProxy == SOCKET_ERROR)return;
struct sockaddr_in Server = { 0 };
Server.sin_family = AF_INET;
Server.sin_addr.S_un.S_addr = INADDR_ANY;
Server.sin_port = htons(LisPort);
if (bind(sProxy, (LPSOCKADDR)&Server, sizeof(Server)) == SOCKET_ERROR)return;
if (listen(sProxy, SOMAXCONN) == SOCKET_ERROR)return;
while (1){
SOCKET sClient = accept(sProxy, NULL, NULL);
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ProxyThread, (PVOID)sClient, 0, NULL);
if (hThread)
CloseHandle(hThread);
}
closesocket(sProxy);
WSACleanup();
}
2. client_socket这个链接发送数据(ver,cmd,rsv,atyp,ip_len,ip_info),proxy_server与其进行协商
DWORD WINAPI ProxyThread(PVOID sClient){
SOCKET CSsocket[2];
CSsocket[0] = (SOCKET)sClient;
CSsocket[1] = NULL;
char buf[1024];
memset(buf, 0, sizeof(buf));
int DataLen = recv(CSsocket[0], buf, sizeof(buf), 0);
if (DataLen < 3)
goto exit;
char ProxyType = buf[0];
if (ProxyType == 5)
{
if (!DoSocks5(CSsocket, buf))
goto exit;
}
else if (ProxyType == 4)
{
Socks4Req *Socks4Request = (Socks4Req *)buf;
IP_PORT IPP;
IPP.Port = Socks4Request->wPort;
if (buf[4] != 0x00)
IPP.IP = Socks4Request->dwIP;
else
{
HOSTENT *hostent = gethostbyname((char*)&Socks4Request->other + 1);
if (hostent == NULL)
goto exit;
IPP.IP = **(PULONG*)hostent->h_addr_list;
}
memset(Socks4Request, 0, 9);
CSsocket[1] = ConnectToRemoteIP(&IPP);
if (CSsocket[1])
Socks4Request->REP = 0x5A;
else
Socks4Request->REP = 0x5B;
if (send(CSsocket[0], (char *)Socks4Request, 8, 0) == SOCKET_ERROR)
goto exit;
if (Socks4Request->REP == 0x5B)
goto exit;
}
else
{
if (!HttpProxy(CSsocket, buf, DataLen))
goto exit;
}
if (CSsocket[0] && CSsocket[1])
TCPTransfer(CSsocket);
exit:
if (CSsocket[1])
closesocket(CSsocket[1]);
if (CSsocket[0])
closesocket(CSsocket[0]);
return 0;
}
BOOL DoSocks5(SOCKET *CSsocket, char *ReceiveBuf){
if (!Authentication(CSsocket[0], ReceiveBuf))
goto exit;
Socks5Reply SAC;
SAC.Ver = 0x05;
SAC.REP = 0x01;
SAC.RSV = 0x00;
SAC.ATYP = 0x01;
IP_PORT IP_Port;
int CMD = Get_IP_Port(CSsocket[0], ReceiveBuf, &IP_Port);
if (!CMD) goto exit;
else if (CMD == 1) {
CSsocket[1] = ConnectToRemoteIP(&IP_Port);
if (CSsocket[1]) SAC.REP = 0x00;
if (send(CSsocket[0], (char *)&SAC, 10, 0) == SOCKET_ERROR)goto exit;
if (SAC.REP == 0x01)goto exit;
return 1;
}
else if (CMD == 3) {
Socks5UDP S5UDP;
std::memset(&S5UDP, 0, sizeof(Socks5UDP));
struct sockaddr_in in;
std::memset(&in, 0, sizeof(sockaddr_in));
int structsize = sizeof(sockaddr_in);
getpeername(CSsocket[0], (struct sockaddr *)&in, &structsize);
S5UDP.Client.socks = CSsocket[0];
S5UDP.Client.IP_Port.IP = in.sin_addr.s_addr;
S5UDP.Client.IP_Port.Port = in.sin_port;
if (CreateUDPSocket(&SAC, &S5UDP.Local.socks))SAC.REP = 0x00;
if (SAC.REP == 0x01) goto exit;
if (send(CSsocket[0], (char *)&SAC, 10, 0) == SOCKET_ERROR) goto exit;
S5UDP.Local.IP_Port = SAC.IP_PORT;
UDPTransfer(&S5UDP);
}
exit:
return 0;
}
3.其中2回应packet(ver,methods)时,看是否存在用户认证,如果存在认证,则先接收认证的数据,如通过则回应成功,如果不需要进行认证,直接回应成功
int Authentication(SOCKET s, char *buf) {
Socks5Req *sq = (Socks5Req *)buf;
char SendBuf[2] = { 5, 0 };
if ((sq->Methods[0] == 0) || (sq->Methods[0] == 2)){
if (strlen(g_Username) == 0) SendBuf[1] = 0x00;
else SendBuf[1] = 0x02;
if (send(s, SendBuf, 2, 0) == SOCKET_ERROR)return 0;
}
else return 0;
if (SendBuf[1] == 2){
char USER[256] = {0};
char PASS[256] = {0};
int DataLen = recv(s, buf, 1024, 0);
if (DataLen == SOCKET_ERROR || DataLen == 0)return 0;
AuthReq *aq = (AuthReq *)buf;
if (aq->Ver != 1)return 0;
if ((aq->Ulen != 0) && (aq->Ulen <= 256))
memcpy(USER, buf + 2, aq->Ulen);
int PLen = buf[2 + aq->Ulen];
if ((PLen != 0) && (PLen <= 256))
memcpy(PASS, buf + 3 + aq->Ulen, PLen);
if (!strcmp(g_Username, USER) && !strcmp(g_Password, PASS)) buf[1] = 0;
else buf[1] = -1;
if (send(s, buf, 2, 0) == SOCKET_ERROR)return 0;
}
return 1;
}
4.proxy_server回应client(ver,rep,rsv,atyp,ip,port)
5.进行数据的转发
void TCPTransfer(SOCKET* CSsocket){
int result;
SOCKET ClientSocket = CSsocket[0];
SOCKET ServerSocket = CSsocket[1];
struct timeval timeset;
fd_set readfd, writefd;
char SenderBuf[MAXBUFSIZE];
char read_in1[MAXBUFSIZE], send_out1[MAXBUFSIZE];
char read_in2[MAXBUFSIZE], send_out2[MAXBUFSIZE];
int read1 = 0, totalread1 = 0, send1 = 0;
int read2 = 0, totalread2 = 0, send2 = 0;
int sendcount1, sendcount2;
int maxfd = (int)(max(ClientSocket, ServerSocket)) + 1;
int i = 0;
memset(read_in1, 0, MAXBUFSIZE);
memset(read_in2, 0, MAXBUFSIZE);
memset(send_out1, 0, MAXBUFSIZE);
memset(send_out2, 0, MAXBUFSIZE);
timeset.tv_sec = TIMEOUT;
timeset.tv_usec = 0;
while (1)
{
FD_ZERO(&readfd);
FD_ZERO(&writefd);
FD_SET((UINT)ClientSocket, &readfd);
FD_SET((UINT)ClientSocket, &writefd);
FD_SET((UINT)ServerSocket, &writefd);
FD_SET((UINT)ServerSocket, &readfd);
result = select(maxfd, &readfd, &writefd, NULL, ×et);
if ((result<0) && (errno != EINTR))
{
printf("Select error.\r\n");
break;
}
else if (result == 0)
{
printf("Socket time out.\r\n");
break;
}
if (FD_ISSET(ServerSocket, &readfd))
{
if (totalread2<MAXBUFSIZE)
{
read2 = recv(ServerSocket, read_in2, MAXBUFSIZE - totalread2, 0);
if (read2 == 0)break;
if ((read2<0) && (errno != EINTR))
{
printf("Read ServerSocket data error,maybe close?\r\n\r\n");
break;
}
memcpy(send_out2 + totalread2, read_in2, read2);
totalread2 += read2;
memset(read_in2, 0, MAXBUFSIZE);
}
}
if (FD_ISSET(ClientSocket, &writefd)){
int err2 = 0;
sendcount2 = 0;
while (totalread2>0){
send2 = send(ClientSocket, send_out2 + sendcount2, totalread2, 0);
if (send2 == 0)break;
if ((send2<0) && (errno != EINTR))
{
printf("Send to ClientSocket unknow error.\r\n");
err2 = 1;
break;
}
if ((send2<0) && (errno == ENOSPC)) break;
sendcount2 += send2;
totalread2 -= send2;
}
if (err2 == 1) break;
if ((totalread2>0) && (sendcount2 > 0))
{
memcpy(send_out2, send_out2 + sendcount2, totalread2);
memset(send_out2 + totalread2, 0, MAXBUFSIZE - totalread2);
}
else
memset(send_out2, 0, MAXBUFSIZE);
}
if (FD_ISSET(ClientSocket, &readfd))
{
if (totalread1<MAXBUFSIZE)
{
read1 = recv(ClientSocket, read_in1, MAXBUFSIZE - totalread1, 0);
if ((read1 == SOCKET_ERROR) || (read1 == 0))
{
break;
}
memcpy(send_out1 + totalread1, read_in1, read1);
totalread1 += read1;
memset(read_in1, 0, MAXBUFSIZE);
}
if (SendRequest(CSsocket, SenderBuf, send_out1, totalread1))
totalread1 = 0;
}
if (FD_ISSET(ServerSocket, &writefd))
{
int err = 0;
sendcount1 = 0;
while (totalread1>0)
{
send1 = send(ServerSocket, send_out1 + sendcount1, totalread1, 0);
if (send1 == 0)break;
if ((send1<0) && (errno != EINTR))
{
err = 1;
break;
}
if ((send1<0) && (errno == ENOSPC)) break;
sendcount1 += send1;
totalread1 -= send1;
}
if (err == 1) break;
if ((totalread1>0) && (sendcount1>0))
{
memcpy(send_out1, send_out1 + sendcount1, totalread1);
memset(send_out1 + totalread1, 0, MAXBUFSIZE - totalread1);
}
else
memset(send_out1, 0, MAXBUFSIZE);
}
Sleep(5);
}
closesocket(ClientSocket);
closesocket(ServerSocket);
}
6.当然涉及的域名解析,和UDP转发等很多,附具体的代码
#include
#include
#include
#include
#pragma comment(lib,"ws2_32.lib")
using namespace std;
#define MAX_HOSTNAME 256
#define MAXBUFSIZE 20480
#define TIMEOUT 10000
#define HEADLEN 7
#define _OUT_
char HTTP_200_OK[] = "HTTP/1.0 200 OK\r\n\r\n";
char g_Username[256];
char g_Password[256];
struct Socks4Req
{
BYTE Ver;
BYTE REP;
WORD wPort;
DWORD dwIP;
BYTE other[1];
};
struct Socks5Req
{
BYTE Ver;
BYTE nMethods;
BYTE Methods[255];
};
struct AuthReq
{
BYTE Ver;
BYTE Ulen;
BYTE UserPass[1024];
};
typedef struct
{
BYTE Ver;
BYTE CMD;
BYTE RSV;
BYTE ATYP;
BYTE IP_LEN;
BYTE szIP;
}Socks5Info;
typedef struct
{
DWORD IP;
WORD Port;
}IP_PORT;
typedef struct
{
BYTE Ver;
BYTE REP;
BYTE RSV;
BYTE ATYP;
IP_PORT IP_PORT;
}Socks5Reply;
typedef struct
{
BYTE RSV[2];
BYTE FRAG;
BYTE ATYP;
IP_PORT IP_PORT;
}Socks5UDPHead;
struct SocketInfo
{
SOCKET socks;
IP_PORT IP_Port;
};
typedef struct
{
SocketInfo Local;
SocketInfo Client;
SocketInfo Server;
}Socks5UDP;
void TCPTransfer(SOCKET* CSsocket);
void UDPTransfer(Socks5UDP *sPara);
BOOL ConnectToRemoteHost(SOCKET *ServerSocket, char *HostName, const WORD RemotePort);
void GetHostNameAndPort(char *ReceiveBuf, int datalen, char *HostName, UINT *RemotePort){
if (datalen > MAX_HOSTNAME)datalen = MAX_HOSTNAME;
char *p = ReceiveBuf;
for (int i = 0;i < datalen && *p != ':' && *p != '\0' && *p != '\r' && *p != '/';i++){
HostName[i] = *p++;
if (*p == ':')*RemotePort = atoi(p + 1);
}
}
char * GetURLRootPoint(char * ReceiveBuf, int DataLen, int *HostNaneLen)
{
for (int i = 0; i < DataLen; i++)
{
if (ReceiveBuf[i] == '/')
{
*HostNaneLen = i;
return &ReceiveBuf[i];
}
}
return NULL;
}
int CheckHttpRequest(const char *ReceiveBuf, int *MethodLength){
if (!_strnicmp(ReceiveBuf, "GET ", 4)){
*MethodLength = 4;
return 1;
}
if (!_strnicmp(ReceiveBuf, "HEAD ", 5))
{
*MethodLength = 5;
return 2;
}
if (!_strnicmp(ReceiveBuf, "POST ", 5))
{
*MethodLength = 5;
return 3;
}
if (!_strnicmp(ReceiveBuf, "CONNECT ", 8))
{
*MethodLength = 8;
return 4;
}
return 0;
}
int ModifyRequest(char *SenderBuf, char *ReceiveBuf, int DataLen, int MethodLength)
{
strncpy_s(SenderBuf, MAXBUFSIZE, ReceiveBuf, MethodLength);
if (strncmp(ReceiveBuf + MethodLength, "http://", HEADLEN))
return 0;
int HedLen = 0;
char * Getrootfp = GetURLRootPoint(ReceiveBuf + MethodLength + HEADLEN, DataLen - MethodLength - HEADLEN, &HedLen);
if (Getrootfp == NULL)
return 0;
memcpy(SenderBuf + MethodLength, Getrootfp, DataLen - MethodLength - HEADLEN - HedLen);
return DataLen - HEADLEN - HedLen;
}
BOOL HttpProxy(SOCKET* CSsocket, char *ReceiveBuf, int DataLen)
{
int MethodLength;
int Flag = CheckHttpRequest(ReceiveBuf, &MethodLength);
if (!Flag)
goto exit;
char *SenderBuf = (char*)malloc(MAXBUFSIZE);
if (SenderBuf)
{
memset(SenderBuf, 0, MAXBUFSIZE);
char HostName[MAX_HOSTNAME] = { 0 };
UINT RemotePort = 80;
if (Flag == 1 || Flag == 2 || Flag == 3)
{
int SendLength = ModifyRequest(SenderBuf, ReceiveBuf, DataLen, MethodLength);
if (!SendLength)
return 0;
GetHostNameAndPort(ReceiveBuf + MethodLength + HEADLEN,
DataLen - MethodLength - HEADLEN,
HostName,
&RemotePort);
if (!ConnectToRemoteHost(&CSsocket[1], HostName, RemotePort))
return 0;
if (send(CSsocket[1], SenderBuf, SendLength, 0) == SOCKET_ERROR)
return 0;
}
else if (Flag == 4)
{
GetHostNameAndPort(ReceiveBuf + MethodLength,
DataLen - MethodLength,
HostName,
&RemotePort);
if (!ConnectToRemoteHost(&CSsocket[1], HostName, RemotePort))
return 0;
send(CSsocket[0], HTTP_200_OK, (int)strlen(HTTP_200_OK) + 1, 0);
}
free(SenderBuf);
return 1;
}
exit:
return 0;
}
BOOL SendRequest(SOCKET* CSsocket, char *SenderBuf, char *ReceiveBuf, int DataLen){
int MethodLength = 0;
int Flag = CheckHttpRequest(ReceiveBuf, &MethodLength);
if (Flag == 0)
return 0;
char HostName[MAX_HOSTNAME] = { 0 };
UINT RemotePort = 80;
if (Flag == 1 || Flag == 2 || Flag == 3){
int SendLength = ModifyRequest(SenderBuf, ReceiveBuf, DataLen, MethodLength);
if (!SendLength)return 0;
GetHostNameAndPort(ReceiveBuf + MethodLength + HEADLEN, DataLen - MethodLength - HEADLEN, HostName, &RemotePort);
if (!ConnectToRemoteHost(&CSsocket[1], HostName, RemotePort))return 0;
if (send(CSsocket[1], SenderBuf, SendLength, 0) == SOCKET_ERROR)return 0;
}
else if (Flag == 4){
GetHostNameAndPort(ReceiveBuf + MethodLength,DataLen - MethodLength,HostName,&RemotePort);
if (!ConnectToRemoteHost(&CSsocket[1], HostName, RemotePort))return 0;
send(CSsocket[0], HTTP_200_OK, (int)strlen(HTTP_200_OK) + 1, 0);
}
return 1;
}
int Authentication(SOCKET s, char *buf) {
Socks5Req *sq = (Socks5Req *)buf;
char SendBuf[2] = { 5, 0 };
if ((sq->Methods[0] == 0) || (sq->Methods[0] == 2)){
if (strlen(g_Username) == 0) SendBuf[1] = 0x00;
else SendBuf[1] = 0x02;
if (send(s, SendBuf, 2, 0) == SOCKET_ERROR)return 0;
}
else return 0;
if (SendBuf[1] == 2){
char USER[256] = {0};
char PASS[256] = {0};
int DataLen = recv(s, buf, 1024, 0);
if (DataLen == SOCKET_ERROR || DataLen == 0)return 0;
AuthReq *aq = (AuthReq *)buf;
if (aq->Ver != 1)return 0;
if ((aq->Ulen != 0) && (aq->Ulen <= 256))
memcpy(USER, buf + 2, aq->Ulen);
int PLen = buf[2 + aq->Ulen];
if ((PLen != 0) && (PLen <= 256))
memcpy(PASS, buf + 3 + aq->Ulen, PLen);
if (!strcmp(g_Username, USER) && !strcmp(g_Password, PASS)) buf[1] = 0;
else buf[1] = -1;
if (send(s, buf, 2, 0) == SOCKET_ERROR)return 0;
}
return 1;
}
ULONG DNS(char *HostName)
{
HOSTENT *hostent = gethostbyname(HostName);
if (hostent == NULL)
return 0;
return **(PULONG*)hostent->h_addr_list;
}
int GetAddressAndPort(char *ReceiveBuf, int DataLen, char *HostName, ULONG *pIp, WORD *RemotePort)
{
Socks5Info *Socks5Request = (Socks5Info *)ReceiveBuf;
if ((Socks5Request->Ver == 0) && (Socks5Request->CMD == 0))
{
if (Socks5Request->ATYP == 1)
{
IP_PORT *IPP = (IP_PORT *)&Socks5Request->IP_LEN;
*pIp = IPP->IP;
*RemotePort = IPP->Port;
return 10;
}
else if (Socks5Request->ATYP == 3)
{
memcpy(HostName, &Socks5Request->szIP, Socks5Request->IP_LEN);
memcpy(RemotePort, &Socks5Request->szIP + Socks5Request->IP_LEN, 2);
return 7 + Socks5Request->IP_LEN;
}
return 1;
}
return 0;
}
SOCKET ConnectToRemoteIP(IP_PORT *pIPP)
{
SOCKET ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ServerSocket == INVALID_SOCKET)
return NULL;
struct sockaddr_in Server;
memset(&Server, 0, sizeof(Server));
Server.sin_family = AF_INET;
Server.sin_addr.s_addr = pIPP->IP;
Server.sin_port = pIPP->Port;
UINT TimeOut = TIMEOUT;
setsockopt(ServerSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&TimeOut, sizeof(TimeOut));
if (connect(ServerSocket, (const SOCKADDR *)&Server, sizeof(Server)) == SOCKET_ERROR)
{
UCHAR *p = (UCHAR *)&pIPP->IP;
printf("Fail To Connect To Remote Host : %d.%d.%d.%d:%d\n",
p[0], p[1], p[2], p[3], ntohs(pIPP->Port));
closesocket(ServerSocket);
return NULL;
}
return ServerSocket;
}
BOOL ConnectToRemoteHost(SOCKET *ServerSocket, char *HostName, const WORD RemotePort)
{
struct sockaddr_in Server;
memset(&Server, 0, sizeof(Server));
Server.sin_family = AF_INET;
Server.sin_port = htons(RemotePort);
if (inet_addr(HostName) != INADDR_NONE)
Server.sin_addr.s_addr = inet_addr(HostName);
else
Server.sin_addr.s_addr = DNS(HostName);
*ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (*ServerSocket == INVALID_SOCKET)
return FALSE;
UINT TimeOut = TIMEOUT;
setsockopt(*ServerSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&TimeOut, sizeof(TimeOut));
if (connect(*ServerSocket, (const SOCKADDR *)&Server, sizeof(Server)) == SOCKET_ERROR)
{
printf("Fail To Connect To Remote Host\n");
closesocket(*ServerSocket);
return FALSE;
}
return TRUE;
}
int Get_IP_Port(SOCKET s, char *ReceiveBuf, IP_PORT *IPP){
int DataLen = recv(s, ReceiveBuf, 1024, 0);
if (DataLen == SOCKET_ERROR || DataLen == 0) return 0;
Socks5Info *Socks5Request = (Socks5Info *)ReceiveBuf;
if (Socks5Request->ATYP == 1){
*IPP = *(IP_PORT *)&Socks5Request->IP_LEN;
}
else if (Socks5Request->ATYP == 3){
IPP->Port = *(WORD*)((char*)&Socks5Request->szIP + Socks5Request->IP_LEN);
if (Socks5Request->IP_LEN >= MAX_HOSTNAME) return 0;
char HostName[MAX_HOSTNAME];
memcpy(HostName, (char*)&Socks5Request->szIP, Socks5Request->IP_LEN);
HostName[Socks5Request->IP_LEN] = 0;
HOSTENT *hostent = gethostbyname(HostName);
if (hostent == NULL) return 0;
IPP->IP = **(PULONG*)hostent->h_addr_list;
}
else
return 0;
if ((Socks5Request->CMD == 1) || (Socks5Request->CMD == 3))
return Socks5Request->CMD;
return 0;
}
BOOL CreateUDPSocket(_OUT_ Socks5Reply *SAC, _OUT_ SOCKET *p_sock)
{
*p_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (*p_sock == SOCKET_ERROR)
return 0;
struct sockaddr_in UDPServer;
UDPServer.sin_family = AF_INET;
UDPServer.sin_addr.s_addr = INADDR_ANY;
UDPServer.sin_port = INADDR_ANY;
if (bind(*p_sock, (SOCKADDR*)&UDPServer, sizeof(UDPServer)) == SOCKET_ERROR)
{
printf("UDP socket bind failed.\n");
return 0;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(sockaddr_in));
int AddrLen = sizeof(sockaddr_in);
getsockname(*p_sock, (struct sockaddr *)&addr, &AddrLen);
SAC->IP_PORT.IP = addr.sin_addr.s_addr;
SAC->IP_PORT.Port = addr.sin_port;
printf("UDP port : %d\n", ntohs(addr.sin_port));
return 1;
}
BOOL DoSocks5(SOCKET *CSsocket, char *ReceiveBuf){
if (!Authentication(CSsocket[0], ReceiveBuf))
goto exit;
Socks5Reply SAC;
SAC.Ver = 0x05;
SAC.REP = 0x01;
SAC.RSV = 0x00;
SAC.ATYP = 0x01;
IP_PORT IP_Port;
int CMD = Get_IP_Port(CSsocket[0], ReceiveBuf, &IP_Port);
if (!CMD) goto exit;
else if (CMD == 1) {
CSsocket[1] = ConnectToRemoteIP(&IP_Port);
if (CSsocket[1]) SAC.REP = 0x00;
if (send(CSsocket[0], (char *)&SAC, 10, 0) == SOCKET_ERROR)goto exit;
if (SAC.REP == 0x01)goto exit;
return 1;
}
else if (CMD == 3) {
Socks5UDP S5UDP;
std::memset(&S5UDP, 0, sizeof(Socks5UDP));
struct sockaddr_in in;
std::memset(&in, 0, sizeof(sockaddr_in));
int structsize = sizeof(sockaddr_in);
getpeername(CSsocket[0], (struct sockaddr *)&in, &structsize);
S5UDP.Client.socks = CSsocket[0];
S5UDP.Client.IP_Port.IP = in.sin_addr.s_addr;
S5UDP.Client.IP_Port.Port = in.sin_port;
if (CreateUDPSocket(&SAC, &S5UDP.Local.socks))SAC.REP = 0x00;
if (SAC.REP == 0x01) goto exit;
if (send(CSsocket[0], (char *)&SAC, 10, 0) == SOCKET_ERROR) goto exit;
S5UDP.Local.IP_Port = SAC.IP_PORT;
UDPTransfer(&S5UDP);
}
exit:
return 0;
}
int UDPSend(SOCKET s, char *buf, int nBufSize, struct sockaddr_in *to, int tolen)
{
int nBytesLeft = nBufSize;
int nBytes = 0;
while (nBytesLeft > 0)
{
nBytes = sendto(s, &buf[nBufSize - nBytesLeft], nBytesLeft, 0, (SOCKADDR *)to, tolen);
if (nBytes == SOCKET_ERROR)
{
return SOCKET_ERROR;
}
nBytesLeft -= nBytes;
}
return nBufSize - nBytesLeft;
}
void UDPTransfer(Socks5UDP *pS5UDP)
{
int result;
struct sockaddr_in SenderAddr;
int SenderAddrSize = sizeof(SenderAddr);
char RecvBuf[MAXBUFSIZE];
struct sockaddr_in UDPClient, UDPServer;
memset(&UDPClient, 0, sizeof(sockaddr_in));
memset(&UDPServer, 0, sizeof(sockaddr_in));
UDPClient.sin_family = AF_INET;
UDPClient.sin_addr.s_addr = pS5UDP->Client.IP_Port.IP;
fd_set readfd;
int DataLength = 0;
while (1)
{
FD_ZERO(&readfd);
FD_SET((UINT)pS5UDP->Local.socks, &readfd);
FD_SET((UINT)pS5UDP->Client.socks, &readfd);
result = select((int)pS5UDP->Local.socks + 1, &readfd, NULL, NULL, NULL);
if ((result<0) && (errno != EINTR))
{
break;
}
if (FD_ISSET(pS5UDP->Client.socks, &readfd))
break;
if (FD_ISSET(pS5UDP->Local.socks, &readfd))
{
memset(RecvBuf, 0, MAXBUFSIZE);
DataLength = recvfrom(pS5UDP->Local.socks,
RecvBuf + 10, MAXBUFSIZE - 10, 0, (struct sockaddr FAR *)&SenderAddr, &SenderAddrSize);
if (DataLength == SOCKET_ERROR)
{
break;
}
if (SenderAddr.sin_addr.s_addr == pS5UDP->Client.IP_Port.IP)
{
char HostName[MAX_HOSTNAME] = { 0 };
ULONG ip = 0;
WORD RemotePort = 0;
int DataOffset = GetAddressAndPort(RecvBuf + 10, DataLength, HostName, &ip, &RemotePort);
if (DataOffset)
{
UDPServer.sin_family = AF_INET;
if (ip)
UDPServer.sin_addr.s_addr = ip;
else
UDPServer.sin_addr.s_addr = DNS(HostName);
UDPServer.sin_port = RemotePort;
result = UDPSend(pS5UDP->Local.socks, RecvBuf + 10 + DataOffset, DataLength - DataOffset, &UDPServer, sizeof(UDPServer));
if (result == SOCKET_ERROR)
{
break;
}
UDPClient.sin_port = SenderAddr.sin_port;
}
else break;
}
else if (SenderAddr.sin_addr.s_addr == UDPServer.sin_addr.s_addr &&
SenderAddr.sin_port == UDPServer.sin_port)
{
Socks5UDPHead *UDPHead = (Socks5UDPHead*)RecvBuf;
memset(UDPHead, 0, 10);
UDPHead->ATYP = 0x01;
UDPHead->IP_PORT.IP = SenderAddr.sin_addr.s_addr;
UDPHead->IP_PORT.Port = SenderAddr.sin_port;
result = UDPSend(pS5UDP->Local.socks, RecvBuf, DataLength + 10, &UDPClient, sizeof(UDPClient));
if (result == SOCKET_ERROR)
{
break;
}
}
}
Sleep(5);
}
closesocket(pS5UDP->Local.socks);
closesocket(pS5UDP->Client.socks);
}
void TCPTransfer(SOCKET* CSsocket){
int result;
SOCKET ClientSocket = CSsocket[0];
SOCKET ServerSocket = CSsocket[1];
struct timeval timeset;
fd_set readfd, writefd;
char SenderBuf[MAXBUFSIZE];
char read_in1[MAXBUFSIZE], send_out1[MAXBUFSIZE];
char read_in2[MAXBUFSIZE], send_out2[MAXBUFSIZE];
int read1 = 0, totalread1 = 0, send1 = 0;
int read2 = 0, totalread2 = 0, send2 = 0;
int sendcount1, sendcount2;
int maxfd = (int)(max(ClientSocket, ServerSocket)) + 1;
int i = 0;
memset(read_in1, 0, MAXBUFSIZE);
memset(read_in2, 0, MAXBUFSIZE);
memset(send_out1, 0, MAXBUFSIZE);
memset(send_out2, 0, MAXBUFSIZE);
timeset.tv_sec = TIMEOUT;
timeset.tv_usec = 0;
while (1)
{
FD_ZERO(&readfd);
FD_ZERO(&writefd);
FD_SET((UINT)ClientSocket, &readfd);
FD_SET((UINT)ClientSocket, &writefd);
FD_SET((UINT)ServerSocket, &writefd);
FD_SET((UINT)ServerSocket, &readfd);
result = select(maxfd, &readfd, &writefd, NULL, ×et);
if ((result<0) && (errno != EINTR))
{
printf("Select error.\r\n");
break;
}
else if (result == 0)
{
printf("Socket time out.\r\n");
break;
}
if (FD_ISSET(ServerSocket, &readfd))
{
if (totalread2<MAXBUFSIZE)
{
read2 = recv(ServerSocket, read_in2, MAXBUFSIZE - totalread2, 0);
if (read2 == 0)break;
if ((read2<0) && (errno != EINTR))
{
printf("Read ServerSocket data error,maybe close?\r\n\r\n");
break;
}
memcpy(send_out2 + totalread2, read_in2, read2);
totalread2 += read2;
memset(read_in2, 0, MAXBUFSIZE);
}
}
if (FD_ISSET(ClientSocket, &writefd)){
int err2 = 0;
sendcount2 = 0;
while (totalread2>0){
send2 = send(ClientSocket, send_out2 + sendcount2, totalread2, 0);
if (send2 == 0)break;
if ((send2<0) && (errno != EINTR))
{
printf("Send to ClientSocket unknow error.\r\n");
err2 = 1;
break;
}
if ((send2<0) && (errno == ENOSPC)) break;
sendcount2 += send2;
totalread2 -= send2;
}
if (err2 == 1) break;
if ((totalread2>0) && (sendcount2 > 0))
{
memcpy(send_out2, send_out2 + sendcount2, totalread2);
memset(send_out2 + totalread2, 0, MAXBUFSIZE - totalread2);
}
else
memset(send_out2, 0, MAXBUFSIZE);
}
if (FD_ISSET(ClientSocket, &readfd))
{
if (totalread1<MAXBUFSIZE)
{
read1 = recv(ClientSocket, read_in1, MAXBUFSIZE - totalread1, 0);
if ((read1 == SOCKET_ERROR) || (read1 == 0))
{
break;
}
memcpy(send_out1 + totalread1, read_in1, read1);
totalread1 += read1;
memset(read_in1, 0, MAXBUFSIZE);
}
if (SendRequest(CSsocket, SenderBuf, send_out1, totalread1))
totalread1 = 0;
}
if (FD_ISSET(ServerSocket, &writefd))
{
int err = 0;
sendcount1 = 0;
while (totalread1>0)
{
send1 = send(ServerSocket, send_out1 + sendcount1, totalread1, 0);
if (send1 == 0)break;
if ((send1<0) && (errno != EINTR))
{
err = 1;
break;
}
if ((send1<0) && (errno == ENOSPC)) break;
sendcount1 += send1;
totalread1 -= send1;
}
if (err == 1) break;
if ((totalread1>0) && (sendcount1>0))
{
memcpy(send_out1, send_out1 + sendcount1, totalread1);
memset(send_out1 + totalread1, 0, MAXBUFSIZE - totalread1);
}
else
memset(send_out1, 0, MAXBUFSIZE);
}
Sleep(5);
}
closesocket(ClientSocket);
closesocket(ServerSocket);
}
DWORD WINAPI ProxyThread(PVOID sClient){
SOCKET CSsocket[2];
CSsocket[0] = (SOCKET)sClient;
CSsocket[1] = NULL;
char buf[1024];
memset(buf, 0, sizeof(buf));
int DataLen = recv(CSsocket[0], buf, sizeof(buf), 0);
if (DataLen < 3)
goto exit;
char ProxyType = buf[0];
if (ProxyType == 5)
{
if (!DoSocks5(CSsocket, buf))
goto exit;
}
else if (ProxyType == 4)
{
Socks4Req *Socks4Request = (Socks4Req *)buf;
IP_PORT IPP;
IPP.Port = Socks4Request->wPort;
if (buf[4] != 0x00)
IPP.IP = Socks4Request->dwIP;
else
{
HOSTENT *hostent = gethostbyname((char*)&Socks4Request->other + 1);
if (hostent == NULL)
goto exit;
IPP.IP = **(PULONG*)hostent->h_addr_list;
}
memset(Socks4Request, 0, 9);
CSsocket[1] = ConnectToRemoteIP(&IPP);
if (CSsocket[1])
Socks4Request->REP = 0x5A;
else
Socks4Request->REP = 0x5B;
if (send(CSsocket[0], (char *)Socks4Request, 8, 0) == SOCKET_ERROR)
goto exit;
if (Socks4Request->REP == 0x5B)
goto exit;
}
else
{
if (!HttpProxy(CSsocket, buf, DataLen))
goto exit;
}
if (CSsocket[0] && CSsocket[1])
TCPTransfer(CSsocket);
exit:
if (CSsocket[1])
closesocket(CSsocket[1]);
if (CSsocket[0])
closesocket(CSsocket[0]);
return 0;
}
void StartProxy(u_short LisPort){
WSADATA WSAData;
if (WSAStartup(MAKEWORD(2, 2), &WSAData))
return;
SOCKET sProxy = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sProxy == SOCKET_ERROR)
return;
struct sockaddr_in Server = { 0 };
Server.sin_family = AF_INET;
Server.sin_addr.S_un.S_addr = INADDR_ANY;
Server.sin_port = htons(LisPort);
if (bind(sProxy, (LPSOCKADDR)&Server, sizeof(Server)) == SOCKET_ERROR)
return;
if (listen(sProxy, SOMAXCONN) == SOCKET_ERROR)
return;
while (1){
SOCKET sClient = accept(sProxy, NULL, NULL);
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ProxyThread, (PVOID)sClient, 0, NULL);
if (hThread)
CloseHandle(hThread);
}
closesocket(sProxy);
WSACleanup();
}
void run(int argc, char* argv[]) {
u_short LisPort = 1080;
printf("SOCKS4 & SOCKS5 & Http Proxy V1.0\n"" usage:\n"" Socks5 [port] [UserName] [PassWord]\n\n");
if (argc >= 2){
LisPort = atoi(argv[1]);
if (argc == 4){
strcpy_s(g_Username, sizeof(g_Username), argv[2]);
strcpy_s(g_Password, sizeof(g_Password), argv[3]);
printf(" ~ Username : %s, Password : %s\n", g_Username, g_Password);
}
}
strcpy_s(g_Username, sizeof(g_Username), "dd");
strcpy_s(g_Password, sizeof(g_Password), "123");
printf(" ~ ProxyPort = %d\n", LisPort);
StartProxy(LisPort);
}
int main(int argc, char* argv[]){
run(argc,argv);
return 0;
}