dpkt Tutorial #4: AS Paths from MRT/BGP
之前,我们着手用dpkt框架创造ICMP echo请求、解析PCAP文件和做了DNS欺骗。今天我会展示如何解析把MRT路由转储的BGP(边际网关协议)信息的自治系统路径解析出来。
解析BGP路由信息很有趣。然而,在类似Routeviews项目到处都是之前,获取一个因特网全局观事实上近乎不可能。但是感谢RouteViews,我们可以从MRT转储中,从许多提供者的观点中提取出有用的信息。
今天我们的例子是,我们会在从MRT转储里的BGP更新信息中解析出自治系统路径。或许你对在源地址和目的地址之间穿过多少AS(自治系统)跳数感兴趣。也许你会推断在路径中基于ASN的ISP对等关系。又或许你会尝试确认表明错误配置或恶意活动的匿名AS路径。不管哪种情况,我们会展示dpkt如何使解析变得简单。
BGP模块是dpkt库的模块(多达800行)中最复杂最难以理解的。它支持BGP RFC核心协议格式,同样也支持BGP协议的扩展8RFCs。在dpkt库BGP模块顶部,我们导入了pybgpdump库(实际上我并没有找到,应该是作者改版了,日了狗了),它通过一个MRT转储抽象出一些迭代格式。
在我们开始之前,我们需要一个MRT转储样本。一个来源于分布在pybgpdump库的有效样本。
Pybgpdump定了一个叫做BGPDump的类,它接受一个文件作为参数(如pybgpdump.py中所见)。BGPDump可以显式处理gzip,bzip压缩或者是未压缩过的MRT转储。一个BGPDump类实例能被迭代出转储中每个MRT记录。如果MRT记录被定为BGP4类型,过程中它将被交给用户。
例如,一个简单的计算在MRT转储中的BGP信息大小的代码片段:
cnt = 0
dump = pybgpdump.BGPDump('sample.dump.gz')
for mrt_h, bgp_h, bgp_m in dump:
cnt += 1
print cnt, 'BGP messages in the MRT dump'
然而,我们的教程是想打印出每个BGP更新信息的AS路径。所以,我们会探究bgp_m对象(一个在bgp.py中的BGP类的实例),而不是在我们的循环中增加一个计数器。一个BGP实例包含了一些其他属性(len,type等等)和一些数据属性,它是一个包括Open、Update、Notification、Keepalive和 RouteRefresh 类(根据消息类型)的实例。因为pybgpdump仅仅会传递给我们更新信息,所以我们知道bgp_m.data是Update类的一个实例。
BGP中的更新信息包含了NLRI (network layer reachability information,网络层可达性信息)、路由的脱离和声明(也就是离开和加入)信息。除此之外,他们包含了各种特别的关于更新信息附加信息的属性。这些属性之一就是AS路径,AS路径是由不同类型的部分组成。为了准确地访问AS路径信息,我们必须深入到达bgp_m对象:
bgp_m: instance of BGP
.type: type of BGP message
.len: length of BGP message
.update/.data: instance of Update()
.withdrawn: list of withdrawn routes
.announced: list of announced routes
.attributes: list of instances of Attribute
.flags: attribute flags
.type: attribute type
.data/.as_path: instance of ASPath
.segments: list of instances of ASPathSegment
.type: type of path segment (set, sequence, confed)
.len: number of ASNs in the segment
.data/.path: list of ASN integers in the segment
尽管从对象体系看起来就让人抓狂时,但访问AS路径的代码是十分的简单:
dump = BGPDump('sample.dump.gz')
for mrt_h, bgp_h, bgp_m in dump:
for attr in bgp_m.update.attributes:
if attr.type == bgp.AS_PATH:
print path_to_str(attr.as_path)
break
我们简单的循环更新信息的属性,直到找到AS路径属性。然而,如对象体系所见,attr.as_path仍然是需要被解码的一列片段。我们使用path_to_str()函数以标准的AS路径格式(标识集,序列,联盟聚合)打印好那一列片段-:
DELIMS = ( ('', ''), ('{', '}'),# AS_SET ('', ''),# AS_SEQUENCE ('(', ')'), # AS_CONFED_SEQUENCE ('[', ']') )
# AS_CONFED_SET
def path_to_str(path):
str = ''
for seg in path.segments:
str += DELIMS[seg.type][0]
for AS in seg.path:
str += '%d ' % (AS) str = str[:-1]
str += DELIMS[seg.type][1] + ' '
return str
最后把所有的都综合在一起,我们仅仅只用几行代码就可以成功地从MRT转储的表中的BGP更新提取出AS路径了:
jonojono@dionysus ~/pybgpdump/samples $ python aspath.py
3333 1103 3549 4755
3333 286 6762 17557
3333 1103 3549 8866 39163
3333 1103 3549 6762 17557
...
整个教程的完整源代码都在一下链接可获得:
http://pybgpdump.googlecode.com/svn/trunk/samples/aspath.py