/**************************************************************************** ** File: icmpv6.c ** ** Author: Mike Borella ** ** Comments: Dump ICMPv6 information ** ** $Id: icmpv6.c,v 1.13 2002/01/03 00:04:01 mborella Exp $ ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU Library General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ** *****************************************************************************/ #include "ipv6.h" #include "icmpv6.h" #define HOLDER_SIZE 64 /* * ICMPv6 type map */ strmap_t icmpv6_type_map [] = { { ICMPV6_TYPE_DESTUNREACHABLE, "destination unreachable" }, { ICMPV6_TYPE_PACKETTOOBIG, "packet too big" }, { ICMPV6_TYPE_TIMEEXCEEDED, "time exceeded" }, { ICMPV6_TYPE_PARAMETERPROBLEM, "parameter problem" }, { ICMPV6_TYPE_ECHOREQUEST, "echo request" }, { ICMPV6_TYPE_ECHOREPLY, "echo reply" }, { ICMPV6_TYPE_GROUPMEMQUERY, "group membership query" }, { ICMPV6_TYPE_GROUPMEMREPORT, "group membership report" }, { ICMPV6_TYPE_GROUPMEMREDUCTION, "group membership reduction" }, { ICMPV6_TYPE_ROUTERSOLICIT, "router solicitation" }, { ICMPV6_TYPE_ROUTERADVERT, "router advertisement" }, { ICMPV6_TYPE_NEIGHBORSOLICIT, "neighbor solicitation" }, { ICMPV6_TYPE_NEIGHBORADVERT, "neighbor advertisement" }, { ICMPV6_TYPE_REDIRECT, "redirect" }, { 0, "" } }; /* * ICMPv6 destination unreachable code map */ strmap_t icmpv6_ducode_map [] = { { ICMPV6_DUCODE_NOROUTE, "no route" }, { ICMPV6_DUCODE_ADMIN, "administratively prohibited" }, { ICMPV6_DUCODE_ADDRUNREACHABLE, "address unreachable" }, { ICMPV6_DUCODE_PORTUNREACHABLE, "port unreachable" }, { 0, "" } }; extern struct arg_t *my_args; /*---------------------------------------------------------------------------- ** ** dump_icmpv6() ** ** Parse ICMPv6 header and dump fields ** **---------------------------------------------------------------------------- */ void dump_icmpv6(packet_t *pkt) { icmpv6_header_t icmpv6; char holder[HOLDER_SIZE]; u_int32_t parameter; u_int16_t ping6_id, ping6_seqno; u_int8_t v6addr[16]; /* Set the layer */ set_layer(LAYER_NETWORK); /* * Stats accounting */ stats_update(STATS_ICMPV6); /* * Get the ICMPv6 header */ if (get_packet_bytes((u_int8_t *) &icmpv6, pkt, 4) == 0) return; /* * Conversions */ icmpv6.checksum = ntohs(icmpv6.checksum); /* * Dump header */ if (my_args->m) { display_minimal_string("| ICMPv6 "); display_minimal_string(map2str(icmpv6_type_map, icmpv6.type)); display_minimal_string(" "); } else { /* announcement */ display_header_banner("ICMPv6 Header"); /* print type */ snprintf(holder, HOLDER_SIZE, "%d (%s)", icmpv6.type, map2str(icmpv6_type_map, icmpv6.type)); display_string("Type", holder); /* based on the type, decide what to do with the code */ switch(icmpv6.type) { case ICMPV6_TYPE_DESTUNREACHABLE: snprintf(holder, HOLDER_SIZE, "%d (%s)", icmpv6.code, map2str(icmpv6_ducode_map, icmpv6.code)); display_string("Code", holder); break; default: display("Code", (u_int8_t *) &icmpv6.code, 1, DISP_DEC); } display("Checksum", (u_int8_t *) &icmpv6.checksum, 2, DISP_DEC); } /* * Special processing of the rest of the ICMP part */ switch(icmpv6.type) { case ICMPV6_TYPE_DESTUNREACHABLE: case ICMPV6_TYPE_TIMEEXCEEDED: /* skip unused 4 bytes */ if (skip_packet_bytes(pkt, 4) == 0) return; /* dump the contained IPv6 header */ if (get_packet_apparentbytesleft(pkt)) dump_ipv6(pkt); break; case ICMPV6_TYPE_PACKETTOOBIG: /* next 4 bytes should be the mtu, get them, convert, display */ if (get_packet_bytes((u_int8_t *) ¶meter, pkt, 4) == 0) return; parameter = ntohl(parameter); display("MTU", (u_int8_t *) ¶meter, 4, DISP_DEC); /* dump the contained IPv6 header */ if (get_packet_apparentbytesleft(pkt)) dump_ipv6(pkt); break; case ICMPV6_TYPE_PARAMETERPROBLEM: /* next 4 bytes should be a pointer, get them, convert, display */ if (get_packet_bytes((u_int8_t *) ¶meter, pkt, 4) == 0) return; parameter = ntohl(parameter); display("Pointer", (u_int8_t *) ¶meter, 4, DISP_DEC); /* dump the contained IPv6 header */ if (get_packet_apparentbytesleft(pkt)) dump_ipv6(pkt); break; case ICMPV6_TYPE_ECHOREQUEST: case ICMPV6_TYPE_ECHOREPLY: /* Next 4 bytes are an id followed by a seqno: get, convert, display */ if (get_packet_bytes((u_int8_t *) &ping6_id, pkt, 2) == 0) return; if (get_packet_bytes((u_int8_t *) &ping6_seqno, pkt, 2) == 0) return; ping6_id = ntohs(ping6_id); ping6_seqno = ntohs(ping6_seqno); if (my_args->m) { display_minimal((u_int8_t *) &ping6_seqno, 2, DISP_DEC); } else { display("Identifier", (u_int8_t *) &ping6_id, 2, DISP_DEC); display("Sequence number", (u_int8_t *) &ping6_seqno, 2, DISP_DEC); } break; case ICMPV6_TYPE_NEIGHBORSOLICIT: /* Next 16 bytes are an IPv6 address */ if (get_packet_bytes((u_int8_t *) &v6addr, pkt, 16) == 0) return; if (my_args->m) { display_minimal_ipv6((u_int8_t *) &v6addr); display_minimal_string(" "); } else display_ipv6("Address", (u_int8_t *) &v6addr); break; default: break; } }