2013-05-17 2 views
1

J'essaie de modifier certains champs dans l'en-tête IP et TCP dans un hook de post-routage netfilter, mais je n'arrive pas à faire fonctionner correctement la fonction checksum TCP du noyau pour l'amender ensuite. La somme de contrôle est correcte pendant l'établissement de liaison TCP, mais dès que le paquet a une charge utile, la somme de contrôle est erronée.Calcul de la somme de contrôle TCP dans un module netfilter

J'ai extrait ce code de contrôle en creusant autour de la source TCP. Je suis assez sûr que tcplen est correct, correspondant à l'en-tête TCP attendu + la taille de la charge utile.

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; 
} 

Ai-je raison de penser que tcp_v4_check calcule l'en-tête et psuedo calcule la somme de contrôle csum_partial déplié pour la charge utile et tcp_header? Je veux vraiment éviter d'écrire la fonction moi-même car le noyau sera beaucoup plus rapide car les fonctions sous-jacentes utilisent l'assemblage pour le calcul.

Existe-t-il une autre méthode qui pourrait fonctionner? Ou y a-t-il quelque chose qui me manque?

+0

Je voulais juste vous remercier pour ce post. Cela m'a aidé à résoudre quelques problèmes que j'ai rencontrés avec mon code netfilter. – sparticvs

Répondre

3

Il n'y a pas besoin d'appel supplémentaire à skb_is_nonlinear(), puisque include/linux/skbuff.h:

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

, vous devez également:

ip_header->check = 0 

avant:

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

Il a fallu du temps pour arriver ici mais le problème semble être que le tampon socket n'est pas toujours linéaire, le code suivant le vérifie avant de calculer la somme de contrôle.

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