Source code for dpkt.pppoe

# $Id: pppoe.py 23 2006-11-08 15:45:33Z dugsong $
# -*- coding: utf-8 -*-
"""PPP-over-Ethernet."""
from __future__ import absolute_import

import struct
import codecs

from . import dpkt
from . import ppp
from .decorators import deprecated

# RFC 2516 codes
PPPoE_PADI = 0x09
PPPoE_PADO = 0x07
PPPoE_PADR = 0x19
PPPoE_PADS = 0x65
PPPoE_PADT = 0xA7
PPPoE_SESSION = 0x00


[docs]class PPPoE(dpkt.Packet): """PPP-over-Ethernet. TODO: Longer class information.... Attributes: __hdr__: Header fields of PPPoE. TODO. """ __hdr__ = ( ('_v_type', 'B', 0x11), ('code', 'B', 0), ('session', 'H', 0), ('len', 'H', 0) # payload length ) @property def v(self): return self._v_type >> 4 @v.setter def v(self, v): self._v_type = (v << 4) | (self._v_type & 0xf) @property def type(self): return self._v_type & 0xf @type.setter def type(self, t): self._v_type = (self._v_type & 0xf0) | t
[docs] def unpack(self, buf): dpkt.Packet.unpack(self, buf) try: if self.code == 0: # We need to use the pppoe.PPP header here, because PPPoE # doesn't do the normal encapsulation. self.data = self.ppp = PPP(self.data) except dpkt.UnpackError: pass
[docs]class PPP(ppp.PPP): # Light version for protocols without the usual encapsulation, for PPPoE __hdr__ = ( # Usuaully two-bytes, but while protocol compression is not recommended, it is supported ('p', 'B', ppp.PPP_IP), )
[docs] def unpack(self, buf): dpkt.Packet.unpack(self, buf) if self.p & ppp.PFC_BIT == 0: try: self.p = struct.unpack('>H', buf[:2])[0] except struct.error: raise dpkt.NeedData self.data = self.data[1:] try: self.data = self._protosw[self.p](self.data) setattr(self, self.data.__class__.__name__.lower(), self.data) except (KeyError, struct.error, dpkt.UnpackError): pass
[docs] def pack_hdr(self): try: # Protocol compression is *not* recommended (RFC2516), but we do it anyway if self.p > 0xff: return struct.pack('>H', self.p) return dpkt.Packet.pack_hdr(self) except struct.error as e: raise dpkt.PackError(str(e))
[docs]def test_pppoe_discovery(): s = ("11070000002801010000010300046413" "85180102000442524153010400103d0f" "0587062484f2df32b9ddfd77bd5b") s = codecs.decode(s, 'hex') p = PPPoE(s) assert p.code == PPPoE_PADO assert p.v == 1 assert p.type == 1 s = ("11190000002801010000010300046413" "85180102000442524153010400103d0f" "0587062484f2df32b9ddfd77bd5b") s = codecs.decode(s, 'hex') p = PPPoE(s) assert p.code == PPPoE_PADR assert p.pack_hdr() == s[:6]
[docs]def test_pppoe_session(): s = "11000011000cc0210101000a050605fcd459" s = codecs.decode(s, 'hex') p = PPPoE(s) assert p.code == PPPoE_SESSION assert isinstance(p.ppp, PPP) assert p.data.p == 0xc021 # LCP assert len(p.data.data) == 10 assert p.data.pack_hdr() == b"\xc0\x21" s = ("110000110066005760000000003c3a40fc000000000000000000000000000001" "fc0000000002010000000000000100018100bf291f9700010102030405060708" "090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728" "292a2b2c2d2e2f3031323334") s = codecs.decode(s, 'hex') p = PPPoE(s) assert p.code == PPPoE_SESSION assert isinstance(p.ppp, PPP) assert p.data.p == ppp.PPP_IP6 assert p.data.data.p == 58 # ICMPv6 assert p.ppp.pack_hdr() == b"\x57"
[docs]def test_ppp_packing(): p = PPP() assert p.pack_hdr() == b"\x21" p.p = 0xc021 # LCP assert p.pack_hdr() == b"\xc0\x21"
[docs]def test_ppp_short(): import pytest pytest.raises(dpkt.NeedData, PPP, b"\x00")
# XXX - TODO TLVs, etc.