| # This file is part of Scapy |
| # Scapy is free software: you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation, either version 2 of the License, or |
| # any later version. |
| # |
| # Scapy is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License |
| # along with Scapy. If not, see <http://www.gnu.org/licenses/>. |
| |
| # scapy.contrib.description = NSH Protocol |
| # scapy.contrib.status = loads |
| |
| from scapy.all import bind_layers |
| from scapy.fields import BitField, ByteField, ByteEnumField |
| from scapy.fields import ShortField, X3BytesField, XIntField |
| from scapy.fields import ConditionalField, PacketListField, BitFieldLenField |
| from scapy.layers.inet import Ether, IP |
| from scapy.layers.inet6 import IPv6 |
| from scapy.layers.vxlan import VXLAN |
| from scapy.packet import Packet |
| from scapy.layers.l2 import GRE |
| |
| from scapy.contrib.mpls import MPLS |
| |
| # |
| # NSH Support |
| # https://www.ietf.org/id/draft-ietf-sfc-nsh-05.txt |
| # |
| |
| |
| class Metadata(Packet): |
| name = 'NSH metadata' |
| fields_desc = [XIntField('value', 0)] |
| |
| |
| class NSHTLV(Packet): |
| "NSH MD-type 2 - Variable Length Context Headers" |
| name = "NSHTLV" |
| fields_desc = [ |
| ShortField('Class', 0), |
| BitField('Critical', 0, 1), |
| BitField('Type', 0, 7), |
| BitField('Reserved', 0, 3), |
| BitField('Len', 0, 5), |
| PacketListField('Metadata', None, XIntField, count_from='Len') |
| ] |
| |
| |
| class NSH(Packet): |
| """Network Service Header. |
| NSH MD-type 1 if there is no ContextHeaders""" |
| name = "NSH" |
| |
| fields_desc = [ |
| BitField('Ver', 0, 2), |
| BitField('OAM', 0, 1), |
| BitField('Critical', 0, 1), |
| BitField('Reserved', 0, 6), |
| BitFieldLenField('Len', None, 6, |
| count_of='ContextHeaders', |
| adjust=lambda pkt, x: 6 if pkt.MDType == 1 else x + 2), |
| ByteEnumField('MDType', 1, {1: 'Fixed Length', |
| 2: 'Variable Length'}), |
| ByteEnumField('NextProto', 3, {1: 'IPv4', |
| 2: 'IPv6', |
| 3: 'Ethernet', |
| 4: 'NSH', |
| 5: 'MPLS'}), |
| X3BytesField('NSP', 0), |
| ByteField('NSI', 1), |
| ConditionalField(XIntField('NPC', 0), lambda pkt: pkt.MDType == 1), |
| ConditionalField(XIntField('NSC', 0), lambda pkt: pkt.MDType == 1), |
| ConditionalField(XIntField('SPC', 0), lambda pkt: pkt.MDType == 1), |
| ConditionalField(XIntField('SSC', 0), lambda pkt: pkt.MDType == 1), |
| ConditionalField(PacketListField("ContextHeaders", None, |
| NSHTLV, count_from="Length"), |
| lambda pkt: pkt.MDType == 2) |
| ] |
| |
| def mysummary(self): |
| return self.sprintf("NSP: %NSP% - NSI: %NSI%") |
| |
| |
| bind_layers(Ether, NSH, {'type': 0x894F}, type=0x894F) |
| bind_layers(VXLAN, NSH, {'flags': 0xC, 'NextProtocol': 4}, NextProtocol=4) |
| bind_layers(GRE, NSH, {'proto': 0x894F}, proto=0x894F) |
| |
| bind_layers(NSH, IP, {'NextProto': 1}, NextProto=1) |
| bind_layers(NSH, IPv6, {'NextProto': 2}, NextProto=2) |
| bind_layers(NSH, Ether, {'NextProto': 3}, NextProto=3) |
| bind_layers(NSH, NSH, {'NextProto': 4}, NextProto=4) |
| bind_layers(NSH, MPLS, {'NextProto': 5}, NextProto=5) |