原始套接字发送UDP

2022-09-23  本文已影响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");
}
上一篇下一篇

猜你喜欢

热点阅读