#!/usr/sbin/dtrace -Cs /* * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License") * (see http://www.opensource.org/licenses/CDDL-1.0). * You may not use this file except in compliance with the License. * * Copyright (c) 2011 Jens Elkner. All rights reserved. * Use is subject to license terms. */ /** * Traces incoming and outgoing ARP packets like 'tcpdump -ennqti $ifname arp' * or 'snoop -d $ifname arp'. However, it tracks all interfaces (i.e. no need * to start an instance for every single interface) and provides IMHO a better * human readable output, than similar tools. * * NOTE: * On Solaris Express, header files are per default not installed. Fix with: * pkg install system/header */ #pragma D option quiet #include string DEC2HEX; string NULLSTR; string OP[uint32_t][2]; struct vlan_tag { ushort_t ether_tpid; ushort_t ether_tci; }; /* string MEDIA[uchar_t][2]; string HW[t_uscalar_t][2]; */ dtrace:::BEGIN { DEC2HEX = "0123456789abcdef"; NULLSTR = "00000000"; /* MEDIA[0x0][0] = "CSMACD"; MEDIA[0x0][1] = "IEEE 802.3 CSMA/CD network"; MEDIA[0x1][0] = "TPB"; MEDIA[0x1][1] = "IEEE 802.4 Token Passing Bus"; MEDIA[0x2][0] = "TPR"; MEDIA[0x2][1] = "IEEE 802.5 Token Passing Ring"; MEDIA[0x3][0] = "METRO"; MEDIA[0x3][1] = "IEEE 802.6 Metro Net"; MEDIA[0x4][0] = "ETHER"; MEDIA[0x4][1] = "Ethernet Bus"; MEDIA[0x05][0] = "HDLC"; MEDIA[0x05][1] = "ISO HDLC protocol support"; MEDIA[0x06][0] = "CHAR"; MEDIA[0x06][1] = "Character Synchronous protocol support"; MEDIA[0x07][0] = "CTCA"; MEDIA[0x07][1] = "IBM Channel-to-Channel Adapter"; MEDIA[0x08][0] = "FDDI"; MEDIA[0x08][1] = "Fiber Distributed data interface"; MEDIA[0x10][0] = "FC"; MEDIA[0x10][1] = "Fibre Channel interface"; MEDIA[0x11][0] = "ATM"; MEDIA[0x11][1] = "ATM"; MEDIA[0x12][0] = "IPATM"; MEDIA[0x12][1] = "ATM Classical IP interface"; MEDIA[0x13][0] = "X25"; MEDIA[0x13][1] = "X.25 LAPB interface"; MEDIA[0x14][0] = "ISDN"; MEDIA[0x14][1] = "ISDN interface"; MEDIA[0x15][0] = "HIPPI"; MEDIA[0x15][1] = "HIPPI interface"; MEDIA[0x16][0] = "100VG"; MEDIA[0x16][1] = "100 Based VG Ethernet"; MEDIA[0x17][0] = "100VGTPR"; MEDIA[0x17][1] = "100 Based VG Token Ring"; MEDIA[0x18][0] = "ETH_CSMA"; MEDIA[0x18][1] = "ISO 8802/3 and Ethernet"; MEDIA[0x19][0] = "100BT"; MEDIA[0x19][1] = "100 Base T"; MEDIA[0x1a][0] = "IB"; MEDIA[0x1a][1] = "Infiniband"; MEDIA[0x0a][0] = "FRAME"; MEDIA[0x0a][1] = "Frame Relay LAPF"; MEDIA[0x0b][0] = "MPFRAME"; MEDIA[0x0b][1] = "Multi-protocol over Frame Relay"; MEDIA[0x0c][0] = "ASYNC"; MEDIA[0x0c][1] = "Character Asynchronous Protocol"; MEDIA[0x0d][0] = "IPX25"; MEDIA[0x0d][1] = "X.25 Classical IP interface"; MEDIA[0x0e][0] = "LOOP"; MEDIA[0x0e][1] = "software loopback"; MEDIA[0x09][0] = "OTHER"; MEDIA[0x09][1] = "Any other medium not listed above"; HW[1][0] = "ETHER"; HW[1][1] = "ethernet hardware address"; HW[2][0] = "EETHER"; HW[2][1] = "experimental ethernet"; HW[3][0] = "AX25"; HW[3][1] = "amateur readio ax.25"; HW[5][0] = "CHAOS"; HW[5][1] = "Chaos net"; HW[6][0] = "IEEE802"; HW[6][1] = "IEEE 802 hardware address"; HW[7][0] = "ARCNET"; HW[7][1] = "ARCNET"; HW[15][0] = "FRAME"; HW[15][1] = "Frame relay"; HW[16][0] = "ATM"; HW[16][1] = "ATM"; HW[17][0] = "HDLC"; HW[17][1] = "HDLC"; HW[18][0] = "FC"; HW[18][1] = "Fibre Channel RFC 4338"; HW[19][0] = "IPATM"; HW[19][1] = "ATM RFC 2225"; HW[23][0] = "METRICOM"; HW[23][1] = "Metricom"; HW[31][0] = "TUNNEL"; HW[31][1] = "IPsec Tunnel RFC 3456"; HW[32][0] = "IB"; HW[32][1] = "IPoIB hardware address"; */ OP[1][0] = "R"; OP[1][1] = "request to resolve address"; OP[2][0] = "A"; OP[2][1] = "response to previous request"; OP[3][0] = "RR"; OP[3][1] = "Reverse ARP request"; OP[4][0] = "RA"; OP[4][1] = "Reverse ARP reply"; } #define MAC2STR(mac, dst) \ dst = (char *) alloca(ETHERADDRL*3); \ dst[2] = dst[5] = dst[8] = dst[11] = dst[14] = ':'; dst[17] = '\0'; \ dst[0] = DEC2HEX[(mac)[0] >> 4 & 0x0f]; dst[1] = DEC2HEX[(mac)[0] & 0x0f]; \ dst[3] = DEC2HEX[(mac)[1] >> 4 & 0x0f]; dst[4] = DEC2HEX[(mac)[1] & 0x0f]; \ dst[6] = DEC2HEX[(mac)[2] >> 4 & 0x0f]; dst[7] = DEC2HEX[(mac)[2] & 0x0f]; \ dst[9] = DEC2HEX[(mac)[3] >> 4 & 0x0f]; dst[10] = DEC2HEX[(mac)[3] & 0x0f]; \ dst[12] = DEC2HEX[(mac)[4] >> 4 & 0x0f]; dst[13] = DEC2HEX[(mac)[4] & 0x0f]; \ dst[15] = DEC2HEX[(mac)[5] >> 4 & 0x0f]; dst[16] = DEC2HEX[(mac)[5] & 0x0f]; #define IP2STR(ip, dst) \ dst = lltostr((ulong_t) (ip)[0]); \ dst = strjoin(dst, "."); \ dst = strjoin(dst, lltostr((ulong_t) (ip)[1])); \ dst = strjoin(dst, "."); \ dst = strjoin(dst, lltostr((ulong_t) (ip)[2])); \ dst = strjoin(dst, "."); \ dst = strjoin(dst, lltostr((ulong_t) (ip)[3])); \ #define ETHERTYPE_VLAN 0x8100 /* 802.1Q VLAN */ #define ARH_FIXED_LEN 8 /* ARP header length in octets */ #define ETHERADDRL 6 /* ethernet address length in octest */ #define IPV4_ADDR_LEN 4 /* IP addr length in octets */ /* see mac_client.c::mac_vlan_header_info(...) 4155, dld_str.c::dld_str_rx_unitdata(...) 1369 */ #define VLAN_ID(mp) *(uint16_t *) (((dl_unitdata_ind_wrapper_t *) \ ((mblk_t *)mp)->b_rptr)->dl_dest_addr + ETHERADDRL) == ETHERTYPE_VLAN \ ? ((struct vlan_tag *)((mblk_t *)mp)->b_cont->b_rptr)->ether_tci & 0x0fffu \ : 0 /* see ip_arp.c::arp_output(...) 1548 */ /** * ARP request/probe sent out by this machine. */ fbt:ip:arp_output:entry /args[0]->ill_phys_addr_length == ETHERADDRL && OP[args[1]][0] == "R"/ { /* MAC of the asking machine */ MAC2STR(args[2], this->haddr1); /* IP of the asking machine. NULL (i.e. 0.0.0.0) if it is an ARP probe. */ IP2STR(args[3] ? (string) args[3] : NULLSTR, this->paddr1); /* undefined */ /* MAC2STR(args[4] ? args[4] : NULLSTR, this->haddr2); */ /* IP for which a MAC addr is needed */ IP2STR(args[5], this->paddr2); /* MEDIA[args[0]->ill_mactype][0] */ printf("%Y OUT [%s]: Whois %s, tell %s [%s]\n", walltimestamp, args[0]->ill_phyint->phyint_name, (string) this->paddr2, (string) this->paddr1, (string) this->haddr1 ); } /** * ARP reply sent out by this machine. */ fbt:ip:arp_output:entry /args[0]->ill_phys_addr_length == ETHERADDRL && OP[args[1]][0] == "A"/ { MAC2STR(args[2], this->haddr1); /* MAC of the answering machine */ IP2STR(args[3], this->paddr1); /* IP of the answering machine */ MAC2STR(args[4], this->haddr2); /* MAC of the asking machine */ IP2STR(args[5], this->paddr2); /* IP of the asking machine */ /* MEDIA[args[0]->ill_mactype][0]; */ printf("%Y OUT [%s]: %s is %s, answering %s [%s]\n", walltimestamp, args[0]->ill_phyint->phyint_name, (string) this->paddr1, (string) this->haddr1, (string) this->paddr2, (string) this->haddr2 ); } /* see ip_arp.c::arp_process_packet(...) 898 */ /** * UnARP request received by this machine */ sdt:ip:arp_process_packet:arp-physical-in-start /((arh_t *) arg1)->arh_hlen == 0 && OP[(uint32_t)((arh_t *) arg1)->arh_operation[1]][0] == "A" / { /* no MACs in ARP header, always dstIP = 255.255.255.255 */ this->saddr = (uchar_t *)(arg1 + ARH_FIXED_LEN); IP2STR(this->saddr, this->paddr1); /* src mac not included in ARP header -> grab it from the ethernet frame: see dld_str.c::str_unitdata_ind(...) 1506 */ this->dlwp = (dl_unitdata_ind_wrapper_t *) ((mblk_t *)arg2)->b_rptr; this->dlp = (dl_unitdata_ind_t *) this->dlwp; this->eaddr = this->dlp->dl_src_addr_length ? (string) (this->dlwp->dl_src_addr) : NULLSTR; MAC2STR(this->eaddr, this->macsender); printf("%Y IN [%s]: %s says uncache %s\n", walltimestamp, (string) ((ill_t *) arg0)->ill_name, (string) this->macsender, (string) this->paddr1 ); } /** * ARP request/probe received by this machine. */ sdt:ip:arp_process_packet:arp-physical-in-start /((arh_t *) arg1)->arh_hlen == ETHERADDRL && OP[(uint32_t)((arh_t *) arg1)->arh_operation[1]][0] == "R" / { this->saddr = (uchar_t *)(arg1 + ARH_FIXED_LEN); MAC2STR(this->saddr, this->haddr1); /* MAC of the asking machine */ this->saddr += ETHERADDRL; IP2STR(this->saddr, this->paddr1); /* IP of the asking machine */ this->saddr += IPV4_ADDR_LEN + ETHERADDRL; IP2STR(this->saddr, this->paddr2); /* IP for which a MAC addr is needed */ this->vlan = VLAN_ID(arg2); printf("%Y IN [%s%s]: Whois %s, tell %s [%s]\n", walltimestamp, (string) ((ill_t *) arg0)->ill_name, this->vlan ? strjoin(" VLAN#", lltostr(this->vlan)) : "", (string) this->paddr2, (string) this->paddr1, (string) this->haddr1 ); } /** * ARP reply received by this machine. */ sdt:ip:arp_process_packet:arp-physical-in-start /((arh_t *) arg1)->arh_hlen == ETHERADDRL && OP[(uint32_t)((arh_t *) arg1)->arh_operation[1]][0] == "A" / { this->saddr = (uchar_t *)(arg1 + ARH_FIXED_LEN); MAC2STR(this->saddr, this->haddr1); /* MAC of the asking machine */ this->saddr += ETHERADDRL; IP2STR(this->saddr, this->paddr1); /* IP of the asking machine */ this->saddr += IPV4_ADDR_LEN; MAC2STR(this->saddr, this->haddr2); /* MAC of the asking machine */ this->saddr += ETHERADDRL; IP2STR(this->saddr, this->paddr2); /* IP of the asking machine */ this->vlan = VLAN_ID(arg2); printf("%Y IN [%s%s]: %s is %s, answering %s [%s]\n", walltimestamp, this->vlan ? strjoin(" VLAN#", lltostr(this->vlan)) : "", (string) ((ill_t *) arg0)->ill_name, (string) this->paddr1, (string) this->haddr1, (string) this->paddr2, (string) this->haddr2 ); }