qfedu-network-advanced-level/exam/t3.c

133 lines
5.2 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.

/*
* 写一个网络数据分析器
* 要求:
* 1、对 arp/ip/tcp/udp 数据进行区分。
* 2、把数据包中的源信息目的信息等重要的信息打印出来。
*/
#include <stdio.h>
#include <pcap/pcap.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h> // memset
#include <net/ethernet.h> // ether_header
#include <netinet/ip.h> // ip
#include <netinet/if_ether.h> // ether_arp
#include <unistd.h> // sleep
int main(int argc, char const *argv[])
{
char errbuf[PCAP_ERRBUF_SIZE]; // 用于存储错误信息的缓冲区
char *dev = pcap_lookupdev(errbuf); // 获取网络接口
if (dev == NULL) // 获取网络接口失败
{
printf("pcap_lookupdev error: %s\n", errbuf);
return -1;
}
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 -1;
}
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 -1;
}
// 分析 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 报文信息
}
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 地址
printf("ip 报文\n");
// 分析 ip 报文类型
// 如果是 tcp 报文,则打印 tcp 报文信息
// 如果是 udp 报文,则打印 udp 报文信息
if (ip_hdr->ip_p == IPPROTO_TCP)
{
printf("tcp 报文\n");
printf("源地址: %s\t\t目的地址: %s\n源MAC: %s\t目的MAC: %s\n", src_ip, dst_ip, src_mac, dst_mac); // 打印 ip 报文信息
}
else if (ip_hdr->ip_p == IPPROTO_UDP)
{
printf("udp 报文\n");
printf("源地址: %s\t\t目的地址: %s\n源MAC: %s\t目的MAC: %s\n", src_ip, dst_ip, src_mac, dst_mac); // 打印 ip 报文信息
}
else
{
printf("其他报文\n");
}
}
else
{
printf("其他报文\n");
}
sleep(1);
}
// 关闭网络设备
pcap_close(pcap_handle);
return 0;
}