c-router-emulator/router/net_task_thread.c

210 lines
7.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "net_task_thread.h"
#include "db.h"
void *net_task(void *arg)
{
printf("net_task\n");
char *dev1 = "ens38"; // 第一个网卡
char *dev2 = "ens33"; // 第二个网卡
// 打开网卡设备
// libnet_context1 使用 open_device 函数打开网卡设备1 后返回的 libnet 上下文
libnet_context1 = open_device(&device1, dev1);
libnet_context2 = open_device(&device2, dev2);
// 开始捕获数据包:
// pcap_loop: 网卡设备、捕获的数据包个数、回调函数、传递给回调函数的参数
pcap_loop(device1, -1, process_packet, NULL); // -1 表示无限循环
pcap_loop(device2, -1, process_packet, NULL); // -1 表示无限循环
return NULL;
}
// 打开网卡设备
// 如果成功打开网卡设备,就返回 libnet 上下文
libnet_t *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_t *libnet = libnet_init(LIBNET_LINK, dev_name, errbuf); // 初始化 libnet
if (libnet == NULL)
{
perror("libnet_init");
exit(-1);
}
return libnet; // 返回 libnet 上下文
}
// 处理数据包
// 参数: 传递给回调函数的参数、数据包头部、数据包
void process_packet(u_char *arg, const struct pcap_pkthdr *pkthdr, const u_char *packet)
{
// 将数据包从一个网卡发送到另一个网卡
// 实际路由中,需要根据路由表进行路由选择
printf("process_packet\n");
/*
libnet_ptag_t t; // libnet 标签: 用于标识数据包中的某一部分
libnet_t *libnet; // libnet 上下文: 用于发送数据包
// 根据网卡设备选择 libnet 上下文,以便发送数据包
// 规则是: 如果是从网卡1接收到的数据包就从网卡2发送出去
if (arg == (u_char *)device1)
{
libnet = libnet_context2;
}
else if (arg == (u_char *)device2)
{
libnet = libnet_context1;
}
t = libnet_build_ethernet(
((struct libnet_ethernet_hdr *)packet)->ether_dhost, // 目的MAC地址
((struct libnet_ethernet_hdr *)packet)->ether_shost, // 源MAC地址
((struct libnet_ethernet_hdr *)packet)->ether_type, // 以太网类型
packet + LIBNET_ETH_H, // 负载数据(携带的数据)
pkthdr->len - LIBNET_ETH_H, // 以太网数据包的数据部分
libnet, // libnet 上下文
0 // 标记
);
if (t == -1)
{
perror("libnet_build_ethernet");
exit(-1);
}
// 发送数据包
int res = libnet_write(libnet);
if (res == -1)
{
perror("libnet_write");
exit(-1);
} */
struct libnet_ethernet_hdr *eth_hdr = (struct libnet_ethernet_hdr *)packet;
// 如果是IP数据包就打印源IP地址和目的IP地址
if (ntohs(eth_hdr->ether_type) == ETHERTYPE_IP)
{
struct libnet_ipv4_hdr *ip_hdr = (struct libnet_ipv4_hdr *)(packet + LIBNET_ETH_H);
if (ip_hdr->ip_p == IPPROTO_TCP)
{
struct libnet_tcp_hdr *tcp_hdr = (struct libnet_tcp_hdr *)(packet + LIBNET_ETH_H + LIBNET_IPV4_H);
printf("TCP: %s:%d -> %s:%d\n", inet_ntoa(ip_hdr->ip_src), ntohs(tcp_hdr->th_sport), inet_ntoa(ip_hdr->ip_dst), ntohs(tcp_hdr->th_dport));
}
else if (ip_hdr->ip_p == IPPROTO_UDP)
{
struct libnet_udp_hdr *udp_hdr = (struct libnet_udp_hdr *)(packet + LIBNET_ETH_H + LIBNET_IPV4_H);
printf("UDP: %s:%d -> %s:%d\n", inet_ntoa(ip_hdr->ip_src), ntohs(udp_hdr->uh_sport), inet_ntoa(ip_hdr->ip_dst), ntohs(udp_hdr->uh_dport));
}
libnet_t *libnet;
if (arg == (u_char *)device1)
{
libnet = libnet_context2;
}
else if (arg == (u_char *)device2)
{
libnet = libnet_context1;
}
printf("testssssxxxxs\n");
libnet_ptag_t t = libnet_build_ethernet(
eth_hdr->ether_dhost,
eth_hdr->ether_shost,
ETHERTYPE_IP,
packet + LIBNET_ETH_H,
pkthdr->len - LIBNET_ETH_H,
libnet,
0);
// 组包测试(如果能打印到这行,则说明组包成功)
printf("testssss\n");
if (t == -1)
{
perror("libnet_build_ethernet");
exit(-1);
}
int res = libnet_write(libnet);
if (res == -1)
{
perror("libnet_write");
exit(-1);
}
}
// 如果是ARP数据包就打印源IP地址和目的IP地址
if (ntohs(eth_hdr->ether_type) == ETHERTYPE_ARP)
{
struct libnet_arp_hdr *arp_hdr = (struct libnet_arp_hdr *)(packet + LIBNET_ETH_H);
// printf("ARP: %s -> %s\n", inet_ntoa(*(struct in_addr *)arp_hdr->arp_spa), inet_ntoa(*(struct in_addr *)arp_hdr->arp_tpa));
}
}
// ARP 数据报处理函数
void process_arp_packet(const u_char *packet)
{
struct ether_header *eth_hdr = (struct ether_header *)packet;
struct ether_arp *arp_hdr = (struct ether_arp *)(packet + LIBNET_ETH_H); // packet + 14
if (ntohs(eth_hdr->ether_type) == ETHERTYPE_ARP)
{
char ip_address[INET_ADDRSTRLEN];
char mac_address[ETH_ALEN * 3]; // ETH_ALEN * 3 是为了申请足够的空间存储 MAC 地址
/*
inet_ntop 用于将二进制的 IP 地址转换为可读的字符串形式
参数说明:
AF_INET指定要转换的地址族这里是 IPv4 地址。
arp_hdr->arp_spa源 IP 地址的指针,它是一个二进制的网络字节序的 IPv4 地址。
ip_address用于存储转换后的 IP 地址字符串的缓冲区。
sizeof(ip_address):指定缓冲区的大小,以确保不会发生缓冲区溢出。
*/
inet_ntop(AF_INET, arp_hdr->arp_spa, ip_address, sizeof(ip_address));
snprintf(mac_address, sizeof(mac_address),
"%02x:%02x:%02x:%02x:%02x:%02x",
arp_hdr->arp_sha[0],
arp_hdr->arp_sha[1],
arp_hdr->arp_sha[2],
arp_hdr->arp_sha[3],
arp_hdr->arp_sha[4],
arp_hdr->arp_sha[5]);
// printf("ARP: %s -> %s\n", ip_address, mac_address);
MYSQL_BIND parmas[2];
parmas[0].buffer_type = MYSQL_TYPE_STRING;
parmas[0].buffer = ip_address;
parmas[0].buffer_length = strlen(ip_address);
parmas[0].is_null = 0;
parmas[0].length = &parmas[0].buffer_length;
parmas[1].buffer_type = MYSQL_TYPE_STRING;
parmas[1].buffer = mac_address;
parmas[1].buffer_length = strlen(mac_address);
parmas[1].is_null = 0;
parmas[1].length = &parmas[1].buffer_length;
// snprintf(arp_result_sql, sizeof(arp_result_sql), "insert into arp_result(ip, mac) values('%s', '%s')", ip_address, mac_address);
char arp_result_sql[1024] = "insert into arp_result(ip, mac) values(?, ?)";
int result = insert(arp_result_sql, parmas);
if (result > 0)
{
printf("ARP: %s -> %s\n", ip_address, mac_address);
}
}
}