iptables+tproxy实现ss-redir的UDP转发的方法

原创 2016年11月17日 18:42:53

使用ss-redir做透明代理转发tcp流量很简单,只需在NAT 表的PREROUTING链中加一句端口转发就可以了,具体方法可以看我之前的一篇博客《Ubuntu编译运行ss-redir打造透明代理Wifi环境》和《Ubuntu 使用Openwrt SDK交叉编译ipk包过程全纪录(超多图)》。

本文在之前转发tcp流量的基础上介绍如何实现UDP流量的转发,因为在某些情况下,比如个别国外的网游可能需要进行UDP加速,另外DNS解析也是UDP协议,所以如果实现了UDP流量的转发,我们将不再需要pdnsd这样的防DNS污染的服务。而且TCP+UDP流量转发下,Shadowsocks可以实现和VPN几乎一样的效果,但是SS比VPN的价格和搭建难度要低得多。

首先你要确定服务端支持UDP转发,你自己搭建服务器的时候要在ss-server的后面加上 -u参数,如果是买网上别人搭好的服务器看看介绍中有没有提及支持UDP转发即可。

下面就可以开启本地的ss-redir服务了,注意Go语言和Python版Shadowsocks均不支持UDP转发,只有c语言版的Shadowsocks-libev才支持,而且c版的更新频率是最高的,CPU内存的占用率是最小的,所以非常推荐使用Shadowsocks-libev,具体编译运行的方法可以看我上面贴出来的两篇文章。

我最常使用的ss-redir命令是(Ubuntu OpenWrt命令相同)
ss-redir -c <配置json文件> -l <端口号> -u

其中,要想做到UDP转发,一定不要忘记-u参数,添加了-u参数之后,你就可以看到ss-redir同时在tcp和udp端口上监听


启动ss-redir之后,先像Ubuntu编译运行ss-redir打造透明代理Wifi环境》一样在NAT表中配置tcp流量的转发,并用百度搜索IP确认tcp流量已经经过了代理。然后我们开始处理UDP流量,逻辑其实很简单,就是把需要转发的UDP包打上一个任意的标志,然后交给TProxy配合iptables进行转发。

所以这里的核心就是TProxy服务,首先在Ubuntu16.04中,系统内核已经默认安装了TProxy,不需要另外安装,但是在OpenWrt中需要去官网下载几个TProxy的依赖包,具体的下载安装方式可以参考《OpenWrt Image Builder 制作带插件的HG255D固件记录》其中你可以通过尝试安装luci-app-shadowsocks,安装过程中会提示你缺少哪些依赖包,并且luci主页的UDP转发项目也会提示



如上图,OpenWrt做UDP转发需要的依赖是:iptables-mod-tproxy,kmod-ipt-tproxy和ip-full
我们可以去OpenWrt的Packages/base里下载这几个依赖包或者下载别人编译好的固件

光安装了依赖还不够,Ubuntu还需要打开内核转发

开启Linux的内核转发方法是,打开/etc/sysctl.conf这个文件,取消掉 net.ipv4.ip_forward=1 这一行的注释.
然后执行
sudo sysctl -p
使修改后的文件配置立即生效。
然后就到了最激动人心的配置iptables的时刻了,配置ss-redir的iptables方法和配置Redsocks2的方法是一样的,原理也一样

这里我们假设我们的ss-redir监听端口是20000

ip rule add fwmark 0x01/0x01 table 100
ip route add local 0.0.0.0/0 dev lo table 100
iptables -t mangle -N SSUDP
iptables -t mangle -A SSUDP -p udp -j TPROXY --on-port 20000 --tproxy-mark 0x01/0x01
iptables -t mangle -A PREROUTING -j SSUDP
如果你在-p udp 后面加上 --dport 53的话就仅转发DNS的UDP流量

当然按照wiki上说明的那么些你是上不了网的,因为DNS解析请求被环形转发了,所以我们避免形成回路,在PREROUTING链前面添加如下规则

