blob: 706e19738c4b24935a33375fbcb00253a17349ce [file] [log] [blame]
Kris Michielsen91074432017-06-22 13:00:20 +02001diff --git a/scapy/layers/inet6.py b/scapy/layers/inet6.py
Klement Sekera75e7d132017-09-20 08:26:30 +02002index 03b80ec..06ef27f 100644
3--- a/scapy/layers/inet6.py
4+++ b/scapy/layers/inet6.py
5@@ -369,6 +369,8 @@ class _IPv6GuessPayload:
Kris Michielsen91074432017-06-22 13:00:20 +02006 return Raw
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
11 else:
12 return get_cls(ipv6nhcls.get(self.nh,"Raw"), "Raw")
Klement Sekera75e7d132017-09-20 08:26:30 +020013
14@@ -430,6 +432,14 @@ class IPv6(_IPv6GuessPayload, Packet, IPTools):
Kris Michielsen91074432017-06-22 13:00:20 +020015 sd = strxor(sd, a)
16 sd = inet_ntop(socket.AF_INET6, sd)
Klement Sekera75e7d132017-09-20 08:26:30 +020017
Kris Michielsen91074432017-06-22 13:00:20 +020018+ 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
21+ try:
22+ sd = self.addresses[0]
23+ except IndexError:
24+ sd = self.dst
25+
26 if self.nh == 44 and isinstance(self.payload, IPv6ExtHdrFragment):
Klement Sekera75e7d132017-09-20 08:26:30 +020027 nh = self.payload.nh
28
29@@ -489,6 +499,8 @@ class IPv6(_IPv6GuessPayload, Packet, IPTools):
30 return self.payload.answers(other.payload.payload)
Kris Michielsen91074432017-06-22 13:00:20 +020031 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
Klement Sekera75e7d132017-09-20 08:26:30 +020038@@ -919,6 +931,148 @@ class IPv6ExtHdrRouting(_IPv6ExtHdr):
Kris Michielsen91074432017-06-22 13:00:20 +020039 pkt = pkt[:3]+struct.pack("B", len(self.addresses))+pkt[4:]
40 return _IPv6ExtHdr.post_build(self, pkt, pay)
Klement Sekera75e7d132017-09-20 08:26:30 +020041
Kris Michielsen91074432017-06-22 13:00:20 +020042+######################### Segment Routing Header ############################
43+
44+# This implementation is based on draft 06, available at:
45+# https://tools.ietf.org/html/draft-ietf-6man-segment-routing-header-06
46+
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) ]
54+
55+ def extract_padding(self, p):
56+ return "",p
57+
58+ registered_sr_tlv = {}
59+ @classmethod
60+ def register_variant(cls):
61+ cls.registered_sr_tlv[cls.type.default] = cls
62+
63+ @classmethod
64+ def dispatch_hook(cls, pkt=None, *args, **kargs):
65+ if pkt:
66+ tmp_type = ord(pkt[0])
67+ return cls.registered_sr_tlv.get(tmp_type, cls)
68+ return cls
69+
70+
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") ]
78+
79+
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") ]
87+
88+
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) ]
94+
95+
96+class IPv6ExtHdrSegmentRouting(_IPv6ExtHdr):
97+ # 0 1 2 3
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+ #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104+ #| |
105+ #| Segment List[0] (128 bits IPv6 address) |
106+ #| |
107+ #| |
108+ #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
109+ #| |
110+ #| |
111+ # ...
112+ #| |
113+ #| |
114+ #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
115+ #| |
116+ #| Segment List[n] (128 bits IPv6 address) |
117+ #| |
118+ #| |
119+ #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
120+ #// //
121+ #// Optional Type Length Value objects (variable) //
122+ #// //
123+ #+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
124+ #
125+ # 0 1 2 3 4 5 6 7
126+ # +-+-+-+-+-+-+-+-+
127+ # |U|P|O|A|H| U |
128+ # +-+-+-+-+-+-+-+-+
129+
130+ name = "IPv6 Segment Routing Extension Header"
131+ fields_desc = [ ByteEnumField("nh", 59, 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)) ]
147+
148+ overload_fields = { IPv6: { "nh": 43 } }
149+
150+ def post_build(self, pkt, pay):
151+
152+ if self.len is None:
153+
154+ # The extension must be align on 8 bytes
155+ tmp_mod = (len(pkt) - 8) % 8
156+ if tmp_mod == 1:
157+ warning("IPv6ExtHdrSegmentRouting(): can't pad 1 byte !")
158+ elif tmp_mod >= 2:
159+ #Add the padding extension
160+ tmp_pad = b"\x00" * (tmp_mod-2)
161+ tlv = IPv6ExtHdrSegmentRoutingTLVPadding(padding=tmp_pad)
162+ pkt += str(tlv)
163+
164+ tmp_len = (len(pkt) - 8) / 8
165+ pkt = pkt[:1] + struct.pack("B", tmp_len)+ pkt[2:]
166+
167+ if self.segleft is None:
168+ tmp_len = len(self.addresses)
169+ if tmp_len:
170+ tmp_len -= 1
171+ pkt = pkt[:3] + struct.pack("B", tmp_len) + pkt[4:]
172+
173+ if self.lastentry is None:
174+ #km - changed to contain n-1
175+ tmp_len = len(self.addresses)
176+ if tmp_len:
177+ tmp_len -= 1
178+ #pkt = pkt[:4] + struct.pack("B", len(self.addresses)) + pkt[5:]
179+ pkt = pkt[:4] + struct.pack("B", tmp_len) + pkt[5:]
180+
181+ return _IPv6ExtHdr.post_build(self, pkt, pay)
182+
183+
184 ########################### Fragmentation Header ############################
185
186 class IPv6ExtHdrFragment(_IPv6ExtHdr):
Neale Ranns8716e6b2017-12-13 02:47:27 -0800187diff --git a/scapy/layers/inet6.py b/scapy/layers/inet6.py
188index 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 )