mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-31 02:05:13 +08:00
🍓 Sync 2026-09-15 02:13:06
This commit is contained in:
1 parent
0e5393594c
commit
1dd96ac2bb
146 files changed
+26541
-508
No files matched your search
@@ -0,0 +1,15 @@
|
||||
|
||||
config global 'settings'
|
||||
option mode 'router'
|
||||
|
||||
config backup 'router_state'
|
||||
option lan_proto 'static'
|
||||
option lan_ipaddr '192.168.1.1'
|
||||
option lan_netmask '255.255.255.0'
|
||||
option lan_gateway ''
|
||||
list lan_dns ''
|
||||
option dhcp_ignore '0'
|
||||
option wan_device ''
|
||||
option wan_disabled '0'
|
||||
option wan6_disabled '0'
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ "$1" = "bound" ] || exit 0
|
||||
|
||||
echo "$ip" > /tmp/ap_switch_probed_ip
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"admin/services/ap_switch": {
|
||||
"title": "AP Switch",
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "ap-switch/ap-switch"
|
||||
},
|
||||
"order": 90,
|
||||
"depends": {
|
||||
"acl": [ "luci-app-ap-switch" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"luci-app-ap-switch": {
|
||||
"description": "ACL for AP Switch",
|
||||
"read": {
|
||||
"uci": [ "ap-switch", "network", "dhcp" ],
|
||||
"ubus": {
|
||||
"luci.ap-switch": [ "get_status", "probe_ip" ],
|
||||
"network.interface": [ "dump" ],
|
||||
"network.device": [ "status" ]
|
||||
}
|
||||
},
|
||||
"write": {
|
||||
"uci": [ "ap-switch", "network", "dhcp" ],
|
||||
"ubus": {
|
||||
"luci.ap-switch": [ "set_mode" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
'use strict';
|
||||
|
||||
import { cursor } from 'uci';
|
||||
import { connect } from 'ubus';
|
||||
import { readfile, unlink } from 'fs';
|
||||
|
||||
const UCI_CONFIG = 'ap-switch';
|
||||
const PROBE_FILE = '/tmp/ap_switch_probed_ip';
|
||||
|
||||
const methods = {
|
||||
get_status: {
|
||||
call: function() {
|
||||
let uci_cursor = cursor();
|
||||
let mode = uci_cursor.get(UCI_CONFIG, 'settings', 'mode') || 'router';
|
||||
|
||||
let lan_proto = uci_cursor.get('network', 'lan', 'proto') || 'static';
|
||||
let lan_ip = ''; // We will get the real-time IP
|
||||
|
||||
let ubus_conn = connect();
|
||||
let lan_mac = '';
|
||||
let wan_mac = '';
|
||||
let wan_ip = '';
|
||||
|
||||
if (ubus_conn) {
|
||||
// 1. Get real-time LAN IP and MAC
|
||||
let lan_status = ubus_conn.call('network.interface.lan', 'status');
|
||||
if (lan_status && type(lan_status['ipv4-address']) === 'array' && length(lan_status['ipv4-address']) > 0) {
|
||||
lan_ip = lan_status['ipv4-address'][0].address;
|
||||
}
|
||||
|
||||
let lan_dev = ubus_conn.call('network.device', 'status', { name: 'br-lan' });
|
||||
lan_mac = lan_dev?.macaddr || '';
|
||||
|
||||
// 2. Get current WAN interface status and its physical device MAC
|
||||
let wan_status = ubus_conn.call('network.interface.wan', 'status');
|
||||
let wan_device_name = wan_status?.device || '';
|
||||
if (wan_device_name) {
|
||||
let wan_dev = ubus_conn.call('network.device', 'status', { name: wan_device_name });
|
||||
wan_mac = wan_dev?.macaddr || '';
|
||||
}
|
||||
|
||||
// 3. Get current WAN IP
|
||||
if (wan_status && type(wan_status['ipv4-address']) === 'array' && length(wan_status['ipv4-address']) > 0) {
|
||||
wan_ip = wan_status['ipv4-address'][0].address;
|
||||
}
|
||||
ubus_conn.disconnect();
|
||||
}
|
||||
|
||||
let probed_ip = rtrim(readfile(PROBE_FILE) || '');
|
||||
|
||||
return {
|
||||
mode: mode,
|
||||
lan_proto: lan_proto,
|
||||
lan_ip: lan_ip,
|
||||
lan_mac: lan_mac,
|
||||
wan_mac: wan_mac,
|
||||
wan_ip: wan_ip,
|
||||
probed_ip: probed_ip
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
probe_ip: {
|
||||
call: function() {
|
||||
unlink(PROBE_FILE);
|
||||
// Run udhcpc on br-lan with a short timeout and our probe script
|
||||
// -n: exit if no lease
|
||||
// -q: quit after obtaining lease
|
||||
// -t 3: send 3 discover packets
|
||||
// -T 2: pause 2 seconds between packets
|
||||
let rc = system('udhcpc -i br-lan -n -q -t 3 -T 2 -s /usr/share/luci-app-ap-switch/dhcp-probe.sh >/dev/null 2>&1');
|
||||
|
||||
let ip = rtrim(readfile(PROBE_FILE) || '');
|
||||
return { success: (rc === 0), ip: ip };
|
||||
}
|
||||
},
|
||||
|
||||
set_mode: {
|
||||
args: { mode: 'string' },
|
||||
call: function(request) {
|
||||
let target_mode = request.args?.mode;
|
||||
if (target_mode !== 'router' && target_mode !== 'ap') {
|
||||
return { error: 'Invalid mode' };
|
||||
}
|
||||
|
||||
let uci_cursor = cursor();
|
||||
let current_mode = uci_cursor.get(UCI_CONFIG, 'settings', 'mode') || 'router';
|
||||
|
||||
if (target_mode === current_mode) {
|
||||
return { result: 'Already in target mode' };
|
||||
}
|
||||
|
||||
if (target_mode === 'ap') {
|
||||
// --- Switch to AP Mode (Full Lossless Snapshot) ---
|
||||
|
||||
// 1. Identify WAN device
|
||||
let wan_device = uci_cursor.get('network', 'wan', 'device');
|
||||
if (!wan_device) {
|
||||
wan_device = uci_cursor.get('network', 'wan', 'ifname');
|
||||
}
|
||||
|
||||
// 2. Full Snapshot Backup of Router Mode state
|
||||
let lan_proto = uci_cursor.get('network', 'lan', 'proto') || 'static';
|
||||
let lan_ipaddr = uci_cursor.get('network', 'lan', 'ipaddr') || '';
|
||||
let lan_netmask = uci_cursor.get('network', 'lan', 'netmask') || '';
|
||||
let lan_gateway = uci_cursor.get('network', 'lan', 'gateway') || '';
|
||||
let lan_dns = uci_cursor.get('network', 'lan', 'dns') || [];
|
||||
let dhcp_ignore = uci_cursor.get('dhcp', 'lan', 'ignore') || '0';
|
||||
let wan_disabled = uci_cursor.get('network', 'wan', 'disabled') || '0';
|
||||
let wan6_disabled = uci_cursor.get('network', 'wan6', 'disabled') || '0';
|
||||
|
||||
uci_cursor.set(UCI_CONFIG, 'router_state', 'lan_proto', lan_proto);
|
||||
uci_cursor.set(UCI_CONFIG, 'router_state', 'lan_ipaddr', lan_ipaddr);
|
||||
uci_cursor.set(UCI_CONFIG, 'router_state', 'lan_netmask', lan_netmask);
|
||||
uci_cursor.set(UCI_CONFIG, 'router_state', 'lan_gateway', lan_gateway);
|
||||
uci_cursor.set(UCI_CONFIG, 'router_state', 'lan_dns', lan_dns);
|
||||
uci_cursor.set(UCI_CONFIG, 'router_state', 'dhcp_ignore', dhcp_ignore);
|
||||
uci_cursor.set(UCI_CONFIG, 'router_state', 'wan_device', wan_device || '');
|
||||
uci_cursor.set(UCI_CONFIG, 'router_state', 'wan_disabled', wan_disabled);
|
||||
uci_cursor.set(UCI_CONFIG, 'router_state', 'wan6_disabled', wan6_disabled);
|
||||
uci_cursor.set(UCI_CONFIG, 'settings', 'mode', 'ap');
|
||||
|
||||
// 3. Bridge WAN device to LAN bridge
|
||||
if (wan_device) {
|
||||
uci_cursor.foreach('network', 'device', (s) => {
|
||||
if (s.name === 'br-lan') {
|
||||
let ports = s.ports || [];
|
||||
if (type(ports) === 'string') ports = [ports];
|
||||
let exists = false;
|
||||
for (let p in ports) if (p === wan_device) exists = true;
|
||||
if (!exists) {
|
||||
push(ports, wan_device);
|
||||
uci_cursor.set('network', s['.name'], 'ports', ports);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 4. Set LAN to DHCP client
|
||||
uci_cursor.set('network', 'lan', 'proto', 'dhcp');
|
||||
uci_cursor.delete('network', 'lan', 'ipaddr');
|
||||
uci_cursor.delete('network', 'lan', 'netmask');
|
||||
uci_cursor.delete('network', 'lan', 'gateway');
|
||||
uci_cursor.delete('network', 'lan', 'dns');
|
||||
|
||||
// 5. Disable WAN interface
|
||||
uci_cursor.set('network', 'wan', 'disabled', '1');
|
||||
uci_cursor.set('network', 'wan6', 'disabled', '1');
|
||||
|
||||
// 6. Disable DHCP Server
|
||||
uci_cursor.set('dhcp', 'lan', 'ignore', '1');
|
||||
|
||||
} else {
|
||||
// --- Switch to Router Mode (Lossless State Restoration) ---
|
||||
|
||||
// 1. Read Snapshot
|
||||
let wan_device = uci_cursor.get(UCI_CONFIG, 'router_state', 'wan_device');
|
||||
let lan_proto = uci_cursor.get(UCI_CONFIG, 'router_state', 'lan_proto') || 'static';
|
||||
let lan_ipaddr = uci_cursor.get(UCI_CONFIG, 'router_state', 'lan_ipaddr') || '192.168.1.1';
|
||||
let lan_netmask = uci_cursor.get(UCI_CONFIG, 'router_state', 'lan_netmask') || '';
|
||||
let lan_gateway = uci_cursor.get(UCI_CONFIG, 'router_state', 'lan_gateway') || '';
|
||||
let lan_dns = uci_cursor.get(UCI_CONFIG, 'router_state', 'lan_dns') || [];
|
||||
let dhcp_ignore = uci_cursor.get(UCI_CONFIG, 'router_state', 'dhcp_ignore') || '0';
|
||||
let wan_disabled = uci_cursor.get(UCI_CONFIG, 'router_state', 'wan_disabled') || '0';
|
||||
let wan6_disabled = uci_cursor.get(UCI_CONFIG, 'router_state', 'wan6_disabled') || '0';
|
||||
|
||||
uci_cursor.set(UCI_CONFIG, 'settings', 'mode', 'router');
|
||||
|
||||
// 2. Remove WAN device from LAN bridge
|
||||
if (wan_device) {
|
||||
uci_cursor.foreach('network', 'device', (s) => {
|
||||
if (s.name === 'br-lan') {
|
||||
let ports = s.ports || [];
|
||||
if (type(ports) === 'string') ports = [ports];
|
||||
let new_ports = [];
|
||||
for (let p in ports) if (p !== wan_device) push(new_ports, p);
|
||||
uci_cursor.set('network', s['.name'], 'ports', new_ports);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 3. Restore LAN settings accurately without hardcoding
|
||||
uci_cursor.set('network', 'lan', 'proto', lan_proto);
|
||||
if (lan_ipaddr) uci_cursor.set('network', 'lan', 'ipaddr', lan_ipaddr);
|
||||
if (lan_netmask) uci_cursor.set('network', 'lan', 'netmask', lan_netmask);
|
||||
if (lan_gateway) uci_cursor.set('network', 'lan', 'gateway', lan_gateway);
|
||||
if (type(lan_dns) === 'array' && length(lan_dns) > 0) {
|
||||
uci_cursor.set('network', 'lan', 'dns', lan_dns);
|
||||
} else if (type(lan_dns) === 'string' && lan_dns !== '') {
|
||||
uci_cursor.set('network', 'lan', 'dns', lan_dns);
|
||||
}
|
||||
|
||||
// 4. Restore WAN / WAN6 states
|
||||
if (wan_disabled === '1') {
|
||||
uci_cursor.set('network', 'wan', 'disabled', '1');
|
||||
} else {
|
||||
uci_cursor.delete('network', 'wan', 'disabled');
|
||||
}
|
||||
if (wan6_disabled === '1') {
|
||||
uci_cursor.set('network', 'wan6', 'disabled', '1');
|
||||
} else {
|
||||
uci_cursor.delete('network', 'wan6', 'disabled');
|
||||
}
|
||||
|
||||
// 5. Restore DHCP Server state
|
||||
if (dhcp_ignore === '1') {
|
||||
uci_cursor.set('dhcp', 'lan', 'ignore', '1');
|
||||
} else {
|
||||
uci_cursor.delete('dhcp', 'lan', 'ignore');
|
||||
}
|
||||
}
|
||||
|
||||
uci_cursor.commit('ap-switch');
|
||||
uci_cursor.commit('network');
|
||||
uci_cursor.commit('dhcp');
|
||||
|
||||
// Apply changes in background
|
||||
system('/etc/init.d/network restart &');
|
||||
system('/etc/init.d/dnsmasq restart &');
|
||||
|
||||
return { success: true, result: 'success' };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return { 'luci.ap-switch': methods };
|
||||
Reference in new issue
Block a user