当前位置:   article > 正文

Linux内核中的IPSEC实现(5)_xfrm支持的算法

xfrm支持的算法
Java代码   收藏代码
  1. 7. IPV4下的xfrm支持处理  
  2.   
  3. 在xfrm中各种和地址相关的操作是和协议族相关的, 因此这部分的具体实现就放在相关的协议族实现中, 然后通过状态和策略信息结构来指引到实际的操作中,完成对普通数据包的IPSEC包装或对IPSEC包的解封装。  
  4.   
  5. 7.1 IPV4下的xfrm策略  
  6.   
  7. IPV4下的xfrm策略在net/ipv4/xfrm4_policy.c文件中定义, 主要是定义IPV4的策略信息结构:  
  8.   
  9. static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {  
  10.  .family =   AF_INET,  
  11.  .dst_ops =  &xfrm4_dst_ops,  
  12.  .dst_lookup =  xfrm4_dst_lookup,  
  13.  .get_saddr =  xfrm4_get_saddr,  
  14.  .find_bundle =   __xfrm4_find_bundle,  
  15.  .bundle_create = __xfrm4_bundle_create,  
  16.  .decode_session = _decode_session4,  
  17. };  
  18.   
  19. 在xfrm_policy_register_afinfo()函数中, 还定义了struct xfrm_policy_afinfo结构的其他几个成员函数,因为这几个函数是和协议无关的, 所以在登记函数中定义了:  
  20.  afinfo->garbage_collect = __xfrm_garbage_collect;  
  21. 该函数已经在本系列的第3篇中介绍过了.  
  22.    
  23. 以下是结构中几个函数的定义:  
  24. // IPV4的路由查找, 就是普通是路由查找方法  
  25. // 返回0成功  
  26. static int xfrm4_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)  
  27. {  
  28.  return __ip_route_output_key((struct rtable**)dst, fl);  
  29. }  
  30. // 查找地址, 这个函数是在通道模式下, 源地址没明确指定时调用的,查找获取  
  31. // 外部头中的源地址  
  32. static int xfrm4_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)  
  33. {  
  34.  struct rtable *rt;  
  35. // 通道的流结构定义,用于查找路由  
  36.  struct flowi fl_tunnel = {  
  37.   .nl_u = {  
  38.    .ip4_u = {  
  39.     .daddr = daddr->a4,  
  40.    },  
  41.   },  
  42.  };  
  43. // 根据目的地址找路由  
  44.  if (!xfrm4_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) {  
  45. // 将找到的路由项中的源地址作为通道模式下的外部源地址  
  46.   saddr->a4 = rt->rt_src;  
  47.   dst_release(&rt->u.dst);  
  48.   return 0;  
  49.  }  
  50.  return -EHOSTUNREACH;  
  51. }  
  52.   
  53. // 查找策略中的安全路由, 查找条件是流结构的定义的参数  
  54. static struct dst_entry *  
  55. __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy)  
  56. {  
  57.  struct dst_entry *dst;  
  58.  read_lock_bh(&policy->lock);  
  59. // 遍历策略的安全路由链表  
  60.  for (dst = policy->bundles; dst; dst = dst->next) {  
  61.   struct xfrm_dst *xdst = (struct xfrm_dst*)dst;  
  62. // 比较网卡位置, 目的地址, 源地址, TOS值是否匹配  
  63. // 同时检查该安全路由是否可用  
  64.   if (xdst->u.rt.fl.oif == fl->oif && /*XXX*/  
  65.       xdst->u.rt.fl.fl4_dst == fl->fl4_dst &&  
  66.           xdst->u.rt.fl.fl4_src == fl->fl4_src &&  
  67.           xdst->u.rt.fl.fl4_tos == fl->fl4_tos &&  
  68.       xfrm_bundle_ok(policy, xdst, fl, AF_INET, 0)) {  
  69.    dst_clone(dst);  
  70.    break;  
  71.   }  
  72.  }  
  73.  read_unlock_bh(&policy->lock);  
  74.  return dst;  
  75. }  
  76.   
  77. // 解码skb数据, 填充流结构  
  78. static void  
  79. _decode_session4(struct sk_buff *skb, struct flowi *fl)  
  80. {  
  81.  struct iphdr *iph = skb->nh.iph;  
  82. // xprth是IP头后的上层协议头起始  
  83.  u8 *xprth = skb->nh.raw + iph->ihl*4;  
  84. // 先将流结构清零  
  85.  memset(fl, 0, sizeof(struct flowi));  
  86. // 数据包必须不是分片包  
  87.  if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) {  
  88.   switch (iph->protocol) {  
  89. // 对UDP(17), TCP(6), SCTP(132)和DCCP(33)协议, 要提取源端口和目的端口  
  90. // 头4字节是源端口和目的端口  
  91.   case IPPROTO_UDP:  
  92.   case IPPROTO_TCP:  
  93.   case IPPROTO_SCTP:  
  94.   case IPPROTO_DCCP:  
  95. // 要让skb预留出IP头长度加4字节的长度, 在IP层data应该指向最外面的IP头  
  96.    if (pskb_may_pull(skb, xprth + 4 - skb->data)) {  
  97.     u16 *ports = (u16 *)xprth;  
  98. // 提取端口参数  
  99.     fl->fl_ip_sport = ports[0];  
  100.     fl->fl_ip_dport = ports[1];  
  101.    }  
  102.    break;  
  103.   case IPPROTO_ICMP:  
  104. // 对ICMP(1)协议要提取ICMP包的类型和编码, 2字节  
  105.    if (pskb_may_pull(skb, xprth + 2 - skb->data)) {  
  106.     u8 *icmp = xprth;  
  107.     fl->fl_icmp_type = icmp[0];  
  108.     fl->fl_icmp_code = icmp[1];  
  109.    }  
  110.    break;  
  111.   case IPPROTO_ESP:  
  112. // 对于ESP(50)协议要提取其中的SPI值, 4字节  
  113.    if (pskb_may_pull(skb, xprth + 4 - skb->data)) {  
  114.     __be32 *ehdr = (__be32 *)xprth;  
  115.     fl->fl_ipsec_spi = ehdr[0];  
  116.    }  
  117.    break;  
  118.   case IPPROTO_AH:  
  119. // 对于AH(51)协议要提取其中的SPI值, 4字节  
  120.    if (pskb_may_pull(skb, xprth + 8 - skb->data)) {  
  121.     __be32 *ah_hdr = (__be32*)xprth;  
  122.     fl->fl_ipsec_spi = ah_hdr[1];  
  123.    }  
  124.    break;  
  125.   case IPPROTO_COMP:  
  126. // 对于COMP(108)协议要提取其中CPI值作为SPI值, 2字节  
  127.    if (pskb_may_pull(skb, xprth + 4 - skb->data)) {  
  128.     __be16 *ipcomp_hdr = (__be16 *)xprth;  
  129.     fl->fl_ipsec_spi = htonl(ntohs(ipcomp_hdr[1]));  
  130.    }  
  131.    break;  
  132.   default:  
  133.    fl->fl_ipsec_spi = 0;  
  134.    break;  
  135.   };  
  136.  }  
  137. // 填充协议,源地址,目的地址, TOS参数  
  138.  fl->proto = iph->protocol;  
  139.  fl->fl4_dst = iph->daddr;  
  140.  fl->fl4_src = iph->saddr;  
  141.  fl->fl4_tos = iph->tos;  
  142. }  
  143.    
  144.   
  145. /* Allocate chain of dst_entry's, attach known xfrm's, calculate 
  146.  * all the metrics... Shortly, bundle a bundle. 
  147.  */  
  148. // 创建安全路由  
  149. static int  
  150. __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,  
  151.         struct flowi *fl, struct dst_entry **dst_p)  
  152. {  
  153.  struct dst_entry *dst, *dst_prev;  
  154.  struct rtable *rt0 = (struct rtable*)(*dst_p);  
  155.  struct rtable *rt = rt0;  
  156.  u32 remote = fl->fl4_dst;  
  157.  u32 local  = fl->fl4_src;  
  158.  struct flowi fl_tunnel = {  
  159.   .nl_u = {  
  160.    .ip4_u = {  
  161.     .saddr = local,  
  162.     .daddr = remote,  
  163.     .tos = fl->fl4_tos  
  164.    }  
  165.   }  
  166.  };  
  167.  int i;  
  168.  int err;  
  169.  int header_len = 0;  
  170.  int trailer_len = 0;  
  171.  dst = dst_prev = NULL;  
  172.  dst_hold(&rt->u.dst);  
  173. // 循环次数为策略中SA的数量, 每个SA对应一个安全路由, 一个安全路由对应对数据包的一个  
  174. // 操作: 如压缩, ESP封装, AH封装等  
  175.  for (i = 0; i < nx; i++) {  
  176. // 分配安全路由, 安全路由的操作结构是xfrm4_dst_ops  
  177. // 因为定义了很多不同类型的路由, 每种路由都有各自的操作结构, 这样在上层可用  
  178. // 统一的接口进行路由处理  
  179.   struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops);  
  180.   struct xfrm_dst *xdst;  
  181.   int tunnel = 0;  
  182.   if (unlikely(dst1 == NULL)) {  
  183.    err = -ENOBUFS;  
  184.    dst_release(&rt->u.dst);  
  185.    goto error;  
  186.   }  
  187.   if (!dst)  
  188. // 第一次循环  
  189.    dst = dst1;  
  190.   else {  
  191. // 将新分配的安全路由作为前一个路由的child  
  192.    dst_prev->child = dst1;  
  193.    dst1->flags |= DST_NOHASH;  
  194.    dst_clone(dst1);  
  195.   }  
  196.   xdst = (struct xfrm_dst *)dst1;  
  197. // 安全路由中保留相应的普通路由  
  198.   xdst->route = &rt->u.dst;  
  199.   xdst->genid = xfrm[i]->genid;  
  200. // 新节点的next是老节点  
  201.   dst1->next = dst_prev;  
  202. // 现在prev节点位新节点  
  203.   dst_prev = dst1;  
  204.   if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {  
  205.    remote = xfrm[i]->id.daddr.a4;  
  206.    local  = xfrm[i]->props.saddr.a4;  
  207.    tunnel = 1;  
  208.   }  
  209.   header_len += xfrm[i]->props.header_len;  
  210.   trailer_len += xfrm[i]->props.trailer_len;  
  211. // 如果是通道模式, 需要重新包裹外部IP头, 需要重新寻找外部IP头的路由  
  212.   if (tunnel) {  
  213.    fl_tunnel.fl4_src = local;  
  214.    fl_tunnel.fl4_dst = remote;  
  215.    err = xfrm_dst_lookup((struct xfrm_dst **)&rt,  
  216.            &fl_tunnel, AF_INET);  
  217.    if (err)  
  218.     goto error;  
  219.   } else  
  220.    dst_hold(&rt->u.dst);  
  221.  }  
  222. // 将最新节点的child指向最后的普通路由  
  223.  dst_prev->child = &rt->u.dst;  
  224. // 最老一个安全路由的path指向最后的普通路由  
  225.  dst->path = &rt->u.dst;  
  226. // 将最老安全路由点作为要返回的路由节点链表头  
  227.  *dst_p = dst;  
  228. // dst现在是最新节点  
  229.  dst = dst_prev;  
  230. // prev现在指向最老安全节点  
  231.  dst_prev = *dst_p;  
  232.  i = 0;  
  233. /* 
  234.  为更好理解上面的操作, 用图来表示. 以上循环形成了下图水平方向的一个链表, 链表中的最左边的路由项节点dst为最老的安全路由项, 新分配的安全路由项通过child链接成链表, child通过next指向老节点, 最后一项是数据包封装完后的最后普通路由项. 
  235. 垂直方向的链表是在xfrm_lookup()中形成的, 是多个策略同时起作用的情况, 一般情况下就只有一个策略, 本文中可不考虑多策略的情况. 
  236.                    
  237.                  rt0.u.dst        rt.u.dst            rt.u.dst 
  238.                      ^               ^                   ^ 
  239.                route |         route |             route |            
  240.                      |     child     |    child          | 
  241.           bundle  +-----+  -----> +-----+ ----->      +-----+ child 
  242.   policy -------> | dst |  <----- | dst | <----- ...  | dst | -----> rt.u.dst 
  243.                   +-----+   next  +-----+  next       +-----+ 
  244.                      | 
  245.                      |next 
  246.                      | 
  247.                      V     child          child 
  248.                   +-----+  -----> +-----+ ----->      +-----+ child 
  249.                   | dst |  <----- | dst | <----- ...  | dst | -----> rt.u.dst 
  250.                   +-----+   next  +-----+  next       +-----+ 
  251.                      | 
  252.                      |next 
  253.                      | 
  254.                      V 
  255.                     .... 
  256. */  
  257. // 对新生成的每个安全路由项填充结构参数  
  258.  for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {  
  259.   struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;  
  260.   x->u.rt.fl = *fl;  
  261.   dst_prev->xfrm = xfrm[i++];  
  262.   dst_prev->dev = rt->u.dst.dev;  
  263.   if (rt->u.dst.dev)  
  264.    dev_hold(rt->u.dst.dev);  
  265.   dst_prev->obsolete = -1;  
  266.   dst_prev->flags        |= DST_HOST;  
  267.   dst_prev->lastuse = jiffies;  
  268.   dst_prev->header_len = header_len;  
  269.   dst_prev->nfheader_len = 0;  
  270.   dst_prev->trailer_len = trailer_len;  
  271.   memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));  
  272.   /* Copy neighbout for reachability confirmation */  
  273.   dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour);  
  274.   dst_prev->input  = rt->u.dst.input;  
  275. // 注意安全路由的输出函数是xfrm4_output, 在以后分析路由过程时要用到  
  276.   dst_prev->output = xfrm4_output;  
  277.   if (rt->peer)  
  278.    atomic_inc(&rt->peer->refcnt);  
  279.   x->u.rt.peer = rt->peer;  
  280.   /* Sheit... I remember I did this right. Apparently, 
  281.    * it was magically lost, so this code needs audit */  
  282.   x->u.rt.rt_flags = rt0->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL);  
  283.   x->u.rt.rt_type = rt->rt_type;  
  284.   x->u.rt.rt_src = rt0->rt_src;  
  285.   x->u.rt.rt_dst = rt0->rt_dst;  
  286.   x->u.rt.rt_gateway = rt->rt_gateway;  
  287.   x->u.rt.rt_spec_dst = rt0->rt_spec_dst;  
  288.   x->u.rt.idev = rt0->idev;  
  289.   in_dev_hold(rt0->idev);  
  290.   header_len -= x->u.dst.xfrm->props.header_len;  
  291.   trailer_len -= x->u.dst.xfrm->props.trailer_len;  
  292.  }  
  293. // 初始化路由项的MTU值  
  294.  xfrm_init_pmtu(dst);  
  295.  return 0;  
  296. error:  
  297.  if (dst)  
  298.   dst_free(dst);  
  299.  return err;  
  300. }  
  301.    
  302. 7.1. 小结  
  303.   
  304. IPV4的策略信息结构中的相关成员函数的被调用关系可如下简单表示:  
  305. xfrm_lookup: find xfrm_dst for the skb, create dst_list  
  306.   -> xfrm_find_bundle  
  307.     -> afinfo->find_bundle() == __xfrm4_find_bundle  
  308.   -> xfrm_tmpl_resolve  
  309.     -> xfrm_tmpl_resolve_one  
  310.       -> xfrm_get_saddr  
  311.         -> afinfo->get_saddr == xfrm4_get_saddr  
  312.           -> xfrm4_dst_lookup  
  313.   -> xfrm_bundle_create  
  314.     -> afinfo->bundle_create() == __xfrm4_bundle_create  
  315.       -> xfrm_dst_lookup()  
  316.         -> afinfo->dst_lookup() == xfrm4_dst_lookup  
  317.   
  318. xfrm4_policy_check  
  319.   -> xfrm_policy_check  
  320.     -> __xfrm_policy_check  
  321.       -> xfrm_decode_session  
  322.         -> afinfo->decode_session() == _decode_session4  
  323.   
  324. 7.2 IPV4安全路由操作  
  325.   
  326. 路由操作是针对每种类型的路由定义的一个操作结构, 对上层隐藏了不同路由处理内部的处理方法, 对于IPSEC的IPV4安全路由(xfrm_dst)的操作结构定义如下:  
  327. /* net/ipv4/xfrm4_policy.c */  
  328. static struct dst_ops xfrm4_dst_ops = {  
  329.  .family =  AF_INET,  
  330.  .protocol =  __constant_htons(ETH_P_IP),  
  331.  .gc =   xfrm4_garbage_collect,  
  332.  .update_pmtu =  xfrm4_update_pmtu,  
  333.  .destroy =  xfrm4_dst_destroy,  
  334.  .ifdown =  xfrm4_dst_ifdown,  
  335.  .gc_thresh =  1024,  
  336.  .entry_size =  sizeof(struct xfrm_dst),  
  337. };  
  338.   
  339. 在xfrm_policy_register_afinfo()函数中, 还定义了安全路由操作结构的其他几个成员函数,因为这几个函数是和协议无关的, 所以在登记函数中定义了:  
  340.  dst_ops->kmem_cachep = xfrm_dst_cache;  
  341.  dst_ops->check = xfrm_dst_check;  
  342.  dst_ops->negative_advice = xfrm_negative_advice;  
  343.  dst_ops->link_failure = xfrm_link_failure;  
  344.    
  345. // 安全路由垃圾搜集, 就是调用安全策略信息结构的垃圾搜集函数  
  346. static inline int xfrm4_garbage_collect(void)  
  347. {  
  348.  xfrm4_policy_afinfo.garbage_collect();  
  349.  return (atomic_read(&xfrm4_dst_ops.entries) > xfrm4_dst_ops.gc_thresh*2);  
  350. }  
  351.   
  352. // 更新路由的MTU  
  353. static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu)  
  354. {  
  355.  struct xfrm_dst *xdst = (struct xfrm_dst *)dst;  
  356.  struct dst_entry *path = xdst->route;  
  357. // 调用的是安全路由的原始普通路由的MTU更新操作  
  358.  path->ops->update_pmtu(path, mtu);  
  359. }  
  360.   
  361. // 释放安全路由  
  362. static void xfrm4_dst_destroy(struct dst_entry *dst)  
  363. {  
  364.  struct xfrm_dst *xdst = (struct xfrm_dst *)dst;  
  365. // 释放inet网卡引用  
  366.  if (likely(xdst->u.rt.idev))  
  367.   in_dev_put(xdst->u.rt.idev);  
  368. // 释放对方IP的引用  
  369.  if (likely(xdst->u.rt.peer))  
  370.   inet_putpeer(xdst->u.rt.peer);  
  371. // 释放安全路由  
  372.  xfrm_dst_destroy(xdst);  
  373. }  
  374.   
  375.  static inline void xfrm_dst_destroy(struct xfrm_dst *xdst)  
  376.  {  
  377.  // 释放和安全路由相关的普通路由  
  378.   dst_release(xdst->route);  
  379.  // 释放SA  
  380.   if (likely(xdst->u.dst.xfrm))  
  381.    xfrm_state_put(xdst->u.dst.xfrm);  
  382.  }  
  383.   
  384. // 网卡down时的回调操作  
  385. static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,  
  386.         int unregister)  
  387. {  
  388.  struct xfrm_dst *xdst;  
  389.  if (!unregister)  
  390.   return;  
  391.  xdst = (struct xfrm_dst *)dst;  
  392. // 该安全路由对应的网卡是当前停掉的网卡  
  393.  if (xdst->u.rt.idev->dev == dev) {  
  394.   struct in_device *loopback_idev = in_dev_get(&loopback_dev);  
  395.   BUG_ON(!loopback_idev);  
  396.   do {  
  397. // 释放安全路由网卡  
  398.    in_dev_put(xdst->u.rt.idev);  
  399. // 安全路由网卡采用自身的回环网卡  
  400.    xdst->u.rt.idev = loopback_idev;  
  401.    in_dev_hold(loopback_idev);  
  402. // 子路由  
  403.    xdst = (struct xfrm_dst *)xdst->u.dst.child;  
  404.   } while (xdst->u.dst.xfrm);  
  405.   __in_dev_put(loopback_idev);  
  406.  }  
  407.  xfrm_dst_ifdown(dst, dev);  
  408. }  
  409.    
  410. 7.3 IPV4下的xfrm状态  
  411.   
  412. IPV4下的xfrm状态在net/ipv4/xfrm4_state.c文件中定义, 主要是定义IPV4的状态信息结构:  
  413. static struct xfrm_state_afinfo xfrm4_state_afinfo = {  
  414.  .family   = AF_INET,  
  415.  .init_flags  = xfrm4_init_flags,  
  416.  .init_tempsel  = __xfrm4_init_tempsel,  
  417. };  
  418.   
  419. 该结构中在IPV4下只定义了两个处理函数:  
  420.   
  421. // 初始化状态标志  
  422. static int xfrm4_init_flags(struct xfrm_state *x)  
  423. {  
  424.  if (ipv4_config.no_pmtu_disc)  
  425.   x->props.flags |= XFRM_STATE_NOPMTUDISC;  
  426.  return 0;  
  427. }  
  428.   
  429. // 初始化模板选择子  
  430. static void  
  431. __xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl,  
  432.        struct xfrm_tmpl *tmpl,  
  433.        xfrm_address_t *daddr, xfrm_address_t *saddr)  
  434. {  
  435. // 填写选择子信息  
  436. // 源地址  
  437.  x->sel.daddr.a4 = fl->fl4_dst;  
  438. // 目的地址  
  439.  x->sel.saddr.a4 = fl->fl4_src;  
  440. // 目的端口, 掩码  
  441.  x->sel.dport = xfrm_flowi_dport(fl);  
  442.  x->sel.dport_mask = htons(0xffff);  
  443. // 源端口掩码  
  444.  x->sel.sport = xfrm_flowi_sport(fl);  
  445.  x->sel.sport_mask = htons(0xffff);  
  446. // 源目的地址长度  
  447.  x->sel.prefixlen_d = 32;  
  448.  x->sel.prefixlen_s = 32;  
  449. // 协议  
  450.  x->sel.proto = fl->proto;  
  451. // 网卡位置  
  452.  x->sel.ifindex = fl->oif;  
  453. // 状态ID值  
  454.  x->id = tmpl->id;  
  455.  if (x->id.daddr.a4 == 0)  
  456.   x->id.daddr.a4 = daddr->a4;  
  457. // 支持结构中的参数  
  458. // 源地址  
  459.  x->props.saddr = tmpl->saddr;  
  460.  if (x->props.saddr.a4 == 0)  
  461.   x->props.saddr.a4 = saddr->a4;  
  462. // 模式  
  463.  x->props.mode = tmpl->mode;  
  464. // 请求ID  
  465.  x->props.reqid = tmpl->reqid;  
  466. // 协议族  
  467.  x->props.family = AF_INET;  
  468. }  
  469.   
  470. 7.3小结  
  471.   
  472. IPV4的状态信息结构中的相关成员函数的被调用关系可如下简单表示:  
  473. xfrm_init_state()  
  474.   -> afinfo->init_flags() == xfrm4_init_flags  
  475.   
  476. xfrm_state_find()  
  477.   -> xfrm_init_tempsel()  
  478.     -> afinfo->init_tempsel() == __xfrm4_init_tempsel  
  479.   
  480. 7.4 模式  
  481.   
  482. xfrm4支持3种模式: 通道, 传输和BEET模式, 分别在xfrm4_mode_tunnel.c, xfrm4_mode_transport.c和xfrm4_mode_beet.c中定义.  
  483. 每个模式都通过结构struct xfrm_mode定义:  
  484. struct xfrm_mode {  
  485.  int (*input)(struct xfrm_state *x, struct sk_buff *skb);  
  486.  int (*output)(struct xfrm_state *x,struct sk_buff *skb);  
  487.  struct module *owner;  
  488.  unsigned int encap;  
  489. };  
  490. 其中input函数在数据接收时调用, output函数数据发出时调用, encap参数表示是否封装.  
  491.   
  492. 7.4.1 通道  
  493. 通道模式通过以下结构定义:  
  494. /* net/ipv4/xfrm4_mode_transport.c */  
  495. static struct xfrm_mode xfrm4_tunnel_mode = {  
  496.  .input = xfrm4_tunnel_input,  
  497.  .output = xfrm4_tunnel_output,  
  498.  .owner = THIS_MODULE,  
  499.  .encap = XFRM_MODE_TUNNEL,  
  500. };  
  501.   
  502. // 通道模式下的接收函数, 解封装  
  503. static int xfrm4_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)  
  504. {  
  505.  struct iphdr *iph = skb->nh.iph;  
  506.  int err = -EINVAL;  
  507. // IP协议为IPPROTO_IPIP(4)  
  508.  if (iph->protocol != IPPROTO_IPIP)  
  509.   goto out;  
  510. // 需要在skb头留出IP头的长度(20字节)  
  511.  if (!pskb_may_pull(skb, sizeof(struct iphdr)))  
  512.   goto out;  
  513. // 如果是clone包,重新拷贝一个  
  514.  if (skb_cloned(skb) &&  
  515.      (err = pskb_expand_head(skb, 00, GFP_ATOMIC)))  
  516.   goto out;  
  517. // 复制dscp字段  
  518.  if (x->props.flags & XFRM_STATE_DECAP_DSCP)  
  519.   ipv4_copy_dscp(iph, skb->h.ipiph);  
  520. // 非XFRM_STATE_NOECN时进行ECN解封装  
  521.  if (!(x->props.flags & XFRM_STATE_NOECN))  
  522.   ipip_ecn_decapsulate(skb);  
  523. // 将硬件地址挪到数据包缓冲区前  
  524.  skb->mac.raw = memmove(skb->data - skb->mac_len,  
  525.           skb->mac.raw, skb->mac_len);  
  526. // 网络部分数据头  
  527.  skb->nh.raw = skb->data;  
  528.  err = 0;  
  529. out:  
  530.  return err;  
  531. }  
  532.   
  533. // 通道模式下的数据发出函数, 进行封装  
  534. static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)  
  535. {  
  536.  struct dst_entry *dst = skb->dst;  
  537.  struct iphdr *iph, *top_iph;  
  538.  int flags;  
  539.  iph = skb->nh.iph;  
  540.  skb->h.ipiph = iph;  
  541. // 数据头部增加外部IP头的长度  
  542.  skb->nh.raw = skb_push(skb, x->props.header_len);  
  543.  top_iph = skb->nh.iph;  
  544. // 填写外部IP头参数  
  545.  top_iph->ihl = 5;  
  546.  top_iph->version = 4;  
  547.  /* DS disclosed */  
  548. // 重新计算TOS  
  549.  top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos);  
  550.  flags = x->props.flags;  
  551.  if (flags & XFRM_STATE_NOECN)  
  552.   IP_ECN_clear(top_iph);  
  553. // 处理分片包情况  
  554.  top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ?  
  555.   0 : (iph->frag_off & htons(IP_DF));  
  556.  if (!top_iph->frag_off)  
  557.   __ip_select_ident(top_iph, dst->child, 0);  
  558. // TTL  
  559.  top_iph->ttl = dst_metric(dst->child, RTAX_HOPLIMIT);  
  560. // 外部源地址用proposal中的源地址  
  561.  top_iph->saddr = x->props.saddr.a4;  
  562. // 外部目的地址是SA中的目的地址  
  563.  top_iph->daddr = x->id.daddr.a4;  
  564. // 外部IP头内的协议号为IPIP(4)  
  565.  top_iph->protocol = IPPROTO_IPIP;  
  566. // IP选项部分设置为0  
  567.  memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));  
  568.  return 0;  
  569. }  
  570.   
  571. 7.4.2 传输  
  572.   
  573. 传输模式下不添加新的IP头, 其实几乎什么都不用做, 老点的2.6内核中就没有专门为传输模式定义.  
  574. 传输模式结构定义为:  
  575. /* net/ipv4/xfrm4_mode_transport.c */  
  576. static struct xfrm_mode xfrm4_transport_mode = {  
  577.  .input = xfrm4_transport_input,  
  578.  .output = xfrm4_transport_output,  
  579.  .owner = THIS_MODULE,  
  580.  .encap = XFRM_MODE_TRANSPORT,  
  581. };  
  582.   
  583. /* Remove encapsulation header. 
  584.  * 
  585.  * The IP header will be moved over the top of the encapsulation header. 
  586.  * 
  587.  * On entry, skb->h shall point to where the IP header should be and skb->nh 
  588.  * shall be set to where the IP header currently is.  skb->data shall point 
  589.  * to the start of the payload. 
  590.  */  
  591. // 传输模式下的数据输入函数  
  592. static int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb)  
  593. {  
  594. // data指向负载头, h指向IP头, 但很多情况下两者相同  
  595.  int ihl = skb->data - skb->h.raw;  
  596. // 如果h和nh不同, 将nh所指向IP头部分移动到h处  
  597.  if (skb->h.raw != skb->nh.raw)  
  598.   skb->nh.raw = memmove(skb->h.raw, skb->nh.raw, ihl);  
  599. // 增加数据包长度, 重新对数据包长度赋值  
  600.  skb->nh.iph->tot_len = htons(skb->len + ihl);  
  601.  skb->h.raw = skb->data;  
  602.  return 0;  
  603. }  
  604.    
  605. /* Add encapsulation header. 
  606.  * 
  607.  * The IP header will be moved forward to make space for the encapsulation 
  608.  * header. 
  609.  * 
  610.  * On exit, skb->h will be set to the start of the payload to be processed 
  611.  * by x->type->output and skb->nh will be set to the top IP header. 
  612.  */  
  613. // 传输模式下的数据发出函数  
  614. static int xfrm4_transport_output(struct xfrm_state *x, struct sk_buff *skb)  
  615. {  
  616.  struct iphdr *iph;  
  617.  int ihl;  
  618. // nh和赋值给h  
  619.  iph = skb->nh.iph;  
  620.  skb->h.ipiph = iph;  
  621. // ip头长度  
  622.  ihl = iph->ihl * 4;  
  623. // 重新计算h位置  
  624.  skb->h.raw += ihl;  
  625. // 重新计算新的nh位置,增加proposal中的头长度, 拷贝原来的IP头数据  
  626.  skb->nh.raw = memmove(skb_push(skb, x->props.header_len), iph, ihl);  
  627.  return 0;  
  628. }  
  629.   
  630. 7.4.3 BEET  
  631.   
  632. 封装成BEETPH(94)包, 非标准IPSEC, 略.  
  633.   
  634. 7.4.4 小结  
  635. 和xfrm_mode相关的xfrm函数有:  
  636. 登记: int xfrm_register_mode(struct xfrm_mode *mode, int family);  
  637. 撤销: int xfrm_unregister_mode(struct xfrm_mode *mode, int family)  
  638. 获取: struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)  
  639. 释放: void xfrm_put_mode(struct xfrm_mode *mode)  
  640.   
  641. xfrm_mode的输入输出函数调用:  
  642. xfrm4_rcv_encap()  
  643.   -> x->mode->input  
  644. xfrm4_output_one()  
  645.   -> x->mode->output  
  646.    
  647. 7.5 数据接收  
  648.   
  649. IPV4的IPSEC数据接收处理在net/ipv4/xfrm4_input.c中定义, 作为AH和ESP协议数据接收处理函数.  
  650.   
  651. /* net/ipv4/xfrm4_input.c */  
  652. int xfrm4_rcv(struct sk_buff *skb)  
  653. {  
  654.  return xfrm4_rcv_encap(skb, 0);  
  655. }  
  656.   
  657. 实际就是xfrm4_rcv_encap,封装类型参数设置为0,在NAT-T时IPSEC数据被封装在UDP包中时, 该参数才非0.  
  658. int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)  
  659. {  
  660.  int err;  
  661.  __be32 spi, seq;  
  662.  struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];  
  663.  struct xfrm_state *x;  
  664.  int xfrm_nr = 0;  
  665.  int decaps = 0;  
  666. // 获取skb中的spi和序列号信息  
  667.  if ((err = xfrm4_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) != 0)  
  668.   goto drop;  
  669. // 进入循环进行解包操作  
  670.  do {  
  671.   struct iphdr *iph = skb->nh.iph;  
  672. // 循环解包次数太深的话放弃  
  673.   if (xfrm_nr == XFRM_MAX_DEPTH)  
  674.    goto drop;  
  675. // 根据地址, SPI和协议查找SA  
  676.   x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, iph->protocol, AF_INET);  
  677.   if (x == NULL)  
  678.    goto drop;  
  679. // 以下根据SA定义的操作对数据解码  
  680.   spin_lock(&x->lock);  
  681.   if (unlikely(x->km.state != XFRM_STATE_VALID))  
  682.    goto drop_unlock;  
  683. // 检查由SA指定的封装类型是否和函数指定的封装类型相同  
  684.   if ((x->encap ? x->encap->encap_type : 0) != encap_type)  
  685.    goto drop_unlock;  
  686. // SA重放窗口检查  
  687.   if (x->props.replay_window && xfrm_replay_check(x, seq))  
  688.    goto drop_unlock;  
  689. // SA生存期检查  
  690.   if (xfrm_state_check_expire(x))  
  691.    goto drop_unlock;  
  692. // type可为esp,ah,ipcomp, ipip等, 对输入数据解密  
  693.   if (x->type->input(x, skb))  
  694.    goto drop_unlock;  
  695.   /* only the first xfrm gets the encap type */  
  696.   encap_type = 0;  
  697. // 更新重放窗口  
  698.   if (x->props.replay_window)  
  699.    xfrm_replay_advance(x, seq);  
  700. // 包数,字节数统计  
  701.   x->curlft.bytes += skb->len;  
  702.   x->curlft.packets++;  
  703.   spin_unlock(&x->lock);  
  704. // 保存数据解封用的SA, 增加SA数量计数  
  705.   xfrm_vec[xfrm_nr++] = x;  
  706. // mode可为通道,传输等模式, 对输入数据解封装  
  707.   if (x->mode->input(x, skb))  
  708.    goto drop;  
  709. // 如果是IPSEC通道模式,将decaps参数置1,否则表示是传输模式  
  710.   if (x->props.mode == XFRM_MODE_TUNNEL) {  
  711.    decaps = 1;  
  712.    break;  
  713.   }  
  714. // 看内层协议是否还要继续解包, 不需要解时返回1, 需要解时返回0, 错误返回负数  
  715. // 协议类型可以多层封装的,比如用AH封装ESP, 就得先解完AH再解ESP  
  716.   if ((err = xfrm_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) < 0)  
  717.    goto drop;  
  718.  } while (!err);  
  719.  /* Allocate new secpath or COW existing one. */  
  720. // 为skb包建立新的安全路径(struct sec_path)  
  721.  if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {  
  722.   struct sec_path *sp;  
  723.   sp = secpath_dup(skb->sp);  
  724.   if (!sp)  
  725.    goto drop;  
  726.   if (skb->sp)  
  727.    secpath_put(skb->sp);  
  728.   skb->sp = sp;  
  729.  }  
  730.  if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)  
  731.   goto drop;  
  732. // 将刚才循环解包用到的SA拷贝到安全路径  
  733. // 因此检查一个数据包是否是普通明文包还是解密后的明文包就看skb->sp参数是否为空  
  734.  memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec,  
  735.         xfrm_nr * sizeof(xfrm_vec[0]));  
  736.  skb->sp->len += xfrm_nr;  
  737.  nf_reset(skb);  
  738.  if (decaps) {  
  739. // 通道模式  
  740.   if (!(skb->dev->flags&IFF_LOOPBACK)) {  
  741.    dst_release(skb->dst);  
  742.    skb->dst = NULL;  
  743.   }  
  744. // 重新进入网卡接收函数  
  745.   netif_rx(skb);  
  746.   return 0;  
  747.  } else {  
  748. // 传输模式  
  749. #ifdef CONFIG_NETFILTER  
  750. // 如果定义NETFILTER, 进入PRE_ROUTING链处理,然后进入路由选择处理  
  751. // 其实现在已经处于INPUT点, 但解码后需要将该包作为一个新包看待  
  752. // 可能需要进行目的NAT操作, 这时候可能目的地址就会改变不是到自身  
  753. // 的了, 因此需要将其相当于是放回PRE_PROUTING点去操作, 重新找路由  
  754. // 这也说明可以制定针对解码后明文包的NAT规则,在还是加密包的时候不匹配  
  755. // 但解码后能匹配上  
  756.   __skb_push(skb, skb->data - skb->nh.raw);  
  757.   skb->nh.iph->tot_len = htons(skb->len);  
  758.   ip_send_check(skb->nh.iph);  
  759.   NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL,  
  760.           xfrm4_rcv_encap_finish);  
  761.   return 0;  
  762. #else  
  763. // 内核不支持NETFILTER, 该包肯定就是到自身的了  
  764. // 返回IP协议的负值, 表示重新进行IP层协议的处理  
  765. // 用解码后的内层协议来处理数据  
  766.   return -skb->nh.iph->protocol;  
  767. #endif  
  768.  }  
  769. drop_unlock:  
  770.  spin_unlock(&x->lock);  
  771.  xfrm_state_put(x);  
  772. drop:  
  773.  while (--xfrm_nr >= 0)  
  774.   xfrm_state_put(xfrm_vec[xfrm_nr]);  
  775.  kfree_skb(skb);  
  776.  return 0;  
  777. }  
  778. // 解析AH,ESP数据包中的SPI和序号  
  779. static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)  
  780. {  
  781.  switch (nexthdr) {  
  782. // 如果只是普通的IPIP包, SPI为源地址, 序号位0  
  783.  case IPPROTO_IPIP:  
  784.   *spi = skb->nh.iph->saddr;  
  785.   *seq = 0;  
  786.   return 0;  
  787.  }  
  788. // 否则解析AH/ESP/COMP协议头中的SPI和序号  
  789.  return xfrm_parse_spi(skb, nexthdr, spi, seq);  
  790. }  
  791. // 接收封装完成处理函数  
  792. static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb)  
  793. {  
  794.  struct iphdr *iph = skb->nh.iph;  
  795. // 如果没有路由, 重新查找路由  
  796.  if (skb->dst == NULL) {  
  797.   if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,  
  798.                      skb->dev))  
  799.    goto drop;  
  800.  }  
  801. // 调用相关的路由输入函数  
  802.  return dst_input(skb);  
  803. drop:  
  804.  kfree_skb(skb);  
  805.  return NET_RX_DROP;  
  806. }  
  807.    
  808. 调用关系:  
  809. ip_rcv  
  810.   -> (AH/ESP) net_protocol->handler == xfrm4_rcv  
  811.     -> xfrm4_rcv_encap  
  812.       -> xfrm4_parse_spi  
  813.          -> xfrm_parse_spi  
  814.       -> xfrm4_rcv_encap_finish  
  815.    
  816. 7.6 数据发送  
  817.   
  818. IPV4的IPSEC数据发送处理在net/ipv4/xfrm4_output.c中定义,作为安全路由的输出函数:  
  819.   
  820. int xfrm4_output(struct sk_buff *skb)  
  821. {  
  822. // 就是一个条件HOOK, 当skb包不带IPSKB_REROUTED标志时进入POSTROUTING点的NAT操作  
  823. // 这是数据在xfrm策略中多个bundle时会多次调用, 也就是数据在封装完成前可以进行  
  824. // 源NAT操作  
  825. // HOOK出口函数为xfrm4_output_finish  
  826.  return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev,  
  827.        xfrm4_output_finish,  
  828.        !(IPCB(skb)->flags & IPSKB_REROUTED));  
  829. }  
  830.   
  831. // 发送结束处理  
  832. static int xfrm4_output_finish(struct sk_buff *skb)  
  833. {  
  834.  struct sk_buff *segs;  
  835. #ifdef CONFIG_NETFILTER  
  836. // 如果内核定义了NETFILTER, 当到达最后一个路由(普通路由)时, 设置IPSKB_REROUTED  
  837. // 标志, 进行普通路由发出函数(ip_output), 设置该标志后不进行源NAT操作  
  838.  if (!skb->dst->xfrm) {  
  839.   IPCB(skb)->flags |= IPSKB_REROUTED;  
  840.   return dst_output(skb);  
  841.  }  
  842. #endif  
  843. // 如果skb包不是是gso, 转xfrm4_output_finish2  
  844. // gso是什么意思现在还不知道, 以后再仔细分析  
  845.  if (!skb_is_gso(skb))  
  846.   return xfrm4_output_finish2(skb);  
  847. // 处理gso数据包, 最终也是使用xfrm4_output_finish2处理数据包  
  848.  skb->protocol = htons(ETH_P_IP);  
  849.  segs = skb_gso_segment(skb, 0);  
  850.  kfree_skb(skb);  
  851.  if (unlikely(IS_ERR(segs)))  
  852.   return PTR_ERR(segs);  
  853.  do {  
  854.   struct sk_buff *nskb = segs->next;  
  855.   int err;  
  856.   segs->next = NULL;  
  857.   err = xfrm4_output_finish2(segs);  
  858.   if (unlikely(err)) {  
  859.    while ((segs = nskb)) {  
  860.     nskb = segs->next;  
  861.     segs->next = NULL;  
  862.     kfree_skb(segs);  
  863.    }  
  864.    return err;  
  865.   }  
  866.   segs = nskb;  
  867.  } while (segs);  
  868.  return 0;  
  869. }  
  870.    
  871. // 第2级发送结束处理  
  872. static int xfrm4_output_finish2(struct sk_buff *skb)  
  873. {  
  874.  int err;  
  875. // 根据安全路由包装要发送数据  
  876.  while (likely((err = xfrm4_output_one(skb)) == 0)) {  
  877. // 处理成功  
  878. // 释放skb中的netfilter信息  
  879.   nf_reset(skb);  
  880. // 重新将该包作为初始发送包, 进入OUTPUT点处理, 注意这是个函数而不是宏  
  881. // 如果内核没定义NETFILTER, 该函数只是个空函数  
  882. // 返回1表示NF_ACCEPT  
  883.   err = nf_hook(PF_INET, NF_IP_LOCAL_OUT, &skb, NULL,  
  884.          skb->dst->dev, dst_output);  
  885.   if (unlikely(err != 1))  
  886.    break;  
  887. // 如果已经没有SA, 就只是个普通包了, 路由发送(ip_output)返回, 退出循环  
  888.   if (!skb->dst->xfrm)  
  889.    return dst_output(skb);  
  890. // 如果还有SA, 目前还只是中间状态, 还可以进行SNAT操作, 进入POSTROUTING点处理  
  891.   err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL,  
  892.          skb->dst->dev, xfrm4_output_finish2);  
  893.   if (unlikely(err != 1))  
  894.    break;  
  895.  }  
  896.  return err;  
  897. }  
  898.   
  899. // 按安全路由链表的安全路由处理数据, 该链表反映了多个SA对数据包进行处理  
  900. // 链表是在__xfrm4_bundle_create函数中建立的  
  901. static int xfrm4_output_one(struct sk_buff *skb)  
  902. {  
  903. // 安全路由  
  904.  struct dst_entry *dst = skb->dst;  
  905. // 相关SA  
  906.  struct xfrm_state *x = dst->xfrm;  
  907.  int err;  
  908. // skb包校验和 检查  
  909.  if (skb->ip_summed == CHECKSUM_PARTIAL) {  
  910.   err = skb_checksum_help(skb);  
  911.   if (err)  
  912.    goto error_nolock;  
  913.  }  
  914. // 如果是通道模式, 检查skb数据长度, 并进行相关处理, 通道模式下封装后的数据包长度可能  
  915. // 会超过1500字节的  
  916.  if (x->props.mode == XFRM_MODE_TUNNEL) {  
  917.   err = xfrm4_tunnel_check_size(skb);  
  918.   if (err)  
  919.    goto error_nolock;  
  920.  }  
  921.  do {  
  922.   spin_lock_bh(&x->lock);  
  923. // SA合法性检查  
  924.   err = xfrm_state_check(x, skb);  
  925.   if (err)  
  926.    goto error;  
  927. // 调用模式输出函数, 如通道封装, 此时外部IP头协议为IPIP  
  928.   err = x->mode->output(x, skb);  
  929.   if (err)  
  930.    goto error;  
  931. // 调用协议输出, 如对应ESP协议来说是esp4_output, 此时外部IP头协议会改为ESP  
  932.   err = x->type->output(x, skb);  
  933.   if (err)  
  934.    goto error;  
  935. // 更新SA中的当前生命期结构中的包和字节计数  
  936.   x->curlft.bytes += skb->len;  
  937.   x->curlft.packets++;  
  938.   spin_unlock_bh(&x->lock);  
  939. // 转移到下一个子路由   
  940.   if (!(skb->dst = dst_pop(dst))) {  
  941.    err = -EHOSTUNREACH;  
  942.    goto error_nolock;  
  943.   }  
  944. // dst和x参数更新为子路由中的安全路由和SA  
  945.   dst = skb->dst;  
  946.   x = dst->xfrm;  
  947. // 循环条件是SA非空, 而且SA提议模式不是通道模式  
  948.  } while (x && (x->props.mode != XFRM_MODE_TUNNEL));  
  949. // skb中设置IPSKB_XFRM_TRANSFORMED标志  
  950. // 有该标志的数据包将NAT操作后将不进行一些特殊检查  
  951.  IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;  
  952.  err = 0;  
  953. out_exit:  
  954.  return err;  
  955. error:  
  956.  spin_unlock_bh(&x->lock);  
  957. error_nolock:  
  958.  kfree_skb(skb);  
  959.  goto out_exit;  
  960. }  
  961.   
  962. IPSEC输出函数调用关系:  
  963. dst_output  
  964.   -> xfrm_dst->output == xfrm4_output  
  965.      -> NF_HOOK(POSTROUTING)  
  966.        -> xfrm4_output_finish  
  967.          -> xfrm4_output_finish2  
  968.            -> xfrm4_output_one  
  969.   
  970. 7.7 NAT-T支持  
  971.   
  972. 在支持NAT穿越的IPSEC处理中,是通过UDP数据包来封装IPSEC数据(ESP数据包),因此在对UDP处理时需要进行特殊处理。由于IKE同样是用UDP处理的, 区分是IKE包还是封装的ESP包就看数据头部头4字节表示的SPI值, SPI为0表示是IKE包, 由IKE用户空间程序接收进行处理, SPI非0表示是UDP封装的ESP包, 需进行ESP解封。  
  973.   
  974. 7.7.1 接收数据  
  975.   
  976. 被UDP封装的IPSEC包在接收时会先按普通UDP包接收,在UDP处理中再解开该包后进行IPSEC处理  
  977. /* net/ipv4/udp.c */  
  978. // 正常接收的UDP包都将进入该函数  
  979. static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)  
  980. {  
  981.  struct udp_sock *up = udp_sk(sk);  
  982.  int rc;  
  983.  /* 
  984.   * Charge it to the socket, dropping if the queue is full. 
  985.   */  
  986. // 检查针对该sock,skb包的输入方法上的是否有安全策略  
  987.  if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) {  
  988.   kfree_skb(skb);  
  989.   return -1;  
  990.  }  
  991.  nf_reset(skb);  
  992. // 检查该SOCK是否是IPSEC封装的,该参数通过setsockopt系统调用的UDP_ENCAP选项设置  
  993. // 一般是IKE程序在打开UDP4500端口时设置的  
  994.  if (up->encap_type) {  
  995.   /* 
  996.    * This is an encapsulation socket, so let's see if this is 
  997.    * an encapsulated packet. 
  998.    * If it's a keepalive packet, then just eat it. 
  999.    * If it's an encapsulateed packet, then pass it to the 
  1000.    * IPsec xfrm input and return the response 
  1001.    * appropriately.  Otherwise, just fall through and 
  1002.    * pass this up the UDP socket. 
  1003.    */  
  1004.   int ret;  
  1005. // 进入UDP封装接收, 判断是否是ESP包  
  1006. // 返回值小于0表示是IPSEC包, 大于0表示是普通UDP包, 等于0表示是错误包  
  1007.   ret = udp_encap_rcv(sk, skb);  
  1008.   if (ret == 0) {  
  1009.    /* Eat the packet .. */  
  1010.    kfree_skb(skb);  
  1011.    return 0;  
  1012.   }  
  1013.   if (ret < 0) {  
  1014. // 进行IPSEC接收处理  
  1015.    /* process the ESP packet */  
  1016.    ret = xfrm4_rcv_encap(skb, up->encap_type);  
  1017.    UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS);  
  1018.    return -ret;  
  1019.   }  
  1020.   /* FALLTHROUGH -- it's a UDP Packet */  
  1021.  }  
  1022. // 以下按普通UDP包接收处理, 分析略  
  1023.  if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {  
  1024.   if (__udp_checksum_complete(skb)) {  
  1025.    UDP_INC_STATS_BH(UDP_MIB_INERRORS);  
  1026.    kfree_skb(skb);  
  1027.    return -1;  
  1028.   }  
  1029.   skb->ip_summed = CHECKSUM_UNNECESSARY;  
  1030.  }  
  1031.  if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {  
  1032.   /* Note that an ENOMEM error is charged twice */  
  1033.   if (rc == -ENOMEM)  
  1034.    UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS);  
  1035.   UDP_INC_STATS_BH(UDP_MIB_INERRORS);  
  1036.   kfree_skb(skb);  
  1037.   return -1;  
  1038.  }  
  1039.  UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS);  
  1040.  return 0;  
  1041. }  
  1042.   
  1043. /* return: 
  1044.  *  1  if the the UDP system should process it 
  1045.  * 0  if we should drop this packet 
  1046.  *  -1 if it should get processed by xfrm4_rcv_encap 
  1047.  */  
  1048. static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb)  
  1049. {  
  1050. #ifndef CONFIG_XFRM  
  1051. // 在内核不支持IPSEC情况下直接返回1  
  1052.  return 1;  
  1053. #else  
  1054.  struct udp_sock *up = udp_sk(sk);  
  1055.    struct udphdr *uh;  
  1056.  struct iphdr *iph;  
  1057.  int iphlen, len;  
  1058.    
  1059.  __u8 *udpdata;  
  1060.  __be32 *udpdata32;  
  1061. // sock的封装标志值  
  1062.  __u16 encap_type = up->encap_type;  
  1063.  /* if we're overly short, let UDP handle it */  
  1064. // UDP数据包中数据部分的长度  
  1065.  len = skb->len - sizeof(struct udphdr);  
  1066.  if (len <= 0)  
  1067.   return 1;  
  1068.  /* if this is not encapsulated socket, then just return now */  
  1069. // 没定义封装处理, 返回1, 普通处理  
  1070.  if (!encap_type)  
  1071.   return 1;  
  1072.  /* If this is a paged skb, make sure we pull up 
  1073.   * whatever data we need to look at. */  
  1074.  if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8)))  
  1075.   return 1;  
  1076.  /* Now we can get the pointers */  
  1077.  uh = skb->h.uh;  
  1078.  udpdata = (__u8 *)uh + sizeof(struct udphdr);  
  1079.  udpdata32 = (__be32 *)udpdata;  
  1080.  switch (encap_type) {  
  1081.  default:  
  1082. // 在UDP中封装ESP  
  1083.  case UDP_ENCAP_ESPINUDP:  
  1084.   /* Check if this is a keepalive packet.  If so, eat it. */  
  1085.   if (len == 1 && udpdata[0] == 0xff) {  
  1086. // 只是普通UDP的IPSEC通道保活包, 直接丢弃  
  1087.    return 0;  
  1088.   } else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0 ) {  
  1089. // 头4字节非零, ESP包,需要下一步解析  
  1090.    /* ESP Packet without Non-ESP header */  
  1091.    len = sizeof(struct udphdr);  
  1092.   } else  
  1093. // 这是IKE包,按普通UDP接收处理  
  1094.    /* Must be an IKE packet.. pass it through */  
  1095.    return 1;  
  1096.   break;  
  1097.  case UDP_ENCAP_ESPINUDP_NON_IKE:  
  1098.   /* Check if this is a keepalive packet.  If so, eat it. */  
  1099.   if (len == 1 && udpdata[0] == 0xff) {  
  1100. // IPSEC通道保活包, 丢弃  
  1101.    return 0;  
  1102.   } else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) &&  
  1103.       udpdata32[0] == 0 && udpdata32[1] == 0) {  
  1104. // 头4字节非零, ESP包,需要下一步解析  
  1105.      
  1106.    /* ESP Packet with Non-IKE marker */  
  1107.    len = sizeof(struct udphdr) + 2 * sizeof(u32);  
  1108.   } else  
  1109. // 这是IKE数据包,由  
  1110.    /* Must be an IKE packet.. pass it through */  
  1111.    return 1;  
  1112.   break;  
  1113.  }  
  1114.  /* At this point we are sure that this is an ESPinUDP packet, 
  1115.   * so we need to remove 'len' bytes from the packet (the UDP 
  1116.   * header and optional ESP marker bytes) and then modify the 
  1117.   * protocol to ESP, and then call into the transform receiver. 
  1118.   */  
  1119. // 如果是clone包需要复制成独立包  
  1120.  if (skb_cloned(skb) && pskb_expand_head(skb, 00, GFP_ATOMIC))  
  1121.   return 0;  
  1122. // 检查数据长度  
  1123.  /* Now we can update and verify the packet length... */  
  1124.  iph = skb->nh.iph;  
  1125.  iphlen = iph->ihl << 2;  
  1126.  iph->tot_len = htons(ntohs(iph->tot_len) - len);  
  1127.  if (skb->len < iphlen + len) {  
  1128.   /* packet is too small!?! */  
  1129.   return 0;  
  1130.  }  
  1131.  /* pull the data buffer up to the ESP header and set the 
  1132.   * transport header to point to ESP.  Keep UDP on the stack 
  1133.   * for later. 
  1134.   */  
  1135. // 修改IP上层头位置  
  1136.  skb->h.raw = skb_pull(skb, len);  
  1137. // 更改IP头协议类型为ESP包, 返回-1  
  1138.  /* modify the protocol (it's ESP!) */  
  1139.  iph->protocol = IPPROTO_ESP;  
  1140.  /* and let the caller know to send this into the ESP processor... */  
  1141.  return -1;  
  1142. #endif  
  1143. }  
  1144.   
  1145. 函数调用关系:  
  1146. udp_rcv  
  1147.   ->udp_queue_rcv_skb  
  1148.     -> udp_encap_rcv  
  1149.     -> xfrm4_policy_check  
  1150.       -> xfrm_policy_check  
  1151.         -> __xfrm_policy_check  
  1152.           
  1153. 7.7.2 ESP包的UDP封装  
  1154.   
  1155. 对于ESP包的UDP封装处理, 在下一节ESP协议数据包的输出处理中介绍.  
  1156.   
  1157. ...... 待续 ......  
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/814565
推荐阅读
相关标签
  

闽ICP备14008679号