c-router-emulator/router/net_task_thread.c

305 lines
11 KiB
C
Raw Permalink 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"
extern volatile int stop_thread; // 声明
void *net_task(void *arg)
{
printf("net_task\n");
char *dev = pcap_lookupdev(errbuf); // 获取网络接口
if (dev == NULL) // 获取网络接口失败
{
printf("pcap_lookupdev error: %s\n", errbuf);
return NULL;
}
printf("网络接口: %s\n", dev);
// 获取网卡的网络号,掩码地址
bpf_u_int32 netip, netmask;
if (pcap_lookupnet(dev, &netip, &netmask, NULL) == 0)
{
unsigned char ip[INET_ADDRSTRLEN] = "";
unsigned char mask[INET_ADDRSTRLEN] = "";
inet_ntop(AF_INET, &netip, ip, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &netmask, mask, INET_ADDRSTRLEN);
printf("网络地址: %s 掩码地址: %s\n", ip, mask);
}
// 打开网络设备,开始捕获数据
pcap_t *pcap_handle = pcap_open_live(dev, BUFSIZ, 1, 0, errbuf);
if (pcap_handle == NULL)
{
printf("pcap_open_live error: %s\n", errbuf);
return NULL;
}
while (1)
{
struct pcap_pkthdr pcap_hdr; // 数据包头
memset(&pcap_hdr, 0, sizeof(pcap_hdr)); // 清空结构体
const u_char *packet = pcap_next(pcap_handle, &pcap_hdr); // 获取数据包
if (packet == NULL)
{
printf("pcap_next error\n");
return NULL;
}
// 分析 ethernet 报文类型
// 如果是 arp 报文,则打印 arp 报文信息
// 如果是 ip 报文,则打印 ip 报文信息
struct ether_header *eth_hdr = (struct ether_header *)packet;
// 拆分源 mac 地址和目的 mac 地址
unsigned char src_mac_x[ETHER_ADDR_LEN] = ""; // 源 mac 地址
unsigned char dst_mac_x[ETHER_ADDR_LEN] = ""; // 目的 mac 地址
memcpy(src_mac_x, eth_hdr->ether_shost, ETHER_ADDR_LEN); // 拷贝源 mac 地址
memcpy(dst_mac_x, eth_hdr->ether_dhost, ETHER_ADDR_LEN); // 拷贝目的 mac 地址
char src_mac[18] = ""; // 存储 MAC 地址的字符串
char dst_mac[18] = ""; // 存储 MAC 地址的字符串
// 将 MAC 地址转换成字符串
sprintf(src_mac, "%02x:%02x:%02x:%02x:%02x:%02x",
src_mac_x[0], src_mac_x[1], src_mac_x[2], src_mac_x[3], src_mac_x[4], src_mac_x[5]);
sprintf(dst_mac, "%02x:%02x:%02x:%02x:%02x:%02x",
dst_mac_x[0], dst_mac_x[1], dst_mac_x[2], dst_mac_x[3], dst_mac_x[4], dst_mac_x[5]);
if (ntohs(eth_hdr->ether_type) == ETHERTYPE_ARP)
{
// 拆分源 ip 地址和目的 ip 地址
unsigned char src_ip[INET_ADDRSTRLEN] = ""; // 源 ip 地址
unsigned char dst_ip[INET_ADDRSTRLEN] = ""; // 目的 ip 地址
struct ether_arp *arp_hdr = (struct ether_arp *)(packet + sizeof(struct ether_header));
inet_ntop(AF_INET, arp_hdr->arp_spa, src_ip, INET_ADDRSTRLEN); // 拷贝源 ip 地址
inet_ntop(AF_INET, arp_hdr->arp_tpa, dst_ip, INET_ADDRSTRLEN); // 拷贝目的 ip 地址
printf("arp 报文\n");
printf("源地址: %s\t\t目的地址: %s\n源MAC: %s\t目的MAC: %s\n", src_ip, dst_ip, src_mac, dst_mac); // 打印 arp 报文信息
// 当 arp 映射表中没有 ip 时,则添加到 arp 映射表中,如果 mac 地址是 00:00:00:00:00:00 则不添加FF:FF:FF:FF:FF:FF 也不添加
if (strcmp(src_mac, "00:00:00:00:00:00") != 0 && strcmp(src_mac, "FF:FF:FF:FF:FF:FF") != 0)
{
// 查询数据库 arp 表中是否已存在此 IP
int ret = search_arp_list_if_ip_have(src_ip);
if (ret > 0)
{
// printf("update_ip_mac\n");
// 将 IP 地址和 MAC 地址更新到 arp 表中
update_arp_list_by_ip(src_ip, src_mac);
}
else
{
// printf("insert_ip_mac\n");
// 将 IP 地址和 MAC 地址添加到 arp 表中
insert_arp_list(src_ip, src_mac);
}
}
}
else if (ntohs(eth_hdr->ether_type) == ETHERTYPE_IP)
{
// 拆分源 ip 地址和目的 ip 地址
unsigned char src_ip[INET_ADDRSTRLEN] = ""; // 源 ip 地址
unsigned char dst_ip[INET_ADDRSTRLEN] = ""; // 目的 ip 地址
struct ip *ip_hdr = (struct ip *)(packet + sizeof(struct ether_header));
inet_ntop(AF_INET, &ip_hdr->ip_src, src_ip, INET_ADDRSTRLEN); // 拷贝源 ip 地址
inet_ntop(AF_INET, &ip_hdr->ip_dst, dst_ip, INET_ADDRSTRLEN); // 拷贝目的 ip 地址
// 检查黑名单
ip_blacklist_filter(src_ip);
ip_blacklist_filter(dst_ip);
// 使用 libnet 组装转发
// 1. 判断目的 IP 是否在路由表中
// 2. 如果在路由表中,则查找下一跳 IP
// 3. 如果不在路由表中,则查找默认网关 IP
// 4. 如果默认网关 IP 也没有,则丢弃此数据包
// 5. 如果有下一跳 IP则查找下一跳 IP 对应的 MAC 地址
// 6. 如果没有下一跳 IP则查找默认网关 IP 对应的 MAC 地址
// 7. 如果没有默认网关 IP 对应的 MAC 地址,则丢弃此数据包
// 8. 如果有 MAC 地址,则使用 libnet 发送数据包
// 1. 判断目的 IP 是否在路由表中
char next_hop_ip[INET_ADDRSTRLEN] = ""; // 下一跳 IP 地址
char next_hop_mac[18] = ""; // 下一跳 MAC 地址
if (is_in_routing_table(dst_ip))
{
// 2. 如果在路由表中,则查找下一跳 IP
get_next_hop_ip(dst_ip, next_hop_ip);
}
else
{
// 3. 如果不在路由表中,则查找默认网关 IP
get_default_gateway_ip(next_hop_ip);
}
if (strlen(next_hop_ip) == 0)
{
// 4. 如果默认网关 IP 也没有,则丢弃此数据包
// printf("No route to host, discarding packet.\n");
continue;
}
// 5. 如果有下一跳 IP则查找下一跳 IP 对应的 MAC 地址
if (is_in_arp_table(next_hop_ip))
{
get_mac_address(next_hop_ip, next_hop_mac);
}
else
{
// 6. 如果没有下一跳 IP则查找默认网关 IP 对应的 MAC 地址
get_mac_address(next_hop_ip, next_hop_mac);
}
if (strlen(next_hop_mac) == 0)
{
// 7. 如果没有默认网关 IP 对应的 MAC 地址,则丢弃此数据包
// printf("No MAC address for next hop, discarding packet.\n");
continue;
}
// 8. 如果有 MAC 地址,则使用 libnet 发送数据包
libnet_t *l;
char errbuf[LIBNET_ERRBUF_SIZE];
l = libnet_init(LIBNET_LINK, NULL, errbuf);
if (l == NULL)
{
fprintf(stderr, "libnet_init() failed: %s\n", errbuf);
return NULL;
}
libnet_ptag_t ptag;
ptag = libnet_build_ipv4(
LIBNET_IPV4_H, 0, 0, 0, 64, IPPROTO_TCP, 0, src_ip, dst_ip,
NULL, 0, l, 0);
if (ptag == -1)
{
fprintf(stderr, "libnet_build_ipv4() failed: %s\n", libnet_geterror(l));
return NULL;
}
uint8_t dst_mac_addr[6];
sscanf(next_hop_mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &dst_mac_addr[0], &dst_mac_addr[1], &dst_mac_addr[2], &dst_mac_addr[3], &dst_mac_addr[4], &dst_mac_addr[5]);
ptag = libnet_build_ethernet(
dst_mac_addr, src_mac_x, ETHERTYPE_IP,
NULL, 0, l, 0);
if (ptag == -1)
{
fprintf(stderr, "libnet_build_ethernet() failed: %s\n", libnet_geterror(l));
return NULL;
}
int c = libnet_write(l);
libnet_destroy(l);
}
else
{
printf("其他报文\n");
}
sleep(1);
}
// 关闭网络设备
pcap_close(pcap_handle);
pthread_exit(NULL);
}
// 发送 ARP 广播
void send_arp_scan_broadcast()
{
libnet_t *my_libnet;
char errbuf[LIBNET_ERRBUF_SIZE];
// 初始化libnet句柄
my_libnet = libnet_init(LIBNET_LINK, NULL, errbuf);
if (my_libnet == NULL)
{
fprintf(stderr, "libnet_init() failed: %s\n", errbuf);
exit(EXIT_FAILURE);
}
// 配置源MAC地址、源IP地址和目的IP地址
uint8_t src_mac[6] = {0x00, 0x0c, 0x29, 0x85, 0xcc, 0x53}; // 源MAC地址
uint8_t src_ip[4] = {192, 168, 32, 133}; // 源IP地址
uint8_t dst_ip[4] = {192, 168, 32, 255}; // 目的IP地址广播地址
// 目的MAC地址广播地址
uint8_t dst_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
// ptag = protocol tag 协议标记
libnet_ptag_t arp_tag, ether_tag;
// 构建ARP数据包
arp_tag = libnet_build_arp(ARPHRD_ETHER, ETHERTYPE_IP, 6, 4, ARPOP_REQUEST,
src_mac, src_ip, dst_mac, dst_ip,
NULL, 0, my_libnet, 0);
if (arp_tag == -1)
{
fprintf(stderr, "libnet_build_arp() failed: %s\n", libnet_geterror(my_libnet));
exit(EXIT_FAILURE);
}
// 构建以太网数据包
uint8_t ether_dst_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; // 以太网目的MAC地址广播地址
uint8_t ether_src_mac[6] = {src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5]}; // 以太网源MAC地址
uint16_t ether_type = ETHERTYPE_ARP; // 以太网类型ARP
ether_tag = libnet_build_ethernet(ether_dst_mac, ether_src_mac, ether_type,
NULL, 0, my_libnet, 0);
if (ether_tag == -1)
{
fprintf(stderr, "libnet_build_ethernet() failed: %s\n", libnet_geterror(my_libnet));
exit(EXIT_FAILURE);
}
// 发送数据包
int bytes_sent = libnet_write(my_libnet);
if (bytes_sent == -1)
{
fprintf(stderr, "libnet_write() failed: %s\n", libnet_geterror(my_libnet));
exit(EXIT_FAILURE);
}
else
{
printf("ARP scan broadcast sent: %d bytes\n", bytes_sent);
}
// 销毁libnet句柄
libnet_destroy(my_libnet);
}
void ip_blacklist_filter(const char *ip)
{
// printf("ip_blacklist_filter\n");
// printf("ip: %s\n", ip);
// 查询数据库黑名单IP表中是否已存在此IP
int ret = search_ip_fw(ip);
if (ret > 0)
{
char iptables_check[256] = "";
sprintf(iptables_check, "iptables -C INPUT -s %s -j DROP", ip);
// 检查规则是否存在
// printf("iptables_command: %s\n", iptables_command);
if (system(iptables_check) != 0)
{
// 规则不存在,添加规则
char iptables_add[256] = "";
sprintf(iptables_add, "iptables -I INPUT -s %s -j DROP", ip);
// printf("iptables_add: %s\n", iptables_add);
system(iptables_add);
}
}
}