socks5 协议简介

http://zhihan.me/network/2017/09/24/socks5-protocol/

什么是socks5

或许你没听说过socks5,但你一定听说过ShadowSocks,ShadowSockS内部使用的正是socks5协议。

socks是”SocketS”的缩写,因此socks5也叫sockets5。

RFC地址:

socks是一种网络传输协议,主要用于客户端与外网服务器之间通讯的中间传递。根据OSI七层模型来划分,SOCKS属于会话层协议,位于表示层与传输层之间。

当防火墙后的客户端要访问外部的服务器时,就跟socks代理服务器连接。该协议设计之初是为了让有权限的用户可以穿过过防火墙的限制,使得高权限用户可以访问外部资源。经过10余年的时间,大量的网络应用程序都支持socks5代理。

这个协议最初由David Koblas开发,而后由NEC的Ying-Da Lee将其扩展到版本4,最新协议是版本5,与前一版本相比,socks5做了以下增强:

  • 增加对UDP协议的支持;
  • 支持多种用户身份验证方式和通信加密方式;
  • 修改了socks服务器进行域名解析的方法,使其更加优雅;

socks5使用场景

socks协议的设计初衷是在保证网络隔离的情况下,提高部分人员的网络访问权限,但是国内似乎很少有组织机构这样使用。一般情况下,大家都会使用更新的网络安全技术来达到相同的目的。

但是由于socksCap32和PSD这类软件,人们找到了socks协议新的用途:突破网络通信限制,这和该协议的设计初衷正好相反。

下面是两个典型的运用场景:

  • 美国某网游的服务器仅允许本国的IP进行连接。非美国玩家为了突破这种限制,可以找一个该地区的socks5代理服务器,然后用PSD接管网游客户端,通过socks5代理服务器连接游戏服务器。这样游戏服务器就会认为该玩家的客户端位于本地区,从而允许该玩家进行游戏(在天朝也叫科学**,属于正向代理)。

  • 某服务器的防火墙仅允许部分端口(如http的80端口)通信,那么可以利用socks5协议和一个打开80端口监听的socks5服务器连接,从而可以连接公网上其他端口的服务器。利用一些额外的技术手段,甚至可以骗过内部的http代理服务器,这时在使用内网http代理上网的环境下也可以不受限制的使用网络服务,这称之为socks over HTTP(我们常说的穿墙)。

  • 内网穿透:在大学里,学校给我们提供了很多服务器资源,我们可以在内网使用。但放寒假回家后,无法进入学校内网,也就无法连接上内网的服务器资源。解决办法:在公网的VPS上搭一个socks代理,并将内网的一台web服务器和该VPS的socks端口打通,通过这台web服务器便可以访问所有内网服务器资源(常见的花生壳nat穿透和这个类似)。

当然,使用代理服务器后,将不可避免的出现通信延迟,所以应该尽量选择同网络(通运营商)、距离近的服务器。

与HTTP代理的对比

socks支持多种用户身份验证方式和通信加密方式。

socks工作在比HTTP代理更低的网络层:socks使用握手协议来通知代理软件其客户端试图进行的连接socks,然后尽可能透明地进行操作,而常规代理可能会解释和重写报头(例如,使用另一种底层协议,例如FTP;然而,HTTP代理只是将HTTP请求转发到所需的HTTP服务器)。

socks5代理支持转发UDP报文,而HTTP属于tcp协议,不支持UDP报文的转发。

虽然HTTP代理有不同的使用模式,CONNECT方法允许转发TCP连接;然而,socks代理还可以转发UDP流量和反向代理,而HTTP代理不能。HTTP代理更适合HTTP协议,执行更高层次的过滤;socks不管应用层是什么协议,只要是传输层是TCP/UDP协议就可以代理。

socks5协议详解

socks5认证协议

在客户端、服务端协商好使用用户名密码认证后,客户端发出用户名密码,格式为:

  • VER:鉴定协议版本
  • ULEN:用户名长度
  • UNAME:用户名
  • PLEN:密码长度
  • PASSWD:密码

服务器鉴定后发出如下回应:

  • VER:鉴定协议版本
  • STATUS:鉴定状态

其中鉴定状态 0x00 表示成功,0x01 表示失败。

socks5传输协议

创建与socks5服务器的TCP连接后,客户端需要先发送请求来协商版本及认证方式,格式为:

  • VER:socks版本(在socks5中是0x05);
  • NMETHODS:在METHODS字段中出现的方法的数目;
  • METHODS:客户端支持的认证方式列表,每个方法占1字节。

服务器从客户端提供的方法中选择一个最优的方法并通过以下消息通知客户端(贪心算法:双方都支持、安全性最高):

  • VER:socks版本(在socks5中是0x05);
  • METHOD:服务端选中的方法(若返回0xFF表示没有方法被选中,客户端需要关闭连接);

