Xray-docs-next/docs/document/level-1/routing-lv1-part2.md
2021-03-25 22:33:41 +08:00

17 KiB
Raw Blame History

路由 (routing) 功能简析(下)

欢迎继续学习 Xray 的【路由】功能!

《路由 (routing) 功能简析(上)》 中,我们已经对【路由】功能的工作逻辑有了清晰的理解,也基于 geosite.dat 文件做了简单的域名分流配置。

如前面所说,域名分流仅仅是【路由】功能的牛刀小试而已。下面就让我们来看看除了域名之外,还什么可以用做分流依据的东西吧!

5. 攻城略池 - 多种路由匹配条件

[域名], [IP], [协议], etc.

基于域名的分流,已经可以让我们对网络流量进行基本合理的分流。为什么说【基本合理】呢?

因为【三分天下】虽然是正确的战略方向,但如果只用【域名】来实现这个战略,其实漏洞百出,比如:

  1. 我读了《小小白白话文》后给VPS新申请了一个 proxy.yourdomain.com 的域名, 我希望它无论如何都代理,geosite.dat 里面有吗?
  2. 如果我还有个 direct.yourdomain.com 的域名,我希望它无论如何都直连, geosite.dat 里面有吗?
  3. 本机 127.0.0.1 的内部流量,是否正确直连了?(比如 docker 等)
  4. 路由器、本地局域网 192.168.*.* 的流量,是否正确直连了?(比如路由器、群晖等)
  5. 我的国内DNS查询223.5.5.5)是否正确直连了?
  6. 我的国外DNS查询1.1.1.1)是否正确代理了?
  7. 其他类似国内公共DNS一样没有域名、只有IP地址的国内网站是否正确直连了
  8. 其他类似国外公共DNS一样没有域名、只有IP地址的国外网站是否正确代理了
  9. BT下载的流量虽然来源是国外但如果通过VPS下载很可能导致违规使用被封这该如何强制直连
  10. ......

我之所以说只用【域名分流】会漏洞百出,是因为 geosite.dat 文件内只包含了一部分常用的域名。换言之,仅仅依赖它,则会:

  • 无法匹配文件里没有的新域名
  • 无法匹配基于IP地址的规则
  • 无法匹配基于网络协议的规则

::: warning 啰嗦君 那我们来复习一下,当上面这些情况无法匹配时,会发生什么?对了,会触发隐藏路由规则,即【转发给第一个出站 】。这其实就是说:

  • 当你的第一个出站是 [direct-out] 时:需要直连的都正确了,但需要代理的则都错误
  • 当你的第一个出站是 [proxy-out-vless] 时:需要代理的都正确了,但需要直连的则都错误 :::

所以,我们需要一个办法,让我们鱼与熊掌兼得。这样的办法是否存在呢?当然存在! 我们需要的只是【域名】之外更多的【分流判断依据】而已。

5.1 基于指定域名分流:[domain], [full]

  1. 如果需要匹配某个子域名,如 a-name.yourdomain.com,我们使用 full: "a-name.yourdomain.com"
  2. 前面的 问题1问题2,就可以通过给 proxy.yourdomain.com 指定 [proxy-out-vless] 出站,给 direct.yourdomain.com 指定 [direct-out] 出站来解决
  3. 如果需要匹配 yourdomain.com 的所有子域名,我们使用 domain: "yourdomain.com" 实现
  4. 上述两个可以成为两个独立的路由规则,达到某些子域名直连,其他子域名代理的配置
  5. 另外,[domain] 还支持正则表达式等匹配方式。详情请参考 《基础配置模块 - 路由》文档

上述配置如下:

"routing": {
    "domainStrategy": "AsIs",
    "rules": [
        // 指定子域名直连
        {
            "type": "field",
            "domain": [
                "full:direct.yourdomain.com"
            ],
            "outboundTag": "direct-out"
        },
        // 指定子域名转发VPS
        {
            "type": "field",
            "domain": [
                "full:proxy.yourdomain.com"
            ],
            "outboundTag": "proxy-out-vless"
        },
        // 指定泛域名转发VPS
        {
            "type": "field",
            "domain": [
                "yourdomain.com"
            ],
            "outboundTag": "proxy-out-vless"
        }
    ]
}

