/tmp/ccxUiHJB.o:在函数‘P’中: sender.c:(.text+0x14):对‘sem_wait’未定义的引用 /tmp/ccxUiHJB.o:在函数‘V’中: sender.c:(.text+0x2e):对‘sem_post’未定义的引用 /tmp/ccxUiHJB.o:在函数‘main’中: sender.c:(.text+0xb1):对‘sem_open’未定义的引用 sender.c:(.text+0xce):对‘sem_open’未定义的引用 collect2: 错误:ld 返回 1
这个错误是因为你在代码中使用了一些未定义的函数,导致链接时出错。根据错误提示看,这些函数包括:sem_wait、sem_post和sem_open。
这些函数都是信号量相关的函数,需要在代码中包含对应的头文件<semaphore.h>
并使用-pthread
选项链接线程库,例如:
#include <semaphore.h>
#include <pthread.h>
// 编译时需要添加-pthread选项链接线程库
另外,还需要注意以下几点:
在使用
sem_open
函数时,需要指定信号量的名字,并且该名字必须以/
开头,例如:"/mysem"
。在使用
sem_wait
和sem_post
函数时,需要先通过sem_open
函数打开信号量并获取其标识符,然后才能进行P操作和V操作。
修改完代码并添加头文件和链接选项后,重新编译并链接即可。
void parseARPPacket(const uint8_t* arpData, const std::string& outputFile) { if (!fileExists(outputFile)) { std::ofstream createFile(outputFile); if (!createFile.is_open()) { std::cerr << "Failed to create output file: " << outputFile << std::endl; return; } createFile.close(); } std::ofstream outFile(outputFile, std::ios::out | std::ios::trunc); if (!outFile.is_open()) { std::cerr << "Failed to open output file: " << outputFile << std::endl; return; } // 解析ARP数据包 // 待实现***** // 输出解析结果到文件 outFile << "Hardware Type: " << std::endl; outFile << "Protocol Type: " << std::endl; outFile << "Hardware Address Length: " << std::endl; outFile << "Protocol Address Length: " << std::endl; outFile << "Operation: " << std::endl; outFile << "Sender MAC: " << std::endl; outFile << "Sender IP: " << std::endl; outFile << "Target MAC: " << std::endl; outFile << "Target IP: " << std::endl; // 关闭文件 outFile.close(); }将函数缺少部分补充完整
解析ARP数据包并提取字段
以下是基于 uint8_t
数组进行字节级操作的 C++ 实现,用于解析 ARP 数据包中的各个字段:
定义结构体
为了方便访问 ARP 报文的各部分,可以按照给定的格式定义一个对应的结构体。
#include <iostream>
#include <cstring>
#pragma pack(push, 1) // 禁用结构体填充
struct ArpHeader {
uint16_t htype; // Hardware type (e.g., Ethernet = 1)
uint16_t ptype; // Protocol type (e.g., IPv4 = 0x0800)
uint8_t hlen; // Hardware address length (e.g., MAC = 6)
uint8_t plen; // Protocol address length (e.g., IPv4 = 4)
uint16_t oper; // Operation code (1=request, 2=reply)
uint8_t sha[6]; // Sender hardware address (MAC)
uint8_t spa[4]; // Sender protocol address (IP)
uint8_t tha[6]; // Target hardware address (MAC)
uint8_t tpa[4]; // Target protocol address (IP)
};
#pragma pack(pop)
上述结构体严格按照提供的 ARP 头部格式定义[^2],并通过 #pragma pack(push, 1)
来确保没有额外的内存对齐填充。
提取字段功能实现
下面是一个函数 parseARPPacket
的实现,它接受一个指向原始数据包的指针以及数据包长度作为参数,并从中提取所需的字段。
void parseARPPacket(const uint8_t* packet, size_t packetSize) {
if (packetSize < sizeof(ArpHeader)) {
std::cerr << "Packet too small to contain an ARP header." << std::endl;
return;
}
const ArpHeader* arpHdr = reinterpret_cast<const ArpHeader*>(packet);
// Extract fields from the ARP header
uint16_t hardwareType = ntohs(arpHdr->htype); // Convert network byte order to host byte order
uint16_t protocolType = ntohs(arpHdr->ptype);
uint8_t hardwareAddressLength = arpHdr->hlen;
uint8_t protocolAddressLength = arpHdr->plen;
uint16_t operationCode = ntohs(arpHdr->oper);
char senderMacStr[18];
snprintf(senderMacStr, sizeof(senderMacStr), "%02X:%02X:%02X:%02X:%02X:%02X",
arpHdr->sha[0], arpHdr->sha[1], arpHdr->sha[2],
arpHdr->sha[3], arpHdr->sha[4], arpHdr->sha[5]);
char senderIpStr[16];
snprintf(senderIpStr, sizeof(senderIpStr), "%u.%u.%u.%u",
arpHdr->spa[0], arpHdr->spa[1], arpHdr->spa[2], arpHdr->spa[3]);
char targetMacStr[18];
snprintf(targetMacStr, sizeof(targetMacStr), "%02X:%02X:%02X:%02X:%02X:%02X",
arpHdr->tha[0], arpHdr->tha[1], arpHdr->tha[2],
arpHdr->tha[3], arpHdr->tha[4], arpHdr->tha[5]);
char targetIpStr[16];
snprintf(targetIpStr, sizeof(targetIpStr), "%u.%u.%u.%u",
arpHdr->tpa[0], arpHdr->tpa[1], arpHdr->tpa[2], arpHdr->tpa[3]);
// Output extracted information
std::cout << "Hardware Type: " << hardwareType << std::endl;
std::cout << "Protocol Type: 0x" << std::hex << protocolType << std::dec << std::endl;
std::cout << "Hardware Address Length: " << static_cast<int>(hardwareAddressLength) << std::endl;
std::cout << "Protocol Address Length: " << static_cast<int>(protocolAddressLength) << std::endl;
std::cout << "Operation Code: " << operationCode << std::endl;
std::cout << "Sender MAC Address: " << senderMacStr << std::endl;
std::cout << "Sender IP Address: " << senderIpStr << std::endl;
std::cout << "Target MAC Address: " << targetMacStr << std::endl;
std::cout << "Target IP Address: " << targetIpStr << std::endl;
}
此代码片段实现了从 uint8_t
数组中读取 ARP 数据包的功能,并将其转换为人可读的形式输出。注意使用了 ntohs()
函数来处理网络字节序到主机字节序的转换。
使用示例
假设我们已经通过某种方式捕获了一个完整的 ARP 数据包存储在一个缓冲区中,则可以通过调用该函数来进行分析。
int main() {
// Example buffer containing a raw ARP packet data.
uint8_t exampleArpPacket[] = {
0x00, 0x01, // Hardware type (Ethernet)
0x08, 0x00, // Protocol type (IPv4)
0x06, // Hardware address length (MAC is 6 bytes)
0x04, // Protocol address length (IPv4 is 4 bytes)
0x00, 0x01, // Operation code (ARP request)
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, // Sender MAC address
0xc0, 0xa8, 0x01, 0x01, // Sender IP address
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Target MAC address (all zeros for requests)
0xc0, 0xa8, 0x01, 0x02 // Target IP address
};
parseARPPacket(exampleArpPacket, sizeof(exampleArpPacket));
return 0;
}
以上展示了如何创建测试环境下的模拟 ARP 数据包及其解析过程。
相关推荐

















