SNMP開發過程中的一些積累


採用snmpusm和snmpvacm操作snmp V3的設置, 有一點一定要注意,就是這些設置在snmpd退出之前,是存在內存中的,當snmpd退出之前,纔會寫入到文件中. 這就是爲什麼單板被突然斷電,snmpd會失去之前的usm和vacm配置的原因. 這不是bug,是snmp官方故意這麼設計的. 要解決這個問題, 只要執行snmpset [options] agent_ip 1.3.6.1.4.1.2021.100.13.0 i 1 即可,即設置versionSavePersistentData這個mib節點爲1,讓其立刻將信息存儲在文件中. 因此,usm和vacm的操作之後,應該加入讓versionSavePersistentData爲1的操作纔是嚴謹的. 


接收SNMP的TRAP可以採用MIB Browser的工具接收,如果用wireshark發現電腦可以收到snmpd上送的包,但是MIB Browser卻無法顯示,基本是如下兩個問題:1.操作系統的防火牆;2.win7自帶的snmp trap進程佔用了162端口。對於第二個問題,搜索“服務”,找到“SNMP Trap”服務,將啓動類型改爲“禁用”,重啓電腦,即可生效。目前主流的MIB Browser可以支持Trap V3,但是支持不了Inform V3,從好用的角度來說,推薦MG-Soft,從免費的角度來說,推薦ManageEngine。


MD5/SHA算法有3個特點:不可逆;雪崩效應;不衝突。不可逆就是拿到計算結果沒有反回來算出輸入是啥;雪崩效應是輸入任何一點變化都會導致輸出變化很大,防止根據輸出的相似性來猜測輸入;不衝突就是輸入與輸出的唯一性。根據這些特點,MD5/SHA會主要用於:認證和內容篡改識別。認證:由於密碼不能明文在網絡傳輸,因此用MD5/SHA計算出一個值,網絡接受者用已知的密碼和用相同的算法計算出另一個值,由於唯一性特點,一定是相等的,因此,可以判斷對方是否擁有正確密碼的設備。SNMP的V3就是使用了這種方法進行認證的。內容篡改識別:計算輸入和計算結果需要一起發給接收者,接收者採用相同算法計算其拿到的輸入,如果結果不一樣,那內容肯定被改了 


SNMP最安全的V3,我們一直用錯了N年,最大的問題是密碼明文存儲。SNMP的V3用戶名和密碼應該寫在/var/net-snmp/snmpd.conf,而不是我們自己的snmpd.conf中,SNMP啓動時會將前者的明文密碼加密。這樣,即使黑客攻入了我們的單板,拿走的也只是加密的密碼,只能訪問這臺設備而已,其他不通用;反之,密碼明文化,一旦密碼文件被盜,我們的全部單板都將會落入別人的完全監控之中。由於密碼加密,我們也無法使用Web的方式去查看和修改密碼,必須採用SNMP提供的工具snmpusm和snmpvacm來控制V3的訪問。我們以前的方法,因爲不正規,反而是無法實現世界通用的snmpusm和snmpvacm的方式來控制權限的


SNMP的V3正確應用爲:在單板第一次啓動時,在/var/net-snmp/snmpd.conf通過createUser明文創建一個V3的初始用戶,snmpd啓動後,會將其刪除並加密。客戶通過snmpusm(user security model)克隆一個新用戶的方式來更改用戶名和密碼(建議同時刪除我們的初始用戶)。這樣客戶就有自己的賬號了,但還不夠,他們還不能訪問我們的單板,因爲這些V3用戶沒有被定義訪問權限。客戶必須通過已知的可讀寫V2賬戶操作snmpvacm(view access control model),經過createView,createSec2Group,createAccess三步後,V3用戶才具備訪問權限。也就是說,權限管理全掌握在客戶那,我們甚至無法知道客戶的V3密碼。這種纔是世界最正式的SNMPV3密碼權限管理。


snmpusm用戶安全模型命令的用法例子:snmpusm -v3 user_name -l authPriv -a MD5 -A md5_passphase -x DES -X des_passphase target_ip create new_user old_user. snmpusm和create之間的一大串,和snmp通用命令操作V3的用法完全一致。注意,snmpusm操作,本質也是操作相應的MIB節點的內容,但該節點只允許V3用戶操作,這就是爲什麼單板必須有一個V3初始用戶的原因。除此之外,V3用戶也應該具有該MIB節點的操作權限,如果無法操作,可以通過snmpvacm增加其權限。需要注意的是,snmpusm無法改變用戶的認證方式和加密方式!如果被克隆的用戶是MD5和DES,那麼是無法修改爲SHA和AES的。如果要支持全部MD5/SHA和DES/AES,必須有4個不同初始用戶才行。 


snmpvacm訪問控制模型命令的用法例子:snmpvacm -v2c -c private target_ip createSec2Group 3 zteuser ZteGroup. 首先,客戶將自己的賬戶zteuser放入一個安全模型爲V3的ZteGroup組中。snmpvacm ... createView zte_view .1.3.6.xx.xx 定義zte_view的可視mib節點範圍,類似宏定義。snmpvacm ... createAccess ZteGroup 3 1 1 zte_view zte_view none給ZteGroup定義訪問級別,第一個數字3表示V3, 第二個數字1代表安全認證級別noAuthNoPriv(2,3依次類推),第三個數字的1代表精確匹配OID,最後三個分別是read,write,notify的view範圍,none表示沒有權限。通過這種方式,可以非常嚴密地控制賬戶的信息安全。


