From: Florian Forster Date: Sat, 16 May 2009 22:05:30 +0000 (+0200) Subject: print-olsr: Add basic IPv6 support. X-Git-Tag: tcpdump-4.1.0~117 X-Git-Url: https://git.tcpdump.org/tcpdump/commitdiff_plain/289e0aed7d910e6b2df73476848674a73b8ab1ac print-olsr: Add basic IPv6 support. Unfortunately OLSR uses the same IDs for IPv4 and IPv6 packets, even though the size of "messages" differ. The version of the internet protocol is therefore handed to the "olsr_print" function. The code isn't very nice, due to a high density of #ifdef INET6'es. If IPv6-support really should be optional, I'm afraid this is inevitable. Both, compilation with and without IPv6 support has been tested. The patch addresses fixes other issues, too. The length given in the packet was used for pointer arithmetic without checking if the value was in a reasonable range first in several places. It should now be possible to decode more than one "namespace message" within a single packet. Other changes remove trailing whitespace or fix lines indented with tabs (the majority of the file is indented using spaces). Signed-off-by: Florian Forster --- diff --git a/CREDITS b/CREDITS index fb9065e3..aa43b929 100644 --- a/CREDITS +++ b/CREDITS @@ -51,6 +51,7 @@ Additional people who have contributed patches: Eddie Kohler Elmar Kirchner Florent Drouin + Florian Forster Francis Dupont Francisco Matias Cuenca-Acuna Francois-Xavier Le Bail diff --git a/interface.h b/interface.h index f6a4a191..afeaee96 100644 --- a/interface.h +++ b/interface.h @@ -229,7 +229,7 @@ extern void ns_print(const u_char *, u_int, int); extern void ntp_print(const u_char *, u_int); extern u_int null_if_print(const struct pcap_pkthdr *, const u_char *); extern void ospf_print(const u_char *, u_int, const u_char *); -extern void olsr_print (const u_char *, u_int); +extern void olsr_print (const u_char *, u_int, int); extern void pimv1_print(const u_char *, u_int); extern void cisco_autorp_print(const u_char *, u_int); extern void rsvp_print(const u_char *, u_int); diff --git a/print-olsr.c b/print-olsr.c index 599fb1f7..07a04b53 100644 --- a/print-olsr.c +++ b/print-olsr.c @@ -1,5 +1,6 @@ /* * Copyright (c) 1998-2007 The TCPDUMP project + * Copyright (c) 2009 Florian Forster * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code @@ -15,6 +16,7 @@ * Optimized Link State Protocl (OLSR) as per rfc3626 * * Original code by Hannes Gredler + * IPv6 additions by Florian Forster */ #ifdef HAVE_CONFIG_H @@ -88,7 +90,7 @@ static struct tok olsr_msg_values[] = { { 0, NULL} }; -struct olsr_msg { +struct olsr_msg4 { u_int8_t msg_type; u_int8_t vtime; u_int8_t msg_len[2]; @@ -98,6 +100,16 @@ struct olsr_msg { u_int8_t msg_seq[2]; }; +struct olsr_msg6 { + u_int8_t msg_type; + u_int8_t vtime; + u_int8_t msg_len[2]; + u_int8_t originator[16]; + u_int8_t ttl; + u_int8_t hopcount; + u_int8_t msg_seq[2]; +}; + struct olsr_hello { u_int8_t res[2]; u_int8_t htime; @@ -115,11 +127,16 @@ struct olsr_tc { u_int8_t res[2]; }; -struct olsr_hna { +struct olsr_hna4 { u_int8_t network[4]; u_int8_t mask[4]; }; +struct olsr_hna6 { + u_int8_t network[16]; + u_int8_t mask[16]; +}; + #define OLSR_EXTRACT_LINK_TYPE(link_code) (link_code & 0x3) #define OLSR_EXTRACT_NEIGHBOR_TYPE(link_code) (link_code >> 2) @@ -139,13 +156,20 @@ static struct tok olsr_neighbor_type_values[] = { { 0, NULL} }; -struct olsr_lq_neighbor { +struct olsr_lq_neighbor4 { u_int8_t neighbor[4]; u_int8_t link_quality; u_int8_t neighbor_link_quality; u_int8_t res[2]; }; +struct olsr_lq_neighbor6 { + u_int8_t neighbor[16]; + u_int8_t link_quality; + u_int8_t neighbor_link_quality; + u_int8_t res[2]; +}; + /* * macro to convert the 8-bit mantissa/exponent to a double float * taken from olsr.org. @@ -158,13 +182,13 @@ struct olsr_lq_neighbor { * print a neighbor list with LQ extensions. */ static void -olsr_print_lq_neighbor (const u_char *msg_data, u_int hello_len) +olsr_print_lq_neighbor4 (const u_char *msg_data, u_int hello_len) { - struct olsr_lq_neighbor *lq_neighbor; + struct olsr_lq_neighbor4 *lq_neighbor; - while (hello_len >= sizeof(struct olsr_lq_neighbor)) { + while (hello_len >= sizeof(struct olsr_lq_neighbor4)) { - lq_neighbor = (struct olsr_lq_neighbor *)msg_data; + lq_neighbor = (struct olsr_lq_neighbor4 *)msg_data; printf("\n\t neighbor %s, link-quality %.2lf%%" ", neighbor-link-quality %.2lf%%", @@ -172,11 +196,33 @@ olsr_print_lq_neighbor (const u_char *msg_data, u_int hello_len) ((double)lq_neighbor->link_quality/2.55), ((double)lq_neighbor->neighbor_link_quality/2.55)); - msg_data += sizeof(struct olsr_lq_neighbor); - hello_len -= sizeof(struct olsr_lq_neighbor); + msg_data += sizeof(struct olsr_lq_neighbor4); + hello_len -= sizeof(struct olsr_lq_neighbor4); } } +#if INET6 +static void +olsr_print_lq_neighbor6 (const u_char *msg_data, u_int hello_len) +{ + struct olsr_lq_neighbor6 *lq_neighbor; + + while (hello_len >= sizeof(struct olsr_lq_neighbor6)) { + + lq_neighbor = (struct olsr_lq_neighbor6 *)msg_data; + + printf("\n\t neighbor %s, link-quality %.2lf%%" + ", neighbor-link-quality %.2lf%%", + ip6addr_string(lq_neighbor->neighbor), + ((double)lq_neighbor->link_quality/2.55), + ((double)lq_neighbor->neighbor_link_quality/2.55)); + + msg_data += sizeof(struct olsr_lq_neighbor6); + hello_len -= sizeof(struct olsr_lq_neighbor6); + } +} +#endif /* INET6 */ + /* * print a neighbor list. */ @@ -202,20 +248,20 @@ olsr_print_neighbor (const u_char *msg_data, u_int hello_len) void -olsr_print (const u_char *pptr, u_int length) +olsr_print (const u_char *pptr, u_int length, int is_ipv6) { union { const struct olsr_common *common; - const struct olsr_msg *msg; + const struct olsr_msg4 *msg4; + const struct olsr_msg6 *msg6; const struct olsr_hello *hello; const struct olsr_hello_link *hello_link; - const struct olsr_lq_neighbor *lq_neighbor; const struct olsr_tc *tc; - const struct olsr_hna *hna; + const struct olsr_hna4 *hna; } ptr; - u_int msg_type, msg_len, msg_tlen, hello_len, prefix; - u_int16_t name_entries, name_entry_type, name_entry_len; + u_int msg_type, msg_len, msg_tlen, hello_len; + u_int16_t name_entry_type, name_entry_len; u_int8_t link_type, neighbor_type; const u_char *tptr, *msg_data; @@ -226,15 +272,16 @@ olsr_print (const u_char *pptr, u_int length) } if (!TTEST2(*tptr, sizeof(struct olsr_common))) { - goto trunc; + goto trunc; } ptr.common = (struct olsr_common *)tptr; length = MIN(length, EXTRACT_16BITS(ptr.common->packet_len)); - printf("OLSR, seq 0x%04x, length %u", - EXTRACT_16BITS(ptr.common->packet_seq), - length); + printf("OLSRv%i, seq 0x%04x, length %u", + (is_ipv6 == 0) ? 4 : 6, + EXTRACT_16BITS(ptr.common->packet_seq), + length); tptr += sizeof(struct olsr_common); @@ -242,36 +289,76 @@ olsr_print (const u_char *pptr, u_int length) * In non-verbose mode, just print version. */ if (vflag < 1) { - return; + return; } while (tptr < (pptr+length)) { - - if (!TTEST2(*tptr, sizeof(struct olsr_msg))) + union + { + struct olsr_msg4 *v4; + struct olsr_msg6 *v6; + } msgptr; + int msg_len_valid = 0; + + if (!TTEST2(*tptr, sizeof(struct olsr_msg4))) goto trunc; - ptr.msg = (struct olsr_msg *)tptr; - - msg_type = ptr.msg->msg_type; - msg_len = EXTRACT_16BITS(ptr.msg->msg_len); +#if INET6 + if (is_ipv6) + { + msgptr.v6 = (struct olsr_msg6 *) tptr; + msg_type = msgptr.v6->msg_type; + msg_len = EXTRACT_16BITS(msgptr.v6->msg_len); + if ((msg_len >= sizeof (struct olsr_msg6)) + && (msg_len <= length)) + msg_len_valid = 1; + + /* infinite loop check */ + if (msg_type == 0 || msg_len == 0) { + return; + } - /* infinite loop check */ - if (msg_type == 0 || msg_len == 0) { - return; + printf("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u" + "\n\t vtime %.3lfs, msg-seq 0x%04x, length %u%s", + tok2str(olsr_msg_values, "Unknown", msg_type), + msg_type, ip6addr_string(msgptr.v6->originator), + msgptr.v6->ttl, + msgptr.v6->hopcount, + ME_TO_DOUBLE(msgptr.v6->vtime), + EXTRACT_16BITS(msgptr.v6->msg_seq), + msg_len, (msg_len_valid == 0) ? " (invalid)" : ""); + + msg_tlen = msg_len - sizeof(struct olsr_msg6); + msg_data = tptr + sizeof(struct olsr_msg6); } + else /* (!is_ipv6) */ +#endif /* INET6 */ + { + msgptr.v4 = (struct olsr_msg4 *) tptr; + msg_type = msgptr.v4->msg_type; + msg_len = EXTRACT_16BITS(msgptr.v4->msg_len); + if ((msg_len >= sizeof (struct olsr_msg4)) + && (msg_len <= length)) + msg_len_valid = 1; + + /* infinite loop check */ + if (msg_type == 0 || msg_len == 0) { + return; + } - printf("\n\t%s Message (%u), originator %s, ttl %u, hop %u" - "\n\t vtime %.3lfs, msg-seq 0x%04x, length %u", - tok2str(olsr_msg_values, "Unknown", msg_type), - msg_type, ipaddr_string(ptr.msg->originator), - ptr.msg->ttl, - ptr.msg->hopcount, - ME_TO_DOUBLE(ptr.msg->vtime), - EXTRACT_16BITS(ptr.msg->msg_seq), - msg_len); - - msg_tlen = msg_len - sizeof(struct olsr_msg); - msg_data = tptr + sizeof(struct olsr_msg); + printf("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u" + "\n\t vtime %.3lfs, msg-seq 0x%04x, length %u%s", + tok2str(olsr_msg_values, "Unknown", msg_type), + msg_type, ipaddr_string(msgptr.v4->originator), + msgptr.v4->ttl, + msgptr.v4->hopcount, + ME_TO_DOUBLE(msgptr.v4->vtime), + EXTRACT_16BITS(msgptr.v4->msg_seq), + msg_len, (msg_len_valid == 0) ? " (invalid)" : ""); + + msg_tlen = msg_len - sizeof(struct olsr_msg4); + msg_data = tptr + sizeof(struct olsr_msg4); + } switch (msg_type) { case OLSR_HELLO_MSG: @@ -320,7 +407,12 @@ olsr_print (const u_char *pptr, u_int length) if (msg_type == OLSR_HELLO_MSG) { olsr_print_neighbor(msg_data, hello_len); } else { - olsr_print_lq_neighbor(msg_data, hello_len); +#if INET6 + if (is_ipv6) + olsr_print_lq_neighbor6(msg_data, hello_len); + else +#endif + olsr_print_lq_neighbor4(msg_data, hello_len); } msg_data += hello_len; @@ -342,74 +434,159 @@ olsr_print (const u_char *pptr, u_int length) if (msg_type == OLSR_TC_MSG) { olsr_print_neighbor(msg_data, msg_tlen); } else { - olsr_print_lq_neighbor(msg_data, msg_tlen); +#if INET6 + if (is_ipv6) + olsr_print_lq_neighbor6(msg_data, msg_tlen); + else +#endif + olsr_print_lq_neighbor4(msg_data, msg_tlen); } break; case OLSR_MID_MSG: - if (!TTEST2(*msg_data, sizeof(struct in_addr))) + { + size_t addr_size = sizeof(struct in_addr); + +#if INET6 + if (is_ipv6) + addr_size = sizeof(struct in6_addr); +#endif + + if (!TTEST2(*msg_data, addr_size)) goto trunc; - while (msg_tlen >= sizeof(struct in_addr)) { - printf("\n\t interface address %s", ipaddr_string(msg_data)); - msg_data += sizeof(struct in_addr); - msg_tlen -= sizeof(struct in_addr); + while (msg_tlen >= addr_size) { + printf("\n\t interface address %s", +#if INET6 + is_ipv6 ? ip6addr_string(msg_data) : +#endif + ipaddr_string(msg_data)); + msg_data += addr_size; + msg_tlen -= addr_size; } break; + } case OLSR_HNA_MSG: - prefix = 1; - printf("\n\t advertised networks\n\t "); - while (msg_tlen >= sizeof(struct olsr_hna)) { - if (!TTEST2(*msg_data, sizeof(struct olsr_hna))) - goto trunc; + printf("\n\t Advertised networks (total %u)", + (unsigned int) (msg_tlen / sizeof(struct olsr_hna6))); +#if INET6 + if (is_ipv6) + { + int i = 0; + while (msg_tlen >= sizeof(struct olsr_hna6)) { + struct olsr_hna6 *hna6; + + if (!TTEST2(*msg_data, sizeof(struct olsr_hna6))) + goto trunc; + + hna6 = (struct olsr_hna6 *)msg_data; + + printf("\n\t #%i: %s/%u", + i, ip6addr_string(hna6->network), + mask62plen (hna6->mask)); + + msg_data += sizeof(struct olsr_hna6); + msg_tlen -= sizeof(struct olsr_hna6); + } + } + else +#endif + { + int col = 0; + while (msg_tlen >= sizeof(struct olsr_hna4)) { + if (!TTEST2(*msg_data, sizeof(struct olsr_hna4))) + goto trunc; - ptr.hna = (struct olsr_hna *)msg_data; + ptr.hna = (struct olsr_hna4 *)msg_data; - /* print 4 prefixes per line */ + /* print 4 prefixes per line */ + if (col == 0) + printf ("\n\t "); + else + printf (", "); - printf("%s/%u%s", - ipaddr_string(ptr.hna->network), - mask2plen(EXTRACT_32BITS(ptr.hna->mask)), - prefix % 4 == 0 ? "\n\t " : " "); + printf("%s/%u", + ipaddr_string(ptr.hna->network), + mask2plen(EXTRACT_32BITS(ptr.hna->mask))); - msg_data += sizeof(struct olsr_hna); - msg_tlen -= sizeof(struct olsr_hna); - prefix ++; + msg_data += sizeof(struct olsr_hna4); + msg_tlen -= sizeof(struct olsr_hna4); + + col = (col + 1) % 4; + } } break; case OLSR_NAMESERVICE_MSG: - name_entries = EXTRACT_16BITS(msg_data+2); - printf("\n\t Version %u, Entries %u", - EXTRACT_16BITS(msg_data), name_entries); + { + u_int16_t name_entries = EXTRACT_16BITS(msg_data+2); + u_int16_t addr_size = 4; + int name_entries_valid = 0; + u_int16_t i; + + if (is_ipv6) + addr_size = 16; + + if ((name_entries > 0) + && ((name_entries * (4 + addr_size)) <= msg_tlen)) + name_entries_valid = 1; + + printf("\n\t Version %u, Entries %u%s", + EXTRACT_16BITS(msg_data), + name_entries, (name_entries_valid == 0) ? " (invalid)" : ""); + + if (name_entries_valid == 0) + break; + msg_data += 4; msg_tlen -= 4; - while (name_entries && msg_tlen) { + for (i = 0; i < name_entries; i++) { + int name_entry_len_valid = 0; + + if (msg_tlen < 4) + break; name_entry_type = EXTRACT_16BITS(msg_data); name_entry_len = EXTRACT_16BITS(msg_data+2); + msg_data += 4; msg_tlen -= 4; - printf("\n\t #%u Name Entry, length %u", - name_entry_type, - name_entry_len); + if ((name_entry_len > 0) && ((addr_size + name_entry_len) <= msg_tlen)) + name_entry_len_valid = 1; - printf(", originator %s", ipaddr_string(msg_data)); + printf("\n\t #%u: type %#06x, length %u%s", + (unsigned int) i, name_entry_type, + name_entry_len, (name_entry_len_valid == 0) ? " (invalid)" : ""); - /* 32-bit alignement */ - if (name_entry_len%4 != 0) - name_entry_len+=4-(name_entry_len%4); + if (name_entry_len_valid == 0) + break; + { + char name[name_entry_len + 1]; + memcpy (name, msg_data + addr_size, name_entry_len); + name[name_entry_len] = 0; +#if INET6 + if (is_ipv6) + printf(", address %s, name \"%s\"", + ip6addr_string(msg_data), name); + else +#endif + printf(", address %s, name \"%s\"", + ipaddr_string(msg_data), name); + } - msg_data += name_entry_len; - msg_tlen -= name_entry_len; + /* 32-bit alignment */ + if (name_entry_len%4 != 0) + name_entry_len+=4-(name_entry_len%4); - name_entries--; - } + msg_data += addr_size + name_entry_len; + msg_tlen -= addr_size + name_entry_len; + } /* for (i = 0; i < name_entries; i++) */ break; + } /* case OLSR_NAMESERVICE_MSG */ /* * FIXME those are the defined messages that lack a decoder @@ -417,11 +594,11 @@ olsr_print (const u_char *pptr, u_int length) */ case OLSR_POWERINFO_MSG: default: - print_unknown_data(msg_data, "\n\t ", msg_tlen); + print_unknown_data(msg_data, "\n\t ", msg_tlen); break; - } + } /* switch (msg_type) */ tptr += msg_len; - } + } /* while (tptr < (pptr+length)) */ return; diff --git a/print-udp.c b/print-udp.c index 5e564cde..0f1528e0 100644 --- a/print-udp.c +++ b/print-udp.c @@ -672,11 +672,16 @@ udp_print(register const u_char *bp, u_int length, hsrp_print((const u_char *)(up + 1), length); else if (ISPORT(LWRES_PORT)) lwres_print((const u_char *)(up + 1), length); - else if (ISPORT(LDP_PORT)) + else if (ISPORT(LDP_PORT)) ldp_print((const u_char *)(up + 1), length); - else if (ISPORT(OLSR_PORT)) - olsr_print((const u_char *)(up + 1), length); - else if (ISPORT(MPLS_LSP_PING_PORT)) + else if (ISPORT(OLSR_PORT)) + olsr_print((const u_char *)(up + 1), length, +#if INET6 + (IP_V(ip) == 6) ? 1 : 0); +#else + 0); +#endif + else if (ISPORT(MPLS_LSP_PING_PORT)) lspping_print((const u_char *)(up + 1), length); else if (dport == BFD_CONTROL_PORT || dport == BFD_ECHO_PORT )