ICMP6(4)

πŸ’– icmp6 β€” Internet Control Message Protocol for IPv6 πŸ’–

okay bestie, so this is the icmp6(4) page from section 4 of the Kernel Interfaces Manual, and it's literally the whole vibe guide to ICMPv6 β€” the error-and-control-message protocol for IPv6. no cap, it's giving "networking's group chat for complaints and announcements" energy. let's get into it 🫢


✨ SYNOPSIS ✨

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/icmp6.h>

int
socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);

🌸 DESCRIPTION 🌸

ICMPv6 is the error and control message protocol used by IPv6 and the whole IPv6 protocol family (peep ip6(4) and inet6(4) for the lore). you can slide into it through a "raw socket" if you're doing network monitoring and diagnostic functions. it's the main character of diagnostics, periodt. πŸ‘‘

the proto parameter you pass to the socket(2) call to create an ICMPv6 socket? you can get it from getprotobyname(3). ICMPv6 sockets are connectionless, and they're normally used with sendto(2) and recvfrom(2) calls β€” though the connect(2) call can also be used to lock in the destination for future packets. and if you do that? then read(2) or recv(2), plus write(2) or send(2) system calls, are totally allowed too. choose your own adventure bestie ✨

outgoing packets automatically get an IPv6 header prepended to them (based on the destination address). incoming packets on the socket arrive with the IPv6 header and any extension headers already removed. so clean, so efficient, we love her πŸ’…

πŸ¦‹ Types πŸ¦‹

ICMPv6 messages get sorted by the type and code fields hanging out in the ICMPv6 header. the abbreviations for the types and codes can be used in rules in pf.conf(5) β€” iykyk. here are the types that are defined:

  • 1 β€” unreach β€” Destination unreachable
  • 2 β€” toobig β€” Packet too big
  • 3 β€” timex β€” Time exceeded
  • 4 β€” paramprob β€” Invalid IPv6 header
  • 128 β€” echoreq β€” Echo service request
  • 129 β€” echorep β€” Echo service reply
  • 130 β€” groupqry β€” Group membership query
  • 130 β€” listqry β€” Multicast listener query
  • 131 β€” grouprep β€” Group membership report
  • 131 β€” listenrep β€” Multicast listener report
  • 132 β€” groupterm β€” Group membership termination
  • 132 β€” listendone β€” Multicast listener done
  • 133 β€” routersol β€” Router solicitation
  • 134 β€” routeradv β€” Router advertisement
  • 135 β€” neighbrsol β€” Neighbor solicitation
  • 136 β€” neighbradv β€” Neighbor advertisement
  • 137 β€” redir β€” Shorter route exists
  • 138 β€” routrrenum β€” Route renumbering
  • 139 β€” fqdnreq β€” FQDN query
  • 139 β€” niqry β€” Node information query
  • 139 β€” wrureq β€” Who-are-you request
  • 140 β€” fqdnrep β€” FQDN reply
  • 140 β€” nirep β€” Node information reply
  • 140 β€” wrurep β€” Who-are-you reply
  • 200 β€” mtraceresp β€” mtrace response
  • 201 β€” mtrace β€” mtrace messages

and here are the codes that are defined (with their type, obvi):

  • 0 β€” noroute-unr β€” type unreach β€” No route to destination
  • 1 β€” admin-unr β€” type unreach β€” Administratively prohibited
  • 2 β€” beyond-unr β€” type unreach β€” Beyond scope of source address
  • 2 β€” notnbr-unr β€” type unreach β€” Not a neighbor (obsolete)
  • 3 β€” addr-unr β€” type unreach β€” Address unreachable
  • 4 β€” port-unr β€” type unreach β€” Port unreachable
  • 0 β€” transit β€” type timex β€” Time exceeded in transit
  • 1 β€” reassemb β€” type timex β€” Time exceeded in reassembly
  • 0 β€” badhead β€” type paramprob β€” Erroneous header field
  • 1 β€” nxthdr β€” type paramprob β€” Unrecognized next header
  • 2 β€” (no abbrev, she's mysterious) β€” type redir β€” Unrecognized option
  • 0 β€” redironlink β€” type redir β€” Redirection to on-link node
  • 1 β€” redirrouter β€” type redir β€” Redirection to better router

πŸŽ€ Headers πŸŽ€

all ICMPv6 messages get prefixed with an ICMPv6 header. this header matches the icmp6_hdr structure and it looks exactly like this, bestie:

struct icmp6_hdr {
        uint8_t  icmp6_type;    /* type field */
        uint8_t  icmp6_code;    /* code field */
        uint16_t icmp6_cksum;   /* checksum field */
        union {
                uint32_t icmp6_un_data32[1]; /* type-specific */
                uint16_t icmp6_un_data16[2]; /* type-specific */
                uint8_t  icmp6_un_data8[4];  /* type-specific */
        } icmp6_dataun;
} __packed;

#define icmp6_data32    icmp6_dataun.icmp6_un_data32
#define icmp6_data16    icmp6_dataun.icmp6_un_data16
#define icmp6_data8     icmp6_dataun.icmp6_un_data8
#define icmp6_pptr      icmp6_data32[0] /* parameter prob */
#define icmp6_mtu       icmp6_data32[0] /* packet too big */
#define icmp6_id        icmp6_data16[0] /* echo request/reply */
#define icmp6_seq       icmp6_data16[1] /* echo request/reply */
#define icmp6_maxdelay  icmp6_data16[0] /* mcast group membership*/

so icmp6_type describes the type of the message, and the suitable values are defined in ⟨netinet/icmp6.h⟩. icmp6_code describes the sub-type of the message and it depends on icmp6_type (they're a package deal, fr). icmp6_cksum holds the checksum for the message and it gets filled in by the kernel on outgoing messages β€” the kernel does that for you, no need to stress πŸ’–. the other fields are used for type-specific purposes.

🌈 Filters 🌈

because ICMPv6 has so much extra functionality compared to ICMPv4, a larger number of messages may potentially be received on an ICMPv6 socket. so input filters are the move β€” they restrict input to a subset of the incoming ICMPv6 messages so that only the interesting ones get returned by the recv(2) family of calls to an application. vibe check: only the messages you asked for make it through.

the icmp6_filter structure can be used to refine the input message set according to the ICMPv6 type. by default, all message types are allowed on newly created raw ICMPv6 sockets. these macros are available to refine the input set:

  • void ICMP6_FILTER_SETPASSALL(struct icmp6_filter *filterp) β€” allow all incoming messages. filterp is modified to allow all message types.
  • void ICMP6_FILTER_SETBLOCKALL(struct icmp6_filter *filterp) β€” ignore all incoming messages. filterp is modified to ignore all message types.
  • void ICMP6_FILTER_SETPASS(int type, struct icmp6_filter *filterp) β€” allow ICMPv6 messages with the given type. filterp is modified to allow such messages.
  • void ICMP6_FILTER_SETBLOCK(int type, struct icmp6_filter *filterp) β€” ignore ICMPv6 messages with the given type. filterp is modified to ignore such messages.
  • int ICMP6_FILTER_WILLPASS(int type, const struct icmp6_filter *filterp) β€” determine if the given filter will allow an ICMPv6 message of the given type.
  • int ICMP6_FILTER_WILLBLOCK(int type, const struct icmp6_filter *filterp) β€” determine if the given filter will ignore an ICMPv6 message of the given type.

the getsockopt(2) and setsockopt(2) calls may be used to obtain and install the filter on ICMPv6 sockets β€” at option level IPPROTO_ICMPV6 and name ICMP6_FILTER, with a pointer to the icmp6_filter structure as the option value. that's the whole recipe, slay. ✨


πŸ‘‘ SEE ALSO πŸ‘‘

W. Stevens and M. Thomas, Advanced Sockets API for IPv6, RFC 2292, February 1998.

A. Conta and S. Deering, Internet Control Message Protocol (ICMPv6) for the Internet Protocol Version 6 (IPv6) Specification, RFC 2463, December 1998.


okay that's the whole page bestie, you ate it πŸ’… this one came from Debian, dated November 7, 2012, and it lives in the manual as ICMP6(4). go forth and diagnose, you iconic network gremlin πŸ¦‹πŸ’–

πŸ“¦ where this page comes from