aboutsummaryrefslogtreecommitdiffstats
path: root/packet-arp.c
blob: b3ddf2149dec2b35f97dc1103008c9d6825e7f49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/* packet-arp.c
 * Routines for ARP packet disassembly
 *
 * $Id: packet-arp.c,v 1.14 1999/07/07 22:51:40 gram Exp $
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@zing.org>
 * Copyright 1998 Gerald Combs
 *
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif

#include <glib.h>
#include "packet.h"
#include "etypes.h"

/* Definitions taken from Linux "linux/if_arp.h" header file, and from

	http://www.isi.edu/in-notes/iana/assignments/arp-parameters

 */

/* ARP protocol HARDWARE identifiers. */
#define ARPHRD_NETROM	0		/* from KA9Q: NET/ROM pseudo	*/
#define ARPHRD_ETHER 	1		/* Ethernet 10Mbps		*/
#define	ARPHRD_EETHER	2		/* Experimental Ethernet	*/
#define	ARPHRD_AX25	3		/* AX.25 Level 2		*/
#define	ARPHRD_PRONET	4		/* PROnet token ring		*/
#define	ARPHRD_CHAOS	5		/* Chaosnet			*/
#define	ARPHRD_IEEE802	6		/* IEEE 802.2 Ethernet/TR/TB	*/
#define	ARPHRD_ARCNET	7		/* ARCnet			*/
#define	ARPHRD_HYPERCH	8		/* Hyperchannel			*/
#define	ARPHRD_LANSTAR	9		/* Lanstar			*/
#define	ARPHRD_AUTONET	10		/* Autonet Short Address	*/
#define	ARPHRD_LOCALTLK	11		/* Localtalk			*/
#define	ARPHRD_LOCALNET	12		/* LocalNet (IBM PCNet/Sytek LocalNET) */
#define	ARPHRD_ULTRALNK	13		/* Ultra link			*/
#define	ARPHRD_SMDS	14		/* SMDS				*/
#define ARPHRD_DLCI	15		/* Frame Relay DLCI		*/
#define ARPHRD_ATM	16		/* ATM				*/
#define ARPHRD_HDLC	17		/* HDLC				*/
#define ARPHRD_FIBREC	18		/* Fibre Channel		*/
#define ARPHRD_ATM2225	19		/* ATM (RFC 2225)		*/
#define ARPHRD_SERIAL	20		/* Serial Line			*/
#define ARPHRD_ATM2	21		/* ATM				*/
#define ARPHRD_MS188220	22		/* MIL-STD-188-220		*/
#define ARPHRD_METRICOM	23		/* Metricom STRIP		*/
#define ARPHRD_IEEE1394	24		/* IEEE 1394.1995		*/
#define ARPHRD_MAPOS	25		/* MAPOS			*/
#define ARPHRD_TWINAX	26		/* Twinaxial			*/
#define ARPHRD_EUI_64	27		/* EUI-64			*/

/* ARP / RARP structs and definitions */
#ifndef ARPOP_REQUEST
#define ARPOP_REQUEST  1       /* ARP request.  */
#endif
#ifndef ARPOP_REPLY
#define ARPOP_REPLY    2       /* ARP reply.  */
#endif
/* Some OSes have different names, or don't define these at all */
#ifndef ARPOP_RREQUEST
#define ARPOP_RREQUEST 3       /* RARP request.  */
#endif
#ifndef ARPOP_RREPLY
#define ARPOP_RREPLY   4       /* RARP reply.  */
#endif

gchar *
arphrdaddr_to_str(guint8 *ad, int ad_len, guint16 type) {
  if ((type == ARPHRD_ETHER || type == ARPHRD_EETHER || type == ARPHRD_IEEE802)
  				&& ad_len == 6) {
    /* Ethernet address (or Experimental 3Mb Ethernet, or IEEE 802.x
       address, which are the same type of address). */
    return ether_to_str(ad);
  }
  return bytes_to_str(ad, ad_len);
}

static gchar *
arpproaddr_to_str(guint8 *ad, int ad_len, guint16 type) {
  if (type == ETHERTYPE_IP && ad_len == 4) {
    /* IP address.  */
    return ip_to_str(ad);
  }
  return bytes_to_str(ad, ad_len);
}

gchar *
arphrdtype_to_str(guint16 hwtype, const char *fmt) {
  static const value_string hrd_vals[] = {
    {ARPHRD_NETROM,   "NET/ROM pseudo"       },
    {ARPHRD_ETHER,    "Ethernet"             },
    {ARPHRD_EETHER,   "Experimental Ethernet"},
    {ARPHRD_AX25,     "AX.25"                },
    {ARPHRD_PRONET,   "ProNET"               },
    {ARPHRD_CHAOS,    "Chaos"                },
    {ARPHRD_IEEE802,  "IEEE 802"             },
    {ARPHRD_ARCNET,   "ARCNET"               },
    {ARPHRD_HYPERCH,  "Hyperchannel"         },
    {ARPHRD_LANSTAR,  "Lanstar"              },
    {ARPHRD_AUTONET,  "Autonet Short Address"},
    {ARPHRD_LOCALTLK, "Localtalk"            },
    {ARPHRD_LOCALNET, "LocalNet"             },
    {ARPHRD_ULTRALNK, "Ultra link"           },
    {ARPHRD_SMDS,     "SMDS"                 },
    {ARPHRD_DLCI,     "Frame Relay DLCI"     },
    {ARPHRD_ATM,      "ATM"                  },
    {ARPHRD_HDLC,     "HDLC"                 },
    {ARPHRD_FIBREC,   "Fibre Channel"        },
    {ARPHRD_ATM2225,  "ATM (RFC 2225)"       },
    {ARPHRD_SERIAL,   "Serial Line"          },
    {ARPHRD_ATM2,     "ATM"                  },
    {ARPHRD_MS188220, "MIL-STD-188-220"      },
    {ARPHRD_METRICOM, "Metricom STRIP"       },
    {ARPHRD_IEEE1394, "IEEE 1394.1995"       },
    {ARPHRD_MAPOS,    "MAPOS"                },
    {ARPHRD_TWINAX,   "Twinaxial"            },
    {ARPHRD_EUI_64,   "EUI-64"               },
    {0,                NULL                  } };

    return val_to_str(hwtype, hrd_vals, fmt);
}

