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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1991-2001, 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/errno.h>
31 #include <setjmp.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 
42 #include "snoop.h"
43 
44 extern char *dlc_header;
45 extern jmp_buf xdr_err;
46 
47 static char *printip(unsigned char *);
48 static char *addrtoname_align(unsigned char *);
49 
50 static char unarp_addr[] = "Unknown";
51 char *opname[] = {
52 	"",
53 	"ARP Request",
54 	"ARP Reply",
55 	"REVARP Request",
56 	"REVARP Reply",
57 };
58 
59 void
60 interpret_arp(int flags, struct arphdr *ap, int alen)
61 {
62 	char *line;
63 	extern char *src_name, *dst_name;
64 	unsigned char *sip, *tip, *sha, *tha;
65 	char *smacbuf = NULL, *dmacbuf = NULL;
66 	int maclen;
67 	ushort_t arpop;
68 	boolean_t is_ip = B_FALSE;
69 
70 	/*
71 	 * Check that at least the generic ARP header was received.
72 	 */
73 	if (sizeof (struct arphdr) > alen)
74 		goto short_packet;
75 
76 	arpop = ntohs(ap->ar_op);
77 	maclen = ap->ar_hln;
78 	if (ntohs(ap->ar_pro) == ETHERTYPE_IP)
79 		is_ip = B_TRUE;
80 
81 	sha = (unsigned char *)(ap + 1);
82 	sip = sha + maclen;
83 	tha = sip + ap->ar_pln;
84 	tip = tha + maclen;
85 
86 	/*
87 	 * Check that the protocol/hardware addresses were received.
88 	 */
89 	if ((tip + ap->ar_pln) > ((unsigned char *)ap + alen))
90 		goto short_packet;
91 
92 	if (maclen == 0) {
93 		smacbuf = dmacbuf = unarp_addr;
94 	} else {
95 		if (((flags & F_DTAIL) && is_ip) || (arpop == ARPOP_REPLY)) {
96 			smacbuf = _link_ntoa(sha, NULL, maclen, IFT_OTHER);
97 			if (smacbuf == NULL)
98 				pr_err("Warning: malloc failure");
99 		}
100 
101 		if (((flags & F_DTAIL) && is_ip) || (arpop ==
102 		    REVARP_REQUEST) || (arpop == REVARP_REPLY)) {
103 			dmacbuf = _link_ntoa(tha, NULL, maclen, IFT_OTHER);
104 			if (dmacbuf == NULL)
105 				pr_err("Warning: malloc failure");
106 		}
107 	}
108 
109 	src_name = addrtoname_align(sip);
110 
111 	if (flags & F_SUM) {
112 
113 		line = get_sum_line();
114 
115 		switch (arpop) {
116 		case ARPOP_REQUEST:
117 			(void) snprintf(line, MAXLINE, "ARP C Who is %s ?",
118 			    printip(tip));
119 			break;
120 		case ARPOP_REPLY:
121 			(void) snprintf(line, MAXLINE, "ARP R %s is %s",
122 			    printip(sip), smacbuf);
123 			dst_name = addrtoname_align(tip);
124 			break;
125 		case REVARP_REQUEST:
126 			(void) snprintf(line, MAXLINE, "RARP C Who is %s ?",
127 			    dmacbuf);
128 			break;
129 		case REVARP_REPLY:
130 			(void) snprintf(line, MAXLINE, "RARP R %s is %s",
131 			    dmacbuf, printip(tip));
132 			dst_name = addrtoname_align(tip);
133 			break;
134 		}
135 	}
136 
137 	if (flags & F_DTAIL) {
138 		show_header("ARP:  ", "ARP/RARP Frame", alen);
139 		show_space();
140 		(void) snprintf(get_line(0, 0), get_line_remain(),
141 		    "Hardware type = %d", 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