Home | History | Annotate | Download | only in contrib
      1 # This file is part of Scapy
      2 # Scapy is free software: you can redistribute it and/or modify
      3 # it under the terms of the GNU General Public License as published by
      4 # the Free Software Foundation, either version 2 of the License, or
      5 # any later version.
      6 #
      7 # Scapy is distributed in the hope that it will be useful,
      8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     10 # GNU General Public License for more details.
     11 #
     12 # You should have received a copy of the GNU General Public License
     13 # along with Scapy. If not, see <http://www.gnu.org/licenses/>.
     14 
     15 # scapy.contrib.description = NSH Protocol
     16 # scapy.contrib.status = loads
     17 
     18 from scapy.all import bind_layers
     19 from scapy.fields import BitField, ByteField, ByteEnumField
     20 from scapy.fields import ShortField, X3BytesField, XIntField
     21 from scapy.fields import ConditionalField, PacketListField, BitFieldLenField
     22 from scapy.layers.inet import Ether, IP
     23 from scapy.layers.inet6 import IPv6
     24 from scapy.layers.vxlan import VXLAN
     25 from scapy.packet import Packet
     26 from scapy.layers.l2 import GRE
     27 
     28 from scapy.contrib.mpls import MPLS
     29 
     30 #
     31 # NSH Support
     32 # https://www.ietf.org/id/draft-ietf-sfc-nsh-05.txt
     33 #
     34 
     35 
     36 class Metadata(Packet):
     37     name = 'NSH metadata'
     38     fields_desc = [XIntField('value', 0)]
     39 
     40 
     41 class NSHTLV(Packet):
     42     "NSH MD-type 2 - Variable Length Context Headers"
     43     name = "NSHTLV"
     44     fields_desc = [
     45         ShortField('Class', 0),
     46         BitField('Critical', 0, 1),
     47         BitField('Type', 0, 7),
     48         BitField('Reserved', 0, 3),
     49         BitField('Len', 0, 5),
     50         PacketListField('Metadata', None, XIntField, count_from='Len')
     51     ]
     52 
     53 
     54 class NSH(Packet):
     55     """Network Service Header.
     56        NSH MD-type 1 if there is no ContextHeaders"""
     57     name = "NSH"
     58 
     59     fields_desc = [
     60         BitField('Ver', 0, 2),
     61         BitField('OAM', 0, 1),
     62         BitField('Critical', 0, 1),
     63         BitField('Reserved', 0, 6),
     64         BitFieldLenField('Len', None, 6,
     65                          count_of='ContextHeaders',
     66                          adjust=lambda pkt, x: 6 if pkt.MDType == 1 else x + 2),
     67         ByteEnumField('MDType', 1, {1: 'Fixed Length',
     68                                     2: 'Variable Length'}),
     69         ByteEnumField('NextProto', 3, {1: 'IPv4',
     70                                        2: 'IPv6',
     71                                        3: 'Ethernet',
     72                                        4: 'NSH',
     73                                        5: 'MPLS'}),
     74         X3BytesField('NSP', 0),
     75         ByteField('NSI', 1),
     76         ConditionalField(XIntField('NPC', 0), lambda pkt: pkt.MDType == 1),
     77         ConditionalField(XIntField('NSC', 0), lambda pkt: pkt.MDType == 1),
     78         ConditionalField(XIntField('SPC', 0), lambda pkt: pkt.MDType == 1),
     79         ConditionalField(XIntField('SSC', 0), lambda pkt: pkt.MDType == 1),
     80         ConditionalField(PacketListField("ContextHeaders", None,
     81                                          NSHTLV, count_from="Length"),
     82                          lambda pkt: pkt.MDType == 2)
     83         ]
     84 
     85     def mysummary(self):
     86         return self.sprintf("NSP: %NSP% - NSI: %NSI%")
     87 
     88 
     89 bind_layers(Ether, NSH, {'type': 0x894F}, type=0x894F)
     90 bind_layers(VXLAN, NSH, {'flags': 0xC, 'NextProtocol': 4}, NextProtocol=4)
     91 bind_layers(GRE, NSH, {'proto': 0x894F}, proto=0x894F)
     92 
     93 bind_layers(NSH, IP, {'NextProto': 1}, NextProto=1)
     94 bind_layers(NSH, IPv6, {'NextProto': 2}, NextProto=2)
     95 bind_layers(NSH, Ether, {'NextProto': 3}, NextProto=3)
     96 bind_layers(NSH, NSH, {'NextProto': 4}, NextProto=4)
     97 bind_layers(NSH, MPLS, {'NextProto': 5}, NextProto=5)
     98