iptables -t mangle -I PREROUTING -d 127.0.0.0/24 -j RETURN  
iptables -t mangle -I PREROUTING -d 192.168.0.0/16 -j RETURN  
iptables -t mangle -I PREROUTING -d 10.42.0.0/16 -j RETURN  
iptables -t mangle -I PREROUTING -d 0.0.0.0/8 -j RETURN  
iptables -t mangle -I PREROUTING -d 10.0.0.0/8 -j RETURN  
iptables -t mangle -I PREROUTING -d 172.16.0.0/12 -j RETURN  
iptables -t mangle -I PREROUTING -d 224.0.0.0/4 -j RETURN  
iptables -t mangle -I PREROUTING -d 240.0.0.0/4 -j RETURN  
iptables -t mangle -I PREROUTING -d 169.254.0.0/16 -j RETURN  
iptables -t mangle -I PREROUTING -d 255.255.0.0/8 -j RETURN  

这个其实和NAT表上做的那些防止tcp流量回路的配置一样,你可以简单的理解成在NAT表中配置TCP的转发规则,在mangle表中配置UDP的转发规则

全都执行完后可以看看mangle表应该如下


而且要注意,ss-redir监听的IP网段要和端口转发的目标在同一个网段,也就是说如果你把Ubuntu作为一个局域网的网关,假设此时Ubuntu局域网的IP为192.168.1.81,你想把Ubuntu设置为网关并让局域网其他电脑(192.168.1.x)通过这台Ubuntu科学上网,那么你就要让ss-redir监听在192.168.1.81:20000,如果你让这个Ubuntu电脑分享了一个wifi,想让连接这个wifi的手机科学上网,那么ss-redir监听端口为10.42.0.1:20000,当然如果你不知道该设为那个网段,那就监听0.0.0.0:20000即可。

下图是开启udp转发之后运行正常时的ss-redir日志(-v啰嗦模式)下图记录的主要是查几个DNS


那么配置完成之后怎样测试UDP转发是否成功呢?我这里提供两个方法

方法一:我们知道DNS请求是通过UDP发送,所以我们在windows环境下测试DNS解析结果有没有被投毒就可以知道UDP有没有走SS了

所以首先找一台电脑并设置上面配置好的Ubuntu/OpenWrt为网关,然后使用境外的DNS服务器如8.8.8.8,8.8.4.4,208.67.222.222,208.67.220.220查询一些被防火墙投毒的域名就可以知道UDP有没有走SS了,如下图的对比

首先是开启UDP转发:


下面是没开启UDP转发,被投毒的比较彻底,facebook和twitter直接被污染到了同一地址



方法二:可以通过一款软件nattypetester来测试UDP转发情况,如果UDP没有成功转发,软件显示的IP为你本地的IP,要是转发成功,显示的IP为服务器的IP



上面两张图可能你们看起来没有查遍,但是只要知道UDP转发成功的话public end是SS服务器的地址,反之没成功的话Public end是本地地址就好

===============我是分割线=============================

关于nattypetester测试工具UDP转发中的FullCone,PortRestrictedCone,RestrictedCone,Symmetric NAT可以参考下面的资料,资料出处:http://koolshare.cn/thread-3843-1-1.html


NAT的四种类型及类型检测


考虑到UDP的无状态特性,目前针对其的NAT实现大致可分为Full Cone、Restricted Cone、Port Restricted Cone和Symmetric NAT四种。值得指出的是,对于TCP协议而言,一般来说,目前NAT中针对TCP的实现基本上是一致的,其间并不存在太大差异,这是因为TCP协议本身 便是面向连接的,因此无需考虑网络连接无状态所带来复杂性。 
用语定义


1.内部Tuple:指内部主机的私有地址和端**所构成的二元组,即内部主机所发送报文的源地址、端口所构成的二元组
2.外部Tuple:指内部Tuple经过NAT的源地址/端口转换之后,所获得的外部地址、端口所构成的二元组,即外部主机收到经NAT转换之后的报文时,它所看到的该报文的源地址(通常是NAT设备的地址)和源端口
3.目标Tuple:指外部主机的地址、端口所构成的二元组,即内部主机所发送报文的目标地址、端口所构成的二元组


