Blame packet/deconstruct_unix.c

Packit b802ec
/*
Packit b802ec
    mtr  --  a network diagnostic tool
Packit b802ec
    Copyright (C) 2016  Matt Kimball
Packit b802ec
Packit b802ec
    This program is free software; you can redistribute it and/or modify
Packit b802ec
    it under the terms of the GNU General Public License version 2 as
Packit b802ec
    published by the Free Software Foundation.
Packit b802ec
Packit b802ec
    This program is distributed in the hope that it will be useful,
Packit b802ec
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit b802ec
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit b802ec
    GNU General Public License for more details.
Packit b802ec
Packit b802ec
    You should have received a copy of the GNU General Public License
Packit b802ec
    along with this program; if not, write to the Free Software
Packit b802ec
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Packit b802ec
*/
Packit b802ec
Packit b802ec
#include "deconstruct_unix.h"
Packit b802ec
Packit b802ec
#include <stdio.h>
Packit b802ec
#include <stdlib.h>
Packit b802ec
#include <string.h>
Packit b802ec
Packit b802ec
#include "protocols.h"
Packit b802ec
Packit b802ec
#define MAX_MPLS_LABELS 8
Packit b802ec
Packit b802ec
/*
Packit b802ec
    Given an ICMP id + ICMP sequence, find the match probe we've
Packit b802ec
    transmitted and if found, respond to the command which sent it
Packit b802ec
*/
Packit b802ec
static
Packit b802ec
void find_and_receive_probe(
Packit b802ec
    struct net_state_t *net_state,
Packit b802ec
    const struct sockaddr_storage *remote_addr,
Packit b802ec
    struct timeval *timestamp,
Packit b802ec
    int icmp_type,
Packit b802ec
    int protocol,
Packit b802ec
    int icmp_id,
Packit b802ec
    int icmp_sequence,
Packit b802ec
    int mpls_count,
Packit b802ec
    struct mpls_label_t *mpls)
