Skip to content
Snippets Groups Projects
Commit f912538b authored by mkaliszan's avatar mkaliszan Committed by Pierre Lalet
Browse files

[isis.py] Add support for some SubTLVs (#305)

* [isis.py] Add support for some SubTLVs
* [isis.py, isis.uts] Fix, (unit-)test and extend SubTLVs support
parent 45c59302
No related branches found
No related tags found
No related merge requests found
...@@ -5,8 +5,9 @@ ...@@ -5,8 +5,9 @@
IS-IS Scapy Extension IS-IS Scapy Extension
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
:copyright: 2014, 2015 BENOCS GmbH, Berlin (Germany) :copyright: 2014-2016 BENOCS GmbH, Berlin (Germany)
:author: Marcel Patzlaff, mpatzlaff@benocs.com :author: Marcel Patzlaff, mpatzlaff@benocs.com
Michal Kaliszan, mkaliszan@benocs.com
:license: GPLv2 :license: GPLv2
This module is free software; you can redistribute it and/or This module is free software; you can redistribute it and/or
...@@ -52,10 +53,13 @@ from scapy.config import conf ...@@ -52,10 +53,13 @@ from scapy.config import conf
from scapy.fields import * from scapy.fields import *
from scapy.packet import * from scapy.packet import *
from scapy.layers.clns import network_layer_protocol_ids, register_cln_protocol 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 conf.debug_dissector = True
...@@ -206,9 +210,128 @@ class ISIS_LspIdField(_ISIS_IdFieldBase): ...@@ -206,9 +210,128 @@ class ISIS_LspIdField(_ISIS_IdFieldBase):
class ISIS_CircuitTypeField(FlagsField): class ISIS_CircuitTypeField(FlagsField):
def __init__(self, name="circuittype", default=2, size=8, def __init__(self, name="circuittype", default=2, size=8,
names=None): names=None):
FlagsField.__init__(self, name, default, size, names)
if names is None: if names is None:
names = ["L1", "L2", "r0", "r1", "r2", "r3", "r4", "r5"] 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)]
####################################################################### #######################################################################
...@@ -283,23 +406,7 @@ _isis_tlv_names = { ...@@ -283,23 +406,7 @@ _isis_tlv_names = {
def _ISIS_GuessTlvClass(p, **kargs): def _ISIS_GuessTlvClass(p, **kargs):
cls = conf.raw_layer return _ISIS_GuessTlvClass_Helper(_isis_tlv_classes, "ISIS_GenericTlv", p, **kargs)
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
class ISIS_AreaEntry(Packet): class ISIS_AreaEntry(Packet):
...@@ -347,20 +454,6 @@ class ISIS_DynamicHostnameTlv(ISIS_GenericTlv): ...@@ -347,20 +454,6 @@ class ISIS_DynamicHostnameTlv(ISIS_GenericTlv):
BoundStrLenField("hostname", "", length_from=lambda pkt: pkt.len)] 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): class ISIS_ExtendedIpPrefix(Packet):
name = "ISIS Extended IP Prefix" name = "ISIS Extended IP Prefix"
fields_desc = [ fields_desc = [
...@@ -369,8 +462,8 @@ class ISIS_ExtendedIpPrefix(Packet): ...@@ -369,8 +462,8 @@ class ISIS_ExtendedIpPrefix(Packet):
BitField("subtlvindicator", 0, 1), BitField("subtlvindicator", 0, 1),
BitFieldLenField("pfxlen", None, 6, length_of="pfx"), BitFieldLenField("pfxlen", None, 6, length_of="pfx"),
IPPrefixField("pfx", None, wordbytes=1, length_from=lambda x: x.pfxlen), 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(FieldLenField("subtlvslen", None, length_of="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(PacketListField("subtlvs", [], _ISIS_GuessSubTlvClass_2, length_from=lambda x: x.subtlvslen), lambda pkt: pkt.subtlvindicator == 1)
] ]
def extract_padding(self, s): def extract_padding(self, s):
...@@ -386,15 +479,17 @@ class ISIS_ExtendedIpReachabilityTlv(ISIS_GenericTlv): ...@@ -386,15 +479,17 @@ class ISIS_ExtendedIpReachabilityTlv(ISIS_GenericTlv):
class ISIS_ExtendedIsNeighbourEntry(Packet): class ISIS_ExtendedIsNeighbourEntry(Packet):
name = "ISIS Extended IS Neighbour Entry" name = "ISIS Extended IS Neighbour Entry"
fields_desc = [ISIS_NodeIdField("neighbourid", "0102.0304.0506.07"), fields_desc = [
ThreeBytesField("metric", 1), ISIS_NodeIdField("neighbourid", "0102.0304.0506.07"),
FieldLenField("subtlvslen", None, length_of="subtlvs", fmt= "B"), ThreeBytesField("metric", 1),
ConditionalField(PacketListField("subtlvs", [], _isis_guess_subtlv_cls, length_from=lambda x: x.subtlvslen), lambda pkt: pkt.subtlvslen > 0)] FieldLenField("subtlvslen", None, length_of="subtlvs", fmt= "B"),
PacketListField("subtlvs", [], _ISIS_GuessSubTlvClass_1, length_from=lambda x: x.subtlvslen)
]
def extract_padding(self, s): def extract_padding(self, s):
return "", s return "", s
class ISIS_ExtendedIsReachabilityTlv(ISIS_GenericTlv): class ISIS_ExtendedIsReachabilityTlv(ISIS_GenericTlv):
name = "ISIS Extended IS Reachability TLV" name = "ISIS Extended IS Reachability TLV"
fields_desc = [ByteEnumField("type", 22, _isis_tlv_names), fields_desc = [ByteEnumField("type", 22, _isis_tlv_names),
...@@ -428,8 +523,8 @@ class ISIS_Ipv6Prefix(Packet): ...@@ -428,8 +523,8 @@ class ISIS_Ipv6Prefix(Packet):
BitField("reserved", 0, 5), BitField("reserved", 0, 5),
FieldLenField("pfxlen", None, length_of="pfx", fmt="B"), FieldLenField("pfxlen", None, length_of="pfx", fmt="B"),
IP6PrefixField("pfx", None, wordbytes=1, length_from=lambda x: x.pfxlen), 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(FieldLenField("subtlvslen", None, length_of="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(PacketListField("subtlvs", [], _ISIS_GuessSubTlvClass_2, length_from=lambda x: x.subtlvslen), lambda pkt: pkt.subtlvindicator == 1)
] ]
def extract_padding(self, s): def extract_padding(self, s):
...@@ -767,3 +862,4 @@ bind_layers(ISIS_CommonHdr, ISIS_L1_CSNP, hdrlen=33, pdutype=24) ...@@ -767,3 +862,4 @@ bind_layers(ISIS_CommonHdr, ISIS_L1_CSNP, hdrlen=33, pdutype=24)
bind_layers(ISIS_CommonHdr, ISIS_L2_CSNP, hdrlen=33, pdutype=25) 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_L1_PSNP, hdrlen=17, pdutype=26)
bind_layers(ISIS_CommonHdr, ISIS_L2_PSNP, hdrlen=17, pdutype=27) bind_layers(ISIS_CommonHdr, ISIS_L2_PSNP, hdrlen=17, pdutype=27)
% IS-IS Tests % IS-IS Tests
* Tests for the IS-IS layer * Tests for the IS-IS layer
+ Syntax check
= Import the isis layer
from scapy.contrib.isis import *
+ Basic Layer Tests + Basic Layer Tests
= Layer Binding = Layer Binding
...@@ -13,9 +18,20 @@ assert(p[ISIS_CommonHdr].pdutype == 17) ...@@ -13,9 +18,20 @@ assert(p[ISIS_CommonHdr].pdutype == 17)
assert(p[ISIS_CommonHdr].hdrlen == 20) assert(p[ISIS_CommonHdr].hdrlen == 20)
+ Package Tests + 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 = LSP
p = Dot3(dst="09:00:2b:00:00:05",src="00:00:00:aa:00:8c")/LLC()/ISIS_CommonHdr()/ISIS_L2_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=[ tlvs=[
ISIS_AreaTlv( ISIS_AreaTlv(
areas=[ISIS_AreaEntry(areaid="49.1000")] areas=[ISIS_AreaEntry(areaid="49.1000")]
...@@ -50,8 +66,71 @@ p = Dot3(dst="09:00:2b:00:00:05",src="00:00:00:aa:00:8c")/LLC()/ISIS_CommonHdr() ...@@ -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( ISIS_ExtendedIsReachabilityTlv(
neighbours=[ISIS_ExtendedIsNeighbourEntry(neighbourid="1720.1600.8004.00", metric=10)] neighbours=[ISIS_ExtendedIsNeighbourEntry(neighbourid="1720.1600.8004.00", metric=10)]
) )
] ])
)
p = p.__class__(str(p)) p = p.__class__(str(p))
assert(p[ISIS_L2_LSP].pdulength == 150) assert(p[ISIS_L2_LSP].pdulength == 150)
assert(p[ISIS_L2_LSP].checksum == 0x8701) assert(p[ISIS_L2_LSP].checksum == 0x8701)
\ No newline at end of file
= 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)
...@@ -36,9 +36,9 @@ class OSPFOptionsField(FlagsField): ...@@ -36,9 +36,9 @@ class OSPFOptionsField(FlagsField):
def __init__(self, name="options", default=0, size=8, def __init__(self, name="options", default=0, size=8,
names=None): names=None):
FlagsField.__init__(self, name, default, size, names)
if names is None: if names is None:
names = ["MT", "E", "MC", "NP", "L", "DC", "O", "DN"] names = ["MT", "E", "MC", "NP", "L", "DC", "O", "DN"]
FlagsField.__init__(self, name, default, size, names)
_OSPF_types = {1: "Hello", _OSPF_types = {1: "Hello",
...@@ -133,9 +133,9 @@ class LLS_ExtendedOptionsField(FlagsField): ...@@ -133,9 +133,9 @@ class LLS_ExtendedOptionsField(FlagsField):
def __init__(self, name="options", default=0, size=32, def __init__(self, name="options", default=0, size=32,
names=None): names=None):
FlagsField.__init__(self, name, default, size, names)
if names is None: if names is None:
names = ["LR", "RS"] names = ["LR", "RS"]
FlagsField.__init__(self, name, default, size, names)
class LLS_Extended_Options(LLS_Generic_TLV): class LLS_Extended_Options(LLS_Generic_TLV):
...@@ -460,9 +460,9 @@ class OSPFv3OptionsField(FlagsField): ...@@ -460,9 +460,9 @@ class OSPFv3OptionsField(FlagsField):
def __init__(self, name="options", default=0, size=24, def __init__(self, name="options", default=0, size=24,
names=None): names=None):
FlagsField.__init__(self, name, default, size, names)
if names is None: if names is None:
names = ["V6", "E", "MC", "N", "R", "DC", "AF", "L", "I", "F"] names = ["V6", "E", "MC", "N", "R", "DC", "AF", "L", "I", "F"]
FlagsField.__init__(self, name, default, size, names)
class OSPFv3_Hello(Packet): class OSPFv3_Hello(Packet):
...@@ -577,9 +577,9 @@ class OSPFv3PrefixOptionsField(FlagsField): ...@@ -577,9 +577,9 @@ class OSPFv3PrefixOptionsField(FlagsField):
def __init__(self, name="prefixoptions", default=0, size=8, def __init__(self, name="prefixoptions", default=0, size=8,
names=None): names=None):
FlagsField.__init__(self, name, default, size, names)
if names is None: if names is None:
names = ["NU", "LA", "MC", "P"] names = ["NU", "LA", "MC", "P"]
FlagsField.__init__(self, name, default, size, names)
class OSPFv3_Inter_Area_Prefix_LSA(OSPF_BaseLSA): class OSPFv3_Inter_Area_Prefix_LSA(OSPF_BaseLSA):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment