Skip to content

Commit

Permalink
[isis.py] Add support for some SubTLVs (#305)
Browse files Browse the repository at this point in the history
* [isis.py] Add support for some SubTLVs
* [isis.py, isis.uts] Fix, (unit-)test and extend SubTLVs support
  • Loading branch information
mkaliszan authored and p-l- committed Dec 16, 2016
1 parent 45c5930 commit f912538
Show file tree
Hide file tree
Showing 3 changed files with 227 additions and 52 deletions.
184 changes: 140 additions & 44 deletions scapy/contrib/isis.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
IS-IS Scapy Extension
~~~~~~~~~~~~~~~~~~~~~
:copyright: 2014, 2015 BENOCS GmbH, Berlin (Germany)
:copyright: 2014-2016 BENOCS GmbH, Berlin (Germany)
:author: Marcel Patzlaff, mpatzlaff@benocs.com
Michal Kaliszan, mkaliszan@benocs.com
:license: GPLv2
This module is free software; you can redistribute it and/or
Expand Down Expand Up @@ -52,10 +53,13 @@
from scapy.fields import *
from scapy.packet import *
from scapy.layers.clns import network_layer_protocol_ids, register_cln_protocol
from scapy.layers.inet6 import IP6ListField
from scapy.layers.inet6 import IP6ListField, IP6Field
from scapy.utils import fletcher16_checkbytes
from scapy.volatile import RandString, RandByte
import random


EXT_VERSION = "v0.0.1"
EXT_VERSION = "v0.0.2"

conf.debug_dissector = True

Expand Down Expand Up @@ -206,9 +210,128 @@ def randval(self):
class ISIS_CircuitTypeField(FlagsField):
def __init__(self, name="circuittype", default=2, size=8,
names=None):
FlagsField.__init__(self, name, default, size, names)
if names is None:
names = ["L1", "L2", "r0", "r1", "r2", "r3", "r4", "r5"]
FlagsField.__init__(self, name, default, size, names)


def _ISIS_GuessTlvClass_Helper(tlv_classes, defaultname, p, **kargs):
cls = conf.raw_layer
if len(p) >= 2:
tlvtype = struct.unpack("!B", p[0])[0]
clsname = tlv_classes.get(tlvtype, defaultname)
cls = globals()[clsname]

return cls(p, **kargs)


class _ISIS_GenericTlv_Base(Packet):
fields_desc = [ByteField("type", 0),
FieldLenField("len", None, length_of="val", fmt="B"),
BoundStrLenField("val", "", length_from=lambda pkt: pkt.len)]

def guess_payload_class(self, p):
return conf.padding_layer


class ISIS_GenericTlv(_ISIS_GenericTlv_Base):
name = "ISIS Generic TLV"


class ISIS_GenericSubTlv(_ISIS_GenericTlv_Base):
name = "ISIS Generic Sub-TLV"


#######################################################################
## ISIS Sub-TLVs for TLVs 22, 23, 141, 222, 223 ##
#######################################################################
_isis_subtlv_classes_1 = {
4: "ISIS_LinkLocalRemoteIdentifiersSubTlv",
6: "ISIS_IPv4InterfaceAddressSubTlv",
8: "ISIS_IPv4NeighborAddressSubTlv",
12: "ISIS_IPv6InterfaceAddressSubTlv",
13: "ISIS_IPv6NeighborAddressSubTlv"
}

_isis_subtlv_names_1 = {
4: "Link Local/Remote Identifiers",
6: "IPv4 Interface Address",
8: "IPv4 Neighbor Address",
12: "IPv6 Interface Address",
13: "IPv6 Neighbor Address"
}


def _ISIS_GuessSubTlvClass_1(p, **kargs):
return _ISIS_GuessTlvClass_Helper(_isis_subtlv_classes_1, "ISIS_GenericSubTlv", p, **kargs)


class ISIS_IPv4InterfaceAddressSubTlv(ISIS_GenericSubTlv):
name = "ISIS IPv4 Interface Address (S)"
fields_desc = [ByteEnumField("type", 6, _isis_subtlv_names_1),
FieldLenField("len", None, length_of= "address", fmt="B"),
IPField("address", "0.0.0.0")]


class ISIS_IPv4NeighborAddressSubTlv(ISIS_GenericSubTlv):
name = "ISIS IPv4 Neighbor Address (S)"
fields_desc = [ByteEnumField("type", 8, _isis_subtlv_names_1),
FieldLenField("len", None, length_of= "address", fmt="B"),
IPField("address", "0.0.0.0")]


class ISIS_LinkLocalRemoteIdentifiersSubTlv(ISIS_GenericSubTlv):
name = "ISIS Link Local/Remote Identifiers (S)"
fields_desc = [ByteEnumField("type", 4, _isis_subtlv_names_1),
FieldLenField("len", 8, fmt="B"),
IntField("localid", "0"),
IntField("remoteid", "0")]


class ISIS_IPv6InterfaceAddressSubTlv(ISIS_GenericSubTlv):
name = "ISIS IPv6 Interface Address (S)"
fields_desc = [ByteEnumField("type", 12, _isis_subtlv_names_1),
FieldLenField("len", None, length_of= "address", fmt="B"),
IP6Field("address", "::")]


class ISIS_IPv6NeighborAddressSubTlv(ISIS_GenericSubTlv):
name = "ISIS IPv6 Neighbor Address (S)"
fields_desc = [ByteEnumField("type", 13, _isis_subtlv_names_1),
FieldLenField("len", None, length_of= "address", fmt="B"),
IP6Field("address", "::")]


#######################################################################
## ISIS Sub-TLVs for TLVs 135, 235, 236, and 237 ##
#######################################################################
_isis_subtlv_classes_2 = {
1: "ISIS_32bitAdministrativeTagSubTlv",
2: "ISIS_64bitAdministrativeTagSubTlv"
}

_isis_subtlv_names_2 = {
1: "32-bit Administrative Tag",
2: "64-bit Administrative Tag"
}


def _ISIS_GuessSubTlvClass_2(p, **kargs):
return _ISIS_GuessTlvClass_Helper(_isis_subtlv_classes_2, "ISIS_GenericSubTlv", p, **kargs)


class ISIS_32bitAdministrativeTagSubTlv(ISIS_GenericSubTlv):
name = "ISIS 32-bit Administrative Tag (S)"
fields_desc = [ByteEnumField("type", 1, _isis_subtlv_names_2),
FieldLenField("len", None, length_of= "tags", fmt="B"),
FieldListField("tags", [], IntField("", 0), count_from= lambda pkt: pkt.len / 4)]


class ISIS_64bitAdministrativeTagSubTlv(ISIS_GenericSubTlv):
name = "ISIS 64-bit Administrative Tag (S)"
fields_desc = [ByteEnumField("type", 2, _isis_subtlv_names_2),
FieldLenField("len", None, length_of= "tags", fmt="B"),
FieldListField("tags", [], LongField("", 0), count_from= lambda pkt: pkt.len / 8)]


#######################################################################
Expand Down Expand Up @@ -283,23 +406,7 @@ def __init__(self, name="circuittype", default=2, size=8,


def _ISIS_GuessTlvClass(p, **kargs):
cls = conf.raw_layer
if len(p) >= 2:
tlvtype = struct.unpack("!B", p[0])[0]
clsname = _isis_tlv_classes.get(tlvtype, "ISIS_GenericTlv")
cls = globals()[clsname]

return cls(p, **kargs)


class ISIS_GenericTlv(Packet):
name = "ISIS Generic TLV"
fields_desc = [ByteEnumField("type", 0, _isis_tlv_names),
FieldLenField("len", None, length_of="val", fmt="B"),
BoundStrLenField("val", "", length_from=lambda pkt: pkt.len)]

def guess_payload_class(self, p):
return conf.padding_layer
return _ISIS_GuessTlvClass_Helper(_isis_tlv_classes, "ISIS_GenericTlv", p, **kargs)


class ISIS_AreaEntry(Packet):
Expand Down Expand Up @@ -347,20 +454,6 @@ class ISIS_DynamicHostnameTlv(ISIS_GenericTlv):
BoundStrLenField("hostname", "", length_from=lambda pkt: pkt.len)]


class ISIS_GenericSubTlv(Packet):
name = "ISIS Generic Sub-TLV"
fields_desc = [ByteField("type", 0),
FieldLenField("len", None, length_of="val", fmt="B"),
BoundStrLenField("val", "", length_from=lambda pkt: pkt.len)]

def guess_payload_class(self, p):
return conf.padding_layer


def _isis_guess_subtlv_cls(p, **kargs):
return ISIS_GenericSubTlv(p, **kargs)


class ISIS_ExtendedIpPrefix(Packet):
name = "ISIS Extended IP Prefix"
fields_desc = [
Expand All @@ -369,8 +462,8 @@ class ISIS_ExtendedIpPrefix(Packet):
BitField("subtlvindicator", 0, 1),
BitFieldLenField("pfxlen", None, 6, length_of="pfx"),
IPPrefixField("pfx", None, wordbytes=1, length_from=lambda x: x.pfxlen),
ConditionalField(FieldLenField("subtlvslen", None, length_of=lambda x: x.subtlvs, fmt= "B"), lambda pkt: pkt.subtlvindicator == 1),
ConditionalField(PacketListField("subtlvs", [], _isis_guess_subtlv_cls, length_from=lambda x: x.subtlvslen), lambda pkt: pkt.subtlvindicator == 1)
ConditionalField(FieldLenField("subtlvslen", None, length_of="subtlvs", fmt= "B"), lambda pkt: pkt.subtlvindicator == 1),
ConditionalField(PacketListField("subtlvs", [], _ISIS_GuessSubTlvClass_2, length_from=lambda x: x.subtlvslen), lambda pkt: pkt.subtlvindicator == 1)
]

def extract_padding(self, s):
Expand All @@ -386,15 +479,17 @@ class ISIS_ExtendedIpReachabilityTlv(ISIS_GenericTlv):

class ISIS_ExtendedIsNeighbourEntry(Packet):
name = "ISIS Extended IS Neighbour Entry"
fields_desc = [ISIS_NodeIdField("neighbourid", "0102.0304.0506.07"),
ThreeBytesField("metric", 1),
FieldLenField("subtlvslen", None, length_of="subtlvs", fmt= "B"),
ConditionalField(PacketListField("subtlvs", [], _isis_guess_subtlv_cls, length_from=lambda x: x.subtlvslen), lambda pkt: pkt.subtlvslen > 0)]
fields_desc = [
ISIS_NodeIdField("neighbourid", "0102.0304.0506.07"),
ThreeBytesField("metric", 1),
FieldLenField("subtlvslen", None, length_of="subtlvs", fmt= "B"),
PacketListField("subtlvs", [], _ISIS_GuessSubTlvClass_1, length_from=lambda x: x.subtlvslen)
]

def extract_padding(self, s):
return "", s


class ISIS_ExtendedIsReachabilityTlv(ISIS_GenericTlv):
name = "ISIS Extended IS Reachability TLV"
fields_desc = [ByteEnumField("type", 22, _isis_tlv_names),
Expand Down Expand Up @@ -428,8 +523,8 @@ class ISIS_Ipv6Prefix(Packet):
BitField("reserved", 0, 5),
FieldLenField("pfxlen", None, length_of="pfx", fmt="B"),
IP6PrefixField("pfx", None, wordbytes=1, length_from=lambda x: x.pfxlen),
ConditionalField(FieldLenField("subtlvslen", None, length_of=lambda x: x.subtlvs, fmt= "B"), lambda pkt: pkt.subtlvindicator == 1),
ConditionalField(PacketListField("subtlvs", [], _isis_guess_subtlv_cls, length_from=lambda x: x.subtlvslen), lambda pkt: pkt.subtlvindicator == 1)
ConditionalField(FieldLenField("subtlvslen", None, length_of="subtlvs", fmt= "B"), lambda pkt: pkt.subtlvindicator == 1),
ConditionalField(PacketListField("subtlvs", [], _ISIS_GuessSubTlvClass_2, length_from=lambda x: x.subtlvslen), lambda pkt: pkt.subtlvindicator == 1)
]

def extract_padding(self, s):
Expand Down Expand Up @@ -767,3 +862,4 @@ def answers(self, other):
bind_layers(ISIS_CommonHdr, ISIS_L2_CSNP, hdrlen=33, pdutype=25)
bind_layers(ISIS_CommonHdr, ISIS_L1_PSNP, hdrlen=17, pdutype=26)
bind_layers(ISIS_CommonHdr, ISIS_L2_PSNP, hdrlen=17, pdutype=27)

87 changes: 83 additions & 4 deletions scapy/contrib/isis.uts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
% IS-IS Tests
* Tests for the IS-IS layer

+ Syntax check

= Import the isis layer
from scapy.contrib.isis import *

+ Basic Layer Tests

= Layer Binding
Expand All @@ -13,9 +18,20 @@ assert(p[ISIS_CommonHdr].pdutype == 17)
assert(p[ISIS_CommonHdr].hdrlen == 20)

+ Package Tests

= P2P Hello
p = Dot3(dst="09:00:2b:00:00:05",src="00:00:00:aa:00:8c")/LLC()/ISIS_CommonHdr()/ISIS_P2P_Hello(
holdingtime=40, sourceid="1720.1600.8016",
tlvs=[
ISIS_ProtocolsSupportedTlv(nlpids=["IPv4", "IPv6"])
])
p = p.__class__(str(p))
assert(p[ISIS_P2P_Hello].pdulength == 24)
assert(network_layer_protocol_ids[p[ISIS_ProtocolsSupportedTlv].nlpids[1]] == "IPv6")

= LSP
p = Dot3(dst="09:00:2b:00:00:05",src="00:00:00:aa:00:8c")/LLC()/ISIS_CommonHdr()/ISIS_L2_LSP(
lifetime=863, lspid="1720.1600.8016.00-00", seqnum=0x1f0, typeblock="L1+L2",
lifetime=863, lspid="1720.1600.8016.00-00", seqnum=0x1f0, typeblock="L1+L2",
tlvs=[
ISIS_AreaTlv(
areas=[ISIS_AreaEntry(areaid="49.1000")]
Expand Down Expand Up @@ -50,8 +66,71 @@ p = Dot3(dst="09:00:2b:00:00:05",src="00:00:00:aa:00:8c")/LLC()/ISIS_CommonHdr()
ISIS_ExtendedIsReachabilityTlv(
neighbours=[ISIS_ExtendedIsNeighbourEntry(neighbourid="1720.1600.8004.00", metric=10)]
)
]
)
])
p = p.__class__(str(p))
assert(p[ISIS_L2_LSP].pdulength == 150)
assert(p[ISIS_L2_LSP].checksum == 0x8701)
assert(p[ISIS_L2_LSP].checksum == 0x8701)

