Lxn-Chan!

(~ ̄▽ ̄)→))* ̄▽ ̄*)o

需求描述:出口为运营商的ONT,下面是Fortigate做多合一网关,在下面有一台Linux服务器,运行PVE,虚拟机内连接另一城市的外部网络,同时在Fortigate上做分流,使得同局域网下其他设备能够访问外部网络。

该项目仅作为个人记录,也许不太容易复制和实践。

所用设备:

  • FortiGate 61E,FortiOS 7.2.13
  • PantherX2,Debian 12.9 aarch64

基础环境

架构简述

  • Fortigate 61E / FortiOS 7.2
    • wan1:去往运营商
    • internal:192.168.99.99/24,管理与普通内网
    • internal.10:VLAN 10,Fortigate → proxy VM 入口
    • internal.20:VLAN 20,proxy VM → Fortigate 出口
  • PVE 单网口接 Fortigate internal
    • vmbr0:开启VLAN-aware
    • tag 10:proxy VM 入口网卡
    • tag 20:proxy VM 出口网卡
  • proxy VM
    • enp0s11(VLAN10):10.10.10.11/30,接收 Fortigate 策略路由送来的流量
    • enp2s4(VLAN20):10.20.20.21/30,mihomo 出站回 Fortigate

IP地址规划

  • Fortigate internal:
    • 192.168.99.99/24
  • PVE 管理地址:
    • 192.168.99.101/24
    • 网关:192.168.99.99
  • VLAN 10 / proxy_in:
    • Fortigate internal.10:10.10.10.10/24
    • mihomo VM enp0s11:10.10.10.11/24
  • VLAN 20 / proxy_out:
    • Fortigate internal.20:10.20.20.20/24
    • mihomo VM enp2s4:10.20.20.21/24
    • 网关:10.20.20.20
  • 其他普通客户端:
    • 192.168.99.0/24
    • 网关:192.168.99.99

流量走向

普通流量:

1
2
3
192.168.99.x
→ Fortigate internal
→ wan1

需要代理的流量:

1
2
3
4
5
6
7
8
192.168.99.x
→ Fortigate internal
→ PBR
→ VLAN10 / 10.10.10.2
→ proxy VM TUN
→ VLAN20 / 10.20.20.2
→ Fortigate internal.20
→ wan1

配置前提示

本文环境假定当前防火前已配通外部网络(即流量走向章节中的普通流量走向是通的);本文中配置大多为最小化配置,但直接复制应该可以跑得起来,主要是展示原理,需要读者具备一定的数通知识。

一、PVE配置

此处PVE的安装和配置省略,可查看本站往期文章。

二、防火墙配置

2.1.创建VLAN

internal硬件交换下创建两个vlan,这里我创建为vlan10和vlan20。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
config system interface
edit "internal"
set vdom "root"
set allowaccess ping https ssh snmp http
set type hard-switch
set monitor-bandwidth enable
set role lan
next
edit "proxyIn"
set vdom "root"
set ip 10.10.10.10 255.255.255.0
set allowaccess ping
set role lan
set interface "internal"
set vlanid 10
next
edit "proxyOut"
set vdom "root"
set ip 10.20.20.20 255.255.255.0
set allowaccess ping
set role lan
set interface "internal"
set vlanid 20
next
end

2.2.创建地址对象

创建代理机相关的地址对象,方便后面写防火墙策略和策略路由。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
config firewall address
edit "proxyIn"
set type iprange
set associated-interface "proxyIn"
set start-ip 10.10.10.11
set end-ip 10.10.10.11
next
edit "proxyOut"
set type iprange
set associated-interface "proxyOut"
set start-ip 10.20.20.21
set end-ip 10.20.20.21
next
end

安全和方便起见,我建议再把客户端的地址对象也创建出来。我这里DHCP实际分配范围没有那么大,所以单独写了个地址对象:

1
2
3
4
5
6
7
8
9
config firewall address
edit "internalClient"
set type iprange
set comment "内网客户端设备(DHCP)"
set associated-interface "internal"
set start-ip 192.168.99.121
set end-ip 192.168.99.170
next
end

2.3.创建需要代理的地址对象

这一步创建需要代理的地址对象,我这里准备了一个用于探测本地IP地址的服务。因为该服务实际位置在海外,意味着在国内访问可以获取国内地址;一旦该服务被代理,则应输出代理的地址。

1
2
C:\Users\LxnChan>curl https://ipdetect.arlxn.top/myip
111.30.*.*

