static const uint8_t 内部函数改变值
static const uint8_t inside function changes value
我正在使用 libpcap 编写一个小型分析工具,它可以嗅探以太网设备上的流量并对接收到的数据包执行某种分析。为此,我有明显的 libpcap 循环:
void packet_loop(u_char *args, const struct pcap_pkthdr *header,
const u_char *packetdata) {
int size = (int)header->len;
//Before we map the buffer to the ethhdr struct,
//we check if the size fits
if (ETHER_HDR_LEN > size)
return;
const struct ethhdr *ethh = (const struct ethhdr *)(packetdata);
//If this protocol is IPv4 and the packet size is bigger than
//ETH hdr size
if (ETHERTYPE_IP == ntohs(ethh->h_proto)) {
//Before we map the buffer to the iph struct,
//we check if the size fits
if (ETHER_HDR_LEN + (int)sizeof(struct iphdr) > size)
return;
const struct iphdr *iph = (const struct iphdr*)
(packetdata + sizeof(struct ethhdr));
//If this protocol isn't UDP and the header length
//isn't 5 (20bytes)
if (IPPROTO_UDP != iph->protocol && 5 != iph->ihl)
return;
//eval_udp(packetdata, size);
const struct udphdr *udph = (const struct udphdr*)
(packetdata + sizeof(struct ethhdr) +
sizeof(struct iphdr));
if (DATA_SRCPORT == ntohs(udph->uh_sport) &&
DATA_DESTPORT == ntohs(udph->uh_dport)) {
analyse_data(packetdata);
}
}
}
在接收到特定数据包类型时调用以下代码。如您所见,我正在使用静态变量来跟踪前一个数据包,以便比较两个数据包。
void analyse_data(const uint8_t *packet)
{
if (!packet)
return;
static const uint8_t *basepacket;
//If there was no packet to base our analysis on, we will wait for one
if (!basepacket) {
basepacket = packet;
return;
}
const struct dataheader *basedh = (const struct dataheader *)
(__OFFSETSHERE__ + basepacket);
const struct dataheader *dh = (const struct dataheader *)
(__OFFSETSHERE__ + packet);
printf("%d -> %d\n", ntohs(basedh->sequenceid),
ntohs(dh->sequenceid));
basepacket = packet;
return;
}
struct dataheader
是一个常规结构,就像 etthdr
一样。我希望打印输出像这样:
0 -> 1
1 -> 2
2 -> 3
不幸的是,我得到了不同的打印输出,这基本上是正确的。但是大约每第 20-40 个数据包,我就会看到以下行为(示例):
12->13
13->14
0->15
15->16
...
有趣的是,当我只收到我关注的特定类型的数据包时,这不会发生 (8-10 Mbit/s)。然而,一旦我在 "regular" 网络环境(大约 100Mbit/s)中使用我的工具,我就会出现这种行为。我检查了我的 if 语句,它可以完美地过滤数据包(检查 UDP 源和目标端口)。 Wireshark 还向我显示,在那些端口上没有一个不是该特定类型的数据包。
libpcap 控制它传递给您的 packet_loop
的数据包数据。一旦 packet_loop
returns,您就无法保证数据包数据的指针指向什么 - libpcap 可能会丢弃数据包,或者它可能会为新数据包重用相同的 space。
这意味着如果你想比较 2 个数据包,你必须复制第一个数据包 - 你不能保存一次调用 packet_loop
的指针并期望该指针有效并指向在以后调用 packet_loop
时使用相同的数据包。所以你的代码可以更改为例如
void analyse_data(const uint8_t *packet, int size )
{
if (!packet)
return;
static const uint8_t basepacket[1024*64];
static int has_basepacket;
//If there was no packet to base our analysis on, we will wait for one
if (!has_basepacket){
if (size < sizeof basepacket) {
memcpy(basepacket, packet, size);
has_basepacket = 1;
}
return;
}
...
此外,请确保您在所有地方都验证尺寸。仅仅因为以太网类型表明它是 IPv4 数据包,并不意味着您可以相信它包含完整的 IP 数据包。仅仅因为 IP header 表示它是 20 个字节,并不意味着您可以相信它包含完整的 IP 数据包,对于您尝试解码的所有层等等。
我正在使用 libpcap 编写一个小型分析工具,它可以嗅探以太网设备上的流量并对接收到的数据包执行某种分析。为此,我有明显的 libpcap 循环:
void packet_loop(u_char *args, const struct pcap_pkthdr *header,
const u_char *packetdata) {
int size = (int)header->len;
//Before we map the buffer to the ethhdr struct,
//we check if the size fits
if (ETHER_HDR_LEN > size)
return;
const struct ethhdr *ethh = (const struct ethhdr *)(packetdata);
//If this protocol is IPv4 and the packet size is bigger than
//ETH hdr size
if (ETHERTYPE_IP == ntohs(ethh->h_proto)) {
//Before we map the buffer to the iph struct,
//we check if the size fits
if (ETHER_HDR_LEN + (int)sizeof(struct iphdr) > size)
return;
const struct iphdr *iph = (const struct iphdr*)
(packetdata + sizeof(struct ethhdr));
//If this protocol isn't UDP and the header length
//isn't 5 (20bytes)
if (IPPROTO_UDP != iph->protocol && 5 != iph->ihl)
return;
//eval_udp(packetdata, size);
const struct udphdr *udph = (const struct udphdr*)
(packetdata + sizeof(struct ethhdr) +
sizeof(struct iphdr));
if (DATA_SRCPORT == ntohs(udph->uh_sport) &&
DATA_DESTPORT == ntohs(udph->uh_dport)) {
analyse_data(packetdata);
}
}
}
在接收到特定数据包类型时调用以下代码。如您所见,我正在使用静态变量来跟踪前一个数据包,以便比较两个数据包。
void analyse_data(const uint8_t *packet)
{
if (!packet)
return;
static const uint8_t *basepacket;
//If there was no packet to base our analysis on, we will wait for one
if (!basepacket) {
basepacket = packet;
return;
}
const struct dataheader *basedh = (const struct dataheader *)
(__OFFSETSHERE__ + basepacket);
const struct dataheader *dh = (const struct dataheader *)
(__OFFSETSHERE__ + packet);
printf("%d -> %d\n", ntohs(basedh->sequenceid),
ntohs(dh->sequenceid));
basepacket = packet;
return;
}
struct dataheader
是一个常规结构,就像 etthdr
一样。我希望打印输出像这样:
0 -> 1
1 -> 2
2 -> 3
不幸的是,我得到了不同的打印输出,这基本上是正确的。但是大约每第 20-40 个数据包,我就会看到以下行为(示例):
12->13
13->14
0->15
15->16
...
有趣的是,当我只收到我关注的特定类型的数据包时,这不会发生 (8-10 Mbit/s)。然而,一旦我在 "regular" 网络环境(大约 100Mbit/s)中使用我的工具,我就会出现这种行为。我检查了我的 if 语句,它可以完美地过滤数据包(检查 UDP 源和目标端口)。 Wireshark 还向我显示,在那些端口上没有一个不是该特定类型的数据包。
libpcap 控制它传递给您的 packet_loop
的数据包数据。一旦 packet_loop
returns,您就无法保证数据包数据的指针指向什么 - libpcap 可能会丢弃数据包,或者它可能会为新数据包重用相同的 space。
这意味着如果你想比较 2 个数据包,你必须复制第一个数据包 - 你不能保存一次调用 packet_loop
的指针并期望该指针有效并指向在以后调用 packet_loop
时使用相同的数据包。所以你的代码可以更改为例如
void analyse_data(const uint8_t *packet, int size )
{
if (!packet)
return;
static const uint8_t basepacket[1024*64];
static int has_basepacket;
//If there was no packet to base our analysis on, we will wait for one
if (!has_basepacket){
if (size < sizeof basepacket) {
memcpy(basepacket, packet, size);
has_basepacket = 1;
}
return;
}
...
此外,请确保您在所有地方都验证尺寸。仅仅因为以太网类型表明它是 IPv4 数据包,并不意味着您可以相信它包含完整的 IP 数据包。仅仅因为 IP header 表示它是 20 个字节,并不意味着您可以相信它包含完整的 IP 数据包,对于您尝试解码的所有层等等。