diff --git a/router/Makefile b/router/Makefile index 945d59c..0f363ef 100644 --- a/router/Makefile +++ b/router/Makefile @@ -20,7 +20,7 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c # 链接规则 $(TARGET): $(OBJS) - $(CC) $^ -o $@ -lpcap -lpthread -lmysqlclient + $(CC) $^ -o $@ -lpcap -lpthread -lmysqlclient -lnet # 默认构建目标 all: $(TARGET) diff --git a/router/db.h b/router/db.h index 065f0f2..f7dc639 100644 --- a/router/db.h +++ b/router/db.h @@ -18,6 +18,7 @@ extern int result_rows(const char *sql); // 插入 extern int insert(const char *sql, MYSQL_BIND *params); +// 删除 extern int delete(const char *sql, MYSQL_BIND *params); diff --git a/router/net_task_thread.c b/router/net_task_thread.c index 5db158f..47b9d27 100644 --- a/router/net_task_thread.c +++ b/router/net_task_thread.c @@ -4,155 +4,43 @@ void *net_task(void *arg) { printf("net_task\n"); - // 1. 获取可用的网络设备名称 - char errbuf[PCAP_ERRBUF_SIZE]; // 错误信息 - pcap_if_t *alldevs; - if (pcap_findalldevs(&alldevs, errbuf) == -1) - { - printf("pcap_findalldevs error: %s\n", errbuf); - return 1; - } + char *dev1 = "ens33"; // 第一个网卡 + char *dev2 = "ens38"; // 第二个网卡 - // 2. 打印网络设备名称 - pcap_if_t *d; - for (d = alldevs; d != NULL; d = d->next) - { - printf("%s\n", d->name); - } + // 打开网卡设备 + open_device(&device1, dev1); + open_device(&device2, dev2); - // 3. 获取第一个网络设备的IP地址 - pcap_addr_t *a; - for (a = alldevs->addresses; a != NULL; a = a->next) - { - if (a->addr->sa_family == AF_INET) - { - // ntoa 将网络字节序的IP地址转换为点分十进制的字符串 - printf("%s\n", inet_ntoa(((struct sockaddr_in *)a->addr)->sin_addr)); - } - } - - // 获取网卡的网络号和网络掩码 - bpf_u_int32 netip, netmask; - if (pcap_lookupnet(alldevs->name, &netip, &netmask, NULL) != 0) - { - printf("网络号和网络掩码获取错误\n"); - return -1; - } - unsigned char ip[INET_ADDRSTRLEN] = ""; - unsigned char mask[INET_ADDRSTRLEN] = ""; - // ntop 将网络字节序的IP地址转换为点分十进制的字符串 - inet_ntop(AF_INET, &netip, ip, INET_ADDRSTRLEN); - inet_ntop(AF_INET, &netmask, mask, INET_ADDRSTRLEN); - printf("网络号: %s 网络掩码: %s\n", ip, mask); - - // 获取网卡的MAC地址 - struct ifreq ifr; - int sockfd = socket(AF_INET, SOCK_DGRAM, 0); - strcpy(ifr.ifr_name, alldevs->name); - if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0) - { - printf("MAC地址获取失败\n"); - return -1; - } - unsigned char mac[6]; - memcpy(mac, ifr.ifr_hwaddr.sa_data, 6); - printf("MAC地址: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - - // 打开网络设备,开始抓包(捕获数据包) - pcap_t *pcap_handle = pcap_open_live(alldevs->name, 65535, 1, 0, errbuf); // 65535 最大捕获的字节数 1 混杂模式 0 不超时 errbuf 错误信息 - if (pcap_handle == NULL) - { - printf("pcap_open_live error: %s\n", errbuf); - return 1; - } - - // 4. 抓包 - struct pcap_pkthdr pcap_header; // 数据包头 - bzero(&pcap_header, sizeof(pcap_header)); // 清空 - const u_char *packet; // 数据包数据 - while (1) - { - packet = pcap_next(pcap_handle, &pcap_header); // 抓包 - if (packet == NULL) - { - printf("pcap_next error\n"); - return 1; - } - printf("数据包长度: %d\n", pcap_header.len); - printf("捕获的数据长度: %d\n", pcap_header.caplen); - // printf("数据包时间: %s", ctime((const time_t *)&pcap_header.ts.tv_sec)); - // printf("数据包内容: "); - // for (int i = 0; i < pcap_header.len; i++) - // { - // printf("%02x ", packet[i]); - // } - - // 5. 解析数据包 - struct ether_header *eth_header = (struct ether_header *)packet; // 以太网帧头 - unsigned char src_mac[18] = ""; - unsigned char dst_mac[18] = ""; - sprintf(src_mac, "%02x:%02x:%02x:%02x:%02x:%02x", eth_header->ether_shost[0], eth_header->ether_shost[1], eth_header->ether_shost[2], eth_header->ether_shost[3], eth_header->ether_shost[4], eth_header->ether_shost[5]); // 将MAC地址转换为点分十进制的字符串 - sprintf(dst_mac, "%02x:%02x:%02x:%02x:%02x:%02x", eth_header->ether_dhost[0], eth_header->ether_dhost[1], eth_header->ether_dhost[2], eth_header->ether_dhost[3], eth_header->ether_dhost[4], eth_header->ether_dhost[5]); - unsigned short eth_type = ntohs(eth_header->ether_type); // type 字段是网络字节序,需要转换为主机字节序 - printf("以太网帧类型: %04x\n", eth_type); // 0x080 IP协议 0x0806 ARP协议 0x8035 RARP协议 0x86dd IPv6协议 - printf("目的MAC地址: %s\n", dst_mac); - printf("源MAC地址: %s\n", src_mac); - - // 如果是ARP协议 - if (eth_type == 0x0806) - { - // // 分析 arp 报文 - // struct ether_arp *arp_header = (struct ether_arp *)(packet + sizeof(struct ether_header)); // arp 报文 - // unsigned short this_arp_op = ntohs(arp_header->arp_op); // 操作码 - // printf("ARP操作码: %d\n", this_arp_op); // 1 ARP请求 2 ARP应答 3 RARP请求 4 RARP应答 - // if (this_arp_op == 1 || this_arp_op == 2) - // { - // unsigned char src_ip[INET_ADDRSTRLEN] = ""; - // unsigned char dst_ip[INET_ADDRSTRLEN] = ""; - // inet_ntop(AF_INET, arp_header->arp_spa, src_ip, INET_ADDRSTRLEN); // 将网络字节序的IP地址转换为点分十进制的字符串 - // inet_ntop(AF_INET, arp_header->arp_tpa, dst_ip, INET_ADDRSTRLEN); - // printf("源IP地址: %s\n", src_ip); - // printf("目的IP地址: %s\n", dst_ip); - // } - - // 发送 ARP 请求,用于广播获取网段内的所有已连接设备的mac地址,并存入 ip_mac 映射表 - } - - // 如果是IP协议 - if (eth_type == 0x800) - { - // 分析 ip 报文 - struct iphdr *ip_header = (struct iphdr *)(packet + sizeof(struct ether_header)); // ip 报文 (sizeof(struct ether_header) = 14 (MAC)以太网帧头长度) - unsigned char src_ip[INET_ADDRSTRLEN] = ""; - unsigned char dst_ip[INET_ADDRSTRLEN] = ""; - unsigned char ip_protocol[INET_ADDRSTRLEN] = ""; // 协议类型 - inet_ntop(AF_INET, &ip_header->saddr, src_ip, INET_ADDRSTRLEN); // 将网络字节序的IP地址转换为点分十进制的字符串 - inet_ntop(AF_INET, &ip_header->daddr, dst_ip, INET_ADDRSTRLEN); - printf("IP协议类型: %d\n", ip_header->protocol); // ICMP(1),IGMP(2),TCP(6),UDP(17),IPv6(41) - printf("源IP地址: %s\n", src_ip); - printf("目的IP地址: %s\n", dst_ip); - - // 如果是黑名单IP,则跳过本次循环,即屏蔽本ip的数据 - if (is_blocked_ip(src_ip) == 0 || is_blocked_ip(dst_ip) == 0) - { - printf("数据报已被过滤\n"); - continue; - } - // is_blocked_ip(src_ip); - printf("数据报正常\n"); - - // 不在黑名单时,进行数据报中ip和mac地址的转换和转发 - - // 先检查ip对应的mac地址是否存在(mysql->ip_mac表查询),存在时进行下一步;不存在时,调用三次循环,来进行ARP广播,获取最新的设备ip--mac - } - - printf("\n"); - sleep(1); - } - - // 3. 释放资源 - pcap_close(pcap_handle); // 关闭网络设备 - pcap_freealldevs(alldevs); // 释放资源 + // 开始捕获数据包: + // pcap_loop: 网卡设备、捕获的数据包个数、回调函数、传递给回调函数的参数 + pcap_loop(device1, -1, process_packet, NULL); // -1 表示无限循环 + pcap_loop(device2, -1, process_packet, NULL); // -1 表示无限循环 return NULL; +} + +// 打开网卡设备 +void open_device(pcap_t **device, char *dev_name) +{ + // 打开网卡设备: 设备名、最大字节数、混杂模式、超时时间、错误信息缓冲区 + *device = pcap_open_live(dev_name, MAX_BYTE, 1, 512, errbuf); + if (*device == NULL) + { + perror("pcap_open_live"); + exit(-1); + } + + // 处理数据包 + libnet_context1 = libnet_init(LIBNET_LINK, dev_name, errbuf); // 初始化 libnet + if (libnet_context1 == NULL) + { + perror("libnet_init"); + exit(-1); + } +} + +// 处理数据包 +void process_packet(u_char *arg, const struct pcap_pkthdr *pkthdr, const u_char *packet) +{ + printf("process_packet\n"); } \ No newline at end of file diff --git a/router/net_task_thread.h b/router/net_task_thread.h index f6cf01d..e0b169a 100644 --- a/router/net_task_thread.h +++ b/router/net_task_thread.h @@ -3,6 +3,19 @@ #include "router.h" +#define MAX_BYTE 65535 // 最大字节数 + +char errbuf[PCAP_ERRBUF_SIZE]; // 错误信息缓冲区 +pcap_t *device1; // 网卡设备1 +pcap_t *device2; // 网卡设备2 + +libnet_t *libnet_context1; // libnet1 上下文 +libnet_t *libnet_context2; // libnet2 上下文 + +// libpcap 相关函数 +void open_device(pcap_t **device, char *dev_name); // 打开网卡设备 +void process_packet(u_char *arg, const struct pcap_pkthdr *pkthdr, const u_char *packet); // 处理数据包 + void *net_task(void *arg); #endif \ No newline at end of file diff --git a/router/router b/router/router deleted file mode 100755 index a9b0913..0000000 Binary files a/router/router and /dev/null differ diff --git a/router/router.c b/router/router.c index 3d499cc..1e388b6 100644 --- a/router/router.c +++ b/router/router.c @@ -1,5 +1,6 @@ #include "router.h" #include "db.h" +#include "net_task_thread.h" int main(int argc, char const *argv[]) { @@ -13,6 +14,10 @@ int main(int argc, char const *argv[]) close(sockfd); // 关闭原始套接字 close_mysql(); // 关闭数据库连接 + // 关闭网络设备 + pcap_close(device1); + pcap_close(device2); + return 0; } @@ -112,6 +117,26 @@ void net_init() printf("黑名单删除失败\n"); } } + + else if (4 == choice) + { + if (0 == pthread_flag) + { + printf("开启路由器\n"); + pthread_flag += 1; // 线程标志位修改 + pthread_t thread_net_task; + pthread_create(&thread_net_task, NULL, net_task, NULL); + pthread_detach(thread_net_task); + } + else + { + printf("路由器正在运行......\n"); + } + } + + else if (5 == choice) + { + } } } @@ -208,4 +233,6 @@ int is_ip_valid(const char *ip) printf("正则表达式匹配错误\n"); return -1; } -} \ No newline at end of file +} + +// 发送ARP请求方法 diff --git a/router/router.h b/router/router.h index 8b180ec..c22eba6 100644 --- a/router/router.h +++ b/router/router.h @@ -17,6 +17,7 @@ #include // mysql #include // ip #include +#include #include // 正则表达式,用于ip地址检查 // 定义全局变量 @@ -27,11 +28,11 @@ char **dbResult; int nrow; int ncolumn; -void show(void); // 后端控制菜单 -void net_init(); // 网络初始化 -void *net_task(void *arg); // 网络任务 -int is_blocked_ip(unsigned char *ip); // 黑名单探测 +void show(void); // 后端控制菜单 +void net_init(); // 网络初始化 +void *net_task(void *arg); // 网络任务 +int is_blocked_ip(unsigned char *ip); // 黑名单探测 void printResult(MYSQL_ROW row, char (*columns)[30], int cols); // 显示查询结果的回调函数 -int is_ip_valid(const char *ip); // 检查ip地址是否合法 +int is_ip_valid(const char *ip); // 检查ip地址是否合法 #endif \ No newline at end of file