5.2 基于IP文件分流geoip.dat

geosite.dat 规则文件十分类似的,我们还有 geoip.dat 这个规则文件它致力于为用户提供成熟完善的【IP分类表】。让用户可以简单的通过 geoip:xxx 这种格式方便的调用任何子类,定制符合自身需求的路由规则 。

  1. 解决前面的 [问题3], [问题4],我们使用 geoip:private 类别来指定 [direct-out]
  2. 解决前面的 [问题7],我们使用 geoip:cn 类别来指定 [direct-out]
  3. 解决前面的 [问题8],由于 geoip 中没有【非中国IP】这个分类因为这等于要收集全世界的IP段所以我们用隐藏规则代替也就是将 [proxy-out-vless] 放在第一个出站

上述配置如下:

"routing": {
    "domainStrategy": "AsIs",
    "rules": [
        // 本机内部地址、局域网地址直连
        {
            "type": "field",
            "ip": [
                "geoip:private"
            ],
            "outboundTag": "direct-out"
        },
        // 国内IP集直连
        {
            "type": "field",
            "ip": [
                "geoip:cn"
            ],
            "outboundTag": "direct-out"
        }
    ]
}

5.3 基于指定IP地址分流

geosite.dat 规则文件十分类似的,我们还有 geoip.dat 这个规则文件,它是供【路由功能】驱使的第二个神兵利器它致力于为用户提供成熟完善的【IP分类表】。让用户可以简单的通过 geoip:xxx 这种格式方便的调用任何子类,定制符合自身需求的路由规则 。

  1. 解决前面的 [问题5],我们使用 ip: "223.5.5.5" 来指定 [direct-out]
  2. 解决前面的 [问题6],我们使用 ip: "1.1.1.1" 来指定 [proxy-out-vless]

上述配置如下:

"routing": {
    "domainStrategy": "AsIs",
    "rules": [
        // 指定IP地址直连
        {
            "type": "field",
            "ip": [
                "223.5.5.5"
            ],
            "outboundTag": "direct-out"
        },
        // 指定IP地址转发VPS
        {
            "type": "field",
            "ip": [
                "1.1.1.1"
            ],
            "outboundTag": "proxy-out-vless"
        }
    ]
}

5.4 基于协议类型分流:[protocol]

  1. 解决前面的 [问题9],我们使用 "protocol": ["bittorrent"] 类别来指定 [direct-out]

::: tip 你需要打开入站代理中的 sniffing 才能使用此种方式分流。 :::

"routing": {
    "domainStrategy": "AsIs",
    "rules": [
        // 指定 BT 协议直连
        {
            "type": "field",
            "protocol": [
                "bittorrent"
            ],
            "outboundTag": "direct-out"
        }
    ]
}

5.5 基于更多条件的分流

到目前位置,我们仍然只讲了【路由功能】分流能力的冰山一角!因为它还支持很多其他的判断条件!我在此简单罗列如下:

本文已经讲过的:

  • inboundTag
  • domain
  • ip
  • protocol

本文尚未讲到的:

  • port
  • sourcePort
  • network
  • source
  • user
  • attrs

但这些内容实在是过多,全部展开就远远不是 level-1 的内容了,所以,需要这些复杂条件的朋友,请仔细阅读 《基础配置模块 - 路由》文档 自学哦!有问题就去 TG 群里面问问吧!

6. “霸业初定”:路由规则整体回顾

到现在为止,我们已经累积出了一套战略雄伟、战术精准的路由规则,为了避免混乱,现在就对它进行一次完整的整理和回顾。

::: warning 注意 路由生效的顺序是:【从上往下,依次判断】,所以我一般推荐的规则顺序是:

[1-block] --> [2-direct] --> [3-proxy] --> [4-first-outbound] :::

