Python SIP日志文件处理
我有一个用Python的scapy生成的VoIP/SIP嗅探/日志文件,格式是这样的:
时间 | 源地址 | 源端口 | 目标地址 | 目标端口 | 数据内容
这个嗅探的Python脚本大概是这样的:
## Import Scapy module
from scapy.all import *
import sys
sys.stdout = open('data.txt', 'w')
pkts = sniff(filter="udp and port 5060 and not port 22", count=0,prn=lambda x:x.sprintf("%sent.time% | %IP.src% | %IP.sport% | %IP.dst% | %IP.dport% | Payload {Raw:%Raw.load%\n}"))
每个数据包占一行,而且每一行的大小可能不同,这取决于SIP消息的类型(比如注册、200 OK、邀请、通知等等……)
我想从这个文件中提取的字段有:时间、源地址、源端口、目标地址、目标端口
,还有数据内容
部分(就是在数据内容后面)中的
1st msg:
07:57:01.894990 | 192.168.1.10 | 5060 | 192.168.1.1 | 5060 | Payload 'INVITE sip:210@test-lab.org SIP/2.0\r\nVia:
SIP/2.0/UDP 192.168.1.10:5060;rport;branch=z9hG4bK-9cbb0ba8\r\nRoute: <sip:192.168.1.1:5060;lr>\r\nFrom: "test-311" <sip:311@test-lab.org>;tag=3d13bd6f\r\n
To: <sip:210@test-lab.org>\r\nCall-ID: 21b0e2c755973976d6d06702ca33b32f@10.193.40.249\r\nCSeq: 1 INVITE\r\n
Contact: "test-311" <sip:311@192.168.1.10:5060;transport=UDP>\r\nMax-Forwards: 70\r\n
Supported: 100rel,replaces\r\nAllow: ACK, BYE, CANCEL, INFO, INVITE, OPTIONS, NOTIFY, PRACK, REFER, UPDATE, MESSAGE\r\nContent-Type: application/sdp\r\nContent-Length: 276\r\n\r\nv=0\r\no=- 3506863524 285638052 IN IP4 192.168.1.10\r\ns=-\r\nc=IN IP4 192.168.1.10\r\nt=0 0\r\nm=audio 8000 RTP/AVP 8 0 18 101\r\nc=IN IP4 192.168.1.10\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:18 G729/8000\r\na=rtpmap:101 telephone-event/8000\r\na=fmtp:101 0-15\r\na=ptime:20\r\n'
2nd msg:
07:57:01.902618 | 192.168.1.1 | 5060 | 192.168.1.10 | 5060 | Payload 'SIP/2.0 100 Trying\r\nVia: SIP/2.0/UDP 192.168.1.10:5060;received=192.168.1.10;branch=z9hG4bK-9cbb0ba8;rport=5060\r\nFrom: "test-311" <sip:+38551311@test-lab.org>;tag=3d13bd6f\r\nTo: <sip:210@test-lab.org>\r\nCall-ID: 21b0e2c755973976d6d06702ca33b32f@192.168.1.10\r\nCSeq: 1 INVITE\r\n\r\n'
我尝试了一行一行地读取并拆分,但我不知道怎么从数据内容部分拆分和提取数据。
任何帮助都非常欢迎。
2 个回答
从scapy库中导入所有功能,这个库可以用来处理网络数据包。
接着,我们导入了MySQLdb库,这个库是用来和MySQL数据库进行交互的,还有一些其他的库,比如string和sys。
然后定义了一个叫做insert_into_mysql的函数,这个函数的作用是把捕获到的数据包插入到MySQL数据库中。这里使用了MySQLdb.connect来连接数据库,连接的参数包括数据库的地址(localhost表示本地)、用户名(test)、密码(testpwd)和数据库名称(my_db)。
cursor = db.cursor()
# now you can use packet.src, packet.sport, packet.dst, packet.dport,
# and packet['Raw'].load
add_sip = ("INSERT INTO py_sniff "
"(time, src_ip, src_port, dst_ip, dst_port, message) "
"VALUES (%s, %s, %s, %s, %s, %s)")
# data from sniff
add_sip = {
'time': packet.sprintf("%sent.time%"),
'src_ip': packet.sprintf("%IP.src%"),
'src_port': packet.sprintf("%IP.sport%"),
'dst_ip': packet.sprintf("%IP.dst%"),
'dst_port': packet.sprintf("%IP.dport%"),
'message': packet.sprintf("{Raw:%Raw.load%}"),
}
# to print the packet
# return packet.sprintf("%sent.time% | %IP.src% | %IP.sport% | %IP.dst% | %IP.dport% | Payload {Raw:%Raw.load%\n}"
cursor.execute(add_sip)
db.commit()
最后一行代码是用来捕获网络数据包的。它会在名为"eth0"的网络接口上监听,过滤条件是UDP协议和端口5060,count=0表示捕获无限个数据包,store=0表示不保存捕获的数据包,而prn=insert_into_mysql则是指每当捕获到一个数据包时,就调用insert_into_mysql这个函数来处理它。
其实,你可以直接通过这个程序把数据输入到mysql里,这可能是最简单的方法。
from scapy.all import *
import sys
# connect to mysql
connection = ...
def insert_into_mysql(packet):
# now you can use packet.src, packet.sport, packet.dst, packet.dport, and
# I believe packet['Raw'].load
connection.execute(...)
# to not print the packet
return None
# to print the packet
return x.sprintf("%sent.time% | %IP.src% | %IP.sport% | %IP.dst% | %IP.dport% | Payload {Raw:%Raw.load%\n}"
pkts = sniff(filter="udp and port 5060", count=0, store=0, prn=insert_into_mysql)
不过,如果你需要使用已有的日志,我觉得你需要用:
for line in open('log.txt'):
sent_time, src, sport, dst, dport, payload = line.split(' | ', 6)
payload = payload.replace('Payload ', '')
# to get the unquoted payload, I'd guess (can't test SIP though)
from ast import literal_eval
payload = literal_eval(payload)