Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Macos OSX上的AF_数据包_Macos_Sockets - Fatal编程技术网

Macos OSX上的AF_数据包

Macos OSX上的AF_数据包,macos,sockets,Macos,Sockets,在Linux上,可以使用AF_数据包创建套接字,以从套接字接收原始数据,并在应用程序中进行IP过滤。但是OSX中的手册页没有: PF_LOCAL Host-internal protocols, formerly called PF_UNIX, PF_UNIX Host-internal protocols, deprecated, use PF_LOCAL, PF_INET Internet version

在Linux上,可以使用AF_数据包创建套接字,以从套接字接收原始数据,并在应用程序中进行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

这不是POSIX标准接口吗?如何在OSX上实现同样的功能?不幸的是,OSX上不存在AF\U数据包。相反,您应该使用
/dev/bpfX
(Berkeley数据包过滤器),这将允许您捕获数据包。更多信息,请阅读:

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

AF_PACKET
是纯Linux的发明,在其他系统上是找不到的

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

如果有人关心,下面是最新的POSIX标准:

如果您确实希望发送原始IP数据包(无论是IPv4还是IPv6),则使用原始IP套接字是最方便的:

int soc = socket(PF_INET, SOCK_RAW, IPPROTO_IP);
然后,您需要告诉系统,您希望提供自己的IP头:

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

引用该手册页:

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

 ip->ip_v = IPVERSION;
 ip->ip_hl = hlen >> 2;
 ip->ip_id = 0;  /* 0 means kernel set appropriate value */
 ip->ip_off = offset;
 ip->ip_len = len;
请注意,
ip\u off
ip\u len
字段的主机字节顺序为

如果头源地址设置为
INADDR\u ANY
,内核将 选择一个合适的地址

请注意,
ip_sum
一点也没有提到,因此显然您不必提供该值,系统将始终为您计算该值

如果将其与Linux进行比较:

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

这里的一些人会问我为什么使用
IPPROTO\u IP
而不是
IPPROTO\u RAW
。使用
IPPROTO\u RAW
时,您不必设置
IP\u HDRINCL

IPPROTO\u RAW
协议意味着启用
IP\u HDRINCL
,并且能够 发送在传递的标头中指定的任何IP协议

但您只能对传出流量使用
IPPROTO_RAW

仅发送
IPPROTO\u原始
套接字

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

int soc = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
当然,现在您只能通过该套接字发送/接收UDP数据包。如果再次设置
IP_HDRINCL
,则需要在发送时提供完整的IP头,在接收时将收到完整的IP头。如果不进行设置,只需在发送时提供UDP报头,系统将添加一个IP报头本身,也就是说,如果套接字已连接并可选择绑定,那么系统将知道在该报头中使用哪些地址。由于接收该选项不起任何作用,因此您始终会获得在此类套接字上接收的每个UDP数据包的IP头


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

如果您想在Mac OS X上发送原始以太网帧(例如,您自己的链路级协议,而不是IP),则可以使用类似于PF_raw的套接字:

#include <sys/socket.h>
#include <net/if.h>
#include <net/ndrv.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <net/ethernet.h>

