【问题标题】:Is there anythign wrong with this checksum calculation?这个校验和计算有什么问题吗?
【发布时间】:2012-10-24 01:45:39
【问题描述】:

来自这个网站:http://www.enderunix.org/docs/en/rawipspoof/

我拉了以下函数

unsigned short in_cksum(unsigned short *addr, int len)
{
    int nleft = len;
    int sum = 0;
    unsigned short *w = addr;
    unsigned short answer = 0;

    while (nleft > 1) {
        sum += *w++;
        nleft -= 2;
    }

    if (nleft == 1) {
        *(unsigned char *) (&answer) = *(unsigned char *) w;
        sum += answer;
    }

    sum = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);
    answer = ~sum;
    return (answer);
}

unsigned short in_cksum_tcp(int src, int dst, unsigned short *addr, int len)
{
    struct psd_tcp buf;
    u_short ans;

    memset(&buf, 0, sizeof(buf));
    buf.src.s_addr = src;
    buf.dst.s_addr = dst;
    buf.pad = 0;
    buf.proto = IPPROTO_TCP;
    buf.tcp_len = htons(len);
    memcpy(&(buf.tcp), addr, len);
    ans = in_cksum((unsigned short *)&buf, 12 + len);
    return (ans);
}

但是,当我对看到的传入 TCP 数据包运行此程序时,我没有得到与当前相同的校验和结果(我保存传入的 TCP 校验和并将数据包上的校验和设置为零,然后再尝试运行校验和函数)

现在,当我对 IP 标头运行“in_cksum”时,我得到了正确的答案。

这是来自该站点的 TCP 伪标头:

struct psd_tcp {
    struct in_addr src;
    struct in_addr dst;
    unsigned char pad;
    unsigned char proto;
    unsigned short tcp_len;
    struct tcphdr tcp;
};

是不是缺少了一些东西来完成这项工作?

【问题讨论】:

  • 对我来说,不清楚什么时候算对,什么时候算错?
  • 当我使用 in_cksum() 作为 IP 标头的校验和时,我得到了正确的结果。当我将 in_cksum_tcp() 用于 TCP 校验和时,我得到了错误的总和。唯一的修改是我在调用任一方法之前将 IP 和 TCP 校验和字段设置为零。
  • 你确定你的编译器没有在struct psd_tcp中添加填充,它真的有12个字节长(没有struct tcphdr)? @德里克
  • 我可以仔细检查。 sizeof() 总是会给你准确的答案吗?我知道 sizeof 告诉我 12 个字节,但也许我需要在声明中指定打包。
  • 这个神奇的数字 12 是什么意思?更好地使用 sizeof() 那里。

标签: c tcp network-programming ip freebsd


【解决方案1】:

嗯,你的主要错误是忘记在校验和计算中包含 TCP 有效负载,只是标题(oops)。请参阅 RFC 793 第 3.1 节 (http://www.ietf.org/rfc/rfc793.txt) 了解此内容:

校验和字段是标题和文本中所有 16 位字的反码和的 16 位反码。

当然这是我假设 'len' 参数是 TCP 标头的长度;如果它包含有效负载,那么您会遇到不同的问题(memcpy 到比源更小的缓冲区...)。

请注意,当您对有效负载进行校验和时,RFC 中还有一个很容易遗漏的小东西:

如果一个段包含奇数个要校验和的标题和文本八位字节,则最后一个八位字节在右侧用零填充以形成一个用于校验和的 16 位字。

请记住在计算校验和之前根据需要用零填充有效负载。

【讨论】:

  • 我实际上是在使用它来校验没有有效负载数据的数据包。它们是 syn/ack 数据包。
猜你喜欢
  • 2012-03-27
  • 2011-01-11
  • 2014-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多