Да, если вы измените структуру skbuff и вычислите соответствующие контрольные суммы, вам просто нужно вернуть NF_ACCEPT. Ядро за вас разберется.
Я сделал это в своей диссертации. Вот некоторый код, который я сделал (он не расширяет и не урезает skbuff, но меняет поле в полезной нагрузке приложения. Однако я также сделал некоторый код, расширяющий skbuff, и теория та же): *
unsigned int pre_routing_hook(filter_specs* sp, 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 udphdr* udp;
__tp(pdu)* pdu;
/*Omitted some sanity checks */
iph = ip_hdr(skb);
udp = (struct udphdr*) (((char*) iph) + (iph->ihl << 2));
//I didn't care about udp checksum so I've stored zero in this field.
udp->check = 0;
switch (iph->protocol) {
case IPPROTO_UDP:
pdu = (__tp(pdu)*) (((char*) iph) + (iph->ihl << 2)
+ sizeof(struct udphdr));
swap_pdu_byte_order(pdu);
pdu->timestamp = get_kernel_current_time() -
(pdu->timestamp + pdu->rtt * 1000);
swap_pdu_byte_order(pdu);
break;
default:
printk("\tProtocol not supported.\n");
}
return NF_ACCEPT;
}
РЕДАКТИРОВАТЬ : Я посмотрел на код, который вы опубликовали, и вот что я придумал. У меня это работает:
#include <linux/ip.h>
#include <linux/in.h>
static uint16_t csum(uint16_t* buff, int nwords) {
uint32_t sum;
for (sum = 0; nwords > 0; nwords--)
sum += *buff++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ((uint16_t) ~sum);
}
//I'm assuming this will run in PRE_ROUTING
unsigned int main_hook(unsigned int hooknum,
struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, int(*okfn)(struct sk_buff*)) {
uint16_t lets_keep_the_original_size;
struct in_device* ipa;
iph = ip_hdr(sock_buff);
lets_keep_the_original_size = ntohs(iph->tot_len);
if(iph->protocol == 1) {
if(skb_headroom(skb) < sizeof(struct iphdr)) {
if( 0 != pskb_expand_head(skb, (sizeof(struct iphdr))-
skb_headroom(skb),0,GFP_ATOMIC) ){
kfree_skb(skb);
return NF_STOLEN;
}
}
iph = (struct iphdr*) skb_push(skb, sizeof(struct iphdr));
iph->proto = IPPROTO_IP;
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = htons(lets_keep_the_original_size + sizeof(struct iphdr));
iph->id = 0;
iph->frag_off = 0;
iph->ttl = 60;
//This must be zero to be able to calculate it with csum above.
iph->check = 0;
//in is the interface where the packet arrived, provided by netfilters.
//In PRE_ROUTING there is no out interface yet so you'll need to add
//the ip manually:
ipa = (struct in_device*) in->ip_ptr;
iph->saddr = ipa->ifa_list->ifa_address;
//in_aton already gives you the address in network byte order .
//You can just add an integer, but I've chosen to use in_aton
//so the code is more readable
iph->daddr = in_aton("192.168.1.1");
//Here is the important part.
iph->check = csum((uint16_t*) iph, (iph->ihl << 1));
//Let the kernel deal with the rest for us.
return NF_ACCEPT;
}
return NF_ACCEPT;
}
Дайте мне знать, если я могу вам чем-то помочь.