美文网首页
C编程 - 使用raw socket发送UDP报文

C编程 - 使用raw socket发送UDP报文

作者: louyang | 来源:发表于2018-05-29 09:45 被阅读177次
    /*
     * Raw UDP sockets
     */
    #include <stdio.h>       //printf
    #include <string.h>      //memset
    #include <sys/socket.h>  //socket
    #include <stdlib.h>      //exit
    #include <errno.h>       //errno
    #include <netinet/udp.h> //udp header
    #include <netinet/ip.h>  //ip header
    #include <arpa/inet.h>   //inet_addr
    
    #define SRCIP "10.107.115.114"
    #define DSTIP "123.0.0.3"
    
    /*
     * 96 bit (12 bytes) pseudo header
     * needed for udp header checksum calculation
    */
    struct pseudo_header
    {
        u_int32_t source_address;
        u_int32_t dest_address;
        u_int8_t placeholder;
        u_int8_t protocol;
        u_int16_t udp_length;
    };
    
    /*
     * Generic checksum calculation function
     */
    unsigned short csum(unsigned short *ptr, int nbytes)
    {
        register long sum;
        unsigned short oddbyte;
        register short answer;
    
        sum=0;
        while(nbytes>1) {
            sum+=*ptr++;
            nbytes-=2;
        }
        if(nbytes==1) {
            oddbyte=0;
            *((u_char*)&oddbyte)=*(u_char*)ptr;
            sum+=oddbyte;
        }
    
        sum = (sum>>16)+(sum & 0xffff);
        sum = sum + (sum>>16);
        answer=(short)~sum;
    
        return(answer);
    }
    
    void die(char *s)
    {
        perror(s);
        exit(1);
    }
    
    int main(void)
    {
        int s = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);
        if (s < 0)
            die("socket()");
    
        char datagram[4096], *pseudogram;
        memset(datagram, 0, 4096);
    
        struct iphdr *iph = (struct iphdr *)datagram;
        struct udphdr *udph = (struct udphdr *)(datagram + sizeof(struct ip));
        char *data = datagram + sizeof(struct iphdr) + sizeof(struct udphdr);
        strcpy(data , "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    
        struct pseudo_header psh;
        char source_ip[32] = SRCIP;
    
        struct sockaddr_in sin;
        sin.sin_family = AF_INET;
        sin.sin_port = htons(80);
        sin.sin_addr.s_addr = inet_addr(DSTIP);
    
        //Fill in the IP Header
        iph->ihl = 5;
        iph->version = 4;
        iph->tos = 0;
        iph->tot_len = sizeof (struct iphdr) + sizeof (struct udphdr) + 1300;
        iph->id = htonl (54321); //Id of this packet
        iph->frag_off = 0;
        iph->ttl = 255;
        iph->protocol = IPPROTO_UDP;
        iph->check = 0;      //Set to 0 before calculating checksum
        iph->saddr = inet_addr ( source_ip );    //Spoof the source ip address
        iph->daddr = sin.sin_addr.s_addr;
    
        //Ip checksum
        iph->check = csum ((unsigned short *) datagram, iph->tot_len);
    
        //UDP header
        udph->source = htons (6666);
        udph->dest = htons (8622);
        udph->len = htons(8 + 1300);
        udph->check = 0; //leave checksum 0 now, filled later by pseudo header
    
        //Now the UDP checksum using the pseudo header
        psh.source_address = inet_addr( source_ip );
        psh.dest_address = sin.sin_addr.s_addr;
        psh.placeholder = 0;
        psh.protocol = IPPROTO_UDP;
        psh.udp_length = htons(sizeof(struct udphdr) + 1300);
    
        int psize = sizeof(struct pseudo_header) + sizeof(struct udphdr) + 1300;
        pseudogram = malloc(psize);
    
        memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
        memcpy(pseudogram + sizeof(struct pseudo_header) , udph , sizeof(struct udphdr) + 1300);
    
        udph->check = csum( (unsigned short*) pseudogram , psize);
    
        //loop if you want to flood :)
        //while (1)
        {
            //Send the packet
            if (sendto (s, datagram, iph->tot_len ,  0, (struct sockaddr *) &sin, sizeof (sin)) < 0) {
                perror("sendto failed");
            }
            //Data send successfully
            else {
                printf ("Packet Send. Length : %d \n" , iph->tot_len);
            }
        }
    
        return 0;
    }
    
    $ gcc a.c && sudo ./a.out
    
    $ sudo tcpdump -ni ext1 udp
    09:42:19.086692 IP 10.107.115.114.ircu-2 > 123.0.0.3.8622: UDP, length 1300
    
    参考文章

    https://www.binarytides.com/raw-udp-sockets-c-linux/

    相关文章

      网友评论

          本文标题:C编程 - 使用raw socket发送UDP报文

          本文链接:https://www.haomeiwen.com/subject/fzjojftx.html