X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/3cd171317f54bc968808d49e3ca87b6c49ccdcdd..refs/heads/master:/print-rip.c diff --git a/print-rip.c b/print-rip.c index 9f409eeb..a399c610 100644 --- a/print-rip.c +++ b/print-rip.c @@ -19,209 +19,376 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#ifndef lint -static const char rcsid[] = - "@(#) $Header: /tcpdump/master/tcpdump/print-rip.c,v 1.42 2000-07-01 03:39:09 assar Exp $ (LBL)"; -#endif - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "interface.h" +/* \summary: Routing Information Protocol (RIP) printer */ + +/* specification: RFC 1058, RFC 2453, RFC 4822 */ + +#include + +#include "netdissect-stdinc.h" + +#define ND_LONGJMP_FROM_TCHECK +#include "netdissect.h" #include "addrtoname.h" -#include "extract.h" /* must come after interface.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 { - u_char rip_cmd; /* request/response */ - u_char rip_vers; /* protocol version # */ - u_short rip_zero2; /* unused */ + 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 */ - -#define RIP_AUTHLEN 16 - -struct rip_netinfo { - u_short rip_family; - u_short rip_tag; - u_int32_t rip_dest; - u_int32_t rip_dest_mask; - u_int32_t rip_router; - u_int32_t rip_metric; /* cost of route */ +/* 5 is reserved */ +#define RIPCMD_TRIGREQ 6 +#define RIPCMD_TRIGRESP 7 +#define RIPCMD_TRIGACK 8 +#define RIPCMD_UPDREQ 9 +#define RIPCMD_UPDRESP 10 +#define RIPCMD_UPDACK 11 + +static const struct tok rip_cmd_values[] = { + { RIPCMD_REQUEST, "Request" }, + { RIPCMD_RESPONSE, "Response" }, + { RIPCMD_TRACEON, "Trace on" }, + { RIPCMD_TRACEOFF, "Trace off" }, + { RIPCMD_TRIGREQ, "Triggered Request" }, + { RIPCMD_TRIGRESP, "Triggered Response" }, + { RIPCMD_TRIGACK, "Triggered Acknowledgement" }, + { RIPCMD_UPDREQ, "Update Request" }, + { RIPCMD_UPDRESP, "Update Response" }, + { RIPCMD_UPDACK, "Update Acknowledge" }, + { 0, NULL} }; -static void -rip_printblk(const u_char *cp, const u_char *ep) -{ - for (; cp < ep; cp += 2) - printf(" %04x", EXTRACT_16BITS(cp)); - return; -} +#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; +}; -static void -rip_entry_print_v1(register int vers, register const struct rip_netinfo *ni) +/* + * 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) { - register u_short family; + 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 */ - family = EXTRACT_16BITS(&ni->rip_family); - if (family != AF_INET) { - printf(" [family %d:", family); - rip_printblk((u_char *)&ni->rip_tag, - (u_char *)&ni->rip_metric + - sizeof(ni->rip_metric)); - printf("]"); - return; + ND_ICHECKMSG_U("remaining data length", remaining, <, RIP_ROUTELEN); + ND_TCHECK_SIZE(ni); + family = GET_BE_U_2(ni->rip_family); + if (family != BSD_AF_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 (ni->rip_tag || ni->rip_dest_mask || ni->rip_router) { + 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 */ - printf(" ["); - rip_printblk((u_char *)&ni->rip_family, - (u_char *)&ni->rip_metric + - sizeof(ni->rip_metric)); - printf("]"); - return; + print_unknown_data(ndo, p, "\n\t ", RIP_ROUTELEN); + return (RIP_ROUTELEN); } - printf(" {%s}(%d)", ipaddr_string(&ni->rip_dest), - EXTRACT_32BITS(&ni->rip_metric)); + 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_AF_INET */ + ND_PRINT("\n\t %s, metric: %u", + GET_IPADDR_STRING(ni->rip_dest), + GET_BE_U_4(ni->rip_metric)); + return (RIP_ROUTELEN); +invalid: + return 0; } -static void -rip_entry_print_v2(register int vers, register const struct rip_netinfo *ni) +static unsigned +rip_entry_print_v2(netdissect_options *ndo, const u_char *p, + unsigned remaining) { - register u_char *p; - register u_short family; - char buf[RIP_AUTHLEN]; - - /* RFC 1723 */ - family = EXTRACT_16BITS(&ni->rip_family); - if (family == 0xFFFF) { - if (EXTRACT_16BITS(&ni->rip_tag) == 2) { - memcpy(buf, &ni->rip_dest, sizeof(buf)); - buf[sizeof(buf)-1] = '\0'; - for (p = buf; *p; p++) { - if (!isprint(*p)) - break; - } - if (!*p) { - printf(" [password %s]", buf); - } else { - printf(" [password: "); - rip_printblk((u_char *)&ni->rip_dest, - (u_char *)&ni->rip_metric + - sizeof(ni->rip_metric)); - printf("]"); - } + const struct rip_entry_header *eh = (const struct rip_entry_header *)p; + u_short family; + const struct rip_netinfo_v2 *ni; + + ND_ICHECKMSG_ZU("remaining data length", remaining, <, sizeof(*eh)); + 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_ICHECKMSG_ZU("remaining data length", remaining, + <, sizeof(*ch)); + 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 { - printf(" [auth %d:", - EXTRACT_16BITS(&ni->rip_tag)); - rip_printblk((u_char *)&ni->rip_dest, - (u_char *)&ni->rip_metric + - sizeof(ni->rip_metric)); - printf("]"); + 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 != AF_INET) { - printf(" [family %d:", family); - rip_printblk((u_char *)&ni->rip_tag, - (u_char *)&ni->rip_metric + - sizeof(ni->rip_metric)); - printf("]"); - return; - } else { /* AF_INET */ - printf(" {%s", ipaddr_string(&ni->rip_dest)); - if (ni->rip_dest_mask) - printf("/%s", ipaddr_string(&ni->rip_dest_mask)); - if (ni->rip_router) - printf("->%s", ipaddr_string(&ni->rip_router)); - if (ni->rip_tag) - printf(" tag %04x", EXTRACT_16BITS(&ni->rip_tag)); - printf("}(%d)", EXTRACT_32BITS(&ni->rip_metric)); + } else if (family != BSD_AF_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_AF_INET or AFI 0 */ + ni = (const struct rip_netinfo_v2 *)p; + ND_ICHECKMSG_ZU("remaining data length", remaining, <, + sizeof(*ni)); + 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); +invalid: + return 0; } void -rip_print(const u_char *dat, u_int length) +rip_print(netdissect_options *ndo, + const u_char *p, u_int len) { - register const struct rip *rp; - register const struct rip_netinfo *ni; - register int i, j, trunc; + const struct rip *rp; + uint8_t vers, cmd; + unsigned entry_size; - i = min(length, snapend - dat) - sizeof(*rp); - if (i < 0) { - printf(" [|rip]"); - return; + ndo->ndo_protocol = "rip"; + ND_PRINT("%s", (ndo->ndo_vflag >= 1) ? "\n\t" : ""); + nd_print_protocol_caps(ndo); + ND_ICHECKMSG_ZU("packet length", len, <, sizeof(*rp)); + + rp = (const struct rip *)p; + + vers = GET_U_1(rp->rip_vers); + ND_PRINT("v%u", vers); + if (vers != 1 && vers != 2) { + ND_PRINT(" [version != 1 && version != 2]"); + goto invalid; } - rp = (struct rip *)dat; - switch (rp->rip_vers) { - case 0: - /* RFC 1058 */ - printf(" RIPv0: "); - rip_printblk((u_char *)&ni->rip_family, - (u_char *)&ni->rip_metric + - sizeof(ni->rip_metric)); - break; - default: - switch (rp->rip_cmd) { - case RIPCMD_REQUEST: - printf(" RIPv%d-req %d", rp->rip_vers, length); - break; - case RIPCMD_RESPONSE: - j = length / sizeof(*ni); - if (j * sizeof(*ni) != length - 4) - printf(" RIPv%d-resp [items %d] [%d]:", - rp->rip_vers, j, length); - else - printf(" RIPv%d-resp [items %d]:", - rp->rip_vers, j); - trunc = (i / sizeof(*ni)) != j; - ni = (struct rip_netinfo *)(rp + 1); - for (; (i -= sizeof(*ni)) >= 0; ++ni) { - if (rp->rip_vers == 1) - rip_entry_print_v1(rp->rip_vers, ni); - else - rip_entry_print_v2(rp->rip_vers, ni); + /* 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), + len); + + ND_TCHECK_SIZE(rp); + if (ndo->ndo_vflag < 1) + return; + p += sizeof(*rp); + len -= sizeof(*rp); + + switch (cmd) { + + case RIPCMD_REQUEST: + case RIPCMD_RESPONSE: + switch (vers) { + + case 1: + ND_PRINT(", routes: %u", len / RIP_ROUTELEN); + while (len != 0) { + entry_size = rip_entry_print_v1(ndo, p, len); + if (entry_size == 0) { + /* Error */ + goto invalid; + } + ND_ICHECKMSG_U("remaining entries length", + len, <, entry_size); + p += entry_size; + len -= entry_size; } - if (trunc) - printf("[|rip]"); - break; - case RIPCMD_TRACEON: - printf(" RIPv%d-traceon %d: \"", rp->rip_vers, length); - (void)fn_print((const u_char *)(rp + 1), snapend); - fputs("\"\n", stdout); - break; - case RIPCMD_TRACEOFF: - printf(" RIPv%d-traceoff %d", rp->rip_vers, length); break; - case RIPCMD_POLL: - printf(" RIPv%d-poll %d", rp->rip_vers, length); - break; - case RIPCMD_POLLENTRY: - printf(" RIPv%d-pollentry %d", rp->rip_vers, length); + + case 2: + ND_PRINT(", routes: %u or less", len / RIP_ROUTELEN); + while (len != 0) { + entry_size = rip_entry_print_v2(ndo, p, len); + if (entry_size == 0) { + /* Error */ + goto invalid; + } + ND_ICHECKMSG_U("remaining entries length", + len, <, entry_size); + p += entry_size; + len -= entry_size; + } break; + default: - printf(" RIPv%d-#%d %d", rp->rip_vers, rp->rip_cmd, - length); + ND_PRINT(", unknown version"); break; } - } + break; + + case RIPCMD_TRACEON: + case RIPCMD_TRACEOFF: + case RIPCMD_TRIGREQ: + case RIPCMD_TRIGRESP: + case RIPCMD_TRIGACK: + case RIPCMD_UPDREQ: + case RIPCMD_UPDRESP: + case RIPCMD_UPDACK: + break; + + default: + if (ndo->ndo_vflag <= 1) { + if (!print_unknown_data(ndo, p, "\n\t", len)) + return; + } + break; + } + /* do we want to see an additionally hexdump ? */ + if (ndo->ndo_vflag > 1 && ND_TTEST_LEN(p, len)) { + if (!print_unknown_data(ndo, p, "\n\t", len)) + return; + } + return; +invalid: + nd_print_invalid(ndo); + ND_TCHECK_LEN(p, len); }