Netfilter例3:ipヘッダの拡張

8392 ワード

最初の2つの例は比較的簡単な応用である.この例では、メッセージヘッダを拡張し、拡張ヘッダを追加します.
/*
* This programe is working as plugin of netfilter which will pin a timestamp to
* the destination header of ipv6 packet every x seconds when the packet is 
* the object multicast packet.
*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 

MODULE_LICENSE("GPL");
MODULE_AUTHOR("newand");
MODULE_DESCRIPTION("Change the header of ipv6 packet");

#define PRINT(fmt,args...) printk("debug: " fmt, ##args)


/* IP6 Hooks */
/* After promisc drops
, checksum checks. */
#define NF_IP6_PRE_ROUTING  0
/* If the packet is destined for this box. */
#define NF_IP6_LOCAL_IN     1
/* If the packet is destined for another interface. */
#define NF_IP6_FORWARD      2
/* Packets coming from a local process. */
#define NF_IP6_LOCAL_OUT        3
/* Packets about to hit the wire. */
#define NF_IP6_POST_ROUTING 4


/*sequence of measeure
 sample packet*/
static int sample_seq = 0;

/*Next header destination header*/
struct ip6_dst_hdr
{
		uint8_t ip6d_nxt;
		uint8_t ip6d_len;
		uint8_t ip6d_opt_type;
		uint8_t ip6d_opt_len;
		uint32_t ip6d_ssn;
		uint32_t ip6d_sec;
		uint32_t ip6d_usec;
};

