diff --git a/man/man8/tcpconnect.8 b/man/man8/tcpconnect.8 index eb1f4adeccf4..60de372ce6a7 100644 --- a/man/man8/tcpconnect.8 +++ b/man/man8/tcpconnect.8 @@ -32,6 +32,12 @@ Trace this process ID only (filtered in-kernel). Comma-separated list of destination ports to trace (filtered in-kernel). .SH EXAMPLES .TP +\-U +Include a UID column. +.TP +\-u UID +Trace this UID only (filtered in-kernel). +.TP Trace all active TCP connections: # .B tcpconnect @@ -49,9 +55,22 @@ Trace ports 80 and 81 only: .B tcpconnect \-P 80,81 .SH FIELDS .TP +Trace all TCP connects, and include UID: +# +.B tcpconnect \-U +.SH FIELDS +.TP +Trace UID 1000 only: +# +.B tcpconnect \-u 1000 +.SH FIELDS +.TP TIME(s) Time of the call, in seconds. .TP +UID +User ID +.TP PID Process ID .TP diff --git a/tools/tcpconnect.py b/tools/tcpconnect.py index ddd3fa3dbafb..9fd22c0be65b 100755 --- a/tools/tcpconnect.py +++ b/tools/tcpconnect.py @@ -16,6 +16,7 @@ # # 25-Sep-2015 Brendan Gregg Created this. # 14-Feb-2016 " " Switch to bpf_perf_output. +# 09-Jan-2019 Takuma Kume Support filtering by UID from __future__ import print_function from bcc import BPF @@ -32,6 +33,8 @@ ./tcpconnect -p 181 # only trace PID 181 ./tcpconnect -P 80 # only trace port 80 ./tcpconnect -P 80,81 # only trace port 80 and 81 + ./tcpconnect -U # include UID + ./tcpconnect -u 1000 # only trace UID 1000 """ parser = argparse.ArgumentParser( description="Trace TCP connects", @@ -43,6 +46,10 @@ help="trace this PID only") parser.add_argument("-P", "--port", help="comma-separated list of destination ports to trace.") +parser.add_argument("-U", "--print-uid", action="store_true", + help="include UID on output") +parser.add_argument("-u", "--uid", + help="trace this UID only") parser.add_argument("--ebpf", action="store_true", help=argparse.SUPPRESS) args = parser.parse_args() @@ -60,6 +67,7 @@ struct ipv4_data_t { u64 ts_us; u32 pid; + u32 uid; u32 saddr; u32 daddr; u64 ip; @@ -71,6 +79,7 @@ struct ipv6_data_t { u64 ts_us; u32 pid; + u32 uid; unsigned __int128 saddr; unsigned __int128 daddr; u64 ip; @@ -84,6 +93,9 @@ u32 pid = bpf_get_current_pid_tgid(); FILTER_PID + u32 uid = bpf_get_current_uid_gid(); + FILTER_UID + // stash the sock ptr for lookup on return currsock.update(&pid, &sk); @@ -116,6 +128,7 @@ if (ipver == 4) { struct ipv4_data_t data4 = {.pid = pid, .ip = ipver}; + data4.uid = bpf_get_current_uid_gid(); data4.ts_us = bpf_ktime_get_ns() / 1000; data4.saddr = skp->__sk_common.skc_rcv_saddr; data4.daddr = skp->__sk_common.skc_daddr; @@ -125,6 +138,7 @@ } else /* 6 */ { struct ipv6_data_t data6 = {.pid = pid, .ip = ipver}; + data6.uid = bpf_get_current_uid_gid(); data6.ts_us = bpf_ktime_get_ns() / 1000; bpf_probe_read(&data6.saddr, sizeof(data6.saddr), skp->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); @@ -160,9 +174,13 @@ dports_if = ' && '.join(['dport != %d' % ntohs(dport) for dport in dports]) bpf_text = bpf_text.replace('FILTER_PORT', 'if (%s) { currsock.delete(&pid); return 0; }' % dports_if) +if args.uid: + bpf_text = bpf_text.replace('FILTER_UID', + 'if (uid != %s) { return 0; }' % args.uid) bpf_text = bpf_text.replace('FILTER_PID', '') bpf_text = bpf_text.replace('FILTER_PORT', '') +bpf_text = bpf_text.replace('FILTER_UID', '') if debug or args.ebpf: print(bpf_text) @@ -176,6 +194,7 @@ class Data_ipv4(ct.Structure): _fields_ = [ ("ts_us", ct.c_ulonglong), ("pid", ct.c_uint), + ("uid", ct.c_uint), ("saddr", ct.c_uint), ("daddr", ct.c_uint), ("ip", ct.c_ulonglong), @@ -187,6 +206,7 @@ class Data_ipv6(ct.Structure): _fields_ = [ ("ts_us", ct.c_ulonglong), ("pid", ct.c_uint), + ("uid", ct.c_uint), ("saddr", (ct.c_ulonglong * 2)), ("daddr", (ct.c_ulonglong * 2)), ("ip", ct.c_ulonglong), @@ -202,6 +222,8 @@ def print_ipv4_event(cpu, data, size): if start_ts == 0: start_ts = event.ts_us print("%-9.3f" % ((float(event.ts_us) - start_ts) / 1000000), end="") + if args.print_uid: + print("%-6d" % event.uid, end="") printb(b"%-6d %-12.12s %-2d %-16s %-16s %-4d" % (event.pid, event.task.decode('utf-8', 'replace'), event.ip, inet_ntop(AF_INET, pack("I", event.saddr)), @@ -214,6 +236,8 @@ def print_ipv6_event(cpu, data, size): if start_ts == 0: start_ts = event.ts_us print("%-9.3f" % ((float(event.ts_us) - start_ts) / 1000000), end="") + if args.print_uid: + print("%-6d" % event.uid, end="") printb(b"%-6d %-12.12s %-2d %-16s %-16s %-4d" % (event.pid, event.task.decode('utf-8', 'replace'), event.ip, inet_ntop(AF_INET6, event.saddr), inet_ntop(AF_INET6, event.daddr), @@ -229,6 +253,8 @@ def print_ipv6_event(cpu, data, size): # header if args.timestamp: print("%-9s" % ("TIME(s)"), end="") +if args.print_uid: + print("%-6s" % ("UID"), end="") print("%-6s %-12s %-2s %-16s %-16s %-4s" % ("PID", "COMM", "IP", "SADDR", "DADDR", "DPORT")) diff --git a/tools/tcpconnect_example.txt b/tools/tcpconnect_example.txt index 6d2f8f8f4419..15f6e712ef8d 100644 --- a/tools/tcpconnect_example.txt +++ b/tools/tcpconnect_example.txt @@ -38,6 +38,24 @@ The output shows some periodic connections (or attempts) from a "local_agent" process to various other addresses. A few connections occur every minute. +The -U option prints a UID column: + +# ./tcpconnect -U +UID PID COMM IP SADDR DADDR DPORT +0 31333 telnet 6 ::1 ::1 23 +0 31333 telnet 4 127.0.0.1 127.0.0.1 23 +1000 31322 curl 4 127.0.0.1 127.0.0.1 80 +1000 31322 curl 6 ::1 ::1 80 + + +The -u option filtering UID: + +# ./tcpconnect -Uu 1000 +UID PID COMM IP SADDR DADDR DPORT +1000 31338 telnet 6 ::1 ::1 23 +1000 31338 telnet 4 127.0.0.1 127.0.0.1 23 + + USAGE message: # ./tcpconnect -h @@ -51,6 +69,8 @@ optional arguments: -p PID, --pid PID trace this PID only -P PORT, --port PORT comma-separated list of destination ports to trace. + -U, --print-uid include UID on output + -u UID, --uid UID trace this UID only examples: ./tcpconnect # trace all TCP connect()s @@ -58,3 +78,5 @@ examples: ./tcpconnect -p 181 # only trace PID 181 ./tcpconnect -P 80 # only trace port 80 ./tcpconnect -P 80,81 # only trace port 80 and 81 + ./tcpconnect -U # include UID + ./tcpconnect -u 1000 # only trace UID 1000