int main (int argc, char **argv) {

   if (geteuid()) { fprintf(stderr,"No root, no service\n"); exit(1); }
   int s = socket(PF_NDRV,SOCK_RAW,0);
   if (s < 0) { perror ("socket"); exit(2); }

   uint16_t   etherType = ntohs(atoi(argv[1]));
   struct sockaddr_ndrv    sa_ndrv;

   strlcpy((char *)sa_ndrv.snd_name, "en0", sizeof (sa_ndrv.snd_name));
   sa_ndrv.snd_family = PF_NDRV;
   sa_ndrv.snd_len = sizeof (sa_ndrv);

   rc = bind(s, (struct sockaddr *) &sa_ndrv, sizeof(sa_ndrv));

   if (rc < 0) { perror ("bind"); exit (3);}

   char packetBuffer[2048];

#ifdef LISTENER
   struct ndrv_protocol_desc desc;
   struct ndrv_demux_desc demux_desc[1];
   memset(&desc, '\0', sizeof(desc));
   memset(&demux_desc, '\0', sizeof(demux_desc));

   /* Request kernel for demuxing of one chosen ethertype */
   desc.version = NDRV_PROTOCOL_DESC_VERS;
   desc.protocol_family = atoi(argv[1]);
   desc.demux_count = 1;
   desc.demux_list = (struct ndrv_demux_desc*)&demux_desc;
   demux_desc[0].type = NDRV_DEMUXTYPE_ETHERTYPE;
   demux_desc[0].length = sizeof(unsigned short);
   demux_desc[0].data.ether_type = ntohs(atoi(argv[1]));

   if (setsockopt(s, 
        SOL_NDRVPROTO, 
        NDRV_SETDMXSPEC, 
     (caddr_t)&desc, sizeof(desc))) {
      perror("setsockopt"); exit(4);
   }
   /* Socket will now receive chosen ethertype packets */
   while ((rc = recv (s, packetBuffer, 2048, 0) ) > 0 ) {
    printf("Got packet\n"); // remember, this is a PoC..
   }
#else
   memset(packetBuffer, '\xff', 12);
   memcpy(packetBuffer + 12, &etherType, 2);
   strcpy(packetBuffer,"NDRV is fun!");
   rc = sendto (s, packetBuffer, 20, 0, 
        (struct sockaddr *)&sa_ndrv, sizeof(sa_ndrv));
   if (rc < 0) { perror("sendto"); }
#endif
} 
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main(int argc,字符**argv){
if(geteuid()){fprintf(stderr,“没有根,没有服务”\n”);退出(1);}
int s=插座(PF_NDRV,SOCK_RAW,0);
如果(s<0){perror(“socket”);退出(2);}
uint16_t etherType=ntohs(atoi(argv[1]);
结构sockaddr_ndrv sa_ndrv;
strlcpy((char*)sa_ndrv.snd_name,“en0”,sizeof(sa_ndrv.snd_name));
sau ndrv.snd_family=PF_ndrv;
sa_ndrv.snd_len=sizeof(sa_ndrv);
rc=bind(s,(struct sockaddr*)和sau ndrv,sizeof(sau ndrv));
如果(rc<0){perror(“bind”);退出(3);}
char packetBuffer[2048];
#ifdef侦听器
结构ndrv_协议描述;
结构ndrv_demux_desc demux_desc[1];
memset(&desc,'\0',sizeof(desc));
memset(&demux_desc,'\0',sizeof(demux_desc));
/*请求内核对所选ethertype进行解复用*/
desc.version=NDRV_协议_desc_VERS;
desc.protocol_family=atoi(argv[1]);
desc.demux_count=1;
desc.demux_list=(结构ndrv_demux_desc*)和dem
#include <sys/socket.h>
#include <net/if.h>
#include <net/ndrv.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <net/ethernet.h>

int main (int argc, char **argv) {

   if (geteuid()) { fprintf(stderr,"No root, no service\n"); exit(1); }
   int s = socket(PF_NDRV,SOCK_RAW,0);
   if (s < 0) { perror ("socket"); exit(2); }

   uint16_t   etherType = ntohs(atoi(argv[1]));
   struct sockaddr_ndrv    sa_ndrv;

   strlcpy((char *)sa_ndrv.snd_name, "en0", sizeof (sa_ndrv.snd_name));
   sa_ndrv.snd_family = PF_NDRV;
   sa_ndrv.snd_len = sizeof (sa_ndrv);

   rc = bind(s, (struct sockaddr *) &sa_ndrv, sizeof(sa_ndrv));

   if (rc < 0) { perror ("bind"); exit (3);}

   char packetBuffer[2048];

#ifdef LISTENER
   struct ndrv_protocol_desc desc;
   struct ndrv_demux_desc demux_desc[1];
   memset(&desc, '\0', sizeof(desc));
   memset(&demux_desc, '\0', sizeof(demux_desc));

   /* Request kernel for demuxing of one chosen ethertype */
   desc.version = NDRV_PROTOCOL_DESC_VERS;
   desc.protocol_family = atoi(argv[1]);
   desc.demux_count = 1;
   desc.demux_list = (struct ndrv_demux_desc*)&demux_desc;
   demux_desc[0].type = NDRV_DEMUXTYPE_ETHERTYPE;
   demux_desc[0].length = sizeof(unsigned short);
   demux_desc[0].data.ether_type = ntohs(atoi(argv[1]));

   if (setsockopt(s, 
        SOL_NDRVPROTO, 
        NDRV_SETDMXSPEC, 
     (caddr_t)&desc, sizeof(desc))) {
      perror("setsockopt"); exit(4);
   }
   /* Socket will now receive chosen ethertype packets */
   while ((rc = recv (s, packetBuffer, 2048, 0) ) > 0 ) {
    printf("Got packet\n"); // remember, this is a PoC..
   }
#else
   memset(packetBuffer, '\xff', 12);
   memcpy(packetBuffer + 12, &etherType, 2);
   strcpy(packetBuffer,"NDRV is fun!");
   rc = sendto (s, packetBuffer, 20, 0, 
        (struct sockaddr *)&sa_ndrv, sizeof(sa_ndrv));
   if (rc < 0) { perror("sendto"); }
#endif
}