The branch main has been updated by otis:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=2deeed061b1473a4230211c6562a533b76ce846c

commit 2deeed061b1473a4230211c6562a533b76ce846c
Author:     Juraj Lutter <[email protected]>
AuthorDate: 2025-10-29 20:48:21 +0000
Commit:     Juraj Lutter <[email protected]>
CommitDate: 2025-11-02 15:17:47 +0000

    sockstat(1): Add "-F" parameter
    
    Add "-F" parameter that, when specified, instructs sockstat(1) to
    only display sockets for username/UID specified.
    
    For consistency with "-j", the last occurence of "-F" is used.
    
    Reviewed by:            asomers
    Approved by:            asomers
    Differential Revision:  https://reviews.freebsd.org/D53458
---
 usr.bin/sockstat/main.c     | 170 +++++++++++++++++++++++++++++++++-----------
 usr.bin/sockstat/sockstat.1 |   7 +-
 2 files changed, 136 insertions(+), 41 deletions(-)

diff --git a/usr.bin/sockstat/main.c b/usr.bin/sockstat/main.c
index 07663e54534d..1f174d827e1a 100644
--- a/usr.bin/sockstat/main.c
+++ b/usr.bin/sockstat/main.c
@@ -88,6 +88,7 @@ static bool    opt_A;         /* Show kernel address of pcb */
 static bool     opt_b;         /* Show BBLog state */
 static bool     opt_C;         /* Show congestion control */
 static bool     opt_c;         /* Show connected sockets */
+static bool     opt_F;         /* Show sockets for selected user only */
 static bool     opt_f;         /* Show FIB numbers */
 static bool     opt_I;         /* Show spliced socket addresses */
 static bool     opt_i;         /* Show inp_gencnt */
@@ -115,6 +116,12 @@ static size_t         default_numprotos = 
nitems(default_protos);
 static int     *protos;        /* protocols to use */
 static size_t   numprotos;     /* allocated size of protos[] */
 
