如何在Linux内核中为IPv6添加一种新的扩展头

来源:互联网 发布:航空发动机 知乎 编辑:程序博客网 时间:2024/05/16 12:56

IPv6头部的设计是一个简洁的基本头部后面根据需要加上多种不同类型的扩展头部,这种设计可以将不常用的功能通过选择性的添加不同的扩展头部实现,从而在保证了基本头部的简洁和处理的快速性。以Linux2.6.28版本内核为例,IPv6扩展首部的定义在linux-2.6.28/include/linux/in6.h和linux-2.6.28/include/net/ipv6.h两个目录下,我们以添加一种IPPROTO_MY类型的扩展头为例:

 

1、在头文件中添加新类型扩展头的定义,在linux-2.6.28/include/linux/in6.h中

/*
 * NextHeader field of IPv6 header
 */

#define NEXTHDR_HOP  0 /* Hop-by-hop option header. */
#define NEXTHDR_TCP  6 /* TCP segment. */
#define NEXTHDR_UDP  17 /* UDP message. */
#define NEXTHDR_IPV6  41 /* IPv6 in IPv6 */
#define NEXTHDR_ROUTING  43 /* Routing header. */
#define NEXTHDR_FRAGMENT 44 /* Fragmentation/reassembly header. */
#define NEXTHDR_ESP  50 /* Encapsulating security payload. */
#define NEXTHDR_AUTH  51 /* Authentication header. */
#define NEXTHDR_ICMP  58 /* ICMP for IPv6. */
#define NEXTHDR_NONE  59 /* No next header */
#define NEXTHDR_DEST  60 /* Destination options header. */
#define NEXTHDR_MOBILITY 135 /* Mobility header. */

 

#define IPPROTO_MY     200    /*自己定义的头部类型 */

 

 

2、在linux-2.6.28/include/net/ipv6.h中定义结构体

/*
 * IPV6 extension headers
 */

#define IPPROTO_HOPOPTS  0 /* IPv6 hop-by-hop options */
#define IPPROTO_ROUTING  43 /* IPv6 routing header  */
#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */
#define IPPROTO_ICMPV6  58 /* ICMPv6   */
#define IPPROTO_NONE  59 /* IPv6 no next header  */
#define IPPROTO_DSTOPTS  60 /* IPv6 destination options */
#define IPPROTO_MH  135 /* IPv6 mobility header  */

自己定义新的扩展头类型如:
#define NEXTHDR_INDEX        200    /*IPv6 next header */

自己定义新的扩展头类型:
struct index_hdr{                              /*index扩展头结构*/
  __u8    nexthdr;
  __u8    hdrlen;
  __u16   reserved;
  __u32   skb_index;
};

 

3、在需要添加头部和删除头部的源文件中添加添加和删除函数,届时直接调用这两个函数即可

static void ip6_index_add(struct sk_buff *skb,unsigned char *data,unsigned int len)
{
 
 struct ipv6hdr *tmp_hdr;
 struct ipv6hdr *old_hdr;
 struct index_hdr *ih;
 u8 prevhdr;
 unsigned int hlen;
 unsigned int ilen;

 ilen=sizeof(struct index_hdr);
 hlen=sizeof(struct ipv6hdr);

 old_hdr=skb_network_header(skb);
 prevhdr=old_hdr->nexthdr;

 if(prevhdr!=200){
  old_hdr->nexthdr=NEXTHDR_INDEX;
  tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC);
  __skb_pull(skb, hlen);                      /*使data指针下移hlen长度,将ipv6头部去掉*/
  ih = (struct index_hdr*)__skb_push(skb, ilen);   /*上移data指针,将index头部添加进去*/
  __skb_push(skb, hlen);    /*继续上移data指针,将原来的ipv6头部加进去*/
  skb_reset_network_header(skb);
  memcpy(skb_network_header(skb), tmp_hdr, hlen);

  /*为index扩展头赋值*/
  ih->nexthdr = prevhdr;
  ih->hdrlen = 8;
  ih->reserved = 0;
  ih->skb_index = htonl(skb->xfrm_index);
                                    
  skb->truesize += ilen;
  ipv6_hdr(skb)->payload_len += ilen;
  data = skb->data;
  len = skb->len;

  kfree(tmp_hdr);
 }
}

 


static void ip6_index_del(struct sk_buff *skb,unsigned char *data,unsigned int len)
{
 struct ipv6hdr *tmp_hdr;
 struct ipv6hdr *old_hdr;
 struct index_hdr *ih;
 u8 prevhdr;
 unsigned int hlen;
 unsigned int ilen;

 ilen=sizeof(struct index_hdr);
 hlen=sizeof(struct ipv6hdr);

 if(ipv6_hdr(skb)->nexthdr == 200){

  tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC); /*保存ipv6头*/

  __skb_pull(skb, hlen);                                   /*下移data指针,去掉ipv6头*/
  skb_reset_network_header(skb);
  ih=(struct index_hdr *)skb_network_header(skb);
  prevhdr = ih->nexthdr;
  tmp_hdr->nexthdr = prevhdr;
    
  __skb_pull(skb, ilen);                                   /*下移data指针,去掉index扩展头*/
  __skb_push(skb, hlen);                     /*上移data指针,将原来的ipv6头添加回去*/
  skb_reset_network_header(skb);
  memcpy(skb_network_header(skb), tmp_hdr, hlen);

  skb_reset_network_header(skb);
  skb->truesize -= ilen;
  ipv6_hdr(skb)->payload_len -= ilen;

  kfree(tmp_hdr);
  }
}

原创粉丝点击