Compare commits

...

16 Commits

Author SHA1 Message Date
6d2366d929 更新readme 2024-09-19 12:27:57 +08:00
f10fe2843e 断线重连 2024-09-12 22:39:20 +08:00
bc6936def1 2 2024-08-12 16:03:35 +08:00
107dc62e40 add color 2024-08-12 16:00:55 +08:00
a8857e40d4 test 2024-08-12 15:38:58 +08:00
b27eceb18c test3 2024-08-10 20:43:16 +08:00
54c19ffe9c test 2024-08-10 20:41:34 +08:00
1f9557df61 test 2024-08-10 19:22:26 +08:00
56d28ad939 fix ipread 2024-08-10 17:59:58 +08:00
68b87a9956 add sort 2024-08-05 21:52:58 +08:00
be8a8fc2b5 fix bug 2024-08-05 21:36:45 +08:00
236e781d22 10 2024-08-05 21:31:39 +08:00
ebfc12e8b4 9 2024-08-05 21:27:53 +08:00
70ee170f58 8 2024-08-05 21:24:44 +08:00
71c0f225d0 7 2024-08-05 21:05:25 +08:00
a32e2db264 test6 2024-08-05 21:00:16 +08:00
9 changed files with 100 additions and 49 deletions

4
.gitignore vendored
View File

@@ -174,6 +174,4 @@ dist
# Finder (MacOS) folder config # Finder (MacOS) folder config
.DS_Store .DS_Store
.prettierrc .prettierrc
package-lock.json

View File

@@ -1,9 +1,11 @@
FROM oven/bun:1 FROM oven/bun:latest
WORKDIR /usr/src/app WORKDIR /usr/src/app
COPY . . RUN mkdir -p /config
COPY ./config.json /config COPY ./config.json /config
COPY . .
RUN bun install --frozen-lockfile --production RUN bun install --frozen-lockfile --production
ENV NODE_ENV=production ENV NODE_ENV=production
EXPOSE 7000/tcp EXPOSE 7000/tcp
VOLUME [ "/config"] VOLUME [ "/config"]
ENTRYPOINT [ "bun", "run", "index.ts" ] ENTRYPOINT [ "bun", "run", "index.ts" ]

View File

@@ -1,15 +1,23 @@
# netgate-switch # ROS 网段切换器
To install dependencies: 基于 bun 运行的 RouterOS 网段切换器前/后端。局域网环境下经常使用网段划分不同用途、类型的设备,以便利用 DHCP 下发不同的网关、DNS、NTP 等信息。直接使用 ros 前端或者 winbox 进行修改是个好方法,然而不是所有设备都能方便地登入以及操作(如移动设备),同时对 ros 的完全访问可能带来额外的安全风险。本项目旨在使局域网中各种设备都能快速便捷切换所在网段。
# 使用方法
1.在 ROS 中创建一个可读写账户
2.准备两个网段,如 10.0.0.0/16、10.1.0.0/16。CRID 数字形式表达,仅支持/8 /16 /24。各设备主机号将被保留。
3.安装依赖:
```bash ```bash
bun install bun install
``` ```
To run: 4.运行:
```bash ```bash
bun run index.ts bun run index.ts
``` ```
This project was created using `bun init` in bun v1.1.18. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. 5.填写网关、账密信息登入后即可运行

BIN
bun.lockb

Binary file not shown.

View File

@@ -2,6 +2,7 @@ services:
netgate-switch: netgate-switch:
build: . build: .
pull_policy: build pull_policy: build
container_name: NetgateSwitch
ports: ports:
- '7000:7000' - '7000:7000'
restart: unless-stopped restart: unless-stopped

View File

@@ -1 +1,9 @@
{"port":7000,"login":false,"host":"","user":"","password":"","maincidr":"","proxycidr":""} {
"port": 7000,
"login": false,
"host": "",
"user": "",
"password": "",
"maincidr": "",
"proxycidr": ""
}

View File

