FreeRadius : 模組開發(一)
這篇文章主要總結一些模組開發的基礎知識。
引文是為FreeRadius3.X增加一個模組的幫助文件,在這裡做一些翻譯。
doc/developer
給開發者的文件,對與模組開發的說明在這裡:
伺服器的職責
這個文件首先說明了Freeradius伺服器主要工作。Freeradius伺服器就是一個認證伺服器(AAA伺服器,認證、授權、計帳),它只做如下工作:
- 獲取一個RADIUS request
- 處理該request
- 在database中查詢資訊
- 將資訊儲存在database中
- 返回一個response
所以Freerasdius不需定時器等其他複雜的設計,因為那樣會讓伺服器不穩定、不安全、不易維護。(KISS原則即視感)
一些思考:看到這裡感覺FR就是在TCP/IP的基礎上,進行分包的處理:接收一個請求request包;分析這個包;處理邏輯;返回響應response。
伺服器的業務邏輯重點就是分包的處理。底層的IO由網路庫來支援好,那麼程式設計師的工作效率會有所提高吧。muduo網路庫、handy網路庫是C++網路庫,libevent是C網路庫,應該感謝這些作者。
模組簡介
一個模組由若干元件構成:
- authorization(授權):檢查使用者是否存在,確定一個認證過程,設定一些response中的attribute
- authentication(認證):驗證密碼是否正確
- accounting(計帳): 將request記錄在log中
…
A module declares which components it supports by putting function pointers in its “module_dl_t rlm_*” structure.
元件其實就是函式,也就是說一個模組需要實現一些特定的函式,供FR呼叫。這些函式的指標存放在一個叫modult_t
的結構中。
模組的配置
要想使用某個模組,需要在radiusd.conf中的modules{}塊中新增該模組的例項:
module_name [instance_name] {
param1 = value1
param2 = value2
param3 = value3
...
}
module_name可以在安裝目錄下的lib資料夾中查詢,我的安裝目錄是/usr/local,因此/usr/local/lib
下包含所有安裝的模組,名字為rlm_xxx.so
instance_name用於區分同一個module的不同例項,如果只有一個例項可以忽略不寫。
param是模組定義的引數,通常是指定database的位置、開啟某些功能。它們由伺服器直接傳遞給模組。
當伺服器接收到一個Access-Request時,authorize{} 塊被呼叫(它會選定某種Auth-Type),然後authenticate{}中的對應的Auth-Type{}塊被呼叫。最後post-auth{}塊被呼叫。
模組的生命週期
當伺服器啟動時或接收到SIGHUP而重新初始化時,伺服器會讀取modules{}塊,在該塊中的module會被載入,並且它的init()方法會被呼叫。(沒明白init)
接著module的instantiate()被呼叫,server會給該函式傳遞兩個引數:
- CONF_SECTION *cs:通過cs可以訪問到在前面設定的模組引數等。
- void *instance : 該模組例項的指標。
int instantiate(CONF_SECTION *cs, void *instance)
模組的authorize(), authenticate(), preaccounting(), and accounting()也以同樣的方式被呼叫,它們的原型如下所示:
int authorize(void *instance, REQUEST *request)
int authenticate(void *instance, REQUEST *request)
int preaccounting(void *instance, REQUEST *request)
int accounting(void *instance, REQUEST *request)
instance與上面相同,是模組的handle,request則代表請求。它們會使用instance中儲存的database來處理該request。
當伺服器關閉時,模組的detach被呼叫,它會釋放在instantiate中獲取的資源。當一個模組的所有例項被detached了,模組的destroy被呼叫,它釋放在init中獲取的資源。
src/modules/stable
將模組名字新增到這個檔案中,模組會被編譯。
伺服器處理流程
FreeRADIUS uses a thread pool to serve requests. Each request is processed
synchronously, and processing passes through a series of stages, and a list
of modules in each stage.
The request is processed as follows
- The radius packet is received by a listener - see listen.c
- The radius packet is parsed and validated into a request - see ?
- The request is processed - see process.c
- The server passes through each authentication stage
- authorize
- if Proxy-To-Realm is set:
- pre-proxy
- send proxy request
- post-proxy
- else
- authenticate
- post-auth
- Authentication stages are lists of modules - see modcall.c