[C++] 纯文本查看 复制代码
#ifndef __net_head_H__
#define __net_head_H__
#include <arpa/inet.h>
#define IP_LEN (4)
#define MAC_LEN (6)
// 以太网头部
struct ethernet_header
{
unsigned char dst_mac[MAC_LEN]; // 目的mac
unsigned char src_mac[MAC_LEN]; // 源mac
unsigned short protocol_type; // 协议类型
#if 1 // protocal_type对应的值
#define ETHERTYPE_IP (0x0800) // IP
#define ETHERTYPE_ARP (0x0806) // ARP
#define ETHERTYPE_RARP (0x8035) // RARP
#endif
}__attribute__ ((__packed__));
// ARP头部
struct arp_header
{
unsigned short hd_type; // 硬件类型
unsigned short protocol_type; // 协议类型
unsigned char hd_addr_len; // 硬件地址长度
unsigned char protocol_addr_len; // 协议地址长度
unsigned short op; // 操作类型
unsigned char src_mac[MAC_LEN]; // 发送端mac
unsigned char src_ip[IP_LEN]; // 发送端ip
unsigned char dst_mac[MAC_LEN]; // 目的端mac
unsigned char dst_ip[IP_LEN]; // 目的端ip
#if 1 // op对应的值
#define ARP_REQUEST (1) // ARP请求
#define ARP_REPLY (2) // ARP应答
#define RARP_REQUEST (3) // RARP请求
#define RARP_REPLY (4) // RARP应答
#endif
}__attribute__ ((__packed__));
// IPv4头部
struct ipv4_header
{
unsigned char version_hd_len; // 版本号、首部长度
unsigned char tos; // 服务类型
unsigned short total_len; // 总长度
unsigned short identification; // 标识
unsigned short flags_offset; // 标志、片偏移
unsigned char ttl; // 生存时间
unsigned char protocol; // 协议
unsigned short checksum; // 首部校验和
unsigned int src_ip; // 源ip
unsigned int dst_ip; // 目的ip
#if 1 // flags对应的值
#define IP_FLAGS_RESERVE (0) // 保留,默认为0
#define IP_FLAGS_DF (1) // 不分片
#define IP_FLAGS_MF (2) // 有分片
#define IP_PROTOCOL_ICMP (1) // ICMP
#define IP_PROTOCOL_TCP (6) // TCP
#define IP_PROTOCOL_UDP (17) // UDP
#endif
}__attribute__ ((__packed__));
// tcp头部
struct tcp_header
{
unsigned short src_port; // 源端口
unsigned short dst_port; // 目的端口
unsigned int sequence; // 序列号
unsigned int ack_sequence; // 确认序列号
unsigned char hd_len_reserve; // 首部长度、保留位
unsigned char flags; // 标志
unsigned short window_size; // 窗口大小,告知接收方还有多少数据
unsigned short checksum; // 校验和(整个)
unsigned short usg_p; // 紧急指针(usg=1时有效)
}__attribute__ ((__packed__));
// UDP头部
struct udp_header
{
unsigned short src_port; // 源端口
unsigned short dst_port; // 目标端口
unsigned short data_len; // UDP数据长度
unsigned short checksum; // 校验和(整个)
}__attribute__ ((__packed__));
// ICMP头部
struct icmp_header
{
unsigned char type; // ICMP类型
unsigned char code; // 代码
unsigned short checksum; // 校验和
unsigned short identification; // 标识
unsigned short sequence; // 序列号
unsigned int timestamp; // 时间戳
}__attribute__ ((__packed__));
#endif
// 源文件
#include <iostream>
#include "network_head.h"
#include <pcap.h>
#include <cstring>
#define MAX_ADDR_LEN 16
#define MAX_LINE_LEN 16
void ntohb(unsigned char *byte)
{
char temp;
temp = *byte;
temp = (temp >> 4);
*byte = (*byte << 4) | temp;
}
// 分析tcp数据包
void resolve_tcp_pkt(u_char *arg, const struct pcap_pkthdr *pkt_header, const u_char *pkt_content)
{
tcp_header *tcp_protocol;
tcp_protocol = (tcp_header*)(pkt_content + sizeof(ethernet_header) + sizeof(ipv4_header));
printf(" TCP Protocol \n");
printf("================================================\n");
printf("源端口: %i\n", ntohs(tcp_protocol->src_port));
printf("目的端口: %i\n", ntohs(tcp_protocol->dst_port));
printf("序列号: %d\n", ntohl(tcp_protocol->sequence));
printf("确认序列号: %d\n", ntohl(tcp_protocol->ack_sequence));
printf("首部长度: %d\n", (tcp_protocol->hd_len_reserve >> 4) * 4);
printf("标志: 0x%.3x ", tcp_protocol->flags);
if (tcp_protocol->flags & 0x08) {
printf("(PSH)\n");
}
if (tcp_protocol->flags & 0x10) {
printf("(ACK)\n");
}
if (tcp_protocol->flags & 0x02) {
printf("(SYN)\n");
}
if (tcp_protocol->flags & 0x20) {
printf("(URG)\n");
}
if (tcp_protocol->flags & 0x01) {
printf("(FIN)\n");
}
if (tcp_protocol->flags & 0x04) {
printf("(RST)\n");
}
printf("窗口大小: %i\n", ntohs(tcp_protocol->window_size));
printf("校验和: 0x%.4x\n", ntohs(tcp_protocol->checksum));
printf("紧急指针: %i\n", ntohs(tcp_protocol->usg_p));
printf("================================================\n");
}
// 分析udp数据包
void resolve_udp_pkt(u_char *arg, const struct pcap_pkthdr *pkt_header, const u_char *pkt_content)
{
udp_header *udp_protocol;
udp_protocol = (udp_header*)(pkt_content + sizeof(ethernet_header) + sizeof(ipv4_header));
printf(" UDP Protocol \n");
printf("================================================\n");
printf("源端口: %i\n", ntohs(udp_protocol->src_port));
printf("目的端口: %i\n", ntohs(udp_protocol->dst_port));
printf("数据包长度: %i\n", ntohs(udp_protocol->data_len));
printf("校验和: 0x%.4x\n", ntohs(udp_protocol->checksum));
printf("================================================\n");
}
// 分析icmp数据包
void resolve_icmp_pkt(u_char *arg, const struct pcap_pkthdr *pkt_header, const u_char *pkt_content)
{
icmp_header *icmp_protocol;
icmp_protocol = (icmp_header*)(pkt_content + sizeof(ethernet_header) + sizeof(ipv4_header));
printf(" ICMP Protocol \n");
printf("================================================\n");
printf("类型: %d ", icmp_protocol->type);
switch (icmp_protocol->type)
{
case 8: {
printf("request\n");
break;
}
case 0: {
printf("reply\n");
break;
}
default: {
break;
}
}
printf("代码: %d\n", icmp_protocol->code);
printf("校验和: 0x%.4x\n", ntohs(icmp_protocol->checksum));
printf("标识: 0x%.4x\n", ntohs(icmp_protocol->identification));
printf("序列号: 0x%.4x\n", ntohs(icmp_protocol->sequence));
printf("================================================\n");
}
// 分析arp数据包
void resolve_arp_pkt(u_char *arg, const struct pcap_pkthdr *pkt_header, const u_char *pkt_content)
{
arp_header *arp_protocol;
arp_protocol = (arp_header*)(pkt_content + sizeof(ethernet_header));
printf(" ARP Protocol \n");
printf("================================================\n");
printf("硬件类型: ");
switch (ntohs(arp_protocol->hd_type))
{
case 1: {
printf("以太网");
break;
}
default: {
break;
}
}
printf(" (%d)\n", ntohs(arp_protocol->hd_type));
printf("Protocol Type: \n");
switch (ntohs(arp_protocol->protocol_type))
{
case 0x0800: {
printf("%s", "IP");
break;
}
case 0x0806: {
printf("%s", "ARP");
break;
}
case 0x8035: {
printf("%s", "RARP");
break;
}
default: {
printf("%s", "Unknown Protocol");
break;
}
}
printf(" (0x%04x)\n", ntohs(arp_protocol->protocol_type));
printf("硬件地址长度: %d\n", arp_protocol->hd_addr_len);
printf("协议地址长度: %d\n", arp_protocol->protocol_addr_len);
printf("操作码: ");
switch (ntohs(arp_protocol->op))
{
case 1: {
printf("arp request");
break;
}
case 2: {
printf("arp reply");
break;
}
case 3: {
printf("rarp request");
break;
}
case 4: {
printf("rarp reply");
break;
}
default: {
break;
}
}
printf(" (%i)\n", ntohs(arp_protocol->op));
printf("================================================\n");
}
// 分析ip数据包
void resolve_ip_pkt(u_char *arg, const struct pcap_pkthdr *pkt_header, const u_char *pkt_content)
{
ipv4_header *ip_protocol;
sockaddr_in source, dest;
char src_ip[MAX_ADDR_LEN], dst_ip[MAX_ADDR_LEN];
ip_protocol = (ipv4_header *)(pkt_content + sizeof(ethernet_header));
source.sin_addr.s_addr = ip_protocol->src_ip;
dest.sin_addr.s_addr = ip_protocol->dst_ip;
strncpy(src_ip, inet_ntoa(source.sin_addr), MAX_ADDR_LEN);
strncpy(dst_ip, inet_ntoa(dest.sin_addr), MAX_ADDR_LEN);
printf(" IP Protocol \n");
printf("================================================\n");
printf("版本: %d\n", ip_protocol->version_hd_len >> 4);
printf("首部长度: %d bytes\n", (ip_protocol->version_hd_len & 0x0f) * 4);
printf("服务类型: %d\n", ip_protocol->tos);
printf("总长度: %d\n", ntohs(ip_protocol->total_len));
printf("标识: 0x%.4x (%i)\n", ntohs(ip_protocol->identification));
printf("标志: %d\n", ntohs(ip_protocol->flags_offset) >> 13);
printf("保留位: %d\n", (ntohs(ip_protocol->flags_offset) & 0x8000) >> 15);
printf("不分片: %d\n", (ntohs(ip_protocol->flags_offset) & 0x4000) >> 14);
printf("有分片: %d\n", (ntohs(ip_protocol->flags_offset) & 0x2000) >> 13);
printf("片偏移: %d\n", ntohs(ip_protocol->flags_offset) & 0x1fff);
printf("生存时间: %d\n", ip_protocol->ttl);
printf("协议类型: ");
switch (ip_protocol->protocol)
{
case 1: {
printf("ICMP");
break;
}
case 6: {
printf("TCP");
break;
}
case 17: {
printf("UDP");
break;
}
default: {
break;
}
}
printf(" (%d)\n", ip_protocol->protocol);
printf("首部校验和: 0x%.4x\n", ntohs(ip_protocol->checksum));
printf("源ip: %s\n", src_ip);
printf("目的ip: %s\n", dst_ip);
printf("================================================\n");
if (ip_protocol->protocol == IP_PROTOCOL_TCP) {
resolve_tcp_pkt(arg, pkt_header, pkt_content);
}
else if (ip_protocol->protocol == IP_PROTOCOL_UDP) {
resolve_udp_pkt(arg, pkt_header, pkt_content);
}
else if (ip_protocol->protocol == IP_PROTOCOL_ICMP) {
resolve_icmp_pkt(arg, pkt_header, pkt_content);
}
}
// 分析以太网数据包
void resolve_ethernet_pkt(u_char *arg, const struct pcap_pkthdr *pkt_header, const u_char *pkt_content)
{
ethernet_header *ethernet_protocol; // 以太网协议
// 获取以太网数据内容
ethernet_protocol = (ethernet_header *)pkt_content;
printf(" Ethernet Protocol \n");
printf("================================================\n");
// 以太网目标地址
printf("目标Mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
ethernet_protocol->dst_mac[0],
ethernet_protocol->dst_mac[1],
ethernet_protocol->dst_mac[2],
ethernet_protocol->dst_mac[3],
ethernet_protocol->dst_mac[4],
ethernet_protocol->dst_mac[5]);
// 以太网源地址
printf("源Mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
ethernet_protocol->src_mac[0],
ethernet_protocol->src_mac[1],
ethernet_protocol->src_mac[2],
ethernet_protocol->src_mac[3],
ethernet_protocol->src_mac[4],
ethernet_protocol->src_mac[5]);
printf("类型: (0x%04x) ", ntohs(ethernet_protocol->protocol_type));
switch (ntohs(ethernet_protocol->protocol_type))
{
case 0x0800: {
printf("IP Protocol\n");
resolve_ip_pkt(arg, pkt_header, pkt_content);
break;
}
case 0x0806: {
printf("ARP Protocol\n");
resolve_arp_pkt(arg, pkt_header, pkt_content);
break;
}
case 0x0835: {
printf("RARP Protocol\n");
break;
}
default: {
printf("Unknown Protocol\n");
break;
}
}
printf("================================================\n");
}
int main(void)
{
pcap_t *pcap_handle;
int res;
struct pcap_pkthdr *header; // 数据包基本信息
const u_char *pkt_data;
time_t local_tv_sec;
struct tm *ltime;
char timestr[16];
int count = 1;
char err_buf[PCAP_ERRBUF_SIZE];
char *pdev_name = NULL;
pdev_name = pcap_lookupdev(err_buf);
if (pdev_name == NULL)
{
printf("%s\n", err_buf);
exit(-1);
}
// 打开网卡设备
if ((pcap_handle = pcap_open_live(pdev_name, 65536, 1, 1000, err_buf)) == NULL)
{
printf("%s\n", err_buf);
exit(-1);
}
if (pcap_datalink(pcap_handle) != DLT_EN10MB)
{
perror("pcap_datalink error:");
exit(-1);
}
while ((res = pcap_next_ex(pcap_handle, &header, &pkt_data)) >= 0)
{
// 超时
if (res == 0)
continue;
// 将时间戳转化为可识别格式
local_tv_sec = header->ts.tv_sec;
ltime = localtime(&local_tv_sec);
strftime(timestr, sizeof(timestr), "%H:%M:%S", ltime);
// 输出编号、时间戳和包长度
printf("==============================================================================\n");
printf("No.%d\ttime: %s\tlen: %ld\n", count++, timestr, header->len);
printf("==============================================================================\n");
char temp[16 + 1];
// 输出包
for (int i = 0; i < header->caplen; ++i)
{
printf("%.2x ", pkt_data[i]);
if (isgraph(pkt_data[i]) || pkt_data[i] == ' ') {
temp[i % MAX_LINE_LEN] = pkt_data[i];
}
else {
temp[i % MAX_LINE_LEN] = '.';
}
if (i % MAX_LINE_LEN == 15)
{
temp[MAX_LINE_LEN] = '\0';
printf(" ");
printf("%s", temp);
printf("\n");
memset(temp, 0, MAX_LINE_LEN);
}
}
printf("\n");
// 分析以太网数据包
resolve_ethernet_pkt(NULL, header, pkt_data);
}
if (res == -1)
{
printf("pcap_next_ex error:%s\n", pcap_geterr(pcap_handle));
pcap_close(pcap_handle);
exit(-1);
}
// 释放
pcap_close(pcap_handle);
return 0;
}