C IPv4报头校验和计算,我缺少什么
尝试修复此代码已有一段时间了,但运气不佳,尝试了计算IPv4报头校验和的不同实现,但是它们的输出与我的程序输出大不相同: 我从linux中偷来的函数可以做到这一点:C IPv4报头校验和计算,我缺少什么,c,linux,sockets,networking,tcp,C,Linux,Sockets,Networking,Tcp,尝试修复此代码已有一段时间了,但运气不佳,尝试了计算IPv4报头校验和的不同实现,但是它们的输出与我的程序输出大不相同: 我从linux中偷来的函数可以做到这一点: static inline uint16_t ip_fast_csum(const void *iph, unsigned int ihl){ unsigned int sum; asm(" movl (%1), %0\n" " subl $4, %2\n" " jb
static inline uint16_t ip_fast_csum(const void *iph, unsigned int ihl){
unsigned int sum;
asm(" movl (%1), %0\n"
" subl $4, %2\n"
" jbe 2f\n"
" addl 4(%1), %0\n"
" adcl 8(%1), %0\n"
" adcl 12(%1), %0\n"
"1: adcl 16(%1), %0\n"
" lea 4(%1), %1\n"
" decl %2\n"
" jne 1b\n"
" adcl $0, %0\n"
" movl %0, %2\n"
" shrl $16, %0\n"
" addw %w2, %w0\n"
" adcl $0, %0\n"
" notl %0\n"
"2:"
/* Since the input registers which are loaded with iph and ihl
are modified, we must also specify them as outputs, or gcc
will assume they contain their original values. */
: "=r" (sum), "=r" (iph), "=r" (ihl)
: "1" (iph), "2" (ihl)
: "memory");
return ( uint16_t)sum; }
示例标题(字节):
45009D432460406AF6CD052ED12AC10A51
我的程序中调用上述函数的部分将校验和分配给报头,并打印报头和校验和:
newpacket.ipheader->check = ip_fast_csum ((unsigned short *) newpacket.ipheader, IP4_HDRLEN);
debug(5,"newpacket checksum set to %0x\r\n",newpacket.ipheader->check);
uint8_t *ipbuf=(uint8_t *)newpacket.ipheader;
for(i=0;i<IP4_HDRLEN;i++){
debug(5,"%0x",ipbuf[i]);
}debug(5,"\n");
wireshark告诉我的屏幕盖:
你能帮我告诉我我做错了什么吗
这是我通常使用的功能:
inline unsigned short csum (unsigned short *buf, int nwords) {
unsigned long sum;
for (sum = 0; nwords > 0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return (unsigned short) (~sum);
}
提前谢谢。只是想从评论和我自己中进一步扩展@SergeyA。如果查看引用的文件,您会在该函数的注释中注意到 ip_fast_csum-高效地计算IPv4报头校验和 您不想计算IPv4报头校验和您想计算TCP校验和。这些是OSI模型中的独立层。要计算TCP校验和,您需要按照人们所描述的那样做 正如您之前所希望的那样,只使用内核代码,这里有一个函数可以计算TCP校验和。下面我将复制它的描述和标题
static inline __sum16 tcp_v4_check(int len, __be32 saddr,
__be32 daddr, __wsum base)
- 计算(/检查)TCP校验和
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
__u8 proto, __wsum sum)
返回输入数据的伪标头校验和。结果是32位
展开
这只是psuedo报头,但是从那里你需要计算总校验和,我相信(不是100%确定),如果你把前面描述的伪报头放到它上面,你可以使用前面展示的函数来计算
顺便说一句,我没有检查过这段代码,但乍一看,这段代码似乎非常准确,计算TCP校验和的C/assembly方法也是如此。我只是想发布这段代码并解决这个问题,在尝试了许多实现之后,我已经解决了这个问题,唯一有效的是Suricata IDPS的代码
static inline uint16_t IPV4CalculateChecksum(uint16_t *pkt, uint16_t hlen)
{
uint32_t csum = pkt[0];
csum += pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[6] + pkt[7] + pkt[8] +
pkt[9];
hlen -= 20;
pkt += 10;
if (hlen == 0) {
;
} else if (hlen == 4) {
csum += pkt[0] + pkt[1];
} else if (hlen == 8) {
csum += pkt[0] + pkt[1] + pkt[2] + pkt[3];
} else if (hlen == 12) {
csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5];
} else if (hlen == 16) {
csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
pkt[7];
} else if (hlen == 20) {
csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
pkt[7] + pkt[8] + pkt[9];
} else if (hlen == 24) {
csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11];
} else if (hlen == 28) {
csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13];
} else if (hlen == 32) {
csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] +
pkt[14] + pkt[15];
} else if (hlen == 36) {
csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] +
pkt[14] + pkt[15] + pkt[16] + pkt[17];
} else if (hlen == 40) {
csum += pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4] + pkt[5] + pkt[6] +
pkt[7] + pkt[8] + pkt[9] + pkt[10] + pkt[11] + pkt[12] + pkt[13] +
pkt[14] + pkt[15] + pkt[16] + pkt[17] + pkt[18] + pkt[19];
}
csum = (csum >> 16) + (csum & 0x0000FFFF);
csum += (csum >> 16);
return (uint16_t) ~csum;
}
我希望这也能帮助其他人,suricata拥有优秀的代码库,编写良好的工作代码
干杯并感谢所有试图帮助我的人。我最近遇到了同样的问题,我发现我错了。计算前将校验和字段设置为零,如下所示:
newpacket.ipheader->check = 0;
newpacket.ipheader->check = ip_fast_csum ((unsigned short *) newpacket.ipheader, IP4_HDRLEN);
,和是提供有关如何计算IPv4标头校验和的算法的源。看起来您正在计算IP标头校验和。Wireshark似乎显示了TCP报头校验和。仅在@SergeyA上展开,您似乎已将IP层校验和放入TCP层。或者用更“官方”的术语。你混淆了第3层和第4层。嗨,TCP校验和在wireshark中很好,如果你看图片,只有ip校验和是红色的。我在维基百科上读了几次,似乎还是遗漏了一些东西。嗨,TCP校验和很好,我有一个单独的函数来计算它。wireshark显示了良好的TCP校验和,所以我不担心,TCP校验和需要TCP heder+数据+ip伪头。这是针对ipv4报头校验和的,该校验和是独立的,并且严格适用于ipv4报头。啊,好吧,从你提供的图片和我认为你把IP校验和放在TCP字段中的文本来看,我犯了一个错误。很抱歉。
newpacket.ipheader->check = 0;
newpacket.ipheader->check = ip_fast_csum ((unsigned short *) newpacket.ipheader, IP4_HDRLEN);