Skip to content
Browse files

Major overhaul

  • Loading branch information...
1 parent 181d525 commit 603620253be7b8354d949860a7cbdefa63c6f755 @steffann committed Jan 11, 2013
Showing with 880 additions and 488 deletions.
  1. +27 −20 ip_test.py
  2. +96 −0 kladblok.txt
  3. +2 −0 pylisp/packet/__init__.py
  4. +3 −0 pylisp/packet/ip/__init__.py
  5. +15 −8 pylisp/packet/ip/ipv4.py
  6. +0 −413 pylisp/packet/ip/ipv6.py
  7. +11 −0 pylisp/packet/ip/ipv6/__init__.py
  8. +153 −0 pylisp/packet/ip/ipv6/base.py
  9. +82 −0 pylisp/packet/ip/ipv6/destination_options_header.py
  10. +99 −0 pylisp/packet/ip/ipv6/fragment_header.py
  11. +82 −0 pylisp/packet/ip/ipv6/hop_by_hop_options_header.py
  12. +54 −0 pylisp/packet/ip/ipv6/no_next_header.py
  13. +97 −0 pylisp/packet/ip/ipv6/routing_header.py
  14. +52 −0 pylisp/packet/ip/protocol.py
  15. +44 −0 pylisp/packet/ip/protocol_registry.py
  16. +21 −8 pylisp/packet/ip/udp.py
  17. +2 −0 pylisp/packet/lisp/__init__.py
  18. 0 pylisp/packet/{ → lisp}/control/__init__.py
  19. +1 −1 pylisp/packet/{ → lisp}/control/base.py
  20. 0 pylisp/packet/{ → lisp}/control/constants.py
  21. +1 −2 pylisp/packet/{ → lisp}/control/encapsulated_control_message.py
  22. 0 pylisp/packet/{ → lisp}/control/locator_record.py
  23. +1 −2 pylisp/packet/{ → lisp}/control/map_notify.py
  24. +3 −4 pylisp/packet/{ → lisp}/control/map_referral.py
  25. +1 −1 pylisp/packet/{ → lisp}/control/map_referral_record.py
  26. +3 −5 pylisp/packet/{ → lisp}/control/map_register.py
  27. +7 −7 pylisp/packet/{ → lisp}/control/map_reply.py
  28. +1 −1 pylisp/packet/{ → lisp}/control/map_reply_record.py
  29. +3 −4 pylisp/packet/{ → lisp}/control/map_request.py
  30. +1 −1 pylisp/packet/{ → lisp}/control/type_registry.py
  31. +13 −7 pylisp/packet/{ → lisp}/data.py
  32. +2 −0 pylisp/utils/checksum.py
  33. +1 −1 unittests/test_packet_control_encapsulated_control_message.py
  34. +1 −1 unittests/test_packet_control_map_request.py
  35. +1 −2 unittests/test_packet_control_type_registry.py
