4
23
2017
15

UDP: 谁动了我的源地址?

本文来自依云's Blog,转载请注明。

最近 #archlinux-cn 又流行玩 teeworlds 了,然而我却连不上那个服务器。

情况很奇怪。我能 ping 通服务器 IP,TCP 连接也正常,UDP traceroute 也表现得很正常(对关闭端口能够完成,对开放端口会在最后一跳开始得到一堆星号),并且我连接的时候,服务器能看到我在连接。也就是说,TCP 和 ICMP 都正常,UDP 上行正常,下行出了状况。

难道是有防火墙?首先呢,我能连接其它服务器,说明我这边没有问题;大部分人能连接上服务器,说明服务器那边也没有问题。所以,问题出在路上。也确实有另外的北京联通用户连不上这个服务器。但是很奇怪啊,为什么单单只是这一个 IP 的 UDP 包丢失了呢?

于是继续试验。从最简单的开始,用 netcat / socat 尝试通讯。方向反过来,我监听,服务器那边连接。端口是我在路由器上做过端口映射的。结果是正常的。再来,服务器那边监听,我往那边发,果然我就收不到包了。按理说,UDP 双方是对等的,不应该换了个方向就出问题呀。难道是因为端口映射?Wireshark 抓包看到本地使用的端口号之后,在路由器上映射一下,果然就通了!

然后,我注意到了一件十分诡异的事情:虽然我和服务器能够通讯了,但是我的 Wireshark 上只显示了我发出去的包,却看不到回来的包!我抓包时按服务器 IP 做了过滤,所以,回来的包的源 IP 不是服务器的地址!

重新抓包一看,果然。服务器 IP 是 202.118.17.142,但是回来的包的源 IP 变成了 121.22.88.41……看起来这是联通的设备,在下行 traceroute 时能够看到有节点与它 IP 相似(121.22.88.1)。原来又是这著名的「联不通」又干坏事了 -_-|||

虽然 socat 接收 UDP 时不介意源 IP 变化了,但是 teeworlds 介意啊。并且 NAT 那边也会不知所措。所以,首先得告诉路由器把来自这个 IP 的 UDP 包全部扔给我:

ssh 192.168.1.1 iptables -I FORWARD -i ppp0.2 -p udp -s 121.22.88.41 -j ACCEPT

于是数据包有了。接下来是修正源 IP。我试过 SNAT,无效。这东西似乎只对本地发出的包有用?于是我又用 netfilter_queue 了。这东西很强大呢~一个简单的 Python 脚本搞定:

#!/usr/bin/env python3

from netfilterqueue import NetfilterQueue
from scapy.all import *

def main(pkt):
  p = IP(pkt.get_payload())
  # print('recv', p)
  p.src = '202.118.17.142'
  p.chksum = None
  p[UDP].chksum = None
  pkt.set_payload(bytes(p))
  # print('fixed to', p)
  print('.', flush=True, end='')
  pkt.accept()

conf.color_theme = DefaultTheme()
nfqueue = NetfilterQueue()
nfqueue.bind(1, main)
try:
  nfqueue.run()
except KeyboardInterrupt:
  pass

然后是 iptables 命令:

sudo iptables -I INPUT -s 121.22.88.41 -p udp -j NFQUEUE --queue-num 1 --queue-bypass

scapy 这个神奇的网络库在 Arch 官方源里叫「scapy3k」。Python 的 netfilterqueue 模块需要用我自己修改过的这个版本

2017年7月30日更新:Python 的依赖有点麻烦,所以我又写了个 Rust 版本,放在 GitHub 上了

Category: 网络 | Tags: linux python 网络 iptables Rust | Read Count: 14087
FiveYellowMice 说:
Apr 23, 2017 06:31:17 PM

辛苦了。你国运营商真是

Hacksign 说:
Apr 24, 2017 11:53:49 AM

dns反射或者syn flood, fuck回去吧......

Sherlock-Holo 说:
Apr 27, 2017 10:35:25 PM

scapy3k是py3的,scapy是py2的

SilverRainZ 说:
Apr 27, 2017 11:08:18 PM

百合总是能解决各种疑难杂症啊…… 我要是碰上这样的问题肯定搞不定。
大家又开始玩 tee 了好棒啊!

cherrot 说:
May 01, 2017 01:44:14 AM

可是为什么会动源IP,联通没NAT干净导致?

Avatar_small
依云 说:
May 01, 2017 09:50:57 AM

不知道啊。而且别的服务器都是好的,就它一个有问题……

FiveYellowMice 说:
May 04, 2017 09:36:21 AM

额, Emoji 又被吞了啊.....

自由建客 说:
May 19, 2017 12:17:14 AM

SNAT 怎么会不行,你的命令是什么?

Avatar_small
依云 说:
May 19, 2017 11:14:47 AM

这样:ssh 192.168.1.1 iptables -t nat -I INPUT -i ppp0.2 -s 121.22.88.41 -p udp -m udp --sport 8121 -j SNAT --to-source 202.118.17.142:8121
以及这样:sudo iptables -t nat -I INPUT -s 121.22.88.41 -p udp -m udp --sport 8121 -j SNAT --to-source 202.118.17.142:8121

Avatar_small
依云 说:
May 19, 2017 11:15:24 AM

也在 POSTROUTING 链上试过。

shentar 说:
Jun 21, 2017 09:56:18 PM

UDP不是对等的,服务端会选择它觉得合适的源IP作为源地址回包。源IP由系统的路由决定的。

https://stackoverflow.com/questions/3062205/setting-the-source-ip-for-a-udp-socket

Avatar_small
依云 说:
Jun 21, 2017 10:31:07 PM

我知道。问题是,那个 IP 不是服务器的……

tdus 说:
Jul 31, 2017 12:36:48 PM

会不会strongswan连上就断掉也是这个问题,俺回去研究下


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

| Theme: Aeros 2.0 by TheBuckmaker.com