python如何實時獲取tcpdump輸出
阿新 • • 發佈:2020-09-17
一、背景
今天有個小需求,要確認客戶端有沒有往服務端傳送udp包,但為了減輕工作量,不想每次到機器上手動執行tcpdump抓包命令。
於是就寫了個指令碼來釋放人力。
二、程式碼實現
整個指令碼我還加了一些其他功能:時間戳、傳送端IP提取,資料包分析,資料持久化等。這裡都先去掉,僅記錄下簡單的實時獲取tcpdump輸出功能。
程式碼如下:
# -*- coding: utf-8 -*- # !/usr/bin/env python # sudo tcpdump -tt -l -nn -c 5 -i enp4s0 udp port 514 or 51414 import subprocess cmd = ['sudo','tcpdump','-tt','-l','-nn','-c','5','-i','enp4s0','udp','port','514','or','51414'] proc = subprocess.Popen(cmd,stdout=subprocess.PIPE) while True: line = proc.stdout.readline() line = line.strip() if not line: print('tcpdump finished...') break print(line)
輸出如下(實時):
wenyuanblog@localhost:/home/test/script# python tcpdump_udp.py tcpdump: verbose output suppressed,use -v or -vv for full protocol decode listening on enp4s0,link-type EN10MB (Ethernet),capture size 262144 bytes 1499774951.124178 IP 192.168.10.210.41974 > 192.168.10.251.514: UDP,length 139 1499774953.125664 IP 192.168.10.210.54995 > 192.168.10.251.51414: UDP,length 139 1499774956.128498 IP 192.168.10.210.56748 > 192.168.10.251.514: UDP,length 139 1499774958.129918 IP 192.168.10.210.53883 > 192.168.10.251.51414: UDP,length 139 1499774961.132921 IP 192.168.10.210.58803 > 192.168.10.251.514: UDP,length 139 5 packets captured 6 packets received by filter 0 packets dropped by kernel tcpdump finished...
以上程式碼相當於手動執行了 sudo tcpdump -tt -l -nn -c 5 -i enp4s0 udp port 514 or 51414
這條命令。
注意引數-l很重要(行顯)。
三、程式碼實現(更新)
上面的程式碼能實現tcpdump的功能,但是有一個問題:沒有做超時保護。即當程式執行時間過長時kill該程序(這裡使用ctrl+c的方式)。
要實現這個功能有很多種方案,例如定時器+多執行緒等,這裡僅演示一種方案,程式碼如下:
# -*- coding: utf-8 -*- # !/usr/bin/env python # sudo tcpdump -tt -l -nn -c 50 -i enp4s0 udp port 514 or 51414 import subprocess import signal import time import os import re import json class CmdServer: def __init__(self,cmd,timeout=120): ''' :param cmd: 執行命令(列表形式) :param timeout: 任務超時時間(seconds,程序執行超過該時間,kill該程序) :param taskname: 任務名稱(根據該任務名稱記錄命令輸出資訊) ''' self.cmd = cmd self.timeout = timeout self.base_path = reduce(lambda x,y: os.path.dirname(x),range(1),os.path.abspath(__file__)) self.output_path = os.path.join(self.base_path,'data.json') self.udp_flow_list = [] self.begin_time = int(time.time()) # 執行tcpdump任務 def run(self): if os.path.exists(self.output_path): with open(self.output_path,'r') as f: self.udp_flow_list = json.load(f) proc = subprocess.Popen(self.cmd,stdout=subprocess.PIPE) stdout = '' while proc.poll() == None: current_time = int(time.time()) if current_time - self.begin_time >= self.timeout: print('tcpdump timeout...') proc.send_signal(signal.SIGINT) stdout = proc.stdout.read() if proc.poll() is not None and not stdout: print('tcpdump finished...') stdout = proc.stdout.read() stdout_list = stdout.split('\n') if stdout_list: self._merge_data(stdout_list) self._save_data() # 資料合併(新增/更新) def _merge_data(self,stdout_list): for line in stdout_list: line = line.strip() if not line: continue timestamp = int(float(line.split('IP')[0].strip())) * 1000 # 源 src_ip_port_list = re.findall(r'IP(.+?)>',line) if not src_ip_port_list: continue src_ip_port_str = src_ip_port_list[0].strip() src_ip = '.'.join(src_ip_port_str.split('.')[0:4]) # 目的 dst_ip_port_list = re.findall(r'>(.+?):',line) if not dst_ip_port_list: continue dst_ip_port_str = dst_ip_port_list[0].strip() dst_port = dst_ip_port_str.split('.')[-1] # 新增/更新latest_timestamp src_item = filter(lambda x: src_ip == x['src_ip'],self.udp_flow_list) if src_item: src_item[0]['dst_port'] = dst_port src_item[0]['latest_timestamp'] = timestamp else: self.udp_flow_list.append(dict( src_ip=src_ip,dst_port=dst_port,latest_timestamp=timestamp )) # 儲存資料 def _save_data(self): # 寫入檔案 with open(self.output_path,'w') as f: json.dump(self.udp_flow_list,f,encoding="utf-8",ensure_ascii=False) if __name__ == '__main__': cmd = ['sudo','51414'] cmd_server = CmdServer(cmd,10) cmd_server.run()
四、總結
比較簡單,僅僅是記錄下。
以上就是python如何實時獲取tcpdump輸出的詳細內容,更多關於python獲取tcpdump輸出的資料請關注我們其它相關文章!