我需要创建一个客户端-服务器 OpenVPN 配置,以便在客户端为每个 IP 数据包分配一些元数据(例如 ID 或名称),而在另一端根据分配给它们的元数据对每个数据包进行不同的处理。对于发送元数据,我可以想到两种方法:
- 使用ToS字段,虽然它很小。
- 附加到有效载荷并从而改变长度/校验和/......
有没有更好的方法来标记每个数据包?OpenVPN 本身是否为这一要求提供了解决方案?
在服务器端(即 OpenVPN 服务器端),有没有办法利用现有机制对每个数据包进行 MITM?更确切地说,我需要读取每个元数据(每个 IP 数据包都附带这些元数据)并记录一些分类统计信息或对它们进行防火墙保护。
OpenVPN 是否为此提供了干净的解决方案?否则我应该接触 OpenVPN 服务器端代码并自行构建它们吗?
+------+ + ----+ +--------+ +--------+ +-----+ +----------+
| apps |---| tun |---| socket | ========= | socket |---| tun | ---| Internet |
+------+ +-----+ +--------+ +--------+ +-----+ +----------+
^ ^
| |
here packets are marked by my custom OpenVPN client |
|
here I'd need to firewall packets based on the "metadata"
答案1
如果您有自定义 OpenVPN 客户端,则需要通过编写代码以您决定的方式处理标记。请注意,发起数据包的进程的 PID 对 OpenVPN 客户端不可用,实际上可能根本不作为数据包的属性可用。您需要将客户端上的进程放在网络命名空间或类似位置才能获取此类信息。
如果您想要其他类型的“元数据”,请指定您想要的内容。
在服务器端,iptables
您可以做任何您想做的事情,而无需修改 OpenVPN 服务器。您可以使用 匹配 ToS --tos
,您可以使用 匹配 TTL --ttl-*
,您可以使用 匹配任何四个字节--u32
,或者如果您决定添加扩展标头或其他内容,您可以使用 运行完整的 BPF 过滤器程序--bytecode
。对于匹配的数据包,您可以将它们放入所需的出口接口,您可以在内部标记它们并路由它们,或者做任何其他您想要的事情。有关详细信息,请参阅man iptables-extensions
。
所以那部分很容易,困难的部分是首先找出除了 PID 之外你想要什么类型的元数据,然后如果 OpenVPN 客户端没有办法获取这些元数据,就找到某种方法将它们添加到数据包中。
编辑
为了获得最大的灵活性,您可以定义自己的IP 选项并将其添加到数据包头之后的每个 IPv4 数据包中。这将显著增加开销,还可能导致更多碎片(我不知道 OpenVPN 如何处理 VPN 隧道内的碎片)。
原则上,您也可以将数据包与目标一起传回用户空间NFQUEUE
。如果对每个数据包都这样做,速度会非常慢,因此我强烈建议不要这样做。
如果您真的想为每个数据包“运行自己的脚本”(我希望这不是 shell 脚本),最好的办法也是修改 OpenVPN 服务器。
我仍然不知道您对此的使用情况,但从您目前对计划的描述来看,我相当肯定这不会奏效,因为一切都会变得非常缓慢。请重新考虑您要做的事情,指定使用情况(您想要实现什么?),并使用 找出内核空间中的解决方案iptables
,如果您想要一些隔离,可能还需要多个 OpenVPN 客户端和服务器。
通常您有用户/进程的类别,您希望允许其中一些执行某些操作,并以不同的方式处理其他用户/进程。将用户/进程分配给这些类别,并在内核空间中处理这些类别。不要尝试通过将此信息添加到每个数据包来处理类别的分配。
祝你好运,你会需要它的。
编辑
我应该补充一点,人们通常认为所有iptables
规则的集合既是“脚本语言”(链中的规则是逐步处理的,可以跳转到其他链),也是大多数用途的“数据库”。当然,“数据库”不应该太大。如果要更改“数据库”,您可以在为此目的而创建的链中添加或删除规则。
处理数据包时速度很重要(内核很多每秒数据包数),而在用户空间和内核空间之间切换对速度的要求很高。 执行一次就可以了,就像在 OpenVPN tun/tap 接口中一样,它有自己的缓冲区,但不需要执行多次。
答案2
SELinux 标签网络允许您编写策略标记流量,直至生成流量的过程。远程主机上的策略会根据标记做出访问决策/过滤。但是,标记网络仅在标记 IPSec 和 CIPSO 上受支持,在 OpenVPN 上不直接受支持。
如果您要转发流量,您可能应该考虑使用自己的逻辑扩展 OpenVPN,而不是尝试在其他地方做出访问控制决策。如果所有传入流量都发往您的应用,您应该考虑在那里做出所有访问控制决策。