[英]Calculating TCP Checksum in a netfilter module
我試圖在netfilter postrouting鈎子中更改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計算psuedo標頭並且csum_partial計算有效負載和tcp_header的展開校驗和?
我真的想避免自己編寫函數,因為內核會更快,因為底層函數使用匯編進行計算。
有沒有可行的替代方法? 還是我錯過了什么?
因為include / linux / skbuff.h,所以不需要額外調用skb_is_nonlinear():
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);
到達此處需要一段時間,但問題似乎是套接字緩沖區並不總是線性的,以下代碼確保它在計算校驗和之前。
if (skb_is_nonlinear(skb)) {
if (skb_linearize(skb) != 0) {
return NF_DROP;
}
iph = ip_hdr(skb);
tcph = (void *)iph + (iph->ihl << 2);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.