[ipv6] Verify destination address in ICMP6 and ensure I/O buffer is freed master
authorMatthew Iselin <matthew@theiselins.net>
Tue, 19 Jul 2011 12:38:19 +0000 (22:38 +1000)
committerMarty Connor <mdc@etherboot.org>
Sun, 7 Aug 2011 14:43:25 +0000 (10:43 -0400)
Previously gPXE would happily respond to any ICMP6 echo packet sent on
the network, regardless of whether that packet was addressed to it or
not. This will stop that from happening.

Also, the previous handling would not free the passed I/O buffer; this
has been fixed in this commit.

Signed-off-by: Matthew Iselin <matthew@theiselins.net>
Signed-off-by: Marty Connor <mdc@etherboot.org>
src/net/icmpv6.c

index ac4e308..d154c03 100644 (file)
@@ -143,7 +143,6 @@ int icmp6_handle_echo ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
                      strerror ( rc ) );
        }
 
-       free_iob(iobuf);
        return rc;
 }
 
@@ -177,6 +176,7 @@ int icmp6_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
                      uint16_t pshdr_csum ) {
        struct icmp6_header *icmp6hdr = iobuf->data;
        struct icmp6_net_protocol *icmp6_net_protocol;
+       struct sockaddr_in6 *dest = ( struct sockaddr_in6 * ) st_dest;
        size_t len = iob_len ( iobuf );
        unsigned int csum;
        int rc;
@@ -187,6 +187,22 @@ int icmp6_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
                free_iob ( iobuf );
                return -EINVAL;
        }
+       
+       /* Get the net protocol for this packet. */
+       icmp6_net_protocol = icmp6_find_protocol ( htons ( ETH_P_IPV6 ) );
+       if ( ! icmp6_net_protocol ) {
+               rc = 0;
+               goto done;
+       }
+       
+       /* Verify that we should even begin to process this packet.
+        * It must be either unicast, and targeted to us, or multicast. */
+       if ( icmp6_net_protocol->check ( netdev, &dest->sin6_addr ) &&
+            ( ! ( dest->sin6_addr.in6_u.u6_addr8[0] == 0xFF ) ) ) {
+               DBG ( "ICMPv6 packet is not targeted to us.\n" );
+               rc = -EINVAL;
+               goto done;
+       }
 
        /* Verify checksum */
        csum = tcpip_continue_chksum ( pshdr_csum, icmp6hdr, len );
@@ -197,30 +213,27 @@ int icmp6_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
                rc = -EINVAL;
                goto done;
        }
-       
-       /* Get the net protocol for this packet. */
-       icmp6_net_protocol = icmp6_find_protocol ( htons ( ETH_P_IPV6 ) );
-       if ( ! icmp6_net_protocol ) {
-               rc = 0;
-               goto done;
-       }
 
        DBG ( "ICMPv6: packet with type %d and code %x\n", icmp6hdr->type, icmp6hdr->code);
 
        /* Process the ICMP header */
        switch ( icmp6hdr->type ) {
        case ICMP6_ROUTER_ADVERT:
-           return ndp_process_radvert ( iobuf, st_src, st_dest, netdev, icmp6_net_protocol );
+               rc = ndp_process_radvert ( iobuf, st_src, st_dest, netdev, icmp6_net_protocol );
+               break;
        case ICMP6_NSOLICIT:
-               return ndp_process_nsolicit ( iobuf, st_src, st_dest, netdev, icmp6_net_protocol );
+               rc = ndp_process_nsolicit ( iobuf, st_src, st_dest, netdev, icmp6_net_protocol );
+               break;
        case ICMP6_NADVERT:
-               return ndp_process_nadvert ( iobuf, st_src, st_dest, icmp6_net_protocol );
+               rc = ndp_process_nadvert ( iobuf, st_src, st_dest, icmp6_net_protocol );
+               break;
        case ICMP6_ECHO_REQUEST:
-               return icmp6_handle_echo ( iobuf, st_src, st_dest, icmp6_net_protocol );
+               rc = icmp6_handle_echo ( iobuf, st_src, st_dest, icmp6_net_protocol );
+               break;
+       default:
+               rc = -ENOSYS;
        }
 
-       rc = -ENOSYS;
-
  done:
        free_iob ( iobuf );
        return rc;