Package dpkt :: Module ethernet
[hide private]
[frames] | no frames]

Source Code for Module dpkt.ethernet

  1  # $Id: ethernet.py 65 2010-03-26 02:53:51Z dugsong $ 
  2  # -*- coding: utf-8 -*- 
  3  """Ethernet II, LLC (802.3+802.2), LLC/SNAP, and Novell raw 802.3, 
  4  with automatic 802.1q, MPLS, PPPoE, and Cisco ISL decapsulation.""" 
  5  from __future__ import print_function 
  6  from __future__ import absolute_import 
  7   
  8  import struct 
  9  import codecs 
 10  from zlib import crc32 
 11   
 12  from . import dpkt 
 13  from . import llc 
 14  from .compat import iteritems 
 15   
 16  try: 
 17      isinstance("", basestring) 
18 - def isstr(s):
19 return isinstance(s, basestring)
20 except NameError:
21 - def isstr(s):
22 return isinstance(s, str)
23 24 ETH_CRC_LEN = 4 25 ETH_HDR_LEN = 14 26 27 ETH_LEN_MIN = 64 # minimum frame length with CRC 28 ETH_LEN_MAX = 1518 # maximum frame length with CRC 29 30 ETH_MTU = (ETH_LEN_MAX - ETH_HDR_LEN - ETH_CRC_LEN) 31 ETH_MIN = (ETH_LEN_MIN - ETH_HDR_LEN - ETH_CRC_LEN) 32 33 # Ethernet payload types - http://standards.ieee.org/regauth/ethertype 34 ETH_TYPE_PUP = 0x0200 # PUP protocol 35 ETH_TYPE_IP = 0x0800 # IP protocol 36 ETH_TYPE_ARP = 0x0806 # address resolution protocol 37 ETH_TYPE_AOE = 0x88a2 # AoE protocol 38 ETH_TYPE_CDP = 0x2000 # Cisco Discovery Protocol 39 ETH_TYPE_DTP = 0x2004 # Cisco Dynamic Trunking Protocol 40 ETH_TYPE_REVARP = 0x8035 # reverse addr resolution protocol 41 ETH_TYPE_8021Q = 0x8100 # IEEE 802.1Q VLAN tagging 42 ETH_TYPE_IPX = 0x8137 # Internetwork Packet Exchange 43 ETH_TYPE_IP6 = 0x86DD # IPv6 protocol 44 ETH_TYPE_PPP = 0x880B # PPP 45 ETH_TYPE_MPLS = 0x8847 # MPLS 46 ETH_TYPE_MPLS_MCAST = 0x8848 # MPLS Multicast 47 ETH_TYPE_PPPoE_DISC = 0x8863 # PPP Over Ethernet Discovery Stage 48 ETH_TYPE_PPPoE = 0x8864 # PPP Over Ethernet Session Stage 49 ETH_TYPE_LLDP = 0x88CC # Link Layer Discovery Protocol 50 ETH_TYPE_TEB = 0x6558 # Transparent Ethernet Bridging
51 52 53 -class Ethernet(dpkt.Packet):
54 """Ethernet. 55 56 Ethernet II, LLC (802.3+802.2), LLC/SNAP, and Novell raw 802.3, 57 with automatic 802.1q, MPLS, PPPoE, and Cisco ISL decapsulation. 58 59 Attributes: 60 __hdr__: Header fields of Ethernet. 61 TODO. 62 """ 63 64 __hdr__ = ( 65 ('dst', '6s', ''), 66 ('src', '6s', ''), 67 ('type', 'H', ETH_TYPE_IP) 68 ) 69 _typesw = {} 70 _typesw_rev = {} # reverse mapping 71
72 - def __init__(self, *args, **kwargs):
73 dpkt.Packet.__init__(self, *args, **kwargs) 74 # if data was given in kwargs, try to unpack it 75 if self.data: 76 if isstr(self.data) or isinstance(self.data, bytes): 77 self._unpack_data(self.data)
78
79 - def _unpack_data(self, buf):
80 if self.type == ETH_TYPE_8021Q: 81 self.vlan_tags = [] 82 83 # support up to 2 tags (double tagging aka QinQ) 84 for _ in range(2): 85 tag = VLANtag8021Q(buf) 86 buf = buf[tag.__hdr_len__:] 87 self.vlan_tags.append(tag) 88 self.type = tag.type 89 if self.type != ETH_TYPE_8021Q: 90 break 91 # backward compatibility, use the 1st tag 92 self.vlanid, self.priority, self.cfi = self.vlan_tags[0].as_tuple() 93 94 elif self.type == ETH_TYPE_MPLS or self.type == ETH_TYPE_MPLS_MCAST: 95 self.labels = [] # old list containing labels as tuples 96 self.mpls_labels = [] # new list containing labels as instances of MPLSlabel 97 98 # XXX - max # of labels is undefined, just use 24 99 for i in range(24): 100 lbl = MPLSlabel(buf) 101 buf = buf[lbl.__hdr_len__:] 102 self.mpls_labels.append(lbl) 103 self.labels.append(lbl.as_tuple()) 104 if lbl.s: # bottom of stack 105 break 106 self.type = ETH_TYPE_IP 107 108 try: 109 self.data = self._typesw[self.type](buf) 110 setattr(self, self.data.__class__.__name__.lower(), self.data) 111 except (KeyError, dpkt.UnpackError): 112 self.data = buf
113
114 - def unpack(self, buf):
115 dpkt.Packet.unpack(self, buf) 116 if self.type > 1500: 117 # Ethernet II 118 self._unpack_data(self.data) 119 120 elif (self.dst.startswith(b'\x01\x00\x0c\x00\x00') or 121 self.dst.startswith(b'\x03\x00\x0c\x00\x00')): 122 # Cisco ISL 123 tag = VLANtagISL(buf) 124 buf = buf[tag.__hdr_len__:] 125 self.vlan_tags = [tag] 126 self.vlan = tag.id # backward compatibility 127 self.unpack(buf) 128 129 elif self.data.startswith(b'\xff\xff'): 130 # Novell "raw" 802.3 131 self.type = ETH_TYPE_IPX 132 self.data = self.ipx = self._typesw[ETH_TYPE_IPX](self.data[2:]) 133 134 else: 135 # IEEE 802.3 Ethernet - LLC 136 # try to unpack FCS here; we follow the same heuristic approach as Wireshark: 137 # if the upper layer len(self.data) can be fully decoded and returns its size, 138 # and there's a difference with size in the Eth header, then assume the last 139 # 4 bytes is the FCS and remaining bytes are a trailer. 140 eth_len = self.type 141 if len(self.data) > eth_len: 142 tail_len = len(self.data) - eth_len 143 if tail_len >= 4: 144 self.fcs = struct.unpack('>I', self.data[-4:])[0] 145 self.trailer = self.data[eth_len:-4] 146 self.data = self.llc = llc.LLC(self.data[:eth_len])
147
148 - def pack_hdr(self):
149 tags_buf = b'' 150 new_type = self.type 151 is_isl = False # ISL wraps Ethernet, this determines order of packing 152 153 # initial type is based on next layer, pointed by self.data; 154 # try to find an ETH_TYPE matching the data class 155 if isinstance(self.data, dpkt.Packet): 156 new_type = self._typesw_rev.get(self.data.__class__, new_type) 157 158 if getattr(self, 'mpls_labels', None): 159 # mark all labels with s=0, last one with s=1 160 for lbl in self.mpls_labels: 161 lbl.s = 0 162 lbl.s = 1 163 164 # set encapsulation type 165 if not (self.type == ETH_TYPE_MPLS or self.type == ETH_TYPE_MPLS_MCAST): 166 new_type = ETH_TYPE_MPLS 167 tags_buf = b''.join(lbl.pack_hdr() for lbl in self.mpls_labels) 168 169 elif getattr(self, 'vlan_tags', None): 170 # set encapsulation types 171 t1 = self.vlan_tags[0] 172 if len(self.vlan_tags) == 1: 173 if isinstance(t1, VLANtag8021Q): 174 t1.type = self.type 175 new_type = ETH_TYPE_8021Q 176 elif isinstance(t1, VLANtagISL): 177 t1.type = 0 # 0 means Ethernet 178 is_isl = True 179 elif len(self.vlan_tags) == 2: 180 t2 = self.vlan_tags[1] 181 if isinstance(t1, VLANtag8021Q) and isinstance(t2, VLANtag8021Q): 182 t2.type = self.type 183 new_type = t1.type = ETH_TYPE_8021Q 184 else: 185 raise dpkt.PackError('maximum is 2 VLAN tags per Ethernet frame') 186 tags_buf = b''.join(tag.pack_hdr() for tag in self.vlan_tags) 187 188 # if self.data is LLC then this is IEEE 802.3 Ethernet and self.type 189 # then actually encodes the length of data 190 if isinstance(self.data, llc.LLC): 191 new_type = len(self.data) 192 193 hdr_buf = dpkt.Packet.pack_hdr(self)[:-2] + struct.pack('>H', new_type) 194 if not is_isl: 195 return hdr_buf + tags_buf 196 else: 197 return tags_buf + hdr_buf
198
199 - def __str__(self):
200 tail = b'' 201 if isinstance(self.data, llc.LLC): 202 if hasattr(self, 'fcs'): 203 if self.fcs: 204 fcs = self.fcs 205 else: 206 # if fcs field is present but 0/None, then compute it and add to the tail 207 fcs_buf = self.pack_hdr() + bytes(self.data) + getattr(self, 'trailer', '') 208 # if ISL header is present, exclude it from the calculation 209 if getattr(self, 'vlan_tags', None): 210 if isinstance(self.vlan_tags[0], VLANtagISL): 211 fcs_buf = fcs_buf[VLANtagISL.__hdr_len__:] 212 revcrc = crc32(fcs_buf) & 0xffffffff 213 fcs = struct.unpack('<I', struct.pack('>I', revcrc))[0] # bswap32 214 tail = getattr(self, 'trailer', b'') + struct.pack('>I', fcs) 215 return str(dpkt.Packet.__bytes__(self) + tail)
216
217 - def __len__(self):
218 tags = getattr(self, 'mpls_labels', []) + getattr(self, 'vlan_tags', []) 219 _len = dpkt.Packet.__len__(self) + sum(t.__hdr_len__ for t in tags) 220 if isinstance(self.data, llc.LLC) and hasattr(self, 'fcs'): 221 _len += len(getattr(self, 'trailer', '')) + 4 222 return _len
223 224 @classmethod
225 - def set_type(cls, t, pktclass):
226 cls._typesw[t] = pktclass 227 cls._typesw_rev[pktclass] = t
228 229 @classmethod
230 - def get_type(cls, t):
231 return cls._typesw[t]
232 233 @classmethod
234 - def get_type_rev(cls, k):
235 return cls._typesw_rev[k]
236
237 238 # XXX - auto-load Ethernet dispatch table from ETH_TYPE_* definitions 239 -def __load_types():
240 g = globals() 241 for k, v in iteritems(g): 242 if k.startswith('ETH_TYPE_'): 243 name = k[9:] 244 modname = name.lower() 245 try: 246 mod = __import__(modname, g, level=1) 247 Ethernet.set_type(v, getattr(mod, name)) 248 except (ImportError, AttributeError): 249 continue 250 # add any special cases below 251 Ethernet.set_type(ETH_TYPE_TEB, Ethernet)
252
253 254 -def _mod_init():
255 """Post-initialization called when all dpkt modules are fully loaded""" 256 if not Ethernet._typesw: 257 __load_types()
258
259 260 # Misc protocols 261 262 263 -class MPLSlabel(dpkt.Packet):
264 """A single entry in MPLS label stack""" 265 266 __hdr__ = ( 267 ('_val_exp_s_ttl', 'I', 0), 268 ) 269 # field names are according to RFC3032 270
271 - def unpack(self, buf):
272 dpkt.Packet.unpack(self, buf) 273 self.val = (self._val_exp_s_ttl & 0xfffff000) >> 12 # label value, 20 bits 274 self.exp = (self._val_exp_s_ttl & 0x00000e00) >> 9 # experimental use, 3 bits 275 self.s = (self._val_exp_s_ttl & 0x00000100) >> 8 # bottom of stack flag, 1 bit 276 self.ttl = self._val_exp_s_ttl & 0x000000ff # time to live, 8 bits 277 self.data = b''
278
279 - def pack_hdr(self):
280 self._val_exp_s_ttl = ( 281 ((self.val & 0xfffff) << 12) | 282 ((self.exp & 7) << 9) | 283 ((self.s & 1) << 8) | 284 ((self.ttl & 0xff)) 285 ) 286 return dpkt.Packet.pack_hdr(self)
287
288 - def as_tuple(self): # backward-compatible representation
289 return (self.val, self.exp, self.ttl)
290
291 292 -class VLANtag8021Q(dpkt.Packet):
293 """IEEE 802.1q VLAN tag""" 294 295 __hdr__ = ( 296 ('_pri_cfi_id', 'H', 0), 297 ('type', 'H', ETH_TYPE_IP) 298 ) 299
300 - def unpack(self, buf):
301 dpkt.Packet.unpack(self, buf) 302 self.pri = (self._pri_cfi_id & 0xe000) >> 13 # priority, 3 bits 303 self.cfi = (self._pri_cfi_id & 0x1000) >> 12 # canonical format indicator, 1 bit 304 self.id = self._pri_cfi_id & 0x0fff # VLAN id, 12 bits 305 self.data = b''
306
307 - def pack_hdr(self):
308 self._pri_cfi_id = ( 309 ((self.pri & 7) << 13) | 310 ((self.cfi & 1) << 12) | 311 ((self.id & 0xfff)) 312 ) 313 return dpkt.Packet.pack_hdr(self)
314
315 - def as_tuple(self):
316 return (self.id, self.pri, self.cfi)
317
318 319 -class VLANtagISL(dpkt.Packet):
320 """Cisco Inter-Switch Link VLAN tag""" 321 322 __hdr__ = ( 323 ('da', '5s', b'\x01\x00\x0c\x00\x00'), 324 ('_type_pri', 'B', 3), 325 ('sa', '6s', ''), 326 ('len', 'H', 0), 327 ('snap', '3s', b'\xaa\xaa\x03'), 328 ('hsa', '3s', b'\x00\x00\x0c'), 329 ('_id_bpdu', 'H', 0), 330 ('indx', 'H', 0), 331 ('res', 'H', 0) 332 ) 333
334 - def unpack(self, buf):
335 dpkt.Packet.unpack(self, buf) 336 self.type = (self._type_pri & 0xf0) >> 4 # encapsulation type, 4 bits; 0 means Ethernet 337 self.pri = self._type_pri & 0x03 # user defined bits, 2 bits are used; means priority 338 self.id = self._id_bpdu >> 1 # VLAN id 339 self.bpdu = self._id_bpdu & 1 340 self.data = b''
341
342 - def pack_hdr(self):
343 self._type_pri = ((self.type & 0xf) << 4) | (self.pri & 0x3) 344 self._id_bpdu = ((self.id & 0x7fff) << 1) | (self.bpdu & 1) 345 return dpkt.Packet.pack_hdr(self)
346
347 348 # Unit tests 349 350 351 -def test_eth():
352 from . import ip # IPv6 needs this to build its protocol stack 353 from . import ip6 354 from . import tcp 355 s = (b'\x00\xb0\xd0\xe1\x80\x72\x00\x11\x24\x8c\x11\xde\x86\xdd\x60\x00\x00\x00' 356 b'\x00\x28\x06\x40\xfe\x80\x00\x00\x00\x00\x00\x00\x02\x11\x24\xff\xfe\x8c' 357 b'\x11\xde\xfe\x80\x00\x00\x00\x00\x00\x00\x02\xb0\xd0\xff\xfe\xe1\x80\x72' 358 b'\xcd\xd3\x00\x16\xff\x50\xd7\x13\x00\x00\x00\x00\xa0\x02\xff\xff\x67\xd3' 359 b'\x00\x00\x02\x04\x05\xa0\x01\x03\x03\x00\x01\x01\x08\x0a\x7d\x18\x3a\x61' 360 b'\x00\x00\x00\x00') 361 eth = Ethernet(s) 362 assert eth 363 assert isinstance(eth.data, ip6.IP6) 364 assert isinstance(eth.data.data, tcp.TCP) 365 assert str(eth) == str(s) 366 assert len(eth) == len(s)
367
368 369 -def test_eth_init_with_data():
370 # initialize with a data string, test that it gets unpacked 371 from . import arp 372 eth1 = Ethernet( 373 dst=b'PQRSTU', src=b'ABCDEF', type=ETH_TYPE_ARP, 374 data=b'\x00\x01\x08\x00\x06\x04\x00\x01123456abcd7890abwxyz') 375 assert isinstance(eth1.data, arp.ARP) 376 377 # now initialize with a class, test packing 378 eth2 = Ethernet( 379 dst=b'PQRSTU', src=b'ABCDEF', 380 data=arp.ARP(sha=b'123456', spa=b'abcd', tha=b'7890ab', tpa=b'wxyz')) 381 assert str(eth1) == str(eth2) 382 assert len(eth1) == len(eth2)
383
384 385 -def test_mpls_label():
386 s = b'\x00\x01\x0b\xff' 387 m = MPLSlabel(s) 388 assert m.val == 16 389 assert m.exp == 5 390 assert m.s == 1 391 assert m.ttl == 255 392 assert str(m) == str(s) 393 assert len(m) == len(s)
394
395 396 -def test_802dot1q_tag():
397 s = b'\xa0\x76\x01\x65' 398 t = VLANtag8021Q(s) 399 assert t.pri == 5 400 assert t.cfi == 0 401 assert t.id == 118 402 assert str(t) == str(s) 403 t.cfi = 1 404 assert str(t) == str(b'\xb0\x76\x01\x65') 405 assert len(t) == len(s)
406
407 408 -def test_isl_tag():
409 s = (b'\x01\x00\x0c\x00\x00\x03\x00\x02\xfd\x2c\xb8\x97\x00\x00\xaa\xaa\x03\x00\x00\x00\x04\x57' 410 b'\x00\x00\x00\x00') 411 t = VLANtagISL(s) 412 assert t.pri == 3 413 assert t.id == 555 414 assert t.bpdu == 1 415 assert str(t) == str(s) 416 assert len(t) == len(s)
417
418 419 -def test_eth_802dot1q():
420 from . import ip 421 s = (b'\x00\x60\x08\x9f\xb1\xf3\x00\x40\x05\x40\xef\x24\x81\x00\x90\x20\x08' 422 b'\x00\x45\x00\x00\x34\x3b\x64\x40\x00\x40\x06\xb7\x9b\x83\x97\x20\x81' 423 b'\x83\x97\x20\x15\x04\x95\x17\x70\x51\xd4\xee\x9c\x51\xa5\x5b\x36\x80' 424 b'\x10\x7c\x70\x12\xc7\x00\x00\x01\x01\x08\x0a\x00\x04\xf0\xd4\x01\x99' 425 b'\xa3\xfd') 426 eth = Ethernet(s) 427 assert eth.cfi == 1 428 assert eth.vlanid == 32 429 assert eth.priority == 4 430 assert len(eth.vlan_tags) == 1 431 assert eth.vlan_tags[0].type == ETH_TYPE_IP 432 assert isinstance(eth.data, ip.IP) 433 434 # construction 435 assert str(eth) == str(s), 'pack 1' 436 assert str(eth) == str(s), 'pack 2' 437 assert len(eth) == len(s) 438 439 # construction with kwargs 440 eth2 = Ethernet(src=eth.src, dst=eth.dst, vlan_tags=eth.vlan_tags, data=eth.data) 441 assert str(eth2) == str(s) 442 443 # construction w/o the tag 444 del eth.vlan_tags, eth.cfi, eth.vlanid, eth.priority 445 assert str(eth) == str(s[:12] + b'\x08\x00' + s[18:])
446
447 448 -def test_eth_802dot1q_stacked(): # 2 VLAN tags
449 from . import arp 450 from . import ip 451 s = (b'\x00\x1b\xd4\x1b\xa4\xd8\x00\x13\xc3\xdf\xae\x18\x81\x00\x00\x76\x81\x00\x00\x0a\x08\x00' 452 b'\x45\x00\x00\x64\x00\x0f\x00\x00\xff\x01\x92\x9b\x0a\x76\x0a\x01\x0a\x76\x0a\x02\x08\x00' 453 b'\xce\xb7\x00\x03\x00\x00\x00\x00\x00\x00\x00\x1f\xaf\x70\xab\xcd\xab\xcd\xab\xcd\xab\xcd' 454 b'\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd' 455 b'\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd' 456 b'\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd') 457 eth = Ethernet(s) 458 assert eth.type == ETH_TYPE_IP 459 assert len(eth.vlan_tags) == 2 460 assert eth.vlan_tags[0].id == 118 461 assert eth.vlan_tags[1].id == 10 462 assert eth.vlan_tags[0].type == ETH_TYPE_8021Q 463 assert eth.vlan_tags[1].type == ETH_TYPE_IP 464 assert [t.as_tuple() for t in eth.vlan_tags] == [(118, 0, 0), (10, 0, 0)] 465 assert isinstance(eth.data, ip.IP) 466 467 # construction 468 assert str(eth) == str(s), 'pack 1' 469 assert str(eth) == str(s), 'pack 2' 470 assert len(eth) == len(s) 471 472 # construction with kwargs 473 eth2 = Ethernet(src=eth.src, dst=eth.dst, vlan_tags=eth.vlan_tags, data=eth.data) 474 assert str(eth2) == str(s) 475 476 # construction w/o the tags 477 del eth.vlan_tags, eth.cfi, eth.vlanid, eth.priority 478 assert str(eth) == str(s[:12] + b'\x08\x00' + s[22:]) 479 480 # 2 VLAN tags + ARP 481 s = (b'\xff\xff\xff\xff\xff\xff\xca\x03\x0d\xb4\x00\x1c\x81\x00\x00\x64\x81\x00\x00\xc8\x08\x06' 482 b'\x00\x01\x08\x00\x06\x04\x00\x01\xca\x03\x0d\xb4\x00\x1c\xc0\xa8\x02\xc8\x00\x00\x00\x00' 483 b'\x00\x00\xc0\xa8\x02\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') 484 eth = Ethernet(s) 485 assert len(eth.vlan_tags) == 2 486 assert eth.vlan_tags[0].type == ETH_TYPE_8021Q 487 assert eth.vlan_tags[1].type == ETH_TYPE_ARP 488 assert isinstance(eth.data, arp.ARP) 489
490 491 -def test_eth_mpls_stacked(): # 2 MPLS labels
492 from . import ip 493 s = (b'\x00\x30\x96\xe6\xfc\x39\x00\x30\x96\x05\x28\x38\x88\x47\x00\x01\x20\xff\x00\x01\x01\xff' 494 b'\x45\x00\x00\x64\x00\x50\x00\x00\xff\x01\xa7\x06\x0a\x1f\x00\x01\x0a\x22\x00\x01\x08\x00' 495 b'\xbd\x11\x0f\x65\x12\xa0\x00\x00\x00\x00\x00\x53\x9e\xe0\xab\xcd\xab\xcd\xab\xcd\xab\xcd' 496 b'\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd' 497 b'\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd' 498 b'\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd\xab\xcd') 499 eth = Ethernet(s) 500 assert len(eth.mpls_labels) == 2 501 assert eth.mpls_labels[0].val == 18 502 assert eth.mpls_labels[1].val == 16 503 assert eth.labels == [(18, 0, 255), (16, 0, 255)] 504 assert isinstance(eth.data, ip.IP) 505 506 # construction 507 assert str(eth) == str(s), 'pack 1' 508 assert str(eth) == str(s), 'pack 2' 509 assert len(eth) == len(s) 510 511 # construction with kwargs 512 eth2 = Ethernet(src=eth.src, dst=eth.dst, mpls_labels=eth.mpls_labels, data=eth.data) 513 assert str(eth2) == str(s) 514 515 # construction w/o labels 516 del eth.labels, eth.mpls_labels 517 assert str(eth) == str(s[:12] + b'\x08\x00' + s[22:]) 518
519 520 -def test_isl_eth_llc_stp(): # ISL - 802.3 Ethernet(w/FCS) - LLC - STP
521 from . import stp 522 s = (b'\x01\x00\x0c\x00\x00\x03\x00\x02\xfd\x2c\xb8\x97\x00\x00\xaa\xaa\x03\x00\x00\x00\x02\x9b' 523 b'\x00\x00\x00\x00\x01\x80\xc2\x00\x00\x00\x00\x02\xfd\x2c\xb8\x98\x00\x26\x42\x42\x03\x00' 524 b'\x00\x00\x00\x00\x80\x00\x00\x02\xfd\x2c\xb8\x83\x00\x00\x00\x00\x80\x00\x00\x02\xfd\x2c' 525 b'\xb8\x83\x80\x26\x00\x00\x14\x00\x02\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x41\xc6' 526 b'\x75\xd6') 527 eth = Ethernet(s) 528 assert eth.vlan == 333 529 assert len(eth.vlan_tags) == 1 530 assert eth.vlan_tags[0].id == 333 531 assert eth.vlan_tags[0].pri == 3 532 533 # check that FCS was decoded 534 assert eth.fcs == 0x41c675d6 535 assert eth.trailer == b'\x00' * 8 536 537 # stack 538 assert isinstance(eth.data, llc.LLC) 539 assert isinstance(eth.data.data, stp.STP) 540 541 # construction 542 assert str(eth) == str(s), 'pack 1' 543 assert str(eth) == str(s), 'pack 2' 544 assert len(eth) == len(s) 545 546 # construction with kwargs 547 eth2 = Ethernet(src=eth.src, dst=eth.dst, vlan_tags=eth.vlan_tags, data=eth.data) 548 eth2.trailer = eth.trailer 549 eth2.fcs = None 550 # test FCS computation 551 assert str(eth2) == str(s) 552 553 # construction w/o the ISL tag 554 del eth.vlan_tags, eth.vlan 555 assert str(eth) == str(s[26:]) 556
557 558 -def test_eth_llc_snap_cdp(): # 802.3 Ethernet - LLC/SNAP - CDP
559 from . import cdp 560 s = (b'\x01\x00\x0c\xcc\xcc\xcc\xc4\x022k\x00\x00\x01T\xaa\xaa\x03\x00\x00\x0c \x00\x02\xb4,B' 561 b'\x00\x01\x00\x06R2\x00\x05\x00\xffCisco IOS Software, 3700 Software (C3745-ADVENTERPRI' 562 b'SEK9_SNA-M), Version 12.4(25d), RELEASE SOFTWARE (fc1)\nTechnical Support: http://www.' 563 b'cisco.com/techsupport\nCopyright (c) 1986-2010 by Cisco Systems, Inc.\nCompiled Wed 18' 564 b'-Aug-10 08:18 by prod_rel_team\x00\x06\x00\x0eCisco 3745\x00\x02\x00\x11\x00\x00\x00\x01' 565 b'\x01\x01\xcc\x00\x04\n\x00\x00\x02\x00\x03\x00\x13FastEthernet0/0\x00\x04\x00\x08\x00' 566 b'\x00\x00)\x00\t\x00\x04\x00\x0b\x00\x05\x00') 567 eth = Ethernet(s) 568 569 # stack 570 assert isinstance(eth.data, llc.LLC) 571 assert isinstance(eth.data.data, cdp.CDP) 572 assert len(eth.data.data.data) == 8 # number of CDP TLVs; ensures they are decoded 573 assert str(eth) == str(s), 'pack 1' 574 assert str(eth) == str(s), 'pack 2' 575 assert len(eth) == len(s) 576
577 578 -def test_eth_llc_ipx(): # 802.3 Ethernet - LLC - IPX
579 from . import ipx 580 s = (b'\xff\xff\xff\xff\xff\xff\x00\xb0\xd0\x22\xf7\xf3\x00\x54\xe0\xe0\x03\xff\xff\x00\x50\x00' 581 b'\x14\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\x04\x55\x00\x00\x00\x00\x00\xb0\xd0\x22\xf7' 582 b'\xf3\x04\x55\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' 583 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x02\x5f\x5f\x4d\x53\x42' 584 b'\x52\x4f\x57\x53\x45\x5f\x5f\x02\x01\x00') 585 eth = Ethernet(s) 586 587 # stack 588 assert isinstance(eth.data, llc.LLC) 589 assert isinstance(eth.data.data, ipx.IPX) 590 assert eth.data.data.pt == 0x14 591 assert str(eth) == str(s), 'pack 1' 592 assert str(eth) == str(s), 'pack 2' 593 assert len(eth) == len(s) 594
595 596 -def test_eth_pppoe(): # Eth - PPPoE - IPv6 - UDP - DHCP6
597 from . import ip # IPv6 needs this to build its protocol stack 598 from . import ip6 599 from . import ppp 600 from . import pppoe 601 from . import udp 602 s = (b'\xca\x01\x0e\x88\x00\x06\xcc\x05\x0e\x88\x00\x00\x88\x64\x11\x00\x00\x11\x00\x64\x57\x6e' 603 b'\x00\x00\x00\x00\x3a\x11\xff\xfe\x80\x00\x00\x00\x00\x00\x00\xce\x05\x0e\xff\xfe\x88\x00' 604 b'\x00\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x02\x02\x22\x02\x23\x00' 605 b'\x3a\x1a\x67\x01\xfc\x24\xab\x00\x08\x00\x02\x05\xe9\x00\x01\x00\x0a\x00\x03\x00\x01\xcc' 606 b'\x05\x0e\x88\x00\x00\x00\x06\x00\x06\x00\x19\x00\x17\x00\x18\x00\x19\x00\x0c\x00\x09\x00' 607 b'\x01\x00\x00\x00\x00\x00\x00\x00\x00') 608 eth = Ethernet(s) 609 610 # stack 611 assert isinstance(eth.data, pppoe.PPPoE) 612 assert isinstance(eth.data.data, ppp.PPP) 613 assert isinstance(eth.data.data.data, ip6.IP6) 614 assert isinstance(eth.data.data.data.data, udp.UDP) 615 616 # construction 617 assert str(eth) == str(s) 618 assert len(eth) == len(s) 619 620 621 622 623 624 if __name__ == '__main__': 625 test_eth() 626 test_eth_init_with_data() 627 test_mpls_label() 628 test_802dot1q_tag() 629 test_isl_tag() 630 test_eth_802dot1q() 631 test_eth_802dot1q_stacked() 632 test_eth_mpls_stacked() 633 test_isl_eth_llc_stp() 634 test_eth_llc_snap_cdp() 635 test_eth_llc_ipx() 636 test_eth_pppoe() 637 638 print('Tests Successful...') 639