<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                RFC4137協議的全稱是"State Machine for Extensible Authentication Protocol(EAP)Peer and Authenticator",它描述了Peer端(即Supplicant端)和Authenticator端通過狀態機(State Machine)這種方式來實現EAP處理流程的具體步驟和相關細節。本節將重點介紹Supplicant端SM的設計原理。為了行文方便,本節將使用SUPP代替Supplicant。 #### **一、Supplicant端SM設計原理** 對狀態機來說,最重要的是其狀態切換圖。RFC4137中SUPP SM狀態切換如圖4-21所示。 圖4-21的內容極為豐富,此處先介紹其中三個知識點。 * SUPP SM一共定義了13個狀態,每個狀態用一個框表示。框頂部所示為狀態名,如INTIALZE、IDLE等。 * 每個狀態都可以有自己的Entry Action(以后簡稱EA)。進入這個狀態后,EA將被執行。EA由狀態框中狀態名下邊的偽代碼(采用了類C++語法)表示。以FAILURE狀態為例,當狀態機進入該狀態后,將執行"eapFail=TRUE"偽代碼,eapFail是SUPP SM定義的變量,下文將詳細介紹圖中涉及的變量和相關函數。 * 圖中的UCT代表Unconditional Transition,即無條件狀態轉換。以DISCARD狀態和IDLE狀態為例,由于UCT的存在,當SUPP SM在DISCARD狀態中執行完其EA后,將直接轉換到IDLE狀態。 對一個狀態機而言,其狀態的轉換是因為外界條件發生變化導致。在規范中,這些外界條件由變量來表達。圖4-21中出現了很多變量和EA所包括的一些函數,它們都由RFC4137文檔定義。了解它們的作用對真正理解SUPP SM有直接和重要幫助。接下來的章節就將介紹這些變量和函數。 :-: ![](https://box.kancloud.cn/55ec2d01f88d9ceb2d71cbc488e8ec6a_1074x1349.jpg) 圖4-21 SUPP SM狀態切換 :-: ![](https://box.kancloud.cn/0d78c75d9d8ac105c56b823c7f69594d_339x276.jpg) 圖4-22 RFC4137 SUPP SM模塊劃分 RFC4137將和SUPP SM相關的模塊分為三層,如圖4-22所示。圖中最底層是Lower Layer(LL),這一層的作用是接收和發送EAP包。位于中間的SUPP SM層實現了Supplican狀態機。最上層是EAP Method(EM)層,它實現了具體的EAP方法。 SUPP SM將與EM層和LL層交互。一個最典型的交互例子就是LL收到EAP數據包后,將該數據包交給SUPP SM層去處理。如果該EAP包需要EM層處理(例如具體的驗證算法需要EM完成),則SUPP SM層將該包交給EM。EM處理完的結果將由SUPP SM轉交給LL去發送。 >[info] 提示 RFC4137中,三層之間交互的手段可以是設置變量,或者是調用函數。 先來看SUPP SM與LL交互時所使用的變量。 **1、LL層和SUPP SM層交互變量** LL層和SUPP SM層的交互比較簡單,主要包括三個步驟。 1. LL層收到EAP數據包后,將其保存在eapReqData變量中,然后設置eapReq變量為TRUE。這個變量的改變對SUPP SM層來說是一個觸發信號(signal)。SUPP SM可能會發生狀態轉換。 2. SUPP SM層從eapReqData中取出數據后進行處理。如果有需要回復的數據,則設置eapResp值為TRUE,否則設置eapNoResp值為TRUE。回復數據存儲在eapRespData中。LL層將發送此回復包。 3. 如果SUPP SM完成身份驗證后,它將設置eapSuccess或eapFailure變量以告知LL層其驗證結果。eapSuccess為TRUE,表明驗證成功。eapFailure為TRUE,則驗證失敗。 上述描述中所涉及的變量及其類型如表4-1所示。注意,此處的數據類型屬于偽代碼。 >[info] 提示 在WPAS中,LL層并非那些直接利用socket進行數據收發的模塊,而是EAPOL模塊。 EAP和EAPOL模塊的關系將留待下一節再介紹。 :-: ![](https://box.kancloud.cn/f727a1c1971b9c12bf47ec7a413146fc_1266x625.jpg) :-: ![](https://box.kancloud.cn/a33fa1554c5d2a3d3b1f941674856ad8_1260x446.jpg) 表4-11 LL層和SUPP層交互變量 表4-1中altAccept和altReject兩個變量的命名非常晦澀難懂。RFC4137指出這兩個變量的定義在RFC3748中。實際上,RFC3748從頭至尾都沒有出現過這兩個變量。經過仔細研究,筆者發現[這篇文章](http://lists.frascone.com/pipermail/eap/msg02578.html )對此有一個說法,內容如下。 這兩個變量取名為lowerLayerSuccess和lowerLayerFailure更合適,它們用于通知LL層Success或Failure信息。結合上述資料,筆者查閱了RFC3748 7.12節,在802.11網絡中,Indicatioin(通知)Success和Failure的可能場景如下。 * 當supplicant收到Disassociate幀或者Deauthenticate幀時,表示lowerLayerFailure。 * 當收到4-Way Handshake第一個Message時,表示lowerLayerSuccess。 >[info] 規范閱讀提示 RFC4137中,上述變量還可分為兩種類型。 1. 由LL層暴露給SUPP SM層的變量(Variables from Lower Layer to Peer)。它們從表4-1中的eapReq開始,到altReject結束。原則上,LL層和SUPP SM層都可以修改這些變量。 2. 由SUPP SM層暴露給LL層的變量(Variables from Peer to Lower Layer)。它們從表4-1中的eapResp開始,到eapKeyAvailable結束。原則上,LL層和SUPP SM層都可以修改這些變量。另外,這些變量也可由SUPP SM層暴露給EM層來使用。 接著來看SUPP SM層和EM層交互變量。 **2、SUPP SM層和EM層交互變量** SUPP SM層和EM層的交互也是通過變量來完成的。這些變量如表4-2所示。 :-: ![](https://box.kancloud.cn/7e3b01017600b98a103d16db09317739_1269x259.jpg) :-: ![](https://box.kancloud.cn/11409c16f177f299ca4a87d58d28dcf6_1058x699.jpg) 表4-2 SUPP SM和EM層交互變量 注意,methodState和decision的值由具體的認證方法(即Method)來確定。 >[info] 提示 本書不討論所有EAP方法的具體實現。感興趣的讀者可以深入研究EAP模塊。不過對EAP SUPP SM來說,methodState和decision的取值情況才是最重要的,因為它們會直接影響SUPP SM的狀態切換。 **3、SUPP SM其他變量和處理函數** RFC4137還為SUPP SM還定義了其他一些變量(Peer State Machine Local Variables)及函數。變量定義見表4-3。 :-: ![](https://box.kancloud.cn/6b6611f3d19c028846599965330c057f_1271x430.jpg) 表4-3 SUPP SM層內部變量定義 :-: ![](https://box.kancloud.cn/0fbc5defdc7e0c8ab10766ad0efb0c6e_1051x677.jpg) 表4-4 SUPP SM處理函數的定義。 注意,表4-4中用偽代碼展示了這些函數的使用案例,它們并不遵守C++語法。例如: ~~~ (rxReq,rxSuccess,rxFailure,reqId,reqMethod)=parseEapReq(eapReqData) ~~~ 等號左邊為parseEapReq函數的返回值,等號右邊括號中的"eapReqData"為parseEapReq的輸入參數。如果使用案例中沒有等號,則表示該函數無返回值(具體實現時,可設置該函數的返回值為void)。 注意 圖4-21中還包含一些其他函數,奇怪的是規范中并沒有列舉它們。不過,相信讀者很容易理解這些數作用,此處不詳述。現在,讀者能看懂圖4-21所示的狀態圖了嗎? **4、SUPP SM定義的狀態** SUPP SM定義的13個狀態如表4-5所示。 :-: ![](https://box.kancloud.cn/3e7efa982ce5d518877bfa7c9ce9933d_1264x255.jpg) :-: ![](https://box.kancloud.cn/988433fcb311acd3c2664a81cea86520_1264x507.jpg) 表4-5 SUPP SM狀態 前面展示了RFC4137中和SUPP SM相關的內容。筆者覺得這個狀態機定義太過煩瑣。不過,本著簡單、明了并且沒有歧義的原則,這種做法似乎又無可厚非。從筆者經驗來看,讀者只要能看懂圖4-21所示SUPP SM狀態切換圖即算掌握了EAP模塊的精髓了。WPAS中EAP SUPPSM該如何實現呢?請看下節。 #### **二、EAP SUPP SM代碼分析** 上文中曾提到過,RFC4137定義的狀態機非常煩瑣,而具體實現可以根據情況進行裁剪。不過,WPAS中的EAP SUPP SM卻較為嚴格得遵循了RFC4137。先來看其定義的數據類型和數據結構。 **1、相關數據結構與數據類型** 圖4-23所示為EAP SUPP SM定義的枚舉變量類型。 :-: ![](https://box.kancloud.cn/fc26c58bb469842712d0ff82098cf687_1114x604.jpg) 圖4-23 EAP SUPP SM枚舉類型定義 圖4-23中,左圖定義了EapDecision、EapMethodState、Boolean、eapol_bool_var和eapol_int_var枚舉類型,它們都和上節介紹的變量及類型有關。右圖定義了EapType枚舉變量,代表不同的EAP Method。 :-: ![](https://box.kancloud.cn/ef9b457c586514883ba07f7e9df72ca6_1039x694.jpg) 圖4-24所示為WPAS中和SUPP SM相關的數據結構。 圖4-24中,eap_sm是RFC4137 EAP SUPP SM的代表。從其成員變量的命名可知,它幾乎完全是按照RFC4137來實現的。eap_sm定義了一個名為EAP_state的枚舉類型成員變量。 eap_sm通過m成員變量指向一個eap_method鏈表。eap_method是一個由next指針鏈接起來的單向鏈表,每一個eap_method對象代表一種具體的EAP Method(EAP Method的注冊請回顧4.3.2節“eap_register_methods函數分析”)。eap_method最重要的是其處理函數,WPAS對其略有修改。例如,process函數實際上完成了表4-4中m.check、m.process和m.buildResp的功能。 eap_method中,process函數第三個參數的類型是`eap_method_ret*`,代表一個`eap_method_ret`對象。由圖4-24可知,它包括了ignore、methodState、decision以及allowNotifications變量。 eap_sm的eapol_cb對象指向一個eapol_callbacks對象,它是LL層的代表。不過,eapol_callbacks的定義看起來和RFC4137關系不大。 >[info] 注意 圖4-24中eap_sm第一個成員變量EAP_State是一個枚舉類型,其枚舉值就是圖4-21中SUPP SM的各個狀態。 EAP SUPP SM初始化時,eap_sm的eapol_callbacks被設置為eapol_cb對象。代碼如下所示。 **eapol_supp_sm.c::eapol_cb定義** ~~~ static struct eapol_callbacks eapol_cb = { eapol_sm_get_config,eapol_sm_get_bool,eapol_sm_set_bool,eapol_sm_get_int, eapol_sm_set_int,eapol_sm_get_eapReqData,eapol_sm_set_config_blob, eapol_sm_get_config_blob,eapol_sm_notify_pending,eapol_sm_eap_param_needed, eapol_sm_notify_cert }; ~~~ 上述函數相關代碼我們留待碰到它們時再介紹。 **2、WPAS狀態機通用宏** WPAS中有許多狀態機,所以它定義了一些通用宏來幫助實現狀態機相關的代碼。這些宏的定義如下所示。 **state_machine.h** ~~~ /* 定義一個狀態的EA,它是一個函數聲明。 而STATE_MACHINE_DATA也是一個宏。對于EAP SSM來說,其類型是struct eap_sm。 global代表觸發該狀態的原因是否為UCT。 */ #define SM_STATE(machine, state) \ static void sm_ ## machine ## _ ## state ## _Enter(STATE_MACHINE_DATA *sm,int global) // 每個狀態進入后執行的一段代碼。一般是打印一些信息,并設置新的狀態 #define SM_ENTRY(machine, state) \ if (!global || sm->machine ## _state != machine ## _ ## state) { \ sm->changed = TRUE; \ // changed變量用于記錄狀態機的狀態是否發生變化 wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " #machine \ " entering state " #state); \ } \ sm->machine ## _state = machine ## _ ## state; // 設置狀態機的狀態 // SM_ENTER宏對應一次函數調用,調用的是SM_STATE宏定義的函數 #define SM_ENTER(machine, state) \ sm_ ## machine ## _ ## state ## _Enter(sm, 0) // 對應一次函數調用,表示因UCT而直接進入某個狀態 #define SM_ENTER_GLOBAL(machine, state) \ sm_ ## machine ## _ ## state ## _Enter(sm, 1) // 這個函數由SM_STATE宏聲明 // 運行狀態機。該宏定義一個函數 #define SM_STEP(machine) \ static void sm_ ## machine ## _Step(STATE_MACHINE_DATA *sm) // 該宏對應一次函數調用,即sm_##machine_Step(sm),sm參數由調用函數內聲明 #define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm) ~~~ 下面通過SUPP SM的實現代碼來認識下上述通用宏的用法。 **3、EAP SUPP SM的實現** SUPP SM的狀態比較多,此處僅列舉DISABLED狀態的實現代碼以幫助讀者理解通用宏的作用。對狀態機來說,其狀態對應的EA非常重要。如下代碼所示為DISABLED狀態對應的EA。根據上節對通用宏的介紹,EA由SM_STATE宏來定義。 **eap.c::SM_STATE(EAP,DISABLED)** ~~~ 該宏對應的代碼是 static void sm_EAP_DISABLED_Enter(STATE_MACHINE_DATA *sm,int global) */ SM_STATE(EAP, DISABLED) { SM_ENTRY(EAP, DISABLED); // 每個狀態的EA都會執行SM_ENTRY代碼段 /* SM_ENTRY宏對應的代碼是: if (!global || sm->EAP_state != EAP_DISABLED) { sm->changed = TRUE; wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " "EAP" \ " entering state " "DISABLED"); // 這段日志對了解SUPP SM當前處于哪個狀態非常重要 } // EAP_state是eap_sm中成員變量。讀者可參考圖4-24 sm->EAP_state = EAP_DISABLED; */ sm->num_rounds = 0; } ~~~ SM_STATE只是定義了狀態機某個狀態的EA,那么狀態機是如何運作的呢?根據圖4-21以及前文所述,狀態機的狀態切換主要是通過判斷條件是否滿足來完成。SM_STEP定義的函數就是用于檢查狀態機的這些條件變量,然后根據情況進行狀態轉換的。SUPP SM的SM_STEP宏對應的代碼如下所示。 **eap.c::SM_STEP(EAP)** ~~~ /* SM_STEP宏對應的函數定義為: static void sm_EAP_Step(STATE_MACHINE_DATA *sm) */ SM_STEP(EAP) { /* 對應UCT的處理。eapol_get_bool函數將調用eapol_callbacks對象中的eapol_sm_get_ bool函數其內部返回eap_sm中eapRestart成員變量的值。 */ if (eapol_get_bool(sm, EAPOL_eapRestart) && eapol_get_bool(sm, EAPOL_portEnabled)) /* 調用由SM_STATE(EAP,INITIALZE)定義的函數,以進入EAP_INITIALIZE狀態。 GLOBAL的意思是UCT。請讀者注意此處的判斷條件:如果eap_sm的eapRestart和 portEnabled成員變量都為true,則直接進入INITIALIZE狀態。它完全和圖4-21 SUPP SM狀態圖一樣。 */ SM_ENTER_GLOBAL(EAP, INITIALIZE); else if (!eapol_get_bool(sm, EAPOL_portEnabled) || sm->force_disabled) SM_ENTER_GLOBAL(EAP, DISABLED); else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) { if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) { ......// 有一些EAP方法在認證錯誤時會有很多消息往來,WPAS對此做了一個限制 // 一旦這些錯誤消息往來超過50次(由EAP_MAX_AUTH_ROUDS),則直接進入FAILURE狀態 sm->num_rounds++; SM_ENTER_GLOBAL(EAP, FAILURE); // GLOBAL代表UCT的情況 } } else eap_peer_sm_step_local(sm); // 對應其他非UCT的情況 } ~~~ 此處簡單看一下eap_peer_sm_step_local的代碼。 **eap.c::eap_peer_sm_step_local** ~~~ static void eap_peer_sm_step_local(struct eap_sm *sm) { switch (sm->EAP_state) { ...... case EAP_IDLE: // 圖4-21中,idle狀態可依據條件不同而跳轉到其他多個狀態 // 下面這個函數用于選擇目標狀態及跳轉到它 eap_peer_sm_step_idle(sm);// 根據圖4-21的idle狀態跳轉,讀者能想象出該函數的代碼實現嗎 break; case EAP_RECEIVED: eap_peer_sm_step_received(sm); break; case EAP_GET_METHOD: if (sm->selectedMethod == sm->reqMethod) SM_ENTER(EAP, METHOD); // 直接進入METHOD狀態 else SM_ENTER(EAP, SEND_RESPONSE); // 直接進入SEND_RESPONSE狀態 break; ...... } } ~~~ eap_peer_sm_step_local用于處理那些非UCT導致的狀態切換。 >[info] 提示 EAP SUPP SM的代碼雖不復雜,但由于SUPP SM狀態和觸發條件(即定義的那些變量)太多,想通過看代碼去跟蹤SUPP SM間的狀態跳轉是一件非常困難的事情。相比而言,圖4-21比代碼要直觀,更加容易把注意力集中在目標狀態以及它對應的EA上。另外,SM_STATE代碼段中包含的那段wpa_printf輸出將告知EAP模塊當前的狀態。讀者以后在分析WPAS日志時千萬要注意。 #### **三、EAP SUPP SM總結** EAP SUPP SM基于RFC4137而實現,其內部變量的定義以及狀態切換邏輯都來源于規范。以筆者的經驗來看,掌握RFC4137是理解WPAS中EAP SUPP SM實現的基石。另外,對具體的處理邏輯而言,SUPP SM最重要的內容還是各個狀態對應的EA。正如前文所述,圖4-21對SUPP SM的運行極為重要,希望讀者認真學習。 另外,對WPAS中狀態機的實現來說,SM_STATE用于定義某個狀態的EA(即一個函數)。每個EA都會執行SM_ENTRY宏定義的一段代碼。SM_ENTER和SM_ENTER_GLOBAL宏用于調用SM_STATE定義的函數。GLOBAL代表UCT的情況。SM_STEP宏用于運行整個狀態機。請讀者注意它和SM_ENTER的區別。SM_ENTER宏將直接調用某個指定狀態(由SM_ENTER宏的參數決定)的EA,而SM_STEP則將根據SM中的變量情況來決定下一個要跳轉的狀態,然后調用它的SM_ENTER。下面來看EAPOL模塊的實現。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看