<s> """<STR_LIT>""" <EOL> from __future__ import print_function , division <EOL> from socket import inet_ntoa , inet_aton , inet_ntop , AF_INET , AF_INET6 <EOL> from struct import unpack , pack <EOL> from time import time , asctime <EOL> from sys import stderr , version_info <EOL> try : <EOL> from collections import OrderedDict <EOL> except : <EOL> from ordereddict import OrderedDict <EOL> IS_PYTHON2 = ( version_info [ <NUM_LIT:0> ] == <NUM_LIT:2> ) <EOL> def parse_mrt_file ( mrt_file , print_progress = False , debug_break_after = None ) : <EOL> """<STR_LIT>""" <EOL> results = OrderedDict ( ) <EOL> n , stime = <NUM_LIT:0> , time ( ) <EOL> while True : <EOL> mrt = MrtRecord . next_dump_table_record ( mrt_file ) <EOL> if not mrt : <EOL> break <EOL> if not mrt . table : <EOL> if print_progress : <EOL> print ( '<STR_LIT>' % mrt ) <EOL> continue <EOL> if mrt . prefix not in results : <EOL> try : <EOL> origin = mrt . as_path . origin_as <EOL> results [ mrt . prefix ] = origin <EOL> except : <EOL> print ( "<STR_LIT>" % ( mrt . prefix ) , file = stderr ) <EOL> raise <EOL> else : <EOL> assert mrt . type == mrt . TYPE_TABLE_DUMP <EOL> n += <NUM_LIT:1> <EOL> if debug_break_after and n > debug_break_after : <EOL> break <EOL> if print_progress and n % ( <NUM_LIT> if mrt . type == mrt . TYPE_TABLE_DUMP_V2 else <NUM_LIT> ) == <NUM_LIT:0> : <EOL> print ( '<STR_LIT>' % ( n , time ( ) - stime ) , file = stderr ) <EOL> if '<STR_LIT>' in results : <EOL> del results [ '<STR_LIT>' ] <EOL> if '<STR_LIT>' in results : <EOL> del results [ '<STR_LIT>' ] <EOL> return results <EOL> def dump_prefixes_to_text_file ( ipasn_data , out_text_file_name , orig_mrt_name , debug_write_sets = False ) : <EOL> if IS_PYTHON2 : <EOL> fw = open ( out_text_file_name , '<STR_LIT>' ) <EOL> else : <EOL> fw = open ( out_text_file_name , '<STR_LIT>' , encoding = '<STR_LIT>' ) <EOL> fw . write ( '<STR_LIT>' % orig_mrt_name ) <EOL> n4 , n6 = <NUM_LIT:0> , <NUM_LIT:0> <EOL> for prefix , origin in ipasn_data . items ( ) : <EOL> n6 += <NUM_LIT:1> if '<STR_LIT::>' in prefix else <NUM_LIT:0> <EOL> n4 += <NUM_LIT:0> if '<STR_LIT::>' in prefix else <NUM_LIT:1> <EOL> assert n4 + n6 == len ( ipasn_data ) <EOL> fw . write ( '<STR_LIT>' % ( asctime ( ) , n4 , n6 ) ) <EOL> for prefix , origin in ipasn_data . items ( ) : <EOL> if not debug_write_sets and isinstance ( origin , set ) : <EOL> origin = list ( origin ) [ <NUM_LIT:0> ] <EOL> fw . write ( '<STR_LIT>' % ( prefix , origin ) ) <EOL> fw . close ( ) <EOL> def dump_prefixes_to_binary_file ( ipasn_data , out_bin_file_name , orig_mrt_name , extra_comments = "<STR_LIT>" ) : <EOL> fw = open ( out_bin_file_name , '<STR_LIT:wb>' ) <EOL> fw . write ( b'<STR_LIT>' ) <EOL> fw . write ( b'<STR_LIT>' ) <EOL> fw . write ( pack ( '<STR_LIT:I>' , <NUM_LIT:0> ) ) <EOL> comments = "<STR_LIT>" % ( asctime ( ) , orig_mrt_name , extra_comments ) <EOL> if not IS_PYTHON2 : <EOL> comments = comments . encode ( '<STR_LIT>' , errors = '<STR_LIT:replace>' ) <EOL> comments = comments [ : <NUM_LIT> ] + b'<STR_LIT>' <EOL> fw . write ( pack ( '<STR_LIT:h>' , len ( comments ) ) ) <EOL> fw . write ( comments ) <EOL> n = <NUM_LIT:0> <EOL> for prefix , origin in ipasn_data . items ( ) : <EOL> if isinstance ( origin , set ) : <EOL> origin = list ( origin ) [ <NUM_LIT:0> ] <EOL> network , mask = prefix . split ( '<STR_LIT:/>' ) <EOL> assert '<STR_LIT::>' not in network <EOL> fw . write ( inet_aton ( network ) ) <EOL> fw . write ( pack ( '<STR_LIT:B>' , int ( mask ) ) ) <EOL> fw . write ( pack ( '<STR_LIT:I>' , origin ) ) <EOL> n += <NUM_LIT:1> <EOL> fw . write ( b'<STR_LIT>' * <NUM_LIT:9> ) <EOL> fw . seek ( <NUM_LIT:6> ) <EOL> fw . write ( pack ( '<STR_LIT:I>' , n ) ) <EOL> fw . close ( ) <EOL> def is_asn_bogus ( asn ) : <EOL> """<STR_LIT>""" <EOL> if <NUM_LIT> <= asn <= <NUM_LIT> or asn >= <NUM_LIT> : <EOL> return True <EOL> if asn >= <NUM_LIT> : <EOL> return True <EOL> return False <EOL> class MrtRecord : <EOL> """<STR_LIT>""" <EOL> TYPE_TABLE_DUMP = <NUM_LIT:12> <EOL> TYPE_TABLE_DUMP_V2 = <NUM_LIT> <EOL> T1_AFI_IPv4 = <NUM_LIT:1> <EOL> T1_AFI_IPv6 = <NUM_LIT:2> <EOL> T2_PEER_INDEX_TABLE = <NUM_LIT:1> <EOL> T2_RIB_IPV4_UNICAST = <NUM_LIT:2> <EOL> T2_RIB_IPV6_UNICAST = <NUM_LIT:4> <EOL> def __init__ ( self , header ) : <EOL> self . ts , self . type , self . sub_type , self . data_len = unpack ( '<STR_LIT>' , header ) <EOL> self . table = None <EOL> @ staticmethod <EOL> def next_dump_table_record ( f ) : <EOL> header_len = <NUM_LIT:12> <EOL> buf = f . read ( header_len ) <EOL> if not buf : <EOL> return None <EOL> mrt = MrtRecord ( buf ) <EOL> buf = f . read ( mrt . data_len ) <EOL> assert len ( buf ) == mrt . data_len <EOL> if mrt . type == MrtRecord . TYPE_TABLE_DUMP : <EOL> assert mrt . sub_type in ( MrtRecord . T1_AFI_IPv4 , MrtRecord . T1_AFI_IPv6 ) <EOL> mrt . table = MrtTableDump1 ( buf , mrt . sub_type ) <EOL> elif mrt . type == MrtRecord . TYPE_TABLE_DUMP_V2 : <EOL> assert mrt . sub_type in ( MrtRecord . T2_PEER_INDEX_TABLE , <EOL> MrtRecord . T2_RIB_IPV4_UNICAST , <EOL> MrtRecord . T2_RIB_IPV6_UNICAST ) <EOL> if mrt . sub_type in ( MrtRecord . T2_RIB_IPV4_UNICAST , MrtRecord . T2_RIB_IPV6_UNICAST ) : <EOL> mrt . table = MrtTableDump2 ( buf , mrt . sub_type ) <EOL> else : <EOL> raise Exception ( "<STR_LIT>" % mrt . type ) <EOL> return mrt <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( self . ts , self . type , self . sub_type , self . data_len , self . table_seq , self . prefix ) <EOL> @ property <EOL> def prefix ( self ) : <EOL> return self . table . s_prefix if self . table else None <EOL> @ property <EOL> def table_seq ( self ) : <EOL> return self . table . seq if self . table else None <EOL> @ property <EOL> def as_path ( self ) : <EOL> path = None <EOL> attrs = self . table . attrs if self . type == MrtRecord . TYPE_TABLE_DUMP else self . table . entries [ <NUM_LIT:0> ] . attrs <EOL> for a in attrs : <EOL> if a . bgp_type == BgpAttribute . ATTR_AS_PATH : <EOL> assert not path <EOL> path = a . path_detail ( ) <EOL> assert path <EOL> return path <EOL> class MrtTableDump1 : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , buf , sub_type1 ) : <EOL> assert sub_type1 == MrtRecord . T1_AFI_IPv4 <EOL> self . view , self . seq , prefix , mask , self . status , self . orig_ts , self . peer_ip , self . peer_as , self . attr_len = unpack ( '<STR_LIT>' , buf [ : <NUM_LIT> ] ) <EOL> self . s_prefix = "<STR_LIT>" % ( inet_ntoa ( pack ( '<STR_LIT>' , prefix ) ) , mask ) <EOL> assert self . view == <NUM_LIT:0> <EOL> self . _attrs = [ ] <EOL> self . _data_buf = buf <EOL> @ property <EOL> def attrs ( self ) : <EOL> if not self . _attrs : <EOL> buf = self . _data_buf [ <NUM_LIT> : ] <EOL> j = self . attr_len <EOL> while j > <NUM_LIT:0> : <EOL> a = BgpAttribute ( buf , is32 = False ) <EOL> self . _attrs . append ( a ) <EOL> buf = buf [ len ( a ) : ] <EOL> j -= len ( a ) <EOL> if a . bgp_type == BgpAttribute . ATTR_AS_PATH : <EOL> break <EOL> return self . _attrs <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( self . seq , self . s_prefix , self . attr_len , self . peer_as , self . orig_ts ) <EOL> class MrtTableDump2 : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , buf , sub_type2 ) : <EOL> assert sub_type2 in ( MrtRecord . T2_RIB_IPV4_UNICAST , MrtRecord . T2_RIB_IPV6_UNICAST ) <EOL> self . seq , mask = unpack ( '<STR_LIT>' , buf [ <NUM_LIT:0> : <NUM_LIT:5> ] ) <EOL> octets = ( mask + <NUM_LIT:7> ) // <NUM_LIT:8> <EOL> if sub_type2 == MrtRecord . T2_RIB_IPV4_UNICAST : <EOL> assert octets <= <NUM_LIT:4> <EOL> padding = bytes ( <NUM_LIT:4> - octets ) if not IS_PYTHON2 else '<STR_LIT>' * ( <NUM_LIT:4> - octets ) <EOL> s_prefix = inet_ntoa ( buf [ <NUM_LIT:5> : <NUM_LIT:5> + octets ] + padding ) <EOL> elif sub_type2 == MrtRecord . T2_RIB_IPV6_UNICAST : <EOL> assert octets <= <NUM_LIT:16> <EOL> padding = bytes ( <NUM_LIT:16> - octets ) if not IS_PYTHON2 else '<STR_LIT>' * ( <NUM_LIT:16> - octets ) <EOL> s_prefix = inet_ntop ( AF_INET6 , buf [ <NUM_LIT:5> : <NUM_LIT:5> + octets ] + padding ) <EOL> self . s_prefix = s_prefix + "<STR_LIT>" % mask <EOL> self . entry_count = unpack ( '<STR_LIT>' , buf [ <NUM_LIT:5> + octets : <NUM_LIT:7> + octets ] ) [ <NUM_LIT:0> ] <EOL> buf = buf [ <NUM_LIT:7> + octets : ] <EOL> self . entries = [ ] <EOL> for i in range ( self . entry_count ) : <EOL> e = self . T2RibEntry ( buf ) <EOL> self . entries . append ( e ) <EOL> break <EOL> buf = buf [ len ( e ) : ] <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( self . seq , self . s_prefix , len ( self . entries ) ) <EOL> class T2RibEntry : <EOL> def __init__ ( self , buf ) : <EOL> self . peer , self . orig_ts , self . attr_len = unpack ( '<STR_LIT>' , buf [ : <NUM_LIT:8> ] ) <EOL> self . _data = buf [ <NUM_LIT:8> : <NUM_LIT:8> + self . attr_len ] <EOL> self . _attrs = [ ] <EOL> @ property <EOL> def attrs ( self ) : <EOL> if not self . _attrs : <EOL> data = self . _data <EOL> j = self . attr_len <EOL> while j > <NUM_LIT:0> : <EOL> attr = BgpAttribute ( data , is32 = True ) <EOL> data = data [ len ( attr ) : ] <EOL> j -= len ( attr ) <EOL> self . _attrs . append ( attr ) <EOL> if attr . bgp_type == BgpAttribute . ATTR_AS_PATH : <EOL> break <EOL> return self . _attrs <EOL> def __len__ ( self ) : <EOL> return <NUM_LIT:8> + self . attr_len <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( self . attr_len , self . peer , self . orig_ts ) <EOL> class BgpAttribute : <EOL> ATTR_AS_PATH = <NUM_LIT:2> <EOL> def _has_ext_len ( self ) : <EOL> ext_len = ( self . flags >> <NUM_LIT:4> ) & <NUM_LIT> <EOL> return ext_len <EOL> def __init__ ( self , buf , is32 ) : <EOL> self . flags = buf [ <NUM_LIT:0> ] if not IS_PYTHON2 else ord ( buf [ <NUM_LIT:0> ] ) <EOL> self . bgp_type = buf [ <NUM_LIT:1> ] if not IS_PYTHON2 else ord ( buf [ <NUM_LIT:1> ] ) <EOL> self . _is32 = is32 <EOL> self . _detail = None <EOL> if self . _has_ext_len ( ) : <EOL> _len = unpack ( '<STR_LIT>' , buf [ <NUM_LIT:2> : <NUM_LIT:4> ] ) [ <NUM_LIT:0> ] <EOL> self . data = buf [ <NUM_LIT:4> : <NUM_LIT:4> + _len ] <EOL> else : <EOL> _len = buf [ <NUM_LIT:2> ] if not IS_PYTHON2 else ord ( buf [ <NUM_LIT:2> ] ) <EOL> self . data = buf [ <NUM_LIT:3> : <NUM_LIT:3> + _len ] <EOL> def __len__ ( self ) : <EOL> return <NUM_LIT:2> + ( <NUM_LIT:2> if self . _has_ext_len ( ) else <NUM_LIT:1> ) + len ( self . data ) <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( self . bgp_type , self . flags , len ( self . data ) ) <EOL> def path_detail ( self ) : <EOL> assert self . bgp_type == self . ATTR_AS_PATH <EOL> if not self . _detail : <EOL> self . _detail = self . BgpAttrASPath ( self . data , self . _is32 ) <EOL> return self . _detail <EOL> class BgpAttrASPath : <EOL> def __init__ ( self , buf , is32 ) : <EOL> self . pathsegs = [ ] <EOL> while buf : <EOL> seg = self . BgpPathSegment ( buf , is32 ) <EOL> buf = buf [ len ( seg ) : ] <EOL> self . pathsegs . append ( seg ) <EOL> def __repr__ ( self ) : <EOL> return "<STR_LIT>" % "<STR_LIT:U+002CU+0020>" . join ( str ( path ) for path in self . pathsegs ) <EOL> @ property <EOL> def origin_as ( self ) : <EOL> """<STR_LIT>""" <EOL> assert self . pathsegs [ <NUM_LIT:0> ] . seg_type == self . BgpPathSegment . AS_SEQUENCE <EOL> origin = None <EOL> for last_seg in reversed ( self . pathsegs ) : <EOL> if last_seg . seg_type == self . BgpPathSegment . AS_SEQUENCE : <EOL> for asn in reversed ( last_seg . path ) : <EOL> if not is_asn_bogus ( asn ) : <EOL> origin = int ( asn ) <EOL> break <EOL> elif last_seg . seg_type == self . BgpPathSegment . AS_SET : <EOL> origin = set ( asn for asn in last_seg . path if not is_asn_bogus ( asn ) ) <EOL> else : <EOL> raise Exception ( "<STR_LIT>" % last_seg . seg_type ) <EOL> if origin : <EOL> break <EOL> assert origin <EOL> return origin <EOL> class BgpPathSegment : <EOL> AS_SET = <NUM_LIT:1> <EOL> AS_SEQUENCE = <NUM_LIT:2> <EOL> AS_CONFED_SEQUENCE = <NUM_LIT:3> <EOL> AS_CONFED_SET = <NUM_LIT:4> <EOL> def __init__ ( self , data , is32 ) : <EOL> self . seg_type = data [ <NUM_LIT:0> ] if not IS_PYTHON2 else ord ( data [ <NUM_LIT:0> ] ) <EOL> cnt = data [ <NUM_LIT:1> ] if not IS_PYTHON2 else ord ( data [ <NUM_LIT:1> ] ) <EOL> data = data [ <NUM_LIT:2> : ] <EOL> assert self . seg_type in ( self . AS_SET , self . AS_SEQUENCE , self . AS_CONFED_SEQUENCE , self . AS_CONFED_SET ) <EOL> self . path = [ ] <EOL> self . as_len = <NUM_LIT:4> if is32 else <NUM_LIT:2> <EOL> for i in range ( cnt ) : <EOL> asn = unpack ( '<STR_LIT>' if is32 else '<STR_LIT>' , data [ : self . as_len ] ) [ <NUM_LIT:0> ] <EOL> data = data [ self . as_len : ] <EOL> self . path . append ( asn ) <EOL> def __len__ ( self ) : <EOL> return <NUM_LIT:2> + self . as_len * len ( self . path ) <EOL> def __str__ ( self ) : <EOL> assert self . seg_type in ( self . AS_SET , self . AS_SEQUENCE ) <EOL> s = '<STR_LIT>' if self . seg_type == self . AS_SEQUENCE else '<STR_LIT>' <EOL> s += str ( self . path ) <EOL> return s <EOL> def __repr__ ( self ) : <EOL> return "<STR_LIT>" + str ( self ) </s>
