Wireshark有抓包功能,可以用于流量分析,但是用于某些特殊場合則不具有靈便性蚪腋,這里我們參考了《Python黑帽子編程》這本書耸棒,并改進(jìn)了他荒澡,用于實現(xiàn)一個高性能的TCP代理
基本原理
作為一個代理(參考BurpSuite),基本的思路應(yīng)該是:
1.接收客戶端的數(shù)據(jù)与殃,處理和編輯单山,發(fā)送給服務(wù)端
2.接收服務(wù)器的數(shù)據(jù),處理和編輯幅疼,發(fā)送給客戶端
基本的TCP連接示例如下
##Todo: add
異步TCP
TCP會話過程中米奸,隨時可能接收到數(shù)據(jù),為了提高代理性能爽篷,我們使用異步模式悴晰,該過程中使用epoll(僅限Linux系統(tǒng))功能(Select也可以)來提高整個代理的性能
epoll用法如下:
import select
epoll = select.epoll()
epoll.register(file_number,select.EPOLLIN)
epoll.register(file_number,select.EPOLLOUT)
##設(shè)置相關(guān)file_number為非阻塞
....
events = epoll.poll(TIMEOUT)
#events為一個List[],成員為tuple(),其數(shù)據(jù)為(file_number,event)
多線程
客戶端的連接可能不止一個逐工,我們需要使用多線程來操作
核心代碼 - 代理handler
###參數(shù)分別為客戶端連接的socket,要連接的遠(yuǎn)程服務(wù)器host和port
def proxy_handler(client_socket,remote_host,remote_port):
MAXLENGTH = 4096
TIMEOUT = 300
##和遠(yuǎn)程服務(wù)器建立連接
remote_socket= socket.socket(socket.AF_INET,socket.SOCK_STREAM)
remote_socket.connect((remote_host,remote_port))
epoll = select.epoll()
epoll.register(client_socket.fileno(),select.EPOLLIN)
epoll.register(remote_socket.fileno(),select.EPOLLIN)
###向系統(tǒng)注冊epoll事件铡溪,事件為:文件有數(shù)據(jù)傳入
remote_socket.setblocking(False)
client_socket.setblocking(False)
###設(shè)置非阻塞Socket
flag_loop = True
while flag_loop:
# 查詢epoll時間
events = epoll.poll(TIMEOUT)
if not events:
##返回為空表明連接崩潰,退出循環(huán)
break
###解析相應(yīng)的事件
for fd, status in events:
# 客戶端 >> 服務(wù)器
if fd == client_socket.fileno():
msg = client_socket.recv(MAXLENGTH)
if not msg:
# Connection closed
flag_loop = False
break
print("[*] Received %d bytes from the client" % (len(msg)))
##request_handler和下面的response_handler用來審查和修改中間經(jīng)過的數(shù)據(jù)
msg = request_handler(msg)
remote_socket.send(msg)
print("[*] Send %d bytes to the remote" % (len(msg)))
# 服務(wù)器 >> 客戶端
elif fd == remote_socket.fileno():
msg = remote_socket.recv(MAXLENGTH)
if not msg:
# Connection closed
flag_loop = False
break
print("[*] Received %d bytes from the remote" % (len(msg)))
msg = response_handler(msg)
client_socket.send(msg)
print("[*] Send %d bytes to the client" % (len(msg)))
remote_socket.close()
client_socket.close()
print("[*] Connection closed")
則接下來考慮輸入多線程