]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-ip6.c
OSPF: Use %zu to print sizeof values
[tcpdump] / print-ip6.c
index 37a17cc86e41c6d104072640218de8136ca071e3..525a284ecdb0c4375631c2c123eb16161d9c3030 100644 (file)
@@ -44,7 +44,7 @@
  * calculation.
  */
 static void
-ip6_finddst(netdissect_options *ndo, struct in6_addr *dst,
+ip6_finddst(netdissect_options *ndo, nd_ipv6 *dst,
             const struct ip6_hdr *ip6)
 {
        const u_char *cp;
@@ -77,7 +77,6 @@ ip6_finddst(netdissect_options *ndo, struct in6_addr *dst,
                         * the header, in units of 8 octets, excluding
                         * the first 8 octets.
                         */
-                       ND_TCHECK_2(cp);
                        advance = (GET_U_1(cp + 1) + 1) << 3;
                        nh = GET_U_1(cp);
                        break;
@@ -88,7 +87,6 @@ ip6_finddst(netdissect_options *ndo, struct in6_addr *dst,
                         * marked as reserved, and the header is always
                         * the same size.
                         */
-                       ND_TCHECK_1(cp);
                        advance = sizeof(struct ip6_frag);
                        nh = GET_U_1(cp);
                        break;
@@ -165,7 +163,7 @@ ip6_finddst(netdissect_options *ndo, struct in6_addr *dst,
 
 done:
 trunc:
-       UNALIGNED_MEMCPY(dst, dst_addr, sizeof(nd_ipv6));
+       GET_CPY_BYTES(dst, dst_addr, sizeof(nd_ipv6));
 }
 
 /*
@@ -177,8 +175,8 @@ nextproto6_cksum(netdissect_options *ndo,
                 u_int len, u_int covlen, uint8_t next_proto)
 {
         struct {
-                struct in6_addr ph_src;
-                struct in6_addr ph_dst;
+                nd_ipv6 ph_src;
+                nd_ipv6 ph_dst;
                 uint32_t       ph_len;
                 uint8_t        ph_zero[3];
                 uint8_t        ph_nxt;
@@ -188,7 +186,7 @@ nextproto6_cksum(netdissect_options *ndo,
 
         /* pseudo-header */
         memset(&ph, 0, sizeof(ph));
-        UNALIGNED_MEMCPY(&ph.ph_src, ip6->ip6_src, sizeof (struct in6_addr));
+        GET_CPY_BYTES(&ph.ph_src, ip6->ip6_src, sizeof(nd_ipv6));
         nh = GET_U_1(ip6->ip6_nxt);
         switch (nh) {
 
@@ -207,8 +205,7 @@ nextproto6_cksum(netdissect_options *ndo,
                 break;
 
         default:
-                UNALIGNED_MEMCPY(&ph.ph_dst, ip6->ip6_dst,
-                                 sizeof (struct in6_addr));
+                GET_CPY_BYTES(&ph.ph_dst, ip6->ip6_dst, sizeof(nd_ipv6));
                 break;
         }
         ph.ph_len = htonl(len);
@@ -231,12 +228,14 @@ ip6_print(netdissect_options *ndo, const u_char *bp, u_int length)
        const struct ip6_hdr *ip6;
        int advance;
        u_int len;
-       const u_char *ipend;
+       u_int total_advance;
        const u_char *cp;
-       u_int payload_len;
+       uint32_t payload_len;
        uint8_t nh;
        int fragmented = 0;
        u_int flow;
+       int found_extension_header;
+       int found_jumbo;
 
        ndo->ndo_protocol = "ip6";
        ip6 = (const struct ip6_hdr *)bp;
@@ -256,10 +255,35 @@ ip6_print(netdissect_options *ndo, const u_char *bp, u_int length)
        }
 
        payload_len = GET_BE_U_2(ip6->ip6_plen);
-       len = payload_len + sizeof(struct ip6_hdr);
-       if (length < len)
-               ND_PRINT("truncated-ip6 - %u bytes missing!",
-                       len - length);
+       /*
+        * RFC 1883 says:
+        *
+        * The Payload Length field in the IPv6 header must be set to zero
+        * in every packet that carries the Jumbo Payload option.  If a
+        * packet is received with a valid Jumbo Payload option present and
+        * a non-zero IPv6 Payload Length field, an ICMP Parameter Problem
+        * message, Code 0, should be sent to the packet's source, pointing
+        * to the Option Type field of the Jumbo Payload option.
+        *
+        * Later versions of the IPv6 spec don't discuss the Jumbo Payload
+        * option.
+        *
+        * If the payload length is 0, we temporarily just set the total
+        * length to the remaining data in the packet (which, for Ethernet,
+        * could include frame padding, but if it's a Jumbo Payload frame,
+        * it shouldn't even be sendable over Ethernet, so we don't worry
+        * about that), so we can process the extension headers in order
+        * to *find* a Jumbo Payload hop-by-hop option and, when we've
+        * processed all the extension headers, check whether we found
+        * a Jumbo Payload option, and fail if we haven't.
+        */
+       if (payload_len != 0) {
+               len = payload_len + sizeof(struct ip6_hdr);
+               if (length < len)
+                       ND_PRINT("truncated-ip6 - %u bytes missing!",
+                               len - length);
+       } else
+               len = length + sizeof(struct ip6_hdr);
 
         nh = GET_U_1(ip6->ip6_nxt);
         if (ndo->ndo_vflag) {
@@ -289,46 +313,57 @@ ip6_print(netdissect_options *ndo, const u_char *bp, u_int length)
        /*
         * Cut off the snapshot length to the end of the IP payload.
         */
-       ipend = bp + len;
-       if (ipend < ndo->ndo_snapend)
-               ndo->ndo_snapend = ipend;
+       nd_push_snapend(ndo, bp + len);
 
        cp = (const u_char *)ip6;
        advance = sizeof(struct ip6_hdr);
+       total_advance = 0;
        /* Process extension headers */
+       found_extension_header = 0;
+       found_jumbo = 0;
        while (cp < ndo->ndo_snapend && advance > 0) {
                if (len < (u_int)advance)
                        goto trunc;
                cp += advance;
                len -= advance;
+               total_advance += advance;
 
                if (cp == (const u_char *)(ip6 + 1) &&
                    nh != IPPROTO_TCP && nh != IPPROTO_UDP &&
                    nh != IPPROTO_DCCP && nh != IPPROTO_SCTP) {
-                       ND_PRINT("%s > %s: ", ip6addr_string(ndo, ip6->ip6_src),
-                                    ip6addr_string(ndo, ip6->ip6_dst));
+                       ND_PRINT("%s > %s: ", GET_IP6ADDR_STRING(ip6->ip6_src),
+                                    GET_IP6ADDR_STRING(ip6->ip6_dst));
                }
 
                switch (nh) {
 
                case IPPROTO_HOPOPTS:
-                       advance = hbhopt_print(ndo, cp);
-                       if (advance < 0)
+                       advance = hbhopt_process(ndo, cp, &found_jumbo, &payload_len);
+                       if (advance < 0) {
+                               nd_pop_packet_info(ndo);
                                return;
+                       }
+                       found_extension_header = 1;
                        nh = GET_U_1(cp);
                        break;
 
                case IPPROTO_DSTOPTS:
-                       advance = dstopt_print(ndo, cp);
-                       if (advance < 0)
+                       advance = dstopt_process(ndo, cp);
+                       if (advance < 0) {
+                               nd_pop_packet_info(ndo);
                                return;
+                       }
+                       found_extension_header = 1;
                        nh = GET_U_1(cp);
                        break;
 
                case IPPROTO_FRAGMENT:
                        advance = frag6_print(ndo, cp, (const u_char *)ip6);
-                       if (advance < 0 || ndo->ndo_snapend <= cp + advance)
+                       if (advance < 0 || ndo->ndo_snapend <= cp + advance) {
+                               nd_pop_packet_info(ndo);
                                return;
+                       }
+                       found_extension_header = 1;
                        nh = GET_U_1(cp);
                        fragmented = 1;
                        break;
@@ -339,21 +374,28 @@ ip6_print(netdissect_options *ndo, const u_char *bp, u_int length)
                         * XXX - we don't use "advance"; RFC 3775 says that
                         * the next header field in a mobility header
                         * should be IPPROTO_NONE, but speaks of
-                        * the possiblity of a future extension in
+                        * the possibility of a future extension in
                         * which payload can be piggybacked atop a
                         * mobility header.
                         */
                        advance = mobility_print(ndo, cp, (const u_char *)ip6);
-                       if (advance < 0)
+                       if (advance < 0) {
+                               nd_pop_packet_info(ndo);
                                return;
+                       }
+                       found_extension_header = 1;
                        nh = GET_U_1(cp);
+                       nd_pop_packet_info(ndo);
                        return;
 
                case IPPROTO_ROUTING:
                        ND_TCHECK_1(cp);
                        advance = rt6_print(ndo, cp, (const u_char *)ip6);
-                       if (advance < 0)
+                       if (advance < 0) {
+                               nd_pop_packet_info(ndo);
                                return;
+                       }
+                       found_extension_header = 1;
                        nh = GET_U_1(cp);
                        break;
 
@@ -362,8 +404,71 @@ ip6_print(netdissect_options *ndo, const u_char *bp, u_int length)
                         * Not an extension header; hand off to the
                         * IP protocol demuxer.
                         */
-                       ip_print_demux(ndo, cp, len, 6, fragmented,
-                           GET_U_1(ip6->ip6_hlim), nh, bp);
+                       if (found_jumbo) {
+                               /*
+                                * We saw a Jumbo Payload option.
+                                * Set the length to the payload length
+                                * plus the IPv6 header length, and
+                                * change the snapshot length accordingly.
+                                *
+                                * But make sure it's not shorter than
+                                * the total number of bytes we've
+                                * processed so far.
+                                */
+                               len = payload_len + sizeof(struct ip6_hdr);
+                               if (len < total_advance)
+                                       goto trunc;
+                               if (length < len)
+                                       ND_PRINT("truncated-ip6 - %u bytes missing!",
+                                               len - length);
+                               nd_change_snapend(ndo, bp + len);
+
+                               /*
+                                * Now subtract the length of the IPv6
+                                * header plus extension headers to get
+                                * the payload length.
+                                */
+                               len -= total_advance;
+                       } else {
+                               /*
+                                * We didn't see a Jumbo Payload option;
+                                * was the payload length zero?
+                                */
+                               if (payload_len == 0) {
+                                       /*
+                                        * Yes.  If we found an extension
+                                        * header, treat that as a truncated
+                                        * packet header, as there was
+                                        * no payload to contain an
+                                        * extension header.
+                                        */
+                                       if (found_extension_header)
+                                               goto trunc;
+
+                                       /*
+                                        * OK, we didn't see any extnesion
+                                        * header, but that means we have
+                                        * no payload, so set the length
+                                        * to the IPv6 header length,
+                                        * and change the snapshot length
+                                        * accordingly.
+                                        */
+                                       len = sizeof(struct ip6_hdr);
+                                       nd_change_snapend(ndo, bp + len);
+
+                                       /*
+                                        * Now subtract the length of
+                                        * the IPv6 header plus extension
+                                        * headers (there weren't any, so
+                                        * that's just the IPv6 header
+                                        * length) to get the payload length.
+                                        */
+                                       len -= total_advance;
+                               }
+                       }
+                       ip_demux_print(ndo, cp, len, 6, fragmented,
+                                      GET_U_1(ip6->ip6_hlim), nh, bp);
+                       nd_pop_packet_info(ndo);
                        return;
                }
 
@@ -371,6 +476,7 @@ ip6_print(netdissect_options *ndo, const u_char *bp, u_int length)
                ndo->ndo_protocol = "ip6";
        }
 
+       nd_pop_packet_info(ndo);
        return;
 trunc:
        nd_print_trunc(ndo);