My first dtrace script...

I had a misbehaving application (I believed it was connecting to the wrong port based on a preference setting), so I figured I’d give dtrace a try and see if I could capture the connect() system call. After a fair amount of tweaking, I was finally able to capture what I was looking for. Here’s the script:

#pragma D option quiet

typedef uint32_t in_addr_t;
typedef uint8_t sa_family_t;
typedef uint16_t in_port_t;

struct in_addr {
  in_addr_t s_addr;
};

struct sockaddr_in {
  uint8_t sin_len;
  sa_family_t sin_family;
  in_port_t sin_port;
  struct in_addr sin_addr;
  char sin_zero[8];
};

dtrace:::BEGIN
{
        /* print header */
        printf("%5s %5s %-12s %4s %5s %s\n",
            "UID", "PID", "CMD", "TYPE", "PORT", "IP_SOURCE");
}

syscall::connect:entry
/arg1/
{
        sa = (struct sockaddr_in *) copyin(
          arg1, sizeof(struct sockaddr_in));
        printf("%5d %5d %-12s %4s %5d %d.%d.%d.%d\n",
               uid, pid, execname, "tcp",
               ((sa->sin_port >> 8) | (sa->sin_port << 8)) & 0xFFFF, 
               sa->sin_addr.s_addr & 0xFF,
               (sa->sin_addr.s_addr >> 8) & 0xFF,
               (sa->sin_addr.s_addr >> 16) & 0xFF,
               sa->sin_addr.s_addr >> 24);
}

And here’s sample output from loading the Slashdot page in Safari:

:: sudo dtrace -C -s snoop-connections.d 
  UID   PID CMD          TYPE  PORT IP_SOURCE
  501 83317 Safari        tcp    80 66.35.250.150
  501 83317 Safari        tcp    80 66.35.250.150
  501 83317 Safari        tcp    80 66.35.250.55
  501 83317 Safari        tcp    80 66.35.250.55
  501 83317 Safari        tcp    80 66.35.250.55