我們知道許多應用程序,例如E-mail、Web和即時通信都依靠網絡才能實現。這些應用程序中的每一個都依賴一種特定的網絡協議,但每個協議都使用相同的常規網絡傳輸方法。許多人都沒有意識到網絡協議本身存在漏洞。本文將會學習如何使用套接字使應用程序訪問網絡以及如何處理常見的網絡漏洞。
1.套接字
套接字是通過操作系統(OS)完成網絡通信的一種標准方法。可以將套接字看作是與連接相連的一個終端,就像是操作員配電盤上的一個插座一樣。但是這些套接字只是程序員的抽象稱呼,它們負責有文描述的OSI模型的所有基本細節。對程序員來說,可以使用一個套接字通過網絡發送或接收數據。這些數據在較低的層(由操作系統處理)之上的會話層(5)傳輸,該層負責路由。有幾種不同的套接字,它們決定了傳輸層的結構。最常見的類型是流套接字和數據報套接字。
流套接字提供了可靠的雙向通信,這類似於您和他人打電話。一方向另一方發起連接,建立連接之後,任何一方都可以和另一方通信。此外,您所說的話實際上是否到達目的地能夠得到快速證實。流套接字使用一種稱為傳輸控制協議(Transmission Control Protocol,TCP)的標准通信協議,這個協議存在於OSI模型的傳輸層(4)。在計算機網絡上,數據通常以我們稱之為包的大數據塊的形式傳輸。TCP被設計為數據包按順序到達目的地並且無差錯,就像在電話中講話時,單詞以它們被說出的順序到達另一端一樣。Web服務器、郵件服務器以及它們各自的客戶應用程序都使用TCP和流套接字進行通信。
另一種常見的套接字類型是數據報套接字。使用數據報套接字通信更像是郵寄一封信而不是打電話。連接是單向的並且不可靠。如果您寄了幾封信,您將不能確定它們是否按照和郵寄時相同的順序到達目的地,甚至連能否被送達目的地也不能保證。郵政服務相當可靠,但Intemet並不可靠。數據報套接字在傳輸層(4)上使用另一種稱為UDP的標准協議來代替TCP。UDP代表用戶數據報協議(User Datagram Protocol),意味著可以用它來創建自定義協議。這個協議非常基本並且是輕量級的,它只內置了很少的保護措施。它並不是一種真正的連接,只是一種從一端向另一端發送數據的基本方法。使用數據報套接字時,協議中的系統開銷非常少,但協議完成的功能也不多。如果程序需要證實另一方接收到了數據包,必須編程使另一方回送一個確認包。有些情況下,可以接受數據包的丟失。數據報套接字和UDP普遍用於網絡游戲和流媒體,因為開發人員可以根據需要精確地修整他們的通信,而不會存在像TCP那樣的固有系統開銷。
2.套接字函數
在C語言中,套接字的行為類似於文件,因為它們使用文件描述符來標識它們自己。套接字的行為與文件非常相似,實際上利用套接字文件描述符,可以使用read()和write()函數接收和發送數據。但是,有幾個函數是專門設計用來處理套接字的。在/usr/include/sys/socket.h文件中有這些函數原型的定義。
extern int socket (int __domain, int __type, int __protocol) __THROW;
用於創建一個新套接字,返回一個表牙示套接字後的文件描述符,錯誤時遣返回-1。extern int connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);
將一個套接字(由文件描述符fd指定)連接到遠程主機。成功返回0,錯誤返回-1。
Listen(int fd,int backlog_queue_size)
偵聽傳入的連接並將連接請求排隊,:直到數量達到backlog_queue_size。成功返回0,錯誤返回-1。
extern int accept (int __fd, __SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len);
一個綁定的端口上接受一個傳入連接。遠程主機的地址信息寫入remote_host結構中,地址結構的實際大小寫入到addr_len中。這個函數返回一個新套接字文件描述符來標識已經連接的套接字,錯誤返回-1。
extern ssize_t send (int __fd, __const void *__buf, size_t __n, int __flags);
從*__buf向套接字fd發送n個字節,返回值為發送的字節數,錯誤返回-1。
extern ssize_t recv (int __fd, void *__buf, size_t __n, int __flags);
從套接字fd接收n個字節到*__buf中,返回值為收到的字節數,錯誤返回-1。
使用socket()函數創建套接字時,必須指定套接字的域(domain)、類型(type)和切協議( protocol)。域指的是套接字的協議族。套接字可以使用各種協議進行通信,從浏覽Web時使用的標准Internet協議到諸如AX.25,這樣的業余無線電協議(如果您是一個無線電發燒友)。這些協議族在bits/socket.h中定義,它自動包含在sys/socket.h中。
/usr/include/bits/socket.h 片段1
/* Protocol families. */
#define PF_UNSPEC 0 /* Unspecified. */
#define PF_LOCAL 1 /* Local to host (pipes and file-domain). */
#define PF_UNIX PF_LOCAL /* Old BSD name for PF_LOCAL. */
#define PF_FILE PF_LOCAL /* Another non-standard name for PF_LOCAL. */
#define PF_INET 2 /* IP protocol family. */
#define PF_AX25 3 /* Amateur Radio AX.25. */
#define PF_IPX 4 /* Novell Internet Protocol. */
#define PF_APPLETALK 5 /* Appletalk DDP. */
#define PF_NETROM 6 /* Amateur radio NetROM. */
#define PF_BRIDGE 7 /* Multiprotocol bridge. */
#define PF_ATMPVC 8 /* ATM PVCs. */
#define PF_X25 9 /* Reserved for X.25 project. */
#define PF_INET6 10 /* IP version 6. */
如前所述,雖然流套接霉字和數據報套接字最常使用,但還有其他幾種類型的套接字。套接字的類型也定義在bits/socket.h中(上面代碼中的/*comment*/是另一種形式的注釋,它將所有處於星號之間的內容作為注釋)。/usr/include/bits/socket.h 片段2
/* Types of sockets. */
enum __socket_type
{
SOCK_STREAM = 1, /* Sequenced, reliable, connection-based
byte streams. */
#define SOCK_STREAM SOCK_STREAM
SOCK_DGRAM = 2, /* Connectionless, unreliable datagrams
of fixed maximum length. */
#define SOCK_DGRAM SOCK_DGRAM