1 diff --git a/scapy/layers/inet6.py b/scapy/layers/inet6.py
2 index 03b80ec..06ef27f 100644
3 --- a/scapy/layers/inet6.py
4 +++ b/scapy/layers/inet6.py
5 @@ -369,6 +369,8 @@ class _IPv6GuessPayload:
7 elif self.nh == 135 and len(p) > 3: # Mobile IPv6
8 return _mip6_mhtype2cls.get(ord(p[2]), MIP6MH_Generic)
9 + elif self.nh == 43 and ord(p[2]) == 4: # Segment Routing header
10 + return IPv6ExtHdrSegmentRouting
12 return get_cls(ipv6nhcls.get(self.nh,"Raw"), "Raw")
14 @@ -430,6 +432,14 @@ class IPv6(_IPv6GuessPayload, Packet, IPTools):
16 sd = inet_ntop(socket.AF_INET6, sd)
18 + if self.nh == 43 and isinstance(self.payload, IPv6ExtHdrSegmentRouting):
19 + # With segment routing header (rh == 4), the destination is
20 + # the first address of the IPv6 addresses list
22 + sd = self.addresses[0]
26 if self.nh == 44 and isinstance(self.payload, IPv6ExtHdrFragment):
29 @@ -489,6 +499,8 @@ class IPv6(_IPv6GuessPayload, Packet, IPTools):
30 return self.payload.answers(other.payload.payload)
31 elif other.nh == 43 and isinstance(other.payload, IPv6ExtHdrRouting):
32 return self.payload.answers(other.payload.payload) # Buggy if self.payload is a IPv6ExtHdrRouting
33 + elif other.nh == 43 and isinstance(other.payload, IPv6ExtHdrSegmentRouting):
34 + return self.payload.answers(other.payload.payload) # Buggy if self.payload is a IPv6ExtHdrRouting
35 elif other.nh == 60 and isinstance(other.payload, IPv6ExtHdrDestOpt):
36 return self.payload.payload.answers(other.payload.payload)
37 elif self.nh == 60 and isinstance(self.payload, IPv6ExtHdrDestOpt): # BU in reply to BRR, for instance
38 @@ -919,6 +931,148 @@ class IPv6ExtHdrRouting(_IPv6ExtHdr):
39 pkt = pkt[:3]+struct.pack("B", len(self.addresses))+pkt[4:]
40 return _IPv6ExtHdr.post_build(self, pkt, pay)
42 +######################### Segment Routing Header ############################
44 +# This implementation is based on draft 06, available at:
45 +# https://tools.ietf.org/html/draft-ietf-6man-segment-routing-header-06
47 +class IPv6ExtHdrSegmentRoutingTLV(Packet):
48 + name = "IPv6 Option Header Segment Routing - Generic TLV"
49 + fields_desc = [ ByteField("type", 0),
50 + ByteField("len", 0),
51 + ByteField("reserved", 0),
52 + ByteField("flags", 0),
53 + StrLenField("value", "", length_from=lambda pkt: pkt.len) ]
55 + def extract_padding(self, p):
58 + registered_sr_tlv = {}
60 + def register_variant(cls):
61 + cls.registered_sr_tlv[cls.type.default] = cls
64 + def dispatch_hook(cls, pkt=None, *args, **kargs):
66 + tmp_type = ord(pkt[0])
67 + return cls.registered_sr_tlv.get(tmp_type, cls)
71 +class IPv6ExtHdrSegmentRoutingTLVIngressNode(IPv6ExtHdrSegmentRoutingTLV):
72 + name = "IPv6 Option Header Segment Routing - Ingress Node TLV"
73 + fields_desc = [ ByteField("type", 1),
74 + ByteField("len", 18),
75 + ByteField("reserved", 0),
76 + ByteField("flags", 0),
77 + IP6Field("ingress_node", "::1") ]
80 +class IPv6ExtHdrSegmentRoutingTLVEgressNode(IPv6ExtHdrSegmentRoutingTLV):
81 + name = "IPv6 Option Header Segment Routing - Egress Node TLV"
82 + fields_desc = [ ByteField("type", 2),
83 + ByteField("len", 18),
84 + ByteField("reserved", 0),
85 + ByteField("flags", 0),
86 + IP6Field("egress_node", "::1") ]
89 +class IPv6ExtHdrSegmentRoutingTLVPadding(IPv6ExtHdrSegmentRoutingTLV):
90 + name = "IPv6 Option Header Segment Routing - Padding TLV"
91 + fields_desc = [ ByteField("type", 4),
92 + FieldLenField("len", None, length_of="padding", fmt="B"),
93 + StrLenField("padding", b"\x00", length_from=lambda pkt: pkt.len) ]
96 +class IPv6ExtHdrSegmentRouting(_IPv6ExtHdr):
98 + # 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
99 + #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
100 + #| Next Header | Hdr Ext Len | Routing Type | Segments Left |
101 + #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
102 + #| Last Entry | Flags | Tag |
103 + #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
105 + #| Segment List[0] (128 bits IPv6 address) |
108 + #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
114 + #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
116 + #| Segment List[n] (128 bits IPv6 address) |
119 + #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
121 + #// Optional Type Length Value objects (variable) //
123 + #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
126 + # +-+-+-+-+-+-+-+-+
128 + # +-+-+-+-+-+-+-+-+
130 + name = "IPv6 Segment Routing Extension Header"
131 + fields_desc = [ ByteEnumField("nh", 143, ipv6nh),
132 + ByteField("len", None),
133 + ByteField("type", 4),
134 + ByteField("segleft", None),
135 + ByteField("lastentry", None),
136 + BitField("unused1", 0, 1),
137 + BitField("protected", 0, 1),
138 + BitField("oam", 0, 1),
139 + BitField("alert", 0, 1),
140 + BitField("hmac", 0, 1),
141 + BitField("unused2", 0, 3),
142 + ShortField("tag", 0),
143 + IP6ListField("addresses", ["::1"],
144 + count_from=lambda pkt: pkt.lastentry+1),
145 + PacketListField("tlv_objects", [], IPv6ExtHdrSegmentRoutingTLV,
146 + length_from=lambda pkt: 8*pkt.len - 16*(pkt.lastentry+1)) ]
148 + overload_fields = { IPv6: { "nh": 43 } }
150 + def post_build(self, pkt, pay):
152 + if self.len is None:
154 + # The extension must be align on 8 bytes
155 + tmp_mod = (len(pkt) - 8) % 8
157 + warning("IPv6ExtHdrSegmentRouting(): can't pad 1 byte !")
159 + #Add the padding extension
160 + tmp_pad = b"\x00" * (tmp_mod-2)
161 + tlv = IPv6ExtHdrSegmentRoutingTLVPadding(padding=tmp_pad)
164 + tmp_len = (len(pkt) - 8) / 8
165 + pkt = pkt[:1] + struct.pack("B", tmp_len)+ pkt[2:]
167 + if self.segleft is None:
168 + tmp_len = len(self.addresses)
171 + pkt = pkt[:3] + struct.pack("B", tmp_len) + pkt[4:]
173 + if self.lastentry is None:
174 + #km - changed to contain n-1
175 + tmp_len = len(self.addresses)
178 + #pkt = pkt[:4] + struct.pack("B", len(self.addresses)) + pkt[5:]
179 + pkt = pkt[:4] + struct.pack("B", tmp_len) + pkt[5:]
181 + return _IPv6ExtHdr.post_build(self, pkt, pay)
184 ########################### Fragmentation Header ############################
186 class IPv6ExtHdrFragment(_IPv6ExtHdr):
187 diff --git a/scapy/layers/inet6.py b/scapy/layers/inet6.py
188 index 20afedf..ae3c4dd 100644
189 --- a/scapy/layers/inet6.py
190 +++ b/scapy/layers/inet6.py
191 @@ -3888,3 +3888,4 @@ bind_layers(IPv6, UDP, nh = socket.IPPROTO_UDP )
192 bind_layers(IP, IPv6, proto = socket.IPPROTO_IPV6 )
193 bind_layers(IPv6, IPv6, nh = socket.IPPROTO_IPV6 )
194 bind_layers(IPv6, IP, nh = socket.IPPROTO_IPIP )
195 +bind_layers(IPv6, GRE, nh = socket.IPPROTO_GRE )