Raw Socket Help: Why UDP packets created by raw so

2020-02-29 02:01发布

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

2条回答
你好瞎i
2楼-- · 2020-02-29 02:34

Ive tried something very similar. The problem is that the socket API and by extension any programs that use them, donot return data that is being WRITTEN by the interface unlike raw sockets used by sniffers like wiresharks/tcpdump which do. So, even though your packets are formed correctly, they are not being read by the UDP application. If you have another computer on the network, use one to generate the traffic and the other to read it. Alternatively if you have two interfaces, you could open a raw socket on each... one for writing and the other for reading.

查看更多
三岁会撩人
3楼-- · 2020-02-29 02:36

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 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.

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

See the following:

查看更多
登录 后发表回答