2021-04-05 22:35:39 +01:00
|
|
|
#!/usr/bin/env drgn
|
2021-11-21 23:59:44 +00:00
|
|
|
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
2022-11-02 00:05:16 +00:00
|
|
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
2020-05-15 23:13:02 +01:00
|
|
|
|
2019-12-20 23:50:51 +00:00
|
|
|
"""List all TCP sockets and their cgroup v2 paths"""
|
|
|
|
|
|
|
|
import ipaddress
|
|
|
|
import socket
|
|
|
|
import struct
|
|
|
|
|
2023-02-03 20:10:10 +00:00
|
|
|
from drgn import cast
|
2022-09-13 19:01:02 +01:00
|
|
|
from drgn.helpers.common.type import enum_type_to_class
|
2019-12-20 23:50:51 +00:00
|
|
|
from drgn.helpers.linux import (
|
2020-01-03 02:14:18 +00:00
|
|
|
cgroup_path,
|
2019-12-20 23:50:51 +00:00
|
|
|
hlist_nulls_empty,
|
2023-02-03 20:10:10 +00:00
|
|
|
hlist_nulls_for_each_entry,
|
2019-12-20 23:50:51 +00:00
|
|
|
sk_fullsock,
|
|
|
|
sk_nulls_for_each,
|
2020-01-03 00:17:44 +00:00
|
|
|
sk_tcpstate,
|
2020-01-03 02:14:18 +00:00
|
|
|
sock_cgroup_ptr,
|
2019-12-20 23:50:51 +00:00
|
|
|
)
|
|
|
|
|
2020-01-14 22:25:32 +00:00
|
|
|
TcpState = enum_type_to_class(
|
|
|
|
prog["TCP_ESTABLISHED"].type_,
|
|
|
|
"TcpState",
|
|
|
|
exclude=("TCP_MAX_STATES",),
|
|
|
|
prefix="TCP_",
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2019-12-20 23:50:51 +00:00
|
|
|
def inet_sk(sk):
|
|
|
|
return cast("struct inet_sock *", sk)
|
|
|
|
|
|
|
|
|
|
|
|
def _ipv4(be32):
|
|
|
|
return ipaddress.IPv4Address(struct.pack("I", be32.value_()))
|
|
|
|
|
|
|
|
|
|
|
|
def _ipv6(in6_addr):
|
|
|
|
return ipaddress.IPv6Address(struct.pack("IIII", *in6_addr.in6_u.u6_addr32))
|
|
|
|
|
|
|
|
|
|
|
|
def _brackets(ip):
|
|
|
|
if ip.version == 4:
|
|
|
|
return "{}".format(ip.compressed)
|
|
|
|
elif ip.version == 6:
|
|
|
|
return "[{}]".format(ip.compressed)
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
|
|
def _ip_port(ip, port):
|
|
|
|
return "{:>40}:{:<6}".format(_brackets(ip), port)
|
|
|
|
|
|
|
|
|
|
|
|
def _print_sk(sk):
|
|
|
|
inet = inet_sk(sk)
|
|
|
|
|
2020-01-14 22:25:32 +00:00
|
|
|
tcp_state = TcpState(sk_tcpstate(sk))
|
2019-12-20 23:50:51 +00:00
|
|
|
|
|
|
|
if sk.__sk_common.skc_family == socket.AF_INET:
|
|
|
|
src_ip = _ipv4(sk.__sk_common.skc_rcv_saddr)
|
|
|
|
dst_ip = _ipv4(sk.__sk_common.skc_daddr)
|
|
|
|
elif sk.__sk_common.skc_family == socket.AF_INET6:
|
|
|
|
src_ip = _ipv6(sk.__sk_common.skc_v6_rcv_saddr)
|
|
|
|
dst_ip = _ipv6(sk.__sk_common.skc_v6_daddr)
|
|
|
|
else:
|
|
|
|
return
|
|
|
|
|
|
|
|
src_port = socket.ntohs(inet.inet_sport)
|
|
|
|
dst_port = socket.ntohs(sk.__sk_common.skc_dport)
|
|
|
|
|
2020-01-03 02:14:18 +00:00
|
|
|
cgrp_path = ""
|
2019-12-20 23:50:51 +00:00
|
|
|
if sk_fullsock(sk):
|
2020-01-03 02:14:18 +00:00
|
|
|
cgrp = sock_cgroup_ptr(sk.sk_cgrp_data)
|
|
|
|
cgrp_path = cgroup_path(cgrp).decode()
|
2019-12-20 23:50:51 +00:00
|
|
|
|
|
|
|
print(
|
|
|
|
"{:<12} {} {} {}".format(
|
|
|
|
tcp_state.name,
|
|
|
|
_ip_port(src_ip, src_port),
|
|
|
|
_ip_port(dst_ip, dst_port),
|
2020-01-03 02:14:18 +00:00
|
|
|
cgrp_path,
|
2020-01-14 19:43:58 +00:00
|
|
|
)
|
2019-12-20 23:50:51 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
# Uncomment to print whole struct:
|
|
|
|
# print(sk)
|
|
|
|
# print(inet)
|
2020-01-03 02:14:18 +00:00
|
|
|
# print(cgrp)
|
2019-12-20 23:50:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
tcp_hashinfo = prog.object("tcp_hashinfo")
|
|
|
|
|
|
|
|
# 1. Iterate over all TCP sockets in TCP_LISTEN state.
|
2023-01-27 14:44:43 +00:00
|
|
|
|
|
|
|
# Since Linux kernel commit cae3873c5b3a ("net: inet: Retire port only
|
|
|
|
# listening_hash") (in v5.19), listening_hash is removed and we need
|
|
|
|
# to iterate lhash2 table.
|
|
|
|
|
|
|
|
try:
|
|
|
|
for ilb in tcp_hashinfo.listening_hash:
|
2023-02-03 20:10:10 +00:00
|
|
|
for sk in hlist_nulls_for_each_entry(
|
|
|
|
"struct sock", ilb.nulls_head, "__sk_common.skc_node"
|
|
|
|
):
|
2023-01-27 14:44:43 +00:00
|
|
|
_print_sk(sk)
|
|
|
|
except AttributeError:
|
|
|
|
for i in range(tcp_hashinfo.lhash2_mask + 1):
|
|
|
|
head = tcp_hashinfo.lhash2[i].nulls_head
|
|
|
|
if hlist_nulls_empty(head):
|
|
|
|
continue
|
|
|
|
for sk in sk_nulls_for_each(head):
|
|
|
|
_print_sk(sk)
|
2019-12-20 23:50:51 +00:00
|
|
|
|
|
|
|
# 2. And all other TCP sockets.
|
|
|
|
for i in range(tcp_hashinfo.ehash_mask + 1):
|
|
|
|
head = tcp_hashinfo.ehash[i].chain
|
|
|
|
if hlist_nulls_empty(head):
|
|
|
|
continue
|
|
|
|
for sk in sk_nulls_for_each(head):
|
|
|
|
_print_sk(sk)
|