ICMPv4 (RFC 792) packet encoding and decoding.

An ICMP message is a 4-byte fixed header (type, code, checksum) followed by a variable-length payload. The 4 bytes that RFC 792 calls the "rest of header" are part of the payload here — their meaning is type-specific (e.g. identifier/sequence for Echo, unused/nextHopMtu for Destination Unreachable), and callers can frame them however they need.

 0      7 8     15 16    23 24    31
+--------+--------+--------+--------+
|  Type  |  Code  |    Checksum     |
+--------+--------+--------+--------+
|        Payload (variable)         |
+-----------------------------------+

Per the binstruct philosophy, encoding does not auto-compute the checksum. Use internetChecksum from @binstruct/inet after encoding (with the checksum field zeroed) to fill it in.

Examples

Round-trip an Echo Request via the generic coder

import { assertEquals } from "@std/assert";
import { ICMP_TYPE, icmpPacket } from "@binstruct/icmp";

const coder = icmpPacket();
// The first 4 bytes of payload are the Echo-specific identifier/sequence,
// followed by the echo data.
const payload = new Uint8Array([0xbe, 0xef, 0x00, 0x2a, ...new TextEncoder().encode("ping")]);
const request = {
  type: ICMP_TYPE.ECHO_REQUEST,
  code: 0,
  checksum: 0,
  payload,
};

const buffer = new Uint8Array(4 + payload.length);
const written = coder.encode(request, buffer);
const [decoded] = coder.decode(buffer.subarray(0, written));

assertEquals(decoded.type, ICMP_TYPE.ECHO_REQUEST);
assertEquals(decoded.payload, payload);