AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / server / 问题 / 1155587
Accepted
user3450564
user3450564
Asked: 2024-03-03 07:14:14 +0800 CST2024-03-03 07:14:14 +0800 CST 2024-03-03 07:14:14 +0800 CST

通过 VPN 本身将 Web 流量传递到 OpenVPN 信封之外的 VPN 端点

  • 772

我有一个 Linux 服务器,它是一个 OpenVPN 端点,但也托管一个网络服务器。当我的客户端连接到网络服务器的服务器地址时,数据包会在 VPN 之外传输。确实如此,因为 OpenVPN 设置的到服务器的路由比进入 VPN 的默认路由更具体。但我认为这是一个“泄漏”。

因此,我尝试设置与 Wireguard 类似的设置(Wireguard 很棒,但我需要 OpenVPN,因为它需要是 TCP)。

我的设置基于 Wireguard 页面以及其他问题: Prevent Routing Loop with FwMark in Wireguard (向那里举行的讲座致敬!) Routing fwmark to VPN gateway using nftables mark

尽管进行了设置,Wireshark 显示 http/https 请求仍然通过物理接口而不是通过 vpn tun0 接口。当我使用 nft 监视器跟踪查看数据包标记时,似乎元标记已正确设置,并且仅出现适当的数据包(发往/来自端口 1194)。

所以我怀疑这是:

  • PBR 规则未按预期工作。
  • 数据包标记没有尽早发生。

我尝试更改链以将传出数据包标记为:

  • 输入路由钩子输出
  • 类型过滤钩输出
  • --> 没有更多的运气

这些命令返回以下内容:

- ip rule:
0:  from all lookup local
32764:  from all lookup main suppress_prefixlength 0
32765:  not from all fwmark 0x4 lookup vpn
32766:  from all lookup main
32767:  from all lookup default

- ip route show table vpn:
default dev tun0 scope link

- ip route:
default via 10.8.0.1 dev tun0 proto static metric 50 
default via 192.168.1.1 dev wlp4s0 proto dhcp src 192.168.1.10 metric 600 
10.8.0.0/24 dev tun0 proto kernel scope link src 10.8.0.2 metric 50 
END.POINT.IP.ADDRESS via 192.168.1.1 dev wlp4s0 proto static metric 50 
192.168.1.0/24 dev wlp4s0 proto kernel scope link src 192.168.1.10 metric 600 

-nft list ruleset:
table inet vpn {
    chain premangle {
        type filter hook prerouting priority mangle; policy accept;
        ip saddr END.POINT.IP.ADDRESS tcp sport 1194 meta nftrace set 1
        meta mark set ct mark
    }

    chain postmangle {
        type filter hook postrouting priority mangle; policy accept;
        ip daddr END.POINT.IP.ADDRESS tcp dport 1194 meta nftrace set 1
        ip daddr END.POINT.IP.ADDRESS tcp dport 1194 meta mark set 0x00000004
        meta mark 0x00000004 ct mark set meta mark
    }
}

- traceroute -n --fwmark=0x4 END.POINT.IP.ADDRESS
    shows it goes via the physical interface out of the vpn (as expected)
    
- traceroute -n END.POINT.IP.ADDRESS
    shows it goes via the physical interface out of the vpn (UNWANTED)

非常感谢您提前!

linux
  • 2 2 个回答
  • 87 Views

2 个回答

  • Voted
  1. Best Answer
    A.B
    2024-03-03T15:12:49+08:002024-03-03T15:12:49+08:00

    如果不使用严格反向路径转发(“SRPF”),则根本不应使用nftables 。

    虽然在iptables或nftables中处理标记时,路由(转发)流量通常工作正常,但由于标记(在链中)而本地启动的重新路由流量通常会出现问题:链中发生的重新路由检查不会神奇地更改本地源已在客户端套接字上选择的 IP 地址。通常是 IP 地址错误。因此,它通常需要 NAT bandaid(在 中需要),并且可能会使 UDP 处理比多宿主环境中的情况更加困难。应尽可能避免为此使用nftables 。type route hook outputtype route hook outputtype nat hook output

    正如 WireGuard 一样,OpenVPN可以在其信封传出流量上充分设置防火墙标记,这将在本地传出流量发生任何路由查找之前发生:

    --mark value

    用值标记正在发送的加密数据包。标记值可以在策略路由和数据包过滤规则中进行匹配。此选项仅在 Linux 中受支持,在其他操作系统上不起作用。

    这与 WireGuard 的工作原理相同:在真实接口上传出的信封数据包可能会通过让客户端SO_MARK在连接到服务器之前使用其套接字来获得标记:

    SO_MARK(自 Linux 2.6.25 起)

    为通过此套接字发送的每个数据包设置标记(类似于 netfilter MARK 目标,但基于套接字)。更改标记可用于无需 netfilter 的基于标记的路由或数据包过滤。

    当然,如果重新路由或直接使用策略路由(包括直接标记(使用SO_MARK或等效方法))都没有到位,那么它很可能根本不起作用。


    因此删除所有nftables规则:

    nft delete table inet vpn
    

    并在客户端配置中添加:

    mark 4
    

    保留路由规则和表(它们可能应该集成在 VPN 挂钩中):

    - ip rule:
    0:  from all lookup local
    32764:  from all lookup main suppress_prefixlength 0
    32765:  not from all fwmark 0x4 lookup vpn
    32766:  from all lookup main
    32767:  from all lookup default
    
    - ip route show table vpn:
    default dev tun0 scope link
    

    注意:本答案末尾的部分仅适用于 SRPF 情况,应在添加上面的路由表条目之前添加,以避免暂时中断。

    不要添加通过 VPN 的默认路由,也不要添加到远程端点的显式路由。不要让服务器推送此配置。或者让客户忽略它:

    pull-filter ignore redirect-gateway
    

    或者:

    route-nopull
    

    为了不出现这些路线:

    default via 10.8.0.1 dev tun0 proto static metric 50 
    
    END.POINT.IP.ADDRESS via 192.168.1.1 dev wlp4s0 proto static metric 50 
    

    但只有这个被添加:

    10.8.0.0/24 dev tun0 proto kernel scope link src 10.8.0.2 metric 50 
    

    相反,策略路由规则将vpn仅在足够时通过选择路由表来处理默认路由。


    正如我对第一个链接的 Q/A 的回答中所解释的, WireGuard +的大多数nftables规则集都是处理回复流量的SRPF。有以下几种情况:Table = autoAllowedIPs = 0.0.0.0

    • rp_filter=0到处

      包括net.ipv4.conf.default.rp_filter和net.ipv4.conf.all.rp_filter。没有 RPF 检查:无事可做。不需要nftables。

    • rp_filter=1

      现在信封回复流量可能会导致 SRPF 失败

      • 要么在主界面上选择Loose RPF:

        sysctl -w net.ipv4.conf.wlp4s0.rp_filter=2
        

        并完成它。不需要nftables,

      • 或实现所有逻辑来标记返回信封流量,就像在 WireGuard 中所做的那样

        • 让 fwmark 也可用于反向路径查找

          通过src_valid_mark在主界面上启用(也可以改为启用all),从而允许 SRPF 通过:

          sysctl -w net.ipv4.conf.wlp4s0.src_valid_mark=1
          
        • 转置(此处仅限 IPv4)WireGuard 的设置

          如链接的 Q/A中所示,末尾描述的其他极端情况也被考虑在内,因此回复流量获得 fwmark

          table ip vpn {
              chain preraw {
                  type filter hook prerouting priority raw; policy accept;
                  iifname != "tun0" ip daddr 10.8.0.2 fib saddr type != local drop
              }
          
              chain premangle {
                  type filter hook prerouting priority mangle; policy accept;
                  ct mark 4 meta mark set ct mark
              }
          
              chain postmangle {
                  type filter hook postrouting priority mangle; policy accept;
                  meta mark 4 ct mark set meta mark
              }
          }
          

          链条preraw是可选的,如果需要可以拆除。它可以防止远程(LAN)尝试访问内部 VPN 本地地址。

          该标记由 OpenVPN 在传出信封数据包上创建,在钩子后路由处复制到 connmark 中,并在钩子预路由处重新注入到回复信封数据包中。任何地方都没有出现端点地址或端口。

          没有重新路由(没有type route hook output也不type nat hook output存在)。

        注意:上面的 sysctl 命令和nftables规则集都应该在路由表中添加默认路由之前执行vpn,否则会发生暂时的连接丢失,直到 VPN TCP 套接字恢复(仍然只有在两者都添加后)。


    客户端系统现在可以从隧道内到达服务器。

    连接测试可以这样完成:

    socat -d -d TCP4:END.POINT.IP.ADDRESS:443 -
    

    OPtcpdump应通过 VPN 单跳到达 END.POINT.IP.ADDRESS。

    至少在 amd64 (x86-64) 架构上,可以通过以下方式绕过 VPN(以 root 身份):

    socat -d -d TCP4:END.POINT.IP.ADDRESS:443,setsockopt-listen=1:36:L4 -
    

    其中setsockopt-listen表示:SO_MARK在连接之前使用(在本例中不是监听)。其中的4与L4OpenVPN使用的标记值相同。


    注意:客户端通过隧道使用服务器的公共 IP 地址查询服务器上的 UDP 服务的具体情况可能会遇到一个与 VPN 无关的常见问题,而是与使用 UDP 和多宿主相关。这要求 UDP 服务具有多宿主感知能力:通常通过使用多个 UDP 套接字,为每个本地地址绑定一次(因此通常每个接口至少IP_PKTINFO绑定一次),或者通过使用附加处理代码来使用单个未绑定的 UDP 套接字。

    • 0
  2. user3450564
    2024-03-04T04:02:03+08:002024-03-04T04:02:03+08:00

    首先非常感谢您的及时回复。

    噢,好吧。据我了解,由于请求过程中的初始路由决策已经发生,如果没有 NAT,重新路由将发送源错误的数据包,从而失败。

    所以我做了以下事情:

    关于 rp_filter,我的发行版默认值为 2,我不会再增加复杂性。因此,请按照建议将所有这些都排除在外。我暂时将这些都设置为 0。

    我保留 nftables 只是为了跟踪数据包并确保 openvpn 确实按照以下方式标记数据包)。

    - ip rule
    0:  from all lookup local
    32764:  from all lookup main suppress_prefixlength 0 **I tried with and without that one with no effect on reaching the webserver**
    32765:  not from all fwmark 0x4 lookup vpn
    32766:  from all lookup main
    32767:  from all lookup default
    
    - ip route show table vpn:
    default dev tun0 scope link
    
    - ip route
    default via 192.168.1.1 dev wlp4s0 proto dhcp src 192.168.1.10 metric 600 
    10.8.0.0/24 dev tun0 proto kernel scope link src 10.8.0.2 
    192.168.1.0/24 dev wlp4s0 proto kernel scope link src 192.168.1.10 metric 600 
    
    - nft list ruleset (kept just for seeing if openvpn did mark the packets, and it did)
    table inet vpn {
        chain premangle {
            type filter hook prerouting priority mangle; policy accept;
            meta mark 0x00000004 meta nftrace set 1
        }
    
        chain postmangle {
            type route hook output priority mangle; policy accept;
            meta mark 0x00000004 meta nftrace set 1
        }
    }
    

    但是现在,我无法再访问网络服务器:

    traceroute -n --fwmark=0x4 END.POINT.IP.ADDRESS
        Shows it goes via the physical interface and my ISP ips outside of the vpn envelope (as expected). Wireshark shows all the Icmp packets.
    
    traceroute -n END.POINT.IP.ADDRESS
        **attempts the 30 hops without success and fails to find a route. Wireshark does not show any Icmp packet on any interface**
    
    socat -d -d TCP4:END.POINT.IP.ADDRESS:443 -
    socat[56833] N opening connection to AF= ** and stalls until Ctrl-C
    

    我这么做ip route flush cache只是为了以防万一。没有成功,虽然一切似乎都井然有序:

    ip route get END.POINT.IP.ADDRESS
    END.POINT.IP.ADDRESS dev tun0 table vpn src 10.8.0.2 uid 0 cache 
    
    ip route get END.POINT.IP.ADDRESS mark 4
    END.POINT.IP.ADDRESS via 192.168.1.1 dev wlp4s0 src 192.168.1.10 mark 4 uid 0 cache 
    

    Wirehshark 不会显示与请求相关的任何数据包,甚至不会显示错误的地址或没有答案。

    请问有什么可能妨碍的线索吗?!抱歉,如果我误解了任何一点,坦率地说,您提出的设置对我来说很有意义。谢谢 !

    • 0

相关问题

  • Linux 主机到主机迁移

  • 如何在 Linux 机器上找到有关硬件的详细信息?

  • 如何在 Linux 下监控每个进程的网络 I/O 使用情况?

  • 在 RHEL4 上修改 CUPS 中的现有打印机设置

  • 为本地网络中的名称解析添加自定义 dns 条目

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    新安装后 postgres 的默认超级用户用户名/密码是什么?

    • 5 个回答
  • Marko Smith

    SFTP 使用什么端口?

    • 6 个回答
  • Marko Smith

    命令行列出 Windows Active Directory 组中的用户?

    • 9 个回答
  • Marko Smith

    什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同?

    • 3 个回答
  • Marko Smith

    如何确定bash变量是否为空?

    • 15 个回答
  • Martin Hope
    Tom Feiner 如何按大小对 du -h 输出进行排序 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    Noah Goodrich 什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent 如何确定bash变量是否为空? 2009-05-13 09:54:48 +0800 CST
  • Martin Hope
    cletus 您如何找到在 Windows 中打开文件的进程? 2009-05-01 16:47:16 +0800 CST

热门标签

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve