您的位置:首页 > 编程语言 > Python开发

python抓包解包

2015-08-02 16:42 537 查看
背景

目的:使用keepalived,在使用过程中可能出现VRID冲突的情况,需要获知网络中正在使用的VRID。

VRRP协议的组播地址为224.0.0.18,通过tcpdumphost224.0.0.18可以抓到VRRP包。

[root@RCDhome]#tcpdumphost224.0.0.18
tcpdump:WARNING:eth0:noIPv4addressassigned
tcpdump:verboseoutputsuppressed,use-vor-vvforfullprotocoldecode
listeningoneth0,link-typeEN10MB(Ethernet),capturesize65535bytes
13:33:50.156553IP10.14.144.21>vrrp.mcast.net:VRRPv2,Advertisement,vrid25,prio100,authtypesimple,intvl1s,length20
13:33:50.157721IP172.18.144.8>vrrp.mcast.net:VRRPv2,Advertisement,vrid16,prio100,authtypesimple,intvl1s,length20


使用python实现的话,可借助pcap和dpkt包。

在搜索可用的包的时候,看到另外的推荐组合:socket和struct。dpkt的实现调用了struct。

安装包

安装pcap:

yuminstalllibpcap-devel

pipinstallpypcap

安装dpkt:

pipinstalldpkt

抓包&解包

抓包:

>>>importpcap
>>>multicast_addr="224.0.0.18"
>>>pc=pcap.pcap(name="br0")
>>>pc.setfilter("host%s"%multicast_addr)
>>>packet=pc.next()
>>>packet
(1438493759.2545481,<read-onlybufferptr0xe74df0,size60at0x7f77b23fa1f0>)


name--nameofanetworkinterfaceordumpfiletoopen,orNonetoopenthefirstavailableupinterface

setfilter(...)

|SetBPF-formatpacketcapturefilter.

packet[1]就是需要解析的包信息

解包:

>>>importdpkt
>>>ip_info=dpkt.ethernet.Ethernet(packet[1])
>>>ip_info
Ethernet(src='\x00\xe0L\x18\x03\x88',dst='\x01\x00^\x00\x00\x12',data=IP(src='\n\x0e\x90\x15',dst='\xe0\x00\x00\x12',tos=192,sum=5803,len=40,p=112,ttl=255,id=10693,data=VRRP(count=1,advtime=1,sum=32091,vrid=25,atype=1,priority=100)))
>>>len(ip_info.data.src)
4


在解析ip_info.data.src时一度走了弯路,使用chardet模块进行字符串编码检测,decode、encode瞎折腾了一通。

调用ord函数,可将ASCII码的字符或Hex转换为十进制值。

>>>ord(ip_info.data.src[0])
10
>>>ord(ip_info.data.src[1])
14
>>>ord(ip_info.data.src[2])
144
>>>ord(ip_info.data.src[3])
21


代码

importpcap
fromdpkt.ethernetimportEthernet
fromdpkt.dpktimportUnpackError
fromtimeimportsleep
deford_ip(ip):
return".".join((map(str,map(ord,list(ip)))))
defcollect_vrrp_info(interface=None):
multicast_addr="224.0.0.18"
pc=pcap.pcap(name=interface)
pc.setfilter("host%s"%multicast_addr)
sleep(5)
packets=pc.readpkts()
vrrp_map={}
forpinpackets:
try:
ip_info=Ethernet(p[1])
exceptUnpackErrorase:
logger.exception(e)
continue
src=ord_ip(ip_info.data.src)
vrid=ip_info.data.data.vrid
vrrp_map.setdefault(vrid,[])
ifsrcnotinvrrp_map[vrid]:
vrrp_map[vrid].append(src)
returnvrrp_map


chrunichrord

>>>help(chr)

Helponbuilt-infunctionchrinmodule__builtin__:
chr(...)
chr(i)->character
Returnastringofonecharacterwithordinali;0<=i<256.

>>>help(unichr)

Helponbuilt-infunctionunichrinmodule__builtin__:
unichr(...)
unichr(i)->Unicodecharacter
ReturnaUnicodestringofonecharacterwithordinali;0<=i<=0x10ffff.

>>>help(ord)

Helponbuilt-infunctionordinmodule__builtin__:
ord(...)
ord(c)->integer
Returntheintegerordinalofaone-characterstring.

>>>chr(255)
'\xff'
>>>ord('\xff')
255
>>>unichr(1024)
u'\u0400'
>>>ord('\u0400')
>>>ord(u'\u0400')
1024
>>>ord('a')
97


map

>>>help(map)

Helponbuilt-infunctionmapinmodule__builtin__:
map(...)
map(function,sequence[,sequence,...])->list
Returnalistoftheresultsofapplyingthefunctiontotheitemsof
theargumentsequence(s).Ifmorethanonesequenceisgiven,the
functioniscalledwithanargumentlistconsistingofthecorresponding
itemofeachsequence,substitutingNoneformissingvalueswhennotall
sequenceshavethesamelength.IfthefunctionisNone,returnalistof
theitemsofthesequence(oralistoftuplesifmorethanonesequence).

编码解码

字符串编码检测:

>>>importchardet
>>>chardet.detect(ip_info.data.src)
{'confidence':0.72999999999999998,'encoding':'windows-1252'}


chardet可以直接用detect函数来检测所给字符的编码。函数返回值为字典,有2个元数,一个是检测的可信度,另外一个就是检测到的编码。

unicode()

Unicode的工厂方法,通Unicode字符串操作符(u/U)的工作方式类似,接受一个string做参数,返回一个Unicode字符串。

decode()

接受一个字符串做参数,返回解码后的字符串。

encode()

接受一个字符串做参数,返回编码后的字符串。

起先是这么干的,然后就懵逼了。

>>>importchardet
>>>chardet.detect(ip_info.data.src)
{'confidence':0.72999999999999998,'encoding':'windows-1252'}
>>>ip_info.data.src.decode('windows-1252')
u'\xac\x12\x01\xd5'
>>>ip_info.data.src.decode('windows-1252').encode('utf-8')
'\xc2\xac\x12\x01\xc3\x95'
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: