【问题标题】:Verify TCP connection is from same machine by MAC address通过 MAC 地址验证 TCP 连接是否来自同一台机器
【发布时间】:2026-01-22 05:00:01
【问题描述】:

请不要批评解决方案。这不是我的设计,是的,这很糟糕。

在运行 Linux 并使用 C 的计算机上,我们需要验证与进程建立的 TCP 连接是否来自同一台计算机。通过 IP 地址进行操作是有问题的,因为操作系统正在生成两个 IP 地址,而进程只知道一个。反正通过IP地址验证有点差。

我们希望通过将“远程”MAC 地址与本地 MAC 地址进行比较来进行验证。我们已经获得了本地 MAC 地址。我只需要知道如何获取“远程”MAC 地址。它位于形成连接时发送的数据包中(以及所有后续连接中)。我们如何将其拖出以太网层?

在任何人再说一遍之前,我知道如果远程主机不在同一个子网/LAN 上,您将无法获取远程主机的 MAC 地址。没关系。大概我们会得到类似 00:00:00:00:00:00 的东西,因为它与本地 MAC 地址不同,所以它会有所不同——这正是我们想要的。

--

所以,总而言之,我们有一个 TCP 连接套接字 fd,我们收到了一个数据包,那么我们如何找到远程主机的 MAC 地址,即包头中的 MAC 地址?

【问题讨论】:

  • 您是否要确定身份?因为我可以想到几种比使用可欺骗 MAC 地址更好的方法
  • 如果本地数据包带有两个不同的 IP 地址,您怎么知道它们不会带有两个不同的 MAC 地址?如果某些数据包通过环回适配器,它们不会到达硬件附近的任何地方,因此根本没有 MAC 地址 (IIRC)。
  • 您是否知道可以仅将服务器绑定到环回接口这一事实?在这种情况下,只有同一台机器上的客户端可以建立连接(并且它们必须使用 127.0.0.1 作为远程地址),无法从另一台机器连接。
  • 当然你说这不是你的设计,但请确保每个人都知道,如果这是出于安全原因,那么它并没有真正起到多大作用。随意更改MAC地址很容易。
  • Hasturkun:是的,我知道这就是为什么我说“首先,请不要批评解决方案。这不是我的设计,是的,它很烂”。米奥先生:我知道。我不是专家,但我认为我们可能会更安全,因为对欺骗 MAC 地址的人的 SYN/ACK 响应不应该靠近欺骗者 - 但就像我说我不是专家一样。我会尽我所能来提高认识,但我怀疑它会产生多大的效果。巴特:好主意。我会建议它,看看会发生什么。

标签: c linux sockets mac-address


【解决方案1】:

如果我理解正确,您并不是要区分远程机器,而是使用源 MAC 和目标 MAC 将匹配从机器发送到其自身的流量的想法到自身,以便允许仅限本地流量。

这似乎相当迂回,并且已被指出不安全。

一个更好的主意可能是让 TCP 客户端只监听环回接口 (127.0.0.1) 而不是 INADDR_ANY。或者更进一步,使用 unix 域套接字而不是 TCP 套接字(当今 X 服务器用来防止远程连接可能性的常用方法)

【讨论】:

  • 有问题的软件是一个 UPNP 服务器,我怀疑他们已经在 UPNP 中包装了我们想要验证的控制请求,因此让它进入同一个 INADDR_ANY 套接字侦听器。请不要评论这是多么愚蠢。我知道。然而,也许我们可以做进一步的破解并将 UPNP 请求发送到 127.0.0.1,即使我们已经在不同的 IP 地址上识别了 UPNP 服务器。
  • 你可以修改哪一端,客户端还是服务器?
  • 两者。问题是因为他们已经将控制请求包装在 UPNP 中(我是对的 - 不幸的是)它将使用双方的所有其他 UPNP 基础设施,并且展开这将非常复杂并涉及架构师等。 . 等等 :( 快速简单的解决方案就是获取连接远程端的 MAC 地址并进行比较。我正在开始使用你的想法,但这需要几周时间——如果我能说服的话他们考虑一下 - 我们已经落后了几周。
  • 修改服务器以监听 tcp 和 unix 套接字,但只接受后者的特殊操作。修改(本地)客户端以在 unix 套接字上连接。
  • 不幸的是,客户端使用相同的 UPNP 代码连接到其他主机上的其他计算机,并且无法进行这种自定义 - 客户端不知道地址 - 它通过 UUID 识别服务器。将这种定制放在堆栈的较低位置将是一个令人讨厌的黑客攻击,更改漂亮的通用 UPNP 代码,因此它仅针对这种情况具有特殊情况。使用环回地址仍然是最好的办法。
【解决方案2】:

实时同子网 TCP 连接的 MAC 地址几乎肯定会在 ARP 缓存中。

在 Linux 上,您可以通过查看 /proc/net/arp 来检查 ARP 缓存。这是它在我的 Ubuntu 盒子上的样子:

aix@aix:~$ cat /proc/net/arp
IP address       HW type     Flags       HW address            Mask     Device
10.0.0.32        0x1         0x2         00:1e:4f:f5:be:dc     *        eth0
10.10.10.1       0x1         0x2         00:1f:6c:3e:02:e3     *        eth0

如果您不愿意解析伪文件,可能有一些可调用的 API 可以用来获取相同的数据。

【讨论】:

  • 如果有桥怎么办?
  • 很遗憾,此文件中仅列出了远程 IP 地址。我想我们可以尝试确认源 IP 地址未列在此文件中,但我认为这不能保证连接来自远程主机。然而,我确实想到我们可以尝试修改代码以扫描盒子上使用的所有 IP 地址并检查我们是否匹配其中任何一个,但这需要更多的代码、工作和难度。
【解决方案3】:

如何配置防火墙(内部或外部)以阻止或 MAC 过滤相关端口上的外部流量?

【讨论】:

  • 查看我对您之前回答的评论。该端口与所有其他 UPNP 流量共享。我相信我们希望从外部访问这个过程,尽管它主要是整个系统的内部组件。
  • 配置防火墙以将外部流量重定向到不同的端口并同时监听?
【解决方案4】:

环回连接(无论是通过环回接口还是其他接口)它没有通过任何以太网设备路由,因此没有与之关联的 MAC 地址

我建议您只使用getsocknamegetpeername 来获取本地和远程IP 地址并比较它们是否相等。这将在没有任何先验知识的情况下工作,您的系统配置的 IP 地址。

此外,如果您想与 IPv4/v6 无关,您可以使用带有 NI_NUMERIC 标志的 getnameinfo 将两个地址转换为数字字符串表示形式和 strcmp 它们。

【讨论】:

  • 这就是我们已经在做的事情,但它不起作用。 getsockname 和 getpeername 返回不同的 IP 地址。我在问题中明确指出有两个 IP 地址,不知何故我们只能在连接的本地端找到一个。因此,我们被引导相信连接来自不同的机器,因为我们不知道套接字另一端的第二个实际上是同一台机器。