详细释义


1. Full Cone NAT:所有来自同一 个内部Tuple X的请求均被NAT转换至同一个外部Tuple Y,而不管这些请求是不是属于同一个应用或者是多个应用的。除此之外,当X-Y的转换关系建立之后,任意外部主机均可随时将Y中的地址和端口作为目标地址 和目标端口,向内部主机发送UDP报文,由于对外部请求的来源无任何限制,因此这种方式虽然足够简单,但却不那么安全


2. Restricted Cone NAT: 它是Full Cone的受限版本:所有来自同一个内部Tuple X的请求均被NAT转换至同一个外部Tuple Y,这与Full Cone相同,但不同的是,只有当内部主机曾经发送过报文给外部主机(假设其IP地址为Z)后,外部主机才能以Y中的信息作为目标地址和目标端口,向内部 主机发送UDP请求报文,这意味着,NAT设备只向内转发(目标地址/端口转换)那些来自于当前已知的外部主机的UDP报文,从而保障了外部请求来源的安 全性


3. Port Restricted Cone NAT:它是Restricted Cone NAT的进一步受限版。只有当内部主机曾经发送过报文给外部主机(假设其IP地址为Z且端口为P)之后,外部主机才能以Y中的信息作为目标地址和目标端 口,向内部主机发送UDP报文,同时,其请求报文的源端口必须为P,这一要求进一步强化了对外部报文请求来源的限制,从而较Restrictd Cone更具安全性


4. Symmetric NAT:这是一种比所有Cone NAT都要更为灵活的转换方式:在Cone NAT中,内部主机的内部Tuple与外部Tuple的转换映射关系是独立于内部主机所发出的UDP报文中的目标地址及端口的,即与目标Tuple无关; 在Symmetric NAT中,目标Tuple则成为了NAT设备建立转换关系的一个重要考量:只有来自于同一个内部Tuple 、且针对同一目标Tuple的请求才被NAT转换至同一个外部Tuple,否则的话,NAT将为之分配一个新的外部Tuple;打个比方,当内部主机以相 同的内部Tuple对2个不同的目标Tuple发送UDP报文时,此时NAT将会为内部主机分配两个不同的外部Tuple,并且建立起两个不同的内、外部 Tuple转换关系。与此同时,只有接收到了内部主机所发送的数据包的外部主机才能向内部主机返回UDP报文,这里对外部返回报文来源的限制是与Port Restricted Cone一致的。不难看出,如果说Full Cone是要求最宽松NAT UDP转换方式,那么,Symmetric NAT则是要求最严格的NAT方式,其不仅体现在转换关系的建立上,而且还体现在对外部报文来源的限制方面。


P2P的NAT研究 
第一部分:NAT介绍 
第二部分:NAT类型检测 


第一部分: NAT介绍 
各种不同类型的NAT(according to RFC) 
Full Cone NAT: 
   内网主机建立一个UDP socket(LocalIPocalPort) 第一次使用这个socket给外部主机发送数据时NAT会给其分配一个公网(PublicIPublicPort),以后用这个socket向外面任何主机发送数据都将使用这对(PublicIPublicPort)。此外,任何外部主机只要知道这个(PublicIPublicPort)就可以发送数据给(PublicIPublicPort),内网的主机就能收到这个数据包 
Restricted Cone NAT: 
   内网主机建立一个UDP socket(LocalIPocalPort) 第一次使用这个socket给外部主机发送数据时NAT会给其分配一个公网(PublicIPublicPort),以后用这个socket向外面任何主机发送数据都将使用这对(PublicIPublicPort)。此外,如果任何外部主机想要发送数据给这个内网主机,只要知道这个(PublicIPublicPort)并且内网主机之前用这个socket曾向这个外部主机IP发送过数据。只要满足这两个条件,这个外部主机就可以用自己的(IP,任何端口)发送数据给(PublicIPublicPort),内网的主机就能收到这个数据包 
