1/*
2 * Copyright (c) 1998-2004  Hannes Gredler <hannes@tcpdump.org>
3 *      The TCPDUMP project
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code
7 * distributions retain the above copyright notice and this paragraph
8 * in its entirety, and (2) distributions including binary code include
9 * the above copyright notice and this paragraph in its entirety in
10 * the documentation or other materials provided with the distribution.
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
12 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
13 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
14 * FOR A PARTICULAR PURPOSE.
15 */
16
17#ifndef lint
18static const char rcsid[] _U_ =
19    "@(#) $Header: /tcpdump/master/tcpdump/print-eigrp.c,v 1.7 2005-05-06 02:53:26 guy Exp $";
20#endif
21
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#include <tcpdump-stdinc.h>
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include "interface.h"
33#include "extract.h"
34#include "addrtoname.h"
35
36/*
37 * packet format documented at
38 * http://www.rhyshaden.com/eigrp.htm
39 */
40
41struct eigrp_common_header {
42    u_int8_t version;
43    u_int8_t opcode;
44    u_int8_t checksum[2];
45    u_int8_t flags[4];
46    u_int8_t seq[4];
47    u_int8_t ack[4];
48    u_int8_t asn[4];
49};
50
51#define	EIGRP_VERSION                        2
52
53#define	EIGRP_OPCODE_UPDATE                  1
54#define	EIGRP_OPCODE_QUERY                   3
55#define	EIGRP_OPCODE_REPLY                   4
56#define	EIGRP_OPCODE_HELLO                   5
57#define	EIGRP_OPCODE_IPXSAP                  6
58#define	EIGRP_OPCODE_PROBE                   7
59
60static const struct tok eigrp_opcode_values[] = {
61    { EIGRP_OPCODE_UPDATE, "Update" },
62    { EIGRP_OPCODE_QUERY, "Query" },
63    { EIGRP_OPCODE_REPLY, "Reply" },
64    { EIGRP_OPCODE_HELLO, "Hello" },
65    { EIGRP_OPCODE_IPXSAP, "IPX SAP" },
66    { EIGRP_OPCODE_PROBE, "Probe" },
67    { 0, NULL}
68};
69
70static const struct tok eigrp_common_header_flag_values[] = {
71    { 0x01, "Init" },
72    { 0x02, "Conditionally Received" },
73    { 0, NULL}
74};
75
76struct eigrp_tlv_header {
77    u_int8_t type[2];
78    u_int8_t length[2];
79};
80
81#define EIGRP_TLV_GENERAL_PARM   0x0001
82#define EIGRP_TLV_AUTH           0x0002
83#define EIGRP_TLV_SEQ            0x0003
84#define EIGRP_TLV_SW_VERSION     0x0004
85#define EIGRP_TLV_MCAST_SEQ      0x0005
86#define EIGRP_TLV_IP_INT         0x0102
87#define EIGRP_TLV_IP_EXT         0x0103
88#define EIGRP_TLV_AT_INT         0x0202
89#define EIGRP_TLV_AT_EXT         0x0203
90#define EIGRP_TLV_AT_CABLE_SETUP 0x0204
91#define EIGRP_TLV_IPX_INT        0x0302
92#define EIGRP_TLV_IPX_EXT        0x0303
93
94static const struct tok eigrp_tlv_values[] = {
95    { EIGRP_TLV_GENERAL_PARM, "General Parameters"},
96    { EIGRP_TLV_AUTH, "Authentication"},
97    { EIGRP_TLV_SEQ, "Sequence"},
98    { EIGRP_TLV_SW_VERSION, "Software Version"},
99    { EIGRP_TLV_MCAST_SEQ, "Next Multicast Sequence"},
100    { EIGRP_TLV_IP_INT, "IP Internal routes"},
101    { EIGRP_TLV_IP_EXT, "IP External routes"},
102    { EIGRP_TLV_AT_INT, "AppleTalk Internal routes"},
103    { EIGRP_TLV_AT_EXT, "AppleTalk External routes"},
104    { EIGRP_TLV_AT_CABLE_SETUP, "AppleTalk Cable setup"},
105    { EIGRP_TLV_IPX_INT, "IPX Internal routes"},
106    { EIGRP_TLV_IPX_EXT, "IPX External routes"},
107    { 0, NULL}
108};
109
110struct eigrp_tlv_general_parm_t {
111    u_int8_t k1;
112    u_int8_t k2;
113    u_int8_t k3;
114    u_int8_t k4;
115    u_int8_t k5;
116    u_int8_t res;
117    u_int8_t holdtime[2];
118};
119
120struct eigrp_tlv_sw_version_t {
121    u_int8_t ios_major;
122    u_int8_t ios_minor;
123    u_int8_t eigrp_major;
124    u_int8_t eigrp_minor;
125};
126
127struct eigrp_tlv_ip_int_t {
128    u_int8_t nexthop[4];
129    u_int8_t delay[4];
130    u_int8_t bandwidth[4];
131    u_int8_t mtu[3];
132    u_int8_t hopcount;
133    u_int8_t reliability;
134    u_int8_t load;
135    u_int8_t reserved[2];
136    u_int8_t plen;
137    u_int8_t destination; /* variable length [1-4] bytes encoding */
138};
139
140struct eigrp_tlv_ip_ext_t {
141    u_int8_t nexthop[4];
142    u_int8_t origin_router[4];
143    u_int8_t origin_as[4];
144    u_int8_t tag[4];
145    u_int8_t metric[4];
146    u_int8_t reserved[2];
147    u_int8_t proto_id;
148    u_int8_t flags;
149    u_int8_t delay[4];
150    u_int8_t bandwidth[4];
151    u_int8_t mtu[3];
152    u_int8_t hopcount;
153    u_int8_t reliability;
154    u_int8_t load;
155    u_int8_t reserved2[2];
156    u_int8_t plen;
157    u_int8_t destination; /* variable length [1-4] bytes encoding */
158};
159
160struct eigrp_tlv_at_cable_setup_t {
161    u_int8_t cable_start[2];
162    u_int8_t cable_end[2];
163    u_int8_t router_id[4];
164};
165
166struct eigrp_tlv_at_int_t {
167    u_int8_t nexthop[4];
168    u_int8_t delay[4];
169    u_int8_t bandwidth[4];
170    u_int8_t mtu[3];
171    u_int8_t hopcount;
172    u_int8_t reliability;
173    u_int8_t load;
174    u_int8_t reserved[2];
175    u_int8_t cable_start[2];
176    u_int8_t cable_end[2];
177};
178
179struct eigrp_tlv_at_ext_t {
180    u_int8_t nexthop[4];
181    u_int8_t origin_router[4];
182    u_int8_t origin_as[4];
183    u_int8_t tag[4];
184    u_int8_t proto_id;
185    u_int8_t flags;
186    u_int8_t metric[2];
187    u_int8_t delay[4];
188    u_int8_t bandwidth[4];
189    u_int8_t mtu[3];
190    u_int8_t hopcount;
191    u_int8_t reliability;
192    u_int8_t load;
193    u_int8_t reserved2[2];
194    u_int8_t cable_start[2];
195    u_int8_t cable_end[2];
196};
197
198static const struct tok eigrp_ext_proto_id_values[] = {
199    { 0x01, "IGRP" },
200    { 0x02, "EIGRP" },
201    { 0x03, "Static" },
202    { 0x04, "RIP" },
203    { 0x05, "Hello" },
204    { 0x06, "OSPF" },
205    { 0x07, "IS-IS" },
206    { 0x08, "EGP" },
207    { 0x09, "BGP" },
208    { 0x0a, "IDRP" },
209    { 0x0b, "Connected" },
210    { 0, NULL}
211};
212
213void
214eigrp_print(register const u_char *pptr, register u_int len) {
215
216    const struct eigrp_common_header *eigrp_com_header;
217    const struct eigrp_tlv_header *eigrp_tlv_header;
218    const u_char *tptr,*tlv_tptr;
219    u_int tlen,eigrp_tlv_len,eigrp_tlv_type,tlv_tlen, byte_length, bit_length;
220    u_int8_t prefix[4];
221
222    union {
223        const struct eigrp_tlv_general_parm_t *eigrp_tlv_general_parm;
224        const struct eigrp_tlv_sw_version_t *eigrp_tlv_sw_version;
225        const struct eigrp_tlv_ip_int_t *eigrp_tlv_ip_int;
226        const struct eigrp_tlv_ip_ext_t *eigrp_tlv_ip_ext;
227        const struct eigrp_tlv_at_cable_setup_t *eigrp_tlv_at_cable_setup;
228        const struct eigrp_tlv_at_int_t *eigrp_tlv_at_int;
229        const struct eigrp_tlv_at_ext_t *eigrp_tlv_at_ext;
230    } tlv_ptr;
231
232    tptr=pptr;
233    eigrp_com_header = (const struct eigrp_common_header *)pptr;
234    TCHECK(*eigrp_com_header);
235
236    /*
237     * Sanity checking of the header.
238     */
239    if (eigrp_com_header->version != EIGRP_VERSION) {
240	printf("EIGRP version %u packet not supported",eigrp_com_header->version);
241	return;
242    }
243
244    /* in non-verbose mode just lets print the basic Message Type*/
245    if (vflag < 1) {
246        printf("EIGRP %s, length: %u",
247               tok2str(eigrp_opcode_values, "unknown (%u)",eigrp_com_header->opcode),
248               len);
249        return;
250    }
251
252    /* ok they seem to want to know everything - lets fully decode it */
253
254    tlen=len-sizeof(struct eigrp_common_header);
255
256    /* FIXME print other header info */
257    printf("\n\tEIGRP v%u, opcode: %s (%u), chksum: 0x%04x, Flags: [%s]\n\tseq: 0x%08x, ack: 0x%08x, AS: %u, length: %u",
258           eigrp_com_header->version,
259           tok2str(eigrp_opcode_values, "unknown, type: %u",eigrp_com_header->opcode),
260           eigrp_com_header->opcode,
261           EXTRACT_16BITS(&eigrp_com_header->checksum),
262           tok2str(eigrp_common_header_flag_values,
263                   "none",
264                   EXTRACT_32BITS(&eigrp_com_header->flags)),
265           EXTRACT_32BITS(&eigrp_com_header->seq),
266           EXTRACT_32BITS(&eigrp_com_header->ack),
267           EXTRACT_32BITS(&eigrp_com_header->asn),
268           tlen);
269
270    tptr+=sizeof(const struct eigrp_common_header);
271
272    while(tlen>0) {
273        /* did we capture enough for fully decoding the object header ? */
274        TCHECK2(*tptr, sizeof(struct eigrp_tlv_header));
275
276        eigrp_tlv_header = (const struct eigrp_tlv_header *)tptr;
277        eigrp_tlv_len=EXTRACT_16BITS(&eigrp_tlv_header->length);
278        eigrp_tlv_type=EXTRACT_16BITS(&eigrp_tlv_header->type);
279
280
281        if (eigrp_tlv_len < sizeof(struct eigrp_tlv_header) ||
282            eigrp_tlv_len > tlen) {
283            print_unknown_data(tptr+sizeof(struct eigrp_tlv_header),"\n\t    ",tlen);
284            return;
285        }
286
287        printf("\n\t  %s TLV (0x%04x), length: %u",
288               tok2str(eigrp_tlv_values,
289                       "Unknown",
290                       eigrp_tlv_type),
291               eigrp_tlv_type,
292               eigrp_tlv_len);
293
294        tlv_tptr=tptr+sizeof(struct eigrp_tlv_header);
295        tlv_tlen=eigrp_tlv_len-sizeof(struct eigrp_tlv_header);
296
297        /* did we capture enough for fully decoding the object ? */
298        TCHECK2(*tptr, eigrp_tlv_len);
299
300        switch(eigrp_tlv_type) {
301
302        case EIGRP_TLV_GENERAL_PARM:
303            tlv_ptr.eigrp_tlv_general_parm = (const struct eigrp_tlv_general_parm_t *)tlv_tptr;
304
305            printf("\n\t    holdtime: %us, k1 %u, k2 %u, k3 %u, k4 %u, k5 %u",
306                   EXTRACT_16BITS(tlv_ptr.eigrp_tlv_general_parm->holdtime),
307                   tlv_ptr.eigrp_tlv_general_parm->k1,
308                   tlv_ptr.eigrp_tlv_general_parm->k2,
309                   tlv_ptr.eigrp_tlv_general_parm->k3,
310                   tlv_ptr.eigrp_tlv_general_parm->k4,
311                   tlv_ptr.eigrp_tlv_general_parm->k5);
312            break;
313
314        case EIGRP_TLV_SW_VERSION:
315            tlv_ptr.eigrp_tlv_sw_version = (const struct eigrp_tlv_sw_version_t *)tlv_tptr;
316
317            printf("\n\t    IOS version: %u.%u, EIGRP version %u.%u",
318                   tlv_ptr.eigrp_tlv_sw_version->ios_major,
319                   tlv_ptr.eigrp_tlv_sw_version->ios_minor,
320                   tlv_ptr.eigrp_tlv_sw_version->eigrp_major,
321                   tlv_ptr.eigrp_tlv_sw_version->eigrp_minor);
322            break;
323
324        case EIGRP_TLV_IP_INT:
325            tlv_ptr.eigrp_tlv_ip_int = (const struct eigrp_tlv_ip_int_t *)tlv_tptr;
326
327            bit_length = tlv_ptr.eigrp_tlv_ip_int->plen;
328            if (bit_length > 32) {
329                printf("\n\t    illegal prefix length %u",bit_length);
330                break;
331            }
332            byte_length = (bit_length + 7) / 8; /* variable length encoding */
333            memset(prefix, 0, 4);
334            memcpy(prefix,&tlv_ptr.eigrp_tlv_ip_int->destination,byte_length);
335
336            printf("\n\t    IPv4 prefix: %15s/%u, nexthop: ",
337                   ipaddr_string(prefix),
338                   bit_length);
339            if (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_int->nexthop) == 0)
340                printf("self");
341            else
342                printf("%s",ipaddr_string(&tlv_ptr.eigrp_tlv_ip_int->nexthop));
343
344            printf("\n\t      delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u",
345                   (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_int->delay)/100),
346                   EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_int->bandwidth),
347                   EXTRACT_24BITS(&tlv_ptr.eigrp_tlv_ip_int->mtu),
348                   tlv_ptr.eigrp_tlv_ip_int->hopcount,
349                   tlv_ptr.eigrp_tlv_ip_int->reliability,
350                   tlv_ptr.eigrp_tlv_ip_int->load);
351            break;
352
353        case EIGRP_TLV_IP_EXT:
354            tlv_ptr.eigrp_tlv_ip_ext = (const struct eigrp_tlv_ip_ext_t *)tlv_tptr;
355
356            bit_length = tlv_ptr.eigrp_tlv_ip_ext->plen;
357            if (bit_length > 32) {
358                printf("\n\t    illegal prefix length %u",bit_length);
359                break;
360            }
361            byte_length = (bit_length + 7) / 8; /* variable length encoding */
362            memset(prefix, 0, 4);
363            memcpy(prefix,&tlv_ptr.eigrp_tlv_ip_ext->destination,byte_length);
364
365            printf("\n\t    IPv4 prefix: %15s/%u, nexthop: ",
366                   ipaddr_string(prefix),
367                   bit_length);
368            if (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_ext->nexthop) == 0)
369                printf("self");
370            else
371                printf("%s",ipaddr_string(&tlv_ptr.eigrp_tlv_ip_ext->nexthop));
372
373            printf("\n\t      origin-router %s, origin-as %u, origin-proto %s, flags [0x%02x], tag 0x%08x, metric %u",
374                   ipaddr_string(tlv_ptr.eigrp_tlv_ip_ext->origin_router),
375                   EXTRACT_32BITS(tlv_ptr.eigrp_tlv_ip_ext->origin_as),
376                   tok2str(eigrp_ext_proto_id_values,"unknown",tlv_ptr.eigrp_tlv_ip_ext->proto_id),
377                   tlv_ptr.eigrp_tlv_ip_ext->flags,
378                   EXTRACT_32BITS(tlv_ptr.eigrp_tlv_ip_ext->tag),
379                   EXTRACT_32BITS(tlv_ptr.eigrp_tlv_ip_ext->metric));
380
381            printf("\n\t      delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u",
382                   (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_ext->delay)/100),
383                   EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_ext->bandwidth),
384                   EXTRACT_24BITS(&tlv_ptr.eigrp_tlv_ip_ext->mtu),
385                   tlv_ptr.eigrp_tlv_ip_ext->hopcount,
386                   tlv_ptr.eigrp_tlv_ip_ext->reliability,
387                   tlv_ptr.eigrp_tlv_ip_ext->load);
388            break;
389
390        case EIGRP_TLV_AT_CABLE_SETUP:
391            tlv_ptr.eigrp_tlv_at_cable_setup = (const struct eigrp_tlv_at_cable_setup_t *)tlv_tptr;
392
393            printf("\n\t    Cable-range: %u-%u, Router-ID %u",
394                   EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_cable_setup->cable_start),
395                   EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_cable_setup->cable_end),
396                   EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_cable_setup->router_id));
397            break;
398
399        case EIGRP_TLV_AT_INT:
400            tlv_ptr.eigrp_tlv_at_int = (const struct eigrp_tlv_at_int_t *)tlv_tptr;
401
402            printf("\n\t     Cable-Range: %u-%u, nexthop: ",
403                   EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_int->cable_start),
404                   EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_int->cable_end));
405
406            if (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_int->nexthop) == 0)
407                printf("self");
408            else
409                printf("%u.%u",
410                       EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_int->nexthop),
411                       EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_int->nexthop[2]));
412
413            printf("\n\t      delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u",
414                   (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_int->delay)/100),
415                   EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_int->bandwidth),
416                   EXTRACT_24BITS(&tlv_ptr.eigrp_tlv_at_int->mtu),
417                   tlv_ptr.eigrp_tlv_at_int->hopcount,
418                   tlv_ptr.eigrp_tlv_at_int->reliability,
419                   tlv_ptr.eigrp_tlv_at_int->load);
420            break;
421
422        case EIGRP_TLV_AT_EXT:
423            tlv_ptr.eigrp_tlv_at_ext = (const struct eigrp_tlv_at_ext_t *)tlv_tptr;
424
425            printf("\n\t     Cable-Range: %u-%u, nexthop: ",
426                   EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_ext->cable_start),
427                   EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_ext->cable_end));
428
429            if (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_ext->nexthop) == 0)
430                printf("self");
431            else
432                printf("%u.%u",
433                       EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_ext->nexthop),
434                       EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_ext->nexthop[2]));
435
436            printf("\n\t      origin-router %u, origin-as %u, origin-proto %s, flags [0x%02x], tag 0x%08x, metric %u",
437                   EXTRACT_32BITS(tlv_ptr.eigrp_tlv_at_ext->origin_router),
438                   EXTRACT_32BITS(tlv_ptr.eigrp_tlv_at_ext->origin_as),
439                   tok2str(eigrp_ext_proto_id_values,"unknown",tlv_ptr.eigrp_tlv_at_ext->proto_id),
440                   tlv_ptr.eigrp_tlv_at_ext->flags,
441                   EXTRACT_32BITS(tlv_ptr.eigrp_tlv_at_ext->tag),
442                   EXTRACT_16BITS(tlv_ptr.eigrp_tlv_at_ext->metric));
443
444            printf("\n\t      delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u",
445                   (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_ext->delay)/100),
446                   EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_ext->bandwidth),
447                   EXTRACT_24BITS(&tlv_ptr.eigrp_tlv_at_ext->mtu),
448                   tlv_ptr.eigrp_tlv_at_ext->hopcount,
449                   tlv_ptr.eigrp_tlv_at_ext->reliability,
450                   tlv_ptr.eigrp_tlv_at_ext->load);
451            break;
452
453            /*
454             * FIXME those are the defined TLVs that lack a decoder
455             * you are welcome to contribute code ;-)
456             */
457
458        case EIGRP_TLV_AUTH:
459        case EIGRP_TLV_SEQ:
460        case EIGRP_TLV_MCAST_SEQ:
461        case EIGRP_TLV_IPX_INT:
462        case EIGRP_TLV_IPX_EXT:
463
464        default:
465            if (vflag <= 1)
466                print_unknown_data(tlv_tptr,"\n\t    ",tlv_tlen);
467            break;
468        }
469        /* do we want to see an additionally hexdump ? */
470        if (vflag > 1)
471            print_unknown_data(tptr+sizeof(struct eigrp_tlv_header),"\n\t    ",
472                               eigrp_tlv_len-sizeof(struct eigrp_tlv_header));
473
474        tptr+=eigrp_tlv_len;
475        tlen-=eigrp_tlv_len;
476    }
477    return;
478trunc:
479    printf("\n\t\t packet exceeded snapshot");
480}
481