V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
KCheshireCat
V2EX  ›  宽带症候群

从原理上根绝运营商劫持,基于 TTL 的反劫持 iptables 规则

  •  
  •   KCheshireCat · 2017-01-22 20:04:41 +08:00 · 10353 次点击
    这是一个创建于 2872 天前的主题,其中的信息可能已经有所发展或是发生改变。

    不管你是遇到加小尾巴跳转,iframe 嵌套广告,302 跳转,还是 JavaScript 脚本劫持.
    只要是基于旁路设备监听抢答数据包这个原理的劫持行为. 这套 iptables 规则就能应对.

    注意:目前仍在实验阶段,浙江移动测试有效,无法保证不会对正常的连接产生破坏.

    主要原理:基于 IP 头 TTL 值的判断丢包.并使用 ACK 空应答包,和装满数据的 TCP 包来更新 TTL,防止正常 TTL 变动导致连接断开.

    • 使用 IP 头 TTL 值是因为旁路设备不可能知道服务器和客户端之间究竟有几跳而"自己"又是在哪个位置,服务器的初始 TTL 又是多少.
    • 使用 ACK 或 ACK,PSH 标识位的空包来更新 TTL 的原因是旁路设备被没有理由发这样的包,这包不能切断连接而且本身也不携带上层数据.
    • 使用数据长度为 MSS 协商值的原因是,旁路设备要追踪 MSS 协商这个性能成本非常高,每条 TCP 连接都会协商 MSS,但不是每条连接都会触发规则需要劫持.

    项目地址

    需要模块

    • bpf
    • u32
    • connmark
    • mark

    注意

    • connmark的标志位需要 0x7FF 长度来记录 MSS 值,还有 0xFF 来记录 TTL 值.默认记录位置为 0x07FF00FF.
    • mark的标志位需要 0x1 长度.默认记录位置为 0x00000001.

    工作原理

    • 对每条 TCP 连接在握手时的SYN+ACK包的 TTL 值和 MSS 协商值.
    • 并使用 TCP flags 标志为ACK|ACK&&PSH,且 TCP Data 长度为 0 或长度为 MSS 协商值的包对保存的 TTL 值更新.
    • 其余包在不符合 TTL 值时将被 DROP.
    29 条回复    2017-08-09 20:49:52 +08:00
    nfroot
        1
    nfroot  
       2017-01-23 00:10:48 +08:00
    之前看劫持包的 TTL 都不对的时候 就在想这个问题了 只是对这个太不了解…… 自己技能也达不到这个级别……

    点赞
    RobertYang
        2
    RobertYang  
       2017-01-23 00:22:23 +08:00 via Android
    点赞,被电信插广告他们还不认
    lslqtz
        3
    lslqtz  
       2017-01-23 05:00:57 +08:00
    如果旁路设备知道客户端与它的 TTL ,那么旁路设备再检测服务器 TTL 加起来的话。
    est
        4
    est  
       2017-01-23 09:24:27 +08:00
    crazy idea 。。。居然能在 iptables 做这么多事。。。学习了。
    est
        5
    est  
       2017-01-23 09:27:30 +08:00
    结合 ip netns 可以只对浏览器生效。这样可以限制误伤范围。
    TMily
        6
    TMily  
       2017-01-23 10:30:04 +08:00
    额 能不能将特定 WAN 口改为特定防火墙区域呢,多拨的话,都不一定是哪个口拨上的说
    KCheshireCat
        7
    KCheshireCat  
    OP
       2017-01-23 10:46:59 +08:00
    @est

    其实这个规则对某国家级防火墙的 RST 包也有效,只不过它会对服务器和客户端双方都发送,虽然有效但是救不了这条连接.
    KCheshireCat
        8
    KCheshireCat  
    OP
       2017-01-23 10:52:43 +08:00
    @TMily

    额,我不清楚 openwrt 上的防火墙区域是怎么回事,你可以直接填上去试试,不行的话,就用排除法.

    把不是 wan 口的接口排除掉
    est
        9
    est  
       2017-01-23 11:27:03 +08:00
    @KCheshireCat 能不能用 bytecode 实现服务器主动发一条 TTL 到达不了客户端的 ACK,PSH 但是墙能收到。。。然后 seq 号是不是就混乱了呢?
    est
        10
    est  
       2017-01-23 11:28:09 +08:00
    @KCheshireCat 你们二次元头像党又是玩技术的太可怕了。
    aru
        11
    aru  
       2017-01-23 13:45:52 +08:00
    1. 能否限制只对 tcp port 80 起作用(也许能降低 cpu 占用率?)
    2. openwrt 下有没有朋友来搞搞?
    feng32
        12
    feng32  
       2017-01-23 20:04:07 +08:00
    好东西,等晚上回去在 openwrt 上测试一下,依赖的模块是否都现成的看一下
    KCheshireCat
        13
    KCheshireCat  
    OP
       2017-01-23 21:34:00 +08:00
    @est iptables 本职工作是防火墙啊,要发包大概要打补丁实现了吧,这方面我不太懂
    KCheshireCat
        14
    KCheshireCat  
    OP
       2017-01-23 21:36:29 +08:00
    @aru 我用 x86 的 AMD 速龙 x4 老爷机跑满 100M 是一点问题也没有,几乎没有负载,轻轻松.
    路由器的嵌入式平台就不知道了,只对 80 起效是可以做到的,但是上网主要流量也就是 80 的多啊...
    aru
        15
    aru  
       2017-01-23 23:19:20 +08:00
    @KCheshireCat
    p2p 下载基本都是非 80 的,而且流量很大。我的大流量应用就是 PT ,经常达到 200Mbps ,估计加上这个会是一个瓶颈。
    今天尝试在 lede ( openwrt fork )上添加项目的 iptables ,找不到 bpf 模块 :(
    KCheshireCat
        16
    KCheshireCat  
    OP
       2017-01-23 23:29:43 +08:00
    @aru
    你需要针对端口限制的话可以在要填"{your WAN}"的那两行加入端口匹配条件.

    然后一般来说容易缺失的 iptables 模块就是 u32 或者 bpf 了,大多数人只是用 iptables 解决些简单的需求,所以不会用到这种需要写字节码的模块.

    不过可以自己编译 openwrt 固件的时候把这几个模块一起编译进去,再或者你可以看看 openwrt 官方源有没有提供补全 iptables 的包,这样就不用自己编译了.
    aru
        17
    aru  
       2017-01-24 00:03:18 +08:00
    @KCheshireCat u32 我编译和加载了, bpf 实在没找到配置选项,网上找了挺多地方,没发现究竟是哪个配置参数
    JJaicmkmy
        18
    JJaicmkmy  
       2017-01-25 20:57:22 +08:00
    @KCheshireCat 如果是自己的服务器的话,可以在服务器上也 DROP 掉 RST 的包,对 SS 有奇效。
    KCheshireCat
        19
    KCheshireCat  
    OP
       2017-01-25 21:01:28 +08:00
    @JJaicmkmy #18
    这么弄的话好像会触发路由黑洞,以前看别人提过。
    Siril
        20
    Siril  
       2017-02-06 14:34:52 +08:00
    awesome idea , but.....
    看 issue ,疑似有误伤,求解惑。
    不知可否在其他发行版复现这个问题
    KCheshireCat
        21
    KCheshireCat  
    OP
       2017-02-06 15:13:00 +08:00   ❤️ 1
    @Siril #20
    目前来说确实有误伤的,这主要和服务器的防火墙策略有一定关系。我在 issue 上做了解释,并提用了使用更宽松规则的临时解决方案。
    但对于问题本身,我还没有更好的想法来解决。
    Siril
        22
    Siril  
       2017-02-06 15:42:17 +08:00
    @KCheshireCat 但愿能找到改进措施。
    ----------
    下面是脑洞:
    仔细考虑后,即使利用 libnetfilter_queue 做出一个,抛开稳定性、吞吐量不谈,
    我感觉按延迟也不靠谱, ack 的时间受目标服务器负载的影响,不能说明问题;
    主动学习数据包长度、 ttl 值 也难免误伤,
    恐怕还要解析数据包内容
    一般也就是内容有固定特征的 302 redirect 、 meta-refresh 、 javascript 啥的。

    字符串黑名单过滤之。

    思路有了,项目起名叫 WFG 不错。 XD
    KCheshireCat
        23
    KCheshireCat  
    OP
       2017-02-06 16:13:53 +08:00
    @Siril #22
    最早最早的时候我也是用 string 模块过滤字段的,但这么作通用性太差,自己用还不错,写作项目的话以后维护起来会变成又臭又长的规则表,而且对单个用户来说有用的可能就其中的几个。某条规则什么的时候已经失效也没法验证。

    最重要的是运营商改劫持模板方便,我们验证规则,抓包困难。这样十分吃力。
    Siril
        24
    Siril  
       2017-02-06 16:30:23 +08:00
    @KCheshireCat
    前述脑洞是尝试由程序主动学习过滤列表,
    比如说请求许多不同的网站返回相似的结果,
    而非人工维护又臭又长的过滤列表。
    Siril
        25
    Siril  
       2017-02-06 16:38:31 +08:00
    啊不能改自己的回复, 突然想到如果 libnetfilter 可行, 何必玩高级花样。
    既然真正的 response 在假的之后到达,那么假数据包太容易辨认了。
    甚至可否将服务端返回的数据包缓存个多少毫秒超时,如果后续没有就发送这个,后续有“重复”的则 DROP 掉前一个。

    ---------
    可能 proxy server 更适合实现这样的功能。
    akw2312
        26
    akw2312  
       2017-02-19 03:06:25 +08:00
    手邊的四川移動機器 測試有效
    不過... 如果劫持是那種整個 TCP 都劫持走的目測也沒辦法了吧..
    tcp traceroute 一看都被劫持走的那種 (icmp 正常, tcp 非 80 443 8080 也正常)
    Tovcn
        27
    Tovcn  
       2017-07-16 22:51:40 +08:00 via Android
    @Siril 可以写个脚本,让 iptables 把疑似重的包 mark 然后对比包内容,基本一致的就 DROP...
    那有对比包的模块否?
    Tovcn
        28
    Tovcn  
       2017-07-16 22:52:58 +08:00 via Android
    @Siril 可不是写脚本啊。。 。。错了
    siyanmao
        29
    siyanmao  
       2017-08-09 20:49:52 +08:00
    @Siril 我倒是觉得基于延迟判断非常靠谱。延迟最低极限的,而旁路劫持的 RTT 一般很低,通过不断采样 RTT,发现 RTT 急剧减小基本就可以判定是出现劫持了。不过这样要写程序追踪每一个 tcp 流了……
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1190 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 23:11 · PVG 07:11 · LAX 15:11 · JFK 18:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.