Better Bot IP-Ranges/Networks detection
This commit is contained in:
@@ -37,6 +37,8 @@
|
||||
&.ipaddr::before { background-image: url('img/addr.png') }
|
||||
&.ip4::before { background-position-y: -20px }
|
||||
&.ip6::before { background-position-y: -40px }
|
||||
&.ipnet::before { background-position-y: -60px }
|
||||
&.ipother::before { background-image: url('img/more.svg') }
|
||||
|
||||
/* Bot icons */
|
||||
&.bot::before { background-image: url('img/bots.png') }
|
||||
@@ -784,7 +786,7 @@
|
||||
&:nth-child(even) {
|
||||
background-color: #DFDFDF;
|
||||
}
|
||||
&.info { color: #626262; font-style: italic;}
|
||||
&.skipped { color: #626262; font-style: italic;}
|
||||
&.success { color: #217121; }
|
||||
&.error { color: #bb2929; }
|
||||
}
|
||||
|
||||
118
admin.js
118
admin.js
@@ -824,6 +824,7 @@ BotMon.live = {
|
||||
const other = {
|
||||
'id': 'other',
|
||||
'name': "Others",
|
||||
'typ': 'other',
|
||||
'count': 0
|
||||
};
|
||||
let total = 0; // adding up the items
|
||||
@@ -834,6 +835,7 @@ BotMon.live = {
|
||||
const rIt = {
|
||||
id: it.id,
|
||||
name: (it.n ? it.n : it.id),
|
||||
typ: it.typ || it.id,
|
||||
count: it.count
|
||||
};
|
||||
rList.push(rIt);
|
||||
@@ -1001,7 +1003,7 @@ BotMon.live = {
|
||||
return bounces;
|
||||
},
|
||||
|
||||
_ipOwners: [],
|
||||
_ipRanges: [],
|
||||
|
||||
/* adds a visit to the ip ranges arrays */
|
||||
addToIpRanges: function(v) {
|
||||
@@ -1012,34 +1014,86 @@ BotMon.live = {
|
||||
|
||||
// Number of IP address segments to look at:
|
||||
const kIP4Segments = 1;
|
||||
const kIP6Segments = 2;
|
||||
const kIP6Segments = 3;
|
||||
|
||||
let isp = 'null'; // default ISP id
|
||||
let name = 'Unknown'; // default ISP name
|
||||
let ipGroup = ''; // group name
|
||||
let ipSeg = []; // IP segment array
|
||||
let rawIP = ''; // raw ip prefix
|
||||
let ipName = ''; // IP group display name
|
||||
|
||||
const ipType = v.ip.indexOf(':') > 0 ? BM_IPVERSION.IPv6 : BM_IPVERSION.IPv4;
|
||||
const ipAddr = BotMon.t._ip2Num(v.ip);
|
||||
|
||||
// is there already a known IP range assigned?
|
||||
if (v._ipRange) {
|
||||
isp = v._ipRange.g;
|
||||
}
|
||||
|
||||
let ispRec = me._ipOwners.find( it => it.id == isp);
|
||||
if (!ispRec) {
|
||||
ispRec = {
|
||||
'id': isp,
|
||||
'n': ipRanges.getOwner( isp ) || "Unknown",
|
||||
'count': v._pageViews.length
|
||||
};
|
||||
me._ipOwners.push(ispRec);
|
||||
} else {
|
||||
ispRec.count += v._pageViews.length;
|
||||
ipGroup = v._ipRange.g; // group name
|
||||
ipName = ipRanges.getOwner( v._ipRange.g ) || "Unknown";
|
||||
|
||||
} else { // no known IP range, let's collect necessary information:
|
||||
|
||||
|
||||
// collect basic IP address info:
|
||||
if (ipType == BM_IPVERSION.IPv6) {
|
||||
ipSeg = ipAddr.split(':');
|
||||
const prefix = v.ip.split(':').slice(0, kIP6Segments).join(':');
|
||||
rawIP = ipSeg.slice(0, kIP6Segments).join(':');
|
||||
ipGroup = 'ip6-' + rawIP.replaceAll(':', '-');
|
||||
ipName = prefix + '::' + '/' + (16 * kIP6Segments);
|
||||
} else {
|
||||
ipSeg = ipAddr.split('.');
|
||||
const prefix = v.ip.split('.').slice(0, kIP4Segments).join('.');
|
||||
rawIP = ipSeg.slice(0, kIP4Segments).join('.') ;
|
||||
ipGroup = 'ip4-' + rawIP.replaceAll('.', '-');
|
||||
ipName = prefix + '.0.0.0'.substring(0, 1+(4-kIP4Segments)*2) + '/' + (8 * kIP4Segments);
|
||||
}
|
||||
}
|
||||
|
||||
// check if record already exists:
|
||||
let ipRec = me._ipRanges.find( it => it.g == ipGroup);
|
||||
if (!ipRec) {
|
||||
|
||||
// ip info record initialised:
|
||||
ipRec = {
|
||||
g: ipGroup,
|
||||
n: ipName,
|
||||
count: 0
|
||||
}
|
||||
|
||||
// existing record?
|
||||
if (v._ipRange) {
|
||||
|
||||
ipRec.from = v._ipRange.from;
|
||||
ipRec.to = v._ipRange.to;
|
||||
ipRec.typ = 'net';
|
||||
|
||||
} else { // no known IP range, let's collect necessary information:
|
||||
|
||||
// complete the ip info record:
|
||||
if (ipType == BM_IPVERSION.IPv6) {
|
||||
ipRec.from = rawIP + ':0000:0000:0000:0000:0000:0000:0000'.substring(0, (8-kIP6Segments)*5);
|
||||
ipRec.to = rawIP + ':FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF'.substring(0, (8-kIP6Segments)*5);
|
||||
ipRec.typ = '6';
|
||||
} else {
|
||||
ipRec.from = rawIP + '.000.000.000.000'.substring(0, (4-kIP4Segments)*4);
|
||||
ipRec.to = rawIP + '.255.255.255.254'.substring(0, (4-kIP4Segments)*4);
|
||||
ipRec.typ = '4';
|
||||
}
|
||||
}
|
||||
|
||||
me._ipRanges.push(ipRec);
|
||||
}
|
||||
|
||||
// add to counter:
|
||||
ipRec.count += v._pageViews.length;
|
||||
|
||||
},
|
||||
|
||||
getTopBotISPs: function(max) {
|
||||
|
||||
const me = BotMon.live.data.analytics;
|
||||
|
||||
return me._makeTopList(me._ipOwners, max);
|
||||
return me._makeTopList(me._ipRanges, max);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1817,6 +1871,8 @@ BotMon.live = {
|
||||
|
||||
const maxItemsPerList = 5; // how many list items to show?
|
||||
|
||||
const kNoData = '–'; // shown when data is missing
|
||||
|
||||
// shortcut for neater code:
|
||||
const makeElement = BotMon.t._makeElement;
|
||||
|
||||
@@ -1831,23 +1887,23 @@ BotMon.live = {
|
||||
switch(i) {
|
||||
case 0:
|
||||
title = "Known bots:";
|
||||
value = data.bots.known;
|
||||
value = data.bots.known || kNoData;
|
||||
break;
|
||||
case 1:
|
||||
title = "Suspected bots:";
|
||||
value = data.bots.suspected;
|
||||
value = data.bots.suspected || kNoData;
|
||||
break;
|
||||
case 2:
|
||||
title = "Probably humans:";
|
||||
value = data.bots.human;
|
||||
value = data.bots.human || kNoData;
|
||||
break;
|
||||
case 3:
|
||||
title = "Registered users:";
|
||||
value = data.bots.users;
|
||||
value = data.bots.users || kNoData;
|
||||
break;
|
||||
case 4:
|
||||
title = "Total:";
|
||||
value = data.totalPageViews;
|
||||
value = data.totalPageViews || kNoData;
|
||||
break;
|
||||
case 5:
|
||||
title = "Bots-humans ratio:";
|
||||
@@ -1879,13 +1935,13 @@ BotMon.live = {
|
||||
// update the suspected bot IP ranges list:
|
||||
const botIps = document.getElementById('botmon__botips');
|
||||
if (botIps) {
|
||||
botIps.appendChild(makeElement('dt', {}, "Top bot ISPs"));
|
||||
botIps.appendChild(makeElement('dt', {}, "Top bot Networks"));
|
||||
|
||||
const ispList = BotMon.live.data.analytics.getTopBotISPs(5);
|
||||
console.log(ispList);
|
||||
//console.log(ispList);
|
||||
ispList.forEach( (netInfo) => {
|
||||
const li = makeElement('dd');
|
||||
li.appendChild(makeElement('span', {'class': 'has_icon ipaddr ip_' + netInfo.id }, netInfo.name));
|
||||
li.appendChild(makeElement('span', {'class': 'has_icon ipaddr ip' + netInfo.typ }, netInfo.name));
|
||||
li.appendChild(makeElement('span', {'class': 'count' }, netInfo.count));
|
||||
botIps.append(li)
|
||||
});
|
||||
@@ -1918,20 +1974,20 @@ BotMon.live = {
|
||||
let value = '';
|
||||
switch(i) {
|
||||
case 0:
|
||||
title = "Page views by registered users:";
|
||||
value = data.bots.users;
|
||||
title = "Registered users’ page views:";
|
||||
value = data.bots.users || kNoData;
|
||||
break;
|
||||
case 1:
|
||||
title = "Page views by “probably humans”:";
|
||||
value = data.bots.human;
|
||||
title = "“Probably humans” page views:";
|
||||
value = data.bots.human || kNoData;
|
||||
break;
|
||||
case 2:
|
||||
title = "Total human page views:";
|
||||
value = data.bots.users + data.bots.human;
|
||||
value = (data.bots.users + data.bots.human) || kNoData;
|
||||
break;
|
||||
case 3:
|
||||
title = "Total human visits:";
|
||||
value = humanVisits;
|
||||
value = humanVisits || kNoData;
|
||||
break;
|
||||
case 4:
|
||||
title = "Humans’ bounce rate:";
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
{
|
||||
"groups": [
|
||||
{"id": "alibaba", "name": "Alibaba"},
|
||||
{"id": "amazon", "name": "Amazon Data Services"},
|
||||
{"id": "amazon", "name": "Amazon DS"},
|
||||
{"id": "amazon-microsoft", "name": "Amazon or Microsoft"},
|
||||
{"id": "brasilnet", "name": "BrasilNet"},
|
||||
{"id": "charter", "name": "Charter Communications Inc."},
|
||||
{"id": "charter", "name": "Charter Inc."},
|
||||
{"id": "chinanet", "name": "Chinanet"},
|
||||
{"id": "cnisp", "name": "China ISP"},
|
||||
{"id": "cnmob", "name": "China Mobile Communications Corp."},
|
||||
{"id": "cnmob", "name": "China Mobile"},
|
||||
{"id": "google", "name": "Google LLC"},
|
||||
{"id": "google-amazon", "name": "Google or Amazon"},
|
||||
{"id": "hetzner", "name": "Hetzner Hosting (US)"},
|
||||
{"id": "hetzner", "name": "Hetzner US"},
|
||||
{"id": "huawei", "name": "Huawei"},
|
||||
{"id": "misc_sa", "name": "Various South- and Central-American ISPs"},
|
||||
{"id": "misc_sa", "name": "Misc. SA ISPs"},
|
||||
{"id": "tencent", "name": "Tencent"},
|
||||
{"id": "unicom", "name": "China Unicom"},
|
||||
{"id": "vnpt", "name": "Vietnam Telecom"},
|
||||
@@ -35,7 +35,7 @@
|
||||
{"from": "44.192.0.0", "to": "44.255.255.254", "m": 16, "g": "tencent"},
|
||||
{"from": "45.0.0.0", "to": "45.255.255.254", "m": 10, "g": "amazon"},
|
||||
{"from": "46.250.160.0", "to": "46.250.191.254", "m": 19, "g": "huawei"},
|
||||
{"from": "47.82.0.0", "to": "47.82.255.254", "m": 16, "g": "alibaba"},
|
||||
{"from": "47.74.0.0", "to": "47.127.255.254", "m": 10, "g": "alibaba"},
|
||||
{"from": "47.200.0.0", "to": "47.203.255.254", "m": 14, "g": "frontier"},
|
||||
{"from": "49.0.192.0", "to": "49.0.255.254", "m": 18, "g": "huawei"},
|
||||
{"from": "52.0.0.0", "to": "52.255.255.254", "m": 8, "g": "amazon-microsoft"},
|
||||
@@ -67,11 +67,14 @@
|
||||
{"from": "162.128.0.0", "to": "162.128.255.254", "m": 16, "g": "zenlayer"},
|
||||
{"from": "166.108.192.0", "to": "166.108.255.254", "m": 18, "g": "huawei"},
|
||||
{"from": "168.232.192.0", "to": "168.232.255.254", "m": 16, "g": "misc_sa"},
|
||||
{"from": "170.82.0.0", "to": "170.82.255.254", "m": 16, "g": "misc_sa"},
|
||||
{"from": "170.0.0.0", "to": "170.3.255.254", "m": 14, "g": "misc_sa"},
|
||||
{"from": "170.80.0.0", "to": "170.83.255.254", "m": 14, "g": "misc_sa"},
|
||||
{"from": "170.254.0.0", "to": "170.254.255.254", "m": 16, "g": "misc_sa"},
|
||||
{"from": "171.224.0.0", "to": "171.239.255.254", "m": 12, "g": "viettel"},
|
||||
{"from": "177.0.0.0", "to": "177.255.255.254", "m": 8, "g": "brasilnet"},
|
||||
{"from": "178.156.128.0", "to": "178.156.255.254", "m": 17, "g": "hetzner"},
|
||||
{"from": "179.0.0.0", "to": "179.255.255.254", "m": 8, "g": "brasilnet"},
|
||||
{"from": "181.0.0.0", "to": "181.255.255.254", "m": 8, "g": "misc_sa"},
|
||||
{"from": "183.87.32.0", "to": "183.87.63.254", "m": 19, "g": "huawei"},
|
||||
{"from": "186.0.0.0", "to": "186.255.255.254", "m": 8, "g": "misc_sa"},
|
||||
{"from": "187.0.0.0", "to": "187.255.255.254", "m": 8, "g": "misc_sa"},
|
||||
|
||||
@@ -35,7 +35,7 @@ class helper_plugin_botmon extends Plugin {
|
||||
if ($bName == '' || $bName == 'logfiles' || $bName == 'empty' || $fName == '.htaccess') {
|
||||
// echo "File “{$fName}” ignored.\n";
|
||||
} else if ($bName == $today || $bName == $yesterday) {
|
||||
echo "<li class='info'>File “{$fName}” skipped.</li>\n";
|
||||
echo "<li class='skipped'>File “{$fName}” skipped.</li>\n";
|
||||
} else {
|
||||
if (unlink(DOKU_PLUGIN . 'botmon/logs/' . $file)) {
|
||||
echo "<li class='success'>File “{$fName}” deleted.</li>\n";
|
||||
@@ -44,7 +44,7 @@ class helper_plugin_botmon extends Plugin {
|
||||
}
|
||||
}
|
||||
}
|
||||
echo "<li class='info'>Done.</li>\n";
|
||||
echo "<li>Done.</li>\n";
|
||||
}
|
||||
|
||||
}
|
||||
BIN
img/addr.png
BIN
img/addr.png
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.9 KiB |
Reference in New Issue
Block a user