透明代理

Table of Contents

环境

光猫------路由器merlin梅林 A--------路由器openwrt B
原来主要通过A拨号上网,B闲置。
为了探索透明代理,防止配置错误影响上网,计划在B上折腾,待条件成熟,考虑迁移到A上。
A的一个LAN口与B的一个LAN口相连,B从A获取IP,或者静态设置IP。 暂时关闭B的WAN拨号功能,并开启WIFI功能。这样可以连接WIFIA或者WIFEB。

B上若实现了透明代理功能(DNS功能和代理功能),这样客户端机器通过自动DHCP获取(连接WIFIB)或者手动设置route/gateway IP 为BIP,同时设置DNS为 BIP,就可以透明上网了。原有连接WIFIA的客户端还可以继续使用WIFIA的方式,保证了平滑过渡。

计划

基本原型

参考透明代理TPROXY

优化

考虑性能、DNS分流方案、Dot、IPv6、Nftable

实践

基本原型

B环境准备

B必须能上网才能做透明代理。

  • BLAN1 与ALAN1相连
  • 在/etc/config/network配置lan interface 为多IP模式。gateway ip是AIP。
list ipaddr '192.168.1.16/24'
list ipaddr '192.168.2.10/24'
option gateway '192.168.1.1'
  • 在/etc/config/network中 disable WAN,不要用DHCP,不然会从A中获取,污染B的路由设置。
  • 配置dnsmasq,添加dns服务器
uci add_list dhcp.@dnsmasq[0].server="192.168.1.1"
uci commit dhcp
service dnsmasq restart

当然可以web或者直接修改配置文件/etc/config/dhcp的方式来完成. 以上两操作保证在B上可以ping通 www.baidu.com.

  • cat /proc/sys/net/ipv4/ip_forward = 1
  • 手动配置某个客户端,将默认网关指向BIP即 192.168.1.16。此时 应当能正常上网。

v客户端安装和配置

  • v版本选择下载,首先判断cpu型号和大端字节序或者小端字节序
root@LEDE:~# cat /proc/cpuinfo
system type     : Broadcom BCM4716
machine         : Asus RT-N16
processor       : 0
cpu model       : MIPS 74Kc V4.0
BogoMIPS        : 239.61
wait instruction    : yes
microsecond timers  : yes
tlb_entries     : 64
extra interrupt vector  : yes
hardware watchpoint : yes, count: 4, address/irw mask: [0x0ffc, 0x0ffc, 0x0ffb, 0x0ffb]
isa         : mips1 mips2 mips32r1 mips32r2
ASEs implemented    : mips16 dsp dsp2
Options implemented : tlb 4kex 4k_cache prefetch mcheck ejtag llsc dc_aliases vint perf_cntr_intr_bit nan_legacy nan_2008 perf
shadow register sets    : 1
kscratch registers  : 0
package         : 0
core            : 0
VCED exceptions     : not available
VCEI exceptions     : not available
root@LEDE:~# hexdump -s 5 -n 1 -C /bin/busybox
00000005  01                                                |.|
00000006
root@LEDE:~# echo -n I | hexdump -o | awk '{ print substr($2,6,1); exit}'
1 //1 mean 小端字节序
  • v 安装
    v解压后60MB,但看B的空间,通过删除v解压后的重复文件可以放到/tmp下,有采用自行编译并用upx来压缩的方式,为了快速达到目标,这次用了usb盘
root@LEDE:~# df -h
Filesystem                Size      Used Available Use% Mounted on
/dev/root                 2.5M      2.5M         0 100% /rom
tmpfs                    61.1M      1.1M     60.0M   2% /tmp
/dev/mtdblock5           27.8M    996.0K     26.8M   4% /overlay
overlayfs:/overlay       27.8M    996.0K     26.8M   4% /
tmpfs                   512.0K         0    512.0K   0% /dev