+/*
+ * Show sockets for user username or UID specified
+ */
+static char    *filter_user_optarg = NULL;     /* saved optarg for 
username/UID resolving */
+static uid_t   filter_user_uid;                /* UID to show sockets for */
+
 struct addr {
        union {
                struct sockaddr_storage address;
@@ -217,6 +224,18 @@ _enforce_ksize(size_t received_size, size_t expected_size, 
const char *struct_na
 }
 #define enforce_ksize(_sz, _struct)    (_enforce_ksize(_sz, sizeof(_struct), 
#_struct))
 
+static inline bool
+filtered_uid(uid_t i_uid)
+{
+       return ((i_uid) == filter_user_uid);
+}
+
+static inline bool
+need_nosocks(void)
+{
+       return !(opt_F || (opt_j >= 0));
+}
+
 static int
 get_proto_type(const char *proto)
 {
@@ -758,7 +777,8 @@ gather_inet(int proto)
                if (sock->socket != 0)
                        RB_INSERT(socks_t, &socks, sock);
                else
-                       SLIST_INSERT_HEAD(&nosocks, sock, socket_list);
+                       if (need_nosocks())
+                               SLIST_INSERT_HEAD(&nosocks, sock, socket_list);
        }
 out:
        free(buf);
@@ -862,6 +882,8 @@ getfiles(void)
        struct xfile *xfiles;
        size_t len, olen;
 
+       int filenum = 0;
+
        olen = len = sizeof(*xfiles);
        if ((xfiles = malloc(len)) == NULL)
                xo_err(1, "malloc()");
@@ -880,14 +902,23 @@ getfiles(void)
        if ((files = malloc(nfiles * sizeof(struct file))) == NULL)
                xo_err(1, "malloc()");
 
+       /* Fill files structure, optionally for specified user */
        for (int i = 0; i < nfiles; i++) {
-               files[i].xf_data = xfiles[i].xf_data;
-               files[i].xf_pid = xfiles[i].xf_pid;
-               files[i].xf_uid = xfiles[i].xf_uid;
-               files[i].xf_fd = xfiles[i].xf_fd;
-               RB_INSERT(files_t, &ftree, &files[i]);
+               if (opt_F && !filtered_uid(xfiles[i].xf_uid))
+                               continue;
+               files[filenum].xf_data = xfiles[i].xf_data;
+               files[filenum].xf_pid = xfiles[i].xf_pid;
+               files[filenum].xf_uid = xfiles[i].xf_uid;
+               files[filenum].xf_fd = xfiles[i].xf_fd;
+               RB_INSERT(files_t, &ftree, &files[filenum]);
+               filenum++;
        }
 
+       /* Adjust global nfiles to match the number of files we
+        * actually filled into files[] array
+        */
+       nfiles = filenum;
+
        free(xfiles);
 }
 
@@ -1584,6 +1615,24 @@ display_sock(struct sock *s, struct col_widths *cw, char 
*buf, size_t bufsize)
 static void
 display(void)
 {
+       static const char *__HDR_USER="USER",
+                         *__HDR_COMMAND="COMMAND",
+                         *__HDR_PID="PID",
+                         *__HDR_FD="FD",
+                         *__HDR_PROTO="PROTO",
+                         *__HDR_LOCAL_ADDRESS="LOCAL ADDRESS",
+                         *__HDR_FOREIGN_ADDRESS="FOREIGN ADDRESS",
+                         *__HDR_PCB_KVA="PCB KVA",
+                         *__HDR_FIB="FIB",
+                         *__HDR_SPLICE_ADDRESS="SPLICE ADDRESS",
+                         *__HDR_ID="ID",
+                         *__HDR_ENCAPS="ENCAPS",
+                         *__HDR_PATH_STATE="PATH STATE",
+                         *__HDR_CONN_STATE="CONN STATE",
+                         *__HDR_BBLOG_STATE="BBLOG STATE",
+                         *__HDR_STACK="STACK",
+                         *__HDR_CC="CC";
+
        struct passwd *pwd;
        struct file *xf;
        struct sock *s;
@@ -1598,23 +1647,23 @@ display(void)
 
        if (!is_xo_style_encoding) {
                cw = (struct col_widths) {
-                       .user = strlen("USER"),
+                       .user = strlen(__HDR_USER),
                        .command = 10,
-                       .pid = strlen("PID"),
-                       .fd = strlen("FD"),
-                       .proto = strlen("PROTO"),
-                       .local_addr = opt_w ? strlen("LOCAL ADDRESS") : 21,
-                       .foreign_addr = opt_w ? strlen("FOREIGN ADDRESS") : 21,
+                       .pid = strlen(__HDR_PID),
+                       .fd = strlen(__HDR_FD),
+                       .proto = strlen(__HDR_PROTO),
+                       .local_addr = opt_w ? strlen(__HDR_LOCAL_ADDRESS) : 21,
+                       .foreign_addr = opt_w ? strlen(__HDR_FOREIGN_ADDRESS) : 
21,
                        .pcb_kva = 18,
-                       .fib = strlen("FIB"),
-                       .splice_address = strlen("SPLICE ADDRESS"),
-                       .inp_gencnt = strlen("ID"),
-                       .encaps = strlen("ENCAPS"),
-                       .path_state = strlen("PATH STATE"),
-                       .conn_state = strlen("CONN STATE"),
-                       .bblog_state = strlen("BBLOG STATE"),
-                       .stack = strlen("STACK"),
-                       .cc = strlen("CC"),
+                       .fib = strlen(__HDR_FIB),
+                       .splice_address = strlen(__HDR_SPLICE_ADDRESS),
+                       .inp_gencnt = strlen(__HDR_ID),
+                       .encaps = strlen(__HDR_ENCAPS),
+                       .path_state = strlen(__HDR_PATH_STATE),
+                       .conn_state = strlen(__HDR_CONN_STATE),
+                       .bblog_state = strlen(__HDR_BBLOG_STATE),
+                       .stack = strlen(__HDR_STACK),
+                       .cc = strlen(__HDR_CC),
                };
                calculate_column_widths(&cw);
        } else
@@ -1625,34 +1674,34 @@ display(void)
        xo_open_list("socket");
        if (!opt_q) {
                xo_emit("{T:/%-*s} {T:/%-*s} {T:/%*s} {T:/%*s} {T:/%-*s} "
-                       "{T:/%-*s} {T:/%-*s}", cw.user, "USER", cw.command,
-                       "COMMAND", cw.pid, "PID", cw.fd, "FD", cw.proto,
-                       "PROTO", cw.local_addr, "LOCAL ADDRESS",
-                       cw.foreign_addr, "FOREIGN ADDRESS");
+                       "{T:/%-*s} {T:/%-*s}", cw.user, __HDR_USER, cw.command,
+                       __HDR_COMMAND, cw.pid, __HDR_PID, cw.fd, __HDR_FD, 
cw.proto,
+                       __HDR_PROTO, cw.local_addr, __HDR_LOCAL_ADDRESS,
+                       cw.foreign_addr, __HDR_FOREIGN_ADDRESS);
                if (opt_A)
-                       xo_emit(" {T:/%-*s}", cw.pcb_kva, "PCB KVA");
+                       xo_emit(" {T:/%-*s}", cw.pcb_kva, __HDR_PCB_KVA);
                if (opt_f)
                        /* RT_MAXFIBS is 65535. */
-                       xo_emit(" {T:/%*s}", cw.fib, "FIB");
+                       xo_emit(" {T:/%*s}", cw.fib, __HDR_FIB);
                if (opt_I)
                        xo_emit(" {T:/%-*s}", cw.splice_address,
-                           "SPLICE ADDRESS");
+                           __HDR_SPLICE_ADDRESS);
                if (opt_i)
-                       xo_emit(" {T:/%*s}", cw.inp_gencnt, "ID");
+                       xo_emit(" {T:/%*s}", cw.inp_gencnt, __HDR_ID);
                if (opt_U)
-                       xo_emit(" {T:/%*s}", cw.encaps, "ENCAPS");
+                       xo_emit(" {T:/%*s}", cw.encaps, __HDR_ENCAPS);
                if (opt_s) {
                        if (show_path_state)
                                xo_emit(" {T:/%-*s}", cw.path_state,
-                                   "PATH STATE");
-                       xo_emit(" {T:/%-*s}", cw.conn_state, "CONN STATE");
+                                   __HDR_PATH_STATE);
+                       xo_emit(" {T:/%-*s}", cw.conn_state, __HDR_CONN_STATE);
                }
                if (opt_b)