METHOD字段的值可以取如下值:

  • X’00’ NO AUTHENTICATION REQUIRED
  • X’01’ GSSAPI
  • X’02’ USERNAME/PASSWORD
  • X’03’ to X’7F’ IANA ASSIGNED
  • X’80’ to X’FE’ RESERVED FOR PRIVATE METHODS
  • X’FF’ NO ACCEPTABLE METHODS

之后客户端和服务端根据选定的认证方式执行对应的认证。认证结束后客户端就可以发送请求信息(如果认证方法有特殊封装要求,请求必须按照方法所定义的方式进行封装)。

socks5请求格式:

  • VER:socks版本(在socks5中是0x05)
  • CMD:SOCK的命令码:
    • CONNECT X’01’
    • BIND X’02’
    • UDP ASSOCIATE X’03’
  • RSV:保留字段
  • ATYP:地址类型:
    • IP V4地址: X’01’
    • 域名地址: X’03’
    • IP V6地址: X’04’
  • DST.ADDR:目的地址

  • DST.PORT:目的端口

服务器按以下格式回应客户端的请求:

  • VER:socks版本(在socks5中是0x05)
  • REP:应答状态码:
    • X’00’ succeeded
    • X’01’ general socks server failure
    • X’02’ connection not allowed by ruleset
    • X’03’ Network unreachable
    • X’04’ Host unreachable
    • X’05’ Connection refused
    • X’06’ TTL expired
    • X’07’ Command not supported
    • X’08’ Address type not supported
    • X’09’ to X’FF’ unassigned
  • RSV:保留字段(需设置为X’00’)
  • ATYP:地址类型:
    • IP V4 address: X’01’
    • DOMAINNAME: X’03’
    • IP V6 address: X’04’
  • BND.ADDR:服务器绑定的地址
  • BND.PORT:服务器绑定的端口

如果被选中的方法包括有认证信息的封装、完整性和/或机密性相关检查,则server端在发送响应包时也需要把这些响应消息封装进去。

SOCKS相关工具

SOCKS服务器

部分SOCKS服务器软件:

SOCKS客户端

一般情况下应用程序会内嵌对SOCKS协议的支持。

客户端 许可证 版本 发布日期 平台 支持协议
Dante client BSD/CMU 1.1.18 09/2005 Linux v4, v5
FreeCap GPL 3.18 02/2005 Windows -
Hummingbird socks - - - Windows -
ProxyCap - 2.03 - Windows -
SocksCap Non-Comercial home use - - - v5
Super Socks5Cap - 1.5.3 - Windows -
tsocks GPL 1.8 10/2002 - -
nylon - - 06/2003 OpenBSD -

python实现socks5代理

为了方便,我们直接使用python中的SocketServer库,直接运行以下程序即可在本机建立了一个socks5的代理服务器:

import socket, sys, select, SocketServer, struct, time

class ThreadingTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): pass

def handle_tcp(sock, remote):
    fdset = [sock, remote]
    while True:
        r, w, e = select.select(fdset, [], [])
        if sock in r:
            if remote.send(sock.recv(4096)) <= 0: break
        if remote in r:
            if sock.send(remote.recv(4096)) <= 0: break

class Socks5Server(SocketServer.StreamRequestHandler):

    def handle(self):
        try:
            print('socks connection from ', self.client_address)
            sock = self.connection
            # 1. Version
            sock.recv(262)
            sock.send(b"\x05\x00");
            # 2. Request
            data = self.rfile.read(4)
            mode = ord(data[1])
            addrtype = ord(data[3])
            if addrtype == 1:  # IPv4
                addr = socket.inet_ntoa(self.rfile.read(4))
            elif addrtype == 3:  # Domain name
                addr = self.rfile.read(ord(sock.recv(1)[0]))
            port = struct.unpack('>H', self.rfile.read(2))
            reply = b"\x05\x00\x00\x01"
            try:
                if mode == 1:  # 1. Tcp connect
                    remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                    remote.connect((addr, port[0]))
                    print('Tcp connect to', addr, port[0])
                else:
                    reply = b"\x05\x07\x00\x01"  # Command not supported
                local = remote.getsockname()
                reply += socket.inet_aton(local[0]) + struct.pack(">H", local[1])
            except socket.error:
                # Connection refused
                reply = '\x05\x05\x00\x01\x00\x00\x00\x00\x00\x00'
            sock.send(reply)
            # 3. Transfering
            if reply[1] == '\x00':  # Success
                if mode == 1:  # 1. Tcp connect
                    handle_tcp(sock, remote)
        except socket.error:
            print('socket error')

def main():
    server = ThreadingTCPServer(('', 1080), Socks5Server)
    server.serve_forever()

if __name__ == '__main__':
    main()

客户端实现代码:

import socket, socks, requests

def main():
    socks.set_default_proxy(socks.SOCKS5, "127.0.0.1", 1080)
    socket.socket = socks.socksocket
    print(requests.get('http://127.0.0.1:1080').text)

