China IP 是指分配给中国的所有 IP 段(通常指 IPV4)。由于中国网络的特殊性,很多应用场景都需要中国 IP 段。
获取中国 IP 段列表
有以下几种方法
从 ipdeny 获取
分配给中国的所有 IPV4 段最新数据可以从 ipdeny 获取:
cn-aggregated.zone (聚合版数据,数量更少,匹配快。推荐)
cn.zone
获取的文件内容格式:
1.0.1.0/24
1.0.2.0/23
1.0.8.0/21
...
这个方式的问题是获取的只是“归属地”为中国的IP,而不是真正地理位置是中国的IP。用来判断是否走代理会有误差。
从 APNIC 获取
APNIC (亚太互联网络信息中心) 公开提供所有亚洲国家的 IPV4 分配信息,可以从以下地址获取:
http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest
获取的文件格式如下,文件里有每行有几个字段,以 "|" 作为分隔符。文件格式说明
# comments
apnic|JP|asn|3391|1|20020801|allocated
apnic|AU|asn|3395|1|20020801|allocated
apnic|CN|asn|3460|1|20020801|allocated
...
需要解析处理该文件才能得到中国 IP 信息。chnroutes 项目提供一个 python 脚本能够自动从 APNIC 获取该文件、解析,然后直接写入系统路由表。
订阅第三方维护的中国IP源
Github 上有很多中国IP源,数据来源不一。
- chn-iplist : 数据来源于 APNIC Delegated List
策略路由
通过 Linux 策略路由实现直连中国 IP,通常用于全局 VPN / 代理环境。具体也有两种方法。
- 使用 ipset + iptables
- 使用 ip route
ipset + iptables 策略路由直连中国 IP
将所有中国 IP 段 存入一个 ipset,并对 dst IP 属于这个 ipset 里的所有流量写入 mark bit 0 = 1,然后做策略路由,使这些流量走系统默认路由(主路由表)
设备启动脚本:
#!/bin/sh
cd /root
# wget -P . http://www.ipdeny.com/ipblocks/data/countries/cn.zone
ipset create cn hash:net
for i in $(cat ./cn.zone ); do ipset -A cn $i; done
iptables -t mangle -I PREROUTING -m set --match-set cn dst -j MARK --set-mark 0x1/0x1
iptables -t mangle -I OUTPUT -m set --match-set cn dst -j MARK --set-mark 0x1/0x1
ip rule add fwmark 0x1/0x1 lookup main prio 1
与使用 "ip route 添加路由表"方式 相比,这种方法优点:
- 只需要在设备启动时执行一次脚本即可。而 ip route 方式需要在每次宽带拨号连接 (PPPoE)后都执行一次脚本(因为每次宽带重新连接后默认网关都会改变)。
缺点:
- ipset (好像)无法批量添加,执行一次添加全部中国 IP 段(几千条记录)操作需要近1分钟时间。而 ip route batch 批量添加路由仅需1秒。
- 用 ip route get 114.114.114.114 查询国内IP无法获取到正确(实际使用的)路由。因为 ip route get 原理只是 "模拟"发包,并没有经过 netfilter 协议栈。
ip route 添加中国 IP 直连路由表
可以参考 chnroutes 提供的 python 脚本。建议将所有中国 IP 单独放在一个路由表里,然后用 ip rule 添加使用这个独立路由表规则(将其优先级设置为高于其他自定义的 VPN 路由表),例如:
设备启动脚本:
ip rule add lookup 4 prio 4
宽带 PPPoE 拨号成功脚本:(因为每次宽带重新连接后默认网关会发生变化,所以必须重新添加中国 IP 路由表)
#!/bin/sh
# 获取设备当前默认网关
GW=$(ip route show 0/0 | head -n1 | grep 'via' | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+')
ip -batch - <<EOF
route add 1.0.1.0/24 via $GW table 4
route add 1.0.2.0/23 via $GW table 4
# more ...
EOF
iptables 中国IP跳过透明代理
如果在 iptables -t nat 的 PREROUTING / OUTPUT 链上用 redsocks / clash / ss-redir 等做了透明代理,可以设置跳过中国 IP:
iptables -t mangle -I PREROUTING -m set --match-set cn dst -j ACCEPT
iptables -t nat -I prerouting_wan_rule -m set --match-set cn dst -j ACCEPT
iptables -t nat -I prerouting_lan_rule -m set --match-set cn dst -j ACCEPT
说明:
- 加在 -t mangle -I PREROUTING 的规则是为了跳过某些代理工具的 TPROXY udp 透明代理。
- prerouting_wan_rule 和 prerouting_lan_rule 是 OpenWrt firewall创建和维护的子链。(子链里必须用 ACCEPT 不能用 RETURN, 因为 RETURN 仅仅停止遍历子链,还会继续遍历父链)
应用场景
配合全局 VPN 使用
设备启动脚本
假设 VPN 启动时把默认路由加到 table 10 的路由表里
# 通用 VPN iptables 规则
iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
iptables -t nat -A POSTROUTING -o tun+ -s 192.168.0.0/16 -j MASQUERADE
iptables -t nat -A POSTROUTING -o tun+ -s 10.0.0.0/8 -j MASQUERADE
# 以下需要 iptables-mod-conntrack-extra 和 kmod-ipt-conntrack-extra
# 使对数据包打的mark对于同一连接的其他数据包(回程或相关的)也生效
iptables -I PREROUTING -t mangle -j CONNMARK --restore-mark
iptables -I POSTROUTING -t mangle -j CONNMARK --save-mark
ip rule add to 192.168.0.0/16 lookup main prio 1
ip rule add to 127.0.0.1/8 lookup main prio 1
ip rule add to 10.0.0.1/8 lookup main prio 1
# VPN server IP
ip rule add to 1.2.3.4/32 lookup main prio 1
ip rule add lookup 10 prio 10
# now sart vpn
# /root/startvpn.sh
VPN 启动成功脚本
ip route add default via 192.168.10.1 table 10
# ip route add default dev tun0 table 10
Tips
- 不要忘了设置 "net.ipv4.ip_forward=1" 内核参数。(路由器之类的设备应该默认开启了这个参数)