Linux下网卡接收数据包过滤关闭设置
在设备使用linux操作系统(湖南麒麟)时,当外界通过网络发组播包给该设备对应网卡时,有可能会出现网卡通过socket无法接收网络包的情况。此时在linux下通过tcpdump能够抓到网卡接收到的网络包,只是该网络包未传递给上层应用。出现这种情况时,通常是linux系统下默认对网卡设置了过滤条件,导致底层能收到包,但被上层过滤。可以通过关闭网卡过滤条件进行解决。在/etc/sysctl.conf内
·
1、问题描述
在设备使用linux操作系统(湖南麒麟)时,当外界通过网络发组播包给该设备对应网卡时,有可能会出现网卡通过socket无法接收网络包的情况。此时在linux下通过tcpdump能够抓到网卡接收到的网络包,只是该网络包未传递给上层应用。
2、解决办法
出现这种情况时,通常是linux系统下默认对网卡设置了过滤条件,导致底层能收到包,但被上层过滤。可以通过关闭网卡过滤条件进行解决。
在/etc/sysctl.conf内
设置
net.ipv4.conf.all.rp_filter=0
net.ipv4.conf.default.rp_filter=0
net.ipv4.conf.XXXX(网卡名称).rp_filter=0
添加后重启系统生效。
3、补充说明
如果要通过组播接收,首先需要设置网卡的路由信息,否则网卡底层也无法接收到组播包,可以通过在/etc/rc.local中添加网卡的路由信息,格式如下:
route add -net 224.X.X.X netmask 255.X.X.X dev XXX(网卡名称)
其实掩码255一般不太常用,chatgpt上面有解释
4、测试代码
可以使用下面代码进行测试,验证是否收到数据
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <net/if.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <time.h>
#define IP_SIZE 16 //不要修改
#define UDP_ADDR "224.0.11.10" //组播地址跟据需要修改
#define UDP_PORT 6000 //端口号跟据需要修改
#define ETHX "enp16s0" //不同网卡名需要修改
#define N 2080
#define COLOR_NONE "\033[0m"
#define RED "\033[1;31;40m"
#define errlog(errmsg) do{perror(errmsg);\
printf("%s--%s--%d\n",\
__FILE__, __func__, __LINE__);\
exit(1);\
}while(0)
int get_local_ip(const char *eth_inf, char *ip)
{
int sd;
struct sockaddr_in sin;
struct ifreq ifr;
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == sd)
{
printf("socket error: %s\n", strerror(errno));
return -1;
}
strncpy(ifr.ifr_name, eth_inf, IFNAMSIZ);
ifr.ifr_name[IFNAMSIZ - 1] = 0;
// if error: No such device
if (ioctl(sd, SIOCGIFADDR, &ifr) < 0)
{
printf("ioctl error: %s\n", strerror(errno));
close(sd);
return -1;
}
memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
snprintf(ip, IP_SIZE, "%s", inet_ntoa(sin.sin_addr));
close(sd);
return 0;
}
int main()
{
int sockfd;
struct sockaddr_in groupcastaddr, addr;
socklen_t addrlen = sizeof(groupcastaddr);
char buf[N] = {};
int i,j = 0;
char ip[IP_SIZE];
unsigned int Num = 0;
unsigned char Slot = 0;
unsigned int Count =0;
int time_interval=0;
time_t time1 = time(NULL);;
time_t time2 = time(NULL);
//第一步:创建套接字
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
errlog("fail to socket");
}
//第二步:填充组播网络信息结构体
//inet_addr:将点分十进制ip地址转化为网络字节序的整型数据
//htons:将主机字节序转化为网络字节序
//atoi:将数字型字符串转化为整型数据
groupcastaddr.sin_family = AF_INET;
groupcastaddr.sin_addr.s_addr = inet_addr(UDP_ADDR); //224-239
groupcastaddr.sin_port = htons(UDP_PORT);
//第三步:将套接字与服务器网络信息结构体绑定
if(bind(sockfd, (struct sockaddr *)&groupcastaddr, addrlen) < 0)
{
errlog("fail to bind");
}
get_local_ip(ETHX, ip);
printf("local %s ip: %s\n", ETHX, ip);
//加入多播组,允许数据链路层处理指定数据包
struct ip_mreq mreq;
struct in_addr inaddr = {0};
inaddr.s_addr = inet_addr(ip);
mreq.imr_interface.s_addr = inaddr.s_addr;
mreq.imr_multiaddr.s_addr = inet_addr(UDP_ADDR);
//mreq.imr_interface.s_addr = htonl(INADDR_ANY);
//mreq.imr_interface.s_addr = inet_addr("192.160.82.99");
if(setsockopt(sockfd, IPPROTO_IP,IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
{
errlog("fail to setsockopt");
}
ssize_t bytes;
while(1)
{
if((bytes = recvfrom(sockfd, buf, N, 0,(struct sockaddr *)&addr, &addrlen)) < 0)
{
errlog("fail to recvfrom");
}
else
{
time1 = time(NULL);
//printf("%d \n",time1);//第N个包时刻
time_interval = time1 - time2; // 时间差
//printf("%d \n",time_interval);
time2 = time1;//第N-1个包的时刻
Count++;
printf("########################################\
##########################################\n");
printf("ip: %s, port: %d Count:%d ",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port),Count);
if( (time_interval < 6) )
{
printf(RED"Rcv_Packet_Interval: %d \n"COLOR_NONE,time_interval);
}
else
{
printf(RED"Rcv_Packet_Interval: ERROR ERROR ERROR \n"COLOR_NONE);
}
for(i=0;i<bytes;i++)
{
printf("%02x ",buf[i]);
}
}
}
close(sockfd);
return 0;
}
更多推荐
已为社区贡献7条内容
所有评论(0)