出于测试目的,这里我使用该服务用于测试分流。

1
2
3
4
5
6
config firewall address
edit "ipdetect"
set type fqdn
set fqdn "ipdetect.arlxn.top"
next
end

2.4.创建策略路由

这一步创建策略路由,策略是将指定地址对象的流量发送到指定的网关上。

1
2
3
4
5
6
7
8
9
10
config router policy
edit 200
set input-device "internal"
set srcaddr "internalClient"
set dstaddr "ipdetect"
set gateway 10.10.10.11
set output-device "proxyIn"
set status enable
next
end

2.5.创建防火墙策略(放行)

  1. 放行内网到代理机的流量
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    config firewall policy
    edit 199
    set name "InternalSetting"
    set srcintf "internal"
    set dstintf "proxyIn"
    set action accept
    set srcaddr "internalClient"
    set dstaddr "proxyIn address"
    set schedule "always"
    set service "ALL"
    next
    end
  2. 放行代理机出网流量
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    config firewall policy
    edit 198
    set name "proxyOut"
    set srcintf "proxyOut"
    set dstintf "wan1"
    set action accept
    set srcaddr "proxyOut"
    set dstaddr "all"
    set schedule "always"
    set service "ALL"
    set nat enable
    set fixedport enable
    set comments "代理机上网"
    next
    end
  3. 我的所有DNS都走内网(内网有独立的DNS服务器),因此还需要放行代理机到内网DNS的流量
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    config firewall policy
    edit 197
    set name "proxyToDNS"
    set srcintf "proxyOut"
    set dstintf "internal"
    set action accept
    set srcaddr "proxyOut"
    set dstaddr "DNServerAddr"
    set schedule "always"
    set service "DNS"
    set comments "代理机DNS"
    next
    end
  4. 放行从【普通客户端】经由【策略路由】指引到【代理机】的流量
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    config firewall policy
    edit 196
    set name "internetThroughProxy"
    set srcintf "internal"
    set dstintf "proxyIn"
    set action accept
    set srcaddr "internalClient"
    set dstaddr "all"
    set schedule "always"
    set service "ALL"
    next
    end

防火墙的配置到此告一段落。

三、虚拟机配置

3.1.创建虚拟机

创建一个具备两块网卡的虚拟机,这里记为enp0s11enp2s4,分别设置tag为10和20。

代理机的操作系统我采用了debian 11.11。

3.2.配置网络

用于传入连接的网卡(vlan10)不需要设置网关(因为代理机自己就是网关),另外一块网卡(vlan20)供代理机上网因此需要设置网关。

1
2
3
4
5
6
7
8
9
10
11
# /etc/network/interfaces
auto enp0s11
iface enp0s11 inet static
address 10.10.10.11
netmask 255.255.255.0

auto enp2s4
iface enp2s4 inet static
address 10.20.20.21
netmask 255.255.255.0
gateway 10.20.20.20

3.3.启用转发和禁用IPv6

禁用IPv6是防止路由泄露,也防止配置混乱,后面如果有用到IPv6再单独配置。

注意修改如下配置文件中的网卡名称

1
2
3
4
5
6
7
8
9
10
11
12
13
cat >/etc/sysctl.d/99-lxnchan-oversea.conf <<'EOF'
net.ipv4.ip_forward=1
net.ipv4.conf.all.rp_filter=0
net.ipv4.conf.default.rp_filter=0
net.ipv4.conf.enp0s11.rp_filter=0
net.ipv4.conf.enp2s4.rp_filter=0
net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.default.disable_ipv6=1
net.ipv6.conf.enp0s11.disable_ipv6=1
net.ipv6.conf.enp2s4.disable_ipv6=1
EOF

sysctl --system

如果是用本机网卡创建的vlan怎么写这个sysctl配置文件:
因为创建的vlan子网卡的网卡名一般是eth0.10这样,因此这么写:

1
net.ipv4.conf.eth0/10.rp_filter=0

即用斜杠做转义即可。

四、配置代理

4.1.下载mihomo

1
2
3
4
5
wget https://github.com/MetaCubeX/mihomo/releases/download/v1.19.24/mihomo-linux-arm64-v1.19.24.gz
gunzip mihomo-linux-arm64-v1.19.24.gz
mv mihomo-linux-arm64-v1.19.24 /usr/local/bin/mihomo
chmod +x /usr/local/bin/mihomo
mihomo -v

生成配置文件夹:

1
2
3
mkdir -p /etc/mihomo
mkdir -p /etc/mihomo/proxy_providers
mkdir -p /etc/mihomo/rule_providers