opkg update && opkg install block-mount e2fsprogs kmod-fs-ext4 kmod-usb-storage kmod-usb2 kmod-usb3
block detect | uci import fstab
uci set fstab.@mount[0].enabled='1' && uci set fstab.@global[0].anon_mount='1' && uci commit
/sbin/block mount && service fstab enable
#copy to B 
scp ~/Downloads/v-linux-mipsle.zip [email protected]:/mnt/sdav/v
  • run v
  root@LEDE:~# opkg install curl
  # config from system proxy or 参考透明代理tproxy的v客户端配置 
  root@LEDE:/mnt/sda/v# ./v -c config.jsonsystemproxy  
  root@LEDE:~# curl -so /dev/null -w "%{http_code}" xxxx.com -x socks5://127.0.0.1:1080
  # 确保301/200就行。 
  • config v for tproxy
  root@LEDE:/mnt/sda/v# opkg install iptables-mod-tproxy ipset
  # maybe we will use ipset later
 
  root@OpenWrt:/mnt/sda/v# cat mytest3.sh
  #!/bin/sh
  
  ip rule add fwmark 1 table 100 # add ip rule ,once a packet match the fwmark = 1,then lookup the route table 100.
  ip route add local 0.0.0.0/0 dev lo src 127.0.0.1 table 100 # add local type's route entry to route table  100
  
  iptables -t mangle -N ONLYONE
  iptables -t mangle -A ONLYONE -j MARK --set-mark 1
  iptables -t mangle -A ONLYONE -j ACCEPT
  iptables -t mangle -A PREROUTING -m socket -j ONLYONE // prevent packet which have existing connectin to enter into tproxy twice
  
  iptables -t mangle -N V
  iptables -t mangle -A V -d 127.0.0.1/32 -j RETURN
  iptables -t mangle -A V -d 224.0.0.0/4 -j RETURN
  iptables -t mangle -A V -d 255.255.255.255/32 -j RETURN
  iptables -t mangle -A V -d 192.168.0.0/16 -p tcp -j RETURN
  iptables -t mangle -A V -d 192.168.0.0/16 -p udp ! --dport 53 -j RETURN # let port 53 udp packet enter into the v app
  iptables -t mangle -A V -p udp -j TPROXY --on-port 13345 --on-ip 127.0.0.1 --tproxy-mark 0x1/0x1 # use tproxy to forward the packet to local port 13345,meantime mark 1
  iptables -t mangle -A V -p tcp -j TPROXY --on-port 13345 --on-ip 127.0.0.1 --tproxy-mark 0x1/0x1
  iptables -t mangle -A PREROUTING -j V // let other new  packet  processing by the v chain
  
  iptables -t mangle -N V_MASK
  iptables -t mangle -A V_MASK -d 224.0.0.0/4 -j RETURN
  iptables -t mangle -A V_MASK -d 255.255.255.255/32 -j RETURN
  iptables -t mangle -A V_MASK -d 192.168.0.0/16 -p tcp -j RETURN
  iptables -t mangle -A V_MASK -d 192.168.0.0/16 -p udp ! --dport 53 -j RETURN
  iptables -t mangle -A V_MASK -j RETURN -m mark --mark 0xff # let packet which have mark 255 to direct connection
  iptables -t mangle -A V_MASK -p udp -j MARK --set-mark 1
  iptables -t mangle -A V_MASK -p tcp -j MARK --set-mark 1
  iptables -t mangle -A OUTPUT -j V_MASK

用执行脚本的方式来验证。待验证成功后,可以放到/etc/firewall.user持久化。v 客户端的配置暂时就是参考链接里的配置。

  • 参考网上配置把v做成服务的方式,系统启动后自动启动。

注意事项

  • B openwrt failsafe mode
    一开始最好调研好怎么进入这个failsafe模式。同时执行时尽量避免把路由器变砖了。
    本人使用iptable,把规则放到了/etc/firewall.user中,然后再也没法访问了,最后只能进入华硕的恢复模式重刷openwrt固件。折腾了半天也没进入openwrt的failsafe mode。

优化

DNS over tls

DoH虽然因为浏览器的普及很容易实现和普及,但据说有泄露agent的可能。综合多种原因,最终选择了Dot。

