75e7d13014
Change-Id: Ic5dcadd13c88b8a5e7896dab82404509c081614a Signed-off-by: Klement Sekera <ksekera@cisco.com>
196 lines
8.8 KiB
Diff
196 lines
8.8 KiB
Diff
diff --git a/scapy/layers/inet6.py b/scapy/layers/inet6.py
|
|
index 03b80ec..06ef27f 100644
|
|
--- a/scapy/layers/inet6.py
|
|
+++ b/scapy/layers/inet6.py
|
|
@@ -369,6 +369,8 @@ class _IPv6GuessPayload:
|
|
return Raw
|
|
elif self.nh == 135 and len(p) > 3: # Mobile IPv6
|
|
return _mip6_mhtype2cls.get(ord(p[2]), MIP6MH_Generic)
|
|
+ elif self.nh == 43 and ord(p[2]) == 4: # Segment Routing header
|
|
+ return IPv6ExtHdrSegmentRouting
|
|
else:
|
|
return get_cls(ipv6nhcls.get(self.nh,"Raw"), "Raw")
|
|
|
|
@@ -430,6 +432,14 @@ class IPv6(_IPv6GuessPayload, Packet, IPTools):
|
|
sd = strxor(sd, a)
|
|
sd = inet_ntop(socket.AF_INET6, sd)
|
|
|
|
+ if self.nh == 43 and isinstance(self.payload, IPv6ExtHdrSegmentRouting):
|
|
+ # With segment routing header (rh == 4), the destination is
|
|
+ # the first address of the IPv6 addresses list
|
|
+ try:
|
|
+ sd = self.addresses[0]
|
|
+ except IndexError:
|
|
+ sd = self.dst
|
|
+
|
|
if self.nh == 44 and isinstance(self.payload, IPv6ExtHdrFragment):
|
|
nh = self.payload.nh
|
|
|
|
@@ -489,6 +499,8 @@ class IPv6(_IPv6GuessPayload, Packet, IPTools):
|
|
return self.payload.answers(other.payload.payload)
|
|
elif other.nh == 43 and isinstance(other.payload, IPv6ExtHdrRouting):
|
|
return self.payload.answers(other.payload.payload) # Buggy if self.payload is a IPv6ExtHdrRouting
|
|
+ elif other.nh == 43 and isinstance(other.payload, IPv6ExtHdrSegmentRouting):
|
|
+ return self.payload.answers(other.payload.payload) # Buggy if self.payload is a IPv6ExtHdrRouting
|
|
elif other.nh == 60 and isinstance(other.payload, IPv6ExtHdrDestOpt):
|
|
return self.payload.payload.answers(other.payload.payload)
|
|
elif self.nh == 60 and isinstance(self.payload, IPv6ExtHdrDestOpt): # BU in reply to BRR, for instance
|
|
@@ -919,6 +931,148 @@ class IPv6ExtHdrRouting(_IPv6ExtHdr):
|
|
pkt = pkt[:3]+struct.pack("B", len(self.addresses))+pkt[4:]
|
|
return _IPv6ExtHdr.post_build(self, pkt, pay)
|
|
|
|
+######################### Segment Routing Header ############################
|
|
+
|
|
+# This implementation is based on draft 06, available at:
|
|
+# https://tools.ietf.org/html/draft-ietf-6man-segment-routing-header-06
|
|
+
|
|
+class IPv6ExtHdrSegmentRoutingTLV(Packet):
|
|
+ name = "IPv6 Option Header Segment Routing - Generic TLV"
|
|
+ fields_desc = [ ByteField("type", 0),
|
|
+ ByteField("len", 0),
|
|
+ ByteField("reserved", 0),
|
|
+ ByteField("flags", 0),
|
|
+ StrLenField("value", "", length_from=lambda pkt: pkt.len) ]
|
|
+
|
|
+ def extract_padding(self, p):
|
|
+ return "",p
|
|
+
|
|
+ registered_sr_tlv = {}
|
|
+ @classmethod
|
|
+ def register_variant(cls):
|
|
+ cls.registered_sr_tlv[cls.type.default] = cls
|
|
+
|
|
+ @classmethod
|
|
+ def dispatch_hook(cls, pkt=None, *args, **kargs):
|
|
+ if pkt:
|
|
+ tmp_type = ord(pkt[0])
|
|
+ return cls.registered_sr_tlv.get(tmp_type, cls)
|
|
+ return cls
|
|
+
|
|
+
|
|
+class IPv6ExtHdrSegmentRoutingTLVIngressNode(IPv6ExtHdrSegmentRoutingTLV):
|
|
+ name = "IPv6 Option Header Segment Routing - Ingress Node TLV"
|
|
+ fields_desc = [ ByteField("type", 1),
|
|
+ ByteField("len", 18),
|
|
+ ByteField("reserved", 0),
|
|
+ ByteField("flags", 0),
|
|
+ IP6Field("ingress_node", "::1") ]
|
|
+
|
|
+
|
|
+class IPv6ExtHdrSegmentRoutingTLVEgressNode(IPv6ExtHdrSegmentRoutingTLV):
|
|
+ name = "IPv6 Option Header Segment Routing - Egress Node TLV"
|
|
+ fields_desc = [ ByteField("type", 2),
|
|
+ ByteField("len", 18),
|
|
+ ByteField("reserved", 0),
|
|
+ ByteField("flags", 0),
|
|
+ IP6Field("egress_node", "::1") ]
|
|
+
|
|
+
|
|
+class IPv6ExtHdrSegmentRoutingTLVPadding(IPv6ExtHdrSegmentRoutingTLV):
|
|
+ name = "IPv6 Option Header Segment Routing - Padding TLV"
|
|
+ fields_desc = [ ByteField("type", 4),
|
|
+ FieldLenField("len", None, length_of="padding", fmt="B"),
|
|
+ StrLenField("padding", b"\x00", length_from=lambda pkt: pkt.len) ]
|
|
+
|
|
+
|
|
+class IPv6ExtHdrSegmentRouting(_IPv6ExtHdr):
|
|
+ # 0 1 2 3
|
|
+ # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
+ #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ #| Next Header | Hdr Ext Len | Routing Type | Segments Left |
|
|
+ #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ #| Last Entry | Flags | Tag |
|
|
+ #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ #| |
|
|
+ #| Segment List[0] (128 bits IPv6 address) |
|
|
+ #| |
|
|
+ #| |
|
|
+ #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ #| |
|
|
+ #| |
|
|
+ # ...
|
|
+ #| |
|
|
+ #| |
|
|
+ #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ #| |
|
|
+ #| Segment List[n] (128 bits IPv6 address) |
|
|
+ #| |
|
|
+ #| |
|
|
+ #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ #// //
|
|
+ #// Optional Type Length Value objects (variable) //
|
|
+ #// //
|
|
+ #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
+ #
|
|
+ # 0 1 2 3 4 5 6 7
|
|
+ # +-+-+-+-+-+-+-+-+
|
|
+ # |U|P|O|A|H| U |
|
|
+ # +-+-+-+-+-+-+-+-+
|
|
+
|
|
+ name = "IPv6 Segment Routing Extension Header"
|
|
+ fields_desc = [ ByteEnumField("nh", 59, ipv6nh),
|
|
+ ByteField("len", None),
|
|
+ ByteField("type", 4),
|
|
+ ByteField("segleft", None),
|
|
+ ByteField("lastentry", None),
|
|
+ BitField("unused1", 0, 1),
|
|
+ BitField("protected", 0, 1),
|
|
+ BitField("oam", 0, 1),
|
|
+ BitField("alert", 0, 1),
|
|
+ BitField("hmac", 0, 1),
|
|
+ BitField("unused2", 0, 3),
|
|
+ ShortField("tag", 0),
|
|
+ IP6ListField("addresses", ["::1"],
|
|
+ count_from=lambda pkt: pkt.lastentry+1),
|
|
+ PacketListField("tlv_objects", [], IPv6ExtHdrSegmentRoutingTLV,
|
|
+ length_from=lambda pkt: 8*pkt.len - 16*(pkt.lastentry+1)) ]
|
|
+
|
|
+ overload_fields = { IPv6: { "nh": 43 } }
|
|
+
|
|
+ def post_build(self, pkt, pay):
|
|
+
|
|
+ if self.len is None:
|
|
+
|
|
+ # The extension must be align on 8 bytes
|
|
+ tmp_mod = (len(pkt) - 8) % 8
|
|
+ if tmp_mod == 1:
|
|
+ warning("IPv6ExtHdrSegmentRouting(): can't pad 1 byte !")
|
|
+ elif tmp_mod >= 2:
|
|
+ #Add the padding extension
|
|
+ tmp_pad = b"\x00" * (tmp_mod-2)
|
|
+ tlv = IPv6ExtHdrSegmentRoutingTLVPadding(padding=tmp_pad)
|
|
+ pkt += str(tlv)
|
|
+
|
|
+ tmp_len = (len(pkt) - 8) / 8
|
|
+ pkt = pkt[:1] + struct.pack("B", tmp_len)+ pkt[2:]
|
|
+
|
|
+ if self.segleft is None:
|
|
+ tmp_len = len(self.addresses)
|
|
+ if tmp_len:
|
|
+ tmp_len -= 1
|
|
+ pkt = pkt[:3] + struct.pack("B", tmp_len) + pkt[4:]
|
|
+
|
|
+ if self.lastentry is None:
|
|
+ #km - changed to contain n-1
|
|
+ tmp_len = len(self.addresses)
|
|
+ if tmp_len:
|
|
+ tmp_len -= 1
|
|
+ #pkt = pkt[:4] + struct.pack("B", len(self.addresses)) + pkt[5:]
|
|
+ pkt = pkt[:4] + struct.pack("B", tmp_len) + pkt[5:]
|
|
+
|
|
+ return _IPv6ExtHdr.post_build(self, pkt, pay)
|
|
+
|
|
+
|
|
########################### Fragmentation Header ############################
|
|
|
|
class IPv6ExtHdrFragment(_IPv6ExtHdr):
|
|
diff --git a/scapy/layers/inet6.py b/scapy/layers/inet6.py
|
|
index 20afedf..ae3c4dd 100644
|
|
--- a/scapy/layers/inet6.py
|
|
+++ b/scapy/layers/inet6.py
|
|
@@ -3888,3 +3888,4 @@ bind_layers(IPv6, UDP, nh = socket.IPPROTO_UDP )
|
|
bind_layers(IP, IPv6, proto = socket.IPPROTO_IPV6 )
|
|
bind_layers(IPv6, IPv6, nh = socket.IPPROTO_IPV6 )
|
|
bind_layers(IPv6, IP, nh = socket.IPPROTO_IPIP )
|
|
+bind_layers(IPv6, GRE, nh = socket.IPPROTO_GRE )
|