SSLH的透明模式如何工作?

SSLH的透明模式如何工作?

我有一台服务器需要在端口 443 上接受 TCP 连接,确定连接是 OpenVPN 客户端还是 HTTPS 客户端,然后将其转发到我的 Web 服务器或 OpenVPN 服务器。

SSLH 是专门为此目的而设计的,并且看起来效果很好。唯一的问题是,虽然将其设置为非透明模式对我来说效果很好,但使用透明模式却给我带来了麻烦。

有人可以解释透明模式应该如何工作背后的理论吗?

SSLH指南说为了透明地使用SSLH, 你需要:

  • 将 sslh.cfg 设置为transparent: true;
    • 我已经这样做了
  • sslh 需要扩展权限 (CAP_NET_ADMIN)
    • 我从 CentOS 7 的存储库安装了 sslh,它附带了用于 systemd 的 sslh.service。该服务文件包含该行CapabilityBoundingSet=... CAP_NET_ADMIN ...,所以我假设这已经由 SystemD 完成
  • 设置标记数据包的 iptables 规则以及某种本地路由
    • 这是我不太清楚的。这些是否在 SSLH 服务器上进行设置?或者他们是否在 OpenVPN 和 HTTPS 服务器上进行设置?

我在示例中了解到,iptables 被告知用 0x1 标记标记源端口为 22 或 4443 的任何数据包,创建一条规则以使任何标记为 0x1 的数据包使用路由表 100,并创建路由表 100设置某种执行某些操作的本地路由。

为什么这些 iptables 规则和路由是必要的?该路线实际上在做什么?我认为路由应该位于 Web 服务器和 OpenVPN 服务器上,并指向 SSLH ip,但这似乎对我也不起作用。

===

更新:我突然想到,这可能是一条指向本地主机的路由,因为在示例中,服务器都在同一台计算机上,并且它们希望来自实际服务器的回复数据包在离开之前通过 SSLH机器。听起来对吗?如果是这样,如果我的服务器位于不同的机器上,我该怎么办?在这些机器上设置流量标记和返回 SSLH 服务器的路由?

更新 2:我只是在与 SSLH 相同的机器上快速设置了 HTTPS 服务器,透明模式似乎确实按照 SSLH 文档示例中的方式工作。当它们位于不同的服务器上时,我需要它才能工作。

答案1

在非透明模式下,客户端连接client_ip:client_portsslh端口 上的代理443。然后代理在端口 上打开与内部服务器的sslh连接。内部 Web 服务器将从 应答到。最后代理将应答数据包的来源重写并发送给客户端。sslh_ip:sslh_port4443web_ip:4443proxy_ip:proxy_portsslhsshl_ip:443

在透明模式下,代理和内部服务器之间的连接的数据sslh包源设置为原始数据包client_ip:client_port。因此,内部 Web 服务器直接响应client_ip:client_port作为web_ip:4443源。但客户端等待数据包形成proxy_ip:443

要管理来自内部服务器的应答包的重写,这些包必须通过sslh守护程序进行路由。我认为守护进程在环回接口上寻找给客户端的应答包。在文档中,仅sslh规定了代理和 Web 内部服务器位于同一台计算机上的情况。

通过尝试和错误,我找到了以下解决方案:(在sslh代理上)

ip route add local default dev lo table 100
ip rule add fwmark 0x1 lookup 100
iptables -t mangle -N SSLH
iptables -t mangle -A SSLH -j MARK --set-mark 0x1
iptables -t mangle -A SSLH -j ACCEPT

(从内部服务器捕获应答包)

iptables -t mangle -A PREROUTING -p tcp -s **web_ip** --sport 4443 -j SSLH

...(其他服务的类似规则,例如 ssh、openvpn)...

仅当内部 Web 服务器的默认路由通过sshl代理服务器到达 Internet 时,此功能才有效。

答案2

谢谢诺伯特 - 你很好地解释了总体思路。因此,综上所述,据我所知,这就是我们正在运行的所有命令所具体发生的情况:

SSLH 服务器:

$ sudo iptables -t mangle -N SSLH
$ sudo iptables -t mangle -A PREROUTING -p tcp -m socket --transparent -j SSLH
$ sudo iptables -t mangle -A SSLH -j MARK --set-mark 0x1 
$ sudo iptables -t mangle -A SSLH -j ACCEPT
$ sudo ip rule add fwmark 0x1 lookup 100 
$ sudo ip route add local 0.0.0.0/0 dev lo table 100

内部网络服务器:

$ sudo iptables -t mangle -N SSLH
$ sudo iptables -t mangle -A OUTPUT -o eth0 -p tcp -m tcp --sport 4443 -j SSLH
$ sudo iptables -t mangle -A SSLH -j MARK --set-mark 0x1 
$ sudo iptables -t mangle -A SSLH -j ACCEPT
$ sudo ip rule add fwmark 0x1 lookup 100 
$ sudo ip route add default via [SSLH_IP] table 100 

