tcpdump mailing list archives

[PATCH 2/2] print-olsr: Add basic IPv6 support.


From: Florian Forster <tcpdump () nospam verplant org>
Date: Sun, 17 May 2009 00:05:30 +0200

From: Florian Forster <octo () leeloo lan home verplant org>

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 <octo () leeloo lan home verplant org>
---
 CREDITS      |    1 +
 interface.h  |    2 +-
 print-olsr.c |  345 ++++++++++++++++++++++++++++++++++++++++++++--------------
 print-udp.c  |   13 ++-
 4 files changed, 272 insertions(+), 89 deletions(-)

diff --git a/CREDITS b/CREDITS
index fb9065e..aa43b92 100644
--- a/CREDITS
+++ b/CREDITS
@@ -51,6 +51,7 @@ Additional people who have contributed patches:
        Eddie Kohler                    <xexd at sourceforge dot net>
        Elmar Kirchner                  <elmar at juniper dot net>
        Florent Drouin                  <Florent dot Drouin at alcatel-lucent dot fr>
+       Florian Forster                 <octo at verplant dot org>
        Francis Dupont                  <Francis dot Dupont at enst-bretagne dot fr>
        Francisco Matias Cuenca-Acuna   <mcuenca at george dot rutgers dot edu>
        Francois-Xavier Le Bail         <fx dot lebail at yahoo dot com>
diff --git a/interface.h b/interface.h
index f6a4a19..afeaee9 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 4147619..fb92a77 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 <hannes () juniper net>
+ * IPv6 additions by Florian Forster <octo at verplant.org>
  */
 
 #ifdef HAVE_CONFIG_H
@@ -28,7 +30,7 @@
 
 #include "interface.h"
 #include "addrtoname.h"
-#include "extract.h"           
+#include "extract.h"
 #include "ip.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,41 +289,81 @@ 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:
         case OLSR_HELLO_LQ_MSG:
-            if (!TTEST2(*msg_data, sizeof(struct olsr_hello))) 
+            if (!TTEST2(*msg_data, sizeof(struct olsr_hello)))
                 goto trunc;
 
             ptr.hello = (struct olsr_hello *)msg_data;
@@ -291,7 +378,7 @@ olsr_print (const u_char *pptr, u_int length)
                 /*
                  * link-type.
                  */
-                if (!TTEST2(*msg_data, sizeof(struct olsr_hello_link)))        
+                if (!TTEST2(*msg_data, sizeof(struct olsr_hello_link)))
                     goto trunc;
 
                 ptr.hello_link = (struct olsr_hello_link *)msg_data;
@@ -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;
@@ -330,7 +422,7 @@ olsr_print (const u_char *pptr, u_int length)
 
         case OLSR_TC_MSG:
         case OLSR_TC_LQ_MSG:
-            if (!TTEST2(*msg_data, sizeof(struct olsr_tc)))    
+            if (!TTEST2(*msg_data, sizeof(struct olsr_tc)))
                 goto trunc;
 
             ptr.tc = (struct olsr_tc *)msg_data;
@@ -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_hna4 *)msg_data;
 
-                ptr.hna = (struct olsr_hna *)msg_data;
+                    /* print 4 prefixes per line */
+                    if (col == 0)
+                        printf ("\n\t    ");
+                    else
+                        printf (", ");
 
-                /* print 4 prefixes per line */
+                    printf("%s/%u",
+                            ipaddr_string(ptr.hna->network),
+                            mask2plen(EXTRACT_32BITS(ptr.hna->mask)));
 
-                printf("%s/%u%s",
-                       ipaddr_string(ptr.hna->network),
-                       mask2plen(EXTRACT_32BITS(ptr.hna->mask)),                       
-                       prefix % 4 == 0 ? "\n\t    " : " ");
+                    msg_data += sizeof(struct olsr_hna4);
+                    msg_tlen -= sizeof(struct olsr_hna4);
 
-                msg_data += sizeof(struct olsr_hna);
-                msg_tlen -= sizeof(struct olsr_hna);
-                prefix ++;
+                    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 5e564cd..0f1528e 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 )
-- 
1.6.2.4

-
This is the tcpdump-workers list.
Visit https://cod.sandelman.ca/ to unsubscribe.


Current thread: