尝试修复此代码一段时间没有运气,尝试了计算IPv4标头校验和的不同实现,但是它们的输出与我的程序输出有很大不同:
我从linux kernel窃取的函数来执行此操作:
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; }
示例标头(字节): 45009d4326400406af6cd052ed12ac10a51
调用上述函数的程序部分将校验和分配给标题并打印标题和校验和:
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");
debug()只是一个printf()包装器,下面是示例输出:
newpacket checksum set to 6caf
45009d4326400406af6cd052ed12ac10a51
来自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);
}
提前致谢。
答案 0 :(得分:0)
只是从评论和我自己多一点扩展@SergeyA。如果您查看引用above的文件,您会注意到该功能的评论
ip_fast_csum - 有效地计算IPv4标头校验和。
您不希望计算您想要TCP校验和的IPv4标头校验和。这些是OSI模型here中的单独层。要计算TCP校验和,您需要按照these好的人描述。
如前所述,只使用内核代码,这里有一个函数可以计算TCP校验和。下面我将复制它的描述和标题。
static inline __sum16 tcp_v4_check(int len, __be32 saddr,
__be32 daddr, __wsum base)
- 计算(/检查)TCP校验和
但是,如果你想这么做的话。查看您引用的同一文件,您可以使用该函数计算TCP数据包的伪标头。
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
__u8 proto, __wsum sum)
返回输入数据的伪标头校验和。结果是32位 展开。
这只是psuedo标题,但是从那里你需要计算我相信的总校验和(不是100%肯定)你可以使用你之前显示的函数计算,如果你填充前面描述的伪标题。
另外,我没有检查过这段代码,但从初看起来看起来非常准确,所以here是计算TCP校验和的C /汇编方式。
答案 1 :(得分:0)
只是想发布并解决这个问题,我在尝试了很多实现后解决了这个问题,唯一有效的是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;
}
https://github.com/inliniac/suricata/blob/master/src/decode-ipv4.h
我希望这也有助于其他人,suricata也有出色的代码库,编写良好的工作代码。
为那些试图提供帮助的人欢呼并感谢你。
答案 2 :(得分:0)
我最近遇到了同样的问题,我发现自己错了。将校验和字段设置为零,然后计算如下:
newpacket.ipheader->check = 0;
newpacket.ipheader->check = ip_fast_csum ((unsigned short *) newpacket.ipheader, IP4_HDRLEN);