if __name__ == '__main__':
    main()

参考文献

 
 
 

[转帖]socks5 协议简介的更多相关文章

  1. 使用netty实现socks5协议

    一.socks5协议简介 SOCKS是一种网络传输协议,主要用于客户端与外网服务器之间通讯的中间传递. SOCKS是"SOCKetS"的缩写[注 1]. 当防火墙后的客户端要访问外 ...

  2. Fiddler--一、HTTP协议简介

    在学习Fiddler之前,最好先学习一下HTTP协议. HTTP协议简介 什么是HTTP协议 超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端 ...

  3. MODBUS-RTU通讯协议简介

    MODBUS-RTU通讯协议简介   什么是MODBUS? MODBUS 是MODICON公司最先倡导的一种软的通讯规约,经过大多数公司 的实际应用,逐渐被认可,成为一种标准的通讯规约,只要按照这种规 ...

  4. JavaWeb:Web与HTTP协议简介

    JavaWeb:Web与HTTP协议简介 Web的概念 什么是Web: Web是网络上使用最广泛的分布式应用架构. 旨在共享分布在网络上的各个Web服务器中的所有互相连接的信息. 三个特征: 用HTM ...

  5. CC2540开发板学习笔记(九)—— BLE协议简介

    一.BLE协议简介 1.协议是什么? 协议是一系列的通信标准,双方需要共同按照这进行正常数据 协议是一系列的通信标准,双方需要共同按照这进行正常数据发射和 接收.协议栈是的具体实现形式,通俗点来理解就 ...

  6. HTTP 协议简介

    HTTP 协议简介 博客分类: acl开发--HTTP协议篇 网络协议http协议  一.TCP/IP 协议介绍 在介绍 HTTP 协议之前,先简单说一下TCP/IP协议的相关内容.TCP/IP协议是 ...

  7. OAUTH协议简介

    OAUTH协议简介 原文来自:http://blog.csdn.net/hereweare2009/article/details/3968582 分类: Open API2009-03-08 12: ...

  8. GRE 协议简介

    1. 协议简介    gre(generic routing encapsulation,通用路由封装)协议是对某些网络层协议(如ip 和ipx)的数据报进行封装,使这些被封装的数据报能够在另一个网络 ...

  9. HTTP协议简介详解 HTTP协议发展 原理 请求方法 响应状态码 请求头 请求首部 java模拟浏览器客户端服务端

    协议简介 协议,自然语言里面就是契约,也是双方或者多方经过协商达成的一致意见; 契约也即类似于合同,自然有甲方123...,乙方123...,哪些能做,哪些不能做; 通信协议,也即是双方通过网络通信必 ...

随机推荐

  1. 11.17 模拟赛&&day-2

    /* 后天就要复赛了啊啊啊啊啊. 可能是因为我是一个比较念旧的人吧. 讲真 还真是有点不舍. 转眼间一年的时间就过去了. 2015.12-2016.11. OI的一年. NOIP gryz RP++. ...

  2. jmeter从文件中读取参数,并实现循环

    1. 通过BeanShell Sampler获取csv的行数 import java.io.BufferedReader;import java.io.FileReader;BufferedReade ...

  3. Django基础之Session

    1. Session的由来 Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的 ...

  4. 2017 ZSTU寒假排位赛 #7

    题目链接:https://vjudge.net/contest/149498#overview. A题,水题,直接按照题意模拟一下即可. B题,我用的是线段树.大力用的差分标记(上次听zy说过,下次再 ...

  5. python性能测试值timeit的使用示例

    from timeit import Timer def t1(): li = [] for i in range(10000): li.append(i) def t2(): li = [] for ...

  6. 预处理、const、static与sizeof-为什么不把所有的函数都定义成内联函数

    1:内联是以代码膨胀(复制)为代价的,仅仅省去了函数调用的开销,从而提高函数的执行效率.如果执行函数体内代码的时间相比于函数调用的开销较大,那么效率的收获会很小.另一方面,每一处内联函数的调用都要复制 ...

  7. Linux设备驱动程序 之 异步通知

    尽管大多数时候阻塞型和非阻塞型操作的组合以及select方法可以有效的查询设备,但是某些时候用这种技术处理就效率不搞了: 例如:一个进程在低优先级执行长的循环计算,但又需要尽可能快的处理输入数据,如果 ...

  8. Linux设备驱动程序 之 休眠

    休眠简介 当一个进程被置入休眠时,它会被标记为一种特殊状态,并从调度器的运行队列中移走:直到某些情况下修改了这个状态,进程才会在任意cpu上调度,即运行该进程:休眠中的进程会被搁置在一边,等待将来的某 ...

  9. .net reflector

    https://www.red-gate.com/dynamic/products/dotnet-development/reflector/download https://github.com/s ...

  10. 检查并解决CentOS 7 安装Tomcat是否成功

    参考网址 https://blog.csdn.net/Blue_Sky_rain/article/details/91348791