乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Linux2.6下ESP包解析流程

       mrjbydd 2011-05-16
      Linux2.6下ESP包解析流程
      Linux2.6下ESP包解析流程
       
      本文檔的Copyleft歸yfydz所有,使用GPL發(fā)布,可以自由拷貝,轉(zhuǎn)載,轉(zhuǎn)載時請保持文檔的完整性,
      嚴禁用于任何商業(yè)用途。
      msn: yfydz_no1@hotmail.com
      來源:http://yfydz.

      1. 前言

      在Linux2.6中自帶了ipsec的實現(xiàn),可以不再使用freeswan及其變種了,freeswan通過建立ipsec*的
      虛擬網(wǎng)卡來將發(fā)送和接收ipsec數(shù)據(jù)包,通過ipsec*網(wǎng)卡看到的數(shù)據(jù)是明文數(shù)據(jù),而2.6中的ipsec實
      現(xiàn)是不建立ipsec*虛擬網(wǎng)卡的,本文分析一下ESP包進入系統(tǒng)協(xié)議棧的處理流程。
      以下Linux內(nèi)核代碼版本為2.6.19.2。

      2. 流程分析

      2.1 esp協(xié)議結(jié)構(gòu)

      esp協(xié)議結(jié)構(gòu)定義,對于每個IPv4上層的協(xié)議,如TCP、UDP、ICMP、IGMP、ESP、AH等都需要定義這個
      結(jié)構(gòu)掛接到IPv4的協(xié)議鏈表中,當接收到IP數(shù)據(jù)包時,會根據(jù)包中定義的IP協(xié)議號找到該結(jié)構(gòu),然后
      調(diào)用其成員handler函數(shù)進行處理。

      /* net/ipv4/esp4.c */
      static struct net_protocol esp4_protocol = {
       .handler = xfrm4_rcv,
       .err_handler = esp4_err,
       .no_policy = 1,
      };

      esp協(xié)議的handler函數(shù)是xfrm4_rcv()

      2.2 xfrm4_rcv
      /* net/ipv4/xfrm4_input.c */
      int xfrm4_rcv(struct sk_buff *skb)
      {
       return xfrm4_rcv_encap(skb, 0);
      }

      實際就是xfrm4_rcv_encap,封裝類型參數(shù)設(shè)置為0,即沒封裝數(shù)據(jù)

      2.3 xfrm4_rcv_encap
      /* net/ipv4/xfrm4_input.c */
      int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
      {
       int err;
       __be32 spi, seq;
       struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
       struct xfrm_state *x;
       int xfrm_nr = 0;
       int decaps = 0;
      // 獲取skb中的spi和序列號信息
       if ((err = xfrm4_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) != 0)
        goto drop;
      // 進入循環(huán)進行解包操作
       do {
        struct iphdr *iph = skb->nh.iph;
      // 循環(huán)解包次數(shù)太深的話放棄
        if (xfrm_nr == XFRM_MAX_DEPTH)
         goto drop;
      // 根據(jù)地址, SPI和協(xié)議查找SA
        x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, iph->protocol,
      AF_INET);
        if (x == NULL)
         goto drop;
      // 以下根據(jù)SA定義的操作對數(shù)據(jù)解碼
        spin_lock(&x->lock);
        if (unlikely(x->km.state != XFRM_STATE_VALID))
         goto drop_unlock;
      // 檢查由SA指定的封裝類型是否和函數(shù)指定的封裝類型相同
        if ((x->encap ? x->encap->encap_type : 0) != encap_type)
         goto drop_unlock;
      // SA重放窗口檢查
        if (x->props.replay_window && xfrm_replay_check(x, seq))
         goto drop_unlock;
      // SA生存期檢查
        if (xfrm_state_check_expire(x))
         goto drop_unlock;
      // type可為esp,ah,ipcomp, ipip等, 對輸入數(shù)據(jù)解密
        if (x->type->input(x, skb))
         goto drop_unlock;
        /* only the first xfrm gets the encap type */
        encap_type = 0;
      // 更新重放窗口
        if (x->props.replay_window)
         xfrm_replay_advance(x, seq);
      // 包數(shù),字節(jié)數(shù)統(tǒng)計
        x->curlft.bytes += skb->len;
        x->curlft.packets++;
        spin_unlock(&x->lock);
        xfrm_vec[xfrm_nr++] = x;
      // mode可為通道,傳輸?shù)饶J? 對輸入數(shù)據(jù)解封裝
        if (x->mode->input(x, skb))
         goto drop;
      // 如果是IPSEC通道模式,將decaps參數(shù)置1,否則表示是傳輸模式
        if (x->props.mode == XFRM_MODE_TUNNEL) {
         decaps = 1;
         break;
        }
      // 看內(nèi)層協(xié)議是否還要繼續(xù)解包, 不需要解時返回1, 需要解時返回0, 錯誤返回負數(shù)
      // 協(xié)議類型可以多層封裝的,比如用AH封裝ESP, 就得先解完AH再解ESP
        if ((err = xfrm_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) < 0)
         goto drop;
       } while (!err);
       /* Allocate new secpath or COW existing one. */
      // 為skb包建立新的安全路徑(struct sec_path)
       if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
        struct sec_path *sp;
        sp = secpath_dup(skb->sp);
        if (!sp)
         goto drop;
        if (skb->sp)
         secpath_put(skb->sp);
        skb->sp = sp;
       }
       if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
        goto drop;
      // 將剛才循環(huán)解包用到的SA拷貝到安全路徑
      // 因此檢查一個數(shù)據(jù)包是否是普通明文包還是解密后的明文包就看skb->sp參數(shù)是否為空
       memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec,
              xfrm_nr * sizeof(xfrm_vec[0]));
       skb->sp->len += xfrm_nr;
       nf_reset(skb);
       if (decaps) {
      // 通道模式
        if (!(skb->dev->flags&IFF_LOOPBACK)) {
         dst_release(skb->dst);
         skb->dst = NULL;
        }
      // 重新進入網(wǎng)卡接收函數(shù)
        netif_rx(skb);
        return 0;
       } else {
      // 傳輸模式
      #ifdef CONFIG_NETFILTER
      // 如果定義NETFILTER, 進入PRE_ROUTING鏈處理,然后進入路由選擇處理
      // 其實現(xiàn)在已經(jīng)處于INPUT點, 但解碼后需要將該包作為一個新包看待
      // 可能需要進行目的NAT操作, 這時候可能目的地址就會改變不是到自身
      // 的了, 因此需要將其相當于是放回PRE_PROUTING點去操作, 重新找路由
      // 這也說明可以制定針對解碼后明文包的NAT規(guī)則,在還是加密包的時候不匹配
      // 但解碼后能匹配上
        __skb_push(skb, skb->data - skb->nh.raw);
        skb->nh.iph->tot_len = htons(skb->len);
        ip_send_check(skb->nh.iph);
        NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL,
                xfrm4_rcv_encap_finish);
        return 0;
      #else
      // 內(nèi)核不支持NETFILTER, 該包肯定就是到自身的了
      // 返回IP協(xié)議的負值, 表示重新進行IP層協(xié)議的處理
      // 用解碼后的內(nèi)層協(xié)議來處理數(shù)據(jù)
        return -skb->nh.iph->protocol;
      #endif
       }
      drop_unlock:
       spin_unlock(&x->lock);
       xfrm_state_put(x);
      drop:
       while (--xfrm_nr >= 0)
        xfrm_state_put(xfrm_vec[xfrm_nr]);
       kfree_skb(skb);
       return 0;
      }

      最后說一下返回負協(xié)議值的處理, IP上層協(xié)議的handler是在ip_local_deliver_finish()函數(shù)中調(diào)用
      的:

      /* net/ipv4/ip_input.c */
      static inline int ip_local_deliver_finish(struct sk_buff *skb)
      {
       int ihl = skb->nh.iph->ihl*4;
       __skb_pull(skb, ihl);
              /* Point into the IP datagram, just past the header. */
              skb->h.raw = skb->data;
       rcu_read_lock();
       {
        /* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
        int protocol = skb->nh.iph->protocol;
        int hash;
        struct sock *raw_sk;
        struct net_protocol *ipprot;
       resubmit:
      // 協(xié)議hash值, IPv4最大支持255種協(xié)議
        hash = protocol & (MAX_INET_PROTOS - 1);
        raw_sk = sk_head(&raw_v4_htable[hash]);
        /* If there maybe a raw socket we must check - if not we
         * don't care less
         */
        if (raw_sk && !raw_v4_input(skb, skb->nh.iph, hash))
         raw_sk = NULL;
      // 直接在協(xié)議數(shù)組中獲取協(xié)議指針
        if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) {
         int ret;
         if (!ipprot->no_policy) {
          if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
           kfree_skb(skb);
           goto out;
          }
          nf_reset(skb);
         }
      // 調(diào)用協(xié)議handler
         ret = ipprot->handler(skb);
         if (ret < 0) {
      // 如果返回值為負, 取反后重新跳回resubmit點進行選協(xié)議處理
          protocol = -ret;
          goto resubmit;
         }
         IP_INC_STATS_BH(IPSTATS_MIB_INDELIVERS);
        } else {
         if (!raw_sk) {
          if (xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
           IP_INC_STATS_BH(IPSTATS_MIB_INUNKNOWNPROTOS);
           icmp_send(skb, ICMP_DEST_UNREACH,
              ICMP_PROT_UNREACH, 0);
          }
         } else
          IP_INC_STATS_BH(IPSTATS_MIB_INDELIVERS);
         kfree_skb(skb);
        }
       }
       out:
       rcu_read_unlock();
       return 0;
      }

      3. 結(jié)論
      雖然在2.6的native ipsec中沒支持虛擬網(wǎng)卡,但在通道模式下也用到了netif_rx函數(shù)將解碼后的數(shù)
      據(jù)包重新接收處理的過程,并沒有改變skb包的dev網(wǎng)卡參數(shù),因此如果在該網(wǎng)卡上抓包,就會同時抓
      到最初的加密包和解碼后的明文包;而用freeswan的實現(xiàn),在普通網(wǎng)卡上抓包抓到的是加密包,由于
      freeswan在解碼后將skb包的dev參數(shù)改為了ipsec*,因此是通過在ipsec*網(wǎng)卡上能抓到解密包。對于
      傳輸模式,由于沒有調(diào)用netif_rx函數(shù),因此在實際網(wǎng)卡抓包只能抓到加密包,解密包只能在
      netfilter架構(gòu)中看到了。
       
      另外,在此情況下NAT規(guī)則仍然是有效的,制定NAT規(guī)則時根據(jù)解密后的地址端口等信息來處理就可以
      了。
       
      識別一個明文包是否是解密過的就看skb的sp參數(shù)即可,該指針為空表示是普通明文包,非空表示是
      解密后的明文包。

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多