This file is indexed.

/usr/lib/python3/dist-packages/provisioningserver/utils/ethernet.py is in python3-maas-provisioningserver 2.4.0~beta2-6865-gec43e47e6-0ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
# Copyright 2016 Canonical Ltd.  This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).

"""Utilities for working with Ethernet packets."""

__all__ = [
    "Ethernet"
]

from collections import namedtuple
import struct

from netaddr import EUI
from provisioningserver.utils.network import (
    bytes_to_int,
    hex_str_to_bytes,
)

# Definitions for Ethernet packet used with `struct`.
ETHERNET_PACKET = '!6s6s2s'

# 6 byte source MAC + 6 byte destination MAC + 2 byte Ethertype
ETHERNET_HEADER_LEN = 14

EthernetPacket = namedtuple('EthernetPacket', (
    'dst_mac',
    'src_mac',
    'ethertype',
))

VLAN_HEADER = '!2s2s'
VLAN_HEADER_LEN = 4


class ETHERTYPE:
    """Enumeration to represent ethertypes that MAAS needs to understand."""
    IPV4 = hex_str_to_bytes('0800')
    IPV6 = hex_str_to_bytes('86dd')
    ARP = hex_str_to_bytes('0806')
    VLAN = hex_str_to_bytes('8100')


class Ethernet:
    """Representation of an Ethernet packet."""

    def __init__(self, pkt_bytes, time=None):
        """Decodes the specified Ethernet packet.

        Supports raw Ethernet frames, and Ethernet frames containing tagged
        802.1q VLANs.

        The VID will be placed in the `vid` attribute, and the payload (next
        layer packet) will be placed in the `payload` attribute.

        If specified, the time will be stored in the `time` attribute.

        The source MAC, destination MAC, and payload Ethertype will be
        stored in `src_mac`, `dst_mac`, and `ethertype` attributes,
        respectively.

        :param pkt_bytes: The input bytes of the Ethernet packet.
        :type pkt_bytes: bytes
        :param time: Timestamp packet was seen (seconds since epoch)
        :type time: str
        :return:
        """
        if len(pkt_bytes) < ETHERNET_HEADER_LEN:
            self.valid = False
            return
        packet = EthernetPacket._make(
            struct.unpack(ETHERNET_PACKET, pkt_bytes[0:ETHERNET_HEADER_LEN]))
        payload_index = ETHERNET_HEADER_LEN
        if packet.ethertype == ETHERTYPE.VLAN:
            # We found an 802.1q encapsulated frame. The next four bytes are
            # the QoS, VLAN ID,and the Ethertype of the encapsulated frame.
            if len(pkt_bytes) < (ETHERNET_HEADER_LEN + VLAN_HEADER_LEN):
                self.valid = False
                return
            vid, ethertype = struct.unpack(
                VLAN_HEADER,
                pkt_bytes[payload_index:payload_index + VLAN_HEADER_LEN])
            vid = bytes_to_int(vid)
            # The VLAN is the lower 12 bits; the upper 4 bits are for QoS.
            vid &= 0xFFF
            self.vid = vid
            # Use the Ethertype found in the VLAN header.
            self.ethertype = ethertype
            payload_index += VLAN_HEADER_LEN
        else:
            self.vid = None
            self.ethertype = packet.ethertype
        self.valid = True
        self.packet = packet
        self.payload = pkt_bytes[payload_index:]
        self.src_mac = packet.src_mac
        self.dst_mac = packet.dst_mac
        self.time = time

    @property
    def src_eui(self):
        """Returns a netaddr.EUI representing the source MAC address."""
        return EUI(bytes_to_int(self.src_mac))

    @property
    def dst_eui(self):
        """Returns a netaddr.EUI representing the destination MAC address."""
        return EUI(bytes_to_int(self.dst_mac))

    def is_valid(self):
        """Returns True if this is a valid Ethernet packet, False otherwise."""
        return self.valid