4.2.安装yq

主要是后面自动patch配置文件时会方便一些。

1
2
3
wget https://github.com/mikefarah/yq/releases/download/latest/yq_linux_arm64 -O /usr/local/bin/yq
chmod +x /usr/local/bin/yq
yq --version

4.3.生成配置文件

我的服务提供商给的配置文件是完整的config.yaml文件,也有的服务商给的只有代理节点信息的,这个之后碰到了再说。

新建/etc/mihomo/config.patched.yaml作为补丁文件,写入需要补充或者覆盖的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 通过其他webui工具进行管理所需,如果不需要直接改成127.0.0.1即可
external-controller: 10.10.10.11:9090
secret: ""

find-process-mode: off
ipv6: false

# TUN设置
tun:
enable: true
stack: system
auto-route: true
auto-redirect: true
auto-detect-interface: false
strict-route: true
dns-hijack:
- any:53
include-interface:
- enp0s11
exclude-interface:
- enp2s4
route-exclude-address:
- 10.10.10.0/24
- 10.20.20.0/24

# GeoIP相关库地址设置,更新不了换别的cdn地址
geodata-mode: true
geo-auto-update: true
geo-update-interval: 24

geox-url:
geoip: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip-lite.dat"
geosite: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat"
mmdb: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country-lite.mmdb"
asn: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/GeoLite2-ASN.mmdb"

# 开启嗅探以便mihomo进行二次分流
sniffer:
enable: true
parse-pure-ip: true
override-destination: false
sniff:
HTTP:
ports: [80, 8080-8880]
override-destination: true
TLS:
ports: [443, 8443]
QUIC:
ports: [443, 8443]
skip-domain:
- Mijia Cloud
- +.push.apple.com

创建Patch脚本。注意修改wget ...为自己的配置链接;修改下面interface-name后面的接口为出网接口名:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash

wget --user-agent="lxnchan/1.1" \
https://lxnchan.cn/proxy/config?serial=oTXZWhS7zj5G5X \
-O /etc/mihomo/lxnchan.yaml

yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' \
/etc/mihomo/lxnchan.yaml \
/etc/mihomo/config.patched.yaml \
> /etc/mihomo/config.yaml

yq eval -i '
with(
.proxies[];
select(tag == "!!map" and has("type") and .type != "direct" and .type != "reject")
| .["interface-name"] = "enp2s4"
)
' /etc/mihomo/config.yaml

systemctl restart mihomo

执行后可以测试一下配置文件:

1
2
3
4
5
6
7
8
9
10
root@proxyMan:/etc/mihomo# /usr/local/bin/mihomo -d /etc/mihomo -f /etc/mihomo/config.yaml -t
INFO[2026-04-23T22:21:47.690430535+08:00] Start initial configuration in progress
INFO[2026-04-23T22:21:47.728850910+08:00] Geodata Loader mode: memconservative
INFO[2026-04-23T22:21:47.729036993+08:00] Geosite Matcher implementation: succinct
INFO[2026-04-23T22:21:47.733894702+08:00] Load GeoIP rule: cn
INFO[2026-04-23T22:21:47.797724785+08:00] Finished initial GeoIP rule cn => DIRECT, records: 7503
INFO[2026-04-23T22:21:47.798422452+08:00] Load GeoIP rule: private
INFO[2026-04-23T22:21:47.806247868+08:00] Finished initial GeoIP rule private => DIRECT, records: 18
INFO[2026-04-23T22:21:47.806824202+08:00] Initial configuration complete, total time: 116ms
configuration file /etc/mihomo/config.yaml test is successful

没有报错就可以了。

4.4.以服务方式运行mihomo

写入/etc/systemd/system/mihomo.service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[Unit]
Description=mihomo Daemon
After=network.target systemd-networkd.service NetworkManager.service

[Service]
Type=simple
LimitNPROC=500
LimitNOFILE=1000000
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE
Restart=always
ExecStartPre=/usr/bin/sleep 1s
ExecStart=/usr/local/bin/mihomo -d /etc/mihomo
ExecReload=/bin/kill -HUP $MAINPID

[Install]
WantedBy=multi-user.target

启动服务:

1
systemctl enable --now mihomo

五、DNS服务器

本来不想写这部分的,后来在实际使用中发现DNS也是很重要的一环。

首先Fortigate的策略路由虽然可以引用域名和Internet服务,但是本质上路径仍然是FQDN先解析为IP然后把对应的流量路由到指定的网关,这意味着Fortigate需要提前知道对应的域名。

