1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
# -*- coding: utf-8 -*-
from __future__ import print_function
from __future__ import absolute_import
import struct
from . import dpkt
from . import stp
class LLC(dpkt.Packet):
"""802.2 Logical Link Control (LLC) data communication protocol.
Attributes:
__hdr__ = (
('dsap', 'B', 0xaa), # Destination Service Access Point
('ssap', 'B', 0xaa), # Source Service Access Point
('ctl', 'B', 3) # Control Byte
)
"""
__hdr__ = (
('dsap', 'B', 0xaa), # Destination Service Access Point
('ssap', 'B', 0xaa), # Source Service Access Point
('ctl', 'B', 3) # Control Byte
)
@property
def is_snap(self):
return self.dsap == self.ssap == 0xaa
def unpack(self, buf):
from .ethernet import Ethernet, ETH_TYPE_IP, ETH_TYPE_IPX
dpkt.Packet.unpack(self, buf)
if self.is_snap:
self.oui, self.type = struct.unpack('>IH', b'\x00' + self.data[:5])
self.data = self.data[5:]
try:
self.data = Ethernet.get_type(self.type)(self.data)
setattr(self, self.data.__class__.__name__.lower(), self.data)
except (KeyError, dpkt.UnpackError):
pass
else:
# non-SNAP
if self.dsap == 0x06: # SAP_IP
self.data = self.ip = Ethernet.get_type(ETH_TYPE_IP)(self.data)
elif self.dsap == 0x10 or self.dsap == 0xe0: # SAP_NETWARE{1,2}
self.data = self.ipx = Ethernet.get_type(ETH_TYPE_IPX)(self.data)
elif self.dsap == 0x42: # SAP_STP
self.data = self.stp = stp.STP(self.data)
def pack_hdr(self):
buf = dpkt.Packet.pack_hdr(self)
if self.is_snap: # add SNAP sublayer
oui = getattr(self, 'oui', 0)
_type = getattr(self, 'type', 0)
if not _type and isinstance(self.data, dpkt.Packet):
from .ethernet import Ethernet
try:
_type = Ethernet.get_type_rev(self.data.__class__)
except KeyError:
pass
buf += struct.pack('>IH', oui, _type)[1:]
return buf
def __len__(self): # add 5 bytes of SNAP header if needed
return self.__hdr_len__ + 5 * int(self.is_snap) + len(self.data)
def test_llc():
from . import ip
from . import ethernet
s = (b'\xaa\xaa\x03\x00\x00\x00\x08\x00\x45\x00\x00\x28\x07\x27\x40\x00\x80\x06\x1d'
b'\x39\x8d\xd4\x37\x3d\x3f\xf5\xd1\x69\xc0\x5f\x01\xbb\xb2\xd6\xef\x23\x38\x2b'
b'\x4f\x08\x50\x10\x42\x04\xac\x17\x00\x00')
llc_pkt = LLC(s)
ip_pkt = llc_pkt.data
assert isinstance(ip_pkt, ip.IP)
assert llc_pkt.type == ethernet.ETH_TYPE_IP
assert ip_pkt.dst == b'\x3f\xf5\xd1\x69'
assert str(llc_pkt) == str(s)
assert len(llc_pkt) == len(s)
# construction with SNAP header
llc_pkt = LLC(ssap=0xaa, dsap=0xaa, data=ip.IP(s[8:]))
assert str(llc_pkt) == str(s)
# no SNAP
llc_pkt = LLC(ssap=6, dsap=6, data=ip.IP(s[8:]))
assert isinstance(llc_pkt.data, ip.IP)
assert str(llc_pkt) == str(b'\x06\x06\x03' + s[8:])
def test_unpack_sap_ip():
from binascii import unhexlify
from . import ip
buf_llc = unhexlify(
'06' # dsap (SAP_IP)
'aa' # ssap
'03' # ctl
)
buf_ip = unhexlify(
'45' # _v_hl
'00' # tos
'0014' # len
'0000' # id
'0000' # off
'80' # ttl
'06' # p
'd47e' # sum
'11111111' # src
'22222222' # dst
)
buf = buf_llc + buf_ip
llc = LLC(buf)
assert isinstance(llc.data, ip.IP)
def test_unpack_exception_handling():
from binascii import unhexlify
buf_llc = unhexlify(
'aa' # dsap (SAP_IP)
'aa' # ssap
'03' # ctl
'111111' # oui
'2222' # type (not valid ethertype)
)
llc = LLC(buf_llc)
assert not isinstance(llc.data, dpkt.Packet)
def test_pack_hdr_invalid_class():
from binascii import unhexlify
class InvalidClass(dpkt.Packet):
__hdr__ = (('test', 'B', 0x22),)
llc = LLC(dsap=0xaa, ssap=0xaa, ctl=3, oui=0x111111, data=InvalidClass())
correct = unhexlify(
'aa' # dsap
'aa' # ssap
'03' # ctl
'111111' # oui
'0000' # type
'22' # data in test class header
)
assert bytes(llc) == correct
|