Compare commits
19 Commits
c864d2e625
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
3a31cd4540
|
|||
|
c876cbedc4
|
|||
|
3bd264f974
|
|||
|
21c3d2e194
|
|||
|
71312297be
|
|||
|
58b8cf3bdc
|
|||
|
38e5654341
|
|||
|
efbcc5a7fb
|
|||
|
20881c1ba4
|
|||
|
ed11b2d15d
|
|||
|
a9ee81c3c4
|
|||
|
e96d3092f5
|
|||
|
b7c9ff1c68
|
|||
|
8b64852e34
|
|||
|
90a9b31d07
|
|||
|
184546335d
|
|||
|
52ea928c86
|
|||
|
3c60b4fe84
|
|||
|
94ef11a0c8
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.env
|
||||||
10
Dockerfile
10
Dockerfile
@@ -1,7 +1,15 @@
|
|||||||
FROM node:lts-alpine
|
FROM node:lts-alpine
|
||||||
USER node
|
USER node
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ENV NODE_ENV production
|
ENV NODE_ENV=production
|
||||||
|
ENV TZ=Europe/Warsaw
|
||||||
COPY --chown=node:node index.mjs ./
|
COPY --chown=node:node index.mjs ./
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
CMD ["node", "./index.mjs"]
|
CMD ["node", "./index.mjs"]
|
||||||
|
|
||||||
|
HEALTHCHECK \
|
||||||
|
--interval=10s \
|
||||||
|
--timeout=5s \
|
||||||
|
--start-period=3s \
|
||||||
|
--retries=3 \
|
||||||
|
CMD ["wget", "http://localhost:3000/health", "-O", "/dev/null", "-q"]
|
||||||
|
|||||||
24
LICENSE
Normal file
24
LICENSE
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <https://unlicense.org/>
|
||||||
101
index.mjs
101
index.mjs
@@ -1,23 +1,100 @@
|
|||||||
import { createServer } from 'node:http';
|
import { createServer } from 'node:http';
|
||||||
import { clearInterval, setInterval } from 'node:timers';
|
import { setTimeout } from 'node:timers';
|
||||||
|
|
||||||
|
const msg = 'Relax, take it easy! For there is nothing that we can do.';
|
||||||
|
const minDelayMs = 3000;
|
||||||
|
const maxDelayMs = 6000;
|
||||||
|
const delayDiff = maxDelayMs - minDelayMs;
|
||||||
|
const randomDelay = () => Math.floor(Math.random() * delayDiff + minDelayMs);
|
||||||
|
const ipNextReportDateMap = new Map();
|
||||||
|
|
||||||
const server = createServer((req, res) => {
|
const server = createServer((req, res) => {
|
||||||
|
const connOpenDate = new Date();
|
||||||
|
const endpoint = `${req.method} ${req.url}`;
|
||||||
|
|
||||||
|
if (endpoint === 'GET /health') {
|
||||||
|
res.statusCode = 200;
|
||||||
|
return res.end('OK\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
const ip = req.headers['x-forwarded-for'];
|
||||||
|
const userAgent = req.headers['user-agent'];
|
||||||
|
const host = req.headers['x-forwarded-host'];
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`Caught ${req.headers['x-forwarded-for']} on ${req.method} ${req.url}`
|
`${ip} (${userAgent}) targeted ${host} on ${endpoint}`
|
||||||
);
|
);
|
||||||
|
|
||||||
let msg = ':) you are an idiot hahahahaha :)';
|
|
||||||
let charIdx = 0;
|
let charIdx = 0;
|
||||||
let intervalId = setInterval(() => {
|
|
||||||
if (charIdx === msg.length) {
|
const hang = () => {
|
||||||
charIdx = 0;
|
if (res.closed) return;
|
||||||
res.write('\n');
|
else if (charIdx === msg.length) res.end('\n');
|
||||||
} else {
|
else res.write(msg[charIdx++]);
|
||||||
res.write(msg[charIdx++]);
|
|
||||||
}
|
|
||||||
}, 3000);
|
|
||||||
|
|
||||||
res.once('close', () => clearInterval(intervalId));
|
setTimeout(hang, randomDelay());
|
||||||
|
};
|
||||||
|
|
||||||
|
hang();
|
||||||
|
|
||||||
|
res.once('close', async () => {
|
||||||
|
const connCloseDate = new Date();
|
||||||
|
const diffText = new Date(connCloseDate - connOpenDate)
|
||||||
|
.toISOString()
|
||||||
|
.substring(14, 19);
|
||||||
|
|
||||||
|
const nextIpReportDate = ipNextReportDateMap.get(ip) || connCloseDate;
|
||||||
|
const hangResult =
|
||||||
|
charIdx === msg.length ? 'received the message' : 'aborted connection';
|
||||||
|
|
||||||
|
console.log(`${ip} ${hangResult} after ${diffText}`);
|
||||||
|
|
||||||
|
if (connCloseDate < nextIpReportDate) return;
|
||||||
|
|
||||||
|
const queryParams = new URLSearchParams();
|
||||||
|
|
||||||
|
queryParams.append('ip', ip);
|
||||||
|
queryParams.append('categories', '15,21');
|
||||||
|
queryParams.append('timestamp', connOpenDate.toISOString());
|
||||||
|
queryParams.append(
|
||||||
|
'comment',
|
||||||
|
`Vulnerability scanner detected!\nUser-Agent: ${userAgent}\nEndpoint: ${endpoint}`
|
||||||
|
);
|
||||||
|
|
||||||
|
const abuseIpDbRes = await fetch(
|
||||||
|
`https://api.abuseipdb.com/api/v2/report?${queryParams.toString()}`,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Key': process.env.ABUSEIPDB_API_KEY,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (abuseIpDbRes.ok) {
|
||||||
|
const reportDate = new Date();
|
||||||
|
|
||||||
|
console.log(`${ip} has been reported!`);
|
||||||
|
ipNextReportDateMap.set(
|
||||||
|
ip,
|
||||||
|
new Date(
|
||||||
|
reportDate.getFullYear(),
|
||||||
|
reportDate.getMonth(),
|
||||||
|
reportDate.getDate() + 1,
|
||||||
|
reportDate.getHours(),
|
||||||
|
reportDate.getMinutes(),
|
||||||
|
reportDate.getSeconds()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
`Failed to report ${ip}: ${abuseIpDbRes.status} ${abuseIpDbRes.statusText}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
server.listen(3000);
|
server.listen(3000);
|
||||||
|
|
||||||
|
process.on('SIGTERM', () => server.close());
|
||||||
|
|||||||
Reference in New Issue
Block a user