- (ui): improved client access check performance
This is still not ideal and if the disallowed clients list is huge enough, the slowdown is considerable. But it's at least x10 or x100 times faster than it was. Closes: #1920
This commit is contained in:
parent
d2bf1e176e
commit
946bda37a3
4
Makefile
4
Makefile
|
@ -134,7 +134,9 @@ lint-go:
|
||||||
golangci-lint run
|
golangci-lint run
|
||||||
|
|
||||||
test:
|
test:
|
||||||
@echo Running unit-tests
|
@echo Running JS unit-tests
|
||||||
|
npm run test --prefix client
|
||||||
|
@echo Running Go unit-tests
|
||||||
go test -race -v -bench=. -coverprofile=coverage.txt -covermode=atomic ./...
|
go test -race -v -bench=. -coverprofile=coverage.txt -covermode=atomic ./...
|
||||||
|
|
||||||
ci: dependencies client test
|
ci: dependencies client test
|
||||||
|
|
|
@ -288,50 +288,6 @@ export const WHOIS_ICONS = {
|
||||||
descr: '',
|
descr: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DNS_RECORD_TYPES = [
|
|
||||||
'A',
|
|
||||||
'AAAA',
|
|
||||||
'AFSDB',
|
|
||||||
'APL',
|
|
||||||
'CAA',
|
|
||||||
'CDNSKEY',
|
|
||||||
'CDS',
|
|
||||||
'CERT',
|
|
||||||
'CNAME',
|
|
||||||
'CSYNC',
|
|
||||||
'DHCID',
|
|
||||||
'DLV',
|
|
||||||
'DNAME',
|
|
||||||
'DNSKEY',
|
|
||||||
'DS',
|
|
||||||
'HIP',
|
|
||||||
'IPSECKEY',
|
|
||||||
'KEY',
|
|
||||||
'KX',
|
|
||||||
'LOC',
|
|
||||||
'MX',
|
|
||||||
'NAPTR',
|
|
||||||
'NS',
|
|
||||||
'NSEC',
|
|
||||||
'NSEC3',
|
|
||||||
'NSEC3PARAM',
|
|
||||||
'OPENPGPKEY',
|
|
||||||
'PTR',
|
|
||||||
'RRSIG',
|
|
||||||
'RP',
|
|
||||||
'SIG',
|
|
||||||
'SMIMEA',
|
|
||||||
'SOA',
|
|
||||||
'SRV',
|
|
||||||
'SSHFP',
|
|
||||||
'TA',
|
|
||||||
'TKEY',
|
|
||||||
'TLSA',
|
|
||||||
'TSIG',
|
|
||||||
'TXT',
|
|
||||||
'URI',
|
|
||||||
];
|
|
||||||
|
|
||||||
export const DEFAULT_LOGS_FILTER = {
|
export const DEFAULT_LOGS_FILTER = {
|
||||||
search: '',
|
search: '',
|
||||||
response_status: '',
|
response_status: '',
|
||||||
|
|
|
@ -5,7 +5,6 @@ import subHours from 'date-fns/sub_hours';
|
||||||
import addHours from 'date-fns/add_hours';
|
import addHours from 'date-fns/add_hours';
|
||||||
import addDays from 'date-fns/add_days';
|
import addDays from 'date-fns/add_days';
|
||||||
import subDays from 'date-fns/sub_days';
|
import subDays from 'date-fns/sub_days';
|
||||||
import isSameDay from 'date-fns/is_same_day';
|
|
||||||
import round from 'lodash/round';
|
import round from 'lodash/round';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import i18n from 'i18next';
|
import i18n from 'i18next';
|
||||||
|
@ -20,7 +19,6 @@ import {
|
||||||
DEFAULT_LANGUAGE,
|
DEFAULT_LANGUAGE,
|
||||||
DEFAULT_TIME_FORMAT,
|
DEFAULT_TIME_FORMAT,
|
||||||
DETAILED_DATE_FORMAT_OPTIONS,
|
DETAILED_DATE_FORMAT_OPTIONS,
|
||||||
DNS_RECORD_TYPES,
|
|
||||||
FILTERED,
|
FILTERED,
|
||||||
FILTERED_STATUS,
|
FILTERED_STATUS,
|
||||||
IP_MATCH_LIST_STATUS,
|
IP_MATCH_LIST_STATUS,
|
||||||
|
@ -31,6 +29,7 @@ import {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param time {string} The time to format
|
* @param time {string} The time to format
|
||||||
|
* @param options {string}
|
||||||
* @returns {string} Returns the time in the format HH:mm:ss
|
* @returns {string} Returns the time in the format HH:mm:ss
|
||||||
*/
|
*/
|
||||||
export const formatTime = (time, options = DEFAULT_TIME_FORMAT) => {
|
export const formatTime = (time, options = DEFAULT_TIME_FORMAT) => {
|
||||||
|
@ -60,12 +59,6 @@ export const formatDetailedDateTime = (dateTime) => formatDateTime(
|
||||||
dateTime, DETAILED_DATE_FORMAT_OPTIONS,
|
dateTime, DETAILED_DATE_FORMAT_OPTIONS,
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* @param date {string}
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
export const isToday = (date) => isSameDay(new Date(date), new Date());
|
|
||||||
|
|
||||||
export const normalizeLogs = (logs) => logs.map((log) => {
|
export const normalizeLogs = (logs) => logs.map((log) => {
|
||||||
const {
|
const {
|
||||||
answer,
|
answer,
|
||||||
|
@ -351,39 +344,6 @@ export const normalizeTopClients = (topClients) => topClients.reduce(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getClientInfo = (clients, ip) => {
|
|
||||||
const client = clients
|
|
||||||
.find((item) => item.ip_addrs?.find((clientIp) => clientIp === ip));
|
|
||||||
|
|
||||||
if (!client) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
const { name, whois_info } = client;
|
|
||||||
const whois = Object.keys(whois_info).length > 0 ? whois_info : '';
|
|
||||||
|
|
||||||
return {
|
|
||||||
name,
|
|
||||||
whois,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getAutoClientInfo = (clients, ip) => {
|
|
||||||
const client = clients.find((item) => ip === item.ip);
|
|
||||||
|
|
||||||
if (!client) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
const { name, whois_info } = client;
|
|
||||||
const whois = Object.keys(whois_info).length > 0 ? whois_info : '';
|
|
||||||
|
|
||||||
return {
|
|
||||||
name,
|
|
||||||
whois,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const sortClients = (clients) => {
|
export const sortClients = (clients) => {
|
||||||
const compare = (a, b) => {
|
const compare = (a, b) => {
|
||||||
const nameA = a.name.toUpperCase();
|
const nameA = a.name.toUpperCase();
|
||||||
|
@ -443,8 +403,6 @@ export const normalizeWhois = (whois) => {
|
||||||
return whois;
|
return whois;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isValidQuestionType = (type) => type && DNS_RECORD_TYPES.includes(type.toUpperCase());
|
|
||||||
|
|
||||||
export const getPathWithQueryString = (path, params) => {
|
export const getPathWithQueryString = (path, params) => {
|
||||||
const searchParams = new URLSearchParams(params);
|
const searchParams = new URLSearchParams(params);
|
||||||
|
|
||||||
|
@ -542,10 +500,10 @@ export const getMap = (arr, key, value) => arr.reduce((acc, curr) => {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param parsedIp {object} ipaddr.js IPv4 or IPv6 object
|
* @param parsedIp {object} ipaddr.js IPv4 or IPv6 object
|
||||||
* @param cidr {array} ipaddr.js CIDR array
|
* @param parsedCidr {array} ipaddr.js CIDR array
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export const isIpMatchCidr = (parsedIp, parsedCidr) => {
|
const isIpMatchCidr = (parsedIp, parsedCidr) => {
|
||||||
try {
|
try {
|
||||||
const cidrIpVersion = parsedCidr[0].kind();
|
const cidrIpVersion = parsedCidr[0].kind();
|
||||||
const ipVersion = parsedIp.kind();
|
const ipVersion = parsedIp.kind();
|
||||||
|
@ -556,6 +514,75 @@ export const isIpMatchCidr = (parsedIp, parsedCidr) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The purpose of this method is to quickly check
|
||||||
|
* if this IP can possibly be in the specified CIDR range.
|
||||||
|
*
|
||||||
|
* @param ip {string}
|
||||||
|
* @param listItem {string}
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
const isIpQuickMatchCIDR = (ip, listItem) => {
|
||||||
|
const ipv6 = ip.indexOf(':') !== -1;
|
||||||
|
const cidrIpv6 = listItem.indexOf(':') !== -1;
|
||||||
|
if (ipv6 !== cidrIpv6) {
|
||||||
|
// CIDR is for a different IP type
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cidrIpv6) {
|
||||||
|
// We don't do quick check for IPv6 addresses
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const idx = listItem.indexOf('/');
|
||||||
|
if (idx === -1) {
|
||||||
|
// Not a CIDR, return false immediately
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cidrIp = listItem.substring(0, idx);
|
||||||
|
const cidrRange = parseInt(listItem.substring(idx + 1), 10);
|
||||||
|
if (Number.isNaN(cidrRange)) {
|
||||||
|
// Not a valid CIDR
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parts = cidrIp.split('.');
|
||||||
|
if (parts.length !== 4) {
|
||||||
|
// Invalid IP, return immediately
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now depending on the range we check if the IP can possibly be in that range
|
||||||
|
if (cidrRange < 8) {
|
||||||
|
// Use the slow approach
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cidrRange < 16) {
|
||||||
|
// Check the first part
|
||||||
|
// Example: 0.0.0.0/8 matches 0.*.*.*
|
||||||
|
return ip.indexOf(`${parts[0]}.`) === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cidrRange < 24) {
|
||||||
|
// Check the first two parts
|
||||||
|
// Example: 0.0.0.0/16 matches 0.0.*.*
|
||||||
|
return ip.indexOf(`${parts[0]}.${parts[1]}.`) === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cidrRange <= 32) {
|
||||||
|
// Check the first two parts
|
||||||
|
// Example: 0.0.0.0/16 matches 0.0.*.*
|
||||||
|
return ip.indexOf(`${parts[0]}.${parts[1]}.${parts[2]}.`) === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// range for IPv4 CIDR cannot be more than 32
|
||||||
|
// no need to check further, this CIDR is invalid
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ip {string}
|
* @param ip {string}
|
||||||
* @param list {string}
|
* @param list {string}
|
||||||
|
@ -573,20 +600,29 @@ export const getIpMatchListStatus = (ip, list) => {
|
||||||
for (let i = 0; i < listArr.length; i += 1) {
|
for (let i = 0; i < listArr.length; i += 1) {
|
||||||
const listItem = listArr[i];
|
const listItem = listArr[i];
|
||||||
|
|
||||||
const parsedIp = ipaddr.parse(ip);
|
if (ip === listItem.trim()) {
|
||||||
const isItemAnIp = ipaddr.isValid(listItem);
|
|
||||||
const parsedItem = isItemAnIp ? ipaddr.parse(listItem) : ipaddr.parseCIDR(listItem);
|
|
||||||
|
|
||||||
if (isItemAnIp && parsedIp.toString() === parsedItem.toString()) {
|
|
||||||
return IP_MATCH_LIST_STATUS.EXACT;
|
return IP_MATCH_LIST_STATUS.EXACT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isItemAnIp && isIpMatchCidr(parsedIp, parsedItem)) {
|
// Using ipaddr.js is quite slow so we first do a quick check
|
||||||
return IP_MATCH_LIST_STATUS.CIDR;
|
// to see if it's possible that this IP may be in the specified CIDR range
|
||||||
|
if (isIpQuickMatchCIDR(ip, listItem)) {
|
||||||
|
const parsedIp = ipaddr.parse(ip);
|
||||||
|
const isItemAnIp = ipaddr.isValid(listItem);
|
||||||
|
const parsedItem = isItemAnIp ? ipaddr.parse(listItem) : ipaddr.parseCIDR(listItem);
|
||||||
|
|
||||||
|
if (isItemAnIp && parsedIp.toString() === parsedItem.toString()) {
|
||||||
|
return IP_MATCH_LIST_STATUS.EXACT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isItemAnIp && isIpMatchCidr(parsedIp, parsedItem)) {
|
||||||
|
return IP_MATCH_LIST_STATUS.CIDR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return IP_MATCH_LIST_STATUS.NOT_FOUND;
|
return IP_MATCH_LIST_STATUS.NOT_FOUND;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
return IP_MATCH_LIST_STATUS.NOT_FOUND;
|
return IP_MATCH_LIST_STATUS.NOT_FOUND;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue