Skip to content

Commit fe7961f

Browse files
authored
Merge pull request #358 from kurok/feat/udp-connection-state
[linux] Display connection state for UDP sockets
2 parents f2c00df + bd7b110 commit fe7961f

File tree

5 files changed

+91
-13
lines changed

5 files changed

+91
-13
lines changed

Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ LINUX_TESTS = lib/dialects/linux/tests/case-10-mqueue.bash \
153153
lib/dialects/linux/tests/case-20-inet6-socket-endpoint.bash \
154154
lib/dialects/linux/tests/case-20-inet-socket-endpoint.bash \
155155
lib/dialects/linux/tests/case-20-mmap.bash \
156+
lib/dialects/linux/tests/case-20-udp-socket-state.bash \
156157
lib/dialects/linux/tests/case-20-mqueue-endpoint.bash \
157158
lib/dialects/linux/tests/case-20-open-flags-cx.bash \
158159
lib/dialects/linux/tests/case-20-open-flags-path.bash \

lib/dialects/linux/dsock.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,17 @@ void build_IPstates(struct lsof_context *ctx) {
401401
(void)enter_IPstate(ctx, "TCP", "CLOSED", 0);
402402
(void)enter_IPstate(ctx, "TCP", (char *)NULL, 0);
403403
}
404+
if (!UdpSt) {
405+
/*
406+
* Linux /proc/net/udp reuses TCP state enum values:
407+
* TCP_ESTABLISHED (1) for connected UDP sockets,
408+
* TCP_CLOSE (7) for unconnected ones.
409+
* Only register ESTABLISHED — unconnected (CLOSE) is the
410+
* default state and not useful to display.
411+
*/
412+
(void)enter_IPstate(ctx, "UDP", "ESTABLISHED", TCP_ESTABLISHED);
413+
(void)enter_IPstate(ctx, "UDP", (char *)NULL, 0);
414+
}
404415
}
405416

406417
/*
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/bin/bash
2+
source tests/common.bash
3+
4+
if [ -z "$(nc -h 2>&1 | grep '\s\-4')" ]; then
5+
echo "nc does not support -4 option, skipping" >> $report
6+
exit 77
7+
fi
8+
9+
if [ -z "$(nc -h 2>&1 | grep '\s\-u')" ]; then
10+
echo "nc does not support -u option, skipping" >> $report
11+
exit 77
12+
fi
13+
14+
# Use sleep as stdin to keep nc alive without flooding data.
15+
# /dev/zero causes "Message too long" with ncat (nmap) on UDP.
16+
sleep 60 | nc -l -u -4 127.0.0.1 10001 > /dev/null &
17+
server=$!
18+
sleep 1
19+
sleep 60 | nc -u -4 127.0.0.1 10001 > /dev/null &
20+
client=$!
21+
22+
sleep 1
23+
24+
killBoth()
25+
{
26+
kill -9 $1
27+
sleep 1
28+
kill -9 $2
29+
} 2> /dev/null > /dev/null
30+
31+
fclient=/tmp/${name}-client-$$
32+
$lsof -n -P -p $client -a -i UDP > $fclient
33+
if ! cat $fclient | grep -q "UDP.*127.0.0.1:.*->127.0.0.1:10001 (ESTABLISHED)"; then
34+
echo "connected UDP socket missing ESTABLISHED state" >> $report
35+
cat $fclient >> $report
36+
killBoth $client $server
37+
rm -f $fclient
38+
exit 1
39+
fi
40+
41+
rm -f $fclient
42+
killBoth $client $server
43+
44+
exit 0

src/dialects/linux/dprint.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,25 @@ void print_tcptpi(struct lsof_context *ctx, /* context */
7777
print_unix(ctx, nl);
7878
return;
7979
}
80-
if ((Ftcptpi & TCPTPI_STATE) && Lf->lts.type == 0) {
80+
if ((Ftcptpi & TCPTPI_STATE) && Lf->lts.type >= 0) {
8181
if (!TcpSt)
8282
(void)build_IPstates(ctx);
83-
if ((s = Lf->lts.state.i + TcpStOff) < 0 || s >= TcpNstates) {
84-
(void)snpf(buf, sizeof(buf), "UNKNOWN_TCP_STATE_%d",
85-
Lf->lts.state.i);
86-
cp = buf;
87-
} else
88-
cp = TcpSt[s];
83+
switch (Lf->lts.type) {
84+
case 0: /* TCP */
85+
if ((s = Lf->lts.state.i + TcpStOff) < 0 || s >= TcpNstates) {
86+
(void)snpf(buf, sizeof(buf), "UNKNOWN_TCP_STATE_%d",
87+
Lf->lts.state.i);
88+
cp = buf;
89+
} else
90+
cp = TcpSt[s];
91+
break;
92+
case 1: /* UDP */
93+
if (!UdpSt)
94+
(void)build_IPstates(ctx);
95+
if ((s = Lf->lts.state.i + UdpStOff) >= 0 && s < UdpNstates)
96+
cp = UdpSt[s];
97+
break;
98+
}
8999
if (cp) {
90100
if (Ffield)
91101
(void)printf("%cST=%s%c", LSOF_FID_TCPTPI, cp, Terminator);

src/print.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2001,16 +2001,28 @@ static void json_print_file(struct lsof_context *ctx, int *sep) {
20012001
printf("\"tcp_info\":{");
20022002
int tsep = 0;
20032003

2004-
if ((Ftcptpi & TCPTPI_STATE) && Lf->lts.type == 0) {
2004+
if ((Ftcptpi & TCPTPI_STATE) && Lf->lts.type >= 0) {
20052005
if (!TcpNstates)
20062006
(void)build_IPstates(ctx);
20072007
int s = Lf->lts.state.i;
2008-
if (s >= 0 && s < TcpNstates && TcpSt[s])
2009-
json_print_str(&tsep, "state", TcpSt[s]);
2010-
else {
2011-
snprintf(buf, sizeof(buf), "UNKNOWN_%d", s);
2012-
json_print_str(&tsep, "state", buf);
2008+
char *st = NULL;
2009+
if (Lf->lts.type == 0) { /* TCP */
2010+
int si = s + TcpStOff;
2011+
if (si >= 0 && si < TcpNstates)
2012+
st = TcpSt[si];
2013+
if (!st) {
2014+
snprintf(buf, sizeof(buf), "UNKNOWN_TCP_STATE_%d", s);
2015+
st = buf;
2016+
}
2017+
} else if (Lf->lts.type == 1) { /* UDP */
2018+
if (!UdpSt)
2019+
(void)build_IPstates(ctx);
2020+
int si = s + UdpStOff;
2021+
if (si >= 0 && si < UdpNstates)
2022+
st = UdpSt[si];
20132023
}
2024+
if (st)
2025+
json_print_str(&tsep, "state", st);
20142026
}
20152027
#if defined(HASTCPTPIQ)
20162028
if (Ftcptpi & TCPTPI_QUEUES) {

0 commit comments

Comments
 (0)