在A路由器merlin上配置Dot

参考DNS privacy
在android和pc 上设置dns ip 为AIP 192.168.1.1.
打开网页测试https://www.cloudflare.com/ssl/encrypted-sni/
这里的设置分为路由(网关)和DNS单独的设置。
所以虽然B透明代理当前也劫持53的DNS流量,但是我们仍然可以用A作为DNS服务器,只是需要手动设置而已。

Dot+ESNI

ESNI属于web服务器的客户端范畴的概念,是TLSv1.3的一个扩展功能,加密我们要访问的服务器名字。

  1. 支持情况:

  2. 测试验证:

    • firefox
      整体结果不理想。
      Mac采用Dot DNS,即设置DNS IP为路由器AIP 192.168.1.1(路由器DNS禁用了doh)。在about:config里设置network.trr.mode 0/2/3/5多种情况下,偶尔发现启用了ESNI。但大多数情况下都失败着。
      采用wireshark抓包、cloudflare checkcloudflare trace api多种验证方法。
      结果不乐观的原因:1, 启用ESNI必须启用Doh,即Doh是依赖。 参见bug. 2, 其他干扰因素比如权威DNS服务器与TLS服务器不同步的话会出现这个问题。
      总之并不能愉快的启用ESNI,特别是在开启Dot的情况下。暂时放弃。

Dot over V

性能

DNS分流方案

IPv6

IPv6 Nftable

一些概念和疑惑

  • router
    Any machine which will accept and forward packets between two networks is a router.Every router is at least dual-homed; one interface connects to one network, and a second interface connects to another network.
  • route -n == netstat -rn
  • ip rule
root@OpenWrt:/mnt/sda/v# ip rule
0:  from all lookup local
32765:  from all fwmark 0x1 lookup 100
32766:  from all lookup main
32767:  from all lookup default

ip rule可以查看有那些路由规则,32765表示优先级, 系统一般默认有路由表main,local,和default。 这里lookup 前的是规则选择的方式,lookup是动作,表示一旦一个packet满足规则,就会lookup某个路由表。 路由表可以有名字或者叫table 100这样的。

  • The route selection algorithm under linux
    分为基于目的地址的路由和基于路由策略的路由。
    高级路由也叫策略路由。
    首先在路由策略数据库rpdb中根据优先级进行迭代遍历,利用longest prefix match selection algorithm 试图找到对应的路由,若找到,就会转发那个包,否则进入下一个规则。
    main路由表里一般包含默认路由,即所有其他IP走这个路由。
  • When do reroute check?
    grep "Reroute for ANY change" net/ipv4/netfilter/iptable_mangle.c.
    Basically "any" means saddr,daddr mark and tos, the four routing-influencing parameters.
    在上面配置output链规则的时候,一旦有这几项改变,会导致包的重路由,不再是原来的正常的路径。
    当然reroute check的执行不一定只在output链这里。
  • 为什么在路由策略里那里添加src 127.0.0.1
    ip route add local 0.0.0.0/0 dev lo src 127.0.0.1 table 100 #
    Make it explicit that the source IP used for this network when connecting locally should be in 127.0.0.0/8 range. This is needed since otherwise the TPROXY rule would match both forward and backward traffic. We want it to catch forward traffic only.
    ref cloudflare blog
    还没明白,但是正常使用来着现在。
  • 为什么要添加match那条规则
    tproxy 中有说明。
    主要是防止已经有连接的包不管TCP还是UDP,不必要再次进入tproxy,只是标记为1,让策略路由把此包根据mark=1的规则来路由。
    估计有性能提升,有兴趣的可以测试下。
  • How does dnsmasq interaction with dot?
  • openwrt fw3 and nftable cheatsheet
  • why fail use this?
    期间遇到的问题,还好解决了,但现在不清楚为啥?
    为了引入match那个规则,采用如下方式
    步骤二执行后,dns不可用,但外网ip可以ping 通。执行步骤三但最后一个规则忽略。然后执行那个规则,会导致服务器无法连接。
    是不是iptable rule执行顺序的问题