"routing": {
    "domainStrategy": "AsIs",
    "rules": [
        // [1-block 广告流量屏蔽]
        // 1.1  广告域名集屏蔽
        {
            "type": "field",
            "domain": [
                "geosite:category-ads-all"
            ],
            "outboundTag": "block"
        },
        // [2-direct 国内流量直连]
        // 2.1 国内域名集、指定子域名直连
        {
            "type": "field",
            "domain": [
                "geosite:cn",
                "full:direct.yourdomain.com"
            ],
            "outboundTag": "direct-out"
        },
        // 2.2 本机内部地址+局域网、国内IP、指定IP直连
        {
            "type": "field",
            "ip": [
                "geoip:private",
                "geoip:cn",
                "223.5.5.5"
            ],
            "outboundTag": "direct-out"
        },
        // 2.3 BT协议流量直连
        {
            "type": "field",
            "protocol": [
                "bittorrent"
            ],
            "outboundTag": "direct-out"
        },
        // [3-proxy 国外流量转发VPS]
        // 3.1 国外域名集、指定子域名、指定泛域名转发VPS
        {
            "type": "field",
            "domain": [
                "geosite:geolocation-!cn",
                "full:proxy.yourdomain.com",
                "yourdomain.com"
            ],
            "outboundTag": "proxy-out-vless"
        },
        // 3.2 指定IP转发VPS
        {
            "type": "field",
            "ip": [
                "1.1.1.1"
            ],
            "outboundTag": "proxy-out-vless"
        }
        // [4-default-routing 第一条出站]
        // 没有匹配到任何规则的流量,默认使用第一条出站处理
    ]
}

此时,路由规则其实变成了:

    graph LR;

    S(APP数据) .-> I[入站]

    subgraph Xray
    I --> R[路由] -- "geosite:category-ads-all" --> O1[block]

    R[路由] -- "geosite:cn" --> O2[direct]
    R[路由] -- "direct.yourdomain.com" --> O2[direct]
    R[路由] -- "geoip:private" --> O2[direct]
    R[路由] -- "geoip:cn" --> O2[direct]
    R[路由] -- "ip:223.5.5.5" --> O2[direct]
    R[路由] -- "protocol:bittorrent" --> O2[direct]

    R[路由] -- "geosite:geolocation-!cn" --> O3[proxy]
    R[路由] -- "proxy.yourdomain.com" --> O3[proxy]
    R[路由] -- "*.yourdomain.com" --> O3[proxy]
    R[路由] -- "ip:1.1.1.1" --> O3[proxy]

    R[路由] -. "没有命中规则的流量" .-> O4[第一条出站]

    end

    O2 .-> D(国内服务器)
    O3 .-> V(VPS)

    O1:::redclass
    V:::greyclass
    S:::greyclass
    R:::routingclass
    classDef redclass fill:#FF0000
    classDef greyclass fill:#C0C0C0
    classDef routingclass fill:#FFFFDE,stroke:#000000

至于第一条出站是 [direct-out] 还是 [proxy-out-vless],这就全看你的需求了。

7. 路由配置常见错误

请大家注意看,我上面每一条路由规则,都是一个独立的匹配依据,只有这样才能确保生效。而新人在自定义路由规则时常犯的一个错误就是:在一条规则内同时匹配了多种不同的匹配依据,造成匹配无效。

比如,他希望实现的配置是:

  1. 自己的 direct.yourdomain.com 直连
  2. 国内DNS查询223.5.5.5)直连

7.1 错误示范

为了实现上面的目标,他写出了以下路由规则:

"routing": {
    "domainStrategy": "AsIs",
    "rules": [
        {
            "type": "field",
            "ip": [
                "223.5.5.5"
            ],
            "domain": [
                "full:direct.yourdomain.com"
            ],
            "outboundTag": "direct-out"
        }
    ]
}

你能看出这里面的错误吗?乍一看,似乎是对的?

::: warning 注意 同一个规则之内,各个依据需要同时成立,才会匹配成功,逻辑关系是 ,而不是 。 :::

换言之,这条规则的意思是:【当你访问的 目标 = direct.yourdomain.com, 并且 同时还满足 目标 = 223.5.5.5 时,Xray 才会将流量转发给 [direct-out] 直连出站】

很显然,一个目标不可能同时等于两个不同的值,所以这不但是一个永远不可能实现的无效规则,更与原本的目标风马牛不相及。

7.2 正确示范

正确示范,自然就是将不同的匹配依据独立出来:

"routing": {
    "domainStrategy": "AsIs",
    "rules": [
        {
            "type": "field",
            "ip": [
                "223.5.5.5"
            ],
            "outboundTag": "direct-out"
        },
        {
            "type": "field",
            "domain": [
                "full:direct.yourdomain.com"
            ],
            "outboundTag": "direct-out"
        }
    ]
}

其实第6点已经是我整理过的规则了原则就是【相同的匹配依据可以合并不同的匹配依据保持独立】。

8. 明修栈道、暗渡陈仓

[domain] 转化 [ip] 的密道:domainStrategy

我们在 5.4 中提交了多种流量判断的【依据】,其中一种是域名 [domain]、一种是 [IP]

如果你初步了解过DNS的运作过程就会知道我们对一个域名 [domain] 发起访问请求时,其实需要先向 DNS 发起请求来解析域名 [domain] 对应的 [IP],在得到 [IP] 后再向它发起实际请求。

所以,面对入站的一次域名请求,Xray 其实有两次机会去判断它的类型。那么,究竟是否要用这两次机会呢?这就是由 domainStrategy 这个配置来决定的。它有三个选项:

  • AsIs
  • IPIfNonMatch
  • IPOnDemand

按么我们逐个来解释一下:

8.1 域名策略: "AsIs"

就是 "As Domain Is",也就是说 【域名什么样,就什么样,不多折腾】。

简单粗暴理解就是说【仅用 [domain] 来匹配】。

::: tip AsIs 的实际意义为 【如原先所示,不加修改】,🍉老师这里描述的不是很恰当。 :::

这个方式的处理都在 Xray 内部完成,没有与外界的数据往来,所以速度最快。它的兜底策略也很清晰:即前面所说的、无法匹配的域名自动转入第一条出站处理。所以,对于常规使用路由功能这最推荐的策略。

8.2 域名策略: "IPIfNonMatch"

就是 "lookup IP if (there's) no matching rule",也就是说【如果其他所有规则都匹配不上,那就转化成 IP 去匹配 IP 规则】。

简单粗暴理解就是说【先把访问目标和其他所有类型规则匹配,如果匹配不上,那就通过 DNS 查询转化成 IP,再从头和所有规则匹配一次】。

该策略下没有命中任何规则的这一部分域名,会需要再经历 DNS 查询过程、以及第二轮规则匹配的过程,其耗时会多于 AsIs 策略,所以并不是首选推荐的策略。

8.3 域名策略: "IPOnDemand"

这里其实说 Demand IP 更准确些,也就是说【当匹配时碰到任何基于 IP 的规则,将域名立即解析为 IP 进行匹配】。

简单粗暴理解就是说【只要路由规则中有 IP 类规则,那么所有基于域名 [domain] 的请求都要解析成 [IP] 然后去匹配 [IP] 类规则】。

它要对所有首次域名访问进行 DNS 解析,所以首次查询比较耗时。虽然由于 XrayDNS 缓存机制的存在,后续对相同域名的访问速度会重回巅峰,但总体来说也不是首选推荐的策略。

::: warning 啰嗦君 domainStrategy 仅对域名生效,不要搞混了哦~ :::

9. 思考题

迄今为止,我们都是在【单入站】和【单出站】的基础上,讲解【路由】内部的各种配置逻辑。

但是,如你所知,Xray 本身是支持多端口,多协议的。那么,如果我问你:

  1. 我希望 VLESS 协议将我日常的网页浏览和APP流量转发给美国的大流量服务器
  2. 我希望 trojan 协议将我的所有Netflix流量转发给日本的服务器解锁各种二次元
  3. 我希望 shadowsocks 协议将我所有的游戏流量转发给香港的服务器达到最低的延迟
  4. 我希望有一个独立的端口,能够把 telegram 的流量全都转发给VPS
  5. 我希望有一个独立的端口,能够把 bittorrent 下载流量全都转发给欧洲大盘鸡
  6. 我希望......

这些想法,是否能通过【路由】功能配置实现呢?

答案当然是 【完全可以】 啦! 但是这些对于 level-1 来说已经超纲了,就留给各位自由的探索吧!

10. 结语

至此,Xray 的【路由】功能就介绍完了。希望本文能够对你理解 Xray 的灵活有所帮助。

11. 尾注

  • 现在你可以重新阅读一遍 路由,看看是否有更加深刻的理解。
  • 🍉🍉🍉🍉🍉 :D