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 21from __future__ import absolute_import 22import struct 23 24from scapy.packet import * 25from scapy.fields import * 26from scapy.ansmachine import * 27from scapy.layers.inet import UDP 28from scapy.layers.inet import TCP 29from scapy.base_classes import Net 30from scapy.modules.six.moves import range 31 32 33# Guess payload 34def 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 61class 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 110class 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 130class 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 160class 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 197class 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 228class 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 265class 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 282class 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 299class 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 316class 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 333class 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 351class 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 369class 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 387class 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 405class 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 424class 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 443class 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 461class 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 475bind_layers( TCP, LDP, sport=646, dport=646 ) 476bind_layers( UDP, LDP, sport=646, dport=646 ) 477