Packit b802ec
{
Packit b802ec
    struct probe_t *probe;
Packit b802ec
Packit b802ec
    probe = find_probe(net_state, protocol, icmp_id, icmp_sequence);
Packit b802ec
    if (probe == NULL) {
Packit b802ec
        return;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    receive_probe(net_state, probe, icmp_type,
Packit b802ec
                  remote_addr, timestamp, mpls_count, mpls);
Packit b802ec
}
Packit b802ec
Packit b802ec
/*
Packit b802ec
    Handle a UDP packet received embedded in an ICMP reply.
Packit b802ec
    The sequence number identifying the probe might be in
Packit b802ec
    the source port number, the destination port number, or
Packit b802ec
    the checksum.  We'll check all three.
Packit b802ec
*/
Packit b802ec
static
Packit b802ec
void handle_inner_udp_packet(
Packit b802ec
    struct net_state_t *net_state,
Packit b802ec
    const struct sockaddr_storage *remote_addr,
Packit b802ec
    int icmp_result,
Packit b802ec
    const struct UDPHeader *udp,
Packit b802ec
    int udp_length,
Packit b802ec
    struct timeval *timestamp,
Packit b802ec
    int mpls_count,
Packit b802ec
    struct mpls_label_t *mpls)
Packit b802ec
{
Packit b802ec
    struct probe_t *probe;
Packit b802ec
Packit b802ec
    probe = find_probe(net_state, IPPROTO_UDP, 0, udp->dstport);
Packit b802ec
    if (probe == NULL) {
Packit b802ec
        probe = find_probe(net_state, IPPROTO_UDP, 0, udp->srcport);
Packit b802ec
    }
Packit b802ec
    if (probe == NULL) {
Packit b802ec
        probe = find_probe(net_state, IPPROTO_UDP, 0, udp->checksum);
Packit b802ec
    }
Packit b802ec
Packit b802ec
    if (probe != NULL) {
Packit b802ec
        receive_probe(net_state, probe, icmp_result,
Packit b802ec
                      remote_addr, timestamp, mpls_count, mpls);
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
/*
Packit b802ec
    We've received an ICMP message with an embedded IP packet.
Packit b802ec
    We will try to determine which of our outgoing probes
Packit b802ec
    corresponds to the embedded IP packet and record the response.
Packit b802ec
*/
Packit b802ec
static
Packit b802ec
void handle_inner_ip4_packet(
Packit b802ec
    struct net_state_t *net_state,
Packit b802ec
    const struct sockaddr_storage *remote_addr,
Packit b802ec
    int icmp_result,
Packit b802ec
    const struct IPHeader *ip,
Packit b802ec
    int packet_length,
Packit b802ec
    struct timeval *timestamp,
Packit b802ec
    int mpls_count,
Packit b802ec
    struct mpls_label_t *mpls)
Packit b802ec
{
Packit b802ec
    const int ip_icmp_size =
Packit b802ec
        sizeof(struct IPHeader) + sizeof(struct ICMPHeader);
Packit b802ec
    const int ip_udp_size =
Packit b802ec
        sizeof(struct IPHeader) + sizeof(struct UDPHeader);
Packit b802ec
    const int ip_tcp_size =
Packit b802ec
        sizeof(struct IPHeader) + sizeof(struct TCPHeader);
Packit b802ec
    const struct ICMPHeader *icmp;
Packit b802ec
    const struct UDPHeader *udp;
Packit b802ec
    const struct TCPHeader *tcp;
Packit b802ec
    int udp_length;
Packit b802ec
#ifdef IPPROTO_SCTP
Packit b802ec
    const int ip_sctp_size =
Packit b802ec
        sizeof(struct IPHeader) + sizeof(struct SCTPHeader);
Packit b802ec
    const struct SCTPHeader *sctp;
Packit b802ec
#endif
Packit b802ec
Packit b802ec
    if (ip->protocol == IPPROTO_ICMP) {
Packit b802ec
        if (packet_length < ip_icmp_size) {
Packit b802ec
            return;
Packit b802ec
        }
Packit b802ec
Packit b802ec
        icmp = (struct ICMPHeader *) (ip + 1);
Packit b802ec
Packit b802ec
        find_and_receive_probe(net_state, remote_addr, timestamp,
Packit b802ec
                               icmp_result, IPPROTO_ICMP, icmp->id,
Packit b802ec
                               icmp->sequence, mpls_count, mpls);
Packit b802ec
    } else if (ip->protocol == IPPROTO_UDP) {
Packit b802ec
        if (packet_length < ip_udp_size) {
Packit b802ec
            return;
Packit b802ec
        }
Packit b802ec
Packit b802ec
        udp = (struct UDPHeader *) (ip + 1);
Packit b802ec
        udp_length = packet_length - sizeof(struct IPHeader);
Packit b802ec
Packit b802ec
        handle_inner_udp_packet(net_state, remote_addr, icmp_result, udp,
Packit b802ec
                                udp_length, timestamp, mpls_count, mpls);
Packit b802ec
    } else if (ip->protocol == IPPROTO_TCP) {
Packit b802ec
        if (packet_length < ip_tcp_size) {
Packit b802ec
            return;
Packit b802ec
        }
Packit b802ec
Packit b802ec
        tcp = (struct TCPHeader *) (ip + 1);
Packit b802ec
Packit b802ec
        find_and_receive_probe(net_state, remote_addr, timestamp,
Packit b802ec
                               icmp_result, IPPROTO_TCP, 0, tcp->srcport,
Packit b802ec
                               mpls_count, mpls);
Packit b802ec
#ifdef IPPROTO_SCTP
Packit b802ec
    } else if (ip->protocol == IPPROTO_SCTP) {
Packit b802ec
        if (packet_length < ip_sctp_size) {
Packit b802ec
            return;
Packit b802ec
        }
Packit b802ec
Packit b802ec
        sctp = (struct SCTPHeader *) (ip + 1);
Packit b802ec
Packit b802ec
        find_and_receive_probe(net_state, remote_addr, timestamp,
Packit b802ec
                               icmp_result, IPPROTO_SCTP, 0, sctp->srcport,
Packit b802ec
                               mpls_count, mpls);
Packit b802ec
#endif
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
/*
Packit b802ec
    Examine the IPv6 header embedded in a returned ICMPv6 packet
Packit b802ec
    in order to match it with a probe which we previously sent.
Packit b802ec
*/
Packit b802ec
static
Packit b802ec
void handle_inner_ip6_packet(
Packit b802ec
    struct net_state_t *net_state,
Packit b802ec
    const struct sockaddr_storage *remote_addr,
Packit b802ec
    int icmp_result,
Packit b802ec
    const struct IP6Header *ip,
Packit b802ec
    int packet_length,
Packit b802ec
    struct timeval *timestamp,
Packit b802ec
    int mpls_count,
Packit b802ec
    struct mpls_label_t *mpls)
Packit b802ec
{
Packit b802ec
    const int ip_icmp_size =
Packit b802ec
        sizeof(struct IP6Header) + sizeof(struct ICMPHeader);
Packit b802ec
    const int ip_udp_size =
Packit b802ec
        sizeof(struct IP6Header) + sizeof(struct UDPHeader);
Packit b802ec
    const int ip_tcp_size =
Packit b802ec
        sizeof(struct IP6Header) + sizeof(struct TCPHeader);
Packit b802ec
    const struct ICMPHeader *icmp;
Packit b802ec
    const struct UDPHeader *udp;
Packit b802ec
    const struct TCPHeader *tcp;
Packit b802ec
    int udp_length;
Packit b802ec
#ifdef IPPROTO_SCTP
Packit b802ec
    const int ip_sctp_size =
Packit b802ec
        sizeof(struct IPHeader) + sizeof(struct SCTPHeader);
Packit b802ec
    const struct SCTPHeader *sctp;
Packit b802ec
#endif
Packit b802ec
Packit b802ec
    if (ip->protocol == IPPROTO_ICMPV6) {
Packit b802ec
        if (packet_length < ip_icmp_size) {
Packit b802ec
            return;
Packit b802ec
        }
Packit b802ec
Packit b802ec
        icmp = (struct ICMPHeader *) (ip + 1);
Packit b802ec
Packit b802ec
        find_and_receive_probe(net_state, remote_addr, timestamp,
Packit b802ec
                               icmp_result, IPPROTO_ICMP, icmp->id,
Packit b802ec
                               icmp->sequence, mpls_count, mpls);
Packit b802ec
    } else if (ip->protocol == IPPROTO_UDP) {
Packit b802ec
        if (packet_length < ip_udp_size) {
Packit b802ec
            return;
Packit b802ec
        }
Packit b802ec
Packit b802ec
        udp = (struct UDPHeader *) (ip + 1);
Packit b802ec
        udp_length = packet_length - sizeof(struct IP6Header);
Packit b802ec
Packit b802ec
        handle_inner_udp_packet(net_state, remote_addr, icmp_result, udp,
Packit b802ec
                                udp_length, timestamp, mpls_count, mpls);
Packit b802ec
    } else if (ip->protocol == IPPROTO_TCP) {
Packit b802ec
        if (packet_length < ip_tcp_size) {
Packit b802ec
            return;
Packit b802ec
        }
Packit b802ec
Packit b802ec
        tcp = (struct TCPHeader *) (ip + 1);
Packit b802ec
        find_and_receive_probe(net_state, remote_addr, timestamp,
Packit b802ec
                               icmp_result, IPPROTO_TCP, 0, tcp->srcport,
Packit b802ec
                               mpls_count, mpls);
Packit b802ec
#ifdef IPPROTO_SCTP
Packit b802ec
    } else if (ip->protocol == IPPROTO_SCTP) {
Packit b802ec
        if (packet_length < ip_sctp_size) {
Packit b802ec
            return;
Packit b802ec
        }
Packit b802ec
Packit b802ec
        sctp = (struct SCTPHeader *) (ip + 1);
Packit b802ec
Packit b802ec
        find_and_receive_probe(net_state, remote_addr, timestamp,
Packit b802ec
                               icmp_result, IPPROTO_SCTP, 0, sctp->srcport,
Packit b802ec
                               mpls_count, mpls);
Packit b802ec
#endif
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
/*  Convert an ICMP MPLS extension object into an mpls_label_t structure  */
Packit b802ec
static
Packit b802ec
int decode_mpls_object(
Packit b802ec
    struct ICMPExtensionObject *icmp_obj,
Packit b802ec
    int obj_len,
Packit b802ec
    struct mpls_label_t *mpls,
Packit b802ec
    int mpls_count)
Packit b802ec
{
Packit b802ec
    int label_bytes;
Packit b802ec
    int labels_present;
Packit b802ec
    int i;
Packit b802ec
    struct ICMPExtMPLSLabel *ext_mpls;
Packit b802ec
    struct ICMPExtMPLSLabel *ext_label;
Packit b802ec
    struct mpls_label_t *label;
Packit b802ec
Packit b802ec
    label_bytes = obj_len - sizeof(struct ICMPExtensionObject);
Packit b802ec
    labels_present = label_bytes / sizeof(struct ICMPExtMPLSLabel);
Packit b802ec
Packit b802ec
    ext_mpls = (struct ICMPExtMPLSLabel *) (icmp_obj + 1);
Packit b802ec
    for (i = 0; i < mpls_count && i < labels_present; i++) {
Packit b802ec
        ext_label = &ext_mpls[i];
Packit b802ec
        label = &mpls[i];
Packit b802ec
Packit b802ec
        memset(label, 0, sizeof(struct mpls_label_t));
Packit b802ec
Packit b802ec
        label->label =
Packit b802ec
            ext_label->label[0] << 12 |
Packit b802ec
            ext_label->label[1] << 4 | ext_label->label[2] >> 4;
Packit b802ec
        label->experimental_use = (ext_label->label[2] & 0x0E) >> 1;
Packit b802ec
        label->bottom_of_stack = ext_label->label[2] & 0x01;
Packit b802ec
        label->ttl = ext_label->ttl;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    return i;
Packit b802ec
}
Packit b802ec
Packit b802ec
/*  Extract MPLS labels from the ICMP extension header, if present  */
Packit b802ec
static
Packit b802ec
int decode_mpls_labels(
Packit b802ec
    const struct ICMPHeader *icmp,
Packit b802ec
    int packet_length,
Packit b802ec
    struct mpls_label_t *mpls,
Packit b802ec
    int mpls_count)
Packit b802ec
{
Packit b802ec
    const int icmp_orig_icmp_ext_size =
Packit b802ec
        sizeof(struct ICMPHeader) + ICMP_ORIGINAL_DATAGRAM_MIN_SIZE +
Packit b802ec
        sizeof(struct ICMPExtensionHeader);
Packit b802ec
    char *inner_packet;
Packit b802ec
    char *icmp_object_bytes;
Packit b802ec
    struct ICMPExtensionHeader *icmp_ext;
Packit b802ec
    struct ICMPExtensionObject *icmp_obj;
Packit b802ec
    int remaining_size;
Packit b802ec
    int obj_len;
Packit b802ec
Packit b802ec
    if (packet_length < icmp_orig_icmp_ext_size) {
Packit b802ec
        return 0;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    inner_packet = (char *) (icmp + 1);
Packit b802ec
    icmp_ext = (struct ICMPExtensionHeader *)
Packit b802ec
        (inner_packet + ICMP_ORIGINAL_DATAGRAM_MIN_SIZE);
Packit b802ec
Packit b802ec
    if ((icmp_ext->version & 0xF0) != 0x20) {
Packit b802ec
        return 0;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    remaining_size = packet_length - icmp_orig_icmp_ext_size;
Packit b802ec
    icmp_object_bytes = (char *) (icmp_ext + 1);
Packit b802ec
Packit b802ec
    /*
Packit b802ec
       Iterate through the chain of extension objects, looking for
Packit b802ec
       an MPLS label extension.
Packit b802ec
     */
Packit b802ec
    while (remaining_size >= sizeof(struct ICMPExtensionObject)) {
Packit b802ec
        icmp_obj = (struct ICMPExtensionObject *) icmp_object_bytes;
Packit b802ec
        obj_len = ntohs(icmp_obj->len);
Packit b802ec
Packit b802ec
        if (obj_len > remaining_size) {
Packit b802ec
            return 0;
Packit b802ec
        }
Packit b802ec
        if (obj_len < sizeof(struct ICMPExtensionObject)) {
Packit b802ec
            return 0;
Packit b802ec
        }
Packit b802ec
Packit b802ec
        if (icmp_obj->classnum == ICMP_EXT_MPLS_CLASSNUM &&
Packit b802ec
            icmp_obj->ctype == ICMP_EXT_MPLS_CTYPE) {
Packit b802ec
Packit b802ec
            return decode_mpls_object(icmp_obj, obj_len, mpls, mpls_count);
Packit b802ec
        }
Packit b802ec
Packit b802ec
        remaining_size -= obj_len;
Packit b802ec
        icmp_object_bytes += obj_len;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    return 0;
Packit b802ec
}
Packit b802ec
Packit b802ec
/*
Packit b802ec
    Decode the ICMP header received and try to find a probe which it
Packit b802ec
    is in response to.
Packit b802ec
*/
Packit b802ec
static
Packit b802ec
void handle_received_icmp4_packet(
Packit b802ec
    struct net_state_t *net_state,
Packit b802ec
    const struct sockaddr_storage *remote_addr,
Packit b802ec
    const struct ICMPHeader *icmp,
Packit b802ec
    int packet_length,
Packit b802ec
    struct timeval *timestamp)
Packit b802ec
{
Packit b802ec
    const int icmp_ip_size =
Packit b802ec
        sizeof(struct ICMPHeader) + sizeof(struct IPHeader);
Packit b802ec
    const struct IPHeader *inner_ip;
Packit b802ec
    int inner_size = packet_length - sizeof(struct ICMPHeader);
Packit b802ec
    int mpls_count;
Packit b802ec
    struct mpls_label_t mpls[MAX_MPLS_LABELS];
Packit b802ec
Packit b802ec
    mpls_count =
Packit b802ec
        decode_mpls_labels(icmp, packet_length, mpls, MAX_MPLS_LABELS);
Packit b802ec
Packit b802ec
    /*  If we get an echo reply, our probe reached the destination host  */
Packit b802ec
    if (icmp->type == ICMP_ECHOREPLY) {
Packit b802ec
        find_and_receive_probe(net_state, remote_addr, timestamp,
Packit b802ec
                               ICMP_ECHOREPLY, IPPROTO_ICMP, icmp->id,
Packit b802ec
                               icmp->sequence, mpls_count, mpls);
Packit b802ec
    }
Packit b802ec
Packit b802ec
    if (packet_length < icmp_ip_size) {
Packit b802ec
        return;
Packit b802ec
    }
Packit b802ec
    inner_ip = (struct IPHeader *) (icmp + 1);
Packit b802ec
Packit b802ec
    /*
Packit b802ec
       If we get a time exceeded, we got a response from an intermediate
Packit b802ec
       host along the path to our destination.
Packit b802ec
     */
Packit b802ec
    if (icmp->type == ICMP_TIME_EXCEEDED) {
Packit b802ec
        /*
Packit b802ec
           The IP packet inside the ICMP response contains our original
Packit b802ec
           IP header.  That's where we can get our original ID and
Packit b802ec
           sequence number.
Packit b802ec
         */
Packit b802ec
        handle_inner_ip4_packet(net_state, remote_addr,
Packit b802ec
                                ICMP_TIME_EXCEEDED, inner_ip, inner_size,
Packit b802ec
                                timestamp, mpls_count, mpls);
Packit b802ec
    }
Packit b802ec
Packit b802ec
    if (icmp->type == ICMP_DEST_UNREACH) {
Packit b802ec
        /*
Packit b802ec
           We'll get a ICMP_PORT_UNREACH when a non-ICMP probe
Packit b802ec
           reaches its final destination.  (Assuming that port isn't
Packit b802ec
           open on the destination host.)
Packit b802ec
         */
Packit b802ec
        if (icmp->code == ICMP_PORT_UNREACH) {
Packit b802ec
            handle_inner_ip4_packet(net_state, remote_addr,
Packit b802ec
                                    ICMP_ECHOREPLY, inner_ip, inner_size,
Packit b802ec
                                    timestamp, mpls_count, mpls);
Packit b802ec
        }
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
/*
Packit b802ec
    Decode the ICMPv6 header.  The code duplication with ICMPv4 is
Packit b802ec
    unfortunate, but small details in structure size and ICMP
Packit b802ec
    constants differ.
Packit b802ec
*/
Packit b802ec
static
Packit b802ec
void handle_received_icmp6_packet(
Packit b802ec
    struct net_state_t *net_state,
Packit b802ec
    const struct sockaddr_storage *remote_addr,
Packit b802ec
    const struct ICMPHeader *icmp,
Packit b802ec
    int packet_length,
Packit b802ec
    struct timeval *timestamp)
Packit b802ec
{
Packit b802ec
    const int icmp_ip_size =
Packit b802ec
        sizeof(struct ICMPHeader) + sizeof(struct IP6Header);
Packit b802ec
    const struct IP6Header *inner_ip;
Packit b802ec
    int inner_size = packet_length - sizeof(struct ICMPHeader);
Packit b802ec
    int mpls_count;
Packit b802ec
    struct mpls_label_t mpls[MAX_MPLS_LABELS];
Packit b802ec
Packit b802ec
    mpls_count =
Packit b802ec
        decode_mpls_labels(icmp, packet_length, mpls, MAX_MPLS_LABELS);
Packit b802ec
Packit b802ec
    if (icmp->type == ICMP6_ECHOREPLY) {
Packit b802ec
        find_and_receive_probe(net_state, remote_addr, timestamp,
Packit b802ec
                               ICMP_ECHOREPLY, IPPROTO_ICMP, icmp->id,
Packit b802ec
                               icmp->sequence, mpls_count, mpls);
Packit b802ec
    }
Packit b802ec
Packit b802ec
    if (packet_length < icmp_ip_size) {
Packit b802ec
        return;
Packit b802ec
    }
Packit b802ec
    inner_ip = (struct IP6Header *) (icmp + 1);
Packit b802ec
Packit b802ec
    if (icmp->type == ICMP6_TIME_EXCEEDED) {
Packit b802ec
        handle_inner_ip6_packet(net_state, remote_addr,
Packit b802ec
                                ICMP_TIME_EXCEEDED, inner_ip, inner_size,
Packit b802ec
                                timestamp, mpls_count, mpls);
Packit b802ec
    }
Packit b802ec
Packit b802ec
    if (icmp->type == ICMP6_DEST_UNREACH) {
Packit b802ec
        if (icmp->code == ICMP6_PORT_UNREACH) {
Packit b802ec
            handle_inner_ip6_packet(net_state, remote_addr,
Packit b802ec
                                    ICMP_ECHOREPLY, inner_ip, inner_size,
Packit b802ec
                                    timestamp, mpls_count, mpls);
Packit b802ec
        }
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
/*
Packit b802ec
    We've received a new IPv4 ICMP packet.
Packit b802ec
    We'll check to see that it is a response to one of our probes, and
Packit b802ec
    if so, report the result of the probe to our command stream.
Packit b802ec
*/
Packit b802ec
void handle_received_ip4_packet(
Packit b802ec
    struct net_state_t *net_state,
Packit b802ec
    const struct sockaddr_storage *remote_addr,
Packit b802ec
    const void *packet,
Packit b802ec
    int packet_length,
Packit b802ec
    struct timeval *timestamp)
Packit b802ec
{
Packit b802ec
    const int ip_icmp_size =
Packit b802ec
        sizeof(struct IPHeader) + sizeof(struct ICMPHeader);
Packit b802ec
    const struct IPHeader *ip;
Packit b802ec
    const struct ICMPHeader *icmp;
Packit b802ec
    int icmp_length;
Packit b802ec
Packit b802ec
    /*  Ensure that we don't access memory beyond the bounds of the packet  */
Packit b802ec
    if (packet_length < ip_icmp_size) {
Packit b802ec
        return;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    ip = (struct IPHeader *) packet;
Packit b802ec
    if (ip->protocol != IPPROTO_ICMP) {
Packit b802ec
        return;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    icmp = (struct ICMPHeader *) (ip + 1);
Packit b802ec
    icmp_length = packet_length - sizeof(struct IPHeader);
Packit b802ec
Packit b802ec
    handle_received_icmp4_packet(net_state, remote_addr, icmp, icmp_length,
Packit b802ec
                                 timestamp);
Packit b802ec
}
Packit b802ec
Packit b802ec
/*
Packit b802ec
    Unlike ICMPv6 raw sockets, unlike ICMPv4, don't include the IP header
Packit b802ec
    in received packets, so we can assume the packet we got starts
Packit b802ec
    with the ICMP packet.
Packit b802ec
*/
Packit b802ec
void handle_received_ip6_packet(
Packit b802ec
    struct net_state_t *net_state,
Packit b802ec
    const struct sockaddr_storage *remote_addr,
Packit b802ec
    const void *packet,
Packit b802ec
    int packet_length,
Packit b802ec
    struct timeval *timestamp)
Packit b802ec
{
Packit b802ec
    const struct ICMPHeader *icmp;
Packit b802ec
Packit b802ec
    icmp = (struct ICMPHeader *) packet;
Packit b802ec
Packit b802ec
    handle_received_icmp6_packet(net_state, remote_addr, icmp,
Packit b802ec
                                 packet_length, timestamp);
Packit b802ec
}