-                       xo_emit(" {T:/%-*s}", cw.bblog_state, "BBLOG STATE");
+                       xo_emit(" {T:/%-*s}", cw.bblog_state, 
__HDR_BBLOG_STATE);
                if (opt_S)
-                       xo_emit(" {T:/%-*s}", cw.stack, "STACK");
+                       xo_emit(" {T:/%-*s}", cw.stack, __HDR_STACK);
                if (opt_C)
-                       xo_emit(" {T:/%-*s}", cw.cc, "CC");
+                       xo_emit(" {T:/%-*s}", cw.cc, __HDR_CC);
                xo_emit("\n");
        }
        cap_setpassent(cappwd, 1);
@@ -1684,7 +1733,7 @@ display(void)
                        xo_close_instance("socket");
                }
        }
-       if (opt_j >= 0)
+       if (!need_nosocks())
                goto out;
        SLIST_FOREACH(s, &nosocks, socket_list) {
                if (!check_ports(s))
@@ -1775,11 +1824,44 @@ jail_getvnet(int jid)
        return (vnet);
 }
 
+/*
+ * Parse username and/or UID
+ */
+static bool
+parse_filter_user(void)
+{
+       struct passwd *pwd;
+       char *ep;
+       uid_t uid;
+       bool rv = false;
+
+       uid = (uid_t)strtol(filter_user_optarg, &ep, 10);
+
+       /* Open and/or rewind capsicumized password file */
+       cap_setpassent(cappwd, 1);
+
+       if (*ep == '\0') {
+               /* We have an UID specified, check if it's valid */
+               if ((pwd = cap_getpwuid(cappwd, uid)) == NULL) 
+                       goto out;
+               filter_user_uid = uid;
+       } else {
+               /* Check if we have a valid username */
+               if ((pwd = cap_getpwnam(cappwd, filter_user_optarg)) == NULL) 
+                       goto out;
+               filter_user_uid = pwd->pw_uid;
+       }
+
+       rv = true;
+out:
+       return (rv);
+}
+
 static void
 usage(void)
 {
        xo_error(
-"usage: sockstat [--libxo ...] [-46AbCcfIiLlnqSsUuvw] [-j jid] [-p ports]\n"
+"usage: sockstat [--libxo ...] [-46AbCcfIiLlnqSsUuvw] [-F uid/username] [-j 
jid] [-p ports]\n"
 "                [-P protocols]\n");
        exit(1);
 }