SNMP的V3主動上送其實不難,在snmpd.conf中使用trapsess關鍵字即可,同時trapsess兼容v1和v2c的主動上送,因此,trapsink(v1),trap2sink(v2c),informsink(v2c)三個指令都可以被trapsess取代掉。trapsess通過-Ci表示是inform格式,-v x代表x版本,如果是v3,用戶名則用-u(user name),否則用戶名用-c(community)。當trapsess使用v3時,通用參數和snmpget等一樣使用,很簡單。需要注意的是,我們自己的snmpd.conf的trapsess中不應該將v3的密碼明文化,而應該使用在/var/net-snmp/snmpd.conf中存在的用戶(已加密),這種情況下,我們的snmpd.conf中的trapsess只需要寫已存在的用戶名和需要的安全級別即可,不需要重複寫密碼。這樣就更安全了。 


SNMP可以實現多維表格,通過多個index實現,index不僅僅可以是數字,甚至可以是字符串,object ID,IP等。假設某個變量的OID爲X,那麼X.3.5的3和5就是第一個index和第二個index的值,代表二維角度的第3行和三維角度的第5行。那其他格式的index怎麼表達呢。字符串和object ID類型都是不定長,因此需要在最開始有其總長度的描述,然後纔是內容(字符串沒有C裏的0作爲結束符),舉例,字符串index內容爲_none_,那麼表達就是6.95.110.111.110.101.95,6代表總長度,後面就是ascii碼對應的數值。因此,SNMP中通過OID一定能唯一識別一個變量的身份。


snmp使用在嵌入式時,存在一些bug,交叉編譯的動態庫在加載時會出現一些奇怪的問題,因此目前需要將庫信息編譯在snmpd程序中。另外,將自己的業務代碼編譯成動態庫時,如果該動態庫依賴了snmp的動態庫,加載時也會出現相同的奇怪問題(Inconsistency detected by ld.so: dl-deps.c: 622),因此,自己的動態庫也不能鏈接snmp的動態庫。解決方法:1.自己的動態庫即使使用了snmp的動態庫,但是編譯時不能加上snmp庫的鏈接信息。2.由於snmp的庫信息實際是被主程序集成的,因此,主程序只需要在編譯時,加上-rdynamic即可,即把符號信息輸出到動態符號表中,那麼後面採用dlmod加載自己的業務模塊時,就不會存在undefined symbol的問題了。


新版源碼snmp(如5.7.3,LTS)的交叉編譯仍然有bug,因爲net-snmp的核心團隊沒有嵌入式的人才。默認交叉編譯時,會出現undefined reference to `clock_gettime'的錯誤。解決方法:configure中,加入--with-libs="-lrt"即可。另外,動態庫的方式是有問題的,需要將庫信息納入bin中,才能正常運行,因此,需要加入--disable-shared 


snmpd支持動態加載mib庫,好處是新的mib的需求,一般不需要改動核心源碼。將新的mib需求編譯成動態庫,由snmpd選擇性加載,對版本管理帶來了很大的方便。業務代碼和龐大的源碼分開,也大大降低了維護難度。一般需要3部:1.讓snmpd支持動態加載,./configure --with-mib-modules="ucd_snmp" --enable-shared 2.將業務代碼編譯成動態庫 3.在snmpd.conf中告訴snmpd去哪加載庫,加入 dlmod xxxx /a/b/c/xxxx.so 即可 第一個參數是動態庫名,第二個參數是全路徑。


如果需要使用pysnmp,強烈建議使用sudo aptitude install python-pysnmp4來安裝。因爲這樣的安裝,會將內容放在一個文件夾裏,自己的MIB文件在編譯後,可以方便的放入/usr/lib/python2.7/dist-packages/pysnmp/smi/mibs裏。否則,如果是下載包自己python setup.py install,會產生安裝內容全部放入一個egg文件裏的情況,即使通過setMibPath來新增搜索路徑來加載自己的mib.py文件也不行。這坑浪費了我半天時間!pysnmp需要通過build-pysnmp-mib指令來將普通的MIB文件(.txt,.my,.mib)變成xxx.py文件,且要放入pysnmp的smi/mibs裏。 


ASN.1的INTEGER嚴格來說是一定要有範圍,但是SMI不是完全照搬ASN.1,因此,SMI默認認爲INTEGER爲Integer32類型(Integer32爲INTEGER (xxx,yyy)),Integer32由於本身就是加了範圍,因此Integer32 {xxx,yyy}的限制就有問題,SMI直接報錯的原因。


snmp的mib文件可以採用smilint命令來檢查語法,如smilint -s xxx.mib . -s意思是加入數字告知錯誤的級別,越小越嚴重越要優先處理,如果只要檢查嚴重的錯誤,只需要加入-l1,即level 爲1才報錯。如果使用smilint出現“smilint failed to locate MIB module”錯誤,只需要下載snmp_mibs_downloader即可(apt-get install snmp_mibs_downloader)安裝基本的mib文件。


net-snmp中有大量的類似DEBUGMSGTL(("trap", "received the inform response for reqid=%d\n",reqid));的調試函數,怎麼輸出呢?網上只說了運行時加 -Dtoken的參數。實際上,Net-snmp-config.h文件中,必須註釋掉NETSNMP_NO_DEBUGGING的宏定義,並把NETSNMP_ALWAYS_DEBUG改爲0,才能是-Dtoken生效。舉例,上面這句的調試token就是第一個“trap”,則./snmp -f -Dtrap就可以只輸出token爲trap的所有調試信息了。 這種技術,如果用在CSU上,將會爲調試提供很多方便。


CSU的snmpd啓動時默認會fork一個進程執行,因此,shell中是看不到任何輸出的,可以加 -f,表示do not fork from the shell,這樣,纔會看到snmpd的輸出信息。snmpd -h可以查看所有的選項,-f是這些當中比較實用的。 




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章