diff --git a/dufs/Makefile b/dufs/Makefile index 1dbbcd39..817aee0b 100644 --- a/dufs/Makefile +++ b/dufs/Makefile @@ -5,8 +5,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=dufs -PKG_VERSION:=0.45.0 -PKG_RELEASE:=1 +PKG_VERSION:=0.46.0 +PKG_RELEASE:=2 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/sigoden/dufs/tar.gz/v$(PKG_VERSION)? diff --git a/hickory-dns/Makefile b/hickory-dns/Makefile index 93e623d0..6a912e8b 100644 --- a/hickory-dns/Makefile +++ b/hickory-dns/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=hickory-dns PKG_VERSION:=0.26.1 -PKG_RELEASE:=20 +PKG_RELEASE:=21 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/hickory-dns/hickory-dns/tar.gz/v$(PKG_VERSION)? diff --git a/hickory-dns/files/etc/init.d/hickory-dns b/hickory-dns/files/etc/init.d/hickory-dns index 01a26e41..52bba064 100755 --- a/hickory-dns/files/etc/init.d/hickory-dns +++ b/hickory-dns/files/etc/init.d/hickory-dns @@ -31,8 +31,3 @@ start_service() { # dynamic DNS entries from the current neighbour table. /etc/init.d/ipv6-neigh restart } - -service_triggers() { - procd_add_reload_trigger "dhcp" "network" "system" - procd_add_reload_interface_trigger "wan_6" -} diff --git a/ipv6-neigh/Makefile b/ipv6-neigh/Makefile index 2e5d74e8..76563328 100644 --- a/ipv6-neigh/Makefile +++ b/ipv6-neigh/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ipv6-neigh PKG_VERSION:=0.1.0 -PKG_RELEASE:=5 +PKG_RELEASE:=6 PKG_BUILD_DEPENDS:=rust/host PKG_BUILD_PARALLEL:=1 diff --git a/ipv6-neigh/files/etc/init.d/ipv6-neigh b/ipv6-neigh/files/etc/init.d/ipv6-neigh index deacd301..33c95722 100644 --- a/ipv6-neigh/files/etc/init.d/ipv6-neigh +++ b/ipv6-neigh/files/etc/init.d/ipv6-neigh @@ -8,7 +8,8 @@ PROG=/usr/bin/ipv6-neigh start_service() { procd_open_instance ipv6-neigh - procd_set_param command $PROG -p -d "[::1]:53" -z lan + # 默认: IPv4 仅私网;IPv6 允许公网(GUA) + procd_set_param command $PROG --private-subnet-v4 -d "[::1]:53" -z lan procd_set_param stdout 1 procd_set_param stderr 1 procd_set_param respawn "${respawn_threshold:-3600}" "${respawn_timeout:-5}" "${respawn_retry:-5}" diff --git a/ipv6-neigh/src/main.rs b/ipv6-neigh/src/main.rs index 6b3a130a..5760d397 100644 --- a/ipv6-neigh/src/main.rs +++ b/ipv6-neigh/src/main.rs @@ -1,12 +1,13 @@ use std::collections::HashMap; -use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr as StdSocketAddr}; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr as StdSocketAddr}; use std::time::Instant; use futures::stream::StreamExt; use futures::stream::TryStreamExt; -use log::{debug, error, info}; +use log::{debug, error, info, warn}; use netlink_packet_core::NetlinkPayload; use netlink_packet_route::RouteNetlinkMessage; +use netlink_packet_route::address::AddressAttribute; use netlink_packet_route::neighbour::NeighbourMessage; use netlink_packet_route::neighbour::{NeighbourAddress, NeighbourAttribute, NeighbourState}; use netlink_packet_route::route::RouteType; @@ -35,8 +36,12 @@ const fn nl_mgrp(group: u32) -> u32 { #[derive(Debug, Parser)] #[clap()] struct Cli { - #[clap(short, long)] - private_subnet: bool, + /// Restrict IPv4 neighbours to private subnets only (10/8, 172.16/12, 192.168/16, 127/8) + #[clap(long)] + private_subnet_v4: bool, + /// Restrict IPv6 neighbours to ULA (fc00::/7) only; without this flag GUA is also included + #[clap(long)] + private_subnet_v6: bool, /// hickory-dns server address for DNS updates (e.g. "[::1]:5335") #[clap(short, long, default_value = "[::1]:5335")] dns_server: StdSocketAddr, @@ -53,8 +58,11 @@ struct Cli { #[clap(short = 'l', long, default_value = "info")] log_level: String, /// Probe interval in seconds for active reachability checks (0 to disable) - #[clap(long, default_value = "120")] + #[clap(long, default_value = "75")] probe_interval: u64, + /// Network interface to read the router's own addresses from + #[clap(long, default_value = "br-lan")] + router_iface: String, } #[derive(Debug)] @@ -68,12 +76,8 @@ struct Neigh { fn if_ipv6_in_private_subnet(ip: &Ipv6Addr) -> bool { // Check if address is ULA (fc00::/7) - let is_ula = (ip.segments()[0] & 0xfe00) == 0xfc00; - - // Check if address is link-local (fe80::/10) - let is_link_local = (ip.segments()[0] & 0xffc0) == 0xfe80; - - is_ula || is_link_local + // Note: link-local is always filtered earlier by is_link_local_ipv6() + (ip.segments()[0] & 0xfe00) == 0xfc00 } fn if_ipv4_in_private_subnet(ip: &Ipv4Addr) -> bool { @@ -177,7 +181,8 @@ async fn main() -> Result<(), ()> { .format_timestamp_secs() .init(); - let private_subnet = args.private_subnet; + let private_subnet_v4 = args.private_subnet_v4; + let private_subnet_v6 = args.private_subnet_v6; let zone = Name::from_ascii(&args.zone).expect("invalid zone name"); let key_data = std::fs::read(&args.key_file) @@ -191,6 +196,24 @@ async fn main() -> Result<(), ()> { let (connection, handle, _) = new_connection().unwrap(); tokio::spawn(connection); + // Register router's own addresses in DNS + let router_hostname = std::fs::read_to_string("/proc/sys/kernel/hostname") + .unwrap_or_default() + .trim() + .to_owned(); + if router_hostname.is_empty() { + warn!("could not read router hostname from /proc/sys/kernel/hostname"); + } else { + register_router_addresses( + handle.clone(), + &args.router_iface, + &router_hostname, + &updater, + private_subnet_v6, + ) + .await; + } + // Load DHCP leases (mac -> hostname) from ubus let mut leases = op::get_lease().unwrap_or_default(); info!("loaded {} DHCP leases", leases.len()); @@ -200,7 +223,7 @@ async fn main() -> Result<(), ()> { // Dump existing neighbours and register only reachable/stale ones debug!("dumping neighbours"); - if let Ok(neighbours) = dump_neighbours(handle.clone(), private_subnet).await { + if let Ok(neighbours) = dump_neighbours(handle.clone(), private_subnet_v4, private_subnet_v6).await { for neigh in &neighbours { debug!("{:?}", neigh); if should_skip_neigh(neigh) || !is_reachable_state(neigh.state) { @@ -260,7 +283,7 @@ async fn main() -> Result<(), ()> { if let NetlinkPayload::InnerMessage(msg) = payload { match msg { RouteNetlinkMessage::NewNeighbour(new_neigh) => { - let Some(neigh) = parse_neighbour_message(new_neigh, private_subnet) else { + let Some(neigh) = parse_neighbour_message(new_neigh, private_subnet_v4, private_subnet_v6) else { continue; }; if should_skip_neigh(&neigh) { @@ -291,7 +314,7 @@ async fn main() -> Result<(), ()> { } } RouteNetlinkMessage::DelNeighbour(del_neigh) => { - let Some(neigh) = parse_neighbour_message(del_neigh, private_subnet) else { + let Some(neigh) = parse_neighbour_message(del_neigh, private_subnet_v4, private_subnet_v6) else { continue; }; if should_skip_neigh(&neigh) { @@ -387,7 +410,7 @@ fn is_link_local_ipv6(addr: &NeighbourAddress) -> bool { matches!(addr, NeighbourAddress::Inet6(ip) if (ip.segments()[0] & 0xffc0) == 0xfe80) } -fn parse_neighbour_message(neigh: NeighbourMessage, private_subnet: bool) -> Option { +fn parse_neighbour_message(neigh: NeighbourMessage, private_subnet_v4: bool, private_subnet_v6: bool) -> Option { let state = neigh.header.state; // Filter out static and incomplete entries if matches!(state, NeighbourState::Permanent | NeighbourState::Noarp) { @@ -401,20 +424,18 @@ fn parse_neighbour_message(neigh: NeighbourMessage, private_subnet: bool) -> Opt if is_link_local_ipv6(&addr) { return None; } - if private_subnet { - match addr { - NeighbourAddress::Inet(addr) => { - if !if_ipv4_in_private_subnet(&addr) { - return None; - } + match addr { + NeighbourAddress::Inet(addr) => { + if private_subnet_v4 && !if_ipv4_in_private_subnet(&addr) { + return None; } - NeighbourAddress::Inet6(addr) => { - if !if_ipv6_in_private_subnet(&addr) { - return None; - } - } - _ => {} } + NeighbourAddress::Inet6(addr) => { + if private_subnet_v6 && !if_ipv6_in_private_subnet(&addr) { + return None; + } + } + _ => {} }; let kind = neigh.header.kind; let ifindex = neigh.header.ifindex; @@ -436,11 +457,11 @@ fn parse_neighbour_message(neigh: NeighbourMessage, private_subnet: bool) -> Opt }) } -async fn dump_neighbours(handle: Handle, private_subnet: bool) -> Result, Error> { +async fn dump_neighbours(handle: Handle, private_subnet_v4: bool, private_subnet_v6: bool) -> Result, Error> { let mut neighbours = handle.neighbours().get().execute(); let mut vec: Vec = Vec::new(); while let Some(route) = neighbours.try_next().await? { - if let Some(neigh) = parse_neighbour_message(route, private_subnet) { + if let Some(neigh) = parse_neighbour_message(route, private_subnet_v4, private_subnet_v6) { if !should_skip_neigh(&neigh) { vec.push(neigh); } @@ -448,3 +469,58 @@ async fn dump_neighbours(handle: Handle, private_subnet: bool) -> Result l, + Ok(None) => { + warn!("interface {} not found, skipping router address registration", iface); + return; + } + Err(e) => { + warn!("failed to find interface {}: {}", iface, e); + return; + } + }; + let ifindex = link.header.index; + let mut addresses = handle.address().get().set_link_index_filter(ifindex).execute(); + while let Ok(Some(msg)) = addresses.try_next().await { + for attr in &msg.attributes { + let ip = match attr { + AddressAttribute::Address(ip) => ip, + _ => continue, + }; + match ip { + IpAddr::V6(addr) => { + // Always skip link-local + if (addr.segments()[0] & 0xffc0) == 0xfe80 { + continue; + } + // Restrict to ULA only when private_subnet_v6 is set + let is_ula = (addr.segments()[0] & 0xfe00) == 0xfc00; + if private_subnet_v6 && !is_ula { + continue; + } + match updater.upsert_aaaa(hostname, *addr, DEFAULT_TTL).await { + Ok(()) => info!("registered router {} AAAA {}", hostname, addr), + Err(e) => warn!("failed to register router AAAA {} for {}: {}", addr, hostname, e), + } + } + IpAddr::V4(addr) => { + match updater.upsert_a(hostname, *addr, DEFAULT_TTL).await { + Ok(()) => info!("registered router {} A {}", hostname, addr), + Err(e) => warn!("failed to register router A {} for {}: {}", addr, hostname, e), + } + } + } + } + } +} diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index f04f6e88..494ab67c 100644 --- a/luci-app-passwall/Makefile +++ b/luci-app-passwall/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall PKG_VERSION:=26.5.3 -PKG_RELEASE:=114 +PKG_RELEASE:=115 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall/luasrc/controller/passwall.lua b/luci-app-passwall/luasrc/controller/passwall.lua index cf591b17..ad5ba05b 100644 --- a/luci-app-passwall/luasrc/controller/passwall.lua +++ b/luci-app-passwall/luasrc/controller/passwall.lua @@ -613,13 +613,17 @@ function delete_select_nodes() uci:delete(appname, t[".name"]) socks = "Socks_" .. t[".name"] end + local changed = false local auto_switch_node_list = uci:get(appname, t[".name"], "autoswitch_backup_node") or {} for i = #auto_switch_node_list, 1, -1 do if w == auto_switch_node_list[i] then table.remove(auto_switch_node_list, i) + changed = true end end - uci:set_list(appname, t[".name"], "autoswitch_backup_node", auto_switch_node_list) + if changed then + uci:set_list(appname, t[".name"], "autoswitch_backup_node", auto_switch_node_list) + end end) local tcp_node = uci:get(appname, "@global[0]", "tcp_node") or "" if tcp_node == w or tcp_node == socks then diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua index baa06527..db2c6d75 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua @@ -186,7 +186,7 @@ if load_balancing_options then -- [[ Load balancing Start ]] o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") end for k1, v1 in pairs(node_list) do - if k1 == "socks_list" or k1 == "normal_list" then + if k1 == "socks_list" or k1 == "normal_list" or k1 == "urltest_list" then for i, v in ipairs(v1) do o:value(v.id, v.remark) o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") diff --git a/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/luci-app-passwall/luasrc/passwall/util_sing-box.lua index ab75bc64..4ab04754 100644 --- a/luci-app-passwall/luasrc/passwall/util_sing-box.lua +++ b/luci-app-passwall/luasrc/passwall/util_sing-box.lua @@ -1267,7 +1267,6 @@ function gen_config(var) else ut_nodes = _node.urltest_node end - if #ut_nodes == 0 then return nil end local valid_nodes = {} for i = 1, #(ut_nodes or {}) do local ut_node_id = ut_nodes[i] diff --git a/luci-app-passwall/root/usr/share/passwall/app.sh b/luci-app-passwall/root/usr/share/passwall/app.sh index 5c08748d..09f5bb6b 100755 --- a/luci-app-passwall/root/usr/share/passwall/app.sh +++ b/luci-app-passwall/root/usr/share/passwall/app.sh @@ -1543,8 +1543,13 @@ start_adblock() { start_haproxy() { [ "$(config_t_get global_haproxy balancing_enable 0)" != "1" ] && return - haproxy_path=$TMP_PATH/haproxy - haproxy_conf="config.cfg" + local haproxy_ver=$($(first_type haproxy) -v 2>/dev/null | awk 'NR==1 {print $3}' | cut -d'-' -f1) + if [ "$(check_ver "$haproxy_ver" "3.0.0")" = "1" ]; then + echolog "* 注意:haproxy($haproxy_ver) 程序版本低,HAPROXY 负载均衡启动失败,请更新到 3.0 以上版本。" + return + fi + local haproxy_path=$TMP_PATH/haproxy + local haproxy_conf="config.cfg" lua $APP_PATH/haproxy.lua -path ${haproxy_path} -conf ${haproxy_conf} -dns ${LOCAL_DNS} ln_run "$(first_type haproxy)" haproxy "/dev/null" -f "${haproxy_path}/${haproxy_conf}" } diff --git a/natflow/Makefile b/natflow/Makefile index f0c69aaf..6143ea46 100644 --- a/natflow/Makefile +++ b/natflow/Makefile @@ -10,12 +10,12 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=natflow PKG_VERSION:=20260313 -PKG_RELEASE:=7 +PKG_RELEASE:=8 PKG_SOURCE:=$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git PKG_SOURCE_PROTO:=git -PKG_SOURCE_VERSION:=9a7789da898a627f3f55f821260f5695bb98f868 +PKG_SOURCE_VERSION:=22c630b387a5ca027bc77d3364818ed87e0a6254 PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_MAINTAINER:=Chen Minqiang PKG_LICENSE:=GPL-2.0 diff --git a/tuic-client/Makefile b/tuic-client/Makefile index 676e5f14..3d3d5fae 100644 --- a/tuic-client/Makefile +++ b/tuic-client/Makefile @@ -5,8 +5,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=tuic-client -PKG_VERSION:=1.7.2 -PKG_RELEASE:=3 +PKG_VERSION:=1.8.1 +PKG_RELEASE:=4 PKG_LICENSE_FILES:=LICENSE PKG_MAINTAINER:=Tianling Shen diff --git a/tun2socks/Makefile b/tun2socks/Makefile index be1f8230..80d0dcfa 100644 --- a/tun2socks/Makefile +++ b/tun2socks/Makefile @@ -2,11 +2,11 @@ include $(TOPDIR)/rules.mk PKG_NAME:=tun2socks PKG_VERSION:=2.6.0 -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/xjasonlyu/tun2socks.git -PKG_SOURCE_VERSION:=1d8af8ed96bc281b81b319193c94305f074e34be +PKG_SOURCE_VERSION:=a9747fa54b2b2bfa6e3411220fd660dcc00acfc1 PKG_MAINTAINER:=Konstantine Shevlakov PKG_LICENSE:=GPL-3.0