# 操作要点: 
主要添加了ONLYONE链,作用是防止同属于一个连接的其后的包进入tproxy两次。
还有在步骤三中,添加了iptables -t mangle -A BYPAS_MASK -d 127.0.0.1/32 -j RETURN
原来参考中,是没有这一句的,原来步骤二三中的直连,不同的就是这一句。
v client 配置用就是那个官方tproxy教程的配置,inbounds没有开放53端口,操作系统有自己的dns应用。 

# 步骤
## 一 策略路由
ip rule add fwmark 1 table 100
ip route add local 0.0.0.0/0 dev lo table 100

## 二 外面发过来的的包到透明网关

iptables -t mangle -N BYPASS
iptables -t mangle -A BYPASS -d 127.0.0.1/32 -j RETURN
iptables -t mangle -A BYPASS -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A BYPASS -d 255.255.255.255/32 -j RETURN

iptables -t mangle -A BYPASS -d 192.168.0.0/16 -p tcp -j RETURN
iptables -t mangle -A BYPASS -d 192.168.0.0/16 -p udp ! --dport 53 -j RETURN


iptables -t mangle -N ONLYONE
iptables -t mangle -A ONLYONE -j MARK --set-mark 1
iptables -t mangle -A ONLYONE -j ACCEPT

iptables -t mangle -N V
iptables -t mangle -A V -p udp -j TPROXY --on-port 12345 --tproxy-mark 1
//用tproxy转发到127.0.0.1 13345,即让v来处理
iptables -t mangle -A V -p tcp -j TPROXY --on-port 13345 --tproxy-mark 1


iptables -t mangle -A PREROUTING -j BYPASS  //BYPASS掉一些私有/内网地址

**iptables -t mangle -A PREROUTING -m socket -j ONLYONE**
// 添加ONLYONE链到mangle表的prerouting链里,即应用ONLY链的规则。 防止同属于一个连接的其后的包进入tproxy两次,
// 这里让它直接进入ONLYONE链里处理,即直接路由到loop,不再经过tproxy,即不会执行下面这个rule了

iptables -t mangle -A PREROUTING -j V 
// 添加V链到mangle表的prerouting链里,即应用规则,即给 UDP/TCP 打标记 1,用tproxy转发至v app 的 13345 端口并开始路由决策


## 三 透明网关自身生成的包: v生成的包要发出去,或者还有自身生成的其他包

iptables -t mangle -N BYPASS_MASK
**iptables -t mangle -A BYPAS_MASK -d 127.0.0.1/32 -j RETURN**
iptables -t mangle -A BYPASS_MASK -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A BYPASS_MASK -d 255.255.255.255/32 -j RETURN

iptables -t mangle -A BYPASS_MASK -d 192.168.0.0/16 -p tcp -j RETURN
iptables -t mangle -A BYPASS_MASK -d 192.168.0.0/16 -p udp ! --dport 53 -j RETURN

iptables -t mangle -N V_MASK
iptables -t mangle -A V_MASK -j RETURN -m mark --mark 0xff //v生成的带mark的包让其直接发出
iptables -t mangle -A V_MASK -p udp -j MARK --set-mark 1 // 这可能是哪个app的流量? 要重新路由到loop
iptables -t mangle -A V_MASK -p tcp -j MARK --set-mark 1 // 这是系统dns的s的流量?要重新路由到loop

iptables -t mangle -A OUTPUT -j BYPASS_MASK //应用bypass规则
**iptables -t mangle -A OUTPUT -j V_MASK** 
Webmentions

Loading...

When you post a tweet with a link to this post it will automatically show up here! (refreshed every 30 minutes) 💯

A small favor

Was anything I wrote confusing, outdated, or incorrect? Please let me know! Just write a few words below and I'll be sure to amend this post with your suggestions.

Follow along

If you want to know about new posts, add your email below. Alternatively, you can subscribe with RSS.

More from 格物治用

实践、探索、思考.

View all posts