core-extra/webapp/static/coreip.js

199 lines
6 KiB
JavaScript

const AF_INET = 2;
const AF_INET6 = 23;
function ord (string) {
var str = string + '';
var code = str.charCodeAt(0);
if (code >= 0xD800 && code <= 0xDBFF) {
// High surrogate (could change last hex to 0xDB7F to treat
// high private surrogates as single characters)
var hi = code;
if (str.length === 1) {
// This is just a high surrogate with no following low surrogate,
// so we return its value;
return code;
// we could also throw an error as it is not a complete character,
// but someone may want to know
}
var low = str.charCodeAt(1);
return ((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000
}
if (code >= 0xDC00 && code <= 0xDFFF) {
// Low surrogate
// This is just a low surrogate with no preceding high surrogate,
// so we return its value;
return code;
// we could also throw an error as it is not a complete character,
// but someone may want to know
}
return code
}
function inetNtop (a) {
var i = 0;
var m = '';
var c = [];
a += '';
if (a.length === 4) {
// IPv4
return [
a.charCodeAt(0),
a.charCodeAt(1),
a.charCodeAt(2),
a.charCodeAt(3)
].join('.');
} else if (a.length === 16) {
// IPv6
for (i = 0; i < 16; i++) {
c.push(((a.charCodeAt(i++) << 8) + a.charCodeAt(i)).toString(16));
}
return c.join(':')
.replace(/((^|:)0(?=:|$))+:?/g, function (t) {
m = (t.length > m.length) ? t : m;
return t;
})
.replace(m || ' ', '::');
} else {
// Invalid length
return false;
}
}
function inetPton(a) {
var r;
var m;
var x;
var i;
var j;
var f = String.fromCharCode;
// IPv4
m = a.match(/^(?:\d{1,3}(?:\.|$)){4}/);
if (m) {
m = m[0].split('.');
m = f(m[0]) + f(m[1]) + f(m[2]) + f(m[3]);
// Return if 4 bytes, otherwise false.
return m.length === 4 ? m : false;
}
r = /^((?:[\da-f]{1,4}(?::|)){0,8})(::)?((?:[\da-f]{1,4}(?::|)){0,8})$/;
// IPv6
m = a.match(r);
if (m) {
// Translate each hexadecimal value.
for (j = 1; j < 4; j++) {
// Indice 2 is :: and if no length, continue.
if (j === 2 || m[j].length === 0) {
continue;
}
m[j] = m[j].split(':');
for (i = 0; i < m[j].length; i++) {
m[j][i] = parseInt(m[j][i], 16);
// Would be NaN if it was blank, return false.
if (isNaN(m[j][i])) {
// Invalid IP.
return false;
}
m[j][i] = f(m[j][i] >> 8) + f(m[j][i] & 0xFF);
}
m[j] = m[j].join('');
}
x = m[1].length + m[3].length;
if (x === 16) {
return m[1] + m[3];
} else if (x < 16 && m[2].length > 0) {
return m[1] + (new Array(16 - x + 1))
.join('\x00') + m[3];
}
}
// Invalid IP
return false
}
class IpAddress {
constructor(addressFamily, address) {
console.log('ip address: ', addressFamily, address);
this.addressFamily = addressFamily;
this.address = address;
}
str() {
return inetNtop(this.address);
}
}
class IpPrefix {
constructor(addressFamily, prefix) {
this.addressFamily = addressFamily;
if (this.addressFamily === AF_INET) {
this.addressLength = 32;
} else if (this.addressFamily == AF_INET6) {
this.addressLength = 128;
} else {
throw Error(`invalid address family: ${addressFamily}`);
}
const values = prefix.split('/');
console.log(`split prefix: ${values}`);
if (values.length > 2) {
throw Error(`invalid prefix: ${prefix}`);
}
if (values.length === 2) {
this.prefixLength = parseInt(values[1]);
} else {
this.prefixLength = this.addressLength;
}
this.prefix = inetPton(values[0]);
if (this.addressLength > this.prefixLength) {
const addressBits = this.addressLength - this.prefixLength;
let netMask = ((1 << this.prefixLength) - 1) << addressBits;
prefix = '';
//in xrange(-1, -(addrbits >> 3) - 2, -1)
const stopValue = -(addressBits) - 2;
for (let i = -1; i > stopValue; --i) {
prefix = String.fromCharCode(ord(this.prefix[i]) & (netMask & 0xff)) + prefix;
netMask >>= 8;
}
this.prefix = this.prefix.slice(0, stopValue) + prefix;
}
}
getAddress(id) {
if (id in [-1, 0, 1] && this.addressLength === this.prefixLength) {
return new IpAddress(this.addressFamily, this.prefix);
}
const value = (1 << (this.addressLength - this.prefixLength)) - 1;
console.log(`address length(${this.addressLength}) prefix length(${this.prefixLength}) value(${value})`);
if (id === 0 || id > value || (this.addressFamily === AF_INET && id === value)) {
throw Error(`invalid id for prefix ${this.prefix}: ${id}`);
}
let address = '';
let prefixEndpoint = -1;
console.log('stop condition: ', -(this.addressLength >> 3) - 1);
for (let i = -1; i > -(this.addressLength >> 3) - 1; --i) {
console.log('i: ', i);
prefixEndpoint = i;
address = String.fromCharCode(ord(this.prefix[i]) | (id & 0xff)) + address;
console.log('address: ', address);
id >>= 8;
console.log('id: ', id);
if (!id) {
break
}
}
address = this.prefix.slice(0, prefixEndpoint) + address;
return new IpAddress(this.addressFamily, address);
}
}