完成该任务需要涉及到以下几个步骤:
- 导入相关模块
- 获取本机IP地址及子网掩码
- 构建IP地址范围
- 扫描IP地址范围
- 发现Web服务器并输出地址
具体实现情况如下:
- 导入相关模块
在开始之前,需要导入以下几个Node.js核心模块:
const os = require('os');
const net = require('net');
const {worker, isMainThread, parentPort} = require('worker_threads');
其中,os模块用于获取本机IP地址和子网掩码,net模块用于建立TCP连接并扫描端口。而worker_threads模块则用于在多线程环境下处理大量扫描任务。
- 获取本机IP地址及子网掩码
为了将扫描限定在局域网范围内,需要先获取本机IP地址和子网掩码。这可以通过os模块提供的网络接口信息来实现:
let interfaces = os.networkInterfaces();
let localAddress, netmask;
Object.keys(interfaces).forEach(name => {
interfaces[name].forEach(ip => {
if (ip.family === 'IPv4' && !ip.internal) {
localAddress = ip.address;
netmask = ip.netmask;
}
});
});
在上述代码中,我们遍历了物理网络接口清单,并选取其中第一个IPv4地址作为本机IP地址。同时,也需要记录选中的网卡的子网掩码,在后续计算IP地址范围时使用。
- 构建IP地址范围
通过本机IP地址和子网掩码,可以计算出本机所在子网内的所有IP地址。为了便于扫描,需要将IP地址转换为十进制数字形式。这里我们使用一个ip2dec
函数来实现这个转换功能:
function ip2dec(addr) {
let parts = addr.split('.');
let dec = 0;
for (let i = 0; i < 4; i++) {
dec += parseInt(parts[i]) << (8 * (3 - i));
}
return dec >>> 0;
}
有了这个函数之后,我们就可以构建IP地址范围了。假设本机IP地址为192.168.0.100
,子网掩码为255.255.255.0
,那么可以通过如下代码计算出IP范围:
let network = ip2dec(localAddress) & ip2dec(netmask);
let min = network + 1;
let max = network | (0xFFFFFFFF ^ ip2dec(netmask));
这里的network
表示子网号,min
和max
分别表示子网内第一个和最后一个可用IP地址。
- 扫描IP地址范围
有了IP地址范围之后,就可以开始扫描指定范围内的IP地址。这里我们使用TCP连接来扫描每个IP地址上的80端口,如果连接成功,则表示该IP地址上有Web服务器。
为了加速扫描速度,我们可以借助worker_threads
模块在多线程环境下同时执行多个扫描任务。具体实现如下:
async function scan(start, end, done) {
if (isMainThread) {
let workerCount = Math.min(end - start, os.cpus().length);
let blockSize = Math.ceil((end - start) / workerCount);
let workers = [];
let result = [];
for (let i = 0; i < workerCount; i++) {
workers.push(new Promise((resolve, reject) => {
let worker = new Worker(__filename, {workerData: {start: start + i * blockSize, end: Math.min(start + (i + 1) * blockSize, end)}});
worker.on('error', reject);
worker.on('message', message => resolve(message));
worker.on('exit', code => {
if (code !== 0) reject(new Error(`Worker exited with code ${code}`));
});
}));
}
Promise.all(workers).then(result => {
done(result.flat());
}).catch(console.error);
return;
}
let results = [];
for (let i = start; i < end; i++) {
let addr = `${(i >>> 24) & 0xFF}.${(i >>> 16) & 0xFF}.${(i >>> 8) & 0xFF}.${i & 0xFF}`;
results.push(await scanPort(addr, 80, 1000));
}
parentPort.postMessage(results.filter(x => x));
}
这个scan
函数可以接受起始IP地址和结束IP地址,并使用worker_threads
模块在多线程环境下执行多个扫描任务。每个扫描任务都使用scanPort
函数来尝试建立TCP80连接并发现Web服务器。如果连接成功,则会返回该IP地址,否则返回null。
- 发现Web服务器并输出地址
有了扫描结果之后,就可以筛选出其中的Web服务器并输出地址了。具体实现如下:
scan(min, max, results => {
let servers = results.filter(x => x);
if (servers.length > 0) {
console.log(`Web servers found (${servers.length}):`);
console.log(servers.join('\n'));
} else {
console.log('No Web servers found.');
}
});
这段代码简单地输出了扫描结果,并将其中的Web服务器地址使用\n
连接为一个长字符串输出。
示例说明1:
假设本地网络中有一台计算机开启了Web服务器并监听了80端口。
运行如下命令即可发现该服务器并输出其IP地址:
$ node scan.js
Web servers found (1):
192.168.0.101
示例说明2:
假设网络中没有开启Web服务器的计算机。
运行如下命令即可输出错误提示:
$ node scan.js
No Web servers found.
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Node.JS中快速扫描端口并发现局域网内的Web服务器地址(80) - Python技术站