/* Offsets of fields within an ARP packet. */
#define	AR_HRD		0
#define	AR_PRO		2
#define	AR_HLN		4
#define	AR_PLN		5
#define	AR_OP		6

void
dissect_arp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
  guint16     ar_hrd;
  guint16     ar_pro;
  guint8      ar_hln;
  guint8      ar_pln;
  guint16     ar_op;
  proto_tree  *arp_tree;
  proto_item  *ti;
  gchar       *op_str;
  int         sha_offset, spa_offset, tha_offset, tpa_offset;
  gchar       *sha_str, *spa_str, *tha_str, *tpa_str;
  static const value_string op_vals[] = {
    {ARPOP_REQUEST,  "ARP request" },
    {ARPOP_REPLY,    "ARP reply"   },
    {ARPOP_RREQUEST, "RARP request"},
    {ARPOP_RREPLY,   "RARP reply"  },
    {0,              NULL          } };

  /* To do: Check for {cap len,pkt len} < struct len */
  ar_hrd = pntohs(&pd[offset + AR_HRD]);
  ar_pro = pntohs(&pd[offset + AR_PRO]);
  ar_hln = (guint8) pd[offset + AR_HLN];
  ar_pln = (guint8) pd[offset + AR_PLN];
  ar_op  = pntohs(&pd[offset + AR_OP]);

  /* Extract the addresses.  */
  sha_offset = offset + 8;
  sha_str = arphrdaddr_to_str((guint8 *) &pd[sha_offset], ar_hln, ar_hrd);
  spa_offset = sha_offset + ar_hln;
  spa_str = arpproaddr_to_str((guint8 *) &pd[spa_offset], ar_pln, ar_pro);
  tha_offset = spa_offset + ar_pln;
  tha_str = arphrdaddr_to_str((guint8 *) &pd[tha_offset], ar_hln, ar_hrd);
  tpa_offset = tha_offset + ar_hln;
  tpa_str = arpproaddr_to_str((guint8 *) &pd[tpa_offset], ar_pln, ar_pro);
  
  if (check_col(fd, COL_PROTOCOL)) {
    if ((op_str = match_strval(ar_op, op_vals)))
      col_add_str(fd, COL_PROTOCOL, op_str);
    else
      col_add_str(fd, COL_PROTOCOL, "ARP");
  }

  if (check_col(fd, COL_INFO)) {
    switch (ar_op) {
      case ARPOP_REQUEST:
        col_add_fstr(fd, COL_INFO, "Who has %s?  Tell %s",
          tpa_str, spa_str);
        break;
      case ARPOP_REPLY:
        col_add_fstr(fd, COL_INFO, "%s is at %s", spa_str, sha_str);
        break;
      case ARPOP_RREQUEST:
        col_add_fstr(fd, COL_INFO, "Who is %s?  Tell %s",
          tha_str, sha_str);
        break;
      case ARPOP_RREPLY:
        col_add_fstr(fd, COL_INFO, "%s is at %s", sha_str, spa_str);
        break;
      default:
        col_add_fstr(fd, COL_INFO, "Unknown ARP opcode 0x%04x", ar_op);
        break;
    }
  }

  if (tree) {
    if ((op_str = match_strval(ar_op, op_vals)))
      ti = proto_tree_add_text(tree, offset, 8 + 2*ar_hln + 2*ar_pln,
        op_str);
    else
      ti = proto_tree_add_text(tree, offset, 8 + 2*ar_hln + 2*ar_pln,
        "Unknown ARP (opcode 0x%04x)", ar_op);
    arp_tree = proto_item_add_subtree(ti, ETT_ARP);
    proto_tree_add_text(arp_tree, offset + AR_HRD, 2,
      "Hardware type: %s", arphrdtype_to_str(ar_hrd, "Unknown (0x%04x)"));
    proto_tree_add_text(arp_tree, offset + AR_PRO, 2,
      "Protocol type: %s", val_to_str(ar_pro, etype_vals, "Unknown (0x%04x)"));
    proto_tree_add_text(arp_tree, offset + AR_HLN, 1,
      "Hardware size: %d", ar_hln);
    proto_tree_add_text(arp_tree, offset + AR_PLN, 1,
      "Protocol size: %d", ar_pln);
    proto_tree_add_text(arp_tree, offset + AR_OP,  2,
      "Opcode: 0x%04x (%s)", ar_op, op_str ? op_str : "Unknown");
    proto_tree_add_text(arp_tree, sha_offset, ar_hln,
      "Sender hardware address: %s", sha_str);
    proto_tree_add_text(arp_tree, spa_offset, ar_pln,
      "Sender protocol address: %s", spa_str);
    proto_tree_add_text(arp_tree, tha_offset, ar_hln,
      "Target hardware address: %s", tha_str);
    proto_tree_add_text(arp_tree, tpa_offset, ar_pln,
      "Target protocol address: %s", tpa_str);
  }
}