Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ LINUX_TESTS = lib/dialects/linux/tests/case-10-mqueue.bash \
lib/dialects/linux/tests/case-20-inet6-socket-endpoint.bash \
lib/dialects/linux/tests/case-20-inet-socket-endpoint.bash \
lib/dialects/linux/tests/case-20-mmap.bash \
lib/dialects/linux/tests/case-20-udp-socket-state.bash \
lib/dialects/linux/tests/case-20-mqueue-endpoint.bash \
lib/dialects/linux/tests/case-20-open-flags-cx.bash \
lib/dialects/linux/tests/case-20-open-flags-path.bash \
Expand Down
11 changes: 11 additions & 0 deletions lib/dialects/linux/dsock.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,17 @@ void build_IPstates(struct lsof_context *ctx) {
(void)enter_IPstate(ctx, "TCP", "CLOSED", 0);
(void)enter_IPstate(ctx, "TCP", (char *)NULL, 0);
}
if (!UdpSt) {
/*
* Linux /proc/net/udp reuses TCP state enum values:
* TCP_ESTABLISHED (1) for connected UDP sockets,
* TCP_CLOSE (7) for unconnected ones.
* Only register ESTABLISHED — unconnected (CLOSE) is the
* default state and not useful to display.
*/
(void)enter_IPstate(ctx, "UDP", "ESTABLISHED", TCP_ESTABLISHED);
(void)enter_IPstate(ctx, "UDP", (char *)NULL, 0);
}
}

/*
Expand Down
44 changes: 44 additions & 0 deletions lib/dialects/linux/tests/case-20-udp-socket-state.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/bash
source tests/common.bash

if [ -z "$(nc -h 2>&1 | grep '\s\-4')" ]; then
echo "nc does not support -4 option, skipping" >> $report
exit 77
fi

if [ -z "$(nc -h 2>&1 | grep '\s\-u')" ]; then
echo "nc does not support -u option, skipping" >> $report
exit 77
fi

# Use sleep as stdin to keep nc alive without flooding data.
# /dev/zero causes "Message too long" with ncat (nmap) on UDP.
sleep 60 | nc -l -u -4 127.0.0.1 10001 > /dev/null &
server=$!
sleep 1
sleep 60 | nc -u -4 127.0.0.1 10001 > /dev/null &
client=$!

sleep 1

killBoth()
{
kill -9 $1
sleep 1
kill -9 $2
} 2> /dev/null > /dev/null

fclient=/tmp/${name}-client-$$
$lsof -n -P -p $client -a -i UDP > $fclient
if ! cat $fclient | grep -q "UDP.*127.0.0.1:.*->127.0.0.1:10001 (ESTABLISHED)"; then
echo "connected UDP socket missing ESTABLISHED state" >> $report
cat $fclient >> $report
killBoth $client $server
rm -f $fclient
exit 1
fi

rm -f $fclient
killBoth $client $server

exit 0
24 changes: 17 additions & 7 deletions src/dialects/linux/dprint.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,25 @@ void print_tcptpi(struct lsof_context *ctx, /* context */
print_unix(ctx, nl);
return;
}
if ((Ftcptpi & TCPTPI_STATE) && Lf->lts.type == 0) {
if ((Ftcptpi & TCPTPI_STATE) && Lf->lts.type >= 0) {
if (!TcpSt)
(void)build_IPstates(ctx);
if ((s = Lf->lts.state.i + TcpStOff) < 0 || s >= TcpNstates) {
(void)snpf(buf, sizeof(buf), "UNKNOWN_TCP_STATE_%d",
Lf->lts.state.i);
cp = buf;
} else
cp = TcpSt[s];
switch (Lf->lts.type) {
case 0: /* TCP */
if ((s = Lf->lts.state.i + TcpStOff) < 0 || s >= TcpNstates) {
(void)snpf(buf, sizeof(buf), "UNKNOWN_TCP_STATE_%d",
Lf->lts.state.i);
cp = buf;
} else
cp = TcpSt[s];
break;
case 1: /* UDP */
if (!UdpSt)
(void)build_IPstates(ctx);
if ((s = Lf->lts.state.i + UdpStOff) >= 0 && s < UdpNstates)
cp = UdpSt[s];
break;
}
if (cp) {
if (Ffield)
(void)printf("%cST=%s%c", LSOF_FID_TCPTPI, cp, Terminator);
Expand Down
24 changes: 18 additions & 6 deletions src/print.c
Original file line number Diff line number Diff line change
Expand Up @@ -2001,16 +2001,28 @@ static void json_print_file(struct lsof_context *ctx, int *sep) {
printf("\"tcp_info\":{");
int tsep = 0;

if ((Ftcptpi & TCPTPI_STATE) && Lf->lts.type == 0) {
if ((Ftcptpi & TCPTPI_STATE) && Lf->lts.type >= 0) {
if (!TcpNstates)
(void)build_IPstates(ctx);
int s = Lf->lts.state.i;
if (s >= 0 && s < TcpNstates && TcpSt[s])
json_print_str(&tsep, "state", TcpSt[s]);
else {
snprintf(buf, sizeof(buf), "UNKNOWN_%d", s);
json_print_str(&tsep, "state", buf);
char *st = NULL;
if (Lf->lts.type == 0) { /* TCP */
int si = s + TcpStOff;
if (si >= 0 && si < TcpNstates)
st = TcpSt[si];
if (!st) {
snprintf(buf, sizeof(buf), "UNKNOWN_TCP_STATE_%d", s);
st = buf;
}
} else if (Lf->lts.type == 1) { /* UDP */
if (!UdpSt)
(void)build_IPstates(ctx);
int si = s + UdpStOff;
if (si >= 0 && si < UdpNstates)
st = UdpSt[si];
}
if (st)
json_print_str(&tsep, "state", st);
}
#if defined(HASTCPTPIQ)
if (Ftcptpi & TCPTPI_QUEUES) {
Expand Down
Loading