linux-kernel - 原始套接字帮助 : Why UDP packets created by raw sockets are not being received by kernel UDP?

标签 linux-kernel udp raw-sockets

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

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校验和的计算似乎有问题。

udp->check=in_cksum((unsigned short*) udp,8+strlen(data));
UDP 校验和必须在 UDP header 之前包含称为“伪 header ”的内容。该代码仅计算 UDP header 和有效负载的校验和。由于错误的校验和,UDP 接收进程可能无法接收数据包。
在 Wireshark 中启用校验和验证,检查 UDP 数据包的校验和字段是否正确。
请参阅以下内容:
  • UDP: Checksum Computation
  • IETF: RFC 768
  • 关于linux-kernel - 原始套接字帮助 : Why UDP packets created by raw sockets are not being received by kernel UDP?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5689238/

    相关文章:

    sockets - UDP 代理,如何维护/重用/清除连接的客户端池?

    c - "SO_REUSEPORT"(OS X) 或 "SO_REUSEADDR"(Linux) 真的允许用户对多个套接字使用 recvfrom 吗?

    无法使用 libpcap 捕获数据包

    c - sendto 需要很多时间

    python - 在 Python 2.x 中同时连接和处理多个原始套接字

    c - 如何使用 EXPORT_SYMBOL 或等效项在两个内核模块之间导出结构?

    linux-kernel - 为什么每秒进行一次非自愿上下文切换?

    java - Java中的UDP认为UDP有 "connections"

    c - 使用 __SYSCALL_DEFINEx 的单个宏定义中的多个值

    linux - USB端口在Gentoo Linux中不起作用