1、C#使用Windows API時必須先使用DllImport來Include Library,主要使用下列15個網路相關的API:
1-01、int WSAStartup(ushort wVersionrequested,ref WSDATA lpWSAData)
一 使用Windows Socket必須成功的調用此函式,才可以完成其他一系列的初始化。
1-02、int sock(int af,int type,int protocol) 一 建立一個具體傳輸服務的Socket。
1-03、int WSAGetLastError() 一 擷取使用Windows Socket函式失敗時的錯誤訊息。
1-04、IntPtr gethostbyname(IntPtr name)
一 傳入DNS名稱透過DNS Server取得Host端的網路位址和其他資訊。
一 一個DNS名稱可能不只對應一個網路位址,但一個網路位址只可以對應一個DNS名稱。
1-05、IntPtr gethostbyaddr(ref uint addr, int type,int len) 一 同上,但是使用網路位址來取得資訊。
1-06、int gethostname(IntPtr name,int namelen) 一 取得本機的網路名稱。
1-07、uint inet_addr(Intptr cp) 一 將帶有dot的字串IP轉換成網路格式(big-endian)的uint。
1-08、string inet_ntoa(uint sin_addr) 一 將網路格式(big-endian)的ushort轉換成帶有dot的字串IP。
1-09、ushort htons(ushort hostshort) 一 將ushort 轉換成網路格式(big-endia)的ushort。
1-10、int setsockopt(int s,int level,int optname,IntPtr optval,int optlen)
一 設定Socket 選項的函式。
Ex. send/receive timeout or 設定IP_HDRINCL 由應用程式產生IP Header。
1-11、int sendto(int s,IntPtr buf,int len,int flags,ref SOCKADDR_IN to,int tolen)
一 傳送資料至Host端,常用於UDP協定。
1-12、int select(int nfds,IntPtr readfds,IntPtr writefds,IntPtr exceptfds,ref timeval timeout)
一 檢查指定的Socket是否有接收到資料或是否可以傳送資料。
1-13、int recvfrom(int s,IntPtr buf,int len,int flags,IntPtr from,ref int fromlen)
一 擷取由Host回傳的訊息,常用於接收UDP協定。
1-14、int closesocket(int s) 一 關閉指定的Socket。
1-15、int WSACleanup() 一 終止使用Windows Socket 2 DLL (to close WSAStartup)
二、實作Ping和Trace功能時,在成功的調用WAStartup函式之後;由於必須讀取網路封包的標頭(Header)
資訊,因此必須使用SOCK_RAW即原始的SOCKET,來取得相關協定的標頭(Header)。
設定方式如下:
Ex. openSocket = socket(AF_INET,SOCK_RAW,protocol)
AF_INET:設定使用IPv4(Inter Protocol Version 4) PS. IPv6是使用AF_INET6
SOCK_RAW:接收/傳送包含IP Header 和 UDP/TCP/ICMP Header
protocol:設定接收/傳送封包的傳送協定。
PS. 由於使用SOCK_RAW程式必須有管理人權限,因此可以執行下列的步驟。
系統將會自動詢問(Vista) 是否以管理人權限來執行。
1. 在專案目錄下建立manifest File內容如下。
Ex. .../PingTrace/PringTrace/PingTrace.manifest
<?xml version="1.0" encoding="utf-8" ?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="X86"
name="someExecName"
type="win32" />
<description>Your Program Description</description>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" /> <==主要在這一行
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
2. Project -> Properties
三、實作Ping函式主要是對Host端傳送ICMP封包,當Host端接收後則會回覆ICMP封包。
如果無法抵達Host端,則會由連線中的某路由器返回'ICMP_DESTUNREACH'錯誤訊息,
但如果Host端已經關機或Host端設定對ICMP不做回應是則必須自行設定超時的功能。
實作Ping函式主要有下列五個步驟:
3.1、對建立的socket使用setsockopt函式設定SO_RCVTIMEO/SO_SNDTIMEO
參數來完成timeout的功能。
3.2、建立ICMP封包.
3.2.1、先建立ICMP Header 並將Type Field 設為ICMP_ECHO。
PS. 其他有關ICMP Header設定可參考Internet Control Message Protocol 。
3.2.2、計算ICMP Checksum值,公式如下:
1. 首先將ICMP Header中的Checksum設定零。
2. 以Word為單位(2byte),累加所有ICMP Package的資料。
3. 將累加後所得的值,分成高位元組(High Byte)和低位元組(Low Byte)再將兩位元組相加。
4. 若兩位元組相加後,產生溢位(overflow)則必須再將溢位值回加至該位元組。
5. 最後所得的位元組取1's Complment(補數),即為該ICMP封包的Checksum。
3.3、設定SOCKADDR_IN structure和使用sendto函式傳送ICMP封包。
3.4、使用recvfrom接收ICMP封包並進行分析,回傳的資料中是包含IP Header的資訊。
分析判斷條件如下:
1. 判斷回傳封包是否大於等28 Bytes [ IP Header (20 bytes) + ICMP Header (8 bytes) ]。
2. 檢查ICMP Header中的Identifier,確認回傳的封包是否是回應給這個應用程式。
PS. 有可能其他的應用程式也在傳送ICMP封包。
3. 檢查ICMP Header中的Type是否為ICMP_ECHOREPLY。
3.5、計算回應時間,從傳送到接收的時間差並除2(來回的時間)。
四、實作Trace函式可以使用UDP或ICMP協定來完成;不管是用UDP或ICMP都是使用相同的原理
來完成Trace的功能不同的只是傳送的封包不同而已。 實作Trace函式的原理是調整對HOST端
所發出封包的TTL(存活時間)值,來得到封包傳遞的路徑。
使用ICMP實作Trace函式主要有下列六個步驟:
4.1.1、對建立的socket使用setsockopt函式設定SO_RCVTIMEO/SO_SNDTIMEO
參數來完成timeout的功能。
4.1.2、建立ICMP封包.
4.1.2.1、先建立ICMP Header 並將Type Field 設為ICMP_ECHO。
PS. 其他有關ICMP Header設定可參考Internet Control Message Protocol 。
4.1.2.2、計算ICMP Checksum值,公式如下:
1. 首先將ICMP Header中的Checksum設定零。
2. 以Word為單位(2byte),累加所有ICMP Package的資料。
3. 將累加後所得的值,分成高位元組(High Byte)和低位元組(Low Byte)再將兩位元組相加。
4. 若兩位元組相加後,產生溢位(overflow)則必須再將溢位值回加至該位元組。
5. 最後所得的位元組取1's Complment(補數),即為該ICMP封包的Checksum。
4.1.3、對建立的Socket使用setsockopt函式設定IP_TTL參數。
4.1.4、設定SOCKADDR_IN structure和使用sendto函式傳送ICMP封包。
4.1.5、使用recvfrom接收ICMP封包並進行分析,回傳的資料中是包含IP Header的資訊。
分析判斷條件如下:
1. 判斷回傳封包是否大於等28 Bytes [ IP Header (20 bytes) + ICMP Header (8 bytes) ]。
2. 檢查ICMP Header中的Identifier,確認回傳的封包是否是回應給這個應用程式。
PS. 有可能其他的應用程式也在傳送ICMP封包。
3. 檢查ICMP Header中的Type是否為ICMP_ECHOREPLY; 若不是則將TTL值加一
再重新傳送ICMP封包。
4.1.6、計算回應時間,從傳送到接收的時間差並除2(來回的時間)。
使用UDP實作Trace函式主要有下列七個步驟:
4.2.1、對建立的socket使用setsockopt函式設定IP_HDRINCL參數,
告知socket由應用程式自行提供IP Header。
4.2.2、建立IP Header和UDP封包。
4.2.2.1、首先必須先建立並設定IP Header的資料,每當要延長TTL值時必須在
IP Header中的TTL Field進行修改。
4.2.2.2、建立並設定UDP Header的資料。
4.2.2.3、計算UDP的Checksum,計算步驟如下:
1. 建立並設定Pseudo Header,但只用於計算UDP Package的Checksum。
實際上傳送的封包並不包含Pseudo Header,排列順序如下:
---------------------------------------------------------------
| Pseudo Header | UDP Header | UDP DATA |
---------------------------------------------------------------
|----- 12 Bytes -----|---- 8 Bytes ----|
2. 以Word為單位(2byte),累加所有Pseudo Header和UDP Package的資料。
3. 將累加後所得的值,分成高位元組(High Byte)和低位元組(Low Byte)再將兩位元組相加。
4. 若兩位元組相加後,產生溢位(overflow)則必須再將溢位值回加至該位元組。
5. 最後所得的位元組取1's Complment(補數),即為該UDP封包的Checksum。
PS. 1 有關IP Header的設定可參考Internet Protocol 。
2 有關UDP Header的設定可參考User Datagram Protocol。
3 有關Pesudo Header的設定可參考Pseudo Header 。
4.2.3、設定SOCKADDR_IN structure和使用sendto函式傳送包含IP Header的UDP封包。
4.2.4、使用select函式來設定timeout的功能。
4.2.5、使用recvfrom接收ICMP封包並進行分析,回傳的資料中是包含IP Header的資訊。
分析判斷條件如下:
1. 判斷IP Header中的Protocol Field是否為IPPROTO_ICMP。
2. 判斷IP Header中的Soruce Address Field是否與Destination Address相同。
3. 判斷ICMP Header中Type Field是否為ICMP_DESTUNREACH,若是則表示找不到Host端
4. 如果2,3項皆否, 則將TTL值加一再重新傳送UDP封包。
4.2.6、計算回應時間,從傳送到接收的時間差並除2(來回的時間)。
Download : PingTrace (Source Code) PingTrace(EXE)
Result :
Ping Result-
ICMP Trace Result-
UDP Trace Result-