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