本文用中文写,主要是因为中文更适合本文的内容。

Shadowsocks透明代理

差不多用了5年ss透明代理,最近换成了v2ray。ss透明代理的好处是配置方便、生态成熟、对硬件要求不高。

只要不是太老的路由器,可刷OpenWRT就基本可以用ss透明代理,就连很多年前的TP link 703N也有不少玩家魔改内存上OpenWRT。

因为一段时间前,ss官方推荐换v2ray混淆插件而不是simple obfs了,后来我试了一次,在路由器上运行非常缓慢,而且我的路由器还不错,Linksys 1900ac v2,就放弃了。最近又想折腾一下,于是用电脑上的v2ray试了下,飞一般的速度,同时用ss并不会达到这样的速度,于是开始着手准备v2ray透明代理搭建。

V2Ray透明代理

如果v2ray没法用透明代理我可能也还会将就ss。因为目前的路由器没法直接运行v2ray,空间和性能都跟不上了,考虑软路由,我的youtube首页总有几个视频是软路由选购、测评。最终没有买,用NAS开了台虚拟机安装v2ray,作为旁路由接入。其实用软路由多半也是用旁路由的模式。另外还考虑了买下一代Linksys产品,再刷openWRT安装v2ray,本着艰苦创业的精神,放弃了。

这个拓扑结构太简单,随便看看就好。旁路由也类似一台设备接入到主路由中,只不过有一部分特别的职责,它可以处理其他设备发来的请求,处理完后还会发回对应设备,作用与主路由的部分功能类似。

一般家庭网络中只有一个网关,作用是连接内部与外部网络,网络内部设备需要访问互联网时,例如要访问百度,则需要通过网关与外界沟通,在百度看来,一直与网关沟通,而不知道网络中的那一台设备在和自己通信,百度也并不关心。

所以最简单的配置就是把旁路由配置成网关,这样网络内其他设备需要访问外网时就会与这台旁路由联系,而旁路由本身并不能直接访问外网,它需要继续与上级设备沟通,而上级设备就是主路由了。

因为还在实验,不想让所有设备都走旁路由,而且需要出国的设备也不多,没必要都接入到旁路由。于是采用了更复杂的路由配置——源地址路由。

source route

在主路由上添加了一个路由表,修改/etc/iproute2/rb_tables

10	v2ray

添加默认网关

ip route add default via 192.168.1.32 table 10

给路由表10添加默认网关,没有其他规则,这样进入该路由表的流量就都转入到了192.168.1.32了,这是旁路由的IP

再添加一条规则

ip rule add from 192.168.1.240/32 table 10

意思是来自192.168.1.240的流量走路由表10,而进入了路由表10就会继续进入到旁路由

不过这样添加很麻烦,每次需要让某个设备出国的话需要在主路由上添加ip rule,后面针对这个做了优化。

透明代理配置

v2ray配置主要包含inbound, outbound, dns, routing

inbound

{
      "tag": "transparent",
      "port": 12345,
      "protocol": "dokodemo-door",
      "settings": {
        "network": "tcp,udp",
        "followRedirect": true
      },
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls"
        ]
      },
      "streamSettings": {
        "sockopt": {
          "tproxy": "tproxy"
        }
      }
    }

协议dokodemo-door,监听12345端口,使用tproxy方式完成透明代理。

本想省略followRedirect,文档描述这个参数设置成true才可以处理iptablesredirect,但我用的是tproxy,理论讲可以省略,然而省略了就不行。

network配置tcp,udp表示接受这两种协议的流量。

tproxy可用tproxy或者redirect,两种透明代理的方法,推荐tproxy,可以代理IPv4/6流量、UDP流量;redirect只能IPv4和UDP。代理UDP流量的目的是让DNS解析也能走代理,因为某些网站的DNS解析也会被恶意篡改,即便你的代理再好再快,如果不能得到正确IP地址的话,一样无法正常访问网站。

sniffing配置,可以从流量中解析出域名和协议,尝试解析,并不是所有流量都能得到域名和协议。猜测:如果解析出来了,并且与配置的destOverride匹配的话,那么就会修改这些流量的outbound target,因为在没有解析的时候只能得到IP,用来匹配outbound,但如果有了域名、协议,就可以做更精确的路由,比如解析出了bt协议,可以选择禁止bt还是其他怎样。

outbound

没啥特别,第一个是proxy的配置