@@ -1789,8 +1871,8 @@ main(int argc, char *argv[])
 {
        cap_channel_t *capcas;
        cap_net_limit_t *limit;
-       const char *pwdcmds[] = { "setpassent", "getpwuid" };
-       const char *pwdfields[] = { "pw_name" };
+       const char *pwdcmds[] = { "setpassent", "getpwuid", "getpwnam" };
+       const char *pwdfields[] = { "pw_name", "pw_uid" };
        int protos_defined = -1;
        int o, i, err;
 
@@ -1803,7 +1885,7 @@ main(int argc, char *argv[])
                        is_xo_style_encoding = true;
        }
        opt_j = -1;
-       while ((o = getopt(argc, argv, "46AbCcfIij:Llnp:P:qSsUuvw")) != -1)
+       while ((o = getopt(argc, argv, "46AbCcF:fIij:Llnp:P:qSsUuvw")) != -1)
                switch (o) {
                case '4':
                        opt_4 = true;
@@ -1823,6 +1905,11 @@ main(int argc, char *argv[])
                case 'c':
                        opt_c = true;
                        break;
+               case 'F':
+                       /* Save optarg for later use when we enter capabilities 
mode */
+                       filter_user_optarg = optarg;
+                       opt_F = true;
+                       break;
                case 'f':
                        opt_f = true;
                        break;
@@ -1934,6 +2021,9 @@ main(int argc, char *argv[])
        if (cap_pwd_limit_fields(cappwd, pwdfields, nitems(pwdfields)) < 0)
                xo_err(1, "Unable to apply pwd commands limits");
 
+       if (opt_F && !parse_filter_user())
+               xo_errx(1, "Invalid username or UID specified");
+
        if ((!opt_4 && !opt_6) && protos_defined != -1)
                opt_4 = opt_6 = true;
        if (!opt_4 && !opt_6 && !opt_u)
diff --git a/usr.bin/sockstat/sockstat.1 b/usr.bin/sockstat/sockstat.1
index 1498fb1d88f7..b0fae81ee566 100644
--- a/usr.bin/sockstat/sockstat.1
+++ b/usr.bin/sockstat/sockstat.1
@@ -25,7 +25,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd October 14, 2025
+.Dd October 29, 2025
 .Dt SOCKSTAT 1
 .Os
 .Sh NAME
@@ -35,6 +35,7 @@
 .Nm
 .Op Fl -libxo
 .Op Fl 46AbCcfIiLlnqSsUuvw
+.Op Fl F Ar user
 .Op Fl j Ar jail
 .Op Fl p Ar ports
 .Op Fl P Ar protocols
@@ -73,6 +74,10 @@ Display the congestion control module, if applicable.
 This is currently only implemented for TCP.
 .It Fl c
 Show connected sockets.
+.It Fl F Ar user
+Show sockets for specified
+.Ar user
+(user name or UID) only.
 .It Fl f
 Show the FIB number of each socket.
 .It Fl I

Reply via email to