diff options
Diffstat (limited to 'print-rip.c')
-rw-r--r-- | print-rip.c | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/print-rip.c b/print-rip.c new file mode 100644 index 0000000..fca534f --- /dev/null +++ b/print-rip.c @@ -0,0 +1,422 @@ +/* + * Copyright (c) 1989, 1990, 1991, 1993, 1994, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* \summary: Routing Information Protocol (RIP) printer */ + +/* specification: RFC 1058, RFC 2453, RFC 4822 */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "netdissect-stdinc.h" + +#include "netdissect.h" +#include "addrtoname.h" +#include "extract.h" + +#include "af.h" + + +/* + * RFC 1058 and RFC 2453 header of packet. + * + * 0 1 2 3 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Command (1) | Version (1) | unused | + * +---------------+---------------+-------------------------------+ + */ +struct rip { + nd_uint8_t rip_cmd; /* request/response */ + nd_uint8_t rip_vers; /* protocol version # */ + nd_byte unused[2]; /* unused */ +}; + +#define RIPCMD_REQUEST 1 /* want info */ +#define RIPCMD_RESPONSE 2 /* responding to request */ +#define RIPCMD_TRACEON 3 /* turn tracing on */ +#define RIPCMD_TRACEOFF 4 /* turn it off */ +#define RIPCMD_POLL 5 /* want info from everybody */ +#define RIPCMD_POLLENTRY 6 /* poll for entry */ + +static const struct tok rip_cmd_values[] = { + { RIPCMD_REQUEST, "Request" }, + { RIPCMD_RESPONSE, "Response" }, + { RIPCMD_TRACEON, "Trace on" }, + { RIPCMD_TRACEOFF, "Trace off" }, + { RIPCMD_POLL, "Poll" }, + { RIPCMD_POLLENTRY, "Poll Entry" }, + { 0, NULL} +}; + +#define RIP_AUTHLEN 16 +#define RIP_ROUTELEN 20 + +/* + * First 4 bytes of all RIPv1/RIPv2 entries. + */ +struct rip_entry_header { + nd_uint16_t rip_family; + nd_uint16_t rip_tag; +}; + +/* + * RFC 1058 entry. + * + * 0 1 2 3 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Address Family Identifier (2) | must be zero (2) | + * +-------------------------------+-------------------------------+ + * | IP Address (4) | + * +---------------------------------------------------------------+ + * | must be zero (4) | + * +---------------------------------------------------------------+ + * | must be zero (4) | + * +---------------------------------------------------------------+ + * | Metric (4) | + * +---------------------------------------------------------------+ + */ +struct rip_netinfo_v1 { + nd_uint16_t rip_family; + nd_byte rip_mbz1[2]; + nd_ipv4 rip_dest; + nd_byte rip_mbz2[4]; + nd_byte rip_mbz3[4]; + nd_uint32_t rip_metric; /* cost of route */ +}; + + +/* + * RFC 2453 route entry + * + * 0 1 2 3 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Address Family Identifier (2) | Route Tag (2) | + * +-------------------------------+-------------------------------+ + * | IP Address (4) | + * +---------------------------------------------------------------+ + * | Subnet Mask (4) | + * +---------------------------------------------------------------+ + * | Next Hop (4) | + * +---------------------------------------------------------------+ + * | Metric (4) | + * +---------------------------------------------------------------+ + * + */ + +struct rip_netinfo_v2 { + nd_uint16_t rip_family; + nd_uint16_t rip_tag; + nd_ipv4 rip_dest; + nd_uint32_t rip_dest_mask; + nd_ipv4 rip_router; + nd_uint32_t rip_metric; /* cost of route */ +}; + +/* + * RFC 2453 authentication entry + * + * 0 1 2 3 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | 0xFFFF | Authentication Type (2) | + * +-------------------------------+-------------------------------+ + * - Authentication (16) - + * +---------------------------------------------------------------+ + */ + +struct rip_auth_v2 { + nd_uint16_t rip_family; + nd_uint16_t rip_tag; + nd_byte rip_auth[16]; +}; + +/* + * RFC 4822 Cryptographic Authentication entry. + * + * 0 1 2 3 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | RIPv2 Packet Length | Key ID | Auth Data Len | + * +---------------+---------------+---------------+---------------+ + * | Sequence Number (non-decreasing) | + * +---------------+---------------+---------------+---------------+ + * | reserved must be zero | + * +---------------+---------------+---------------+---------------+ + * | reserved must be zero | + * +---------------+---------------+---------------+---------------+ + */ +struct rip_auth_crypto_v2 { + nd_uint16_t rip_packet_len; + nd_uint8_t rip_key_id; + nd_uint8_t rip_auth_data_len; + nd_uint32_t rip_seq_num; + nd_byte rip_mbz1[4]; + nd_byte rip_mbz2[4]; +}; + +static unsigned +rip_entry_print_v1(netdissect_options *ndo, const u_char *p, + unsigned remaining) +{ + const struct rip_entry_header *eh = (const struct rip_entry_header *)p; + u_short family; + const struct rip_netinfo_v1 *ni = (const struct rip_netinfo_v1 *)p; + + /* RFC 1058 */ + if (remaining < RIP_ROUTELEN) + return (0); + ND_TCHECK_SIZE(ni); + family = GET_BE_U_2(ni->rip_family); + if (family != BSD_AFNUM_INET && family != 0) { + ND_PRINT("\n\t AFI %s, ", tok2str(bsd_af_values, "Unknown (%u)", family)); + print_unknown_data(ndo, p + sizeof(*eh), "\n\t ", RIP_ROUTELEN - sizeof(*eh)); + return (RIP_ROUTELEN); + } + if (GET_BE_U_2(ni->rip_mbz1) || + GET_BE_U_4(ni->rip_mbz2) || + GET_BE_U_4(ni->rip_mbz3)) { + /* MBZ fields not zero */ + print_unknown_data(ndo, p, "\n\t ", RIP_ROUTELEN); + return (RIP_ROUTELEN); + } + if (family == 0) { + ND_PRINT("\n\t AFI 0, %s, metric: %u", + GET_IPADDR_STRING(ni->rip_dest), + GET_BE_U_4(ni->rip_metric)); + return (RIP_ROUTELEN); + } /* BSD_AFNUM_INET */ + ND_PRINT("\n\t %s, metric: %u", + GET_IPADDR_STRING(ni->rip_dest), + GET_BE_U_4(ni->rip_metric)); + return (RIP_ROUTELEN); +trunc: + return 0; +} + +static unsigned +rip_entry_print_v2(netdissect_options *ndo, const u_char *p, + unsigned remaining) +{ + const struct rip_entry_header *eh = (const struct rip_entry_header *)p; + u_short family; + const struct rip_netinfo_v2 *ni; + + if (remaining < sizeof(*eh)) + return (0); + ND_TCHECK_SIZE(eh); + family = GET_BE_U_2(eh->rip_family); + if (family == 0xFFFF) { /* variable-sized authentication structures */ + uint16_t auth_type = GET_BE_U_2(eh->rip_tag); + + p += sizeof(*eh); + remaining -= sizeof(*eh); + if (auth_type == 2) { + ND_PRINT("\n\t Simple Text Authentication data: "); + nd_printjnp(ndo, p, RIP_AUTHLEN); + } else if (auth_type == 3) { + const struct rip_auth_crypto_v2 *ch; + + ch = (const struct rip_auth_crypto_v2 *)p; + ND_TCHECK_SIZE(ch); + if (remaining < sizeof(*ch)) + return (0); + ND_PRINT("\n\t Auth header:"); + ND_PRINT(" Packet Len %u,", + GET_BE_U_2(ch->rip_packet_len)); + ND_PRINT(" Key-ID %u,", GET_U_1(ch->rip_key_id)); + ND_PRINT(" Auth Data Len %u,", + GET_U_1(ch->rip_auth_data_len)); + ND_PRINT(" SeqNo %u,", GET_BE_U_4(ch->rip_seq_num)); + ND_PRINT(" MBZ %u,", GET_BE_U_4(ch->rip_mbz1)); + ND_PRINT(" MBZ %u", GET_BE_U_4(ch->rip_mbz2)); + } else if (auth_type == 1) { + ND_PRINT("\n\t Auth trailer:"); + print_unknown_data(ndo, p, "\n\t ", remaining); + return (sizeof(*eh) + remaining); /* AT spans till the packet end */ + } else { + ND_PRINT("\n\t Unknown (%u) Authentication data:", + auth_type); + print_unknown_data(ndo, p, "\n\t ", remaining); + return (sizeof(*eh) + remaining); /* we don't know how long this is, so we go to the packet end */ + } + } else if (family != BSD_AFNUM_INET && family != 0) { + ND_PRINT("\n\t AFI %s", tok2str(bsd_af_values, "Unknown (%u)", family)); + print_unknown_data(ndo, p + sizeof(*eh), "\n\t ", RIP_ROUTELEN - sizeof(*eh)); + } else { /* BSD_AFNUM_INET or AFI 0 */ + ni = (const struct rip_netinfo_v2 *)p; + ND_TCHECK_SIZE(ni); + if (remaining < sizeof(*ni)) + return (0); + ND_PRINT("\n\t AFI %s, %15s/%-2d, tag 0x%04x, metric: %u, next-hop: ", + tok2str(bsd_af_values, "%u", family), + GET_IPADDR_STRING(ni->rip_dest), + mask2plen(GET_BE_U_4(ni->rip_dest_mask)), + GET_BE_U_2(ni->rip_tag), + GET_BE_U_4(ni->rip_metric)); + if (GET_BE_U_4(ni->rip_router)) + ND_PRINT("%s", GET_IPADDR_STRING(ni->rip_router)); + else + ND_PRINT("self"); + } + return (RIP_ROUTELEN); +trunc: + return 0; +} + +void +rip_print(netdissect_options *ndo, + const u_char *dat, u_int length) +{ + const struct rip *rp; + uint8_t vers, cmd; + const u_char *p; + u_int len, routecount; + unsigned entry_size; + + ndo->ndo_protocol = "rip"; + if (ndo->ndo_snapend < dat) { + nd_print_trunc(ndo); + return; + } + len = ND_BYTES_AVAILABLE_AFTER(dat); + if (len > length) + len = length; + if (len < sizeof(*rp)) { + nd_print_trunc(ndo); + return; + } + len -= sizeof(*rp); + + rp = (const struct rip *)dat; + + ND_TCHECK_SIZE(rp); + vers = GET_U_1(rp->rip_vers); + ND_PRINT("%sRIPv%u", + (ndo->ndo_vflag >= 1) ? "\n\t" : "", + vers); + + if (vers == 0) { + /* + * RFC 1058. + * + * XXX - RFC 1058 says + * + * 0 Datagrams whose version number is zero are to be ignored. + * These are from a previous version of the protocol, whose + * packet format was machine-specific. + * + * so perhaps we should just dump the packet, in hex. + */ + print_unknown_data(ndo, (const uint8_t *)&rp->rip_cmd, "\n\t", length); + return; + } + + /* dump version and lets see if we know the commands name*/ + cmd = GET_U_1(rp->rip_cmd); + ND_PRINT(", %s, length: %u", + tok2str(rip_cmd_values, "unknown command (%u)", cmd), + length); + + if (ndo->ndo_vflag < 1) + return; + + switch (cmd) { + + case RIPCMD_REQUEST: + case RIPCMD_RESPONSE: + switch (vers) { + + case 1: + routecount = length / RIP_ROUTELEN; + ND_PRINT(", routes: %u", routecount); + p = (const u_char *)(rp + 1); + while (len != 0) { + entry_size = rip_entry_print_v1(ndo, p, len); + if (entry_size == 0) { + /* Error */ + nd_print_trunc(ndo); + break; + } + if (len < entry_size) { + ND_PRINT(" [remaining entries length %u < %u]", + len, entry_size); + nd_print_invalid(ndo); + break; + } + p += entry_size; + len -= entry_size; + } + break; + + case 2: + routecount = length / RIP_ROUTELEN; + ND_PRINT(", routes: %u or less", routecount); + p = (const u_char *)(rp + 1); + while (len != 0) { + entry_size = rip_entry_print_v2(ndo, p, len); + if (entry_size == 0) { + /* Error */ + nd_print_trunc(ndo); + break; + } + if (len < entry_size) { + ND_PRINT(" [remaining entries length %u < %u]", + len, entry_size); + nd_print_invalid(ndo); + break; + } + p += entry_size; + len -= entry_size; + } + break; + + default: + ND_PRINT(", unknown version"); + break; + } + break; + + case RIPCMD_TRACEOFF: + case RIPCMD_POLL: + case RIPCMD_POLLENTRY: + break; + + case RIPCMD_TRACEON: + /* fall through */ + default: + if (ndo->ndo_vflag <= 1) { + if (!print_unknown_data(ndo, (const uint8_t *)rp, "\n\t", length)) + return; + } + break; + } + /* do we want to see an additionally hexdump ? */ + if (ndo->ndo_vflag> 1) { + if (!print_unknown_data(ndo, (const uint8_t *)rp, "\n\t", length)) + return; + } +trunc: + return; +} |