OSX 上的 AF_PACKET

lan*_*ng2 7 sockets macos

在 Linux 上,可以使用 AF_PACKET 创建套接字以从套接字接收原始数据并在应用程序中进行 IP 过滤。但是 OSX 中的手册页没有这个:

       PF_LOCAL        Host-internal protocols, formerly called PF_UNIX,
       PF_UNIX         Host-internal protocols, deprecated, use PF_LOCAL,
       PF_INET         Internet version 4 protocols,
       PF_ROUTE        Internal Routing protocol,
       PF_KEY          Internal key-management function,
       PF_INET6        Internet version 6 protocols,
       PF_SYSTEM       System domain,
       PF_NDRV         Raw access to network device
Run Code Online (Sandbox Code Playgroud)

这不是POSIX标准接口吗?如何在 OSX 上实现同样的效果?

Mec*_*cki 6

任何协议都不是 POSIX 标准。POSIX 不要求系统支持任何特定的网络协议或根本不支持任何网络协议。

\n

AF_PACKETAFAIK 是纯粹的 Linux 发明,您在其他系统上找不到它。

\n

BPF(Berkley Packet Filters)也不是 POSIX,它是一个 BSD 发明,许多系统都复制了它,因为它非常方便。但是,您不能用它注入流量,只能用它捕获传入和传出流量。

\n

如果有人关心,这里是最新的 POSIX 标准:
\n Open Group 基本规范第 7 期,2018 年版
\nIEEE Std 1003.1\xe2\x84\xa2-2017(IEEE Std 1003.1-2008 的修订版)

\n

如果您确实想要发送原​​始 IP 数据包(无论是 IPv4 还是 IPv6),使用原始 IP 套接字是最便携的:

\n
int soc = socket(PF_INET, SOCK_RAW, IPPROTO_IP);\n
Run Code Online (Sandbox Code Playgroud)\n

然后你需要告诉系统你想要提供你自己的 IP 标头:

\n
int yes = 1;\nsetsockopt(soc, IPPROTO_IP, IP_HDRINCL, &yes, sizeof(yes));\n
Run Code Online (Sandbox Code Playgroud)\n

现在您可以将原始 IP 数据包(例如 IP 标头 + UDP 标头 + 有效负载数据)发送到套接字进行发送,但是,根据您的系统,系统将执行一些健全性检查,并可能覆盖标头中的某些字段。例如,它可能不允许您创建格式错误的 IP 数据包或阻止您执行 IP 地址欺骗。0.0.0.0因此,它可以为您计算 IPv4 标头校验和,或者如果您的 IP 标头使用或作为源地址,则自动填写正确的源地址::。检查目标系统上的ip(4)手册页。raw(7)Apple 不再提供 macOS 的程序员手册页,但您可以在线找到它们。

\n

引用该手册页:

\n
\n

与以前的 BSD 版本不同,该程序必须设置 IP 标头的所有字段,包括以下内容:

\n
 ip->ip_v = IPVERSION;\n ip->ip_hl = hlen >> 2;\n ip->ip_id = 0;  /* 0 means kernel set appropriate value */\n ip->ip_off = offset;\n ip->ip_len = len;\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,ip_offip_len字段采用主机字节顺序

\n

如果标头源地址设置为INADDR_ANY,内核将\n选择一个适当的地址。

\n
\n

请注意,ip_sum根本没有提及这一点,因此显然您不必提供该信息,系统将始终为您计算。

\n

如果将其与 Linux raw(7)进行比较:

\n
\n
\xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\n\xe2\x94\x82IP Header fields modified on sending by IP_HDRINCL \xe2\x94\x82\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xa4\n\xe2\x94\x82IP Checksum           \xe2\x94\x82 Always filled in           \xe2\x94\x82\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xbc\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xa4\n\xe2\x94\x82Source Address        \xe2\x94\x82 Filled in when zero        \xe2\x94\x82\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xbc\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xa4\n\xe2\x94\x82Packet ID             \xe2\x94\x82 Filled in when zero        \xe2\x94\x82\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xbc\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xa4\n\xe2\x94\x82Total Length          \xe2\x94\x82 Always filled in           \xe2\x94\x82\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xb4\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\n
Run Code Online (Sandbox Code Playgroud)\n
\n

当从原始 IP 套接字接收时,您将获得到达主机的所有传入 IP 数据包或仅获得其中的一个子集(例如,Windows 确实支持原始套接字,但永远不会让您发送或接收 TCP 数据包)。您将收到完整的数据包,包括所有标头,因此收到的每个数据包的第一个字节是 IP 标头的第一个字节。

\n

这里有人会问我为什么用IPPROTO_IP而不用IPPROTO_RAW。使用时IPPROTO_RAW无需设置IP_HDRINCL

\n
\n

协议IPPROTO_RAW暗示已启用IP_HDRINCL,并且能够发送在传递的标头中指定的任何 IP 协议。

\n
\n

但您只能用于IPPROTO_RAW传出流量:

\n
\n

套接字IPPROTO_RAW仅用于发送。

\n
\n

在 macOS 上您可以使用IPPROTO_IP并且您将收到所有 IP 数据包,但在 Linux 上这可能不起作用,因此创建了一个新的套接字PF_PACKET套接字类型。在两个系统上都应该工作的是指定一个子协议:

\n
int soc = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);\n
Run Code Online (Sandbox Code Playgroud)\n

当然,现在您只能通过该套接字发送/接收 UDP 数据包。如果再次设置IP_HDRINCL,则需要在发送时提供完整的 IP 标头,并且在接收时您将收到完整的 IP 标头。如果你不设置它,你可以只在发送时提供 UDP 标头,系统将添加一个 IP 标头本身,也就是说,如果套接字已连接并且可选地绑定,那么系统知道在该套接字中使用哪些地址标头。对于接收该选项不起作用,您始终会获取在此类套接字上收到的每个 UDP 数据包的 IP 标头。

\n

如果人们想知道我为什么使用PF_INET而不使用AF_INET:PF 表示协议族,AF 表示地址族。通常这些是相同的(例如AF_INET == PF_INET),所以你使用什么并不重要,但严格来说,应该创建套接字,并且应该设置结构PF_中的族,因为有一天可能会有一种协议支持两种不同的协议地址,然后就会有和,并且两者都不可能与 相同。sockaddrAF_AF_XXX1AF_XXX2PF_XXX

\n


Rob*_*ore 2

AF_PACKET不幸的是,OS X 上不存在。相反,您应该使用/dev/bpfX(伯克利数据包过滤器),它允许您捕获数据包。有关更多信息,请阅读:https ://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man4/bpf.4.html