@@ -54,6 +54,14 @@
background-color: #dfdfdf; background-color: #dfdfdf;
} }
.device {
background-color: #ffff00;
}
.online {
color: #00ff00;
}
.btn:hover { .btn:hover {
background-color: #b9b9b9; background-color: #b9b9b9;
} }
@@ -144,7 +152,9 @@
tb.append(trn); tb.append(trn);
for (let i in list) { for (let i in list) {
trn = document.createElement('tr'); trn = document.createElement('tr');
trn.setAttribute('class', list[i].device === true ? 'device' : '');
td1 = document.createElement('td'); td1 = document.createElement('td');
td1.setAttribute('class', list[i].status === 'bound' ? 'online' : '');
td2 = document.createElement('td'); td2 = document.createElement('td');
td3 = document.createElement('td'); td3 = document.createElement('td');
td4 = document.createElement('td'); td4 = document.createElement('td');
@@ -158,7 +168,7 @@
btn2.setAttribute('cidrgroup', 'proxy'); btn2.setAttribute('cidrgroup', 'proxy');
btn2.setAttribute('deviceid', list[i].id); btn2.setAttribute('deviceid', list[i].id);
btn2.append('切换至Proxy'); btn2.append('切换至Proxy');
td1.append(list[i].host); td1.append(list[i].comment === undefined ? list[i].host : list[i].comment);
td2.append(list[i].address); td2.append(list[i].address);
td3.append(list[i].mac); td3.append(list[i].mac);
td4.append(btn1); td4.append(btn1);

View File

@@ -4,7 +4,6 @@ import { RouterOSAPI } from 'node-routeros';
const path = '/config/config.json'; const path = '/config/config.json';
const cfgfile = Bun.file(path); const cfgfile = Bun.file(path);
let cfg = await cfgfile.json(); let cfg = await cfgfile.json();
console.log(cfg);
let api = new RouterOSAPI({ let api = new RouterOSAPI({
host: cfg.host, host: cfg.host,
@@ -12,9 +11,8 @@ let api = new RouterOSAPI({
password: cfg.password, password: cfg.password,
}); });
const maincidr = cfg.maincidr; let maincidr = cfg.maincidr;
const proxycidr = cfg.proxycidr; let proxycidr = cfg.proxycidr;
let haslogin = cfg.login; let haslogin = cfg.login;
type Device = { type Device = {
id: string; id: string;
@@ -34,7 +32,7 @@ if (haslogin) {
const server = serve({ const server = serve({
port: cfg.port, port: cfg.port,
async fetch(request) { async fetch(request, server) {
const url = new URL(request.url); const url = new URL(request.url);
if (url.pathname === '/') { if (url.pathname === '/') {
let file = haslogin let file = haslogin
@@ -61,6 +59,8 @@ const server = serve({
data.main, data.main,
data.proxy data.proxy
); );
maincidr = data.main;
proxycidr = data.proxy;
console.log('配置文件已更新'); console.log('配置文件已更新');
return new Response('登入成功'); return new Response('登入成功');
} else { } else {
@@ -71,7 +71,13 @@ const server = serve({
if (url.pathname === '/core/get/') { if (url.pathname === '/core/get/') {
if (!haslogin) if (!haslogin)
return new Response('ROS配置未设置', { status: 401 }); return new Response('ROS配置未设置', { status: 401 });
return new Response(JSON.stringify(await getDHCPList())); const sockaddr = server.requestIP(request);
let ipinfo = sockaddr === null ? '' : sockaddr.address;
let ipaddr = ipinfo.split(':');
console.log(sockaddr);
return new Response(
JSON.stringify(await getDHCPList(ipaddr[ipaddr.length - 1]))
);
} }
if (url.pathname === '/core/switch/') { if (url.pathname === '/core/switch/') {
@@ -99,6 +105,9 @@ const server = serve({
if (group !== 'main' && group !== 'proxy') { if (group !== 'main' && group !== 'proxy') {
return new Response('group错误', { status: 401 }); return new Response('group错误', { status: 401 });
} }
if (maincidr === '' || proxycidr === '') {
return new Response('配置文件错误', { status: 401 });
}
if (await switchNetgate(id, addr, group)) { if (await switchNetgate(id, addr, group)) {
return new Response('切换成功'); return new Response('切换成功');
} else { } else {
@@ -128,18 +137,38 @@ async function connectAPI() {
} }
} }
async function getDHCPList() { async function getDHCPList(addr: string | null) {
const result = await api.write('/ip/dhcp-server/lease/print');
list = []; list = [];
for (let eq in result) { try {
list.push({ const result = await api.write('/ip/dhcp-server/lease/print');
id: result[eq]['.id'], for (let eq in result) {
address: result[eq]['address'], let format = {
mac: result[eq]['mac-address'], id: result[eq]['.id'],
status: result[eq]['status'], address: result[eq]['address'],
host: result[eq]['host-name'], mac: result[eq]['mac-address'],
comment: result[eq]['comment'], status: result[eq]['status'],
host: result[eq]['host-name'],
comment: result[eq]['comment'],
device: false,
};
if (addr !== null || addr !== undefined || addr !== '') {
if (addr === format.address) {
format.device = true;
list.unshift(format);
} else {
list.push(format);
}
continue;
}
list.push(format);
}
} catch (e) {
api = new RouterOSAPI({
host: cfg.host,
user: cfg.user,
password: cfg.password,
}); });
api.connect();
} }
return list; return list;
} }
@@ -150,11 +179,7 @@ async function switchNetgate(id: string, addr: string, group: string) {
let targetcidr = (group === 'proxy' ? proxycidr : maincidr) let targetcidr = (group === 'proxy' ? proxycidr : maincidr)
.split('/')[0] .split('/')[0]
.split('.'); .split('.');
console.log(proxycidr);
console.log(maincidr);
console.log(targetcidr);
let address = addr.split('.'); let address = addr.split('.');
console.log(address);
let num = 2; let num = 2;
if (mask == 16) { if (mask == 16) {
num = 1; num = 1;
@@ -192,7 +217,7 @@ async function writeConfig(
cfg.proxycidr = pcidr; cfg.proxycidr = pcidr;
haslogin = true; haslogin = true;
await Bun.write('/config/config.json', JSON.stringify(cfg)); await Bun.write(path, JSON.stringify(cfg));
} }
async function cleanConfig() { async function cleanConfig() {
@@ -203,5 +228,5 @@ async function cleanConfig() {
cfg.password = ''; cfg.password = '';
cfg.maincidr = ''; cfg.maincidr = '';
cfg.proxycidr = ''; cfg.proxycidr = '';
await Bun.write('/config/config.json', JSON.stringify(cfg)); await Bun.write(path, JSON.stringify(cfg));
} }

View File

@@ -1,18 +1,17 @@
{ {
"name": "netgate-switch", "name": "netgate-switch",
"module": "index.ts", "module": "index.ts",
"devDependencies": { "devDependencies": {
"@types/bun": "latest" "@types/bun": "latest"
}, },
"peerDependencies": { "peerDependencies": {
"typescript": "^5.0.0" "typescript": "^5.0.0"
}, },
"scripts": { "scripts": {
"dev": "bun run index.ts" "dev": "bun run index.ts"
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"netgate-switch": "file:", "node-routeros": "^1.6.9"
"node-routeros": "^1.6.9" }
}
} }