router模块: 通过libpcap来通过ens33/ens38接收网卡数据,初始化libnet

This commit is contained in:
flykhan 2023-09-21 09:51:03 +08:00
parent f993cd14d2
commit 80d9ba5f9e
7 changed files with 84 additions and 154 deletions

View File

@ -20,7 +20,7 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
# 链接规则 # 链接规则
$(TARGET): $(OBJS) $(TARGET): $(OBJS)
$(CC) $^ -o $@ -lpcap -lpthread -lmysqlclient $(CC) $^ -o $@ -lpcap -lpthread -lmysqlclient -lnet
# 默认构建目标 # 默认构建目标
all: $(TARGET) all: $(TARGET)

View File

@ -18,6 +18,7 @@ extern int result_rows(const char *sql);
// 插入 // 插入
extern int insert(const char *sql, MYSQL_BIND *params); extern int insert(const char *sql, MYSQL_BIND *params);
// 删除
extern int delete(const char *sql, MYSQL_BIND *params); extern int delete(const char *sql, MYSQL_BIND *params);

View File

@ -4,155 +4,43 @@ void *net_task(void *arg)
{ {
printf("net_task\n"); printf("net_task\n");
// 1. 获取可用的网络设备名称 char *dev1 = "ens33"; // 第一个网卡
char errbuf[PCAP_ERRBUF_SIZE]; // 错误信息 char *dev2 = "ens38"; // 第二个网卡
pcap_if_t *alldevs;
if (pcap_findalldevs(&alldevs, errbuf) == -1)
{
printf("pcap_findalldevs error: %s\n", errbuf);
return 1;
}
// 2. 打印网络设备名称 // 打开网卡设备
pcap_if_t *d; open_device(&device1, dev1);
for (d = alldevs; d != NULL; d = d->next) open_device(&device2, dev2);
{
printf("%s\n", d->name);
}
// 3. 获取第一个网络设备的IP地址 // 开始捕获数据包:
pcap_addr_t *a; // pcap_loop: 网卡设备、捕获的数据包个数、回调函数、传递给回调函数的参数
for (a = alldevs->addresses; a != NULL; a = a->next) pcap_loop(device1, -1, process_packet, NULL); // -1 表示无限循环
{ pcap_loop(device2, -1, process_packet, NULL); // -1 表示无限循环
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),IPv641
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); // 释放资源
return NULL; 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");
}

View File

@ -3,6 +3,19 @@
#include "router.h" #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); void *net_task(void *arg);
#endif #endif

Binary file not shown.

View File

@ -1,5 +1,6 @@
#include "router.h" #include "router.h"
#include "db.h" #include "db.h"
#include "net_task_thread.h"
int main(int argc, char const *argv[]) int main(int argc, char const *argv[])
{ {
@ -13,6 +14,10 @@ int main(int argc, char const *argv[])
close(sockfd); // 关闭原始套接字 close(sockfd); // 关闭原始套接字
close_mysql(); // 关闭数据库连接 close_mysql(); // 关闭数据库连接
// 关闭网络设备
pcap_close(device1);
pcap_close(device2);
return 0; return 0;
} }
@ -112,6 +117,26 @@ void net_init()
printf("黑名单删除失败\n"); 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)
{
}
} }
} }
@ -209,3 +234,5 @@ int is_ip_valid(const char *ip)
return -1; return -1;
} }
} }
// 发送ARP请求方法

View File

@ -17,6 +17,7 @@
#include <mysql/mysql.h> // mysql #include <mysql/mysql.h> // mysql
#include <netinet/ip.h> // ip #include <netinet/ip.h> // ip
#include <pcap/pcap.h> #include <pcap/pcap.h>
#include <libnet.h>
#include <regex.h> // 正则表达式用于ip地址检查 #include <regex.h> // 正则表达式用于ip地址检查
// 定义全局变量 // 定义全局变量