Port Restricted Cone NAT: 
    内网主机建立一个UDP socket(LocalIPocalPort) 第一次使用这个socket给外部主机发送数据时NAT会给其分配一个公网(PublicIPublicPort),以后用这个socket向外面任何主机发送数据都将使用这对(PublicIPublicPort)。此外,如果任何外部主机想要发送数据给这个内网主机,只要知道这个(PublicIP:PublicPort)并且内网主机之前用这个socket曾向这个外部主机(IP,Port)发送过数据。只要满足这两个条件,这个外部主机就可以用自己的(IP,Port)发送数据给(PublicIP:PublicPort),内网的主机就能收到这个数据包 
Symmetric NAT: 
    内网主机建立一个UDP socket(LocalIP,LocalPort),当用这个socket第一次发数据给外部主机1时,NAT为其映射一个(PublicIP-1,Port-1),以后内网主机发送给外部主机1的所有数据都是用这个(PublicIP-1,Port-1),如果内网主机同时用这个socket给外部主机2发送数据,第一次发送时,NAT会为其分配一个(PublicIP-2,Port-2), 以后内网主机发送给外部主机2的所有数据都是用这个(PublicIP-2,Port-2).如果NAT有多于一个公网IP,则PublicIP-1和PublicIP-2可能不同,如果NAT只有一个公网IP,则Port-1和Port-2肯定不同,也就是说一定不能是PublicIP-1等于 PublicIP-2且Port-1等于Port-2。此外,如果任何外部主机想要发送数据给这个内网主机,那么它首先应该收到内网主机发给他的数据,然后才能往回发送,否则即使他知道内网主机的一个(PublicIP,Port)也不能发送数据给内网主机,这种NAT无法实现UDP-P2P通信。 


第二部:NAT类型检测


前提条件:有一个公网的Server并且绑定了两个公网IP(IP-1,IP-2)。这个Server做UDP监听(IP-1,Port-1),(IP-2,Port-2)并根据客户端的要求进行应答。


第一步:检测客户端是否有能力进行UDP通信以及客户端是否位于NAT后?


客户端建立UDP socket然后用这个socket向服务器的(IP-1,Port-1)发送数据包要求服务器返回客户端的IP和Port, 客户端发送请求后立即开始接受数据包,要设定socket Timeout(300ms),防止无限堵塞. 重复这个过程若干次。如果每次都超时,无法接受到服务器的回应,则说明客户端无法进行UDP通信,可能是防火墙或NAT阻止UDP通信,这样的客户端也就 不能P2P了(检测停止)。 
当客户端能够接收到服务器的回应时,需要把服务器返回的客户端(IP,Port)和这个客户端socket的 (LocalIP,LocalPort)比较。如果完全相同则客户端不在NAT后,这样的客户端具有公网IP可以直接监听UDP端口接收数据进行通信(检 测停止)。否则客户端在NAT后要做进一步的NAT类型检测(继续)。


第二步:检测客户端NAT是否是Full Cone NAT?


客户端建立UDP socket然后用这个socket向服务器的(IP-1,Port-1)发送数据包要求服务器用另一对(IP-2,Port-2)响应客户端的请求往回 发一个数据包,客户端发送请求后立即开始接受数据包,要设定socket Timeout(300ms),防止无限堵塞. 重复这个过程若干次。如果每次都超时,无法接受到服务器的回应,则说明客户端的NAT不是一个Full Cone NAT,具体类型有待下一步检测(继续)。如果能够接受到服务器从(IP-2,Port-2)返回的应答UDP包,则说明客户端是一个Full Cone NAT,这样的客户端能够进行UDP-P2P通信(检测停止)。


第三步:检测客户端NAT是否是Symmetric NAT?


客户端建立UDP socket然后用这个socket向服务器的(IP-1,Port-1)发送数据包要求服务器返回客户端的IP和Port, 客户端发送请求后立即开始接受数据包,要设定socket Timeout(300ms),防止无限堵塞. 重复这个过程直到收到回应(一定能够收到,因为第一步保证了这个客户端可以进行UDP通信)。 
用同样的方法用一个socket向服务器的(IP-2,Port-2)发送数据包要求服务器返回客户端的IP和Port。 
比 较上面两个过程从服务器返回的客户端(IP,Port),如果两个过程返回的(IP,Port)有一对不同则说明客户端为Symmetric NAT,这样的客户端无法进行UDP-P2P通信(检测停止)。否则是Restricted Cone NAT,是否为Port Restricted Cone NAT有待检测(继续)。


