I want to use dtrace to show information about tcp connect, accepts, and data sends...but i also want to show port and ip information.
Is there a way of doing this on osx? I notice that osx does not have a TCP provider (unlike solaris), but is there another way of doing it?
OSX does have a TCP provider. Here's how to confirm:
sudo dtrace -l | perl -pe 's/^.*?\S+\s+(\S+?)([0-9]|\s).*/\1/' | sort | uniq
The following DTrace script has been tested on macOS 10.13 High Sierra and 10.12 Sierra.
Invoke like so:
sudo ./tcpsnoop.d 2>/dev/null
#!/usr/sbin/dtrace -s
#pragma D option quiet
#pragma D option switchrate=10hz
dtrace:::BEGIN
{
printf("%6s %20s %15s:%-5s %15s:%-5s %6s %s\n",
"TIME", "CMD", "LADDR", "PORT", "RADDR", "PORT", "BYTES", "FLAGS");
}
tcp:::send
{
this->length = args[2]->ip_plength - args[4]->tcp_offset;
printf("%6d %20s %15s:%-5d -> %15s:%-5d %6d (",
timestamp/1000, execname, args[2]->ip_saddr,
args[4]->tcp_sport, args[2]->ip_daddr, args[4]->tcp_dport,
this->length);
}
tcp:::receive
{
this->length = args[2]->ip_plength - args[4]->tcp_offset;
printf("%6d %20s %15s:%-5d <- %15s:%-5d %6d (",
timestamp/1000, execname, args[2]->ip_daddr,
args[4]->tcp_dport, args[2]->ip_saddr, args[4]->tcp_sport,
this->length);
}
tcp:::send,
tcp:::receive
{
printf("%s", args[4]->tcp_flags & TH_FIN ? "FIN|" : "");
printf("%s", args[4]->tcp_flags & TH_SYN ? "SYN|" : "");
printf("%s", args[4]->tcp_flags & TH_RST ? "RST|" : "");
printf("%s", args[4]->tcp_flags & TH_PUSH ? "PUSH|" : "");
printf("%s", args[4]->tcp_flags & TH_ACK ? "ACK|" : "");
printf("%s", args[4]->tcp_flags & TH_URG ? "URG|" : "");
printf("%s", args[4]->tcp_flags & TH_ECE ? "ECE|" : "");
printf("%s", args[4]->tcp_flags & TH_CWR ? "CWR|" : "");
printf("%s", args[4]->tcp_flags == 0 ? "null " : "");
printf("\b)\n");
}
Output:
TIME CMD LADDR:PORT RADDR:PORT BYTES FLAGS
146791177843 curl 192.168.232.2:56775 -> 151.101.65.69:80 16172 (SYN)
146791206127 curl 192.168.232.2:56775 -> 151.101.65.69:80 35052 (PUSH|ACK)
146791390070 curl 192.168.232.2:56775 -> 151.101.65.69:80 13292 (FIN|ACK)
Some suggestions for how to extend it:
Add a filter /execname == $1/
onto each of the three blocks tcp:::send
, tcp:::receive
, tcp:::send, tcp:::receive
.
This lets you filter by process name:
sudo ./tcpsnoop.d 2>/dev/null curl
Add a filter /progenyof($target) || pid == $target/
onto each of the three blocks tcp:::send
, tcp:::receive
, tcp:::send, tcp:::receive
.
This lets you filter by PID:
pgrep 'pritunl-openvpn' | xargs -n 1 sudo ./tcpsnoop3.d 2>/dev/null -p