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