Linux kernel 原始套接字帮助:为什么内核UDP不接收由原始套接字创建的UDP数据包?
我正在研究原始套接字。我使用IP_HDRINCL选项构建自己的IP头。在IP报头之后,我正在构建一个UDP报头。然后我将数据包发送到系统的环回地址。我有另一个程序正在运行,它将捕获UDP数据包。为了检查数据包是否正确形成和接收,我运行了另一个进程,它正在读取原始IP数据报。我的问题是,尽管第二个进程(读取原始数据报)运行良好(所有IP和UDP字段似乎都正常),但第一个进程(接收UDP)没有接收我创建的任何数据包。IP头中的协议字段正常,端口也匹配。。。 我使用的是Linux 2.6.35-22。 我想知道这在新内核中是否正常?请检查下面的代码是否有任何错误。应该接收数据包的UDP进程正在同一台机器上绑定到端口50000的套接字上侦听Linux kernel 原始套接字帮助:为什么内核UDP不接收由原始套接字创建的UDP数据包?,linux-kernel,udp,raw-sockets,Linux Kernel,Udp,Raw Sockets,我正在研究原始套接字。我使用IP_HDRINCL选项构建自己的IP头。在IP报头之后,我正在构建一个UDP报头。然后我将数据包发送到系统的环回地址。我有另一个程序正在运行,它将捕获UDP数据包。为了检查数据包是否正确形成和接收,我运行了另一个进程,它正在读取原始IP数据报。我的问题是,尽管第二个进程(读取原始数据报)运行良好(所有IP和UDP字段似乎都正常),但第一个进程(接收UDP)没有接收我创建的任何数据包。IP头中的协议字段正常,端口也匹配。。。 我使用的是Linux 2.6.35-22。
unsigned short in_cksum(unsigned short *addr, int len)
{
int nleft = len;
int sum = 0;
unsigned short *w = addr;
unsigned short answer = 0;
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
if (nleft == 1) {
*(unsigned char *) (&answer) = *(unsigned char *) w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}
main()
{
int fd=socket(AF_INET,SOCK_RAW,IPPROTO_UDP);
int val=1;
int ret=setsockopt(fd,IPPROTO_IP,IP_HDRINCL,&val,sizeof(val));
char buf[8192];
/* create a IP header */
struct iphdr* ip=(struct iphdr*)buf;//(struct iphdr*) malloc(sizeof(struct iphdr));
ip->version=4;
ip->ihl=5;
ip->tos=0;
ip->id=0;
ip->frag_off=0;
ip->ttl=255;
ip->protocol=IPPROTO_UDP;
ip->check=0;
ip->saddr=inet_addr("1.2.3.4");
ip->daddr=inet_addr("127.0.0.1");
struct udphdr* udp=(struct udphdr*)(buf+sizeof(struct iphdr));//(struct udphdr*) malloc(sizeof(struct udphdr));
udp->source=htons(40000);
udp->dest=htons(50000);
udp->check=0;
char* data=(char*)buf+sizeof(struct iphdr)+sizeof(struct udphdr);strcpy(data,"Harry Potter and the Philosopher's Stone");
udp->len=htons(sizeof(struct udphdr)+strlen(data));
udp->check=in_cksum((unsigned short*) udp,8+strlen(data));
ip->tot_len=htons(sizeof(struct iphdr)+sizeof(struct udphdr)+strlen(data));
struct sockaddr_in d;
bzero(&d,sizeof(d));
d.sin_family=AF_INET;
d.sin_port=htons(50000);
inet_pton(AF_INET,"localhost",&d.sin_addr.s_addr);
while(1)
sendto(fd,buf,sizeof(struct iphdr)+sizeof(struct udphdr)+strlen(data),0,(struct sockaddr*) &d,sizeof(d));
}
我也试过类似的方法。问题在于,套接字API及其扩展版的任何使用它们的程序都不会返回接口正在编写的数据,不像wiresharks/tcpdump等嗅探器使用的原始套接字那样。因此,即使数据包的格式正确,UDP应用程序也不会读取它们。
如果网络上有另一台计算机,请使用其中一台生成流量,另一台读取流量。或者,如果您有两个接口,您可以在每个接口上打开一个原始套接字。。。一个用于写入,另一个用于读取。UDP校验和的计算似乎有问题
udp->check=in_cksum((unsigned short*) udp,8+strlen(data));
UDP校验和必须在UDP报头之前包含称为“伪报头”的内容。该代码仅计算UDP报头和有效负载上的校验和。由于校验和错误,UDP接收进程可能未接收数据包
在Wireshark中启用校验和验证,并检查UDP数据包的校验和字段是否正确
见下文: