socks5理解

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与其进行协商
//1.进行代理类型的判断
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) //USERID !!
			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; //GRANT  准许
		else
			Socks4Request->REP = 0x5B; //REJECT 拒绝

		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;
}
//2.proxy_server回应client  (ver,nmethod)
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) {
   //TCP CONNECT
		CSsocket[1]
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值