【问题标题】:Calculating TCP Checksum in a netfilter module在 netfilter 模块中计算 TCP 校验和
【发布时间】:2013-05-17 14:02:23
【问题描述】:

我正在尝试更改 netfilter 后路由挂钩中 IP 和 TCP 标头中的某些字段,但是我似乎无法让内核 TCP 校验和功能正常工作以在之后对其进行修改。

在 TCP 握手期间校验和正常,但一旦数据包有任何有效负载,校验和就会出错。

我从挖掘 TCP 源代码中提取了这个校验和代码。我相当确定 tcplen 是正确的,与预期的 TCP 标头 + 有效负载大小匹配。

static unsigned int posthook_fn(
    unsigned int hooknum, 
    struct sk_buff *skb,
    const struct net_device *in, 
    const struct net_device *out,
    int (*okfn)(struct sk_buff *))
{
  struct iphdr *iph;
  struct tcphdr *tcph;
  iph = ip_hdr(skb);
  tcph = (struct tcphdr *)(skb->data + iph->ihl * 4);

  tcph->source = port;
  iph->saddr = addr;

  tcplen = (skb->len - (ip_header->ihl << 2));
  tcph->check = 0; 
  tcph->check = tcp_v4_check(tcph, tcplen, 
        iph->saddr, 
        iph->daddr, 
        csum_partial((char *)tcph, tcplen, 0)); 
  skb->ip_summed = CHECKSUM_NONE; //stop offloading

  ip_header->check = ip_fast_csum((u8 *)iph, iph->ihl);         

  return NF_ACCEPT;
}

我认为 tcp_v4_check 计算伪标头而 csum_partial 计算有效负载和 tcp_header 的展开校验和是否正确?

我真的想避免自己编写函数,因为内核会更快,因为底层函数使用汇编进行计算。

是否有其他可行的方法?还是我错过了什么?

【问题讨论】:

  • 我只是想感谢你的这篇文章。它帮助我解决了我在使用 netfilter 代码时遇到的几个问题。

标签: c linux tcp kernel netfilter


【解决方案1】:

不需要额外调用 skb_is_nonlinear(),因为 include/linux/skbuff.h:

static inline int skb_linearize(struct sk_buff *skb)
{
         return skb_is_nonlinear(skb) ? __skb_linearize(skb) : 0;
}

另外,你必须:

ip_header->check = 0

之前:

ip_header->check = ip_fast_csum((u8 *)iph, iph->ihl);

【讨论】:

    【解决方案2】:

    到这里花了一些时间,但问题似乎是套接字缓冲区并不总是线性的,下面的代码确保它在计算校验和之前。

    if (skb_is_nonlinear(skb)) {
        if (skb_linearize(skb) != 0) {
            return NF_DROP;
        }
        iph = ip_hdr(skb);
        tcph = (void *)iph + (iph->ihl << 2);
    }
    

    【讨论】:

      猜你喜欢
      • 2018-02-09
      • 1970-01-01
      • 1970-01-01
      • 2015-01-04
      • 2016-03-09
      • 1970-01-01
      • 1970-01-01
      • 2019-01-30
      • 2012-10-08
      相关资源
      最近更新 更多