хуйу нас не матерятся
Давайте за пару минут напишем приложуньку на nodejs, которая будет сканировать интернеты в поисках открытых прокси серверов.
После беглого гугления по npmjs.org, я нашел пакетик с подходящим функционалом: portscanner. Из него нам понадобится только функция portscanner.checkPortStatus, и которую нам нужно обернуть в промис:
function Pscan(addr, port) {
return new Promise( function(resolve) {
portscanner.checkPortStatus(port, addr, function(error, status) {
resolve(status);
});
});
}
Наша Pscan будет использоваться в более расширенной функции, которая будет перебирать порты для сканирования и в случае нахождения открытого порта, возвращать его:
async function scan(addr, ports) {
let strAddr = addr.join('.');
let testStart = new Date();
for (let port of ports) {
let status = await Pscan(strAddr, port);
if ( status === 'open' ) {
let testTime = new Date() - testStart;
console.log(colors.green(`${strAddr}:${port} time: ${testTime}`));
return {
addr: strAddr,
port: port,
type: 'HTTP',
time: testTime
};
}
}
let testTime = new Date() - testStart;
console.log(colors.red(`${strAddr} time: ${testTime}`));
return null;
}
Далее нам потребуется немного магии по работе с ИП адресами. Нужны функции: увеличения ип адреса на 1, преобразования строкового адреса в массив байт и из массива байт в инт, для сравнения.
function parseIPv4(str) {
let result = [];
let parts = str.trim().split('.');
if ( parts.length != 4 ) {
return null;
}
for (let part of parts) {
let byte = parseInt(part);
if ( byte < 0 ) {
return null;
}
if ( byte > 255 ) {
return null;
}
result.push(byte);
}
return result;
}
function incIPv4(addr) {
addr[ 3 ]++;
for (let index=3; index>0; index--) {
if ( addr[ index ] > 255 ) {
addr[ index - 1 ]++;
addr[ index ] = 0;
}
}
if ( addr[ 0 ] > 255 ) {
return null;
}
return addr;
}
function Ipv4IntValue(addr) {
return addr[ 3 ] + ( addr[ 2 ] * 255 ) + ( addr[ 1 ] * 255 * 255 ) + +( addr[ 1 ] * 255 * 255 * 255 );
}
И нам остаётся собрать этот пазл воедино, не забыв о псевдопараллелизме, чтобы не приходилось проверять адреса один за другим, а условно, сразу N адресов:
async function main() {
if ( process.argv.length < 5 ) {
console.error(colors.red('Not enough arguments, usage:'));
console.log('node scanner.js ipv4_start_add ipv4_stop_addr out_file.csv [ optional pseudo_threads_count ]');
console.log('Example:');
console.log('node scanner.js 127.0.0.0 127.0.0.1 ./out_file.csv 5');
process.exit(1);
}
const startADDR = parseIPv4(process.argv[ 2 ]);
const stopADDR = parseIPv4(process.argv[ 3 ]);
const dstFile = process.argv[ 4 ];
let pseudoThreads = 1;
if ( process.argv[ 5 ] ) {
pseudoThreads = parseInt(process.argv[ 5 ]);
}
if ( startADDR === null ) {
console.error(colors.red('Wrong start addr: ' + process.argv[ 2 ]));
process.exit(1);
}
if ( stopADDR === null ) {
console.error(colors.red('Wrong stop addr: ' + process.argv[ 3 ]));
process.exit(1);
}
// prepare output file
if ( !fs.existsSync(dstFile) ) {
fs.writeFileSync(dstFile, outHeaders.join(',') + '
', { encoding: 'utf8' });
}
let curAddr = startADDR.map( item => item);
let eof = false;
let addrScanned = 0;
let scanStart = new Date();
while ( !eof ) {
let promises = [];
for (let tc=0; tc<pseudoThreads; tc++) {
addrScanned++;
if ( curAddr === null ) {// The end of IPv4 network
eof = true;
break;
}
if ( Ipv4IntValue(curAddr) > Ipv4IntValue(stopADDR) ) {
eof = true;
break;
}
promises.push(scan(curAddr, defaultPorts));
curAddr = incIPv4(curAddr);
}
let results = await Promise.all(promises);
let outString = '';
for (let result of results) {
if ( result !== null ) {
let cols = [];
for (let header of outHeaders) {
cols.push( result[ header ] );
}
outString += cols.join(',') + '
';
}
}
if ( outString !== '' ) {
fs.writeFileSync(dstFile, outString, { encoding: 'utf8', flag: 'a' });
}
}
console.log('Done!');
console.log('Addressess scaned:', addrScanned, 'scan time:', new Date() - scanStart, 'ms');
process.exit();
}
main();
Ещё чтобы увеличить скорость проверки, мы не будем сканировать все 65к портов на каждом хосте, а просканируем только самые распространённые порты указанные в константе: const defaultPorts = [ 8000, 8080, 8888, 3128 ]
Результаты сканирования выведутся в консоль, а успешные сканы запишутся в .csv файл.
Давайте запустим эту хреновину:
node scanner.js 5.135.100.0 5.135.255.255 ./result.csv 100
За тестовое сканирование было опрошено 39937 адресов, было найдено 2173 открытых порта, и потрачено 647183 ms (~10 минут) времени.
Но это не значит, что на всех этих 2173 хостах работают именно прокси, это всего лиш найденные открытые порты, и даже если часть из них действительно прокси сервера, то они почти со 100% вероятностью закрыты авторизацией. По этому поиск открытых анонимных прокси дело долгое.
Что бы ускорить поиск, можно разбивать диапазоны ИП адресов на блоки и одновременно запускать несколько сканеров.
Готовый проект на гитлабе: https://gitlab.com/hololoev/http_proxy_scanner
Продолжение следует