layers_IPv6.js

const { OsiModelLayers } = require('./osi');
const { IPProtocolTypes } = require('./enums');
const { inetPton, inetNtop } = require('#lib/converters');
const { AF_INET6 } = require('#lib/socket');
const { makeLayer, attach, byField } = require('./define');

/**
 * IPv6 protocol layer
 * @class
 * @implements {Layer}
 * @property {number} version - IP version, has the value of 6 for IPv6.
 * @property {number} trafficClass - Traffic class (DSCP + ECN), 8 bits.
 * @property {number} flowLabel - Flow label, 20 bits.
 * @property {number} payloadLength - Length of payload following the header in bytes.
 * @property {number} nextHeader - Next header type. Must be one of ::IPProtocolTypes.
 * @property {number} hopLimit - Hop limit, decremented by each forwarder.
 * @property {string} src - IPv6 source address in human-readable form.
 * @property {string} dst - IPv6 destination address in human-readable form.
 */
const IPv6 = (() => {
  const { Layer, proto } = makeLayer('IPv6', `
    //@NE
    struct IPv6Header {
      uint32_t flowLabel:20, trafficClass:8, version:4;
      uint16_t payloadLength;
      uint8_t nextHeader;
      uint8_t hopLimit;
      uint8_t src[16];
      uint8_t dst[16];
    } __attribute__(packed);
  `, {
    osi: OsiModelLayers.Network,
  });

  attach.virtualField(proto, 'src', {
    get() { return inetNtop(AF_INET6, this._buf.subarray(8, 24)); },
    set(v) { inetPton(AF_INET6, v).copy(this._buf, 8); },
  });
  attach.virtualField(proto, 'dst', {
    get() { return inetNtop(AF_INET6, this._buf.subarray(24, 40)); },
    set(v) { inetPton(AF_INET6, v).copy(this._buf, 24); },
  });
  attach.toObjectExtras(proto, ['src', 'dst']);

  const dispatcher = byField('nextHeader', {
    [IPProtocolTypes.UDP]: 'UDP',
    [IPProtocolTypes.TCP]: 'TCP',
    [IPProtocolTypes.ICMP]: 'ICMP',
    [IPProtocolTypes.ICMPV6]: 'ICMPv6',
    [IPProtocolTypes.GRE]: 'GRE',
    [IPProtocolTypes.IGMP]: 'IGMP',
    [IPProtocolTypes.AH]: 'AuthenticationHeader',
    [IPProtocolTypes.ESP]: 'ESP',
    [IPProtocolTypes.IPV6]: 'IPv6',
    [IPProtocolTypes.VRRP]: 'VRRP',
  });
  attach.dispatch(proto, dispatcher);
  attach.defaults(proto, {
    version: 6,
    hopLimit: 64,
    trafficClass: 0,
    flowLabel: 0,
    payloadLength: ($) => $.next?.length ?? 0,
    nextHeader: dispatcher.reverseDefault(IPProtocolTypes.RAW),
  });

  return Layer;
})();

module.exports = { IPv6 };