diff --git a/day6/homework/fake_feiqiu.c b/day6/homework/fake_feiqiu.c new file mode 100644 index 0000000..4e7e370 --- /dev/null +++ b/day6/homework/fake_feiqiu.c @@ -0,0 +1,199 @@ +// 飞秋伪装(UDP应用) +/* + MAC -> 14 + IP -> 20 + UDP -> 8 + UDP 数据报数据部分 +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name); +unsigned short checksum(unsigned short *buf, int len); + +// 伪头部(UDP 校验时需要再 UDP 报文之间加上伪头部) +typedef struct pseudo_udp_head_struct +{ + unsigned int saddr; // 源IP + unsigned int daddr; // 目的IP + unsigned char flag; // 0 + unsigned char protocol; // 协议类型 + unsigned short len; // UDP 首部长度 + 数据部分长度 +} PSEUDO_UDP_HEAD; + +int main(int argc, char const *argv[]) +{ + // 创建原始套接字 + int sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (sock_fd < 0) + { + perror("raw socket"); + return -1; + } + /* + // 网卡结构体 + struct ifreq ether_req; // 网卡接口请求结构体 + strncpy(ether_req.ifr_name, "ens34", IFNAMSIZ); // 指定网卡名字, IFNAMESIZ 是接口网卡的名字大小 + // 如果网卡不存在,返回错误,否则返回网卡接口索引 + if (ioctl(sock_fd, SIOCGIFINDEX, ðer_req) == -1) + { + perror("ioctl"); + return -1; + } + + // 发送接口的结构体 + struct sockaddr_ll sll; // 网络层套接字地址结构体 + bzero(&sll, sizeof(sll)); + sll.sll_ifindex = ether_req.ifr_ifindex; // 将网卡的接口类型赋值给发送接口 */ + + char sender_name[128] = ""; + printf("请输入要伪装的发送者名字:"); + scanf("%s", sender_name); + char sender_pc_name[128] = ""; + printf("请输入要伪装的发送者电脑名字:"); + scanf("%s", sender_pc_name); + + while (1) + { + + unsigned char udp_buf[1500] = ""; // UDP 数据报 + + // 伪装飞秋数据报(UDP) + // 1. 伪装飞秋数据报的源IP和目的IP + // 2. 伪装飞秋数据报的源端口和目的端口 + // 3. 伪装飞秋数据报的校验和 + // 4. 伪装飞秋数据报的数据部分 + // 5. 伪装飞秋数据报的长度 + + // 伪装飞秋数据报的数据部分 + // char msg_data[1024] = "1_lbt6_47#128#704D7B3F6397#0#0#0#4001#9:1694470508:chai:chai:32:hi liangzai"; + char msg_data[1024] = ""; + char say_what[1024] = ""; + printf("请输入要发送的内容:"); + scanf("%s", say_what); + if (strcmp(say_what, "exit") == 0) + { + break; + } + sprintf(msg_data, "1:%d:%s:%s:%d:%s", 123, sender_name, sender_pc_name, 32, say_what); + int msg_data_len = strlen(msg_data) + strlen(msg_data) % 2; // 整数补齐偶数位,strlen(msg_data)%2 : 偶数+0,奇数+1 + printf("msg_data_len = %d ---> %s\n", msg_data_len, msg_data); + + /* ---------------------组装 UDP 数据报的 UDP 首部--------------------- */ + struct udphdr *udp_head = (struct udphdr *)(udp_buf + 14 + 20); // UDP 首部开始位置 + udp_head->source = htons(2425); // 源端口 + udp_head->dest = htons(2425); // 目的端口 + udp_head->len = htons(8 + msg_data_len); // UDP 首部长度 + 数据部分长度 + udp_head->check = htons(0); // UDP 首部校验和 + + /* ---------------------UDP 伪首部校验--------------------- */ + // UDP 校验时需要再 UDP 报文之间加上伪头部 + /* + UDP 校验中的伪头部(pseudo header)是在计算 UDP 校验和时使用的辅助数据。伪头部包含了源 IP 地址、目的 IP 地址、协议类型(通常是 UDP)和 UDP 报文长度等信息。 + 在计算 UDP 校验和时,将伪头部和 UDP 报文的内容拼接在一起,然后计算校验和。这样做的目的是增加校验和的安全性,使其更具可靠性。 + */ + unsigned char pseudo_udp_buf[1056] = ""; // 伪头部 + PSEUDO_UDP_HEAD *pseudo_udp_head = (PSEUDO_UDP_HEAD *)pseudo_udp_buf; + pseudo_udp_head->saddr = inet_addr("192.168.31.155"); // 伪装源IP + pseudo_udp_head->daddr = inet_addr("192.168.31.147"); // 目的IP + pseudo_udp_head->flag = 0; // 0 + pseudo_udp_head->protocol = 17; // 协议类型 UDP + pseudo_udp_head->len = htons(8 + msg_data_len); // UDP 首部长度 + 数据部分长度 + + memcpy(pseudo_udp_buf + 12, udp_head, 8); // 拷贝 UDP 首部到伪头部 + memcpy(pseudo_udp_buf + 12 + 8, msg_data, msg_data_len); // 拷贝数据部分到伪头部 + // 计算 UDP 首部校验和 + udp_head->check = checksum((unsigned short *)pseudo_udp_buf, 12 + 8 + msg_data_len); + memcpy(udp_buf + 14 + 20 + 8, msg_data, msg_data_len); // 拷贝数据部分到 UDP 首部 + + /* ---------------------组装 UDP 数据报的 IP 首部--------------------- */ + struct iphdr *ip_head = (struct iphdr *)(udp_buf + 14); // IP 首部开始位置 + ip_head->version = 4; // 版本号 IPv4 + ip_head->ihl = 5; // 首部长度 5 * 4 = 20 字节 + ip_head->tos = 0; // 服务类型 + ip_head->tot_len = htons(20 + 8 + msg_data_len); // IP 首部长度 + UDP 首部长度 + 数据部分长度 + ip_head->id = htons(0); // 标识 + ip_head->frag_off = htons(0); // 标志和片偏移 + ip_head->ttl = 128; // 生存时间 + ip_head->protocol = 17; // 协议类型 UDP + // ip 校验时不需要伪头部 + ip_head->check = htons(0); // 原始校验和(暂时未知,赋值0) + ip_head->saddr = inet_addr("192.168.31.155"); // 伪装源IP + ip_head->daddr = inet_addr("192.168.31.147"); // 目的IP + ip_head->check = checksum((unsigned short *)(udp_buf + 14), 20); // IP 首部校验和(计算 IP 首部的校验和) + + /* ---------------------组装 UDP 数据报的 MAC 首部--------------------- */ + struct ether_header *mac_head = (struct ether_header *)udp_buf; // MAC 首部开始位置 + unsigned char dst_mac[8] = {0x00, 0xa5, 0x54, 0x89, 0xb5, 0xc5}; // 主机 MAC (目的 MAC) + unsigned char src_mac[8] = {0xb8, 0x8a, 0x60, 0xa0, 0x49, 0x2f}; // 虚拟机 MAC (源 MAC) + // 使用 memcpy 函数将 dst_mac 的内容拷贝到 mac_head.ether_dhost 中 + memcpy(mac_head->ether_dhost, dst_mac, 6); // 目的 MAC + memcpy(mac_head->ether_shost, src_mac, 6); // 源 MAC + mac_head->ether_type = htons(0x0800); // 2 个字节的数据需要大小端转换 (0x0800: IP 协议) + + /* ---------------------发送数据--------------------- */ + // int send_len = sendto(sock_fd, udp_buf, 14 + 20 + 8 + msg_data_len, 0, (struct sockaddr *)&sll, sizeof(sll)); + int send_len = send_datapacket(sock_fd, udp_buf, 14 + 20 + 8 + msg_data_len, "ens34"); + printf("send_len = %d\n", send_len); + } + + close(sock_fd); + + return 0; +} + +ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name) +{ + // 1. 获取网络接口类型(通过网卡名查找网卡索引) + struct ifreq ether_req; + bzero(ðer_req, sizeof(ether_req)); + strncpy(ether_req.ifr_name, ether_name, IF_NAMESIZE); // # define ifr_name ifr_ifrn.ifrn_name + + if (ioctl(fd, SIOCGIFINDEX, ðer_req) == -1) + { + perror("ioctl"); + return -1; + } + + // 2. 选择发送数据的网络接口索引(选择合适的网卡索引) + struct sockaddr_ll sll; + bzero(&sll, sizeof(sll)); + sll.sll_ifindex = ether_req.ifr_ifindex; // # define ifr_ifindex ifr_ifru.ifru_ivalue + + // 3. 发送数据 + ssize_t len = sendto(fd, buf, buf_size, 0, (struct sockaddr *)&sll, sizeof(sll)); + return len; +} + +// IP、UDP校验 +// 数据报校验计算 +// 接收传递的数据地址、长度 +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; +} \ No newline at end of file