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