@juit/lib-ping
Version:
ICMPv4/ICMPv6 Ping library for NodeJS
102 lines (101 loc) • 3.93 kB
JavaScript
// protocol.ts
import { randomBytes } from "node:crypto";
var ERR_WRONG_LENGTH = -1n;
var ERR_WRONG_CORRELATION = -2n;
var ERR_WRONG_ICMP_TYPE = -3n;
var ERR_WRONG_ICMP_CODE = -4n;
var ERR_WRONG_SEQUENCE = -5n;
var ERR_SEQUENCE_TOO_BIG = -6n;
var ERR_SEQUENCE_TOO_SMALL = -7n;
var ERR_LATENCY_NEGATIVE = -8n;
function getWarning(num) {
if (num >= 0) return { code: "OK", message: `Latency is ${Number(num) / 1e6} ms` };
switch (num) {
case ERR_WRONG_LENGTH:
return { code: "ERR_WRONG_LENGTH", message: "Received packet with invalid length" };
case ERR_WRONG_CORRELATION:
return { code: "ERR_WRONG_CORRELATION", message: "Received packet with invalid correlation data" };
case ERR_WRONG_ICMP_TYPE:
return { code: "ERR_WRONG_ICMP_TYPE", message: "Received packet with invalid ICMP type" };
case ERR_WRONG_ICMP_CODE:
return { code: "ERR_WRONG_ICMP_CODE", message: "Received packet with invalid ICMP code" };
case ERR_WRONG_SEQUENCE:
return { code: "ERR_WRONG_SEQUENCE", message: "Received packet with mismatched sequence in header/payload" };
case ERR_SEQUENCE_TOO_BIG:
return { code: "ERR_SEQUENCE_TOO_BIG", message: "Received packet with sequence in the future" };
case ERR_SEQUENCE_TOO_SMALL:
return { code: "ERR_SEQUENCE_TOO_SMALL", message: "Received packet with sequence in the past (duplicate packet?)" };
case ERR_LATENCY_NEGATIVE:
return { code: "ERR_LATENCY_NEGATIVE", message: "Received packet with negative latence (time travel is possible!)" };
default:
return { code: "ERR_UNKNOWN", message: `Unknown error code (code=${num})` };
}
}
var ProtocolHandler = class {
__packet = randomBytes(64);
__type;
__seq_out = 0;
__seq_in = 0;
constructor(v6) {
this.__type = v6 ? 129 : 0;
this.__packet.writeUInt32BE(v6 ? 2147483648 : 134217728, 0);
this.__packet.writeUInt16BE(process.pid % 65535, 4);
this.__packet.writeUInt16BE(this.__seq_out, 6);
this.__packet.writeBigUInt64BE(0n, 8);
}
outgoing() {
const buffer = Buffer.from(this.__packet);
buffer.writeUInt32BE(++this.__seq_out, 16);
buffer.writeUInt16BE(this.__seq_out & 255, 6);
buffer.writeBigUInt64BE(process.hrtime.bigint(), 8);
buffer.writeUInt16BE(rfc1071crc(buffer), 2);
return buffer;
}
incoming(buffer, now = process.hrtime.bigint()) {
if (buffer.length > 64) {
const first = buffer.readUInt8(0);
const version = first >> 4;
if (version === 6) {
if (buffer.length === 104) buffer = buffer.subarray(40);
} else if (version === 4) {
const length = (first & 15) * 4;
if (buffer.length === length + 64) buffer = buffer.subarray(length);
}
}
if (buffer.length !== 64) return ERR_WRONG_LENGTH;
if (buffer.compare(this.__packet, 20, 64, 20, 64) !== 0) return ERR_WRONG_CORRELATION;
const type = buffer.readUInt8(0);
if (type !== this.__type) return ERR_WRONG_ICMP_TYPE;
const code = buffer.readUInt8(1);
if (code !== 0) return ERR_WRONG_ICMP_CODE;
const sequence = buffer.readUInt32BE(16);
if ((buffer.readUInt16BE(6) & 255) != (sequence & 255)) return ERR_WRONG_SEQUENCE;
if (sequence > this.__seq_out) return ERR_SEQUENCE_TOO_BIG;
if (sequence <= this.__seq_in) return ERR_SEQUENCE_TOO_SMALL;
const latency = now - buffer.readBigInt64BE(8);
if (latency < 0n) return ERR_LATENCY_NEGATIVE;
this.__seq_in = sequence;
return latency;
}
};
function rfc1071crc(buffer) {
let sum = 0;
for (let i = 0; i < buffer.length; i += 2) {
sum = (sum + buffer.readUInt16BE(i)) % 65535;
}
return ~sum & 65535;
}
export {
ERR_LATENCY_NEGATIVE,
ERR_SEQUENCE_TOO_BIG,
ERR_SEQUENCE_TOO_SMALL,
ERR_WRONG_CORRELATION,
ERR_WRONG_ICMP_CODE,
ERR_WRONG_ICMP_TYPE,
ERR_WRONG_LENGTH,
ERR_WRONG_SEQUENCE,
ProtocolHandler,
getWarning,
rfc1071crc
};
//# sourceMappingURL=protocol.mjs.map