本文示範如何使用 Winsock 2 在指定 IP 上監聽 TCP Port 80,並利用 SO_REUSEADDR 選項繫結已被佔用的埠口,將連線轉發至本機真正的服務(如 127.0.0.1:80),達到透明 Proxy/流量分析的效果。
WSAStartup(MAKEWORD(2,2), &wsaData)。socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)。TIME_WAIT 或被其他處理序監聽的埠口(需管理員權限)。INADDR_ANY)與 Port 80。accept 取得客戶端 Socket,建立工作執行緒 ClientThread 處理。127.0.0.1:80,雙向 recv/send 並記錄流量至 port80log.txt。
// 主監聽迴圈
while (1) {
caddsize = sizeof(scaddr);
sc = accept(s, (sockaddr*)&scaddr, &caddsize);
if (sc != INVALID_SOCKET) {
HANDLE hThread = CreateThread(NULL, 0, ClientThread, (LPVOID)sc, 0, &tid);
if (hThread) CloseHandle(hThread);
}
}
// ClientThread:雙向轉發並記錄
DWORD WINAPI ClientThread(LPVOID lpParam)
{
SOCKET ss = (SOCKET)lpParam;
SOCKET sc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in srv = { AF_INET, htons(80), inet_addr("127.0.0.1") };
connect(sc, (sockaddr*)&srv, sizeof(srv));
// 設定接收逾時 100ms 避免阻塞
DWORD timeout = 100;
setsockopt(ss, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
setsockopt(sc, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
ofstream log("port80log.txt", ios::app);
char buf[4096];
while (1) {
int n = recv(ss, buf, sizeof(buf), 0);
if (n > 0) { log << " == DATA == " << string(buf, n); send(sc, buf, n, 0); }
else if (n == 0) break;
n = recv(sc, buf, sizeof(buf), 0);
if (n > 0) { log << " == DATA == " << string(buf, n); send(ss, buf, n, 0); }
else if (n == 0) break;
}
log.close();
closesocket(ss); closesocket(sc);
return 0;
}
bind 成功即使埠口處於 TIME_WAIT 或已被其他 Socket 監聽(需同屬同一使用者/權限)。若設定 SO_EXCLUSIVEADDRUSE 則會阻止重複繫結。recv 後寫入檔案,可作為 HTTP 封包分析、入侵偵測的基礎資料。透過 SO_REUSEADDR、多執行緒轉發與流量記錄,可快速建立一個 TCP 透明 Proxy 原型。理解此機制有助於網路程式除錯、協定逆向工程與安全審計,但務必遵守法律法規與使用者隱私權。