Demonstrations of tcpconnect, the Linux eBPF/bcc version.


This tool traces the kernel function performing active TCP connections
(eg, via a connect() syscall; accept() are passive connections). Some example
output (IP addresses changed to protect the innocent):

# ./tcpconnect
PID    COMM         IP SADDR            DADDR            DPORT
1479   telnet       4  127.0.0.1        127.0.0.1        23
1469   curl         4  10.201.219.236   54.245.105.25    80
1469   curl         4  10.201.219.236   54.67.101.145    80
1991   telnet       6  ::1              ::1              23
2015   ssh          6  fe80::2000:bff:fe82:3ac fe80::2000:bff:fe82:3ac 22

This output shows four connections, one from a "telnet" process, two from
"curl", and one from "ssh". The output details shows the IP version, source
address, destination address, and destination port. This traces attempted
connections: these may have failed.

The overhead of this tool should be negligible, since it is only tracing the
kernel functions performing connect. It is not tracing every packet and then
filtering.


The -t option prints a timestamp column:

# ./tcpconnect -t
TIME(s)  PID    COMM         IP SADDR            DADDR            DPORT
31.871   2482   local_agent  4  10.103.219.236   10.251.148.38    7001
31.874   2482   local_agent  4  10.103.219.236   10.101.3.132     7001
31.878   2482   local_agent  4  10.103.219.236   10.171.133.98    7101
90.917   2482   local_agent  4  10.103.219.236   10.251.148.38    7001
90.928   2482   local_agent  4  10.103.219.236   10.102.64.230    7001
90.938   2482   local_agent  4  10.103.219.236   10.115.167.169   7101

The output shows some periodic connections (or attempts) from a "local_agent"
process to various other addresses. A few connections occur every minute.

The -d option tracks DNS responses and tries to associate each connection with
the a previous DNS query issued before it.  If a DNS response matching the IP
is found, it will be printed. If no match was found, "No DNS Query" is printed
in this column. Queries for 127.0.0.1 and ::1 are automatically associated with
"localhost". If the time between when the DNS response was received and a
connect call was traced exceeds 100ms, the tool will print the time delta
after the query name.  See below for www.domain.com for an example.

# ./tcpconnect -d
PID    COMM         IP SADDR            DADDR            DPORT QUERY
1543   amazon-ssm-a 4  10.66.75.54      176.32.119.67    443   ec2messages.us-west-1.amazonaws.com
1479   telnet       4  127.0.0.1        127.0.0.1        23    localhost
1469   curl         4  10.201.219.236   54.245.105.25    80    www.domain.com (123.342ms)
1469   curl         4  10.201.219.236   54.67.101.145    80    No DNS Query
1991   telnet       6  ::1              ::1              23    localhost
2015   ssh          6  fe80::2000:bff:fe82:3ac fe80::2000:bff:fe82:3ac 22    anotherhost.org


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

To spot heavy outbound connections quickly one can use the -c flag. It will
count all active connections per source ip and destination ip/port.

# ./tcpconnect.py -c
Tracing connect ... Hit Ctrl-C to end
^C
LADDR                 RADDR                      RPORT             CONNECTS
192.168.10.50         172.217.21.194             443               70
192.168.10.50         172.213.11.195             443               34
192.168.10.50         172.212.22.194             443               21
[...]


The --cgroupmap option filters based on a cgroup set. It is meant to be used
with an externally created map.

# ./tcpconnect --cgroupmap /sys/fs/bpf/test01

For more details, see docs/special_filtering.md


USAGE message:

# ./tcpconnect -h

usage: tcpconnect.py [-h] [-t] [-p PID] [-P PORT] [-U] [-u UID] [-c]
                     [--cgroupmap CGROUPMAP] [--mntnsmap MNTNSMAP] [-d]

Trace TCP connects

optional arguments:
  -h, --help            show this help message and exit
  -t, --timestamp       include timestamp on output
  -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
  -c, --count           count connects per src ip and dest ip/port
  --cgroupmap CGROUPMAP
                        trace cgroups in this BPF map only
  --mntnsmap MNTNSMAP   trace mount namespaces in this BPF map only
  -d, --dns             include likely DNS query associated with each connect

examples:
    ./tcpconnect           # trace all TCP connect()s
    ./tcpconnect -t        # include timestamps
    ./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
    ./tcpconnect -c        # count connects per src ip and dest ip/port
    ./tcpconnect --cgroupmap mappath  # only trace cgroups in this BPF map
    ./tcpconnect --mntnsmap mappath   # only trace mount namespaces in the map