= LSP with Sub-TLVs
p = Dot3(dst="09:00:2b:00:00:05",src="00:00:00:aa:00:8c")/LLC()/ISIS_CommonHdr()/ISIS_L2_LSP(
lifetime=863, lspid="1720.1600.8016.00-00", seqnum=0x1f0, typeblock="L1+L2",
tlvs=[
ISIS_AreaTlv(
areas=[ISIS_AreaEntry(areaid="49.1000")]
),
ISIS_ProtocolsSupportedTlv(
nlpids=["IPv4", "IPv6"]
),
ISIS_DynamicHostnameTlv(
hostname="BR-HH"
),
ISIS_IpInterfaceAddressTlv(
addresses=["172.16.8.16"]
),
ISIS_GenericTlv(
type=134,
val="\xac\x10\x08\x10"
),
ISIS_ExtendedIpReachabilityTlv(
pfxs=[
ISIS_ExtendedIpPrefix(metric=0, pfx="172.16.8.16/32"),
ISIS_ExtendedIpPrefix(metric=10, pfx="10.1.0.109/30", subtlvindicator=1,
subtlvs=[
ISIS_32bitAdministrativeTagSubTlv(tags=[321, 123]),
ISIS_64bitAdministrativeTagSubTlv(tags=[54321, 4294967311])
]),
ISIS_ExtendedIpPrefix(metric=10, pfx="10.1.0.181/30", subtlvindicator=1,
subtlvs=[
ISIS_GenericSubTlv(type=123, val="\x11\x1f\x01\x1c")
])
]
),
ISIS_Ipv6ReachabilityTlv(
pfxs=[
ISIS_Ipv6Prefix(metric=0, pfx="fe10:1::10/128"),
ISIS_Ipv6Prefix(metric=10, pfx="fd1f:1::/64", subtlvindicator=1,
subtlvs=[
ISIS_GenericSubTlv(type=99, val="\x1f\x01\x1f\x01\x11\x1f\x01\x1c")
]),
ISIS_Ipv6Prefix(metric=10, pfx="fd1f:1:12::/64")
]
),
ISIS_ExtendedIsReachabilityTlv(
neighbours=[
ISIS_ExtendedIsNeighbourEntry(neighbourid="1720.1600.8004.00", metric=10,
subtlvs=[
ISIS_IPv4InterfaceAddressSubTlv(address="172.16.8.4"),
ISIS_LinkLocalRemoteIdentifiersSubTlv(localid=418, remoteid=54321),
ISIS_IPv6NeighborAddressSubTlv(address="fe10:1::5")
])
]
)
])
p = p.__class__(str(p))
assert(p[ISIS_L2_LSP].pdulength == 231)
assert(p[ISIS_L2_LSP].checksum == 0xf8df)
assert(p[ISIS_ExtendedIpReachabilityTlv].pfxs[1].subtlvs[1].tags[0]==54321)
assert(p[ISIS_Ipv6ReachabilityTlv].pfxs[1].subtlvs[0].len==8)
assert(p[ISIS_ExtendedIsReachabilityTlv].neighbours[0].subtlvs[0].address=='172.16.8.4')
assert(p[ISIS_ExtendedIsReachabilityTlv].neighbours[0].subtlvs[1].localid==418)

Loading

0 comments on commit f912538

Please sign in to comment.