{
      "tag": "proxy",
      "protocol": "vmess",
      "settings": {
        "vnext": [
          {
            "address": "your proxy address",
            "port": your proxy port,
            "users": [
              {
                "id": "your id",
                "alterId": your alert id
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "tcp",
        "security": "tls",
        "sockopt": {
          "mark": 255
        }
      },
      "mux": {
        "enabled": false
      }
    }

streamSettings根据需要填写networkingsecurity,但需要注意sockopt设置mark是透明代理需要。

mux配置默认关闭就好,文档没看清楚,以为开着看视频啥的更好,结果并不是,是更差。开着的话看youtube视频能到10W,关闭后能到20W。。。同一时间同一个server。

另外几个outbound

{
      "tag": "direct",
      "protocol": "freedom",
      "settings": {
        "domainStrategy": "UseIP"
      },
      "streamSettings": {
        "sockopt": {
          "mark": 255
        }
      }
    },
    {
      "tag": "block",
      "protocol": "blackhole",
      "settings": {
        "response": {
          "type": "http"
        }
      }
    },
    {
      "tag": "dns-out",
      "protocol": "dns",
      "streamSettings": {
        "sockopt": {
          "mark": 255
        }
      }
    }

directdns-out没啥特别,要mark

DNS

v2ray内建的dns配置

{
    "servers": [
      "8.8.8.8",
      "1.1.1.1",
      {
        "address": "114.114.114.114",
        "port": 53,
        "domains": [
          "geosite:cn",
          "domain:ntp.org",
          "domain:zoom.us",
          "domain:slack.com",
          "domain:slack-core.com"
        ]
      },
      "223.5.5.5"
    ]
  }

国内域名、ntp、其他需要用国内DNS解析的可以继续添加。其他域名就从8.8.8.8开始解析了。

routing

这是最复杂的一部分,几乎能和上面各个部分联系起来。

{
    "domainStrategy": "IPIfNonMatch",
    "rules": [
      { "type": "field", "inboundTag": [ "transparent" ], "port": 53, "network": "udp", "outboundTag": "dns-out" },
      { "type": "field", "inboundTag": [ "transparent" ], "port": 123, "network": "udp", "outboundTag": "direct" },
      { "type": "field", "ip": [ "223.5.5.5", "114.114.114.114" ], "outboundTag": "direct" },
      { "type": "field", "ip": [ "8.8.8.8", "1.1.1.1" ], "outboundTag": "proxy" },
      { "type": "field", "ip": [ "geoip:private", "geoip:cn" ], "outboundTag": "direct" }, 
      { "type": "field", "domain": [ "vali.cp31.ott.cibntv.net" ], "outboundTag": "direct" },
      { "type": "field", "domain": [ "geosite:category-ads-all" ], "outboundTag": "block" },
      { "type": "field", "domain": [ "geosite:cn" ], "outboundTag": "direct" }
    ]
}

Routing控制流入v2ray的流量该如何流出,主要目的就是让该走代理的流量走代理,不该走的不走。

目前的规则:

  • 进入的udp流量,端口是53的,走dns-outdns-out就是mark一下
  • 进入的udp流量,端口是123的,走direct,直连
  • 114DNS和aliDNS走direct
  • GoogleDNS和CloudflareDNS走proxy
  • 内网地址IP、国内IP走direct
  • vali.cp31.ott.cibntv.net这个域名是youku播放视频前需要访问的,默认被放在了广告域名中,会被下一条规则block,但在使用投影仪投屏时,如果访问不到这个域名,视频播放就有问题,于是放行了
  • geosite:category-ads-all表示所有的广告域名,会被block
  • 最后,国内网站域名,直连
  • 匹配不到的,走outbound第一个,即proxy

domainStrategy可选值:"AsIs" | "IPIfNonMatch" | "IPOnDemand”。

这三个可选值,不管选哪一个,要求都是能解析出域名,解析不出的话,我猜测还是用IP匹配。

默认AsIs,只用域名选择路由。猜测意思是能解析出域名的,会用域名在rules中匹配规则;没有域名的,用IP匹配。

进一步,IPIfNonMatch,如果有一个域名匹配不了,那么会解析域名,解析出来的IPs,会再次匹配。

最后,IPOnDemand,如果rules中有IP相关的规则,就会把域名解析成IP再匹配规则。

Zoom优化

我观测到的Zoom用了UDP通信,特定端口范围,虽然进入了v2ray也是用直连规则,因为dest ip是国内,所以会选direct,然而udp过了v2ray依然断流,作者优化过一次断流问题,我编译后测试并没有解决,而且更严重。。。作者说先放一放,等有一个udp加速功能合并进来再测试一下。

目前做法是让这些udp流量不要进入v2ray:

sudo iptables -t mangle -A V2RAY -p udp -m multiport --dport 3478,3479,8801:8810 -j RETURN

Slack call优化方法类似