Home | History | Annotate | Download | only in contrib
      1 # scapy.contrib.description = Label Distribution Protocol (LDP)
      2 # scapy.contrib.status = loads
      3 
      4 # http://git.savannah.gnu.org/cgit/ldpscapy.git/snapshot/ldpscapy-5285b81d6e628043df2a83301b292f24a95f0ba1.tar.gz
      5 
      6 # This program is free software: you can redistribute it and/or modify
      7 # it under the terms of the GNU General Public License as published by
      8 # the Free Software Foundation, either version 3 of the License, or
      9 # (at your option) any later version.
     10 
     11 # This program is distributed in the hope that it will be useful,
     12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 # GNU General Public License for more details.
     15 
     16 # You should have received a copy of the GNU General Public License
     17 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
     18 
     19 # Copyright (C) 2010 Florian Duraffourg
     20 
     21 from __future__ import absolute_import
     22 import struct
     23 
     24 from scapy.packet import *
     25 from scapy.fields import *
     26 from scapy.ansmachine import *
     27 from scapy.layers.inet import UDP
     28 from scapy.layers.inet import TCP
     29 from scapy.base_classes import Net
     30 from scapy.modules.six.moves import range
     31 
     32 
     33 # Guess payload
     34 def guess_payload(p):
     35     LDPTypes = {
     36         0x0001: LDPNotification,
     37         0x0100: LDPHello,
     38         0x0200: LDPInit,
     39         0x0201: LDPKeepAlive,
     40         0x0300: LDPAddress,
     41         0x0301: LDPAddressWM,
     42         0x0400: LDPLabelMM,
     43         0x0401: LDPLabelReqM,
     44         0x0404: LDPLabelARM,
     45         0x0402: LDPLabelWM,
     46         0x0403: LDPLabelRelM,
     47         }
     48     type = struct.unpack("!H",p[0:2])[0]
     49     type = type & 0x7fff
     50     if type == 0x0001 and struct.unpack("!H",p[2:4])[0] > 20:
     51         return LDP
     52     if type in LDPTypes:
     53         return LDPTypes[type]
     54     else:
     55         return conf.raw_layer
     56 
     57 ## Fields ##
     58 
     59 # 3.4.1. FEC TLV
     60 
     61 class FecTLVField(StrField):
     62     islist=1
     63     def m2i(self, pkt, x):
     64         nbr = struct.unpack("!H",x[2:4])[0]
     65         used = 0
     66         x=x[4:]
     67         list=[]
     68         while x:
     69             #if x[0] == 1:
     70             #   list.append('Wildcard')
     71             #else:
     72             #mask=ord(x[8*i+3])
     73             #add=inet_ntoa(x[8*i+4:8*i+8])
     74             mask=ord(x[3])
     75             nbroctets = mask / 8
     76             if mask % 8:
     77                 nbroctets += 1
     78             add=inet_ntoa(x[4:4+nbroctets]+b"\x00"*(4-nbroctets))
     79             list.append( (add, mask) )
     80             used += 4 + nbroctets
     81             x=x[4+nbroctets:]
     82         return list
     83     def i2m(self, pkt, x):
     84         if isinstance(x, str):
     85             return x
     86         s = b"\x01\x00"
     87         l = 0
     88         fec = ""
     89         for o in x:
     90             fec += b"\x02\x00\x01"
     91             # mask length
     92             fec += struct.pack("!B",o[1])
     93             # Prefix
     94             fec += inet_aton(o[0])
     95             l += 8
     96         s += struct.pack("!H",l)
     97         s += fec
     98         return s
     99     def size(self, s):
    100         """Get the size of this field"""
    101         l = 4 + struct.unpack("!H",s[2:4])[0]
    102         return l
    103     def getfield(self, pkt, s):
    104         l = self.size(s)
    105         return s[l:],self.m2i(pkt, s[:l])
    106         
    107 
    108 # 3.4.2.1. Generic Label TLV
    109 
    110 class LabelTLVField(StrField):
    111     def m2i(self, pkt, x):
    112         return struct.unpack("!I",x[4:8])[0]
    113     def i2m(self, pkt, x):
    114         if isinstance(x, str):
    115             return x
    116         s = b"\x02\x00\x00\x04"
    117         s += struct.pack("!I",x)
    118         return s
    119     def size(self, s):
    120         """Get the size of this field"""
    121         l = 4 + struct.unpack("!H",s[2:4])[0]
    122         return l
    123     def getfield(self, pkt, s):
    124         l = self.size(s)
    125         return s[l:],self.m2i(pkt, s[:l])
    126 
    127 
    128 # 3.4.3. Address List TLV
    129 
    130 class AddressTLVField(StrField):
    131     islist=1
    132     def m2i(self, pkt, x):
    133         nbr = struct.unpack("!H",x[2:4])[0] - 2
    134         nbr /= 4
    135         x=x[6:]
    136         list=[]
    137         for i in range(0, nbr):
    138             add = x[4*i:4*i+4]
    139             list.append(inet_ntoa(add))
    140         return list
    141     def i2m(self, pkt, x):
    142         if isinstance(x, str):
    143             return x
    144         l=2+len(x)*4
    145         s = b"\x01\x01"+struct.pack("!H",l)+b"\x00\x01"
    146         for o in x:
    147             s += inet_aton(o)
    148         return s
    149     def size(self, s):
    150         """Get the size of this field"""
    151         l = 4 + struct.unpack("!H",s[2:4])[0]
    152         return l
    153     def getfield(self, pkt, s):
    154         l = self.size(s)
    155         return s[l:],self.m2i(pkt, s[:l])
    156 
    157 
    158 # 3.4.6. Status TLV
    159 
    160 class StatusTLVField(StrField):
    161     islist=1
    162     def m2i(self, pkt, x):
    163         l = []
    164         statuscode = struct.unpack("!I",x[4:8])[0]
    165         l.append( (statuscode & 2**31) >> 31)
    166         l.append( (statuscode & 2**30) >> 30)
    167         l.append( statuscode & 0x3FFFFFFF )
    168         l.append( struct.unpack("!I", x[8:12])[0] )
    169         l.append( struct.unpack("!H", x[12:14])[0] )
    170         return l
    171     def i2m(self, pkt, x):
    172         if isinstance(x, str):
    173             return x
    174         s = b"\x03\x00" + struct.pack("!H",10)
    175         statuscode = 0
    176         if x[0] != 0:
    177             statuscode += 2**31
    178         if x[1] != 0:
    179             statuscode += 2**30
    180         statuscode += x[2]
    181         s += struct.pack("!I",statuscode)
    182         if len(x) > 3:
    183             s += struct.pack("!I",x[3])
    184         else:
    185             s += b"\x00\x00\x00\x00"
    186         if len(x) > 4:
    187             s += struct.pack("!H",x[4])
    188         else:
    189             s += b"\x00\x00"
    190         return s
    191     def getfield(self, pkt, s):
    192         l = 14
    193         return s[l:],self.m2i(pkt, s[:l])
    194 
    195 
    196 # 3.5.2 Common Hello Parameters TLV
    197 class CommonHelloTLVField(StrField):
    198     islist = 1
    199     def m2i(self, pkt, x):
    200         list = []
    201         v = struct.unpack("!H",x[4:6])[0]
    202         list.append(v)
    203         flags = struct.unpack("B",x[6])[0]
    204         v = ( flags & 0x80 ) >> 7
    205         list.append(v)
    206         v = ( flags & 0x40 ) >> 7
    207         list.append(v)
    208         return list
    209     def i2m(self, pkt, x):
    210         if isinstance(x, str):
    211             return x
    212         s = b"\x04\x00\x00\x04"
    213         s += struct.pack("!H",x[0])
    214         byte = 0
    215         if x[1] == 1:
    216             byte += 0x80
    217         if x[2] == 1:
    218             byte += 0x40
    219         s += struct.pack("!B",byte)
    220         s += b"\x00"
    221         return s
    222     def getfield(self, pkt, s):
    223         l = 8
    224         return s[l:],self.m2i(pkt, s[:l])
    225 
    226 
    227 # 3.5.3 Common Session Parameters TLV
    228 class CommonSessionTLVField(StrField):
    229     islist = 1
    230     def m2i(self, pkt, x):
    231         l = [struct.unpack("!H", x[6:8])[0]]
    232         octet = struct.unpack("B",x[8:9])[0]
    233         l.append( (octet & 2**7 ) >> 7 )
    234         l.append( (octet & 2**6 ) >> 6 )
    235         l.append( struct.unpack("B",x[9:10])[0] )
    236         l.append( struct.unpack("!H",x[10:12])[0] )
    237         l.append( inet_ntoa(x[12:16]) )
    238         l.append( struct.unpack("!H",x[16:18])[0] )
    239         return l
    240     def i2m(self, pkt, x):
    241         if isinstance(x, str):
    242             return x
    243         s = b"\x05\x00\x00\x0E\x00\x01"
    244         s += struct.pack("!H",x[0])
    245         octet = 0
    246         if x[1] != 0:
    247             octet += 2**7
    248         if x[2] != 0:
    249             octet += 2**6
    250         s += struct.pack("!B",octet)
    251         s += struct.pack("!B",x[3])
    252         s += struct.pack("!H",x[4])
    253         s += inet_aton(x[5])
    254         s += struct.pack("!H",x[6])
    255         return s
    256     def getfield(self, pkt, s):
    257         l = 18
    258         return s[l:],self.m2i(pkt, s[:l])
    259     
    260 
    261 
    262 ## Messages ##
    263 
    264 # 3.5.1. Notification Message
    265 class LDPNotification(Packet):
    266     name = "LDPNotification"
    267     fields_desc = [ BitField("u",0,1),
    268                     BitField("type", 0x0001, 15),
    269                     ShortField("len", None),
    270                     IntField("id", 0) ,
    271                     StatusTLVField("status",(0,0,0,0,0)) ]
    272     def post_build(self, p, pay):
    273         if self.len is None:
    274             l = len(p) - 4
    275             p = p[:2]+struct.pack("!H", l)+p[4:]
    276         return p+pay  
    277     def guess_payload_class(self, p):
    278         return guess_payload(p)
    279 
    280 
    281 # 3.5.2. Hello Message
    282 class LDPHello(Packet):
    283     name = "LDPHello"
    284     fields_desc = [ BitField("u",0,1),
    285                     BitField("type", 0x0100, 15),
    286                     ShortField("len", None),
    287                     IntField("id", 0) ,
    288                     CommonHelloTLVField("params",[180,0,0]) ]
    289     def post_build(self, p, pay):
    290         if self.len is None:
    291             l = len(p) - 4
    292             p = p[:2]+struct.pack("!H", l)+p[4:]
    293         return p+pay  
    294     def guess_payload_class(self, p):
    295         return guess_payload(p)
    296 
    297 
    298 # 3.5.3. Initialization Message
    299 class LDPInit(Packet):
    300     name = "LDPInit"
    301     fields_desc = [ BitField("u",0,1),
    302                     XBitField("type", 0x0200, 15),
    303                     ShortField("len", None),
    304                     IntField("id", 0),
    305                     CommonSessionTLVField("params",None)]
    306     def post_build(self, p, pay):
    307         if self.len is None:
    308             l = len(p) - 4
    309             p = p[:2]+struct.pack("!H", l)+p[4:]
    310         return p+pay  
    311     def guess_payload_class(self, p):
    312         return guess_payload(p)
    313 
    314 
    315 # 3.5.4. KeepAlive Message
    316 class LDPKeepAlive(Packet):
    317     name = "LDPKeepAlive"
    318     fields_desc = [ BitField("u",0,1),
    319                     XBitField("type", 0x0201, 15),
    320                     ShortField("len", None),
    321                     IntField("id", 0)]
    322     def post_build(self, p, pay):
    323         if self.len is None:
    324             l = len(p) - 4
    325             p = p[:2]+struct.pack("!H", l)+p[4:]
    326         return p+pay  
    327     def guess_payload_class(self, p):
    328         return guess_payload(p)
    329 
    330 
    331 # 3.5.5. Address Message
    332 
    333 class LDPAddress(Packet):
    334     name = "LDPAddress"
    335     fields_desc = [ BitField("u",0,1),
    336                     XBitField("type", 0x0300, 15),
    337                     ShortField("len", None),
    338                     IntField("id", 0),
    339                     AddressTLVField("address",None) ]
    340     def post_build(self, p, pay):
    341         if self.len is None:
    342             l = len(p) - 4
    343             p = p[:2]+struct.pack("!H", l)+p[4:]
    344         return p+pay
    345     def guess_payload_class(self, p):
    346         return guess_payload(p)
    347 
    348 
    349 # 3.5.6. Address Withdraw Message
    350 
    351 class LDPAddressWM(Packet):
    352     name = "LDPAddressWM"
    353     fields_desc = [ BitField("u",0,1),
    354                     XBitField("type", 0x0301, 15),
    355                     ShortField("len", None),
    356                     IntField("id", 0),
    357                     AddressTLVField("address",None) ]
    358     def post_build(self, p, pay):
    359         if self.len is None:
    360             l = len(p) - 4
    361             p = p[:2]+struct.pack("!H", l)+p[4:]
    362         return p+pay
    363     def guess_payload_class(self, p):
    364         return guess_payload(p)
    365 
    366 
    367 # 3.5.7. Label Mapping Message
    368 
    369 class LDPLabelMM(Packet):
    370     name = "LDPLabelMM"
    371     fields_desc = [ BitField("u",0,1),
    372                     XBitField("type", 0x0400, 15),
    373                     ShortField("len", None),
    374                     IntField("id", 0),
    375                     FecTLVField("fec",None),
    376                     LabelTLVField("label",0)]
    377     def post_build(self, p, pay):
    378         if self.len is None:
    379             l = len(p) - 4
    380             p = p[:2]+struct.pack("!H", l)+p[4:]
    381         return p+pay  
    382     def guess_payload_class(self, p):
    383         return guess_payload(p)
    384 
    385 # 3.5.8. Label Request Message
    386 
    387 class LDPLabelReqM(Packet):
    388     name = "LDPLabelReqM"
    389     fields_desc = [ BitField("u",0,1),
    390                     XBitField("type", 0x0401, 15),
    391                     ShortField("len", None),
    392                     IntField("id", 0),
    393                     FecTLVField("fec",None)]
    394     def post_build(self, p, pay):
    395         if self.len is None:
    396             l = len(p) - 4
    397             p = p[:2]+struct.pack("!H", l)+p[4:]
    398         return p+pay  
    399     def guess_payload_class(self, p):
    400         return guess_payload(p)
    401 
    402 
    403 # 3.5.9. Label Abort Request Message
    404 
    405 class LDPLabelARM(Packet):
    406     name = "LDPLabelARM"
    407     fields_desc = [ BitField("u",0,1),
    408                     XBitField("type", 0x0404, 15),
    409                     ShortField("len", None),
    410                     IntField("id", 0),
    411                     FecTLVField("fec",None),
    412                     IntField("labelRMid",0)]
    413     def post_build(self, p, pay):
    414         if self.len is None:
    415             l = len(p) - 4
    416             p = p[:2]+struct.pack("!H", l)+p[4:]
    417         return p+pay  
    418     def guess_payload_class(self, p):
    419         return guess_payload(p)
    420 
    421 
    422 # 3.5.10. Label Withdraw Message
    423 
    424 class LDPLabelWM(Packet):
    425     name = "LDPLabelWM"
    426     fields_desc = [ BitField("u",0,1),
    427                     XBitField("type", 0x0402, 15),
    428                     ShortField("len", None),
    429                     IntField("id", 0),
    430                     FecTLVField("fec",None),
    431                     LabelTLVField("label",0)]
    432     def post_build(self, p, pay):
    433         if self.len is None:
    434             l = len(p) - 4
    435             p = p[:2]+struct.pack("!H", l)+p[4:]
    436         return p+pay  
    437     def guess_payload_class(self, p):
    438         return guess_payload(p)
    439 
    440 
    441 # 3.5.11. Label Release Message
    442 
    443 class LDPLabelRelM(Packet):
    444     name = "LDPLabelRelM"
    445     fields_desc = [ BitField("u",0,1),
    446                     XBitField("type", 0x0403, 15),
    447                     ShortField("len", None),
    448                     IntField("id", 0),
    449                     FecTLVField("fec",None),
    450                     LabelTLVField("label",0)]
    451     def post_build(self, p, pay):
    452         if self.len is None:
    453             l = len(p) - 4
    454             p = p[:2]+struct.pack("!H", l)+p[4:]
    455         return p+pay  
    456     def guess_payload_class(self, p):
    457         return guess_payload(p)
    458 
    459 
    460 # 3.1. LDP PDUs
    461 class LDP(Packet):
    462     name = "LDP"
    463     fields_desc = [ ShortField("version",1),
    464                     ShortField("len", None),
    465                     IPField("id","127.0.0.1"),
    466                     ShortField("space",0) ]
    467     def post_build(self, p, pay):
    468         if self.len is None:
    469             l = len(p)+len(pay)-4
    470             p = p[:2]+struct.pack("!H", l)+p[4:]
    471         return p+pay
    472     def guess_payload_class(self, p):
    473         return guess_payload(p)
    474 
    475 bind_layers( TCP, LDP, sport=646, dport=646 )
    476 bind_layers( UDP, LDP, sport=646, dport=646 )
    477