UNPKG

@aikidosec/firewall

Version:

Zen by Aikido is an embedded Web Application Firewall that autonomously protects Node.js apps against common and critical attacks

193 lines (192 loc) 5.89 kB
"use strict"; // Based on https://github.com/demskie/netparser // MIT License - Copyright (c) 2019 alex Object.defineProperty(exports, "__esModule", { value: true }); exports.Address = void 0; const parse = require("./parse"); const BEFORE = -1; const EQUALS = 0; const AFTER = 1; class Address { constructor(address) { if (address) { const net = parse.network(address); if (net) { this.arr = net.bytes; return; } } this.arr = []; } bytes() { return this.arr ? this.arr : []; } setBytes(bytes) { if (bytes.length === 4 || bytes.length === 16) { this.arr = bytes; } else { this.arr = []; } return this; } destroy() { if (this.isValid()) { this.arr = []; } return this; } isValid() { return this.arr.length > 0; } isIPv4() { return this.arr.length === 4; } isIPv6() { return this.arr.length === 16; } duplicate() { return new Address().setBytes(this.arr.slice()); } equals(address) { return this.compare(address) === EQUALS; } compare(address) { // check that both addresses are valid if (!this.isValid() || !address.isValid()) return null; // handle edge cases like mixing IPv4 and IPv6 if (this === address) return EQUALS; if (this.arr.length < address.arr.length) return BEFORE; if (this.arr.length > address.arr.length) return AFTER; // compare addresses for (let i = 0; i < this.arr.length; i++) { if (this.arr[i] < address.arr[i]) return BEFORE; if (this.arr[i] > address.arr[i]) return AFTER; } // otherwise they must be equal return EQUALS; } applySubnetMask(cidr) { if (!this.isValid()) return this; let maskBits = this.arr.length * 8 - cidr; for (let i = this.arr.length - 1; i >= 0; i--) { switch (Math.max(0, Math.min(maskBits, 8))) { case 0: return this; case 1: this.arr[i] &= ~1; break; case 2: this.arr[i] &= ~3; break; case 3: this.arr[i] &= ~7; break; case 4: this.arr[i] &= ~15; break; case 5: this.arr[i] &= ~31; break; case 6: this.arr[i] &= ~63; break; case 7: this.arr[i] &= ~127; break; case 8: this.arr[i] = 0; break; } maskBits -= 8; } return this; } isBaseAddress(cidr) { if (!this.isValid() || cidr < 0 || cidr > this.arr.length * 8) return false; if (cidr === this.arr.length * 8) return true; let maskBits = this.arr.length * 8 - cidr; for (let i = this.arr.length - 1; i >= 0; i--) { switch (Math.max(0, Math.min(maskBits, 8))) { case 0: return true; case 1: if (this.arr[i] !== (this.arr[i] & ~1)) return false; break; case 2: if (this.arr[i] !== (this.arr[i] & ~3)) return false; break; case 3: if (this.arr[i] !== (this.arr[i] & ~7)) return false; break; case 4: if (this.arr[i] !== (this.arr[i] & ~15)) return false; break; case 5: if (this.arr[i] !== (this.arr[i] & ~31)) return false; break; case 6: if (this.arr[i] !== (this.arr[i] & ~63)) return false; break; case 7: if (this.arr[i] !== (this.arr[i] & ~127)) return false; break; case 8: if (this.arr[i] !== 0) return false; break; } maskBits -= 8; } return true; } increase(cidr) { if (this.isValid()) { this.offsetAddress(cidr, true); } else { this.destroy(); } return this; } offsetAddress(cidr, forwards, throwErrors) { const targetByte = Math.floor((cidr - 1) / 8); if (this.isValid() && targetByte >= 0 && targetByte < this.arr.length) { const increment = Math.pow(2, 8 - (cidr - targetByte * 8)); this.arr[targetByte] += increment * (forwards ? 1 : -1); if (targetByte >= 0) { if (this.arr[targetByte] < 0) { this.arr[targetByte] = 256 + (this.arr[targetByte] % 256); this.offsetAddress(targetByte * 8, forwards, throwErrors); } else if (this.arr[targetByte] > 255) { this.arr[targetByte] %= 256; this.offsetAddress(targetByte * 8, forwards, throwErrors); } } else { this.destroy(); } } else { this.destroy(); } } } exports.Address = Address;