mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-14 21:20:48 +08:00
Detached tasks spawned on every config generation set and restored the placeholder DNS without ordering, so a set could back up the placeholder itself and a later restore reported success while leaving it in place. Reconcile from the applied config under the lifecycle lock, and restore whenever the core stops. Keep one backup per network service, never back up the placeholder, and restore only while the service still holds it. Scripts verify every read and write and are killed after 5 s. Refs #8070, #8168
63 lines
2.2 KiB
Bash
63 lines
2.2 KiB
Bash
#!/bin/bash
|
|
[ $# -lt 1 ] && echo "Usage: $0 <placeholder IP address>" && exit 1
|
|
|
|
# Prints one value of a SystemConfiguration dictionary, or nothing when the key is absent.
|
|
function sc_value() {
|
|
printf 'show %s\nquit\n' "$1" | scutil | sed -n "s/^ *$2 : //p"
|
|
}
|
|
|
|
# Prints the service's DNS servers, or "empty" when none is set; fails on any other answer.
|
|
function dns_of() {
|
|
local dns line ip='^[0-9A-Fa-f]*[.:][0-9A-Fa-f.:]*(%[[:alnum:]_.-]+)?$'
|
|
dns=$(networksetup -getdnsservers "$1") || return 1
|
|
if [ "$dns" = "There aren't any DNS Servers set on $1." ]; then
|
|
echo "empty"
|
|
return
|
|
fi
|
|
[ -n "$dns" ] || return 1
|
|
while read -r line; do
|
|
[[ $line =~ $ip ]] || return 1
|
|
done <<<"$dns"
|
|
echo "$dns"
|
|
}
|
|
|
|
result=0
|
|
# Older releases kept a single backup for whichever service was primary.
|
|
if [ -f .original_dns.txt ]; then
|
|
service_id=$(sc_value State:/Network/Global/IPv4 PrimaryService)
|
|
if [ -z "$service_id" ] || ! mkdir -p .original_dns; then
|
|
result=1
|
|
elif [ -f ".original_dns/$service_id" ]; then
|
|
rm -f .original_dns.txt || result=1
|
|
elif ! mv .original_dns.txt ".original_dns/$service_id"; then
|
|
result=1
|
|
fi
|
|
fi
|
|
|
|
for backup in .original_dns/*; do
|
|
[ -f "$backup" ] || continue
|
|
hardware_port=$(sc_value "Setup:/Network/Service/${backup##*/}" UserDefinedName)
|
|
# Kept for a service that is gone: there is nothing to write it back to.
|
|
[ -n "$hardware_port" ] || continue
|
|
if ! current_dns=$(dns_of "$hardware_port"); then
|
|
echo "Cannot read DNS servers of $hardware_port." >&2
|
|
result=1
|
|
continue
|
|
fi
|
|
# A service no longer on the placeholder was changed by someone else, and that change stands.
|
|
if [ "$current_dns" = "$1" ]; then
|
|
original_dns=$(cat "$backup") || { result=1; continue; }
|
|
# Older releases could back up the placeholder itself.
|
|
[ "$original_dns" = "$1" ] && original_dns=empty
|
|
networksetup -setdnsservers "$hardware_port" $original_dns
|
|
if [ "$(dns_of "$hardware_port")" != "$original_dns" ]; then
|
|
echo "Failed to restore DNS for $hardware_port." >&2
|
|
result=1
|
|
continue
|
|
fi
|
|
fi
|
|
rm -f "$backup" || result=1
|
|
done
|
|
rmdir .original_dns 2>/dev/null
|
|
exit $result
|