diff --git a/scapy/contrib/nsh.py b/scapy/contrib/nsh.py index 8175e9a7627..cf6df807c55 100644 --- a/scapy/contrib/nsh.py +++ b/scapy/contrib/nsh.py @@ -8,7 +8,7 @@ from scapy.all import bind_layers from scapy.fields import BitField, ByteField, ByteEnumField, BitEnumField, \ ShortField, X3BytesField, XIntField, XStrFixedLenField, \ - ConditionalField, PacketListField, BitFieldLenField + ConditionalField, FieldListField, PacketListField, BitFieldLenField from scapy.layers.inet import Ether, IP from scapy.layers.inet6 import IPv6 from scapy.layers.vxlan import VXLAN @@ -30,10 +30,15 @@ class NSHTLV(Packet): ShortField('class_', 0), BitField('type', 0, 8), BitField('reserved', 0, 1), - BitField('length', 0, 7), - PacketListField('metadata', None, XIntField, count_from='length') + BitFieldLenField('length', None, 7, count_of='metadata', + adjust=lambda pkt, x: x * 4), + FieldListField('metadata', [], XIntField('', 0), + length_from=lambda pkt: (pkt.length + 3) // 4 * 4) ] + def extract_padding(self, s): + return b'', s + class NSH(Packet): """Network Service Header. @@ -46,9 +51,9 @@ class NSH(Packet): BitField('unused1', 0, 1), BitField('ttl', 63, 6), BitFieldLenField('length', None, 6, - count_of='vlch', + length_of='vlch', adjust=lambda pkt, x: 6 if pkt.mdtype == 1 - else x + 2), + else x // 4 + 2), BitField('unused2', 0, 4), BitEnumField('mdtype', 1, 4, {0: 'Reserved MDType', 1: 'Fixed Length', @@ -65,9 +70,10 @@ class NSH(Packet): ByteField('si', 0xFF), ConditionalField(XStrFixedLenField("context_header", "", 16), lambda pkt: pkt.mdtype == 1), - ConditionalField(PacketListField("vlch", None, NSHTLV, - count_from="length"), - lambda pkt: pkt.mdtype == 2) + ConditionalField(PacketListField( + "vlch", None, NSHTLV, + length_from=lambda pkt: (pkt.length - 2) * 4), + lambda pkt: pkt.mdtype == 2) ] def mysummary(self): diff --git a/test/contrib/nsh.uts b/test/contrib/nsh.uts index 0751edd1338..3885ed5fadb 100644 --- a/test/contrib/nsh.uts +++ b/test/contrib/nsh.uts @@ -18,3 +18,30 @@ raw(NSH(mdtype=2, spi=0xF0F0F0, si=0xFF)) == b'\x0f\xc2\x02\x03\xf0\xf0\xf0\xff = Build a NSH over VXLAN packet and verify bindings raw(Ether(dst='0c:42:a1:5f:fb:e0', src='b8:59:9f:cd:de:3e')/IPv6(src='::1', dst='::2')/UDP(sport=10, dport=8472)/VXLAN(NextProtocol=4, vni=4660)/NSH()/NSH()/Ether(dst='0c:42:a1:5f:fb:e4', src='b8:59:9f:cd:de:33')/IP(src='10.200.100.10', dst='2.2.2.3')/TCP(sport=123, dport=333)) == b'\x0cB\xa1_\xfb\xe0\xb8Y\x9f\xcd\xde>\x86\xdd`\x00\x00\x00\x00v\x11@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\n!\x18\x00v\x05F\x0c\x00\x00\x04\x00\x124\x00\x0f\xc6\x01\x04\x00\x00\x00\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\xc6\x01\x03\x00\x00\x00\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0cB\xa1_\xfb\xe4\xb8Y\x9f\xcd\xde3\x08\x00E\x00\x00(\x00\x01\x00\x00@\x06\x07\xf9\n\xc8d\n\x02\x02\x02\x03\x00{\x01M\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00\x1bD\x00\x00' + ++ MD-Type 2 variable length context headers + += Dissect a NSH MD-Type 2 packet carrying one context header +p = NSH(hex_bytes('0fc40203000001ff00010204deadbeef')) +assert p.mdtype == 2 +assert p.length == 4 +assert len(p.vlch) == 1 +assert p.vlch[0].class_ == 1 +assert p.vlch[0].type == 2 +assert p.vlch[0].length == 4 +assert p.vlch[0].metadata == [0xdeadbeef] +assert raw(p) == hex_bytes('0fc40203000001ff00010204deadbeef') + += Dissect a NSH MD-Type 2 packet carrying two context headers +p = NSH(hex_bytes('0fc60203000001ff00010204deadbeef00020104cafebabe')) +assert p.length == 6 +assert len(p.vlch) == 2 +assert p.vlch[0].metadata == [0xdeadbeef] +assert p.vlch[1].class_ == 2 +assert p.vlch[1].metadata == [0xcafebabe] +assert raw(p) == hex_bytes('0fc60203000001ff00010204deadbeef00020104cafebabe') + += Build a NSH MD-Type 2 packet and check the computed length +p = NSH(mdtype=2, nextproto=3, spi=1, si=255, vlch=[NSHTLV(class_=1, type=2, metadata=[0xdeadbeef])]) +assert raw(p) == hex_bytes('0fc40203000001ff00010204deadbeef') +assert NSH(raw(p)).length == 4