第四步:检测客户端NAT是否是Restricted Cone NAT还是Port Restricted Cone NAT?


客户端建立UDP socket然后用这个socket向服务器的(IP-1,Port-1)发送数据包要求服务器用IP-1和一个不同于Port-1的端口发送一个UDP 数据包响应客户端, 客户端发送请求后立即开始接受数据包,要设定socket Timeout(300ms),防止无限堵塞. 重复这个过程若干次。如果每次都超时,无法接受到服务器的回应,则说明客户端是一个Port Restricted Cone NAT,如果能够收到服务器的响应则说明客户端是一个Restricted Cone NAT。以上两种NAT都可以进行UDP-P2P通信。


注:以上检测过程中只说明了可否进行UDP-P2P的打洞通信,具体怎么通信一般要借助于Rendezvous Server。另外对于Symmetric NAT不是说完全不能进行UDP-P2P达洞通信,可以进行端口预测打洞,不过不能保证成功。

如果还想了解更多关于UDP转发和PS4游戏加速的问题,可以参考这个帖子:http://tieba.baidu.com/p/3517836858?see_lz=1

版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

iptables学习笔记:同一端口号同时支持tcp和udp的转发

前段时间,某项目中遇到一个端口转发问题,虽然我无缘参与项目,但由于项目使用到的一个平台恰好是我前不久搞过的,所以最终还是找我,于是中断了正在进行的任务进行协助。他们定位到只有udp无法转发成功,而tc...

Ubuntu 使用Openwrt SDK交叉编译ipk包过程全纪录(超多图)

本文从在Ubuntu中下载SDK,git克隆最新代码,make menu,编译ipk包,解决编译错误,安装ipk,解决安装ipk中碰到的依赖,部署iptables和ss-redir,安装luci界面,...

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

OpenWrt Image Builder 制作带插件的HG255D固件记录

使用网上下载的别人编译的Openwrt固件总会存在这样或者那样的问题,或者根本不满足自己的需要,这时候就需要自己编译固件,自己编译ipk包。可以解决很多内核版本不匹配,软件过时,路由器不稳定,固件臃肿...

TPROXY之殇-NAT设备加代理的恶果

一段往事无独有偶,过了N多年,又到了这个时候,碰到了同样的事情...xx年的万圣节,由于服务器瘫痪我们被罚了500块钱,最终发现瘫痪的原因是TPROXY造成的,当时每个大服务区有一台LVS负载均衡设备...
  • dog250
  • dog250
  • 2013-10-26 23:39
  • 10736

Ubuntu编译运行ss-redir打造透明代理Wifi环境

研究了一阵子的Openwrt路由器,主要是让ss作为一个服务跑在openwrt路由器上,然后该路由器就实现了透明代理功能,连入该路由器Wifi的设备都实现了代理,达到了科学上网的效果。后来又一想,既然...

iptables设置端口转发

将本地接口IP 61.144.14.72 的3389端口 转发到 116.6.73.229的3389       (主要访问到61.144.14.72的3389端口,就会跳转到116.6.73.22...

通过iptables实现端口转发和内网共享上网

原文:http://wwdhks.blog.51cto.com/839773/1154032本文作者:张天成 zhangtiancheng#gmail.com 转发请注明出处。 iptables...

iptables:tproxy做透明代理

透明代理:客户端向真实服务器发起连接,代理机冒充服务器与客户端建立连接,并以客户端ip与真实服务器建立连接进行代理转发。因此对于客户端与服务器来说,代理机都是透明的。

iptables 扩展详解

1、其实匹配扩展中,还有需要加-m引用模块的显示扩展,默认是隐含扩展,不要使用 -m 状态检测的包过滤 -m state        --state {NEW,ESTATBLISHED,I...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)