Added Sockstat linux plugin to enumerate all processes sockets.

The output format is based on the `ss` tools. It supports:
* Unix socket
* Inet/Inet6 sockets
* Netlink sockets
* VSock sockets
* Packet sockets
* XDP sockets (eBPF)
* Bluetooth sockets (When the respective symbols are present)

Changes to the linux Lsof plugin were required to be able to reuse its filedescriptor listing capability.
This commit is contained in:
Gustavo Moreira
2021-12-10 17:51:27 +11:00
parent 02bf609fd1
commit 6456e55ddc
4 changed files with 864 additions and 0 deletions
@@ -11,3 +11,219 @@ KERNEL_NAME = "__kernel__"
# arch/x86/include/asm/page_types.h
PAGE_SHIFT = 12
"""The value hard coded from the Linux Kernel (hence not extracted from the layer itself)"""
# Standard well-defined IP protocols.
# ref: include/uapi/linux/in.h
IP_PROTOCOLS = {
0: "IP",
1: "ICMP",
2: "IGMP",
4: "IPIP",
6: "TCP",
8: "EGP",
12: "PUP",
17: "UDP",
22: "IDP",
29: "TP",
33: "DCCP",
41: "IPV6",
46: "RSVP",
47: "GRE",
50: "ESP",
51: "AH",
92: "MTP",
94: "BEETPH",
98: "ENCAP",
103: "PIM",
108: "COMP",
132: "SCTP",
136: "UDPLITE",
137: "MPLS",
143: "ETHERNET",
255: "RAW",
262: "MPTCP",
}
# IPV6 extension headers
# ref: include/uapi/linux/in6.h
IPV6_PROTOCOLS = {
0: "HOPBYHOP_OPTS",
43: "ROUTING",
44: "FRAGMENT",
58: "ICMPv6",
59: "NO_NEXT",
60: "DESTINATION_OPTS",
135: "MOBILITY",
}
# ref: include/net/tcp_states.h
TCP_STATES = (
"",
"ESTABLISHED",
"SYN_SENT",
"SYN_RECV",
"FIN_WAIT1",
"FIN_WAIT2",
"TIME_WAIT",
"CLOSE",
"CLOSE_WAIT",
"LAST_ACK",
"LISTEN",
"CLOSING",
"TCP_NEW_SYN_RECV",
)
# ref: include/linux/net.h (socket_type enum)
SOCK_TYPES = {
1: "STREAM",
2: "DGRAM",
3: "RAW",
4: "RDM",
5: "SEQPACKET",
6: "DCCP",
10: "PACKET",
}
# Address families
# ref: include/linux/socket.h
SOCK_FAMILY = (
"AF_UNSPEC",
"AF_UNIX",
"AF_INET",
"AF_AX25",
"AF_IPX",
"AF_APPLETALK",
"AF_NETROM",
"AF_BRIDGE",
"AF_ATMPVC",
"AF_X25",
"AF_INET6",
"AF_ROSE",
"AF_DECnet",
"AF_NETBEUI",
"AF_SECURITY",
"AF_KEY",
"AF_NETLINK",
"AF_PACKET",
"AF_ASH",
"AF_ECONET",
"AF_ATMSVC",
"AF_RDS",
"AF_SNA",
"AF_IRDA",
"AF_PPPOX",
"AF_WANPIPE",
"AF_LLC",
"AF_IB",
"AF_MPLS",
"AF_CAN",
"AF_TIPC",
"AF_BLUETOOTH",
"AF_IUCV",
"AF_RXRPC",
"AF_ISDN",
"AF_PHONET",
"AF_IEEE802154",
"AF_CAIF",
"AF_ALG",
"AF_NFC",
"AF_VSOCK",
"AF_KCM",
"AF_QIPCRTR",
"AF_SMC",
"AF_XDP",
)
# Netlink protocols
# ref: include/uapi/linux/netlink.h
NETLINK_PROTOCOLS = (
"NETLINK_ROUTE",
"NETLINK_UNUSED",
"NETLINK_USERSOCK",
"NETLINK_FIREWALL",
"NETLINK_SOCK_DIAG",
"NETLINK_NFLOG",
"NETLINK_XFRM",
"NETLINK_SELINUX",
"NETLINK_ISCSI",
"NETLINK_AUDIT",
"NETLINK_FIB_LOOKUP",
"NETLINK_CONNECTOR",
"NETLINK_NETFILTER",
"NETLINK_IP6_FW",
"NETLINK_DNRTMSG",
"NETLINK_KOBJECT_UEVENT",
"NETLINK_GENERIC",
"NETLINK_DM",
"NETLINK_SCSITRANSPORT",
"NETLINK_ECRYPTFS",
"NETLINK_RDMA",
"NETLINK_CRYPTO",
"NETLINK_SMC",
)
# Short list of Ethernet Protocol ID's.
# ref: include/uapi/linux/if_ether.h
# Used in AF_PACKET socket family
ETH_PROTOCOLS = {
0x0001: "ETH_P_802_3",
0x0002: "ETH_P_AX25",
0x0003: "ETH_P_ALL",
0x0004: "ETH_P_802_2",
0x0005: "ETH_P_SNAP",
0x0006: "ETH_P_DDCMP",
0x0007: "ETH_P_WAN_PPP",
0x0008: "ETH_P_PPP_MP",
0x0009: "ETH_P_LOCALTALK",
0x000c: "ETH_P_CAN",
0x000f: "ETH_P_CANFD",
0x0010: "ETH_P_PPPTALK",
0x0011: "ETH_P_TR_802_2",
0x0016: "ETH_P_CONTROL",
0x0017: "ETH_P_IRDA",
0x0018: "ETH_P_ECONET",
0x0019: "ETH_P_HDLC",
0x001a: "ETH_P_ARCNET",
0x001b: "ETH_P_DSA",
0x001c: "ETH_P_TRAILER",
0x0060: "ETH_P_LOOP",
0x00F6: "ETH_P_IEEE802154",
0x00F7: "ETH_P_CAIF",
0x00F8: "ETH_P_XDSA",
0x00F9: "ETH_P_MAP",
0x0800: "ETH_P_IP",
0x0805: "ETH_P_X25",
0x0806: "ETH_P_ARP",
0x8035: "ETH_P_RARP",
0x809B: "ETH_P_ATALK",
0x80F3: "ETH_P_AARP",
0x8100: "ETH_P_8021Q",
}
# Connection and socket states
# ref: include/net/bluetooth/bluetooth.h
BLUETOOTH_STATES = (
"",
"CONNECTED",
"OPEN",
"BOUND",
"LISTEN",
"CONNECT",
"CONNECT2",
"CONFIG",
"DISCONN",
"CLOSED",
)
# Bluetooth protocols
# ref: include/net/bluetooth/bluetooth.h
BLUETOOTH_PROTOCOLS = (
"L2CAP",
"HCI",
"SCO",
"RFCOMM",
"BNEP",
"CMTP",
"HIDP",
"AVDTP",
)
@@ -0,0 +1,374 @@
# This file is Copyright 2021 Volatility Foundation and licensed under the Volatility Software License 1.0
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#
# Author: Gustavo Moreira
import logging
from typing import Callable
from volatility3.framework import renderers, interfaces, exceptions, constants
from volatility3.framework.configuration import requirements
from volatility3.framework.interfaces import plugins
from volatility3.framework.objects import utility
from volatility3.framework.symbols import linux
from volatility3.plugins.linux import lsof
vollog = logging.getLogger(__name__)
class SockHandlers(object):
def __init__(self, vmlinux, task):
self._vmlinux = vmlinux
self._task = task
netns_id = task.nsproxy.net_ns.get_inode()
self._netdevices = self._build_network_devices_map(netns_id)
self._sock_family_handlers = {
"AF_UNIX": self._unix_sock,
"AF_INET": self._inet_sock,
"AF_INET6": self._inet_sock,
"AF_NETLINK": self._netlink_sock,
"AF_VSOCK": self._vsock_sock,
"AF_PACKET": self._packet_sock,
"AF_XDP": self._xdp_sock,
"AF_BLUETOOTH": self._bluetooth_sock,
}
def _build_network_devices_map(self, netns_id):
netdevices_map = {}
nethead = self._vmlinux.object_from_symbol(symbol_name="net_namespace_list")
net_symname = self._vmlinux.symbol_table_name + constants.BANG + "net"
for net in nethead.to_list(net_symname, "list"):
net_device_symname = self._vmlinux.symbol_table_name + constants.BANG + "net_device"
for net_dev in net.dev_base_head.to_list(net_device_symname, "dev_list"):
if net.get_inode() != netns_id:
continue
dev_name = str(utility.array_to_string(net_dev.name))
netdevices_map[net_dev.ifindex] = dev_name
return netdevices_map
def process_sock(self, sock):
family = sock.family
extended = {}
sock_handler = self._sock_family_handlers.get(family)
if sock_handler:
try:
sock_fields = sock_handler(sock, extended)
return *sock_fields, extended
except exceptions.SymbolError as e:
# Cannot finds the *_sock type in the symbols
vollog.warning("Error processing socket family '%s': %s", family, e)
else:
vollog.warning("Unsupported family '%s'", family)
# Even if the sock family is not supported, or the required types
# are not present in the symbols, we can still show some general
# information about the socket that may be helpful.
saddr_tag = daddr_tag = state = "?"
sock_stat = saddr_tag, daddr_tag, state
return sock, sock_stat, extended
def _unix_sock(self, sock, _extended):
unix_sock = sock.cast("unix_sock")
state = unix_sock.state
saddr = unix_sock.name
sinode = unix_sock.inode
if unix_sock.peer != 0:
peer = unix_sock.peer.dereference().cast("unix_sock")
daddr = peer.name
dinode = peer.inode
else:
daddr = dinode = ""
saddr_tag = f"{saddr} {sinode}"
daddr_tag = f"{daddr} {dinode}"
sock_stat = saddr_tag, daddr_tag, state
return unix_sock, sock_stat
def _inet_sock(self, sock, _extended):
inet_sock = sock.cast("inet_sock")
saddr = inet_sock.src_addr
sport = inet_sock.src_port
daddr = inet_sock.dst_addr
dport = inet_sock.dst_port
state = inet_sock.state
if inet_sock.family == "AF_INET6":
saddr = f"[{saddr}]"
saddr_tag = f"{saddr}:{sport}"
daddr_tag = f"{daddr}:{dport}"
sock_stat = saddr_tag, daddr_tag, state
return inet_sock, sock_stat
def _netlink_sock(self, sock, _extended):
netlink_sock = sock.cast("netlink_sock")
saddr_list = []
src_portid = f"portid:{netlink_sock.portid}"
saddr_list.append(src_portid)
if netlink_sock.groups != 0:
groups_bitmap = netlink_sock.groups.dereference()
groups_str = f"groups:0x{groups_bitmap:08x}"
saddr_list.append(groups_str)
daddr_list = []
dst_portid = f"portid:{netlink_sock.dst_portid}"
daddr_list.append(dst_portid)
dst_group = f"group:0x{netlink_sock.dst_group:08x}"
daddr_list.append(dst_group)
module = netlink_sock.module
if module and netlink_sock.module.name:
module_name_str = utility.array_to_string(netlink_sock.module.name)
module_name = f"lkm:{module_name_str}"
daddr_list.append(module_name)
saddr_tag = ",".join(saddr_list)
daddr_tag = ",".join(daddr_list)
state = netlink_sock.state
sock_stat = saddr_tag, daddr_tag, state
return netlink_sock, sock_stat
def _vsock_sock(self, sock, _extended):
vsock_sock = sock.cast("vsock_sock")
saddr = vsock_sock.local_addr.svm_cid
sport = vsock_sock.local_addr.svm_port
daddr = vsock_sock.remote_addr.svm_cid
dport = vsock_sock.remote_addr.svm_port
state = "" # Protocol is always 0
saddr_tag = f"{saddr}:{sport}"
daddr_tag = f"{daddr}:{dport}"
sock_stat = saddr_tag, daddr_tag, state
return vsock_sock, sock_stat
def _packet_sock(self, sock, extended):
packet_sock = sock.cast("packet_sock")
ifindex = packet_sock.ifindex
dev_name = self._netdevices.get(ifindex, "") if ifindex > 0 else "ANY"
if sock.has_member("sk_filter"):
sock_filter = sock.sk_filter
self.__update_extra_socket_bpf(sock_filter, extended)
if sock.has_member("sk_reuseport_cb"):
sock_reuseport_cb = sock.sk_reuseport_cb
self.__update_extra_socket_bpf(sock_reuseport_cb, extended)
saddr_tag = f"{dev_name}"
daddr_tag = ""
state = packet_sock.state
sock_stat = saddr_tag, daddr_tag, state
return packet_sock, sock_stat
def __update_extra_socket_bpf(self, sock_filter, extended):
if not sock_filter:
return
extended["bpf_filter_type"] = "cBPF"
if not sock_filter.has_member("prog"):
return
bpfprog = sock_filter.prog
if not bpfprog:
return
BPF_PROG_TYPE_UNSPEC = 0
if bpfprog.type > BPF_PROG_TYPE_UNSPEC:
extended["bpf_filter_type"] = "eBPF"
bpfprog_aux = bpfprog.aux
if bpfprog_aux:
extended["bpf_filter_id"] = str(bpfprog_aux.id)
bpfprog_name = str(utility.array_to_string(bpfprog.aux.name))
if bpfprog_name:
extended["bpf_filter_name"] = bpfprog_name
def _xdp_sock(self, sock, _extended):
xdp_sock = sock.cast("xdp_sock")
device = xdp_sock.dev
if not device:
return
dev_name = utility.array_to_string(device.name)
saddr_tag = f"{dev_name}"
bpfprog = device.xdp_prog
if not bpfprog:
return
bpfprog_aux = bpfprog.aux
if bpfprog_aux:
bpfprog_id = bpfprog_aux.id
daddr_tag = f"ebpf_prog_id:{bpfprog_id}"
bpf_name = utility.array_to_string(bpfprog_aux.name)
if bpf_name:
daddr_tag += f",ebpf_prog_name:{bpf_name}"
else:
daddr_tag = ""
# Hallelujah, xdp_sock.state is an enum
xsk_state = xdp_sock.state.lookup()
state = xsk_state.replace("XSK_", "")
sock_stat = saddr_tag, daddr_tag, state
return xdp_sock, sock_stat
def _bluetooth_sock(self, sock, _extended):
bt_sock = sock.cast("bt_sock")
def bt_addr(addr):
return ":".join(reversed(["%02x" % x for x in addr.b]))
saddr_tag = daddr_tag = ""
if bt_sock.protocol == "HCI":
pinfo = bt_sock.cast("hci_pinfo")
elif bt_sock.protocol == "L2CAP":
pinfo = bt_sock.cast("l2cap_pinfo")
src_addr = bt_addr(pinfo.chan.src)
dst_addr = bt_addr(pinfo.chan.dst)
saddr_tag = f"{src_addr}"
daddr_tag = f"{dst_addr}"
elif bt_sock.protocol == "RFCOMM":
pinfo = bt_sock.cast("rfcomm_pinfo")
src_addr = bt_addr(pinfo.src)
dst_addr = bt_addr(pinfo.dst)
channel = pinfo.channel
saddr_tag = f"[{src_addr}]:{channel}"
daddr_tag = f"{dst_addr}"
else:
vollog.warning("Unsupported bluetooth protocol '%s'", bt_sock.protocol)
state = bt_sock.state
sock_stat = saddr_tag, daddr_tag, state
return bt_sock, sock_stat
class Sockstat(plugins.PluginInterface):
"""Lists all network connections for all processes."""
_required_framework_version = (2, 0, 0)
_version = (2, 0, 0)
@classmethod
def get_requirements(cls):
return [
requirements.ModuleRequirement(name="kernel", description="Linux kernel",
architectures=["Intel32", "Intel64"]),
requirements.PluginRequirement(name="lsof", plugin=lsof.Lsof, version=(2, 0, 0)),
requirements.VersionRequirement(name="linuxutils", component=linux.LinuxUtilities, version=(2, 0, 0)),
requirements.BooleanRequirement(name="unix",
description=("Show UNIX domain Sockets only"),
default=False,
optional=True),
requirements.ListRequirement(name="pids",
description="Filter results by process IDs. "
"It takes the root PID namespace identifiers.",
element_type=int,
optional=True),
requirements.IntRequirement(name="netns",
description="Filter results by network namespace. "
"Otherwise, all of them are shown.",
optional=True),
]
@classmethod
def list_sockets(cls,
context: interfaces.context.ContextInterface,
vmlinux_module_name: str,
filter_func: Callable[[int], bool] = lambda _: False):
"""
Returns every single socket descriptors
"""
vmlinux = context.modules[vmlinux_module_name]
sfop_addr = vmlinux.object_from_symbol("socket_file_ops").vol.offset
dfop_addr = vmlinux.object_from_symbol("sockfs_dentry_operations").vol.offset
fd_generator = lsof.Lsof.list_fds(context, vmlinux.name, filter_func)
for _pid, _task_comm, task, fd_fields in fd_generator:
fd_num, filp, _full_path = fd_fields
if filp.f_op not in (sfop_addr, dfop_addr):
continue
dentry = filp.get_dentry()
if not dentry:
continue
d_inode = dentry.d_inode
if not d_inode:
continue
socket_alloc = linux.LinuxUtilities.container_of(d_inode, "socket_alloc", "vfs_inode", vmlinux)
_socket = socket_alloc.socket
vfs_inode = socket_alloc.vfs_inode
if not (_socket and vfs_inode):
continue
sock = _socket.sk.dereference()
sock_type = sock.type
family = sock.family
sock_handler = SockHandlers(vmlinux, task)
sock_fields = sock_handler.process_sock(sock)
if not sock_fields:
continue
child_sock = sock_fields[0]
protocol = child_sock.protocol if hasattr(child_sock, "protocol") else ""
net = task.nsproxy.net_ns
netns_id = net.proc_inum if net.has_member("proc_inum") else net.ns.inum
yield task, netns_id, fd_num, family, sock_type, protocol, sock_fields
def _generator(self):
pids = self.config.get('pids')
filter_func = lsof.pslist.PsList.create_pid_filter(pids)
tasks_per_sock = {}
socket_generator = self.list_sockets(self.context, self.config['kernel'], filter_func=filter_func)
for task, netns, fd_num, family, sock_type, protocol, sock_fields in socket_generator:
if self.config['netns'] and self.config['netns'] != netns:
continue
sock, sock_stat, extended = sock_fields
task_comm = utility.array_to_string(task.comm)
task_info = f"{task_comm},pid={task.pid},fd={fd_num}"
if extended:
extended_str = ",".join(f"{k}={v}" for k, v in extended.items())
task_info = f"{task_info},{extended_str}"
fields = netns, family, sock_type, protocol, *sock_stat
sock_addr = sock.vol.offset
tasks_per_sock.setdefault(sock_addr, {})
tasks_per_sock[sock_addr].setdefault('tasks', [])
tasks_per_sock[sock_addr]['tasks'].append(task_info)
tasks_per_sock[sock_addr]['fields'] = fields
for data in tasks_per_sock.values():
task_list = [f"({task})" for task in data['tasks']]
tasks = ",".join(task_list)
fields = data['fields'] + (tasks,)
yield (0, fields)
def run(self):
tree_grid_args = [("NetNS", int),
("Family", str),
("Type", str),
("Proto", str),
("Source Addr:Port", str),
("Destination Addr:Port", str),
("State", str),
("Tasks", str)]
return renderers.TreeGrid(tree_grid_args, self._generator())
@@ -30,6 +30,16 @@ class LinuxKernelIntermedSymbols(intermed.IntermediateSymbolTable):
self.set_type_class('vfsmount', extensions.vfsmount)
self.set_type_class('kobject', extensions.kobject)
# Network
self.set_type_class('net', extensions.net)
self.set_type_class('sock', extensions.sock)
self.set_type_class('inet_sock', extensions.inet_sock)
self.set_type_class('unix_sock', extensions.unix_sock)
self.set_type_class('netlink_sock', extensions.netlink_sock)
self.set_type_class('packet_sock', extensions.packet_sock)
if 'bt_sock' in self.types:
self.set_type_class('bt_sock', extensions.bt_sock)
if 'module' in self.types:
self.set_type_class('module', extensions.module)
@@ -183,6 +193,10 @@ class LinuxUtilities(interfaces.configuration.VersionableInterface):
def files_descriptors_for_process(cls, context: interfaces.context.ContextInterface, symbol_table: str,
task: interfaces.objects.ObjectInterface):
# task.files can be null
if not task.files:
return
fd_table = task.files.get_fds()
if fd_table == 0:
return
@@ -267,3 +281,12 @@ class LinuxUtilities(interfaces.configuration.VersionableInterface):
list_struct = vmlinux.object(object_type = struct_name, offset = list_start.vol.offset)
yield list_struct
list_start = getattr(list_struct, list_member)
@classmethod
def container_of(cls, addr, type_name, member_name, vmlinux):
if not addr:
return
type_dec = vmlinux.get_type(type_name)
member_offset = type_dec.relative_child_offset(member_name)
container_addr = addr - member_offset
return vmlinux.object(object_type=type_name, offset=container_addr, absolute=True)
@@ -4,9 +4,15 @@
import collections.abc
import logging
import socket
from typing import Generator, Iterable, Iterator, Optional, Tuple
from volatility3.framework import constants
from volatility3.framework.constants.linux import SOCK_TYPES, SOCK_FAMILY
from volatility3.framework.constants.linux import IP_PROTOCOLS, IPV6_PROTOCOLS
from volatility3.framework.constants.linux import TCP_STATES, NETLINK_PROTOCOLS
from volatility3.framework.constants.linux import ETH_PROTOCOLS, BLUETOOTH_STATES
from volatility3.framework.constants.linux import BLUETOOTH_PROTOCOLS
from volatility3.framework import exceptions, objects, interfaces, symbols
from volatility3.framework.layers import linear
from volatility3.framework.objects import utility
@@ -539,3 +545,248 @@ class kobject(objects.StructType):
ret = refcnt.refs.counter
return ret
class mnt_namespace(objects.StructType):
def get_inode(self):
if self.has_member("proc_inum"):
return self.proc_inum
elif self.ns.has_member("inum"):
return self.ns.inum
else:
raise AttributeError("Unable to find mnt_namespace inode")
class net(objects.StructType):
def get_inode(self):
if self.has_member("proc_inum"):
return self.proc_inum
elif self.ns.has_member("inum"):
return self.ns.inum
else:
raise AttributeError("Unable to find net_namespace inode")
class sock(objects.StructType):
def __get_vol_kernel_module_name(self):
symbol_table_arr = self.vol.type_name.split("!", 1)
symbol_table = symbol_table_arr[0] if len(symbol_table_arr) == 2 else None
module_names = list(self._context.modules.get_modules_by_symbol_tables(symbol_table))
if not module_names:
raise ValueError(f"No module using the symbol table {symbol_table}")
return module_names[0]
@property
def family(self):
family_idx = self.__sk_common.skc_family
if 0 <= family_idx < len(SOCK_FAMILY):
return SOCK_FAMILY[family_idx]
else:
return "UNKNOWN"
@property
def type(self):
return SOCK_TYPES.get(self.sk_type, "")
@property
def inode(self):
if not self.sk_socket:
return 0
kernel_module_name = self.__get_vol_kernel_module_name()
kernel = self._context.modules[kernel_module_name]
socket_alloc = linux.LinuxUtilities.container_of(self.sk_socket, "socket_alloc", "socket", kernel)
vfs_inode = socket_alloc.vfs_inode
return vfs_inode.i_ino
class unix_sock(objects.StructType):
@property
def name(self):
if self.addr:
sockaddr_un = self.addr.name.cast("sockaddr_un")
saddr = str(utility.array_to_string(sockaddr_un.sun_path))
else:
saddr = ""
return saddr
@property
def protocol(self):
return ""
@property
def state(self):
"""Return a string representing the sock state."""
# Unix socket states reuse (a subset) of the inet_sock states contants
if self.sk.type == "STREAM":
state_idx = self.sk.__sk_common.skc_state
if 0 <= state_idx < len(TCP_STATES):
state = TCP_STATES[state_idx]
else:
state = "UNKNOWN"
else:
state = "UNCONNECTED"
return state
@property
def inode(self):
return self.sk.inode
class inet_sock(objects.StructType):
@property
def family(self):
family_idx = self.sk.__sk_common.skc_family
if 0 <= family_idx < len(SOCK_FAMILY):
return SOCK_FAMILY[family_idx]
else:
return "UNKNOWN"
@property
def protocol(self):
# If INET6 family and a proto is defined, we use that specific IPv6 protocol.
# Otherwise, we use the standard IP protocol.
protocol = IP_PROTOCOLS.get(self.sk.sk_protocol, "UNKNOWN")
if self.family == "AF_INET6":
protocol = IPV6_PROTOCOLS.get(self.sk.sk_protocol, protocol)
return protocol
@property
def state(self):
"""Return a string representing the sock state."""
if self.sk.type == "STREAM":
state_idx = self.sk.__sk_common.skc_state
if 0 <= state_idx < len(TCP_STATES):
state = TCP_STATES[state_idx]
else:
state = "UNKNOWN"
else:
state = "UNCONNECTED"
return state
@property
def src_port(self):
sport_le = getattr(self, "sport", getattr(self, "inet_sport", None))
if sport_le is not None:
return socket.htons(sport_le)
@property
def dst_port(self):
sk_common = self.sk.__sk_common
if hasattr(sk_common, "skc_portpair"):
dport_le = sk_common.skc_portpair & 0xffff
elif hasattr(self, "dport"):
dport_le = self.dport
elif hasattr(self, "inet_dport"):
dport_le = self.inet_dport
elif hasattr(sk_common, "skc_dport"):
dport_le = sk_common.skc_dport
else:
return
return socket.htons(dport_le)
@property
def src_addr(self):
sk_common = self.sk.__sk_common
family = sk_common.skc_family
if family == socket.AF_INET:
addr_size = 4
if hasattr(self, "rcv_saddr"):
saddr = self.rcv_saddr
elif hasattr(self, "inet_rcv_saddr"):
saddr = self.inet_rcv_saddr
else:
saddr = sk_common.skc_rcv_saddr
elif family == socket.AF_INET6:
addr_size = 16
saddr = self.pinet6.saddr
else:
return
parent_layer = self._context.layers[self.vol.layer_name]
addr_bytes = parent_layer.read(saddr.vol.offset, addr_size)
return socket.inet_ntop(family, addr_bytes)
@property
def dst_addr(self):
sk_common = self.sk.__sk_common
family = sk_common.skc_family
if family == socket.AF_INET:
if hasattr(self, "daddr") and self.daddr:
daddr = self.daddr
elif hasattr(self, "inet_daddr") and self.inet_daddr:
daddr = self.inet_daddr
else:
daddr = sk_common.skc_daddr
addr_size = 4
elif family == socket.AF_INET6:
if hasattr(self.pinet6, "daddr"):
daddr = self.pinet6.daddr
else:
daddr = sk_common.skc_v6_daddr
addr_size = 16
else:
return
parent_layer = self._context.layers[self.vol.layer_name]
addr_bytes = parent_layer.read(daddr.vol.offset, addr_size)
return socket.inet_ntop(family, addr_bytes)
class netlink_sock(objects.StructType):
@property
def protocol(self):
protocol_idx = self.sk.sk_protocol
if 0 <= protocol_idx < len(NETLINK_PROTOCOLS):
return NETLINK_PROTOCOLS[protocol_idx]
else:
return "UNKNOWN"
@property
def state(self):
# Netlink is a datagram-oriented service. We can only have
# SOCK_RAW or SOCK_DGRAM socket types.
# NOTE: We are overridden the netlink_sock.state member here
return "UNCONNECTED"
class packet_sock(objects.StructType):
@property
def protocol(self):
eth_proto = socket.htons(self.num)
if eth_proto == 0:
return ""
elif eth_proto in ETH_PROTOCOLS:
return ETH_PROTOCOLS[eth_proto]
else:
return f"0x{eth_proto:x}"
@property
def state(self):
# Packet socket types are either SOCK_RAW or SOCK_DGRAM.
# NOTE: We are overriding netlink_sock.state here
return "UNCONNECTED"
class bt_sock(objects.StructType):
@property
def protocol(self):
type_idx = self.sk.sk_protocol
if 0 <= type_idx < len(BLUETOOTH_PROTOCOLS):
state = BLUETOOTH_PROTOCOLS[type_idx]
else:
state = "UNKNOWN"
return state
@property
def state(self):
state_idx = self.sk.__sk_common.skc_state
if 0 <= state_idx < len(BLUETOOTH_STATES):
state = BLUETOOTH_STATES[state_idx]
else:
state = "UNKNOWN"
return state