寫在前面的話
RADIUS:Remote Authentication Dial In User Service,遠端使用者撥號認證系統由RFC2865,RFC2866定義,是應用最廣泛的AAA協議。
如下簡單的分析一下 RADIUS 協議是怎麼工作的。
名詞解釋
BRAS:寬頻接入伺服器,Broadband Remote Access Server,簡稱 BRAS
NAS: 網路接入伺服器,Network Access Server,簡稱 NAS
AAA: 認證 Authentication,授權 Authorization,計費 Accounting
RADIUS: 遠端認證撥號使用者服務,remote authentication dial-in user service,簡稱RADIUS。
DM: Radius主動發起斷開連結請求 Disconnect-Request,簡稱DM
COA: Radius主動發起修改授權屬性,Change of Authorization,簡稱 COA
報文說明
Radius協議的報文協議
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Code | Identifier | Length |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | |
- | Authenticator |
- | |
- | |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Attributes ...
- +-+-+-+-+-+-+-+-+-+-+-+-+-
在報文中的表示如下所示:
Radius 報文可以分為 Header 和 Attribute 兩部分
Radius 的頭部程式碼定義
- // radius header
- typedef struct RadHeader {i
- unsigned char code;
- unsigned char identifier;
- unsigned short length;
- unsigned char authcator[16];
- } RadHeader;
Code 佔一個位元組
常用的取值如下:
- 1 Access-Request
- 2 Access-Accept
- 3 Access-Reject
- 4 Accounting-Request
- 5 Accounting-Response
- 6 Accounting Status (now Interim Accounting [5])
- 7 Password Request
- 8 Password Ack
- 9 Password Reject
- 10 Accounting Message
- 11 Access-Challenge
- 12 Status-Server (experimental)
- 13 Status-Client (experimental)
- 21 Resource Free Request
- 22 Resource Free Response
- 23 Resource Query Request
- 24 Resource Query Response
- 25 Alternate Resource Reclaim Request
- 26 NAS Reboot Request
- 27 NAS Reboot Response
- 29 Next Passcode
- 30 New Pin
- 31 Terminate Session
- 32 Password Expired
- 33 Event Request
- 34 Event Response
- 40 Disconnect Request
- 41 Disconnect Ack
- 42 Disconnect Nak
- 43 Change Filters Request
- 44 Change Filters Ack
- 45 Change Filters Nak
- 50 IP Address Allocate
- 51 IP Address Release
- 255 Reserved
Identifier是報文的流水號
NAS 和 AAA 伺服器通過這個流水號來標識認證請求和認證響應,計費請求和計費響應的配對關係。
如下所示:
認證請求和認證響應的配對關係。
計費請求和計費響應的配對關係。
Length 欄位是整個報文的長度
長度包括 Code, Identifier, Length, Authenticator 和 Attribute fields.
Authenticator認證
這個欄位主要是為了驗證報文的合法性。
計算方式如下 MD5(Code+ID+Length+RequestAuth+Attributes+Secret)
Attribute屬性
這個欄位是 Radius 協議的重點,包括標準屬性和廠家的26號私有屬性兩類。
Attribute 通過 T-L-V 編碼格式進行編碼,Type-Length-Value
Radius 的 Attribute 程式碼定義
- // radius int attribute.
- typedef struct RadInt {
- unsigned char type;
- unsigned char length;
- char value[4];
- } RadInt;
- #define RAD_ATTRSTR_LEN 253 /* Attribute (string) */
- // radius string attribute.
- typedef struct RadStr {
- unsigned char type;
- unsigned char length;
- char value[RAD_ATTRSTR_LEN];
- } RadStr;
- // radius structure attribute.
- typedef struct AttrStru {
- unsigned char type;
- unsigned char length;
- char iValue[1];
- } AttrStru;
Radius 的 Attribute 的 Type 有如下幾種,不同的型別使用不同的編解碼器進行編解碼處理。
- // Define Attribute and Value Type.
- #define RAD_ATTR_TYPE_STRING (0x01)
- #define RAD_ATTR_TYPE_ADDRESS (0x02)
- #define RAD_ATTR_TYPE_INTEGER (0x03)
- #define RAD_ATTR_TYPE_TIME (0x04)
- #define RAD_ATTR_TYPE_ADDRESS6 (0x05)
- #define RAD_ATTR_TYPE_FIX8 (0x06)
- #define RAD_ATTR_TYPE_BINARY (0x07)
- #define RAD_ATTR_TYPE_IPV6PREFIX (0x08)
- #define RAD_ATTR_TYPE_SECRET (0x09)
- #define RAD_ATTR_TYPE_UNKNOWNTP (0x00)
認證計費的完整流程
認證失敗流程
AAA 返回給 NAS認證拒絕時,流程結束 。
認證成功+計費流程
AAA 返回給 NAS 認證成功時,NAS 會繼續發起計費開始報文,使用者下線時 NAS 發起計費結束報文,AAA 回覆計費相應報文。
認證請求報文(Authentication Request)
報文資料方向,NAS發起到AAA Radius Server
- +----------+ Auth-Request +----------+
- | | --------------------> | |
- | NAS | | RADIUS |
- | | Auth-Response | Server |
- | | <--------------------- | |
- +----------+ +----------+
Code取值:1
如下以華為的裝置為例說明認證請求報文:
認證通過響應報文(Authentication Accept)
報文資料方向,AAA Radius Server傳送認證通過給 NAS
- +----------+ Auth-Request +----------+
- | | --------------------> | |
- | NAS | | RADIUS |
- | | Auth-Response | Server |
- | | <--------------------- | |
- +----------+ +----------+
Code取值:2
如下是一個認證成功的響應報文例子:
通過驗證使用者的賬號和密碼,驗證方式優 PAP 和 CHAP, 對通過驗證的使用者,下發授權峰值頻寬,控制使用者的上網頻寬。
以華為裝置為例,AAA 會通過上網策略下發如下幾個屬性控制上網頻寬。
如下舉例說明,將上行頻寬設定為1M,下行頻寬設定為2M。
HW-Input-Peak-Rate 1048576
HW-Input-Average-Rate 1048576
HW-Input-Basic-Rate 1048576
HW-Output-Peak-Rate 2097152
HW-Output-Average-Rate 2097152
HW-Output-Basic-Rate 2097152
認證拒絕響應報文(Authentication Reject)
報文資料方向,AAA Radius Server傳送認證拒絕給 NAS
- +----------+ Auth-Request +----------+
- | | --------------------> | |
- | NAS | | RADIUS |
- | | Auth-Response | Server |
- | | <--------------------- | |
- +----------+ +----------+
Code取值:3
通過PAP 和 CHAP方式驗證使用者的使用者名稱和加密密碼失敗時,AAA會返給NAS 一個認證拒絕報文。
如下是一個認證拒絕的響應報文例子:
計費請求報文(Accounting Request)
報文資料方向,NAS 傳送計費報文給AAA Radius Server
- +----------+ Acct-Request +----------+
- | | --------------------> | |
- | NAS | | RADIUS |
- | | Acct-Response | Server |
- | | <--------------------- | |
- +----------+ +----------+
Code取值:4
通過第一步中,NAS 發起認證請求到 AAA,AAA 認證通過給 NAS 後。
NAS 進行第二步的報文互動,NAS 發起計費開始報文請求到 AAA,AAA 計費響應報文給 NAS 。
注:計費報文的 Acct-Session-Id必須和第一步認證通過的 Acct-Session-Id 一致,說明本次計費是以認證成功的 Acct-Session-Id為計費物件。
使用者某一時間段的總流量是通過這個時間段內一個一個的 Acct-Session-Id上流量合併得到。
計費報文分三類:
- 計費開始報文 Start
- 計費保活報文 Keepalive
- 計費結束報文 Stop
計費的開始報文Start:
計費請求引數 Acct-Status-Type = 1
如下是一個計費開始報文的報文例子:
計費的結束報文Stop
計費報文的Acct-Status-Type = 2
問題:運營商是如何統計一個寬頻賬號使用了多少流量呢?
運營商通過計費結束報文的Acct-Input-Octets統計上行流量,Acct-Output-Octets 統計下線流量,將這兩個流量相加得到使用者實際上網使用的流量是多少。
注:若使用者流量超過一定的額度,可以通過下次賬號登入後,下發授權峰值頻寬,控制使用者的上網頻寬。見認證響應通過報文。
如下是一個計費結束報文的報文例子:
計費響應報文(Accounting Response)
報文資料方向,AAA Radius Server傳送計費相應給 NAS
- +----------+ Acct-Request +----------+
- | | --------------------> | |
- | NAS | | RADIUS |
- | | Acct-Response | Server |
- | | <--------------------- | |
- +----------+ +----------+
Code取值:5
如下是一個計費響應報文的報文例子:
DM踢使用者下線報文
- +----------+ Disconnect-Request +----------+
- | | <-------------------- | |
- | NAS | | RADIUS |
- | | Disconnect-Response | Server |
- | | ---------------------> | |
- +----------+ +----------+
Code取值:請求40,響應成功41,響應失敗42
注:在 DM 報文中比較重要的屬性是 Acct-Session-Id,即:要將使用者的哪個會話踢下線。
如下是一個 DM 的組包程式碼例子:
- int DisconnectHuaWei(int argc, char **argv) {
- char radiusPacketBuffer[0xffff+1] = {0};
- memset(radiusPacketBuffer, 0, sizeof(radiusPacketBuffer));
- radiusPacketBuffer[0] = 40;
- gID = ++gID % 0xff;
- radiusPacketBuffer[1] = gID;
- int len = 20;
- // User-Name 1
- int tmpLen = strlen(argv[1]);
- sprintf(radiusPacketBuffer+len, "%c%c%s", 1, tmpLen+2, argv[1]);
- len += tmpLen+2;
- // Framed-Ip-Address 8
- unsigned int sin_addr;
- if(inet_pton(AF_INET, argv[2], &sin_addr) <= 0)
- {
- return TCL_ERROR;
- }
- // 轉換成網路套接字
- //sin_addr = htonl(sin_addr);
- radiusPacketBuffer[len++] = 8;
- radiusPacketBuffer[len++] = 6;
- memcpy(radiusPacketBuffer+len, &sin_addr, 4);
- len += 4;
- // NAS-IP-Address 4
- if(inet_pton(AF_INET, argv[4], &sin_addr) <= 0)
- {
- return ERROR;
- }
- // 轉換成網路套接字
- //sin_addr = htonl(sin_addr);
- radiusPacketBuffer[len++] = 4;
- radiusPacketBuffer[len++] = 6;
- memcpy(radiusPacketBuffer+len, &sin_addr, 4);
- len += 4;
- // Acct-Session-Id 44
- tmpLen = strlen(argv[3]);
- sprintf(radiusPacketBuffer+len, "%c%c%s", 44, tmpLen+2, argv[3]);
- len += tmpLen+2;
- radiusPacketBuffer[2] = len / 0xff;
- radiusPacketBuffer[3] = len % 0xff;
- unsigned char authen[17] = {0};
- int keyLen = strlen(brasSecureKey);
- memcpy(radiusPacketBuffer+len, brasSecureKey, keyLen);
- MD5Calc((unsigned char*)radiusPacketBuffer, len+keyLen, authen);
- memcpy(radiusPacketBuffer+4, authen, 16);
- return OK;
- }
COA下發策略報文(修改上下行頻寬,即:網路提速)
- +----------+ CoA-Request +----------+
- | | <-------------------- | |
- | NAS | | RADIUS |
- | | CoA-Response | Server |
- | | ---------------------> | |
- +----------+ +----------+
Code取值:請求43,響應成功44,響應失敗45
COA 的請求包43
如下是一個 COA 報文例子:
注:在 COA 報文中比較重要的屬性是 Acct-Session-Id,即:要改變使用者的哪個會話上的屬性。
COA 可以做 Portal 登入重定向,修改上網頻寬等功能。
COA的回包44
如下是一個 COA 的組包程式碼例子
- int OpenHUAWEI(int argc, char **argv) {
- char radiusPacketBuffer[0xffff+1] = {0};
- memset(radiusPacketBuffer, 0, sizeof(radiusPacketBuffer));
- radiusPacketBuffer[0] = 43;
- gID = ++gID % 0xff;
- radiusPacketBuffer[1] = gID;
- int len = 20;
- // User-Name 1
- int tmpLen = strlen(argv[1]);
- sprintf(radiusPacketBuffer+len, "%c%c%s", 1, tmpLen+2, argv[1]);
- len += tmpLen+2;
- // Framed-Ip-Address 8
- unsigned int sin_addr;
- if(inet_pton(AF_INET, argv[2], &sin_addr) <= 0)
- {
- return ERROR;
- }
- // 轉換成網路套接字
- //sin_addr = htonl(sin_addr);
- radiusPacketBuffer[len++] = 8;
- radiusPacketBuffer[len++] = 6;
- memcpy(radiusPacketBuffer+len, &sin_addr, 4);
- len += 4;
- // Acct-Session-Id 44
- tmpLen = strlen(argv[3]);
- sprintf(radiusPacketBuffer+len, "%c%c%s", 44, tmpLen+2, argv[3]);
- len += tmpLen+2;
- // Huawei-HW-Portal-Mode 85
- radiusPacketBuffer[len++] = 0x1a;
- radiusPacketBuffer[len++] = 6+4+2;
- radiusPacketBuffer[len++] = HUAWEIVendor[0];
- radiusPacketBuffer[len++] = HUAWEIVendor[1];
- radiusPacketBuffer[len++] = HUAWEIVendor[2];
- radiusPacketBuffer[len++] = HUAWEIVendor[3];
- radiusPacketBuffer[len++] = 0x55;
- radiusPacketBuffer[len++] = 0x06;
- radiusPacketBuffer[len++] = 0x00;
- radiusPacketBuffer[len++] = 0x00;
- radiusPacketBuffer[len++] = 0x00;
- radiusPacketBuffer[len++] = 0x01;
- // Huawei-PortalURL 27
- tmpLen = strlen(argv[4]);
- radiusPacketBuffer[len++] = 0x1a;
- radiusPacketBuffer[len++] = tmpLen+2+4+2;
- radiusPacketBuffer[len++] = HUAWEIVendor[0];
- radiusPacketBuffer[len++] = HUAWEIVendor[1];
- radiusPacketBuffer[len++] = HUAWEIVendor[2];
- radiusPacketBuffer[len++] = HUAWEIVendor[3];
- sprintf(radiusPacketBuffer+len, "%c%c%s", 27, tmpLen+2, argv[4]);
- len += tmpLen+2;
- radiusPacketBuffer[2] = len / 0xff;
- radiusPacketBuffer[3] = len % 0xff;
- unsigned char authen[17] = {0};
- int keyLen = strlen(brasSecureKey);
- memcpy(radiusPacketBuffer+len, brasSecureKey, keyLen);
- MD5Calc((unsigned char*)radiusPacketBuffer, len+keyLen, authen);
- memcpy(radiusPacketBuffer+4, authen, 16);
- return OK;
- }
26號私有屬性說明
不同的廠家使用的26號私有屬性各有不同,如下列舉國內運營商常用的廠家的26號屬性。
# 亞信 AsiaInfo extern Vendor Attrib
# Vendor 26, 999
#
# 愛立信 Ericsson extern Vendor Attrib
# Vendor 26, 2352
#
# 華為 HuaWei extern Vendor Attrib
# Vendor 26, 2011
#
# 中興 ZTE extern Vendor Attrib
# Vendor 26, 3902
#
# 貝爾 BELL-ALC extern Vendor Attrib
# Vendor 26, 6527
#
# 海蜘蛛 HISPIDER extern Vendor Attrib
# Vendor 26, 16010
# ...
參考材料:
認證報文RFC參考 RFC2865: https://www.rfc-editor.org/rfc/rfc2865
計費報文RFC參考 RFC2866:https://www.rfc-editor.org/rfc/rfc2866
動態授權(DM和COA)RFC參考 RFC3576:https://www.rfc-editor.org/rfc/rfc3576
認證請求的CHAP參考:https://www.cnblogs.com/voipman/p/5047912.html
認證請求報文的PAP參考:https://www.cnblogs.com/voipman/p/5345320.html
PPPoE的參考:https://www.cnblogs.com/voipman/p/pppoe.html