/*
* Debug print the addresss of ipv6 packets
*/
inline
void print_6addr(const struct in6_addr *addr)
{
    PRINT("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x
", (int)addr->s6_addr[0], (int)addr->s6_addr[1], (int)addr->s6_addr[2], (int)addr->s6_addr[3], (int)addr->s6_addr[4], (int)addr->s6_addr[5], (int)addr->s6_addr[6], (int)addr->s6_addr[7], (int)addr->s6_addr[8], (int)addr->s6_addr[9], (int)addr->s6_addr[10], (int)addr->s6_addr[11], (int)addr->s6_addr[12], (int)addr->s6_addr[13], (int)addr->s6_addr[14], (int)addr->s6_addr[15]); } /* * If the tailroom is enought, then change the orginal packets * add an extention header in it */ struct sk_buff * ip6_reconstruct_ori_pkt(struct sk_buff *skb) { struct ipv6hdr * ip6_hdr = ipv6_hdr(skb); struct ip6_dst_hdr *ip6_dst; struct timeval tv;//get time int i =0; int extend_len = sizeof(struct ip6_dst_hdr); ip6_hdr->nexthdr = 0x3c;//set next header as 60 which means next destination header. ip6_hdr->payload_len = htons(ntohs(ip6_hdr->payload_len) + extend_len); //move tail to tail + sizeof(ip6_dst_hdr) skb_put(skb, sizeof(struct ip6_dst_hdr)); skb->truesize += sizeof(struct ip6_dst_hdr); //insert a ip6_dst_hdr between the memory //copy memory in one space,like move from the top to the bottom int begin = skb->data + 40; int end = skb->data + skb->len -16; for(i = end; i-begin >=16; i=i-16) { memcpy(i,i-16,16); } if(i-begin>0) memcpy(begin+16,begin,i-begin); //turn the space to ip6_dst struct ip6_dst = (struct ip6_dst_hdr *)(skb->data + 40); memset(ip6_dst,0,sizeof(struct ip6_dst_hdr));//clear //add ipv6 destination header ip6_dst->ip6d_nxt = 0x11; ip6_dst->ip6d_len = 0x01; ip6_dst->ip6d_opt_type = 0x15;// type of option ip6_dst->ip6d_opt_len = 0x0c; do_gettimeofday(&tv); ip6_dst->ip6d_sec = htonl(tv.tv_sec); ip6_dst->ip6d_usec = htonl(tv.tv_usec); sample_seq++; if(sample_seq==0xffffffff)//if overflow ,reset { sample_seq=0; } ip6_dst->ip6d_ssn = htonl(sample_seq); return skb; } /* * If the tailroom is enought, then copy the sk_buff * and add an extention header in it */ struct sk_buff * ip6_reconstruct_copy_pkt(struct sk_buff *skb) { struct sk_buff *new_skb, *temp_skb; struct ipv6hdr * ip6_hdr = ipv6_hdr(skb); struct ip6_dst_hdr *ip6_dst; struct timeval tv;//get time int extend_len = sizeof(struct ip6_dst_hdr); ip6_hdr->nexthdr = 0x3c;//set next header as 60 which means next destination header. ip6_hdr->payload_len = htons(ntohs(ip6_hdr->payload_len) + extend_len); //copy from the *skb to new_skb new_skb = skb_copy_expand(skb, skb_headroom(skb), skb_tailroom(skb) + extend_len, GFP_ATOMIC); if(new_skb == NULL) { PRINT("Allocate new sk_buffer error!
"); //FIXME:if error happens ,will free the last struct cause any problem? //kfree_skb(skb); return NULL; } //set the new_skb if(skb->sk != NULL) skb_set_owner_w(new_skb, skb->sk); //move tail to tail + sizeof(ip6_dst_hdr) skb_put(new_skb,extend_len); //insert a ip6_dst_hdr between the memory memcpy (new_skb->data, skb->data, 40);//assume that the ip header has 40 bytes memcpy (new_skb->data + 40 + sizeof (struct ip6_dst_hdr), skb->data + 40, skb->len - 40); //release the old struct //call kfree_skb will crash the system, so here use a compromise way to drop the old skb in ip6_multi_modify //kfree_skb(skb); skb = new_skb;//skb pointer to new_skb //turn the space to ip6_dst struct ip6_dst = (struct ip6_dst_hdr *)(skb->data + 40); memset(ip6_dst,0,extend_len);//clear //add ipv6 destination header ip6_dst->ip6d_nxt = 0x11; ip6_dst->ip6d_len = 0x01; ip6_dst->ip6d_opt_type = 0x15;// type of option ip6_dst->ip6d_opt_len = 0x0c; do_gettimeofday(&tv); ip6_dst->ip6d_sec = htonl(tv.tv_sec); ip6_dst->ip6d_usec = htonl(tv.tv_usec); sample_seq++; if(sample_seq==0xffffffff) { //if overflow ,reset sample_seq=0; } ip6_dst->ip6d_ssn = htonl(sample_seq); return skb; } /* * Hook which will call the encapsulate func when condition satisfied *condition1: IPv6 Multicast packets */ static unsigned int ip6_multi_modify(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff*)) { struct sk_buff *sk = skb; struct ipv6hdr *ip6_hdr = ipv6_hdr(skb);//header //because nh only supportted in kernels below 2.6 //after 2.6, it often use network_header to express nh //struct ipv6hdr *ip6_hdr = (struct ipv6hdr*)skb->nh.ipv6h; if(ip6_hdr->version == 6) { struct in6_addr destip = ip6_hdr->daddr;//destination ip if(destip.s6_addr[0] == 0xff && destip.s6_addr[1] == 0x15) //if(ipv6_addr_is_multicast(&ip6_hdr->daddr)) { if(skb_tailroom(sk) >= 40) { PRINT("tailroom is enough
"); //tailroom is enough we can insert the header skb = ip6_reconstruct_ori_pkt(skb); } else { if(ip6_hdr->nexthdr != 0x3c){ //if the next header is no 60 that is this packet was not reconstructed skb = ip6_reconstruct_copy_pkt(skb); ip_route_me_harder(skb,RTN_LOCAL);//ip6_route_me_harder send the copied skb okfn(skb); //drop the old skb return NF_STOLEN; } if(skb == NULL) { PRINT("Allocate new sk_buffer error!
"); return NF_STOLEN; } if(!skb) return NF_STOLEN; } } return NF_ACCEPT; } /*Initialize the hook*/ static struct nf_hook_ops nf_out_modify = { .hook = ip6_multi_modify, .hooknum = NF_IP6_LOCAL_OUT, .owner = THIS_MODULE, .pf = PF_INET6, .priority = NF_IP6_PRI_FIRST, }; /*Initialize the module*/ static int __init ip6_multi_init(void) { int ret; ret = nf_register_hook(&nf_out_modify); PRINT("IPV6 multicast packet modify module init.
"); return 0; //success } /*Clear the module*/ static void __exit ip6_multi_exit(void) { nf_unregister_hook(&nf_out_modify); PRINT("IPV6 multicast packet modify module exit.
"); } module_init(ip6_multi_init); module_exit(ip6_multi_exit);

 
141行目:skb_copy_expandコピー&sk_buffとそのデータは、指定されたスペースを割り当てます.この関数は名前の通りskbをコピーし、拡張する際に使用されます.(pskb_expand_headの代わりにpskb_expand_headを使用するかどうか、pskb_expand_headはデータ領域のみを拡張し、skb構造体を変更しない)
230行目:ip 6_route_me_harderは、netfilerの関数です.新しいskbがこの関数を呼び出さないと送信されません.(試験結果より)