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. Enable file editing in Visual Studio's debug mode

    Visual Studio 使用及调试必知必会 http://www.cnblogs.com/luminji/p/3287728.html How do I enable file editing i ...

  2. 将.py脚本打包成.exe

    https://www.cnblogs.com/wyl-0120/p/10823102.html 为了方便使用,通过pyinstaller对脚本进行打包成exe文件. pip3 install pyi ...

  3. more/less

    more less

  4. 小米 oj 纯位数

     纯位数 序号:#101难度:非常难时间限制:2000ms内存限制:20M 描述 在数学中,所谓"纯位数"是指由相同位元重复而组成的自然数.比如在十进制中,1,22,333,555 ...

  5. 【SecureCRT】SecureCRT 护眼配色

      终端有一个好的配色,不仅能保护自己的眼睛,也能给人一个好心情,本配色方案适合任意一种SSH客户端软件.   设置背景颜色 Options => Sessions options => ...

  6. html页面之间相互传值

    常见的在页面登录过后会获得一个token值然后页面跳转时传给下一个页面 sessionStorage.setItem("token",result.token);//传输token ...

  7. Java核心复习 —— ArrayList源码阅读

    一.ArrayList 介绍 ArrayList是List接口可变数组的实现. 特点 非线程安全 查找和修改效率高 二.ArrayList 使用方法 remove元素 @Test public voi ...

  8. [Javascript]客户端检测

    客户端检测是一种行之有效的开发策略.但不到万不得已,就不要使用客户端检测.先设计通用的方案,然后根据浏览器之间的差异和各自的怪癖quirky,再使用特定于浏览器的技术增强该方案. 能力检测 Featu ...

  9. Rvm 进行gem安装时必须输入密码Your user account isn't allowed to install to the system RubyGems 解决方案

    今天开发过程中,从master拉下代码后重启项目,想用控制台时,却发现需要密码??并且三次密码确认后还是疯狂报错. 当时第一想到是rvm版本不一致,随即则检查了版本跟gem生成,当确认rvm版本无误时 ...

  10. C# 创建、部署和调用WebService的示例

    http://www.cnblogs.com/Brambling/p/6815565.html