1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #pragma ident   "%Z%%M% %I%     %E% SMI"
  27 
  28 #include <sys/types.h>
  29 #include <sys/errno.h>
  30 #include <setjmp.h>
  31 #include <sys/socket.h>
  32 #include <net/if.h>
  33 #include <net/if_arp.h>
  34 #include <netinet/in_systm.h>
  35 #include <netinet/in.h>
  36 #include <netinet/ip.h>
  37 #include <netinet/if_ether.h>
  38 #include <netdb.h>
  39 #include <net/if_types.h>
  40 
  41 #include "snoop.h"
  42 
  43 extern char *dlc_header;
  44 extern jmp_buf xdr_err;
  45 
  46 static char *printip(unsigned char *);
  47 static char *addrtoname_align(unsigned char *);
  48 
  49 static char unarp_addr[] = "Unknown";
  50 char *opname[] = {
  51         "",
  52         "ARP Request",
  53         "ARP Reply",
  54         "REVARP Request",
  55         "REVARP Reply",
  56 };
  57 
  58 void
  59 interpret_arp(int flags, struct arphdr *ap, int alen)
  60 {
  61         char *line;
  62         extern char *src_name, *dst_name;
  63         unsigned char *sip, *tip, *sha, *tha;
  64         char *smacbuf = NULL, *dmacbuf = NULL;
  65         int maclen;
  66         ushort_t arpop;
  67         boolean_t is_ip = B_FALSE;
  68 
  69         /*
  70          * Check that at least the generic ARP header was received.
  71          */
  72         if (sizeof (struct arphdr) > alen)
  73                 goto short_packet;
  74 
  75         arpop = ntohs(ap->ar_op);
  76         maclen = ap->ar_hln;
  77         if (ntohs(ap->ar_pro) == ETHERTYPE_IP)
  78                 is_ip = B_TRUE;
  79 
  80         sha = (unsigned char *)(ap + 1);
  81         sip = sha + maclen;
  82         tha = sip + ap->ar_pln;
  83         tip = tha + maclen;
  84 
  85         /*
  86          * Check that the protocol/hardware addresses were received.
  87          */
  88         if ((tip + ap->ar_pln) > ((unsigned char *)ap + alen))
  89                 goto short_packet;
  90 
  91         if (maclen == 0) {
  92                 smacbuf = dmacbuf = unarp_addr;
  93         } else {
  94                 if (((flags & F_DTAIL) && is_ip) || (arpop == ARPOP_REPLY)) {
  95                         smacbuf = _link_ntoa(sha, NULL, maclen, IFT_OTHER);
  96                         if (smacbuf == NULL)
  97                                 pr_err("Warning: malloc failure");
  98                 }
  99 
 100                 if (((flags & F_DTAIL) && is_ip) || (arpop ==
 101                     REVARP_REQUEST) || (arpop == REVARP_REPLY)) {
 102                         dmacbuf = _link_ntoa(tha, NULL, maclen, IFT_OTHER);
 103                         if (dmacbuf == NULL)
 104                                 pr_err("Warning: malloc failure");
 105                 }
 106         }
 107 
 108         src_name = addrtoname_align(sip);
 109 
 110         if (flags & F_SUM) {
 111 
 112                 line = get_sum_line();
 113 
 114                 switch (arpop) {
 115                 case ARPOP_REQUEST:
 116                         (void) snprintf(line, MAXLINE, "ARP C Who is %s ?",
 117                             printip(tip));
 118                         break;
 119                 case ARPOP_REPLY:
 120                         (void) snprintf(line, MAXLINE, "ARP R %s is %s",
 121                             printip(sip), smacbuf);
 122                         dst_name = addrtoname_align(tip);
 123                         break;
 124                 case REVARP_REQUEST:
 125                         (void) snprintf(line, MAXLINE, "RARP C Who is %s ?",
 126                             dmacbuf);
 127                         break;
 128                 case REVARP_REPLY:
 129                         (void) snprintf(line, MAXLINE, "RARP R %s is %s",
 130                             dmacbuf, printip(tip));
 131                         dst_name = addrtoname_align(tip);
 132                         break;
 133                 }
 134         }
 135 
 136         if (flags & F_DTAIL) {
 137                 show_header("ARP:  ", "ARP/RARP Frame", alen);
 138                 show_space();
 139                 (void) snprintf(get_line(0, 0), get_line_remain(),
 140                     "Hardware type = %d (%s)", ntohs(ap->ar_hrd),
 141                     arp_htype(ntohs(ap->ar_hrd)));
 142                 (void) snprintf(get_line(0, 0), get_line_remain(),
 143                     "Protocol type = %04x (%s)", ntohs(ap->ar_pro),
 144                     print_ethertype(ntohs(ap->ar_pro)));
 145                 (void) snprintf(get_line(0, 0), get_line_remain(),
 146                     "Length of hardware address = %d bytes", ap->ar_hln);
 147                 (void) snprintf(get_line(0, 0), get_line_remain(),
 148                     "Length of protocol address = %d bytes", ap->ar_pln);
 149                 (void) snprintf(get_line(0, 0), get_line_remain(),
 150                     "Opcode %d (%s)", arpop,
 151                     (arpop > REVARP_REPLY) ? opname[0] : opname[arpop]);
 152 
 153                 if (is_ip) {
 154                         (void) snprintf(get_line(0, 0), get_line_remain(),
 155                             "Sender's hardware address = %s", smacbuf);
 156                         (void) snprintf(get_line(0, 0), get_line_remain(),
 157                             "Sender's protocol address = %s",
 158                             printip(sip));
 159                         (void) snprintf(get_line(0, 0), get_line_remain(),
 160                             "Target hardware address = %s",
 161                             arpop == ARPOP_REQUEST ? "?" : dmacbuf);
 162                         (void) snprintf(get_line(0, 0), get_line_remain(),
 163                             "Target protocol address = %s",
 164                             arpop == REVARP_REQUEST ? "?" :
 165                             printip(tip));
 166                 }
 167                 show_trailer();
 168         }
 169 
 170         if (maclen != 0) {
 171                 free(smacbuf);
 172                 free(dmacbuf);
 173         }
 174         return;
 175 
 176 short_packet:
 177         if (flags & F_SUM) {
 178                 (void) snprintf(get_sum_line(), MAXLINE,
 179                     "ARP (short packet)");
 180         } else if (flags & F_DTAIL) {
 181                 show_header("ARP:  ", "ARP/RARP Frame", alen);
 182                 show_space();
 183                 (void) snprintf(get_line(0, 0), get_line_remain(),
 184                     "ARP (short packet)");
 185         }
 186 }
 187 
 188 char *
 189 printip(unsigned char *p)
 190 {
 191         static char buff[MAXHOSTNAMELEN + 32];
 192         char *ap, *np;
 193         struct in_addr a;
 194 
 195         memcpy(&a, p, 4);
 196         ap = (char *)inet_ntoa(a);
 197         np = (char *)addrtoname(AF_INET, &a);
 198         (void) snprintf(buff, MAXHOSTNAMELEN, "%s, %s", ap, np);
 199         return (buff);
 200 }
 201 
 202 char *
 203 addrtoname_align(unsigned char *p)
 204 {
 205         struct in_addr a;
 206 
 207         memcpy(&a, p, 4);
 208         return ((char *)addrtoname(AF_INET, &a));
 209 }
 210 
 211 /*
 212  * These numbers are assigned by the IANA.  See the arp-parameters registry.
 213  * Only those values that are used within Solaris have #defines.
 214  */
 215 const char *
 216 arp_htype(int t)
 217 {
 218         switch (t) {
 219         case ARPHRD_ETHER:
 220                 return ("Ethernet (10Mb)");
 221         case 2:
 222                 return ("Experimental Ethernet (3MB)");
 223         case 3:
 224                 return ("Amateur Radio AX.25");
 225         case 4:
 226                 return ("Proteon ProNET Token Ring");
 227         case 5:
 228                 return ("Chaos");
 229         case ARPHRD_IEEE802:
 230                 return ("IEEE 802");
 231         case 7:
 232                 return ("ARCNET");
 233         case 8:
 234                 return ("Hyperchannel");
 235         case 9:
 236                 return ("Lanstar");
 237         case 10:
 238                 return ("Autonet");
 239         case 11:
 240                 return ("LocalTalk");
 241         case 12:
 242                 return ("LocalNet");
 243         case 13:
 244                 return ("Ultra Link");
 245         case 14:
 246                 return ("SMDS");
 247         case ARPHRD_FRAME:
 248                 return ("Frame Relay");
 249         case ARPHRD_ATM:
 250                 return ("ATM");
 251         case ARPHRD_HDLC:
 252                 return ("HDLC");
 253         case ARPHRD_FC:
 254                 return ("Fibre Channel");
 255         case ARPHRD_IPATM:
 256                 return ("IP-ATM");
 257         case ARPHRD_TUNNEL:
 258                 return ("Tunnel");
 259         case ARPHRD_IB:
 260                 return ("IPIB");
 261         };
 262         return ("UNKNOWN");
 263 }