From 1d571c284cea0ea972a673d4a3f53e06908e641b Mon Sep 17 00:00:00 2001 From: nymkappa Date: Mon, 29 Aug 2022 23:36:18 +0200 Subject: [PATCH] Fix wrong ASN for Lunanode ip ranges --- .../lightning/sync-tasks/node-locations.ts | 10 +- backend/src/utils/ipcheck.js | 119 ++++++++++++++++++ backend/tsconfig.json | 3 +- production/nginx-cache-warmer | 2 +- 4 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 backend/src/utils/ipcheck.js diff --git a/backend/src/tasks/lightning/sync-tasks/node-locations.ts b/backend/src/tasks/lightning/sync-tasks/node-locations.ts index 30a6bfc2a..fbcc6c30d 100644 --- a/backend/src/tasks/lightning/sync-tasks/node-locations.ts +++ b/backend/src/tasks/lightning/sync-tasks/node-locations.ts @@ -4,6 +4,7 @@ import nodesApi from '../../../api/explorer/nodes.api'; import config from '../../../config'; import DB from '../../../database'; import logger from '../../../logger'; +import * as IPCheck from '../../../utils/ipcheck.js'; export async function $lookupNodeLocation(): Promise { let loggerTimer = new Date().getTime() / 1000; @@ -27,6 +28,11 @@ export async function $lookupNodeLocation(): Promise { const asn = lookupAsn.get(ip); const isp = lookupIsp.get(ip); + let asOverwrite: number | null = null; + if (asn && (IPCheck.match(ip, '170.75.160.0/20') || IPCheck.match(ip, '172.81.176.0/21'))) { + asOverwrite = 394745; + } + if (city && (asn || isp)) { const query = ` UPDATE nodes SET @@ -41,7 +47,7 @@ export async function $lookupNodeLocation(): Promise { `; const params = [ - isp?.autonomous_system_number ?? asn?.autonomous_system_number, + asOverwrite ?? isp?.autonomous_system_number ?? asn?.autonomous_system_number, city.city?.geoname_id, city.country?.geoname_id, city.subdivisions ? city.subdivisions[0].geoname_id : null, @@ -91,7 +97,7 @@ export async function $lookupNodeLocation(): Promise { if (isp?.autonomous_system_organization ?? asn?.autonomous_system_organization) { await DB.query( `INSERT IGNORE INTO geo_names (id, type, names) VALUES (?, 'as_organization', ?)`, - [isp?.autonomous_system_number ?? asn?.autonomous_system_number, JSON.stringify(isp?.isp ?? asn?.autonomous_system_organization)]); + [asOverwrite ?? isp?.autonomous_system_number ?? asn?.autonomous_system_number, JSON.stringify(isp?.isp ?? asn?.autonomous_system_organization)]); } } diff --git a/backend/src/utils/ipcheck.js b/backend/src/utils/ipcheck.js new file mode 100644 index 000000000..06d4a6f15 --- /dev/null +++ b/backend/src/utils/ipcheck.js @@ -0,0 +1,119 @@ +var net = require('net'); + +var IPCheck = module.exports = function(input) { + var self = this; + + if (!(self instanceof IPCheck)) { + return new IPCheck(input); + } + + self.input = input; + self.parse(); +}; + +IPCheck.prototype.parse = function() { + var self = this; + + if (!self.input || typeof self.input !== 'string') return self.valid = false; + + var ip; + + var pos = self.input.lastIndexOf('/'); + if (pos !== -1) { + ip = self.input.substring(0, pos); + self.mask = +self.input.substring(pos + 1); + } else { + ip = self.input; + self.mask = null; + } + + self.ipv = net.isIP(ip); + self.valid = !!self.ipv && !isNaN(self.mask); + + if (!self.valid) return; + + // default mask = 32 for ipv4 and 128 for ipv6 + if (self.mask === null) self.mask = self.ipv === 4 ? 32 : 128; + + if (self.ipv === 4) { + // difference between ipv4 and ipv6 masks + self.mask += 96; + } + + if (self.mask < 0 || self.mask > 128) { + self.valid = false; + return; + } + + self.address = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; + + if(self.ipv === 4){ + self.parseIPv4(ip); + }else{ + self.parseIPv6(ip); + } +}; + +IPCheck.prototype.parseIPv4 = function(ip) { + var self = this; + + // ipv4 addresses live under ::ffff:0:0 + self.address[10] = self.address[11] = 0xff; + + var octets = ip.split('.'); + for (var i = 0; i < 4; i++) { + self.address[i + 12] = parseInt(octets[i], 10); + } +}; + + +var V6_TRANSITIONAL = /:(\d+\.\d+\.\d+\.\d+)$/; + +IPCheck.prototype.parseIPv6 = function(ip) { + var self = this; + + var transitionalMatch = V6_TRANSITIONAL.exec(ip); + if(transitionalMatch){ + self.parseIPv4(transitionalMatch[1]); + return; + } + + var bits = ip.split(':'); + if (bits.length < 8) { + ip = ip.replace('::', Array(11 - bits.length).join(':')); + bits = ip.split(':'); + } + + var j = 0; + for (var i = 0; i < bits.length; i += 1) { + var x = bits[i] ? parseInt(bits[i], 16) : 0; + self.address[j++] = x >> 8; + self.address[j++] = x & 0xff; + } +}; + +IPCheck.prototype.match = function(cidr) { + var self = this; + + if (!(cidr instanceof IPCheck)) cidr = new IPCheck(cidr); + if (!self.valid || !cidr.valid) return false; + + var mask = cidr.mask; + var i = 0; + + while (mask >= 8) { + if (self.address[i] !== cidr.address[i]) return false; + + i++; + mask -= 8; + } + + var shift = 8 - mask; + return (self.address[i] >>> shift) === (cidr.address[i] >>> shift); +}; + + +IPCheck.match = function(ip, cidr) { + ip = ip instanceof IPCheck ? ip : new IPCheck(ip); + return ip.match(cidr); +}; diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 6a1970331..0670010e1 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -13,7 +13,8 @@ "node_modules/@types" ], "allowSyntheticDefaultImports": true, - "esModuleInterop": true + "esModuleInterop": true, + "allowJs": true, }, "include": [ "src/**/*.ts" diff --git a/production/nginx-cache-warmer b/production/nginx-cache-warmer index 0928990c8..27d1e3a8f 100755 --- a/production/nginx-cache-warmer +++ b/production/nginx-cache-warmer @@ -99,7 +99,7 @@ do for url in / \ '/api/v1/lightning/nodes/isp/39572' `# DataWeb` \ '/api/v1/lightning/nodes/isp/14061' `# Digital Ocean` \ '/api/v1/lightning/nodes/isp/24940,213230' `# Hetzner` \ - '/api/v1/lightning/nodes/isp/174' `# LunaNode` \ + '/api/v1/lightning/nodes/isp/394745' `# LunaNode` \ '/api/v1/lightning/nodes/isp/45102' `# Alibaba` \ '/api/v1/lightning/nodes/isp/3209' `# Vodafone Germany` \ '/api/v1/lightning/nodes/isp/7922' `# Comcast Cable` \