使用Linux原始套接字捕获PTP数据包

使用Linux原始套接字捕获PTP数据包,linux,ethernet,raw-sockets,bpf,Linux,Ethernet,Raw Sockets,Bpf,我想实现一个捕获以太网上所有精确时间协议(PTP)帧的C程序,因此我创建了一个原始套接字并附加了一个PTP过滤器,我使用recvmsg()从套接字读取数据。 第一个问题是我没有收到任何PTP帧,所以我注释掉了过滤器,但现在我也没有收到任何以太网帧 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #如果名称为“enx503eaa33fc9d”,则定义PTP #定义数据包大小300 #每行定义\u块的数量\u #定义块3的大小 #定义打印缓冲区的大小\

我想实现一个捕获以太网上所有精确时间协议(PTP)帧的C程序,因此我创建了一个原始套接字并附加了一个PTP过滤器,我使用recvmsg()从套接字读取数据。 第一个问题是我没有收到任何PTP帧,所以我注释掉了过滤器,但现在我也没有收到任何以太网帧

#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#如果名称为“enx503eaa33fc9d”,则定义PTP
#定义数据包大小300
#每行定义\u块的数量\u
#定义块3的大小
#定义打印缓冲区的大小\
((每行块数*BYYE打印块大小)+1)
#定义PERROR(x,…)printf(x“stderr:%m\n”,####VA_uargs_uuu)
#定义信息(x,…)printf
#定义错误(x,…)printf(x“\n”、###
int-eventSock=-1;
无效打印缓冲区(无符号字符*缓冲区,大小){
无符号字符溢出器[打印缓冲区的大小];
无符号字符*pOutBuffer=exputffer;
int usedBytes=0;
对于(int i=0;i打印缓冲区的大小){
信息(“%s”,突发事件);
memset(突发,0,sizeof(突发));
usedBytes=0;
pOutBuffer=突出物;
}
sprintf(pOutBuffer,“%02x”,缓冲区[i]);
usedBytes+=字节打印块的大小;
pOutBuffer+=BYYE打印块的大小;
}
信息(“%s”,突发事件);
}
int getInterfaceIndex(字符*ifaceName){
int-sockfd;
结构ifreq-ifr;
sockfd=插座(AF_INET,SOCK_DGRAM,0);
if(sockfd<0){
错误(“无法检索%s的接口索引”,ifaceName);
返回-1;
}
memset(&ifr,0,sizeof(ifr));
strncpy(ifr.ifr_名称、ifaceName、IFNAMSIZ);
如果(ioctl(sockfd、SIOCGIFINDEX和ifr)<0){
PERROR(“无法请求%s的硬件地址”,ifaceName);
关闭(sockfd);
返回-1;
}
关闭(sockfd);
返回ifr.ifr\u ifindex;
}
bool InitSocket(char*ifaceName){
国际指数;
结构sockaddr\u ll sll;
IfIndex=获取接口索引(ifaceName);
如果(i指数<0){
返回false;
}
/*创建套接字*/
if((eventSock=socket(AF_数据包,SOCK_原始,htons(ETH_P_全部)))<0){
PERROR(“未能初始化原始套接字”);
返回false;
}
/*绑定到接口*/
memset(&sll,0,sizeof(sll));
sll.sll_family=AF_数据包;
sll.sll_ifindex=ifindex;
sll.sll_协议=HTON(ETH_P_ALL);
/*将套接字绑定到接口*/
if(bind(eventSock,(struct sockaddr*)&sll,sizeof(sll))<0){
PERROR(“绑定原始事件套接字失败”);
返回false;
}
/*仅过滤PTP数据包的bpf字节码(以太网类型0x88f7)
*通过“tcpdump-dd乙醚协议0x88f7”获取*/
//结构sock_filter_ptp[]={
//{0x28,0,0,0x0000000c},//ldh[12]
//{0x15,0,1,0x000088f7},//jeq#0x88f7 jt 2 jf 3
//{0x06,0,0,0x00040000},//ret#262144
//{0x06,0,0,0x00000000},//ret#0
//  };
//
//结构sock_fprog bpf_ptp={.len=4,.filter=filter_ptp,};
//
//if(设置套接字选项)(事件套接字、SOL_套接字、SO_连接过滤器和bpf_ptp、,
//sizeof(bpf_ptp))){
//PERROR(“将筛选器连接到原始事件套接字失败”);
//返回false;
//  }
}
int waitForData(结构timeval*timeout,fd_set*readfds){
int ret,nfds;
结构时间值tv,*tv\u ptr;
如果(超时){
tv.tv_sec=超时->tv_sec;
tv.tv\u usec=超时->tv\u usec;
tv_ptr=&tv;
}否则{
tv_ptr=NULL;
}
FD_零(读取FDS);
nfds=0;
FD_集(eventSock、readfds);
nfds=eventSock;
nfds++;
ret=选择(NFD、readfds、0、0、tv_ptr);
返回ret;
}
无效网络(无效){
ssize_t ret=0;
char-buf[1024];
结构msghdr msg;
结构iovec vec[1];
结构sockaddr\u在from\u addr中;
联合{
结构cmsghdr-cm;
字符控制[256];
}cmsg_un;
结构cmsghdr*cmsg;
vec[0].iov_base=buf;
vec[0]。iov_len=数据包大小;
memset(&msg,0,sizeof(msg));
memset(&from_addr,0,sizeof(from_addr));
memset(buf,0,数据包大小);
memset(&cmsg_un,0,sizeof(cmsg_un));
msg.msg_name=(caddr_t)&来自地址;
msg.msg\u namelen=sizeof(来自地址);
msg.msg_iov=vec;
msg.msg_iovlen=1;
msg.msg_control=cmsg_un.control;
msg.msg\u controllen=sizeof(cmsg\u un.control);
msg.msg_标志=0;
ret=recvmsg(eventSock,&msg,msg_DONTWAIT);
如果(ret<0){
PERROR(“接收消息失败!”);
}
信息(“收到的字节数:%ld”,ret);
打印缓冲区(msg.msg\u iov->iov\u base,数据包大小);
}
内部主(空){
int ret;
fd_设置读取FDS;
struct timeval timeout={.tv_sec=1.tv_usec=0};
信息(“主启动!!”;
InitSocket(PTP_IF_NAME);
而(1){
信息(“等待事件!!”;
ret=waitForData(&timeout,&readfds);
信息(“选择返回=%d”,返回);
如果(ret>0){
if(FD_ISSET(eventSock和readfds)){
netr();
}
}
}
}

您的代码本身似乎没有问题。可以通过在localhost界面上运行程序来验证这一点,例如,仅更改以下行:

#如果名称为“lo”,则定义PTP#U
通过发送帧,
ping 127.0.0.1

根据评论中的讨论,当Wireshark运行并在接口上转储数据包时,您显然可以看到帧,但它在其余时间不起作用。这可能是一个迹象,表明您需要将界面设置为“混杂模式”

杂乱模式告诉你的卡捕获所有的数据包,即使是那些
$ sudo ip link set enx503eaa33fc9d promisc on