在 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 上实现同样的效果?
任何协议都不是 POSIX 标准。POSIX 不要求系统支持任何特定的网络协议或根本不支持任何网络协议。
\nAF_PACKET
AFAIK 是纯粹的 Linux 发明,您在其他系统上找不到它。
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 的修订版)
如果您确实想要发送原始 IP 数据包(无论是 IPv4 还是 IPv6),使用原始 IP 套接字是最便携的:
\nint soc = socket(PF_INET, SOCK_RAW, IPPROTO_IP);\n
Run Code Online (Sandbox Code Playgroud)\n然后你需要告诉系统你想要提供你自己的 IP 标头:
\nint 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 标头的所有字段,包括以下内容:
\nRun Code Online (Sandbox Code Playgroud)\nip->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
请注意,
\nip_off
和ip_len
字段采用主机字节顺序。如果标头源地址设置为
\nINADDR_ANY
,内核将\n选择一个适当的地址。
请注意,ip_sum
根本没有提及这一点,因此显然您不必提供该信息,系统将始终为您计算。
如果将其与 Linux raw(7)进行比较:
\n\n\nRun Code Online (Sandbox Code Playgroud)\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
当从原始 IP 套接字接收时,您将获得到达主机的所有传入 IP 数据包或仅获得其中的一个子集(例如,Windows 确实支持原始套接字,但永远不会让您发送或接收 TCP 数据包)。您将收到完整的数据包,包括所有标头,因此收到的每个数据包的第一个字节是 IP 标头的第一个字节。
\n这里有人会问我为什么用IPPROTO_IP
而不用IPPROTO_RAW
。使用时IPPROTO_RAW
无需设置IP_HDRINCL
:
\n\n协议
\nIPPROTO_RAW
暗示已启用IP_HDRINCL
,并且能够发送在传递的标头中指定的任何 IP 协议。
但您只能用于IPPROTO_RAW
传出流量:
\n\n套接字
\nIPPROTO_RAW
仅用于发送。
在 macOS 上您可以使用IPPROTO_IP
并且您将收到所有 IP 数据包,但在 Linux 上这可能不起作用,因此创建了一个新的套接字PF_PACKET
套接字类型。在两个系统上都应该工作的是指定一个子协议:
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 标头。
如果人们想知道我为什么使用PF_INET
而不使用AF_INET
:PF 表示协议族,AF 表示地址族。通常这些是相同的(例如AF_INET == PF_INET
),所以你使用什么并不重要,但严格来说,应该创建套接字,并且应该设置结构PF_
中的族,因为有一天可能会有一种协议支持两种不同的协议地址,然后就会有和,并且两者都不可能与 相同。sockaddr
AF_
AF_XXX1
AF_XXX2
PF_XXX
AF_PACKET
不幸的是,OS X 上不存在。相反,您应该使用/dev/bpfX
(伯克利数据包过滤器),它允许您捕获数据包。有关更多信息,请阅读:https ://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man4/bpf.4.html
归档时间: |
|
查看次数: |
7557 次 |
最近记录: |