first commit
This commit is contained in:
20
Dockerfile
Normal file
20
Dockerfile
Normal file
@@ -0,0 +1,20 @@
|
||||
# 使用基础镜像(根据需要选择合适的版本)
|
||||
FROM debian:bullseye-slim # 或 ubuntu:22.04
|
||||
|
||||
# 设置非交互模式,避免安装过程中出现交互提示
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# 更新软件源并安装iproute2,同时清理缓存减小镜像体积
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
iproute2 \ # 包含ip命令的工具包
|
||||
&& \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# 可选:设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 可选:添加启动命令
|
||||
CMD ["bash"]
|
||||
|
||||
4
config/index.js
Normal file
4
config/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
port: 9900,
|
||||
command: 'ip -6 addr show enp3s0'
|
||||
}
|
||||
29
index.js
Normal file
29
index.js
Normal file
@@ -0,0 +1,29 @@
|
||||
const { execSync } = require('child_process');
|
||||
const ip = require('./utils/ip');
|
||||
const { port, command } = require('./config');
|
||||
|
||||
const express = require('express')
|
||||
const app = express()
|
||||
|
||||
|
||||
app.get('/ip', async (req, res) => {
|
||||
// let output = execSync(command, { encoding: "utf8" });
|
||||
let output = `2: enp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
|
||||
inet6 240e:362:2245:9b00::68c/128 scope global dynamic noprefixroute
|
||||
valid_lft 24426sec preferred_lft 24426sec
|
||||
inet6 240e:362:2245:9b00:2e0:4cff:fe09:1f7f/64 scope global dynamic mngtmpaddr noprefixroute
|
||||
valid_lft 222142sec preferred_lft 135742sec
|
||||
inet6 240e:362:223c:2800:2e0:4cff:fe09:1f7f/64 scope global dynamic mngtmpaddr noprefixroute
|
||||
valid_lft 221829sec preferred_lft 135429sec
|
||||
inet6 fe80::2e0:4cff:fe09:1f7f/64 scope link
|
||||
valid_lft forever preferred_lft forever`
|
||||
res.json(await ip.parseNetworkInfo(output))
|
||||
})
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`app listening on port: http://127.0.0.1:${port}`)
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
16
package.json
Normal file
16
package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "ipv6",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"express": "^5.1.0"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
"start": "node-dev index.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
||||
117
utils/ip.js
Normal file
117
utils/ip.js
Normal file
@@ -0,0 +1,117 @@
|
||||
const net = require('net');
|
||||
|
||||
class Ip {
|
||||
static async parseNetworkInfo(output) {
|
||||
// 初始化结果对象
|
||||
const result = {
|
||||
interface: '',
|
||||
flags: [],
|
||||
mtu: '',
|
||||
state: '',
|
||||
ipv6Addresses: []
|
||||
};
|
||||
|
||||
// 按行分割输入
|
||||
const lines = output.split('\n').map(line => line.trim());
|
||||
|
||||
// 解析第一行的基本信息
|
||||
if (lines.length > 0) {
|
||||
const firstLineParts = lines[0].split(/\s+/);
|
||||
// 提取接口名称
|
||||
result.interface = firstLineParts[1].replace(':', '');
|
||||
|
||||
// 提取标志
|
||||
if (firstLineParts[2] && firstLineParts[2].startsWith('<') && firstLineParts[2].endsWith('>')) {
|
||||
result.flags = firstLineParts[2].slice(1, -1).split(',');
|
||||
}
|
||||
|
||||
// 提取MTU
|
||||
const mtuIndex = firstLineParts.indexOf('mtu');
|
||||
if (mtuIndex !== -1 && mtuIndex + 1 < firstLineParts.length) {
|
||||
result.mtu = firstLineParts[mtuIndex + 1];
|
||||
}
|
||||
|
||||
// 提取状态
|
||||
const stateIndex = firstLineParts.indexOf('state');
|
||||
if (stateIndex !== -1 && stateIndex + 1 < firstLineParts.length) {
|
||||
result.state = firstLineParts[stateIndex + 1];
|
||||
}
|
||||
}
|
||||
|
||||
// 解析IPv6地址信息
|
||||
let currentIpv6 = null;
|
||||
for (let i = 1; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
if (line.startsWith('inet6')) {
|
||||
// 如果有当前正在处理的IPv6地址,先保存
|
||||
if (currentIpv6) {
|
||||
result.ipv6Addresses.push(currentIpv6);
|
||||
}
|
||||
|
||||
// 开始解析新的IPv6地址
|
||||
const parts = line.split(/\s+/);
|
||||
const ipv6Address = parts[1].split("/")[0]
|
||||
currentIpv6 = {
|
||||
connect: await Ip.checkIPv6WithTcp(ipv6Address),
|
||||
address: parts[1].split("/")[0],
|
||||
scope: parts[2].replace('scope', ''),
|
||||
properties: parts.slice(3),
|
||||
validLft: '',
|
||||
preferredLft: ''
|
||||
};
|
||||
} else if (currentIpv6 && line.includes('valid_lft')) {
|
||||
// 解析有效期信息
|
||||
const lftParts = line.split(/\s+/);
|
||||
currentIpv6.validLft = lftParts[0].replace('valid_lft', '');
|
||||
currentIpv6.preferredLft = lftParts[1].replace('preferred_lft', '');
|
||||
}
|
||||
}
|
||||
|
||||
// 添加最后一个IPv6地址
|
||||
if (currentIpv6) {
|
||||
result.ipv6Addresses.push(currentIpv6);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测IPv6地址是否可访问(通过尝试建立TCP连接)
|
||||
* @param {string} ipv6 - 要检测的IPv6地址
|
||||
* @param {number} port - 目标端口,默认 21100
|
||||
* @param {number} timeout - 超时时间(毫秒),默认1000
|
||||
* @returns {Promise<boolean>} - 是否可访问
|
||||
*/
|
||||
static checkIPv6WithTcp(ipv6, port = 21100, timeout = 1000) {
|
||||
return new Promise((resolve) => {
|
||||
// 验证IPv6格式
|
||||
if (!net.isIPv6(ipv6)) {
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const socket = new net.Socket({ family: 6 }); // 指定IPv6
|
||||
|
||||
// 设置超时
|
||||
const timer = setTimeout(() => {
|
||||
socket.destroy();
|
||||
resolve(false);
|
||||
}, timeout);
|
||||
|
||||
// 尝试连接
|
||||
socket.connect(port, ipv6, () => {
|
||||
clearTimeout(timer);
|
||||
socket.destroy();
|
||||
resolve(true);
|
||||
});
|
||||
|
||||
// 错误处理
|
||||
socket.on('error', () => {
|
||||
clearTimeout(timer);
|
||||
resolve(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Ip
|
||||
Reference in New Issue
Block a user