# scapy.contrib.description = Label Distribution Protocol (LDP)
|
# scapy.contrib.status = loads
|
|
# http://git.savannah.gnu.org/cgit/ldpscapy.git/snapshot/ldpscapy-5285b81d6e628043df2a83301b292f24a95f0ba1.tar.gz
|
|
# This program 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 3 of the License, or
|
# (at your option) any later version.
|
|
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
# Copyright (C) 2010 Florian Duraffourg
|
|
from __future__ import absolute_import
|
import struct
|
|
from scapy.packet import *
|
from scapy.fields import *
|
from scapy.ansmachine import *
|
from scapy.layers.inet import UDP
|
from scapy.layers.inet import TCP
|
from scapy.base_classes import Net
|
from scapy.modules.six.moves import range
|
|
|
# Guess payload
|
def guess_payload(p):
|
LDPTypes = {
|
0x0001: LDPNotification,
|
0x0100: LDPHello,
|
0x0200: LDPInit,
|
0x0201: LDPKeepAlive,
|
0x0300: LDPAddress,
|
0x0301: LDPAddressWM,
|
0x0400: LDPLabelMM,
|
0x0401: LDPLabelReqM,
|
0x0404: LDPLabelARM,
|
0x0402: LDPLabelWM,
|
0x0403: LDPLabelRelM,
|
}
|
type = struct.unpack("!H",p[0:2])[0]
|
type = type & 0x7fff
|
if type == 0x0001 and struct.unpack("!H",p[2:4])[0] > 20:
|
return LDP
|
if type in LDPTypes:
|
return LDPTypes[type]
|
else:
|
return conf.raw_layer
|
|
## Fields ##
|
|
# 3.4.1. FEC TLV
|
|
class FecTLVField(StrField):
|
islist=1
|
def m2i(self, pkt, x):
|
nbr = struct.unpack("!H",x[2:4])[0]
|
used = 0
|
x=x[4:]
|
list=[]
|
while x:
|
#if x[0] == 1:
|
# list.append('Wildcard')
|
#else:
|
#mask=ord(x[8*i+3])
|
#add=inet_ntoa(x[8*i+4:8*i+8])
|
mask=ord(x[3])
|
nbroctets = mask / 8
|
if mask % 8:
|
nbroctets += 1
|
add=inet_ntoa(x[4:4+nbroctets]+b"\x00"*(4-nbroctets))
|
list.append( (add, mask) )
|
used += 4 + nbroctets
|
x=x[4+nbroctets:]
|
return list
|
def i2m(self, pkt, x):
|
if isinstance(x, str):
|
return x
|
s = b"\x01\x00"
|
l = 0
|
fec = ""
|
for o in x:
|
fec += b"\x02\x00\x01"
|
# mask length
|
fec += struct.pack("!B",o[1])
|
# Prefix
|
fec += inet_aton(o[0])
|
l += 8
|
s += struct.pack("!H",l)
|
s += fec
|
return s
|
def size(self, s):
|
"""Get the size of this field"""
|
l = 4 + struct.unpack("!H",s[2:4])[0]
|
return l
|
def getfield(self, pkt, s):
|
l = self.size(s)
|
return s[l:],self.m2i(pkt, s[:l])
|
|
|
# 3.4.2.1. Generic Label TLV
|
|
class LabelTLVField(StrField):
|
def m2i(self, pkt, x):
|
return struct.unpack("!I",x[4:8])[0]
|
def i2m(self, pkt, x):
|
if isinstance(x, str):
|
return x
|
s = b"\x02\x00\x00\x04"
|
s += struct.pack("!I",x)
|
return s
|
def size(self, s):
|
"""Get the size of this field"""
|
l = 4 + struct.unpack("!H",s[2:4])[0]
|
return l
|
def getfield(self, pkt, s):
|
l = self.size(s)
|
return s[l:],self.m2i(pkt, s[:l])
|
|
|
# 3.4.3. Address List TLV
|
|
class AddressTLVField(StrField):
|
islist=1
|
def m2i(self, pkt, x):
|
nbr = struct.unpack("!H",x[2:4])[0] - 2
|
nbr /= 4
|
x=x[6:]
|
list=[]
|
for i in range(0, nbr):
|
add = x[4*i:4*i+4]
|
list.append(inet_ntoa(add))
|
return list
|
def i2m(self, pkt, x):
|
if isinstance(x, str):
|
return x
|
l=2+len(x)*4
|
s = b"\x01\x01"+struct.pack("!H",l)+b"\x00\x01"
|
for o in x:
|
s += inet_aton(o)
|
return s
|
def size(self, s):
|
"""Get the size of this field"""
|
l = 4 + struct.unpack("!H",s[2:4])[0]
|
return l
|
def getfield(self, pkt, s):
|
l = self.size(s)
|
return s[l:],self.m2i(pkt, s[:l])
|
|
|
# 3.4.6. Status TLV
|
|
class StatusTLVField(StrField):
|
islist=1
|
def m2i(self, pkt, x):
|
l = []
|
statuscode = struct.unpack("!I",x[4:8])[0]
|
l.append( (statuscode & 2**31) >> 31)
|
l.append( (statuscode & 2**30) >> 30)
|
l.append( statuscode & 0x3FFFFFFF )
|
l.append( struct.unpack("!I", x[8:12])[0] )
|
l.append( struct.unpack("!H", x[12:14])[0] )
|
return l
|
def i2m(self, pkt, x):
|
if isinstance(x, str):
|
return x
|
s = b"\x03\x00" + struct.pack("!H",10)
|
statuscode = 0
|
if x[0] != 0:
|
statuscode += 2**31
|
if x[1] != 0:
|
statuscode += 2**30
|
statuscode += x[2]
|
s += struct.pack("!I",statuscode)
|
if len(x) > 3:
|
s += struct.pack("!I",x[3])
|
else:
|
s += b"\x00\x00\x00\x00"
|
if len(x) > 4:
|
s += struct.pack("!H",x[4])
|
else:
|
s += b"\x00\x00"
|
return s
|
def getfield(self, pkt, s):
|
l = 14
|
return s[l:],self.m2i(pkt, s[:l])
|
|
|
# 3.5.2 Common Hello Parameters TLV
|
class CommonHelloTLVField(StrField):
|
islist = 1
|
def m2i(self, pkt, x):
|
list = []
|
v = struct.unpack("!H",x[4:6])[0]
|
list.append(v)
|
flags = struct.unpack("B",x[6])[0]
|
v = ( flags & 0x80 ) >> 7
|
list.append(v)
|
v = ( flags & 0x40 ) >> 7
|
list.append(v)
|
return list
|
def i2m(self, pkt, x):
|
if isinstance(x, str):
|
return x
|
s = b"\x04\x00\x00\x04"
|
s += struct.pack("!H",x[0])
|
byte = 0
|
if x[1] == 1:
|
byte += 0x80
|
if x[2] == 1:
|
byte += 0x40
|
s += struct.pack("!B",byte)
|
s += b"\x00"
|
return s
|
def getfield(self, pkt, s):
|
l = 8
|
return s[l:],self.m2i(pkt, s[:l])
|
|
|
# 3.5.3 Common Session Parameters TLV
|
class CommonSessionTLVField(StrField):
|
islist = 1
|
def m2i(self, pkt, x):
|
l = [struct.unpack("!H", x[6:8])[0]]
|
octet = struct.unpack("B",x[8:9])[0]
|
l.append( (octet & 2**7 ) >> 7 )
|
l.append( (octet & 2**6 ) >> 6 )
|
l.append( struct.unpack("B",x[9:10])[0] )
|
l.append( struct.unpack("!H",x[10:12])[0] )
|
l.append( inet_ntoa(x[12:16]) )
|
l.append( struct.unpack("!H",x[16:18])[0] )
|
return l
|
def i2m(self, pkt, x):
|
if isinstance(x, str):
|
return x
|
s = b"\x05\x00\x00\x0E\x00\x01"
|
s += struct.pack("!H",x[0])
|
octet = 0
|
if x[1] != 0:
|
octet += 2**7
|
if x[2] != 0:
|
octet += 2**6
|
s += struct.pack("!B",octet)
|
s += struct.pack("!B",x[3])
|
s += struct.pack("!H",x[4])
|
s += inet_aton(x[5])
|
s += struct.pack("!H",x[6])
|
return s
|
def getfield(self, pkt, s):
|
l = 18
|
return s[l:],self.m2i(pkt, s[:l])
|
|
|
|
## Messages ##
|
|
# 3.5.1. Notification Message
|
class LDPNotification(Packet):
|
name = "LDPNotification"
|
fields_desc = [ BitField("u",0,1),
|
BitField("type", 0x0001, 15),
|
ShortField("len", None),
|
IntField("id", 0) ,
|
StatusTLVField("status",(0,0,0,0,0)) ]
|
def post_build(self, p, pay):
|
if self.len is None:
|
l = len(p) - 4
|
p = p[:2]+struct.pack("!H", l)+p[4:]
|
return p+pay
|
def guess_payload_class(self, p):
|
return guess_payload(p)
|
|
|
# 3.5.2. Hello Message
|
class LDPHello(Packet):
|
name = "LDPHello"
|
fields_desc = [ BitField("u",0,1),
|
BitField("type", 0x0100, 15),
|
ShortField("len", None),
|
IntField("id", 0) ,
|
CommonHelloTLVField("params",[180,0,0]) ]
|
def post_build(self, p, pay):
|
if self.len is None:
|
l = len(p) - 4
|
p = p[:2]+struct.pack("!H", l)+p[4:]
|
return p+pay
|
def guess_payload_class(self, p):
|
return guess_payload(p)
|
|
|
# 3.5.3. Initialization Message
|
class LDPInit(Packet):
|
name = "LDPInit"
|
fields_desc = [ BitField("u",0,1),
|
XBitField("type", 0x0200, 15),
|
ShortField("len", None),
|
IntField("id", 0),
|
CommonSessionTLVField("params",None)]
|
def post_build(self, p, pay):
|
if self.len is None:
|
l = len(p) - 4
|
p = p[:2]+struct.pack("!H", l)+p[4:]
|
return p+pay
|
def guess_payload_class(self, p):
|
return guess_payload(p)
|
|
|
# 3.5.4. KeepAlive Message
|
class LDPKeepAlive(Packet):
|
name = "LDPKeepAlive"
|
fields_desc = [ BitField("u",0,1),
|
XBitField("type", 0x0201, 15),
|
ShortField("len", None),
|
IntField("id", 0)]
|
def post_build(self, p, pay):
|
if self.len is None:
|
l = len(p) - 4
|
p = p[:2]+struct.pack("!H", l)+p[4:]
|
return p+pay
|
def guess_payload_class(self, p):
|
return guess_payload(p)
|
|
|
# 3.5.5. Address Message
|
|
class LDPAddress(Packet):
|
name = "LDPAddress"
|
fields_desc = [ BitField("u",0,1),
|
XBitField("type", 0x0300, 15),
|
ShortField("len", None),
|
IntField("id", 0),
|
AddressTLVField("address",None) ]
|
def post_build(self, p, pay):
|
if self.len is None:
|
l = len(p) - 4
|
p = p[:2]+struct.pack("!H", l)+p[4:]
|
return p+pay
|
def guess_payload_class(self, p):
|
return guess_payload(p)
|
|
|
# 3.5.6. Address Withdraw Message
|
|
class LDPAddressWM(Packet):
|
name = "LDPAddressWM"
|
fields_desc = [ BitField("u",0,1),
|
XBitField("type", 0x0301, 15),
|
ShortField("len", None),
|
IntField("id", 0),
|
AddressTLVField("address",None) ]
|
def post_build(self, p, pay):
|
if self.len is None:
|
l = len(p) - 4
|
p = p[:2]+struct.pack("!H", l)+p[4:]
|
return p+pay
|
def guess_payload_class(self, p):
|
return guess_payload(p)
|
|
|
# 3.5.7. Label Mapping Message
|
|
class LDPLabelMM(Packet):
|
name = "LDPLabelMM"
|
fields_desc = [ BitField("u",0,1),
|
XBitField("type", 0x0400, 15),
|
ShortField("len", None),
|
IntField("id", 0),
|
FecTLVField("fec",None),
|
LabelTLVField("label",0)]
|
def post_build(self, p, pay):
|
if self.len is None:
|
l = len(p) - 4
|
p = p[:2]+struct.pack("!H", l)+p[4:]
|
return p+pay
|
def guess_payload_class(self, p):
|
return guess_payload(p)
|
|
# 3.5.8. Label Request Message
|
|
class LDPLabelReqM(Packet):
|
name = "LDPLabelReqM"
|
fields_desc = [ BitField("u",0,1),
|
XBitField("type", 0x0401, 15),
|
ShortField("len", None),
|
IntField("id", 0),
|
FecTLVField("fec",None)]
|
def post_build(self, p, pay):
|
if self.len is None:
|
l = len(p) - 4
|
p = p[:2]+struct.pack("!H", l)+p[4:]
|
return p+pay
|
def guess_payload_class(self, p):
|
return guess_payload(p)
|
|
|
# 3.5.9. Label Abort Request Message
|
|
class LDPLabelARM(Packet):
|
name = "LDPLabelARM"
|
fields_desc = [ BitField("u",0,1),
|
XBitField("type", 0x0404, 15),
|
ShortField("len", None),
|
IntField("id", 0),
|
FecTLVField("fec",None),
|
IntField("labelRMid",0)]
|
def post_build(self, p, pay):
|
if self.len is None:
|
l = len(p) - 4
|
p = p[:2]+struct.pack("!H", l)+p[4:]
|
return p+pay
|
def guess_payload_class(self, p):
|
return guess_payload(p)
|
|
|
# 3.5.10. Label Withdraw Message
|
|
class LDPLabelWM(Packet):
|
name = "LDPLabelWM"
|
fields_desc = [ BitField("u",0,1),
|
XBitField("type", 0x0402, 15),
|
ShortField("len", None),
|
IntField("id", 0),
|
FecTLVField("fec",None),
|
LabelTLVField("label",0)]
|
def post_build(self, p, pay):
|
if self.len is None:
|
l = len(p) - 4
|
p = p[:2]+struct.pack("!H", l)+p[4:]
|
return p+pay
|
def guess_payload_class(self, p):
|
return guess_payload(p)
|
|
|
# 3.5.11. Label Release Message
|
|
class LDPLabelRelM(Packet):
|
name = "LDPLabelRelM"
|
fields_desc = [ BitField("u",0,1),
|
XBitField("type", 0x0403, 15),
|
ShortField("len", None),
|
IntField("id", 0),
|
FecTLVField("fec",None),
|
LabelTLVField("label",0)]
|
def post_build(self, p, pay):
|
if self.len is None:
|
l = len(p) - 4
|
p = p[:2]+struct.pack("!H", l)+p[4:]
|
return p+pay
|
def guess_payload_class(self, p):
|
return guess_payload(p)
|
|
|
# 3.1. LDP PDUs
|
class LDP(Packet):
|
name = "LDP"
|
fields_desc = [ ShortField("version",1),
|
ShortField("len", None),
|
IPField("id","127.0.0.1"),
|
ShortField("space",0) ]
|
def post_build(self, p, pay):
|
if self.len is None:
|
l = len(p)+len(pay)-4
|
p = p[:2]+struct.pack("!H", l)+p[4:]
|
return p+pay
|
def guess_payload_class(self, p):
|
return guess_payload(p)
|
|
bind_layers( TCP, LDP, sport=646, dport=646 )
|
bind_layers( UDP, LDP, sport=646, dport=646 )
|