原始套接字帮助:为什么内核UDP无法接收由原始套接字创建的UDP数据包? [英] Raw Socket Help: Why UDP packets created by raw sockets are not being received by kernel UDP?

查看:207
本文介绍了原始套接字帮助:为什么内核UDP无法接收由原始套接字创建的UDP数据包?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究原始套接字.我使用IP_HDRINCL选项构建了自己的IP标头.在IP标头之后,我正在构建UDP标头.然后,我将数据包发送到系统的环回地址.我有另一个正在运行的程序,它将在收到UDP数据包时捕获它们.为了检查数据包是否被正确地形成和接收,我正在运行另一个进程,该进程正在读取原始IP数据报.我的问题是,尽管第二个进程(读取原​​始数据报)运行良好(所有IP和UDP字段似乎都可以),但是第一个进程(接收UDP)没有收到我创建的任何数据包. IP标头中的协议字段可以,并且端口也匹配... 我正在使用Linux 2.6.35-22. 我想知道在新内核中这是否正常?请检查以下代码是否有任何错误.应该接收数据包的UDP进程正在侦听绑定到同一台计算机上端口50000的套接字...

I am studying raw sockets. I used the IP_HDRINCL option to build my own IP headers. After the IP header, I am building a UDP header. Then I am sending the packet to my system's loopback address. I have another program running which will catch the UDP packets as they come. To check whether the packets are being correctly formed and received, I have another process running which is reading raw IP datagrams. My problem is that although the second process(reading raw datagrams) is working well(all the IP and UDP fields seem to be okay), but the first process(receiving UDP) is not receiving any of the packets that I created. The protocol field in the IP header is okay and the port also matches... I am using Linux 2.6.35-22. I want to know whether this is normal in new kernels? Please check the code below for any bugs. The UDP process which should receive the packets is listening on a socket bound to port 50000 on the same machine...

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));
}   

推荐答案

UDP校验和的计算似乎存在问题.

There seems to be a problem with the calculation of the UDP check-sum.

udp->check=in_cksum((unsigned short*) udp,8+strlen(data));

UDP校验和必须在UDP头之前包含称为伪头"的内容.该代码仅在UDP报头和有效负载上计算校验和.由于校验和错误,UDP接收进程可能未接收到数据包.

UDP check-sum must include something called the "Pseudo-Header" before the UDP header. The code calculates checksum over only the UDP header and the payload. The UDP receiving process might not be receiving the packets because of the wrong check-sums.

在Wireshark中启用校验和验证,并检查UDP数据包的校验和字段是否正确.

Enable check-sum validation in Wireshark and check whether the check-sum fields of the UDP packets are correct or not.

请参阅以下内容:

  • UDP: Checksum Computation
  • IETF: RFC 768

这篇关于原始套接字帮助:为什么内核UDP无法接收由原始套接字创建的UDP数据包?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