这个校验和计算有什么问题吗?

时间:2012-11-03 17:14:55

标签: c tcp network-programming ip freebsd

来自此网站: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;
};

是否缺少使这项工作的东西?

1 个答案:

答案 0 :(得分:1)

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

  

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

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

请注意,当您对有效负载进行校验和时,RFC中的另一件小事很容易错过:

  

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

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