View
47 ip_test.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-from pylisp.packet.ip.udp import UDPMessage
-from pylisp.packet.control.base import LISPControlMessage
+from pylisp.packet.ip.ipv4 import IPv4Packet
+from pylisp.packet.ip.ipv6 import IPv6HopByHopOptionsHeader, IPv6Packet
ip_packet_hex = ('45c00078000a0000201173c85cfe1cbdd413d814'
'10f610f6006437b6'
@@ -11,27 +11,25 @@
'0064ff00000500015cfe1cbd')
ip_packet = ip_packet_hex.decode('hex')
-from pylisp.packet.ip.ipv4 import IPv4Packet
-
packet = IPv4Packet.from_bytes(ip_packet)
-print packet
+print repr(packet)
-pkt_bytes = packet.to_bytes()
+pkt_bytes = bytes(packet)
pkt_bytes_hex = pkt_bytes.encode('hex')
print ip_packet == pkt_bytes
-udp_message = UDPMessage.from_bytes(packet.payload)
-print udp_message
+udp_message = packet.payload
+print repr(udp_message)
print udp_message.calculate_checksum(packet.source, packet.destination)
udp_msg_bytes = udp_message.to_bytes()
udp_msg_bytes_hex = udp_msg_bytes.encode('hex')
print packet.payload == udp_msg_bytes
-lisp_message = LISPControlMessage.from_bytes(udp_message.payload)
-print lisp_message
+lisp_message = udp_message.payload
+print repr(lisp_message)
ipv6_packet_hex = ('6000000000d611fffe80000000000000'
'aafad8fffeec0ea3ff02000000000000'
@@ -52,30 +50,39 @@
'0004aafad8ec0ea3a8fad8ec0ea3')
ipv6_packet = ipv6_packet_hex.decode('hex')
-from pylisp.packet.ip.ipv6 import IPv6Packet
-
packet = IPv6Packet.from_bytes(ipv6_packet)
-print packet
+print repr(packet)
pkt_bytes = packet.to_bytes()
pkt_bytes_hex = pkt_bytes.encode('hex')
print ipv6_packet == pkt_bytes
-udp_message = UDPMessage.from_bytes(packet.payload)
-print udp_message
+udp_message = packet.payload
+print repr(udp_message)
print udp_message.calculate_checksum(packet.source, packet.destination)
udp_msg_bytes = udp_message.to_bytes()
udp_msg_bytes_hex = udp_msg_bytes.encode('hex')
print packet.payload == udp_msg_bytes
-from pylisp.packet.ip.ipv6 import IPv6HopByHopOptionsHeader
-
-hdrbytes_hex = ('00010000000000000000000000000000')
+hdrbytes_hex = ('3b010000000000000000000000000000')
hdrbytes = hdrbytes_hex.decode('hex')
hdr = IPv6HopByHopOptionsHeader.from_bytes(hdrbytes)
-print hdr
+print repr(hdr)
print hdrbytes_hex
-print hdr.to_bytes().encode('hex')
+print bytes(hdr).encode('hex')
+
+multilayer_hex = ('45000073f7734000ff1173f95f61535d'
+ '254d380104ce10f5005f0000c0ac1912'
+ '00000007600000000027113e2a008640'
+ '0001000002204afffec8259920010503'
+ '0c2700000000000000020030d21d0035'
+ '0027af7b942700000001000000000000'
+ '08686f73746e616d650462696e640000'
+ '100003')
+multilayer = multilayer_hex.decode('hex')
+
+outer = IPv4Packet.from_bytes(multilayer)
+print repr(outer)
View
96 kladblok.txt
@@ -0,0 +1,96 @@
+# from pylisp.packet.control import LISPControlPacket
+# from pylisp.packet.data import LISPDataPacket
+# import doctest
+# import pylisp.packet.control.encapsulated_control_message
+#
+# print '-------------------------------------------------'
+# print 'Testing parsing and re-constructing a data packet'
+# print '-------------------------------------------------'
+#
+# data_packet_hex = ('c033d3c10000000745c0005835400000' +
+# 'ff06094a254d38204d45d1a30016f597' +
+# 'a1c3c7406718bf1b50180ff0793f0000' +
+# 'b555e59ff5ba6aad33d875c600fd8c1f' +
+# 'c5268078f365ee199179fbd09d09d690' +
+# '193622a6b70bcbc7bf5f20dda4258801')
+#
+# data_packet = data_packet_hex.decode('hex')
+#
+# print 'Parsing...'
+# packet = LISPDataPacket.from_bytes(data_packet)
+# print 'Parsed', packet.__class__.__name__, packet
+# print 'Reconstructing...'
+# packet_bin = packet.to_bytes()
+# assert(data_packet == packet_bin)
+# print 'Reconstructed packet matches original'
+#
+#
+# control_packets_hex = [('13000001ae92b5574f849cd00001ac10'
+# '1f0300015cfe1cbd00200001ac101f01'),
+# ('28000001ae92b5574f849cd0000005a0'
+# '0120100000000001ac101f010064ff00'
+# '00070001d41ac503'),
+# ('30000003'
+# '3a59ec0af1f32f480001001469719fe8'
+# '91f6705e111e912200856438d38c1c96'
+# '000005a0031f100000000001254d3820'
+# '3264ff000005000157c3c44d0a64ff00'
+# '000500015f61535d3264ff0000050002'
+# '200109e085000b000000000000000001'
+# '000005a0031a100000000001254d3840'
+# '3264ff000005000157c3c44d0a64ff00'
+# '000500015f61535d3264ff0000050002'
+# '200109e085000b000000000000000001'
+# '000005a0031e100000000001254d3938'
+# '3264ff000005000157c3c44d0a64ff00'
+# '000500015f61535d3264ff0000050002'
+# '200109e085000b000000000000000001'),
+# ('40000003'
+# '3a59ec0af1f32f4800010014cfa7ab7f'
+# '3cfea95378ac6efbb0f548930944592d'
+# '000005a0031f100000000001254d3820'
+# '3264ff000005000157c3c44d0a64ff00'
+# '000500015f61535d3264ff0000050002'
+# '200109e085000b000000000000000001'
+# '000005a0031a100000000001254d3840'
+# '3264ff000005000157c3c44d0a64ff00'
+# '000500015f61535d3264ff0000050002'
+# '200109e085000b000000000000000001'
+# '000005a0031e100000000001254d3938'
+# '3264ff000005000157c3c44d0a64ff00'
+# '000500015f61535d3264ff0000050002'
+# '200109e085000b000000000000000001'),
+# ('80000000'
+# '6e000000004811402a0086400001ffff'
+# '000000000000000a2a02000000000000'
+# '0000000000000000'
+# '10f610f600487396'
+# '10000201ee924adef97a97d700000001'
+# '57c3c44d00015f61535d0002200109e0'
+# '85000b000000000000000001000f0002'
+# '2a020000000000000000000000000000')]
+#
+# key = 'pylisp-demonstration-key'
+#
+# for control_packet_hex in control_packets_hex:
+# print '----------------------------------------------------'
+# print 'Testing parsing and re-constructing a control packet'
+# print '----------------------------------------------------'
+#
+# control_packet = control_packet_hex.decode('hex')
+#
+# print 'Parsing...'
+# message = LISPControlPacket.from_bytes(control_packet)
+# print 'Parsed', message.__class__.__name__, message
+# print 'Reconstructing...'
+# message_bin = message.to_bytes()
+# assert(control_packet == message_bin)
+# print 'Reconstructed packet matches original'
+#
+# if hasattr(message, 'verify_authentication_data'):
+# print 'Verifying authentication data...'
+# assert(message.verify_authentication_data(key))
+# print 'Authentication data is correct'
+#
+# doctest.testmod(pylisp.packet.control.encapsulated_control_message,
+# verbose=True)
View
2 pylisp/packet/__init__.py
@@ -0,0 +1,2 @@
+import ip
+import lisp
View
3 pylisp/packet/ip/__init__.py
@@ -0,0 +1,3 @@
+import ipv4
+import ipv6
+import udp
View
23 pylisp/packet/ip/ipv4.py
@@ -3,18 +3,21 @@
@author: sander
'''
-from bitstring import ConstBitStream, BitStream
from IPy import IP
+from bitstring import ConstBitStream, BitStream
+from pylisp.packet.ip import protocol_registry
from pylisp.utils import checksum
import math
+from pylisp.packet.ip.protocol import Protocol
-class IPv4Packet(object):
+class IPv4Packet(Protocol):
'''
Minimal IPv4 implementation to use in LISP Encapsulated Control Messages.
Options are not interpreted.
'''
+ header_type = 4
version = 4
def __init__(self, tos=0, identification=0, dont_fragment=False,
@@ -126,6 +129,10 @@ def from_bytes(cls, bitstream):
payload_bytes = (total_length) - (ihl * 4)
packet.payload = bitstream.read('bytes:%d' % payload_bytes)
+ payload_class = protocol_registry.get_type_class(packet.protocol)
+ if payload_class:
+ packet.payload = payload_class.from_bytes(packet.payload)
+
# There should be no remaining bits
if bitstream.pos != bitstream.len:
raise ValueError('Bits remaining after processing packet')
@@ -153,7 +160,8 @@ def to_bytes(self):
bitstream += BitStream('uint:8=%d' % self.tos)
# Write the total length
- total_length = 20 + len(self.payload)
+ payload_bytes = bytes(self.payload)
+ total_length = 20 + len(payload_bytes)
bitstream += BitStream('uint:16=%d' % total_length)
# Write the identification
@@ -190,9 +198,8 @@ def to_bytes(self):
my_checksum = checksum.ones_complement(bitstream.bytes)
bitstream[80:96] = BitStream('uint:16=%d' % my_checksum)
- # Determine payload
- payload = self.payload
- if hasattr(payload, 'to_bytes'):
- payload = payload.to_bytes()
+ return bitstream.bytes + payload_bytes
+
- return bitstream.bytes + payload
+# Register this header type
+protocol_registry.register_type_class(IPv4Packet)
View
413 pylisp/packet/ip/ipv6.py
@@ -1,413 +0,0 @@
-'''
-Created on 9 jan. 2013
-
-@author: sander
-'''
-from bitstring import ConstBitStream, BitStream
-from IPy import IP
-from abc import ABCMeta, abstractmethod
-import math
-
-
-class IPv6Packet(object):
- '''
- Minimal IPv4 implementation to use in LISP Encapsulated Control Messages.
- Options are not supported, will be dropped on input and never generated on
- output.
- '''
-
- version = 6
-
- def __init__(self, traffic_class=0, flow_label=0, next_header=0,
- hop_limit=0, source=None, destination=None, payload=''):
- '''
- Constructor
- '''
- # Set defaults
- self.traffic_class = traffic_class
- self.flow_label = flow_label
- self.next_header = next_header
- self.hop_limit = hop_limit
- self.source = source
- self.destination = destination
- self.payload = payload
-
- def __repr__(self):
- # This works as long as we accept all properties as paramters in the
- # constructor
- params = ['%s=%r' % (k, v) for k, v in self.__dict__.iteritems()]
- return '%s(%s)' % (self.__class__.__name__,
- ', '.join(params))
-
- def sanitize(self):
- '''
- Check if the current settings conform to the RFC and fix where possible
- '''
- # TODO: everything...
-
- @classmethod
- def from_bytes(cls, bitstream):
- '''
- Parse the given packet and update properties accordingly
- '''
- packet = cls()
-
- # Convert to ConstBitStream (if not already provided)
- if not isinstance(bitstream, ConstBitStream):
- bitstream = ConstBitStream(bytes=bitstream)
-
- # Read the version
- version = bitstream.read('uint:4')
- if version != packet.version:
- raise ValueError('Provided bytes do not contain an IPv6 packet')
-
- # Read the traffic class
- packet.traffic_class = bitstream.read('uint:8')
-
- # Read the flow label
- packet.flow_label = bitstream.read('uint:20')
-
- # Read the payload length
- payload_length = bitstream.read('uint:16')
-
- # Read the next header type
- packet.next_header = bitstream.read('uint:8')
-
- # Read the hop limit
- packet.hop_limit = bitstream.read('uint:8')
-
- # Read the source and destination addresses
- packet.source = IP(bitstream.read('uint:128'))
- packet.destination = IP(bitstream.read('uint:128'))
-
- # And the rest is payload
- packet.payload = bitstream.read('bytes:%d' % payload_length)
-
- # There should be no remaining bits
- if bitstream.pos != bitstream.len:
- raise ValueError('Bits remaining after processing packet')
-
- # Verify that the properties make sense
- packet.sanitize()
-
- return packet
-
- def to_bytes(self):
- '''
- Create bytes from properties
- '''
- # Verify that the properties make sense
- self.sanitize()
-
- # Write the version
- bitstream = BitStream('uint:4=%d' % self.version)
-
- # Write the traffic class
- bitstream += BitStream('uint:8=%d' % self.traffic_class)
-
- # Write the flow label
- bitstream += BitStream('uint:20=%d' % self.flow_label)
-
- # Write the payload length
- payload_length = len(self.payload)
- bitstream += BitStream('uint:16=%d' % payload_length)
-
- # Write the next header type
- bitstream += BitStream('uint:8=%d' % self.next_header)
-
- # Write the hop limit
- bitstream += BitStream('uint:8=%d' % self.hop_limit)
-
- # Write the source and destination addresses
- bitstream += BitStream('uint:128=%d, '
- 'uint:128=%d' % (self.source.ip,
- self.destination.ip))
-
- # Determine payload
- payload = self.payload
- if hasattr(payload, 'to_bytes'):
- payload = payload.to_bytes()
-
- return bitstream.bytes + payload
-
-
-class IPv6ExtensionHeader(object):
- __metaclass__ = ABCMeta
-
- header_type = 0
-
- @abstractmethod
- def __init__(self, next_header=0, payload=''):
- '''
- Constructor
- '''
- self.next_header = next_header
- self.payload = payload
-
- def __repr__(self):
- # This works as long as we accept all properties as paramters in the
- # constructor
- params = ['%s=%r' % (k, v) for k, v in self.__dict__.iteritems()]
- return '%s(%s)' % (self.__class__.__name__,
- ', '.join(params))
-
- @abstractmethod
- def sanitize(self):
- '''
- Check and optionally fix properties
- '''
-
- @classmethod
- @abstractmethod
- def from_bytes(cls, bitstream):
- '''
- Parse the given packet and update properties accordingly
- '''
-
- @abstractmethod
- def to_bytes(self):
- '''
- Create bytes from properties
- '''
-
-
-class IPv6HopByHopOptionsHeader(IPv6ExtensionHeader):
- header_type = 0
-
- def __init__(self, next_header=0, payload='', options=''):
- super(IPv6HopByHopOptionsHeader, self) \
- .__init__(next_header=next_header,
- payload=payload)
-
- self.options = options
-
- def sanitize(self):
- '''
- Check and optionally fix properties
- '''
-
- @classmethod
- def from_bytes(cls, bitstream):
- packet = cls()
-
- # Convert to ConstBitStream (if not already provided)
- if not isinstance(bitstream, ConstBitStream):
- bitstream = ConstBitStream(bytes=bitstream)
-
- # Read the next header type
- packet.next_header = bitstream.read('uint:8')
-
- # Read the header length, given in multiples of 8 octets
- header_length = bitstream.read('uint:8') + 1
-
- # Read the options
- options_length = (header_length * 8) - 2
- packet.options = bitstream.read('bytes:%d' % options_length)
-
- # And the rest is payload
- remaining = bitstream[bitstream.pos:]
- packet.payload = remaining.bytes
-
- # Verify that the properties make sense
- packet.sanitize()
-
- return packet
-
- def to_bytes(self):
- '''
- Create bytes from properties
- '''
- # Verify that the properties make sense
- self.sanitize()
-
- # Write the next header type
- bitstream = BitStream('uint:8=%d' % self.next_header)
-
- # Write the header length
- header_length_unpadded = len(self.options) + 2
- header_length = math.ceil(header_length_unpadded / 8.0)
- bitstream += BitStream('uint:8=%d' % (header_length - 1))
-
- # Add the options
- bitstream += BitStream(bytes=self.options)
- padding_len = (8 - (header_length_unpadded % 8)) % 8
- bitstream += BitStream(padding_len * 8)
-
- # Determine payload
- payload = self.payload
- if hasattr(payload, 'to_bytes'):
- payload = payload.to_bytes()
-
- return bitstream.bytes + payload
-
-
-class IPv6RoutingHeader(IPv6ExtensionHeader):
- header_type = 43
-
- def __init__(self, next_header=0, payload='', routing_type=0,
- segments_left=0, data=''):
- super(IPv6RoutingHeader, self) \
- .__init__(next_header=next_header,
- payload=payload)
-
- self.routing_type = routing_type
- self.segments_left = segments_left
- self.data = data
-
- def sanitize(self):
- '''
- Check and optionally fix properties
- '''
-
- @classmethod
- def from_bytes(cls, bitstream):
- packet = cls()
-
- # Convert to ConstBitStream (if not already provided)
- if not isinstance(bitstream, ConstBitStream):
- bitstream = ConstBitStream(bytes=bitstream)
-
- # Read the next header type
- packet.next_header = bitstream.read('uint:8')
-
- # Read the header length, given in multiples of 8 octets
- header_length = bitstream.read('uint:8') + 1
-
- # Read the routing type
- packet.routing_type = bitstream.read('uint:8')
-
- # Read the segments left
- packet.segments_left = bitstream.read('uint:8')
-
- # Read the data
- data_length = (header_length * 8) - 4
- packet.data = bitstream.read('bytes:%d' % data_length)
-
- # And the rest is payload
- remaining = bitstream[bitstream.pos:]
- packet.payload = remaining.bytes
-
- # Verify that the properties make sense
- packet.sanitize()
-
- return packet
-
- def to_bytes(self):
- '''
- Create bytes from properties
- '''
- # Verify that the properties make sense
- self.sanitize()
-
- # Write the next header type
- bitstream = BitStream('uint:8=%d' % self.next_header)
-
- # Write the header length
- header_length_unpadded = len(self.data) + 4
- header_length = math.ceil(header_length_unpadded / 8.0)
- bitstream += BitStream('uint:8=%d' % (header_length - 1))
-
- # Add the routing type
- bitstream += BitStream('uint:8=%d' % self.routing_type)
-
- # Add the segments left
- bitstream += BitStream('uint:8=%d' % self.segments_left)
-
- # Add the data
- bitstream += BitStream(bytes=self.data)
- padding_len = (8 - (header_length_unpadded % 8)) % 8
- bitstream += BitStream(padding_len * 8)
-
- # Determine payload
- payload = self.payload
- if hasattr(payload, 'to_bytes'):
- payload = payload.to_bytes()
-
- return bitstream.bytes + payload
-
-
-class IPv6FragmentHeader(IPv6ExtensionHeader):
- header_type = 43
-
- def __init__(self, next_header=0, payload='', fragment_offset=0,
- more_fragments=False, identification=0):
- super(IPv6RoutingHeader, self) \
- .__init__(next_header=next_header,
- payload=payload)
-
- self.fragment_offset = fragment_offset
- self.more_fragments = more_fragments
- self.identification = identification
-
- def sanitize(self):
- '''
- Check and optionally fix properties
- '''
-
- @classmethod
- def from_bytes(cls, bitstream):
- packet = cls()
-
- # Convert to ConstBitStream (if not already provided)
- if not isinstance(bitstream, ConstBitStream):
- bitstream = ConstBitStream(bytes=bitstream)
-
- # Read the next header type
- packet.next_header = bitstream.read('uint:8')
-
- # Skip over reserved bits
- bitstream.read(8)
-
- # Read the fragment offset
- packet.fragment_offset = bitstream.read('uint:13')
-
- # Skip over reserved bits
- bitstream.read(2)
-
- # Read the more fragments
- packet.more_fragments = bitstream.read('bool')
-
- # Read the identification
- packet.identification = bitstream.read('uint:32')
-
- # And the rest is payload
- remaining = bitstream[bitstream.pos:]
- packet.payload = remaining.bytes
-
- # Verify that the properties make sense
- packet.sanitize()
-
- return packet
-
- def to_bytes(self):
- '''
- Create bytes from properties
- '''
- # Verify that the properties make sense
- self.sanitize()
-
- # Write the next header type
- bitstream = BitStream('uint:8=%d' % self.next_header)
-
- # Write the header length
- header_length_unpadded = len(self.data) + 4
- header_length = math.ceil(header_length_unpadded / 8.0)
- bitstream += BitStream('uint:8=%d' % (header_length - 1))
-
- # Add the routing type
- bitstream += BitStream('uint:8=%d' % self.routing_type)
-
- # Add the segments left
- bitstream += BitStream('uint:8=%d' % self.segments_left)
-
- # Add the data
- bitstream += BitStream(bytes=self.data)
- padding_len = (8 - (header_length_unpadded % 8)) % 8
- bitstream += BitStream(padding_len * 8)
-
- # Determine payload
- payload = self.payload
- if hasattr(payload, 'to_bytes'):
- payload = payload.to_bytes()
-
- return bitstream.bytes + payload
View
11 pylisp/packet/ip/ipv6/__init__.py
@@ -0,0 +1,11 @@
+# Packet
+# ======
+from base import IPv6Packet
+
+# Extension headers
+# =================
+from hop_by_hop_options_header import IPv6HopByHopOptionsHeader
+from routing_header import IPv6RoutingHeader
+from fragment_header import IPv6FragmentHeader
+from destination_options_header import IPv6DestinationOptionsHeader
+from no_next_header import IPv6NoNextHeader
View
153 pylisp/packet/ip/ipv6/base.py
@@ -0,0 +1,153 @@
+'''
+Created on 9 jan. 2013
+
+@author: sander
+'''
+from IPy import IP
+from bitstring import ConstBitStream, BitStream
+from pylisp.packet.ip.protocol import Protocol
+from pylisp.packet.ip import protocol_registry
+
+
+class IPv6Packet(Protocol):
+ '''
+ Minimal IPv4 implementation to use in LISP Encapsulated Control Messages.
+ Options are not supported, will be dropped on input and never generated on
+ output.
+ '''
+
+ header_type = 41
+ version = 6
+
+ def __init__(self, traffic_class=0, flow_label=0, next_header=0,
+ hop_limit=0, source=None, destination=None, payload=''):
+ '''
+ Constructor
+ '''
+ # Set defaults
+ self.traffic_class = traffic_class
+ self.flow_label = flow_label
+ self.next_header = next_header
+ self.hop_limit = hop_limit
+ self.source = source
+ self.destination = destination
+ self.payload = payload
+
+ def __repr__(self):
+ # This works as long as we accept all properties as paramters in the
+ # constructor
+ params = ['%s=%r' % (k, v) for k, v in self.__dict__.iteritems()]
+ return '%s(%s)' % (self.__class__.__name__,
+ ', '.join(params))
+
+ def get_final_payload(self):
+ next_header = self.next_header
+ payload = self.payload
+
+ while isinstance(payload, IPv6ExtensionHeader) \
+ and payload.next_header is not None:
+ next_header = payload.next_header
+ payload = payload.payload
+
+ return (next_header, payload)
+
+ def sanitize(self):
+ '''
+ Check if the current settings conform to the RFC and fix where possible
+ '''
+ # TODO: everything...
+
+ @classmethod
+ def from_bytes(cls, bitstream):
+ '''
+ Parse the given packet and update properties accordingly
+ '''
+ packet = cls()
+
+ # Convert to ConstBitStream (if not already provided)
+ if not isinstance(bitstream, ConstBitStream):
+ bitstream = ConstBitStream(bytes=bitstream)
+
+ # Read the version
+ version = bitstream.read('uint:4')
+ if version != packet.version:
+ raise ValueError('Provided bytes do not contain an IPv6 packet')
+
+ # Read the traffic class
+ packet.traffic_class = bitstream.read('uint:8')
+
+ # Read the flow label
+ packet.flow_label = bitstream.read('uint:20')
+
+ # Read the payload length
+ payload_length = bitstream.read('uint:16')
+
+ # Read the next header type
+ packet.next_header = bitstream.read('uint:8')
+
+ # Read the hop limit
+ packet.hop_limit = bitstream.read('uint:8')
+
+ # Read the source and destination addresses
+ packet.source = IP(bitstream.read('uint:128'))
+ packet.destination = IP(bitstream.read('uint:128'))
+
+ # And the rest is payload
+ packet.payload = bitstream.read('bytes:%d' % payload_length)
+
+ payload_class = protocol_registry.get_type_class(packet.next_header)
+ if payload_class:
+ packet.payload = payload_class.from_bytes(packet.payload)
+
+ # There should be no remaining bits
+ if bitstream.pos != bitstream.len:
+ raise ValueError('Bits remaining after processing packet')
+
+ # Verify that the properties make sense
+ packet.sanitize()
+
+ return packet
+
+ def to_bytes(self):
+ '''
+ Create bytes from properties
+ '''
+ # Verify that the properties make sense
+ self.sanitize()
+
+ # Write the version
+ bitstream = BitStream('uint:4=%d' % self.version)
+
+ # Write the traffic class
+ bitstream += BitStream('uint:8=%d' % self.traffic_class)
+
+ # Write the flow label
+ bitstream += BitStream('uint:20=%d' % self.flow_label)
+
+ # Write the payload length
+ payload_bytes = bytes(self.payload)
+ payload_length = len(payload_bytes)
+ bitstream += BitStream('uint:16=%d' % payload_length)
+
+ # Write the next header type
+ bitstream += BitStream('uint:8=%d' % self.next_header)
+
+ # Write the hop limit
+ bitstream += BitStream('uint:8=%d' % self.hop_limit)
+
+ # Write the source and destination addresses
+ bitstream += BitStream('uint:128=%d, '
+ 'uint:128=%d' % (self.source.ip,
+ self.destination.ip))
+
+ return bitstream.bytes + payload_bytes
+
+
+class IPv6ExtensionHeader(Protocol):
+ '''
+ IPv6 extension headers use the same number space as protocols
+ '''
+
+
+# Register this header type
+protocol_registry.register_type_class(IPv6Packet)
View
82 pylisp/packet/ip/ipv6/destination_options_header.py
@@ -0,0 +1,82 @@
+'''
+Created on 11 jan. 2013
+
+@author: sander
+'''
+from bitstring import BitStream, ConstBitStream
+from pylisp.packet.ip import protocol_registry
+from pylisp.packet.ip.ipv6.base import IPv6ExtensionHeader
+import math
+
+
+class IPv6DestinationOptionsHeader(IPv6ExtensionHeader):
+ header_type = 60
+
+ def __init__(self, next_header=0, payload='', options=''):
+ super(IPv6DestinationOptionsHeader, self) \
+ .__init__(next_header=next_header,
+ payload=payload)
+
+ self.options = options
+
+ def sanitize(self):
+ '''
+ Check and optionally fix properties
+ '''
+
+ @classmethod
+ def from_bytes(cls, bitstream):
+ packet = cls()
+
+ # Convert to ConstBitStream (if not already provided)
+ if not isinstance(bitstream, ConstBitStream):
+ bitstream = ConstBitStream(bytes=bitstream)
+
+ # Read the next header type
+ packet.next_header = bitstream.read('uint:8')
+
+ # Read the header length, given in multiples of 8 octets
+ header_length = bitstream.read('uint:8') + 1
+
+ # Read the options
+ options_length = (header_length * 8) - 2
+ packet.options = bitstream.read('bytes:%d' % options_length)
+
+ # And the rest is payload
+ remaining = bitstream[bitstream.pos:]
+ packet.payload = remaining.bytes
+
+ payload_class = protocol_registry.get_type_class(packet.next_header)
+ if payload_class:
+ packet.payload = payload_class.from_bytes(packet.payload)
+
+ # Verify that the properties make sense
+ packet.sanitize()
+
+ return packet
+
+ def to_bytes(self):
+ '''
+ Create bytes from properties
+ '''
+ # Verify that the properties make sense
+ self.sanitize()
+
+ # Write the next header type
+ bitstream = BitStream('uint:8=%d' % self.next_header)
+
+ # Write the header length
+ header_length_unpadded = len(self.options) + 2
+ header_length = math.ceil(header_length_unpadded / 8.0)
+ bitstream += BitStream('uint:8=%d' % (header_length - 1))
+
+ # Add the options
+ bitstream += BitStream(bytes=self.options)
+ padding_len = (8 - (header_length_unpadded % 8)) % 8
+ bitstream += BitStream(padding_len * 8)
+
+ return bitstream.bytes + bytes(self.payload)
+
+
+# Register this header type
+protocol_registry.register_type_class(IPv6DestinationOptionsHeader)
View
99 pylisp/packet/ip/ipv6/fragment_header.py
@@ -0,0 +1,99 @@
+'''
+Created on 11 jan. 2013
+
+@author: sander
+'''
+from bitstring import BitStream, ConstBitStream
+from pylisp.packet.ip.ipv6.base import IPv6ExtensionHeader
+import math
+from pylisp.packet.ip import protocol_registry
+
+
+class IPv6FragmentHeader(IPv6ExtensionHeader):
+ header_type = 44
+
+ def __init__(self, next_header=0, payload='', fragment_offset=0,
+ more_fragments=False, identification=0):
+ super(IPv6FragmentHeader, self) \
+ .__init__(next_header=next_header,
+ payload=payload)
+
+ self.fragment_offset = fragment_offset
+ self.more_fragments = more_fragments
+ self.identification = identification
+
+ def sanitize(self):
+ '''
+ Check and optionally fix properties
+ '''
+
+ @classmethod
+ def from_bytes(cls, bitstream):
+ packet = cls()
+
+ # Convert to ConstBitStream (if not already provided)
+ if not isinstance(bitstream, ConstBitStream):
+ bitstream = ConstBitStream(bytes=bitstream)
+
+ # Read the next header type
+ packet.next_header = bitstream.read('uint:8')
+
+ # Skip over reserved bits
+ bitstream.read(8)
+
+ # Read the fragment offset
+ packet.fragment_offset = bitstream.read('uint:13')
+
+ # Skip over reserved bits
+ bitstream.read(2)
+
+ # Read the more fragments
+ packet.more_fragments = bitstream.read('bool')
+
+ # Read the identification
+ packet.identification = bitstream.read('uint:32')
+
+ # And the rest is payload
+ remaining = bitstream[bitstream.pos:]
+ packet.payload = remaining.bytes
+
+ # Verify that the properties make sense
+ packet.sanitize()
+
+ return packet
+
+ def to_bytes(self):
+ '''
+ Create bytes from properties
+ '''
+ # Verify that the properties make sense
+ self.sanitize()
+
+ # Write the next header type
+ bitstream = BitStream('uint:8=%d' % self.next_header)
+
+ # Write the header length
+ header_length_unpadded = len(self.data) + 4
+ header_length = math.ceil(header_length_unpadded / 8.0)
+ bitstream += BitStream('uint:8=%d' % (header_length - 1))
+
+ # Add the reserved bits
+ bitstream += BitStream(8)
+
+ # Add the fragment offset
+ bitstream += BitStream('uint:13=%d' % self.fragment_offset)
+
+ # Add the reserved bits
+ bitstream += BitStream(2)
+
+ # Add the flags
+ bitstream += BitStream('bool=%d' % self.more_fragments)
+
+ # Add the identification
+ bitstream += BitStream('uint:32=%d' % self.identification)
+
+ return bitstream.bytes + bytes(self.payload)
+
+
+# Register this header type
+protocol_registry.register_type_class(IPv6FragmentHeader)
View
82 pylisp/packet/ip/ipv6/hop_by_hop_options_header.py
@@ -0,0 +1,82 @@
+'''
+Created on 11 jan. 2013
+
+@author: sander
+'''
+from bitstring import BitStream, ConstBitStream
+from pylisp.packet.ip import protocol_registry
+from pylisp.packet.ip.ipv6.base import IPv6ExtensionHeader
+import math
+
+
+class IPv6HopByHopOptionsHeader(IPv6ExtensionHeader):
+ header_type = 0
+
+ def __init__(self, next_header=0, payload='', options=''):
+ super(IPv6HopByHopOptionsHeader, self) \
+ .__init__(next_header=next_header,
+ payload=payload)
+
+ self.options = options
+
+ def sanitize(self):
+ '''
+ Check and optionally fix properties
+ '''
+
+ @classmethod
+ def from_bytes(cls, bitstream):
+ packet = cls()
+
+ # Convert to ConstBitStream (if not already provided)
+ if not isinstance(bitstream, ConstBitStream):
+ bitstream = ConstBitStream(bytes=bitstream)
+
+ # Read the next header type
+ packet.next_header = bitstream.read('uint:8')
+
+ # Read the header length, given in multiples of 8 octets
+ header_length = bitstream.read('uint:8') + 1
+
+ # Read the options
+ options_length = (header_length * 8) - 2
+ packet.options = bitstream.read('bytes:%d' % options_length)
+
+ # And the rest is payload
+ remaining = bitstream[bitstream.pos:]
+ packet.payload = remaining.bytes
+
+ payload_class = protocol_registry.get_type_class(packet.next_header)
+ if payload_class:
+ packet.payload = payload_class.from_bytes(packet.payload)
+
+ # Verify that the properties make sense
+ packet.sanitize()
+
+ return packet
+
+ def to_bytes(self):
+ '''
+ Create bytes from properties
+ '''
+ # Verify that the properties make sense
+ self.sanitize()
+
+ # Write the next header type
+ bitstream = BitStream('uint:8=%d' % self.next_header)
+
+ # Write the header length
+ header_length_unpadded = len(self.options) + 2
+ header_length = math.ceil(header_length_unpadded / 8.0)
+ bitstream += BitStream('uint:8=%d' % (header_length - 1))
+
+ # Add the options
+ bitstream += BitStream(bytes=self.options)
+ padding_len = (8 - (header_length_unpadded % 8)) % 8
+ bitstream += BitStream(padding_len * 8)
+
+ return bitstream.bytes + bytes(self.payload)
+
+
+# Register this header type
+protocol_registry.register_type_class(IPv6HopByHopOptionsHeader)
View
54 pylisp/packet/ip/ipv6/no_next_header.py
@@ -0,0 +1,54 @@
+'''
+Created on 11 jan. 2013
+
+@author: sander
+'''
+from bitstring import ConstBitStream
+from pylisp.packet.ip import protocol_registry
+from pylisp.packet.ip.ipv6.base import IPv6ExtensionHeader
+
+
+class IPv6NoNextHeader(IPv6ExtensionHeader):
+ header_type = 59
+
+ def __init__(self, next_header=0, payload=''):
+ super(IPv6NoNextHeader, self) \
+ .__init__(next_header=next_header,
+ payload=payload)
+
+ # No next header, ever
+ self.next_header = None
+
+ def sanitize(self):
+ '''
+ Check and optionally fix properties
+ '''
+
+ @classmethod
+ def from_bytes(cls, bitstream):
+ packet = cls()
+
+ # Convert to ConstBitStream (if not already provided)
+ if not isinstance(bitstream, ConstBitStream):
+ bitstream = ConstBitStream(bytes=bitstream)
+
+ # Everything is payload
+ remaining = bitstream[bitstream.pos:]
+ packet.payload = remaining.bytes
+
+ # Verify that the properties make sense
+ packet.sanitize()
+
+ return packet
+
+ def to_bytes(self):
+ '''
+ Create bytes from properties
+ '''
+ # Verify that the properties make sense
+ self.sanitize()
+
+ return bytes(self.payload)
+
+# Register this header type
+protocol_registry.register_type_class(IPv6NoNextHeader)
View
97 pylisp/packet/ip/ipv6/routing_header.py
@@ -0,0 +1,97 @@
+'''
+Created on 11 jan. 2013
+
+@author: sander
+'''
+from bitstring import BitStream, ConstBitStream
+from pylisp.packet.ip import protocol_registry
+from pylisp.packet.ip.ipv6.base import IPv6ExtensionHeader
+import math
+
+
+class IPv6RoutingHeader(IPv6ExtensionHeader):
+ header_type = 43
+
+ def __init__(self, next_header=0, payload='', routing_type=0,
+ segments_left=0, data=''):
+ super(IPv6RoutingHeader, self) \
+ .__init__(next_header=next_header,
+ payload=payload)
+
+ self.routing_type = routing_type
+ self.segments_left = segments_left
+ self.data = data
+
+ def sanitize(self):
+ '''
+ Check and optionally fix properties
+ '''
+
+ @classmethod
+ def from_bytes(cls, bitstream):
+ packet = cls()
+
+ # Convert to ConstBitStream (if not already provided)
+ if not isinstance(bitstream, ConstBitStream):
+ bitstream = ConstBitStream(bytes=bitstream)
+
+ # Read the next header type
+ packet.next_header = bitstream.read('uint:8')
+
+ # Read the header length, given in multiples of 8 octets
+ header_length = bitstream.read('uint:8') + 1
+
+ # Read the routing type
+ packet.routing_type = bitstream.read('uint:8')
+
+ # Read the segments left
+ packet.segments_left = bitstream.read('uint:8')
+
+ # Read the data
+ data_length = (header_length * 8) - 4
+ packet.data = bitstream.read('bytes:%d' % data_length)
+
+ # And the rest is payload
+ remaining = bitstream[bitstream.pos:]
+ packet.payload = remaining.bytes
+
+ payload_class = protocol_registry.get_type_class(packet.next_header)
+ if payload_class:
+ packet.payload = payload_class.from_bytes(packet.payload)
+
+ # Verify that the properties make sense
+ packet.sanitize()
+
+ return packet
+
+ def to_bytes(self):
+ '''
+ Create bytes from properties
+ '''
+ # Verify that the properties make sense
+ self.sanitize()
+
+ # Write the next header type
+ bitstream = BitStream('uint:8=%d' % self.next_header)
+
+ # Write the header length
+ header_length_unpadded = len(self.data) + 4
+ header_length = math.ceil(header_length_unpadded / 8.0)
+ bitstream += BitStream('uint:8=%d' % (header_length - 1))
+
+ # Add the routing type
+ bitstream += BitStream('uint:8=%d' % self.routing_type)
+
+ # Add the segments left
+ bitstream += BitStream('uint:8=%d' % self.segments_left)
+
+ # Add the data
+ bitstream += BitStream(bytes=self.data)
+ padding_len = (8 - (header_length_unpadded % 8)) % 8
+ bitstream += BitStream(padding_len * 8)
+
+ return bitstream.bytes + bytes(self.payload)
+
+
+# Register this header type
+protocol_registry.register_type_class(IPv6RoutingHeader)
View
52 pylisp/packet/ip/protocol.py
@@ -0,0 +1,52 @@
+'''
+Created on 11 jan. 2013
+
+@author: sander
+'''
+from abc import abstractmethod, ABCMeta
+
+
+class Protocol(object):
+ __metaclass__ = ABCMeta
+
+ header_type = None
+
+ @abstractmethod
+ def __init__(self, next_header=None, payload=''):
+ '''
+ Constructor
+ '''
+ self.next_header = next_header
+ self.payload = payload
+
+ def __repr__(self):
+ # This works as long as we accept all properties as paramters in the
+ # constructor
+ params = ['%s=%r' % (k, v) for k, v in self.__dict__.iteritems()]
+ return '%s(%s)' % (self.__class__.__name__,
+ ', '.join(params))
+
+ @abstractmethod
+ def sanitize(self):
+ '''
+ Check and optionally fix properties
+ '''
+
+ @classmethod
+ @abstractmethod
+ def from_bytes(cls, bitstream):
+ '''
+ Parse the given packet and update properties accordingly
+ '''
+
+ @abstractmethod
+ def to_bytes(self):
+ '''
+ Create bytes from properties
+ '''
+
+ def __str__(self):
+ return str(self.to_bytes())
+
+ def __bytes__(self):
+ return bytes(self.to_bytes())
View
44 pylisp/packet/ip/protocol_registry.py
@@ -0,0 +1,44 @@
+'''
+Created on 6 jan. 2013
+
+@author: sander
+'''
+import numbers
+from pylisp.packet.ip.protocol import Protocol
+
+
+# Store supported protocol types and their classes
+_type_classes = {}
+
+
+__all__ = ['register_type_class', 'get_type_class']
+
+
+def register_type_class(type_class):
+ # Check for valid class
+ if not issubclass(type_class, Protocol):
+ msg = 'Message type classes must be subclasses of Protocol'
+ raise ValueError(msg)
+
+ # Check for valid type numbers
+ type_nr = type_class.header_type
+
+ if not isinstance(type_nr, numbers.Integral) \
+ or type_nr < 0 or type_nr > 255:
+ raise ValueError('Invalid protocol {0}'.format(type_nr))
+
+ # Check for duplicates
+ if type_nr in _type_classes:
+ # Ignore identical registrations
+ if type_class is _type_classes[type_nr]:
+ return
+
+ msg = 'Protocol {0} is already bound to class {1}'
+ class_name = _type_classes[type_nr].__name__
+ raise ValueError(msg.format(type_nr, class_name))
+
+ _type_classes[type_nr] = type_class
+
+
+def get_type_class(type_nr):
+ return _type_classes.get(type_nr)
View
29 pylisp/packet/ip/udp.py
@@ -4,10 +4,14 @@
@author: sander
'''
from bitstring import BitStream, ConstBitStream
+from pylisp.packet.ip.protocol import Protocol
from pylisp.utils import checksum
+from pylisp.packet.ip import protocol_registry
-class UDPMessage(object):
+class UDPMessage(Protocol):
+ header_type = 17
+
def __init__(self, source_port=0, destination_port=0, checksum=0,
payload=''):
self.source_port = source_port
@@ -30,7 +34,7 @@ def sanitize(self):
def generate_pseudo_header(self, source, destination):
# Calculate the length of the UDP layer
- udp_length = 8 + len(self.payload)
+ udp_length = 8 + len(bytes(self.payload))
if source.version() == 4 and destination.version() == 4:
# Generate an IPv4 pseudo-header
@@ -97,6 +101,16 @@ def from_bytes(cls, bitstream):
payload_bytes = length - 8
packet.payload = bitstream.read('bytes:%d' % payload_bytes)
+ # LISP-specific handling
+ if packet.source_port == 4341 or packet.destination_port == 4341:
+ # Payload is a LISP data packet
+ from pylisp.packet.lisp.data import LISPDataPacket
+ packet.payload = LISPDataPacket.from_bytes(packet.payload)
+ elif packet.source_port == 4342 or packet.destination_port == 4342:
+ # Payload is a LISP control message
+ from pylisp.packet.lisp.control.base import LISPControlMessage
+ packet.payload = LISPControlMessage.from_bytes(packet.payload)
+
# There should be no remaining bits
if bitstream.pos != bitstream.len:
raise ValueError('Bits remaining after processing packet')
@@ -119,15 +133,14 @@ def to_bytes(self):
self.destination_port))
# Write the length
- length = len(self.payload) + 8
+ payload_bytes = bytes(self.payload)
+ length = len(payload_bytes) + 8
bitstream += BitStream('uint:16=%d' % length)
# Write the checksum
bitstream += BitStream('uint:16=%d' % self.checksum)
- # Determine payload
- payload = self.payload
- if hasattr(payload, 'to_bytes'):
- payload = payload.to_bytes()
+ return bitstream.bytes + payload_bytes
- return bitstream.bytes + payload
+# Register this header type
+protocol_registry.register_type_class(UDPMessage)
View
2 pylisp/packet/lisp/__init__.py
@@ -0,0 +1,2 @@
+import control
+import data
View
0 pylisp/packet/control/__init__.py → pylisp/packet/lisp/control/__init__.py
File renamed without changes.
View
2 pylisp/packet/control/base.py → pylisp/packet/lisp/control/base.py
@@ -44,7 +44,7 @@ def from_bytes(cls, bitstream):
Look at the type of the message, instantiate the correct class and
let it parse the message.
'''
- from pylisp.packet.control import type_registry
+ from pylisp.packet.lisp.control import type_registry
# Convert to ConstBitStream (if not already provided)
if not isinstance(bitstream, ConstBitStream):
View
0 pylisp/packet/control/constants.py → pylisp/packet/lisp/control/constants.py
File renamed without changes.
View
3 ...t/control/encapsulated_control_message.py → ...p/control/encapsulated_control_message.py
@@ -4,8 +4,7 @@
@author: sander
'''
from bitstring import ConstBitStream, BitArray
-from pylisp.packet.control import type_registry
-from pylisp.packet.control.base import LISPControlMessage
+from pylisp.packet.lisp.control import type_registry, LISPControlMessage
__all__ = ['LISPEncapsulatedControlMessage']
View
0 pylisp/packet/control/locator_record.py → pylisp/packet/lisp/control/locator_record.py
File renamed without changes.
View
3 pylisp/packet/control/map_notify.py → pylisp/packet/lisp/control/map_notify.py
@@ -3,8 +3,7 @@
@author: sander
'''
-from pylisp.packet.control import type_registry
-from pylisp.packet.control.map_register import LISPMapRegisterMessage
+from pylisp.packet.lisp.control import type_registry, LISPMapRegisterMessage
__all__ = ['LISPMapNotify']
View
7 pylisp/packet/control/map_referral.py → pylisp/packet/lisp/control/map_referral.py
@@ -4,9 +4,8 @@
@author: sander
'''
from bitstring import ConstBitStream, BitArray
-from pylisp.packet.control import type_registry
-from pylisp.packet.control.base import LISPControlMessage
-from pylisp.packet.control.map_referral_record import LISPMapReferralRecord
+from pylisp.packet.lisp.control import type_registry, LISPControlMessage, \
+ LISPMapReferralRecord
__all__ = ['LISPMapReferralMessage']
@@ -44,7 +43,7 @@ def sanitize(self):
# SHOULD be generated by a properly seeded pseudo-random (or strong
# random) source. See [RFC4086] for advice on generating security-
# sensitive random data.
- if not isinstance(self.nonce, bytes) or len(self.nonce) != 8:
+ if len(bytes(self.nonce)) != 8:
raise ValueError('Invalid nonce')
# Map-Referral Records: When the M bit is set, this field is the size
View
2 pylisp/packet/control/map_referral_record.py → ...acket/lisp/control/map_referral_record.py
@@ -5,7 +5,7 @@
'''
from IPy import IP
from bitstring import ConstBitStream, BitArray
-from pylisp.packet.control.locator_record import LISPLocatorRecord
+from pylisp.packet.lisp.control import LISPLocatorRecord
from pylisp.utils.afi import read_afi_address_from_bitstream, \
get_bitstream_for_afi_address
import numbers
View
8 pylisp/packet/control/map_register.py → pylisp/packet/lisp/control/map_register.py
@@ -5,10 +5,8 @@
'''
from base import LISPControlMessage
from bitstring import ConstBitStream, BitArray
-from pylisp.packet.control import type_registry
-from pylisp.packet.control.constants import KEY_ID_HMAC_SHA_1_96, \
- KEY_ID_HMAC_SHA_256_128, KEY_ID_NONE
-from pylisp.packet.control.map_reply_record import LISPMapReplyRecord
+from pylisp.packet.lisp.control import type_registry, KEY_ID_HMAC_SHA_1_96, \
+ KEY_ID_HMAC_SHA_256_128, KEY_ID_NONE, LISPMapReplyRecord
import hashlib
import hmac
@@ -62,7 +60,7 @@ def sanitize(self):
# messages. Since the Map-Register message is authenticated, the
# nonce field is not currently used for any security function but
# may be in the future as part of an anti-replay solution.
- if not isinstance(self.nonce, bytes) or len(self.nonce) != 8:
+ if len(bytes(self.nonce)) != 8:
raise ValueError('Invalid nonce')
# Key ID: A configured ID to find the configured Message
View
14 pylisp/packet/control/map_reply.py → pylisp/packet/lisp/control/map_reply.py
@@ -4,9 +4,8 @@
@author: sander
'''
from bitstring import ConstBitStream, BitArray
-from pylisp.packet.control import type_registry
-from pylisp.packet.control.base import LISPControlMessage
-from pylisp.packet.control.map_reply_record import LISPMapReplyRecord
+from pylisp.packet.lisp.control import type_registry, LISPControlMessage, \
+ LISPMapReplyRecord
__all__ = ['LISPMapReplyMessage']
@@ -66,7 +65,7 @@ def sanitize(self):
# from the Map-Request is echoed in this Nonce field of the Map-
# Reply. When a 24-bit value is supplied, it resides in the low-
# order 64 bits of the nonce field.
- if not isinstance(self.nonce, bytes) or len(self.nonce) not in (3, 8):
+ if len(bytes(self.nonce)) not in (3, 8):
raise ValueError('Invalid nonce')
# Map-Reply Record: When the M bit is set, this field is the size of a
@@ -155,11 +154,12 @@ def to_bytes(self):
bitstream += BitArray('uint:8=%d' % len(self.records))
# Add the nonce
- if len(self.nonce) < 8:
- padding_len = 8 - len(self.nonce)
+ nonce = bytes(self.nonce)
+ if len(nonce) < 8:
+ padding_len = 8 - len(nonce)
bitstream += BitArray(8 * padding_len)
- bitstream += BitArray(bytes=self.nonce)
+ bitstream += BitArray(bytes=nonce)
# Add the map-reply records
for record in self.records:
View
2 pylisp/packet/control/map_reply_record.py → ...p/packet/lisp/control/map_reply_record.py
@@ -5,7 +5,7 @@
'''
from IPy import IP
from bitstring import ConstBitStream, BitArray
-from pylisp.packet.control.locator_record import LISPLocatorRecord
+from pylisp.packet.lisp.control import LISPLocatorRecord
from pylisp.utils.afi import read_afi_address_from_bitstream, \
get_bitstream_for_afi_address
import numbers
View
7 pylisp/packet/control/map_request.py → pylisp/packet/lisp/control/map_request.py
@@ -5,9 +5,8 @@
'''
from IPy import IP
from bitstring import ConstBitStream, BitArray
-from pylisp.packet.control import type_registry
-from pylisp.packet.control.base import LISPControlMessage
-from pylisp.packet.control.map_reply_record import LISPMapReplyRecord
+from pylisp.packet.lisp.control import type_registry, LISPControlMessage, \
+ LISPMapReplyRecord
from pylisp.utils.afi import read_afi_address_from_bitstream, \
get_bitstream_for_afi_address
@@ -113,7 +112,7 @@ def sanitize(self):
# SHOULD be generated by a properly seeded pseudo-random (or strong
# random) source. See [RFC4086] for advice on generating security-
# sensitive random data.
- if not isinstance(self.nonce, bytes) or len(self.nonce) != 8:
+ if len(bytes(self.nonce)) != 8:
raise ValueError('Invalid nonce')
# Source EID Address: This is the EID of the source host which
View
2 pylisp/packet/control/type_registry.py → pylisp/packet/lisp/control/type_registry.py
@@ -4,7 +4,7 @@
@author: sander
'''
import numbers
-from pylisp.packet.control.base import LISPControlMessage
+from pylisp.packet.lisp.control import LISPControlMessage
# Store supported message types and their classes
_type_classes = {}
View
20 pylisp/packet/data.py → pylisp/packet/lisp/data.py
@@ -6,6 +6,8 @@
from bitstring import ConstBitStream, BitArray
import collections
import numbers
+from pylisp.packet.ip.ipv4 import IPv4Packet
+from pylisp.packet.ip.ipv6.base import IPv6Packet
__all__ = ['LISPDataPacket']
@@ -195,7 +197,16 @@ def from_bytes(cls, bitstream):
# The rest of the packet is payload
remaining = bitstream[bitstream.pos:]
- packet.payload = remaining.bytes
+
+ # Parse IP packet
+ if len(remaining):
+ ip_version = remaining.peek('uint:4')
+ if ip_version == 4:
+ packet.payload = IPv4Packet.from_bytes(remaining)
+ elif ip_version == 6:
+ packet.payload = IPv6Packet.from_bytes(remaining)
+ else:
+ packet.payload = remaining.bytes
# Verify that the properties make sense
packet.sanitize()
@@ -255,9 +266,4 @@ def to_bytes(self):
else:
bitstream += BitArray(lsb_bits)
- # Determine payload
- payload = self.payload
- if hasattr(payload, 'to_bytes'):
- payload = payload.to_bytes()
-
- return bitstream.bytes + payload
+ return bitstream.bytes + bytes(self.payload)
View
2 pylisp/utils/checksum.py
@@ -6,6 +6,8 @@
def ones_complement(message):
+ message = bytes(message)
+
# Add padding if the message has an odd number of bytes
if len(message) % 2 == 1:
message = message + '\x00'
View
2 unittests/test_packet_control_encapsulated_control_message.py
@@ -6,7 +6,7 @@
sys.path.insert(0, '.')
sys.path.insert(0, '..')
-from pylisp.packet.control import encapsulated_control_message
+from pylisp.packet.lisp.control import encapsulated_control_message
import doctest
import unittest
View
2 unittests/test_packet_control_map_request.py
@@ -8,7 +8,7 @@
sys.path.insert(0, '.')
sys.path.insert(0, '..')
-from pylisp.packet.control import map_request
+from pylisp.packet.lisp.control import map_request
import doctest
import unittest
View
3 unittests/test_packet_control_type_registry.py
@@ -7,8 +7,7 @@
sys.path.insert(0, '..')
from copy import copy
-from pylisp.packet.control import type_registry
-from pylisp.packet.control.base import LISPControlMessage
+from pylisp.packet.lisp.control import type_registry, LISPControlMessage
import doctest
import unittest

0 comments on commit 6036202

Please sign in to comment.
Something went wrong with that request. Please try again.