photo by Stuart Williams
My internet provider said my service was degraded due to the large amount of data uploading from my computer. As far as I knew, my computer wasn’t uploading anything but I didn’t know how to prove it.
I decided to try and write a DTrace program to look at it. (I also installed “Little Snitch” which seems pretty cool).
One problem with using DTrace on TCP on a Mac is a lot of the providers and provider information I‘m use to on Solaris isn’t on the Mac. Another problem is that when receiving data, the program shows up as kernel_task instead of the program that the data was mean for. To get around this I did two things. One I recorded which program was using which IP when sending data and I also used some code from a program by Brendan Gregg to track which programs connected on which IPs
#!/usr/sbin/dtrace -s
#pragma D option defaultargs
#pragma D option quiet
inline int af_inet = 2; /* AF_INET defined in bsd/sys/socket.h */
inline int af_inet6 = 30; /* AF_INET6 defined in bsd/sys/socket.h */
dtrace:::BEGIN
{ TITLE = 10;
title = 0;
walltime=timestamp;
printf("starting up ...\n");
procs["0"]=" ";
}
/* syscall::connect stuff from Brendan Gregg
http://dtracebook.com/index.php/Network_Lower_Level_Protocols:soconnect.d#Mac_OS_X
*/
syscall::connect*:entry
{
/* assume this is sockaddr_in until we can examine family */
this->s = (struct sockaddr_in *)copyin(arg1, sizeof (struct sockaddr));
this->f = this->s->sin_family;
}
syscall::connect*:entry
/ this->f == af_inet
/
{
this->a = (uint8_t *)&this->s->sin_addr;
this->addr1 = strjoin(lltostr(this->a[0] + 0ULL), strjoin(".",
strjoin(lltostr(this->a[1] + 0ULL), ".")));
this->addr2 = strjoin(lltostr(this->a[2] + 0ULL), strjoin(".",
lltostr(this->a[3] + 0ULL)));
self->address = strjoin(this->addr1, this->addr2);
self->start = timestamp;
}
syscall::connect*:return
/self->start/
{
procs[self->address]=execname;
printf(" --> %-16s %s \n", execname, self->address );
self->address = 0;
self->start = 0;
}
tcp:::send, tcp:::receive
/ title == 0 /
{ printf(" %9s %8s %8s \n",
"delta" ,
"send" ,
"recd"
);
title=TITLE;
}
tcp:::send
{ delta=timestamp-walltime;
walltime=timestamp;
printf("send %9d %8d < / %8s %-15s %s\n", delta/1000, args[2]->ip_plength - args[4]->tcp_offset,
"",
args[2]->ip_daddr ,
curpsinfo->pr_psargs
);
procs[args[2]->ip_daddr]=curpsinfo->pr_psargs;
title--;
}
tcp:::receive
/ args[2]->ip_saddr != "127.0.0.1" && procs[args[2]->ip_saddr] == "" /
{ delta=timestamp-walltime;
walltime=timestamp;
printf("recd %9d %8s > \ %-8d %-15s %s (missing proc name) \n",
delta/1000,
"",
args[2]->ip_plength - args[4]->tcp_offset,
args[2]->ip_saddr ,
execname
);
}
tcp:::receive
/ args[2]->ip_saddr != "127.0.0.1" && procs[args[2]->ip_saddr] != "" /
{ delta=timestamp-walltime;
walltime=timestamp;
printf("recd %9d %8s > \ %-8d %-15s %s\n",
delta/1000,
"",
args[2]->ip_plength - args[4]->tcp_offset,
args[2]->ip_saddr ,
procs[args[2]->ip_saddr]
);
title--;
}
The output looks like
elapsed send recd IP program
send 34 49 < / 74.125.239.35 kernel_task
send 58276 49 < / 74.125.239.35 Safari
send 87468 49 < / 74.125.239.35 Safari
send 255594 49 < / 74.125.239.35 Safari
recd 46989 > \ 8241 74.125.239.35 Safari
send 69 49 < / 74.125.239.35 kernel_task
recd 36360 > \ 8113 74.125.239.53 WebProcess
send 28 49 < / 74.125.239.53 kernel_task
send 4751 65393 < / 74.125.20.84 WebProcess
Still missing some of the program names Would be nice if something like this would work
dtrace -n 'mib:::tcpInDataInorderBytes { @[execname] = sum(args[0]);}'
but mibs don’t seem to be implemented on the Mac.
So all in all “Little Snitch” seems much better, but it’s pay for package, and DTrace, at least as far as I have been able to use it, is a bit lacking.
I’m sure someone out there could but together a more useful DTrace TCP script for the Mac. Looking forward to any revelations people might have.
I once heard the quipped “you ask for hamburger and complain when I give you steak” when someone complained about not wanting to learn DTrace and just wanting to use a standard tool. I’d say instead of steak for hamburger it’s more like someone gives you a whole side of beef hanging on a hook when someone is just asking for a hamburger, or maybe like giving you the whole cattle when just wanting a hamburger. It’s often a lot of work to get to the hamburger, or steak, from there, though with some insight, especially into the kernel code, one can do amazing things.
Comments