c-router-emulator/router/net_task_thread.c

158 lines
6.9 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"
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;
}
// 2. 打印网络设备名称
pcap_if_t *d;
for (d = alldevs; d != NULL; d = d->next)
{
printf("%s\n", d->name);
}
// 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),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;
}