監看網路封包程式設計概說

以前同事寫的文章.
作者: 邵文琳
前一個禮拜花了不少時間在看網路封包方面的程式設計 ..覺得十分有興趣.
感謝charles 和 ellery 的幫助 . 讓我觀念比較清楚 …
在這裡我把我這一個星期的學習心得寫下來.
讓大家以後若有機會寫到類似程式時, 可是事半功倍 ..
網路程式設計方面相關資料很多 . 但是都是對比較上層的tcp,或udp的應用在做介紹.
對於網路層和datalink層面則著墨較少 .
所以”對我而言” 學習起來比較困難. 希望寫下這個對大家會有幫助.
一個網路封包監看程式 . 說穿了 只有四個重點:
第一 . 開啟一個可接收raw packet 的socket .
一般我們開始socket接收tcp或udp的packet 時, 我們收到的內容就直接是資料內容 .
kernel 己經幫我們把ethernet header 和 ip 或 arp header 都拿掉了.
但是在寫網路封包程式時, 我們需要header . 因此我們在開啟socket 的時候,就可以針對我們要收集的封包總類做過濾. 要求接收到的資料裡要包涵完整的封包標頭檔…
第二 . 有條件的接收封包和無條件的接收封包.
網路卡只會接收到ethernet header 的target mac 是自己的mac 時, 或接收到TARGET MAC 為 ff:ff:ff:ff:ff 的封包, 或是multicasting 的封包(也就是target ip是224開頭的封包 . 這種情況叫做 nonPromiscuous . 當我們要監看網路封包時,希望收到的不只是broadcast 或是 multicasting 或是自己的封包時, 我就要把網路卡設定成 Promiscuous . 如此一來我們就可以接到實體網路上的所有封包了…
第三 . filter 的設定.
當我們把網路卡設成 Promiscuous , 而且看到了所有封包header 時, 我們就可以依照我們自己的意思去過濾出我們想要的封包 . 可是一個問題來了 .. 網路上的封包那麼多.我們全都要一個個的去把它的標頭打開, 看看是不是自己要看的封包. 這樣做花的時間太長.以致於後面進來的封包都塞在buffer 裡, 等你一個個的檢查..我們需要一個filter 建立在硬體層和聯結層中建立一個filter , 先過濾出我們要的封包,再交由程式處理 . 這就是filter的功用.這種filter 是由bpf code 寫出來的! 不會寫bpf code ? 沒關係. 我們還是有別的方法把它變出來 ,,,,,
第四 . multiplexing I/O (blocking VS noblocking)
就如我們所知道的當我們在receving packet 時. 如果沒有資料進來, 程式就會等在那裡 ,這種情況叫做blocking , 但是有時候我們不想要無止限的等在那裡時, 郤又沒法把break 出來時,怎麼辦呢?使用signal 嗎? 另一種解決方式就是把資料流做unblocking.但unblocking 郤不能完成解決我的需求, 於是我利用到了 multiplexing I/O.接下來我在對以上四項做詳細解釋和範例:
第一 socket .
要如何開一個可以接收raw_data 的socket呢 ?

int sock;
// 開一個接收所有走ip protocol 封包的完整封包
sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
// 開一個接收所有走arp protocol 封包的完整封包
sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
// 開一個接收所有 protocol 封包的完整封包
sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_All));
// 在linux 下接收datalink 層的網路封包
sock = socket(PF_INET, SOCK_PACKET, htons(ETH+P_ALL));

PF_PACKET 支援兩個socket type:SOCK_RAW 和 SOCK_DGRAM, SOCK_RAW 會留下完整的 ethernet 標頭.SOCK_DGRAM 會去掉ETHERNET 標頭.但在linux 下使用PF_SOCK , SOCK_RAW 會有問題.最好是使用 PF_INET, SOCKET_PACKET 也可以留下完整的實體層的標頭.
第二 Promiscuous.
網路卡預設當然都是nonPromiscuous , 要變成 Promiscuous 必須對網卡做設定.在socket 己經open 下

#include <linux/in.h>
#include <linux/if_ether.h>
struct ifreq ifrq;
strncpy(ethreq.ifr_name,”eth0″,IFNAMSIZ);
ioctl(sock,SIOCGIFFLAGS,&ifrq);
ifrq.ifr_flags|=IFF_PROMISC;
ioctl(sock,SIOCSIFFLAGS,&ifrq);

