def _header_body(self, header, body): header = ' header %s' % hexstring(header) if header else '' body = ' body %s' % hexstring(body) if body else '' total_string = header + body if body else header return total_string
def _header(self, content, header, body, neighbor, message_type=None): peer = '"host" : "%s", ' % socket.gethostname() pid = '"pid" : %s, ' % os.getpid() ppid = '"ppid" : %s, ' % os.getppid() counter = '"counter": %s, ' % self._counter( neighbor) if neighbor is not None else '' header = '"header": "%s", ' % hexstring(header) if header else '' body = '"body": "%s", ' % hexstring(body) if body else '' mtype = '"type": "%s", ' % message_type if message_type else 'default' return \ '{ '\ '"exabgp": "%s", '\ '"time": %s, ' \ '%s%s%s%s%s%s%s%s ' \ '}' % ( self.version, self.time(time.time()), peer, pid, ppid, counter, mtype, header, body, content )
def _header_body (self, header, body): header = ' header %s' % hexstring(header) if header else '' body = ' body %s' % hexstring(body) if body else '' total_string = header+body if body else header return total_string
def _header (self, content, header, body, neighbor,message_type=None): peer = '"host" : "%s", ' % socket.gethostname() pid = '"pid" : %s, ' % os.getpid() ppid = '"ppid" : %s, ' % os.getppid() counter = '"counter": %s, ' % self._counter(neighbor) if neighbor is not None else '' header = '"header": "%s", ' % hexstring(header) if header else '' body = '"body": "%s", ' % hexstring(body) if body else '' mtype = '"type": "%s", ' % message_type if message_type else 'default' return \ '{ '\ '"exabgp": "%s", '\ '"time": %s, ' \ '%s%s%s%s%s%s%s%s ' \ '}' % ( self.version, self.time(time.time()), peer, pid, ppid, counter, mtype, header, body, content )
def packets (self, neighbor, direction, category, header, body): return self._header(self._neighbor(neighbor,direction,self._kv({ 'message': '{ %s } ' % self._kv({ 'category': category, 'header': hexstring(header), 'body': hexstring(body), }) })),'','',neighbor,message_type=Message.string(category))
def __init__(self, code, subcode, data=b'', parse_data=True): self.code = code self.subcode = subcode if not parse_data: self.data = data return if not (code, subcode) in [(6, 2), (6, 4)]: self.data = data if not len([_ for _ in str(data) if _ not in string.printable]) else hexbytes(data) return if len(data) == 0: # shutdown without shutdown communication (the old fashioned way) self.data = b'' return # draft-ietf-idr-shutdown or the peer was using 6,2 with data shutdown_length = data[0] data = data[1:] if shutdown_length == 0: self.data = b"empty Shutdown Communication." # move offset past length field return if len(data) < shutdown_length: self.data = b"invalid Shutdown Communication (buffer underrun) length : %i [%s]" % ( shutdown_length, hexstring(data), ) return if shutdown_length > 128: self.data = b"invalid Shutdown Communication (too large) length : %i [%s]" % ( shutdown_length, hexstring(data), ) return try: self.data = b'Shutdown Communication: "%s"' % data[:shutdown_length].decode('utf-8').replace( '\r', ' ' ).replace('\n', ' ') except UnicodeDecodeError: self.data = b"invalid Shutdown Communication (invalid UTF-8) length : %i [%s]" % ( shutdown_length, hexstring(data), ) return trailer = data[shutdown_length:] if trailer: self.data += b", trailing data: " + hexstring(trailer)
def packets (self, neighbor, direction, category, negotiated, header, body): message = { 'message': '{ %s } ' % self._kv({ 'category': category, 'header': hexstring(header), 'body': hexstring(body), }) } if negotiated: message.update(self._negotiated(negotiated)) return self._header(self._neighbor(neighbor,direction,self._kv( message )),'','',neighbor,message_type=Message.string(category))
def packets (self, neighbor, direction, category, negotiated, header, body): message = { 'message': '{ %s } ' % self._kv({ 'category': category, 'header': hexstring(header), 'body': hexstring(body), }) } if negotiated: message.update(self._negotiated(negotiated)) return self._header(self._neighbor(neighbor,direction,self._kv( message )),'','',neighbor,message_type=Message.string(category))
def unpack(cls, data, length): # We only support IS-IS flags for now. flags = cls.unpack_flags(data[0:1]) # Parse adj weight weight = data[1] # Move pointer 4 bytes: Flags(1) + Weight(1) + Reserved(2) data = data[4:] # SID/Index/Label: according to the V and L flags, it contains # either: # * A 3 octet local label where the 20 rightmost bits are used for # encoding the label value. In this case the V and L flags MUST # be set. # # * A 4 octet index defining the offset in the SID/Label space # advertised by this router using the encodings defined in # Section 3.1. In this case V and L flags MUST be unset. sids = [] raw = [] while data: # Range Size: 3 octet value indicating the number of labels in # the range. if int(flags['V']) and int(flags['L']): sid = unpack('!L', bytes([0]) + data[:3])[0] data = data[3:] sids.append(sid) elif (not flags['V']) and (not flags['L']): sid = unpack('!I', data[:4])[0] data = data[4:] sids.append(sid) else: raw.append(hexstring(data)) break return cls(flags=flags, sids=sids, weight=weight, undecoded=raw)
def unpack_message(cls, data, negotiated): # pylint: disable=W0613 # This can not happen at decode time as we check the length of the KEEPALIVE message # But could happen when calling the function programmatically if data: raise Notify('Keepalive can not have any payload but contains %s', hexstring(data)) return cls()
def notification (self, neighbor, direction, message, header, body): return self._header(self._neighbor(neighbor,direction,self._kv({ 'notification': '{ %s } ' % self._kv({ 'code': message.code, 'subcode': message.subcode, 'data': hexstring(message.data), }) })),header,body,neighbor,message_type='notification')
def notification (self, neighbor, direction, message, negotiated, header, body): return self._header(self._neighbor(neighbor,direction,self._kv({ 'notification': '{ %s } ' % self._kv({ 'code': message.code, 'subcode': message.subcode, 'data': hexstring(message.data), }) })),header,body,neighbor,message_type='notification')
def notification(self, neighbor, direction, message, negotiated, header, body): return 'neighbor %s %s notification code %d subcode %d data %s%s\n' % ( neighbor['peer-address'], direction, message.code, message.subcode, hexstring(message.data), self._header_body(header, body), )
def notification (self, neighbor, direction, message, negotiated, header, body): return 'neighbor %s %s notification code %d subcode %d data %s%s\n' % ( neighbor.peer_address, direction, message.code, message.subcode, hexstring(message.data), self._header_body(header,body) )
def _str (self): t,c1,c2,c3 = unpack('!HHHH',self.rd) if t == 0: rd = '%d:%d' % (c1,(c2 << 16)+c3) elif t == 1: rd = '%d.%d.%d.%d:%d' % (c1 >> 8,c1 & 0xFF,c2 >> 8,c2 & 0xFF,c3) elif t == 2: rd = '%d:%d' % ((c1 << 16) + c2,c3) else: rd = hexstring(self.rd) return rd
def _str(self): t, c1, c2, c3 = unpack('!HHHH', self.rd) if t == 0: rd = '%d:%d' % (c1, (c2 << 16) + c3) elif t == 1: rd = '%d.%d.%d.%d:%d' % (c1 >> 8, c1 & 0xFF, c2 >> 8, c2 & 0xFF, c3) elif t == 2: rd = '%d:%d' % ((c1 << 16) + c2, c3) else: rd = hexstring(self.rd) return rd
def __init__ (self, code, subcode, data=b'', parse_data=True): self.code = code self.subcode = subcode if not parse_data: self.data = data return if not (code, subcode) in [(6, 2), (6, 4)]: self.data = data if not len([_ for _ in str(data) if _ not in string.printable]) else hexbytes(data) return if len(data) == 0: # shutdown without shutdown communication (the old fashioned way) self.data = b'' return # draft-ietf-idr-shutdown or the peer was using 6,2 with data shutdown_length = ordinal(data[0]) data = data[1:] if shutdown_length == 0: self.data = b"empty Shutdown Communication." # move offset past length field return if len(data) < shutdown_length: self.data = b"invalid Shutdown Communication (buffer underrun) length : %i [%s]" % (shutdown_length, hexstring(data)) return if shutdown_length > 128: self.data = b"invalid Shutdown Communication (too large) length : %i [%s]" % (shutdown_length, hexstring(data)) return try: self.data = b'Shutdown Communication: "%s"' % \ data[:shutdown_length].decode('utf-8').replace('\r',' ').replace('\n',' ') except UnicodeDecodeError: self.data = b"invalid Shutdown Communication (invalid UTF-8) length : %i [%s]" % (shutdown_length, hexstring(data)) return trailer = data[shutdown_length:] if trailer: self.data += b", trailing data: " + hexstring(trailer)
def unpack(cls, data, length): # We only support IS-IS flags for now. flags = LsGenericFlags.unpack(data[0:1], LsGenericFlags.ISIS_SR_FLAGS) # # Parse Algorithm sr_algo = six.indexbytes(data, 1) # Move pointer 4 bytes: Flags(1) + Algorithm(1) + Reserved(2) data = data[4:] # SID/Index/Label: according to the V and L flags, it contains # either: # * A 3 octet local label where the 20 rightmost bits are used for # encoding the label value. In this case the V and L flags MUST # be set. # # * A 4 octet index defining the offset in the SID/Label space # advertised by this router using the encodings defined in # Section 3.1. In this case V and L flags MUST be unset. sids = [] raw = [] while data: if flags.flags['V'] and flags.flags['L']: b = BitArray(bytes=data[:3]) sid = b.unpack('uintbe:24')[0] data = data[3:] sids.append(sid) elif (not flags.flags['V']) and \ (not flags.flags['L']): if len(data) != 4: # Cisco IOS XR Software, Version 6.1.1.19I is not # correctly setting the flags raise Notify( 3, 5, "SID/Label size doesn't match V and L flag state") sid = unpack('!I', data[:4])[0] data = data[4:] sids.append(sid) else: raw.append(hexstring(data)) break return cls(flags=flags, sids=sids, sr_algo=sr_algo, undecoded=raw)
def _from_json(self, direction, json_string): try: parsed = json.loads(json_string) except ValueError: print('invalid JSON message', file=sys.stderr) sys.exit(1) if parsed.get('exabgp', '0.0.0') != json_version: print('invalid json version', json_string, file=sys.stderr) sys.exit(1) content = parsed.get('type', '') if not content: print('invalid json content', json_string, file=sys.stderr) sys.exit(1) neighbor = _FakeNeighbor( parsed['neighbor']['address']['local'], parsed['neighbor']['address']['peer'], parsed['neighbor']['asn']['local'], parsed['neighbor']['asn']['peer'], ) if content == 'state': self._state() return json_string direction = parsed['neighbor']['direction'] category = parsed['neighbor']['message']['category'] header = parsed['neighbor']['message']['header'] body = parsed['neighbor']['message']['body'] data = b''.join(bytes([int(body[_ : _ + 2], 16)]) for _ in range(0, len(body), 2)) if content == 'open': message = Open.unpack_message(data) self._open(direction, message) return self.encoder.open(neighbor, direction, message, None, header, body) if content == 'keepalive': return self.encoder.keepalive(neighbor, direction, None, header, body) if content == 'notification': # XXX: Use the code of the Notifcation class here .. message = Notification.unpack_message(data) if (message.code, message.subcode) != (6, 2): message.data = data if not len([_ for _ in data if _ not in string.printable]) else hexstring(data) return self.encoder.notification(neighbor, direction, message, None, header, body) if len(data) == 0: # shutdown without shutdown communication (the old fashioned way) message.data = '' return self.encoder.notification(neighbor, direction, message, None, header, body) # draft-ietf-idr-shutdown or the peer was using 6,2 with data shutdown_length = data[0] data = data[1:] if shutdown_length == 0: message.data = "empty Shutdown Communication." # move offset past length field return self.encoder.notification(neighbor, direction, message, None, header, body) if len(data) < shutdown_length: message.data = "invalid Shutdown Communication (buffer underrun) length : %i [%s]" % ( shutdown_length, hexstring(data), ) return self.encoder.notification(neighbor, direction, message, None, header, body) if shutdown_length > 128: message.data = "invalid Shutdown Communication (too large) length : %i [%s]" % ( shutdown_length, hexstring(data), ) return self.encoder.notification(neighbor, direction, message, None, header, body) try: message.data = 'Shutdown Communication: "%s"' % data[:shutdown_length].decode('utf-8').replace( '\r', ' ' ).replace('\n', ' ') except UnicodeDecodeError: message.data = "invalid Shutdown Communication (invalid UTF-8) length : %i [%s]" % ( shutdown_length, hexstring(data), ) return self.encoder.notification(neighbor, direction, message, None, header, body) trailer = data[shutdown_length:] if trailer: message.data += ", trailing data: " + hexstring(trailer) return self.encoder.notification(neighbor, direction, message, None, header, body) if not self.negotiated: print('invalid message sequence, open not exchange not complete', json_string, file=sys.stderr) sys.exit(1) message = Message.unpack(category, data, direction, self.negotiated) if content == 'update': return self.encoder.update(neighbor, direction, message, None, header, body) if content == 'eor': # XXX: Should not be required return self.encoder.update(neighbor, direction, message, None, header, body) if content == 'refresh': return self.json.refresh(neighbor, direction, message, None, header, body) if content == 'operational': return self.json.refresh(neighbor, direction, message, None, header, body) raise RuntimeError('the programer is a monkey and forgot a JSON message type')
def _from_json (self, json_string): try: parsed = json.loads(json_string) except ValueError: print('invalid JSON message', file=sys.stderr) sys.exit(1) if parsed.get('exabgp','0.0.0') != json_version: print('invalid json version', json_string, file=sys.stderr) sys.exit(1) content = parsed.get('type','') if not content: print('invalid json content', json_string, file=sys.stderr) sys.exit(1) neighbor = _FakeNeighbor( parsed['neighbor']['address']['local'], parsed['neighbor']['address']['peer'], parsed['neighbor']['asn']['local'], parsed['neighbor']['asn']['peer'], ) if content == 'state': self._state() return json_string direction = parsed['neighbor']['direction'] category = parsed['neighbor']['message']['category'] header = parsed['neighbor']['message']['header'] body = parsed['neighbor']['message']['body'] data = concat_bytes_i(character(int(body[_:_+2],16)) for _ in range(0,len(body),2)) if content == 'open': message = Open.unpack_message(data) self._open(direction,message) return self.encoder.open(neighbor,direction,message,None,header,body) if content == 'keepalive': return self.encoder.keepalive(neighbor,direction,None,header,body) if content == 'notification': # XXX: Use the code of the Notifcation class here .. message = Notification.unpack_message(data) if (message.code, message.subcode) != (6, 2): message.data = data if not len([_ for _ in data if _ not in string.printable]) else hexstring(data) return self.encoder.notification(neighbor,direction,message,None,header,body) if len(data) == 0: # shutdown without shutdown communication (the old fashioned way) message.data = '' return self.encoder.notification(neighbor,direction,message,None,header,body) # draft-ietf-idr-shutdown or the peer was using 6,2 with data shutdown_length = ordinal(data[0]) data = data[1:] if shutdown_length == 0: message.data = "empty Shutdown Communication." # move offset past length field return self.encoder.notification(neighbor,direction,message,None,header,body) if len(data) < shutdown_length: message.data = "invalid Shutdown Communication (buffer underrun) length : %i [%s]" % (shutdown_length, hexstring(data)) return self.encoder.notification(neighbor,direction,message,None,header,body) if shutdown_length > 128: message.data = "invalid Shutdown Communication (too large) length : %i [%s]" % (shutdown_length, hexstring(data)) return self.encoder.notification(neighbor,direction,message,None,header,body) try: message.data = 'Shutdown Communication: "%s"' % \ data[:shutdown_length].decode('utf-8').replace('\r',' ').replace('\n',' ') except UnicodeDecodeError: message.data = "invalid Shutdown Communication (invalid UTF-8) length : %i [%s]" % (shutdown_length, hexstring(data)) return self.encoder.notification(neighbor,direction,message,None,header,body) trailer = data[shutdown_length:] if trailer: message.data += ", trailing data: " + hexstring(trailer) return self.encoder.notification(neighbor,direction,message,None,header,body) if not self.negotiated: print('invalid message sequence, open not exchange not complete', json_string, file=sys.stderr) sys.exit(1) message = Message.unpack(category,data,self.negotiated) if content == 'update': return self.encoder.update(neighbor, direction, message, None, header,body) if content == 'eor': # XXX: Should not be required return self.encoder.update(neighbor, direction, message, None, header,body) if content == 'refresh': return self.json.refresh(neighbor, direction, message, None, header,body) if content == 'operational': return self.json.refresh(neighbor, direction, message, None, header,body) raise RuntimeError('the programer is a monkey and forgot a JSON message type')
def json(self, compact=None): return '"attribute-not-implemented-%s": "%s"' % (self.code, hexstring(self.rep))
def json(self): return '{ "id": %d, "flag": %d, "payload": "%s"}' % ( self.ID, self.FLAG, hexstring(self.data))
def json (self): return '{ "id": %d, "flag": %d, "payload": "%s"}' % (self.ID,self.FLAG,hexstring(self.data))
def json(self): merged = ', '.join(['"{}"'.format(hexstring(_)) for _ in self.content]) return '"generic-lsid-{}": [{}]'.format(self.TLV, merged)