而Fortigate知道对应域名的IP的方式主要有两种:通过FortiGuard更新的ISDB库,内置了Fortigate官方对这些域名的解析值;其余手动添加的域名一般都需要Fortigate自己去向DNS请求解析。那么这里就会有一个问题就是当Fortigate和客户端获得的解析不同时,会发生客户端请求无法正确通过策略走向指定路由。本章节所有配置文件仅为展示原理及细节,不是完整配置文件,实际使用需根据实际情况调整。

5.1.DNS部署与配置

我这里内网已经有了DNS,选用的是smartdns,性能和资源占用都比较优秀。

主要需要配置的有两部分(最小配置):

  1. 解析至少要分为default和oversea两部分,oversea全部配置海外DNS服务。必要时可以配置doh。
    1
    2
    3
    4
    5
    6
    7
    # oversea
    server-https https://dns.quad9.net/dns-query -group oversea
    server-https https://dns.google/dns-query -group oversea
    # default
    server-https https://doh.pub/dns-query
    server-https https://dns.alidns.com/dns-query
    server 119.29.29.29
  2. 需要把经过策略路由的域名加入oversea组强制走海外解析,此处仅为示例,建议将所有过策略路由的域名都加入oversea解析组,
    1
    2
    3
    4
    5
    6
    7
    # Github oversea
    nameserver /github.com/oversea
    nameserver /githubusercontent.com/oversea
    nameserver /github.io/oversea
    nameserver /ghcr.io/oversea
    nameserver /githubassets.com/oversea
    nameserver /github.blog/oversea
    如果写了DoH,建议把DoH的域名也使用oversea解析
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # Cloudflare DNS
    server 1.0.0.1 -group oversea -group bootstrap-dns
    server 1.1.1.1 -group oversea -group bootstrap-dns
    # doh bootstrap
    nameserver /dns.google/bootstrap-dns
    nameserver /dns.quad9.net/bootstrap-dns
    # doh servers
    server-https https://dns.quad9.net/dns-query -group oversea
    server-https https://dns.google/dns-query -group oversea

5.2.EDNS

这一步建议不配置。EDNS相关知识请见官方文档

国内DNS直接写自己所在网络的子网:

1
2
3
4
# DNSPod DNS+
server 119.29.29.29 -subnet 111.32.0.0/16
# AliDNS
server 223.5.5.5 -subnet 111.32.0.0/16

海外DNS不写-subnet参数,禁用全局EDNS配置(默认情况下EDNS是未启用的)。当然海外DNS也可以根据你海外节点去写对应的EDNS,但是如果线路比较多且使用了CDN产品会导致维护成本过高,实际操作中还是不建议启用。

5.3.防火墙配置

防火墙上主要就是通过策略路由把指定的海外DNS本身的请求流量直接路由到代理网关:

  1. 配置地址对象
    1
    2
    3
    4
    5
    6
    7
    8
    9
    config firewall address
    edit "CloudflareDNS"
    set subnet 1.1.1.1 255.255.255.255
    next
    edit "GoogleDNS"
    set type fqdn
    set fqdn "dns.google"
    next
    end
  2. 配置DNS的策略路由
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    config router policy
    edit 205
    set input-device "internal"
    set srcaddr "DNServerAddr"
    set dstaddr "CloudflareDNS" "GoogleDNS"
    set gateway 10.10.10.11
    set output-device "proxyIn"
    set comments "海外DNS出方向"
    next
    end
  3. 在确保Fortigate本机到DNS服务器路由层面通的前提下把Fortigate的系统DNS改到smartDNS,以便Fortigate能和客户端获取相同的地址解析
    1
    2
    3
    4
    config system dns
    set primary 192.168.99.100
    set secondary 1.0.0.1
    end

六、测试并正式启用

此时测试,可以正常走海外线路了:

1
2
C:\Users\LxnChan>curl https://ipdetect.arlxn.top/myip
60.249.27.69

此时可以把Google、X或者Telegram等服务加入到策略路由的地址组中,观察到可以正常使用了。

 简单说两句



联系站长 | 服务状态 | 友情链接

备案号:辽ICP备19013963号

津公网安备12011602300394号

中国互联网违法和不良信息举报中心

架构版本号:8.2.1 | 本站已全面支持IPv6

正在载入运行数据(1/2)请稍后...
正在载入运行数据(2/2)请稍后...

O to die advancing on!

Copyright 2024 LingXuanNing, All rights reserved.