# This file is Copyright 2023 Volatility Foundation and licensed under the Volatility Software License 1.0
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#
from typing import List
from volatility3.framework import interfaces, renderers, constants
from volatility3.framework.configuration import requirements
from volatility3.framework.interfaces import plugins
from volatility3.framework.symbols.linux import network
from volatility3.framework.symbols.linux.extensions import network as net_extensions
[docs]
class Addr(plugins.PluginInterface):
"""Lists network interface information for all devices"""
_required_framework_version = (2, 22, 0)
_version = (1, 0, 2)
[docs]
@classmethod
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
return [
requirements.ModuleRequirement(
name="kernel",
description="Linux kernel",
architectures=["Intel32", "Intel64"],
),
requirements.VersionRequirement(
name="Net", component=network.NetSymbols, version=(1, 0, 0)
),
]
def _gather_net_dev_info(self, net_dev: net_extensions.net_device):
mac_addr = net_dev.get_mac_address()
promisc = net_dev.promisc
operational_state = net_dev.get_operational_state()
iface_name = net_dev.get_device_name()
iface_ifindex = net_dev.ifindex
try:
net_ns_id = net_dev.get_net_namespace_id()
except AttributeError:
net_ns_id = None
# Interface IPv4 Addresses
in_device = net_dev.ip_ptr.dereference().cast("in_device")
for in_ifaddr in in_device.get_addresses():
prefix_len = in_ifaddr.get_prefix_len()
scope_type = in_ifaddr.get_scope_type()
ip_addr = in_ifaddr.get_address()
yield (
net_ns_id,
iface_ifindex,
iface_name,
mac_addr,
promisc,
ip_addr,
prefix_len,
scope_type,
operational_state,
)
# Interface IPv6 Addresses
inet6_dev = net_dev.ip6_ptr.dereference().cast("inet6_dev")
for inet6_ifaddr in inet6_dev.get_addresses():
prefix_len = inet6_ifaddr.get_prefix_len()
scope_type = inet6_ifaddr.get_scope_type()
ip6_addr = inet6_ifaddr.get_address()
yield (
net_ns_id,
iface_ifindex,
iface_name,
mac_addr,
promisc,
ip6_addr,
prefix_len,
scope_type,
operational_state,
)
def _enumerate_net_namespace_list(self):
vmlinux = self.context.modules[self.config["kernel"]]
net_type_symname = vmlinux.symbol_table_name + constants.BANG + "net"
net_device_symname = vmlinux.symbol_table_name + constants.BANG + "net_device"
network.NetSymbols.apply(self.context.symbol_space[vmlinux.symbol_table_name])
# 'net_namespace_list' exists from kernels >= 2.6.24
net_namespace_list = vmlinux.object_from_symbol("net_namespace_list")
for net_ns in net_namespace_list.to_list(net_type_symname, "list"):
yield from net_ns.dev_base_head.to_list(net_device_symname, "dev_list")
def _generator(self):
for net_dev in self._enumerate_net_namespace_list():
for (
net_ns_id,
iface_ifindex,
iface_name,
mac_addr,
promisc,
ip6_addr,
prefix_len,
scope_type,
operational_state,
) in self._gather_net_dev_info(net_dev):
yield (
0,
(
net_ns_id or renderers.NotAvailableValue(),
iface_ifindex,
iface_name,
mac_addr,
promisc,
ip6_addr,
prefix_len,
scope_type,
operational_state,
),
)
[docs]
def run(self):
headers = [
("NetNS", int),
("Index", int),
("Interface", str),
("MAC", str),
("Promiscuous", bool),
("IP", str),
("Prefix", int),
("Scope Type", str),
("State", str),
]
return renderers.TreeGrid(headers, self._generator())
[docs]
class Link(plugins.PluginInterface):
"""Lists information about network interfaces similar to `ip link show`"""
_required_framework_version = (2, 0, 0)
_version = (1, 0, 0)
[docs]
@classmethod
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
return [
requirements.ModuleRequirement(
name="kernel",
description="Linux kernel",
architectures=["Intel32", "Intel64"],
),
requirements.VersionRequirement(
name="Net", component=network.NetSymbols, version=(1, 0, 0)
),
]
def _gather_net_dev_link_info(self, net_device):
mac_addr = net_device.get_mac_address()
operational_state = net_device.get_operational_state()
iface_name = net_device.get_device_name()
mtu = net_device.mtu
qdisc_name = net_device.get_qdisc_name()
qlen = net_device.get_queue_length()
try:
net_ns_id = net_device.get_net_namespace_id()
except AttributeError:
net_ns_id = renderers.NotAvailableValue()
# Format flags to string. Drop IFF_ to match iproute2 'ip link' output.
# Also, note that iproute2 removes IFF_RUNNING, see print_link_flags()
flags_list = [
flag.replace("IFF_", "")
for flag in net_device.get_flag_names()
if flag != "IFF_RUNNING"
]
flags_str = ",".join(flags_list)
yield (
net_ns_id or renderers.NotAvailableValue(),
iface_name,
mac_addr,
operational_state,
mtu,
qdisc_name or renderers.NotAvailableValue(),
qlen,
flags_str,
)
def _generator(self):
vmlinux = self.context.modules[self.config["kernel"]]
network.NetSymbols.apply(self.context.symbol_space[vmlinux.symbol_table_name])
net_type_symname = vmlinux.symbol_table_name + constants.BANG + "net"
net_device_symname = vmlinux.symbol_table_name + constants.BANG + "net_device"
# 'net_namespace_list' exists from kernels >= 2.6.24
net_namespace_list = vmlinux.object_from_symbol("net_namespace_list")
for net_ns in net_namespace_list.to_list(net_type_symname, "list"):
for net_dev in net_ns.dev_base_head.to_list(net_device_symname, "dev_list"):
for fields in self._gather_net_dev_link_info(net_dev):
yield 0, fields
[docs]
def run(self):
headers = [
("NS", int),
("Interface", str),
("MAC", str),
("State", str),
("MTU", int),
("Qdisc", str),
("Qlen", int),
("Flags", str),
]
return renderers.TreeGrid(headers, self._generator())