Linux IPv4 forward自动丢弃源IP为系统已绑定的IP的问题

A是路由,其上做了策略,一部分符合特定条件的流量,是要转发到B进行封装处理,A和B之间做了数个VLAN,B根据VLAN应用不同的策略。

不过这里的问题是,B的默认网关也是A(环路问题是不存在的,已经有对应规则处理),所以B自身发出的流量也会由A应用策略,转发回给B自己。而B收到src IP是local IP(系统已绑定的IP)的包时,kernel会直接丢弃数据包,所以除了B自己的数据包,B都能正常封装。

解决这个问题的一个方法,是让A在把数据包转发给B前,做一次SNAT,这样B收到的数据包,src IP就是A的IP了。其实SNAT并没有什么影响,A对NAT也有hardware offload,但这样操作实在觉得多此一举。

翻了下kernel ip sysctl部分的文档,发现个参数accept_local:

accept_local – BOOLEAN

Accept packets with local source addresses. In combination with suitable routing, this can be used to direct packets between two local interfaces over the wire and have them accepted properly. default FALSE

所以把这个参数置1就能不依赖SNAT解决问题了:

TCP Sendbuffer Size与RTT的问题

最近从A服务器下载数据时,发现如果走B服务器的VPN下载,速率只能跑到300KB左右,但是B从A直接下载却能跑到1MB+/s,B到本地的速度也远超过A到B的速度,其实一开始我以为是VPN实现的问题,有段时间在思考如何优化VPN,但是尝试了其它VPN实现,问题并没有解决。后来发现,走B的代理而不是VPN,速度正常。

本地到B的RTT大约160ms,B到A大约50ms。

Wireshark抓包,对tcp sequence number统计了下:

放大点看:

大概每传输60KB,就要等大约200ms才能继续。200ms刚好差不多等于本地走VPN到A的RTT。传这60KB,只花了大概10ms,忽略这10ms不算的话,每秒大概只能接收五次60KB,5*60KB=300KB,刚好接近走VPN的下载速度。

TCP要发送的数据包存放在send buffer中,send buffer已使用的空间,在收到ACK前是不能释放的,所以,如果这时send buffer满了而未收到ACK,那kernel就不会继续对外发送数据。

所以,走VPN慢的原因,是因为A设定的的send buffer太小,在本地发出的ACK送达A前,A的send buffer就满了。走B代理快,是因为B到A的RTT比较小,ACK是由B上的代理程序在接收到数据后发送给A的,所以A很快就能收到ACK而继续向B发送数据,B到本地没有send buffer过小的问题,所以B上的代理往本地发回数据的速率几乎与A到B的速率一致。

L2TPv3 MTU

L2TPv3支持自动拆包,封装后的数据包如果超出裸线路的MTU也能正常运作。

拆包合包毕竟需要耗资源的,这种多余的操作,能避免的话当然最好。

要避免,首先确定好L2TPv3隧道的MTU。

图:

UDP封装模式:

L2TPv3隧道MTU = 裸线路MTU – IP头 – UDP头 – L2TPv3头 – 以太网头

经测试L2TPv3头在这种模式下是12字节,如果裸线路MTU是1500,那么隧道MTU = 1500 – 20 – 8 – 12 – 14 = 1446,TCP MSS = 1446 – 20 – 20 = 1406

IP封装模式:

L2TPv3隧道MTU = 裸线路MTU – IP头 –  L2TPv3头 – 以太网头

经测试L2TPv3头在这种模式下是8字节,如果裸线路MTU是1500,那么隧道MTU = 1500 – 20 – 8 – 14 = 1458,TCP MSS = 1458- 20 – 20 = 1418

 

以太网头不一定是14字节,根据实际使用情况自行调整。

Fix Ubuntu policy-based route with fwmark not work

近期发现Ubuntu基于ip rule add fwmark … lookup …所做的策略路由无法正常使用,而Debian正常。抓包的特征就是,出网数据包能应用到策略路由,也能抓到回应的数据包,但回应的数据包被内核丢弃,不会送达user space。

而ip rule add from … lookup …则正常。

查找资料得知是rp_filter的影响(见此:https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt),继而发现Ubuntu的/etc/sysctl.d是有以下这个文件的:

编辑/etc/sysctl.d/10-network-security.conf,把net.ipv4.conf.default.rp_filter以及net.ipv4.conf.all.rp_filter改成2,然后应用:

 

Linux Policy-based site-to-site IPsec VPN动态IP的配置及内网穿透的应用(StrongSwan)

