Last active
April 28, 2019 22:43
-
-
Save FlyInk13/5b952b05be4daf17b95559a3d4ec23c9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const { spawn } = require('child_process'); | |
| const https = require('https'); | |
| const info = { | |
| lastPending: false, | |
| lastDataDate: 0, | |
| lastLineDate: 0, | |
| lastPushDate: 0, | |
| cpErrors: '\n', | |
| buffer: '', | |
| ipInfo: [], | |
| ipError: [], | |
| lastIp: {}, | |
| }; | |
| const HistoryLog = { | |
| history: [], | |
| counters: {}, | |
| limit: 10e3, | |
| minuteLimit: 1, | |
| push: (data) => { | |
| HistoryLog.clean(); | |
| data = { id: data.id, time: Date.now(), count: data.count }; | |
| HistoryLog.history.push(data); | |
| HistoryLog.countIncr(data.id, data.count); | |
| }, | |
| clean: () => { | |
| var array = HistoryLog.history; | |
| var count = array.length - 1; | |
| var death = Date.now() - HistoryLog.minuteLimit + 60e3; | |
| var item; | |
| while (count-- > 0) { | |
| item = array[count]; | |
| if (item.time < death) { | |
| HistoryLog.countIncr(array[count], -item.count); | |
| array.splice(count, 1); | |
| } | |
| } | |
| if (array.length > HistoryLog.limit) { | |
| var spliced = array.splice(0, array.length - HistoryLog.limit); | |
| HistoryLog.countIncrList(spliced); | |
| } | |
| }, | |
| countGet: (data) => { | |
| var count = HistoryLog.countIncr(data, 0); | |
| return count; | |
| }, | |
| countIncrList: (list, value) => { | |
| var count = list.length; | |
| var item; | |
| while (count--) { | |
| item = list[count]; | |
| HistoryLog.countIncr(item.id, -item.count); | |
| } | |
| }, | |
| countIncr: (key, value) => { | |
| if (!HistoryLog.counters[key]) { | |
| HistoryLog.counters[key] = 0; | |
| } | |
| HistoryLog.counters[key] += value; | |
| if (!HistoryLog.counters[key]) { | |
| delete HistoryLog.counters[key]; | |
| } | |
| return HistoryLog.counters[key] || 0; | |
| }, | |
| }; | |
| // ip info | |
| function matchIp(ip) { | |
| if (/^[\d.]+$/.test(ip)) { | |
| return ip.split('.').splice(0, 4).join('.'); | |
| } else if (/^[\w\d:.]+$/.test(ip)) { | |
| return ip.split('.').splice(0, 1).join('.'); | |
| } | |
| return ip; | |
| } | |
| function toLong(ip) { | |
| var ipl = 0; | |
| ip.split('.').forEach((octet) => { | |
| ipl <<= 8; | |
| ipl += parseInt(octet); | |
| }); | |
| return (ipl >>> 0); | |
| }; | |
| function fromLong(ipl) { | |
| return ( | |
| (ipl >>> 24 ) + '.' + | |
| (ipl >> 16 & 255) + '.' + | |
| (ipl >> 8 & 255) + '.' + | |
| (ipl & 255) | |
| ); | |
| }; | |
| function fillRange(first, last, description) { | |
| if (!/^[\d.]+$/.test(first)) return; | |
| if (!/^[\d.]+$/.test(last)) return; | |
| if (first !== fromLong(toLong(first))) return console.log('overflow', first, fromLong(toLong(first))); | |
| if (last !== fromLong(toLong(last))) return console.log('overflow', last, fromLong(toLong(last))); | |
| if (toLong(last) <= toLong(first)) return console.log('bad range'); | |
| var min = toLong(first); | |
| var max = toLong(last); | |
| var ip = ''; | |
| while (max > min) { | |
| ip = fromLong(max--); | |
| info.ipInfo[ip] = ip + ' (' + description + ')'; | |
| } | |
| } | |
| function whoIsApi(ip) { | |
| if (info.lastPending) return; | |
| info.lastPending = true; | |
| return new Promise((resolve, reject) => { | |
| https.get('https://api.iptoasn.com/v1/as/ip/' + ip, (res) => { | |
| var buffer = ''; | |
| res.on('data', (c) => buffer += c); | |
| res.on('end', () => resolve(buffer)); | |
| }).on('error', reject); | |
| }).then((res) => { | |
| try { | |
| return JSON.parse(res); | |
| } catch (e) { | |
| throw { code: 'ECONNRESET' }; | |
| } | |
| }).then((r) => { | |
| if (!r.as_description) { | |
| throw r; | |
| } | |
| info.lastIp = r; | |
| if (r.first_ip && r.last_ip) { | |
| fillRange(r.first_ip, r.last_ip, r.as_description); | |
| } | |
| return ip + ' (' + r.as_description + ')'; | |
| }).catch((e) => { | |
| if (e.code == 'ECONNRESET') return whoIsApi(ip); | |
| throw e; | |
| }).then((ipName) => { | |
| info.lastPending = false; | |
| info.ipInfo[ip] = ipName; | |
| }).catch((e) => { | |
| info.lastPending = false; | |
| info.ipInfo[ip] = -1; | |
| info.ipError[ip] = e; | |
| console.log(e); | |
| }); | |
| } | |
| function getInfo(ip) { | |
| if (!info.ipInfo[ip]) { | |
| info.ipInfo[ip] = -1; | |
| return ip; | |
| } else if (info.ipInfo[ip] == -1) { | |
| return ip; | |
| } else { | |
| return info.ipInfo[ip]; | |
| } | |
| } | |
| // tcpdump | |
| function onTcpData(data) { | |
| info.buffer += data; | |
| let index = info.buffer.indexOf('\n'); | |
| let line, match; | |
| info.lastDataDate = new Date(); | |
| while (index > -1) { | |
| info.lastLineDate = new Date(); | |
| line = info.buffer.substr(0, index); | |
| match = line.match(/.+ IP6? (.+) > .+? length (\d+)/); | |
| if (match) { | |
| var [, id, count] = match; | |
| id = matchIp(id); | |
| HistoryLog.push({ id, count: parseInt(count) }); | |
| } | |
| info.buffer = info.buffer.substr(index + 1); | |
| index = info.buffer.indexOf('\n'); | |
| info.lastPushDate = new Date(); | |
| } | |
| } | |
| function tcpdumpStart() { | |
| const tcpdump = spawn('tcpdump', ['-n', '-nn', 'inbound', 'and', 'greater 10']); | |
| tcpdump.stdout.on('data', onTcpData); | |
| tcpdump.stderr.on('data', (data) => info.cpErrors += data); | |
| tcpdump.on('close', (code) => info.cpErrors += '\nEXIT: ' + code); | |
| } | |
| // tick | |
| function onTick() { | |
| var ip = Object.entries(info.ipInfo) | |
| .sort((a, b) => HistoryLog.counters[b[0]] - HistoryLog.counters[a[0]]) | |
| .find((ip, i) => i < 30 && ip[1] === -1); | |
| if (ip) whoIsApi(ip[0]); | |
| var top = Object.entries(HistoryLog.counters) | |
| .sort((a, b) => b[1] - a[1]) | |
| .map((i) => i[1] + ' - ' + getInfo(i[0])) | |
| .splice(0, 30) | |
| .join('\n'); | |
| process.stdout.write('\u001bc'); | |
| console.log(top); | |
| console.log('\n\nInfo:'); | |
| Object.entries(info).forEach(([name, data]) => { | |
| if (name == 'ipInfo') return; | |
| if (!/last/.test(name)) console.log(); | |
| console.log(name + ':', data); | |
| }); | |
| console.log('\nLast log:', HistoryLog.history[HistoryLog.history.length - 1]); | |
| } | |
| // init | |
| tcpdumpStart(); | |
| setInterval(onTick, 1000); |
Example out:
374538 - 95.213.11.164 (VKONTAKTE-SPB-AS http://vk.com)
352434 - 149.154.167.99 (TELEGRAM)
31181 - 87.240.188.134 (VKONTAKTE-SPB-AS http://vk.com)
29331 - 87.240.188.175 (VKONTAKTE-SPB-AS http://vk.com)
28241 - 87.240.188.193 (VKONTAKTE-SPB-AS http://vk.com)
28230 - 87.240.188.216 (VKONTAKTE-SPB-AS http://vk.com)
28133 - 87.240.188.150 (VKONTAKTE-SPB-AS http://vk.com)
27603 - 87.240.188.189 (VKONTAKTE-SPB-AS http://vk.com)
27402 - 87.240.188.131 (VKONTAKTE-SPB-AS http://vk.com)
27363 - 87.240.188.176 (VKONTAKTE-SPB-AS http://vk.com)
27222 - 87.240.188.147 (VKONTAKTE-SPB-AS http://vk.com)
27007 - 149.154.167.220 (TELEGRAM)
26950 - 87.240.188.181 (VKONTAKTE-SPB-AS http://vk.com)
25850 - 87.240.188.213 (VKONTAKTE-SPB-AS http://vk.com)
25813 - 87.240.188.148 (VKONTAKTE-SPB-AS http://vk.com)
25597 - 87.240.188.165 (VKONTAKTE-SPB-AS http://vk.com)
25489 - 87.240.188.170 (VKONTAKTE-SPB-AS http://vk.com)
24998 - 87.240.188.202 (VKONTAKTE-SPB-AS http://vk.com)
23967 - 87.240.188.139 (VKONTAKTE-SPB-AS http://vk.com)
23718 - 87.240.188.159 (VKONTAKTE-SPB-AS http://vk.com)
22486 - 87.240.188.222 (VKONTAKTE-SPB-AS http://vk.com)
22212 - 87.240.188.142 (VKONTAKTE-SPB-AS http://vk.com)
22144 - 87.240.188.205 (VKONTAKTE-SPB-AS http://vk.com)
21834 - 87.240.188.224 (VKONTAKTE-SPB-AS http://vk.com)
21545 - 87.240.188.211 (VKONTAKTE-SPB-AS http://vk.com)
21324 - 87.240.188.188 (VKONTAKTE-SPB-AS http://vk.com)
21090 - 87.240.188.206 (VKONTAKTE-SPB-AS http://vk.com)
20992 - 87.240.188.219 (VKONTAKTE-SPB-AS http://vk.com)
20780 - 87.240.188.197 (VKONTAKTE-SPB-AS http://vk.com)
20435 - 87.240.188.149 (VKONTAKTE-SPB-AS http://vk.com)
Info:
lastPending: false
lastDataDate: 2019-04-28T22:40:38.381Z
lastLineDate: 2019-04-28T22:40:38.396Z
lastPushDate: 2019-04-28T22:40:38.397Z
cpErrors:
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
buffer: 01:41:14.668140 IP 149.154.167.
ipError: []
lastIp: { announced: true,
as_country_code: 'US',
as_description: 'DIGITALOCEAN-ASN - DigitalOcean, LLC',
as_number: 14061,
first_ip: '162.243.128.0',
ip: '162.243.151.204',
last_ip: '162.243.159.255' }
Last log: { id: '149.154.167.220', time: 1556491238397, count: 1448 }
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
toLong / fromLong:
https://gist.github.com/monkeym4ster/7eff5843863f2b373a1e
whoIsApi:
https://github.com/jedisct1/iptoasn-webservice