在内部 Web 服务器上:

  • Web 服务器(如 apache 或 nginx)正在侦听端口 4443
  • 源端口为 4443 的 eth0 发出的任何内容都会发送到 SSLH 链
  • SSLH 链中的任何内容都会被标记为 0x1
  • 创建一条路由规则,规定任何标记为 0x1 的内容都应使用路由表 100,而不是主路由表
  • 路由表 100 有一个条目表示将流量发送到 SSLH 服务器,而不是默认网关

这一系列事件基本上强制将来自 Web 服务器进程(nginx/apache/其他)的流量路由到 SSLH 服务器,而不是像系统的其余流量一样路由到默认网关。

在 SSLH 服务器上:

  • 来自 Web 服务器(源端口 4443)的任何内容都会发送到 SSLH 链
  • SSLH 链中的任何内容都会被标记为 0x1
  • 创建一条路由规则,规定任何标记为 0x1 的内容都应使用路由表 100,而不是主路由表
  • 路由表 100 有一个条目,表示强制使用此路由表的所有流量重定向到环回接口

这一系列事件基本上迫使来自内部 Web 服务器的流量重定向到 SSLH 服务器上的环回接口,其中 SSLH 进程将重写其源 IP 和端口并将其发送出去。

我还有疑问:

  • 听起来对吗?
  • 做什么iptables -t mangle -A SSLH -j ACCEPT?有必要吗?这不是 FILTER 表 - 为什么我们要在这里接受流量?
  • 就我而言,SSLH 主机上的 iptables 预路由规则看起来与 Norbert 的不同。这是如何运作的?它如何知道某物是否存在--transparent

答案3

我按照 GitHub 上的文档步骤进行操作(https://github.com/yrutschle/sslh/blob/master/doc/config.md),使用--transparent文件中的参数/etc/default/sslh

例如,如果 Apache 正在侦听端口 4443 而不是 443,并且我们也使用 OpenVPN:

DAEMON_OPTS="--user sslh --transparent --listen 0.0.0.0:443 --ssh 127.0.0.1:22 --ssl 127.0.0.1:4443 --openvpn 127.0.0.1:1194 --pidfile /var/run/sslh/sslh.pid"

请注意,您可能需要替换127.0.0.1:1194为您的 VPN IP 地址,后跟:1194(https://github.com/yrutschle/sslh/issues/83#issuecomment-515675186)。

如果您需要 IPv6 支持,您可以将 0.0.0.0 替换为指向远程 IPv4 / IPv6 的“双栈”域名,并将 127.0.0.1 替换为localhost指向本地 IPv4 / IPv6(如果在/etc/hosts.

为了使其在 Debian 上重新启动后永久生效,我必须在现有配置下方post-up为本地接口添加这些规则:/etc/network/interfaces

# The loopback network interface
auto lo
iface lo inet loopback
# Configure routing for those marked packets (required by sslh transparent mode for IPv4)
        post-up ip rule add fwmark 0x1 lookup 100
        post-up ip route add local 0.0.0.0/0 dev lo table 100
iface lo inet6 loopback
# Configure routing for those marked packets (required by sslh transparent mode for IPv6)
        post-up ip -6 rule add fwmark 0x1 lookup 100
        post-up ip -6 route add local ::/0 dev lo table 100

这些规则在/etc/sysctl.conf

# Set route_localnet = 1 on all interfaces so that ssl can use "localhost" as destination (required by sslh transparent mode)
net.ipv4.conf.default.route_localnet=1
net.ipv4.conf.all.route_localnet=1

在文档中,还有一些可以永久使用的 iptables 规则iptables-persistent(我不知道为什么,但当我测试时,透明模式似乎无需这些规则即可工作):

# DROP martian packets as they would have been if route_localnet was zero
# Note: packets not leaving the server aren't affected by this, thus sslh will still work
iptables -t raw -A PREROUTING ! -i lo -d 127.0.0.0/8 -j DROP
iptables -t mangle -A POSTROUTING ! -o lo -s 127.0.0.0/8 -j DROP

# Mark all connections made by ssl for special treatment (here sslh is run as user "sslh")
iptables -t nat -A OUTPUT -m owner --uid-owner sslh -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x01/0x0f

# Outgoing packets that should go to sslh instead have to be rerouted, so mark them accordingly (copying over the connection mark)
iptables -t mangle -A OUTPUT ! -o lo -p tcp -m connmark --mark 0x01/0x0f -j CONNMARK --restore-mark --mask 0x0f

对于 IPv6:

# DROP martian packets as they would have been if route_localnet was zero
# Note: packets not leaving the server aren't affected by this, thus sslh will still work
ip6tables -t raw -A PREROUTING ! -i lo -d ::1/128 -j DROP
ip6tables -t mangle -A POSTROUTING ! -o lo -s ::1/128 -j DROP

# Mark all connections made by ssl for special treatment (here sslh is run as user "sslh")
ip6tables -t nat -A OUTPUT -m owner --uid-owner sslh -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x01/0x0f

# Outgoing packets that should go to sslh instead have to be rerouted, so mark them accordingly (copying over the connection mark)
ip6tables -t mangle -A OUTPUT ! -o lo -p tcp -m connmark --mark 0x01/0x0f -j CONNMARK --restore-mark --mask 0x0f

相关内容