美文网首页
原始套接字发送UDP

原始套接字发送UDP

作者: 二进制人类 | 来源:发表于2022-09-23 19:52 被阅读0次
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>         
    #include <sys/socket.h>
    #include <netinet/ether.h>
    #include <netinet/ip.h>
    #include <netinet/udp.h>
    #include <arpa/inet.h>
    #include <net/if.h>
    #include <netpacket/packet.h>
    #include <sys/ioctl.h>
    
    struct UdpHdr {
        u_int32_t source;
        u_int32_t dest;
        u_int8_t flag;
        u_int8_t protocol;
        u_int16_t len;
    };
    
    
    int SendTo(int sockfd, void *msg, int msg_len, char *eth_name) 
    {
        int ret;
        struct ifreq ethreq;
        struct sockaddr_ll sll;
        
        /* 获取网络接口类型 */
        memset(&ethreq, 0, sizeof(ethreq));
        strncpy(ethreq.ifr_name, eth_name, IFNAMSIZ);
        ret = ioctl(sockfd, SIOCGIFINDEX, &ethreq);
        if (ret == -1) {
            perror("ioctl");
            return -1;
        }
        
        /* 设置网络接口类型 */
        memset(&sll, 0, sizeof(sll));
        sll.sll_ifindex = ethreq.ifr_ifindex;
        
        /* 发送数据 */
        ret = sendto(sockfd, msg, msg_len, 0, (const struct sockaddr *)&sll, sizeof(sll));
        if (ret == -1) {
            perror("sendto");
            return -1;
        }
    }
    
    unsigned short checksum(unsigned short *buf, int len)
    {
        int nword = len / 2;
        unsigned long sum;
    
        if (len % 2 == 1)
            nword++;
        for (sum = 0; nword > 0; nword--)
        {
            sum += *buf;
            buf++;
        }
        sum = (sum >> 16) + (sum & 0xffff);
        sum += (sum >> 16);
        return ~sum;
    }
    
    int main()
    {
        int ret;
        int sockfd;
        int msg_len;
        unsigned char msg[1024];
        
        /* 创建原始套接字文件:基于链路层,可用于任意协议数据的收发 */
        sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
        if(sockfd == -1) {
            perror("socket");
            return -1;
        }
        printf("sockfd = %d\n", sockfd);
        
        /* 组以太网头部报文数据 */
        char src_mac[] =    {0x00, 0x0c, 0x29, 0x84, 0x0e, 0x96};   //源mac
        char dest_mac[] =   {0x00, 0xe0, 0x4c, 0x7b, 0x59, 0x17};   //目的mac
        struct ether_header *ethead = (struct ether_header *)msg;
        memcpy(ethead->ether_dhost, dest_mac, sizeof(dest_mac));
        memcpy(ethead->ether_shost, src_mac, sizeof(src_mac));
        ethead->ether_type = htons(0x0800);
        
        /* 组IP报文数据 */
        char src_ip[] = "10.7.181.10";
        char dest_ip[] = "10.7.181.140";
        char data[] = "hello raw send udp";
        unsigned short data_len = strlen(data) + strlen(data) % 2;      /* 数据的发送需要以偶数字节发送 */
        struct iphdr *ipheader = (struct iphdr *)(msg+14);
        ipheader->version = 4;                  /* 协议版本:4 = IPV4 */
        ipheader->ihl = 5;                      /* 头部长度 */
        ipheader->tos = 0;                      /* 服务类型 */
        ipheader->tot_len = htons(20+8+data_len);   /* IP报文数据总长度:20表示IP报文首部长度,8表示UDP报文首部长度,data_len需要发送数据的长度 */
        ipheader->id = htons(0);                /* 标识 */
        ipheader->frag_off = htons(0);          /* 偏移量 */
        ipheader->ttl = 128;                    /* 生存时间 */
        ipheader->protocol = 17;                /* 协议类型:17 = UDP报文 */
        ipheader->check = htons(0);             /* 不是最后设置的值,只是占位用于数据的校验 */
        ipheader->saddr = inet_addr(src_ip);    /* 设置源IP */
        ipheader->daddr = inet_addr(dest_ip);   /* 设置目的IP */
        /* IP头部检验和的设置 */
        ipheader->check = checksum((unsigned short *)ipheader, 20);
        
        /* 封装UDP报文的头部 */
        struct udphdr * udpheader = (struct udphdr *)(msg+14+20);
        udpheader->source = htons(8888);
        udpheader->dest = htons(8080);
        udpheader->len = htons(8+data_len);
        udpheader->check = htons(0);
        
        /* 封装需要发送的数据 */
        memcpy(msg+14+20+8, data, data_len);
        
        /* 伪首部:只用于头部校验,不用于数据的发送 */
        char msg_buf[512];
        struct UdpHdr *Udp_Hdr = (struct UdpHdr *)msg_buf;
        Udp_Hdr->source = inet_addr(src_ip);    /* 设置源IP */
        Udp_Hdr->dest = inet_addr(dest_ip);     /* 设置目的IP */
        Udp_Hdr->flag = 0;
        Udp_Hdr->protocol = 17;                 /* 协议类型:17 = UDP报文 */
        Udp_Hdr->len = htons(8+data_len);       /* UDP数据长度:8表示UDP头部长度,data_len需要发送数据的长度 */
        memcpy(msg_buf+12, udpheader, 8+data_len);
        /* 设置UDP头部校验和 */
        udpheader->check = checksum((unsigned short *)msg_buf, 12+8+data_len);
        /* 发送数据 */
        SendTo(sockfd, msg, 14+20+8+data_len, "ens33");
    }
    

    相关文章

      网友评论

          本文标题:原始套接字发送UDP

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