上一篇文章提到了一点StrongSwan的配置。

本文继续使用StrongSwan。

StrongSwan的left和right是支持使用域名的,利用此可以实现动态IP的支持;上一篇文章用了type=transport模式转发UDP端口构建L2TPv3,如果没有L2组网的需求,其实可以直接利用type=tunnel模式实现L3转发。

网络拓扑:

上图中的路由器lan-router1和lan-router2都是通过pppoe接入互联网的,域名lan-router1.router和lan-router2.router通过ddns分别解析到了各自pppoe0的IP地址上;server1和server2分别通过lan-router1和lan-router2接入互联网。

下面的操作将在server1与lan-router2之间构建site-to-site IPsec VPN,接通192.168.1.0/24与10.0.0.0/24这两个内网。

提醒:用StrongSwan构建site-to-site IPsec VPN的话,需要至少有一端的UDP 500和4500端口在公网可以访问。

1. 配置StrongSwan

安装StrongSwan就不再阐述了。

在IPsec的配置文件中,left指本地,right指对方。

2.1 server1的配置

编辑/etc/ipsec.conf,末尾加入:

这里left直接用0.0.0.0表示任何IP都接受连接,right用lan-router2的ddns域名lan-router2.router。

其中left/rightsubnet分别定义了server1的内网IP段,server2的内网IP段,意思就是leftsubnet和rightsubnet之间的流量将走site-to-site IPsec VPN。left/rightsubnet支持定义多个子网的,用逗号分隔。

在server1的auto是route,意思是当内核遇到目的地为rightsubnet的流量,自动发起协商构建site-to-site IPsec VPN。

left/rightid是不建议省略的,另外记得在开头添加@阻止把字符串当成域名解析成IP。

其余的参数,大概就是使用aes-128加密,sha1签名,ikev2协议交换密钥,30秒发送一次心跳包(使用NAT的话尤其重要),心跳包超过120秒无回应重新构建连接(dpdaction=restart)。

编辑/etc/ipsec.secrets,在末尾加入(其中的pre-shared-key是密码,记得改成你自己定的值)

ipsec.secrets的格式,上一篇文章也有提到,是:

2.2 server2的配置

server2需开放UDP端口500与4500。

编辑/etc/ipsec.conf,末尾加入:

其实大体上就是把server1的配置中的left和right调换过来。

当然,这边的right用了域名lan-router1.router,这个域名是会解析到lan-router1 的pppoe0接口的IP的。

此外,这边的auto是add,dpdaction是clear,主要原因是server1处于内网,在server2是无法主动发起协商请求的,所以让StrongSwan启动时仅加载此配置,不作任何其它操作,并且心跳回应超时后,不重建连接。

编辑/etc/ipsec.secrets,在末尾加入(其中的pre-shared-key是密码,记得改成你自己定的值)

2.3 重启StrongSwan并发起协商构建连接

server1和lan-router2执行下面的命令重启StrongSwan:

发起协商是仅能从server1发起的,原因上一篇文章和开头已提过:

如果up有提示successfully,但是ping不通的话,见本文2.3防火墙的配置。

在lan-router2上测试:

因为设置了心跳,所以无需担心路由器上的NAT记录超时,此外server1上设置了自动重连,所以更换IP或者其它原因导致VPN断开后,只要ddns更新的DNS记录生效了或者网络恢复正常,理论上server1是会自动重连的,当然,理论上。

2. 其它配置

2.1 L2TPv3、GRE等应用

通过上面构造的VPN,因为server1和lan-router2都是分别拥有一个固定的内网IP的,所以可以直接指定双方的内网IP构建L2TPv3(详见上一篇文章)或者GRE之类的。

2.2 启用IPv4转发以及设置SNAT规则

上面配置的都是/24的子网,如果两边都未启用IPv4转发,双方都仅能访问对方的IP。

本文的拓扑中,server1是需要启用IPv4转发并设置SNAT的,lan-router2上一般不需要进行这两项配置。

如何启用IPv4转发以及设置SNAT规则,网络上很多资料,这个各位自行按实际情况解决。

2.3 防火墙的配置

这里给个匹配IPsec流量的规则,自行按需应用吧:

例如lan-router2上pppoe0接口可能配了防火墙对入网流量进行了较为严格的入网流量控制,会导致lan-router2可以主动访问server1但server1无法主动访问lan-router2,加入以下规则即可解决:

转发的类似,加入FORWARD链即可。