若在打開之後,沒有在程式結束前關閉. 它就會一直打開哦 . 所以記得要關閉它.

strncpy(ethreq.ifr_name,”eth0″,IFNAMSIZ);
ioctl(sock,SIOCGIFFLAGS,&ifrq);
ifrq.ifr_flags&=~IFF_PROMISC;
ioctl(sock,SIOCSIFFLAGS,&ifrq);

第三. 設filter
filter 的設定主要是使用在實體層和連接層中間 . 用一種近似組語的bpf code 組成.寫起來挺麻煩的 . 所以我們直接使用tcpdump -dd 來產生的binary code 來用 .

for example:
tcpdump -dd ip dst 172.16.0.3
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 3, 0x00000800 },
{ 0x20, 0, 0, 0x0000001e },
{ 0x15, 0, 1, 0xac100003 },
{ 0x6, 0, 0, 0x00000044 },
{ 0x6, 0, 0, 0x00000000 },
tcpdump -dd ip src 172.16.0.3
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 3, 0x00000800 },
{ 0x20, 0, 0, 0x0000001a },
{ 0x15, 0, 1, 0xac100003 },
{ 0x6, 0, 0, 0x00000044 },
{ 0x6, 0, 0, 0x00000000 },
tcpdump -dd arp dst 172.16.0.3
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 3, 0x00000806 },
{ 0x2 0, 0, 0, 0x00000026 },
{ 0x15, 0, 1, 0xac100003 },
{ 0x6, 0, 0, 0x00000044 },
{ 0x6, 0, 0, 0x00000000 },

其實這些code 的產生是有跡可找的..我就把下面程式碼的binary code 原始bpf pesude code 列出來,可以相對應比較看看

/*
udp and host 192.168.9.10 and src port 5000
(000) ldh [12]
(001) jeq #0x800 jt 2 jf 14
(002) ldb [23]
(003) jeq #0x11 jt 4 jf 14
(004) ld [26]
(005) jeq #0xc0a8090a jt 8 jf 6
(006) ld [30]
(007) jeq #0xc0a8090a jt 8 jf 14
(008) ldh [20]
(009) jset #0x1fff jt 14 jf 10
(010) ldxb 4*([14]&0xf)
(011) ldh [x + 14]
(012) jeq #0x1388 jt 13 jf 14
(013) ret #68
(014) ret #0
*/

我們可以依我們的需要去下command 給tcpdump -dd 幫我們產生binary code. tcpdump, 不但區分不同的protocol. 來源,目的地, even 標頭的第幾個byte,和要接收封包的大小, 都可以變化. 實在是太神奇了.
接下來我們要把code 整合到程式裡去 …
第四 . blocking VS noblocking multiplexing I/O
unblocking 最重要的意思是當有資料流進來時立刻就傳回. 當沒有資料流進來時, 也傳回0.於是我們就可以利用unblocking 和loop 來控制我們要的時間.
以下是程式的寫法:

(fcntl(fd ,F_GETFL) & O_NONBLOCKING) // 1 成功 0 失敗

但是把資料一點一滴的傳進來也並不是我們要的 . 我們還是希望傳進來的資料是一個個block 過的資料,只是當沒有資料進來時, 能夠不要永遠的等在那而己.這就是multiplexing I/O 的概念.當我們read 和recvfrom 一個 file handle 時, 我們可以設定如何沒有資料進來時我要等多久,就能回到程式繼續執行我們要做的動作.
以下是程式的寫法:

#include “sys/time.h”
#include “sys/select.h”
int sock;
struct timeval tv;
fd_set readfds;
sock = socket(…);
tv.tv_sec=1;
tv.tv_usec=0;
FD_ZERO(&readfds); // 清空file handle set.
FD_SET(sock,&readfds); // 加入一個file handle 到file handle set
FD_SET(xxx,&readfds); // 如果還有別的file handle 也要加入同一個
set做控制的話 ..
select(sock+1,&readfds,NULL,NULL,&tv); // 對 file handle set 設
定時間控制
if(FD_ISSET(sock,&readfds)){ // 依readfds的設定來看是否為
true , 依我們的
例出來說,程式會在這裡等上一秒鐘. 如果在這一秒裡有data流進來,
傳回true, 再交給recvfrom把data 接下來, 否則一秒鐘後傳回false
!
// recvfrom(….)
}

基本上把握這幾個主要的重點, 要變化出自己的sniffer 不是問題..剩下來比較討厭的就是把ip 轉成network address to host address..大小印地安,和 inetaddr, inet_addr, inet_aton, inet_ntoa …這些變來變去的死東西了.

.Net 的安全

ASP.Net 的身分驗證
以組態設定(web.config)即可,不必再使用以前的 cookie.
大致的 web.config 如下

<system.web>
…..
<authentication mode=”Forms|Windows|Passport|None”>
  <form name=”your_form” loginUrl=”secure/login.aspx”/>
</authentication>
<authorization>
  <allow users=”*”/>
</authorization>
<globalization requestEncoding=”utf-8″ responseEncoding=”utf-8″/>
…..
</system.web>

子目錄會自動繼承父目錄的 web.config.
一般子目錄裡的 web.config 只有設定

…..
<deny user=”?”/>
…..

程式裡面則是使用 System.Web.Security.FormsAuthentication 類別以及 Redirect 方法作轉向以及驗證工作.
類別的安全
某些類別有受到系統保護,當無法存取時,會丟出 SecurityException.
有兩種方法可以實現:
1.命令式,為權限建立 instance.

new FileIOPermission( FileIOPermissionAccess.Read, Path).Demand()

2.宣告式,以屬性的方式來宣告,比較固定

<FileIOPermission( SecurityAction.Demand, write=”/tmp”>
void foo()
{
}

簡單說,類別若有”類別Permission”的類別,就可以用”類別Permission”去控制類別是否可以被存取.
AssemblyInfo.cs evidence, 此部分與 gac_util 有關係
Permission Set, Security Policy
安全性原則,用 .Net 工具就可以管理其組態.
Role -> 類似群組
Identity -> 類似 user 帳號
Principal -> Role
PrincipalPermission
非結合 Windows 的方法

GenericIdentity MyIdentity=new GenericIdentity(“myuser”);
string[] MyStringArray={“Mgr”,”Developer”};
GenericPrinpal MyPrincipal=new(….);

結合 Windows 方法
AppDomain.CurrentDomain.SetPrincipalPolicy()
Thread.CurrentPrincipal 取得或給定
或先取 Identity, 再由 Identity取得 Principal
WindowsIdentity.GetCurrent(); 取得目前的 identity
=====
ASP.Net 的認證與控制
基本上都是在 web.config 中指定

<authentication mode=”Forms”>
<form name=”” loginUrl=””/>
</authentication>

mode 可以填 passport, none, windows

<authentication>
<allow users=”*”/>
<deny users=”aaa”/>
</authentication>

Weak reference 與垃圾回收機制

閱讀 RUN!PC 蔡學鏞的文章時隨手記下來的~
WeakReference() 弱參考~ System.GC
不太清楚使用時機.
GC=Garbage collection
支援 GC 的語言有 eiffel, python, ruby, java, c#…
GC 演算法,一般常見的作法就是 “標記,清掃,縮併”.
1. mark and sweep collection
2. compacting collection or copying collection, compact collection 就類似磁碟最佳化,copying collection 就類似把東西搬到另外一個地方去重放.
目前被多數 GC 採用的方法則是上述的综合體 – generation collection.
垃圾收集器中有數個 Generation,一般有3個,可以呼叫 System.GC.MaxGeneration 取得;若要強制垃圾收集器進行蒐集垃圾,可以用 GC.Collect( int generation ) 或 GC.Collect();用 GC.GetGeneration(object obj) 可以得知物件在哪個 generation 中.
Rotor?? 是 SSCLi 的代號.
善用 GC 的方法就是不用的變數早早設置為 null.
可參考:
Richard Jones Algorithms for Automatic Dynamic Memory Management.
http://blogs.msdn.com/joelpob/archive/2004/02/26/80776.aspx
關於蔡學鏞其人,可以參考:
Sleepless in Java
Sleepless 2.0

doxygen

以前試 doxygen 怎麼試都試不出來~後來才知道是註解錯了~~
從 RUN!PC 上看到 Java 的註解方法,用這招就萬無一失了~

/**
* description
* –> 一定要空一行喔!!!
* @param text
* @todo
* @see
* @return
* @throws
*/

想要知道怎麼使用 doxygen 的話,可以參考這篇.
網址:http://www.stack.nl/~dimitri/doxygen/doxygen_intro_cn.html
寫的蠻仔細的,中文參考資料也好像就這麼一篇….

機車皮帶又斷了

星期二的早上, 5/11 騎車上班的途中,到福和橋下的時候,機車突然發出啪啪的聲音,然後油門怎麼催都沒有反應,我知道,這是因為機車的皮帶斷了~~
於是只好和太太把車牽去修理,並請他先搭計程車去上班~~
可能是因為太早了吧,才八點多,雖然這附近有蠻多機車店的,但並沒有任何一家機車店開門~~送太太搭計程車之後,心裡想,把車丟了,先去吃早餐好了~~
來到早餐店,
“老闆,一份烤煎蛋還有一杯奶茶”
“什麼?”
喔~~原來是外籍人士,可能是越南人吧,所以聽不懂…
“一份火腿蛋三明治,一杯奶茶”
“好…”
過了不久,三明治還有奶茶送到.咬了三明治一口,發現裡面有生菜~光這點,口感就與其他家早餐店的三明治不同了,再加上醬料也相當不錯,讓我對這家早餐店的印象不錯…
吃完,回去機車那邊,發現剛好有一家機車店開門了~~
老闆是個年紀有點大的中年人,邊修車的同時,他問我,要不要順便驗一下排氣?
我說好~~
很愉快的花了一千元搞定之後,就快要九點了….
於是就趕緊騎車去上班了~~
運氣還真的是不錯啊~~

ltdl library

可以輸入 info libtool 找 Module loaders for libltdl 就可以得到不少資訊.
簡單說,就是可以製作能動態載入 module/plugin 的 library, 以 linux 來說,底層其實就是 dlopen, dlsym 這些函數
這個 library 其實是一個 wrapper, 跨了好幾個平台: BSD, Linux, Win32…
configure.in 中的設定
AC_LIBLTDL_CONVENIENCE
AC_SUBST(LTLINCL)
AC_SUBST(LIBLTDL)
AC_LIBTOOL_DLOPEN
AC_PROG_LIBTOOL
AC_CONFIG_SUBDIRS(libltdl)
Makefile.am 中的設定
SUBDIRS=libltdl
INCLUDES=$(LTDLINCL)
prog_LDFLAGS=-export-dynamic
prog_LDADD=$(LIBLTDL) “_dlopen” self “_dlopen” fxx.la
prog_DEPENDENCIES=$(LIBLTDL) fool.la
prog 指的是執行檔名稱
而 module/plugin 的 Makefile.am 設定
xxx_la_LDFLAGS=-module
函數蠻多的,可以直接從 ltdl.h 去找或參考 info
對於 Multi-Thread 也有支援.

[亂逛]WxWidget相關軟體

2003年底某天去找 WxWindows (現已更名為 WxWidget) 逛到的一些用 WxWidget 這個 framework 的軟體.
WxWidget http://www.wxwidget.org 官方網站
WxJS http://wxjs.sourceforge.net
WxBasic http://wxbasic.sourceforge.net
WxWorkshop http://wxworkshop.sourceforge.net 開發工具
poedit http://poedit.sourceforge.net 編輯 po 檔的工具,用過的感覺還不錯~~蠻好用的~~
ldaptool http://ldaptool.sourceforge.net LDAP Explorer Tool
text2rtf http://www.wxwidget.org/text2rtf/index.htm 轉換 LaTex 的文檔為 rtf / html / xlp
pgadmin3 http://pgadmin.org/pgadmin3/index.php Postgre SQL 的管理工具
WxBlogger http://homepage.mac.com/codonnell/wxBlogger/Personal Blog, blog 的內容都會轉存為 html 檔.屆時發佈這些 html 檔就行了~~

骨折記

記得 2000 年年初的時候,有一次,因為客戶有問題,處理的一肚子火,於是很生氣,就打牆壁,想說牆壁有貼一塊軟木紙,應該不會有事,就用力打.
結果……好痛……
那時候已經晚上九點多了,強忍痛意騎車去看醫生~~
照了 X 光,醫生說,”是骨折,右手手掌連接小指的那根骨頭斷了~你明天最好去大醫院看~~”
所以只幫我固定了一下~~而我仍然神勇地騎車回家……
隔天去了永和耕莘醫院,醫生看了看就說,”少年仔,跟別人打架喔~~”
我說,”不是….”
醫生說,”不要騙了啦….”
我只好不說話,因為實在不想說出原因…..
於是就打了一個月的石膏…..開始練習左手吃飯,左手打字,左手用滑鼠……
經歷了這件事情以後,我體悟到一件很重要的事情:
就是…..心情不好的時候,絕對不要自殘身體….否則…..會更痛苦…..