117680Spst/*
217680Spst * Copyright (c) 1989, 1990, 1991, 1993, 1994, 1996
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2017680Spst */
2117680Spst
22313537Sglebius/* \summary: Routing Information Protocol (RIP) printer */
23313537Sglebius
2456893Sfenner#ifdef HAVE_CONFIG_H
2556893Sfenner#include "config.h"
2656893Sfenner#endif
2756893Sfenner
28313537Sglebius#include <netdissect-stdinc.h>
2917680Spst
3017680Spst#include <stdio.h>
3117680Spst
32313537Sglebius#include "netdissect.h"
3317680Spst#include "addrtoname.h"
34313537Sglebius#include "extract.h"
3517680Spst
36190207Srpaulo#include "af.h"
37190207Srpaulo
38276788Sdelphijstatic const char tstr[] = "[|rip]";
39276788Sdelphij
4017680Spststruct rip {
41276788Sdelphij	uint8_t rip_cmd;		/* request/response */
42276788Sdelphij	uint8_t rip_vers;		/* protocol version # */
43276788Sdelphij	uint8_t unused[2];		/* unused */
4417680Spst};
45127668Sbms
4617680Spst#define	RIPCMD_REQUEST		1	/* want info */
4717680Spst#define	RIPCMD_RESPONSE		2	/* responding to request */
4817680Spst#define	RIPCMD_TRACEON		3	/* turn tracing on */
4917680Spst#define	RIPCMD_TRACEOFF		4	/* turn it off */
5017680Spst#define	RIPCMD_POLL		5	/* want info from everybody */
5117680Spst#define	RIPCMD_POLLENTRY	6	/* poll for entry */
5217680Spst
53127668Sbmsstatic const struct tok rip_cmd_values[] = {
54127668Sbms    { RIPCMD_REQUEST,	        "Request" },
55127668Sbms    { RIPCMD_RESPONSE,	        "Response" },
56127668Sbms    { RIPCMD_TRACEON,	        "Trace on" },
57127668Sbms    { RIPCMD_TRACEOFF,	        "Trace off" },
58127668Sbms    { RIPCMD_POLL,	        "Poll" },
59127668Sbms    { RIPCMD_POLLENTRY,	        "Poll Entry" },
60127668Sbms    { 0, NULL}
61127668Sbms};
6275115Sfenner
63127668Sbms#define RIP_AUTHLEN  16
64127668Sbms#define RIP_ROUTELEN 20
65127668Sbms
66127668Sbms/*
67127668Sbms * rfc 1723
68276788Sdelphij *
69127668Sbms *  0                   1                   2                   3 3
70127668Sbms *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
71127668Sbms * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
72127668Sbms * | Command (1)   | Version (1)   |           unused              |
73127668Sbms * +---------------+---------------+-------------------------------+
74127668Sbms * | Address Family Identifier (2) |        Route Tag (2)          |
75127668Sbms * +-------------------------------+-------------------------------+
76127668Sbms * |                         IP Address (4)                        |
77127668Sbms * +---------------------------------------------------------------+
78127668Sbms * |                         Subnet Mask (4)                       |
79127668Sbms * +---------------------------------------------------------------+
80127668Sbms * |                         Next Hop (4)                          |
81127668Sbms * +---------------------------------------------------------------+
82127668Sbms * |                         Metric (4)                            |
83127668Sbms * +---------------------------------------------------------------+
84127668Sbms *
85127668Sbms */
86127668Sbms
8717680Spststruct rip_netinfo {
88276788Sdelphij	uint16_t rip_family;
89276788Sdelphij	uint16_t rip_tag;
90276788Sdelphij	uint32_t rip_dest;
91276788Sdelphij	uint32_t rip_dest_mask;
92276788Sdelphij	uint32_t rip_router;
93276788Sdelphij	uint32_t rip_metric;		/* cost of route */
9417680Spst};
9517680Spst
9617680Spststatic void
97276788Sdelphijrip_entry_print_v1(netdissect_options *ndo,
98276788Sdelphij                   register const struct rip_netinfo *ni)
9917680Spst{
10075115Sfenner	register u_short family;
10117680Spst
10275115Sfenner	/* RFC 1058 */
10375115Sfenner	family = EXTRACT_16BITS(&ni->rip_family);
104251158Sdelphij	if (family != BSD_AFNUM_INET && family != 0) {
105276788Sdelphij		ND_PRINT((ndo, "\n\t AFI %s, ", tok2str(bsd_af_values, "Unknown (%u)", family)));
106313537Sglebius		print_unknown_data(ndo, (const uint8_t *)&ni->rip_family, "\n\t  ", RIP_ROUTELEN);
10775115Sfenner		return;
10875115Sfenner	}
109127668Sbms	if (EXTRACT_16BITS(&ni->rip_tag) ||
110127668Sbms	    EXTRACT_32BITS(&ni->rip_dest_mask) ||
111127668Sbms	    EXTRACT_32BITS(&ni->rip_router)) {
11275115Sfenner		/* MBZ fields not zero */
113313537Sglebius                print_unknown_data(ndo, (const uint8_t *)&ni->rip_family, "\n\t  ", RIP_ROUTELEN);
11475115Sfenner		return;
115251158Sdelphij	}
116251158Sdelphij	if (family == 0) {
117276788Sdelphij		ND_PRINT((ndo, "\n\t  AFI 0, %s, metric: %u",
118276788Sdelphij			ipaddr_string(ndo, &ni->rip_dest),
119276788Sdelphij			EXTRACT_32BITS(&ni->rip_metric)));
120251158Sdelphij		return;
121190207Srpaulo	} /* BSD_AFNUM_INET */
122276788Sdelphij	ND_PRINT((ndo, "\n\t  %s, metric: %u",
123276788Sdelphij               ipaddr_string(ndo, &ni->rip_dest),
124276788Sdelphij	       EXTRACT_32BITS(&ni->rip_metric)));
12575115Sfenner}
12675115Sfenner
127251158Sdelphijstatic unsigned
128276788Sdelphijrip_entry_print_v2(netdissect_options *ndo,
129276788Sdelphij                   register const struct rip_netinfo *ni, const unsigned remaining)
13075115Sfenner{
13175115Sfenner	register u_short family;
13275115Sfenner
13375115Sfenner	family = EXTRACT_16BITS(&ni->rip_family);
134251158Sdelphij	if (family == 0xFFFF) { /* variable-sized authentication structures */
135276788Sdelphij		uint16_t auth_type = EXTRACT_16BITS(&ni->rip_tag);
136251158Sdelphij		if (auth_type == 2) {
137313537Sglebius			register const u_char *p = (const u_char *)&ni->rip_dest;
138251158Sdelphij			u_int i = 0;
139276788Sdelphij			ND_PRINT((ndo, "\n\t  Simple Text Authentication data: "));
140251158Sdelphij			for (; i < RIP_AUTHLEN; p++, i++)
141276788Sdelphij				ND_PRINT((ndo, "%c", ND_ISPRINT(*p) ? *p : '.'));
142251158Sdelphij		} else if (auth_type == 3) {
143276788Sdelphij			ND_PRINT((ndo, "\n\t  Auth header:"));
144313537Sglebius			ND_PRINT((ndo, " Packet Len %u,", EXTRACT_16BITS((const uint8_t *)ni + 4)));
145313537Sglebius			ND_PRINT((ndo, " Key-ID %u,", *((const uint8_t *)ni + 6)));
146313537Sglebius			ND_PRINT((ndo, " Auth Data Len %u,", *((const uint8_t *)ni + 7)));
147276788Sdelphij			ND_PRINT((ndo, " SeqNo %u,", EXTRACT_32BITS(&ni->rip_dest_mask)));
148276788Sdelphij			ND_PRINT((ndo, " MBZ %u,", EXTRACT_32BITS(&ni->rip_router)));
149276788Sdelphij			ND_PRINT((ndo, " MBZ %u", EXTRACT_32BITS(&ni->rip_metric)));
150251158Sdelphij		} else if (auth_type == 1) {
151276788Sdelphij			ND_PRINT((ndo, "\n\t  Auth trailer:"));
152313537Sglebius			print_unknown_data(ndo, (const uint8_t *)&ni->rip_dest, "\n\t  ", remaining);
153251158Sdelphij			return remaining; /* AT spans till the packet end */
154276788Sdelphij		} else {
155276788Sdelphij			ND_PRINT((ndo, "\n\t  Unknown (%u) Authentication data:",
156276788Sdelphij			       EXTRACT_16BITS(&ni->rip_tag)));
157313537Sglebius			print_unknown_data(ndo, (const uint8_t *)&ni->rip_dest, "\n\t  ", remaining);
15875115Sfenner		}
159251158Sdelphij	} else if (family != BSD_AFNUM_INET && family != 0) {
160276788Sdelphij		ND_PRINT((ndo, "\n\t  AFI %s", tok2str(bsd_af_values, "Unknown (%u)", family)));
161313537Sglebius                print_unknown_data(ndo, (const uint8_t *)&ni->rip_tag, "\n\t  ", RIP_ROUTELEN-2);
162251158Sdelphij	} else { /* BSD_AFNUM_INET or AFI 0 */
163276788Sdelphij		ND_PRINT((ndo, "\n\t  AFI %s, %15s/%-2d, tag 0x%04x, metric: %u, next-hop: ",
164251158Sdelphij                       tok2str(bsd_af_values, "%u", family),
165276788Sdelphij                       ipaddr_string(ndo, &ni->rip_dest),
166127668Sbms		       mask2plen(EXTRACT_32BITS(&ni->rip_dest_mask)),
167127668Sbms                       EXTRACT_16BITS(&ni->rip_tag),
168276788Sdelphij                       EXTRACT_32BITS(&ni->rip_metric)));
169127668Sbms		if (EXTRACT_32BITS(&ni->rip_router))
170276788Sdelphij			ND_PRINT((ndo, "%s", ipaddr_string(ndo, &ni->rip_router)));
171276788Sdelphij		else
172276788Sdelphij			ND_PRINT((ndo, "self"));
17317680Spst	}
174251158Sdelphij	return sizeof (*ni);
17517680Spst}
17617680Spst
17717680Spstvoid
178276788Sdelphijrip_print(netdissect_options *ndo,
179276788Sdelphij          const u_char *dat, u_int length)
18017680Spst{
18117680Spst	register const struct rip *rp;
18217680Spst	register const struct rip_netinfo *ni;
183127668Sbms	register u_int i, j;
18417680Spst
185276788Sdelphij	if (ndo->ndo_snapend < dat) {
186276788Sdelphij		ND_PRINT((ndo, " %s", tstr));
18717680Spst		return;
18856893Sfenner	}
189276788Sdelphij	i = ndo->ndo_snapend - dat;
190127668Sbms	if (i > length)
191127668Sbms		i = length;
192127668Sbms	if (i < sizeof(*rp)) {
193276788Sdelphij		ND_PRINT((ndo, " %s", tstr));
194127668Sbms		return;
195127668Sbms	}
196127668Sbms	i -= sizeof(*rp);
19717680Spst
198313537Sglebius	rp = (const struct rip *)dat;
199127668Sbms
200276788Sdelphij	ND_PRINT((ndo, "%sRIPv%u",
201276788Sdelphij               (ndo->ndo_vflag >= 1) ? "\n\t" : "",
202276788Sdelphij               rp->rip_vers));
203127668Sbms
20475115Sfenner	switch (rp->rip_vers) {
20575115Sfenner	case 0:
20675115Sfenner		/*
20775115Sfenner		 * RFC 1058.
20875115Sfenner		 *
20975115Sfenner		 * XXX - RFC 1058 says
21075115Sfenner		 *
21175115Sfenner		 * 0  Datagrams whose version number is zero are to be ignored.
21275115Sfenner		 *    These are from a previous version of the protocol, whose
21375115Sfenner		 *    packet format was machine-specific.
21475115Sfenner		 *
215127668Sbms		 * so perhaps we should just dump the packet, in hex.
21698524Sfenner		 */
217313537Sglebius                print_unknown_data(ndo, (const uint8_t *)&rp->rip_cmd, "\n\t", length);
21817680Spst		break;
21917680Spst	default:
220127668Sbms                /* dump version and lets see if we know the commands name*/
221276788Sdelphij                ND_PRINT((ndo, ", %s, length: %u",
222127668Sbms                       tok2str(rip_cmd_values,
223127668Sbms                               "unknown command (%u)",
224127668Sbms                               rp->rip_cmd),
225276788Sdelphij                       length));
226127668Sbms
227276788Sdelphij                if (ndo->ndo_vflag < 1)
228127668Sbms                    return;
229127668Sbms
23075115Sfenner		switch (rp->rip_cmd) {
231251158Sdelphij		case RIPCMD_REQUEST:
23275115Sfenner		case RIPCMD_RESPONSE:
23375115Sfenner			j = length / sizeof(*ni);
234276788Sdelphij			ND_PRINT((ndo, ", routes: %u%s", j, rp->rip_vers == 2 ? " or less" : ""));
235313537Sglebius			ni = (const struct rip_netinfo *)(rp + 1);
236127668Sbms			for (; i >= sizeof(*ni); ++ni) {
23775115Sfenner				if (rp->rip_vers == 1)
238251158Sdelphij				{
239276788Sdelphij					rip_entry_print_v1(ndo, ni);
240251158Sdelphij					i -= sizeof(*ni);
241251158Sdelphij				}
242127668Sbms				else if (rp->rip_vers == 2)
243276788Sdelphij					i -= rip_entry_print_v2(ndo, ni, i);
244127668Sbms                                else
245127668Sbms                                    break;
24675115Sfenner			}
247251158Sdelphij			if (i)
248276788Sdelphij				ND_PRINT((ndo, "%s", tstr));
24975115Sfenner			break;
250127668Sbms
25175115Sfenner		case RIPCMD_TRACEOFF:
25275115Sfenner		case RIPCMD_POLL:
25375115Sfenner		case RIPCMD_POLLENTRY:
25475115Sfenner			break;
255127668Sbms
256127668Sbms		case RIPCMD_TRACEON:
257127668Sbms                    /* fall through */
258127668Sbms	        default:
259276788Sdelphij                    if (ndo->ndo_vflag <= 1) {
260313537Sglebius                        if(!print_unknown_data(ndo, (const uint8_t *)rp, "\n\t", length))
261127668Sbms                            return;
262127668Sbms                    }
263127668Sbms                    break;
264127668Sbms                }
265127668Sbms                /* do we want to see an additionally hexdump ? */
266276788Sdelphij                if (ndo->ndo_vflag> 1) {
267313537Sglebius                    if(!print_unknown_data(ndo, (const uint8_t *)rp, "\n\t", length))
268127668Sbms                        return;
269127668Sbms                }
270127668Sbms        }
27117680Spst}
272127668Sbms
273127668Sbms
274