diff --git a/podkop/files/usr/bin/podkop b/podkop/files/usr/bin/podkop index 5b347859..6f07bda1 100755 --- a/podkop/files/usr/bin/podkop +++ b/podkop/files/usr/bin/podkop @@ -436,7 +436,7 @@ get_remote_ruleset_update_interval() { } capture_reload_state() { - config_load "$PODKOP_CONFIG" + config_load "$PODKOP_CONFIG_NAME" RELOAD_STATE_RESTART_SIGNATURE="$(build_restart_signature)" RELOAD_STATE_DNSMASQ_SIGNATURE="$(build_dnsmasq_signature)" RELOAD_STATE_SING_BOX_SIGNATURE="$(build_sing_box_signature)" @@ -1030,7 +1030,7 @@ reload() { [ "$reload_reason" = "on_config_change" ] || force_runtime_reload=1 migration - config_load "$PODKOP_CONFIG" + config_load "$PODKOP_CONFIG_NAME" check_requirements config_foreach process_validate_rule "rule" ensure_runtime_dirs @@ -1088,11 +1088,10 @@ reload() { needs_zapret_restart=1 fi - if [ "$RELOAD_STATE_DNSMASQ_SIGNATURE" != "$previous_dnsmasq_signature" ] && - [ "$RELOAD_STATE_DONT_TOUCH_DHCP" != "$previous_dont_touch_dhcp" ]; then + if [ "$RELOAD_STATE_DNSMASQ_SIGNATURE" != "$previous_dnsmasq_signature" ]; then if [ "$RELOAD_STATE_DONT_TOUCH_DHCP" -eq 0 ]; then needs_dnsmasq_configure=1 - else + elif [ "$previous_dont_touch_dhcp" = "0" ]; then needs_dnsmasq_restore=1 fi fi @@ -1790,8 +1789,153 @@ backup_dnsmasq_config_option() { fi } +list_has_item() { + local list="$1" + local needle="$2" + local item + + for item in $list; do + [ "$item" = "$needle" ] && return 0 + done + + return 1 +} + +uci_add_list_unique() { + local package="$1" + local section="$2" + local option="$3" + local value="$4" + local current_values + + current_values="$(uci_get "$package" "$section" "$option")" + list_has_item "$current_values" "$value" && return 0 + + uci_add_list "$package" "$section" "$option" "$value" +} + +backup_dnsmasq_config_list_option() { + local key="$1" + local backup_key="$2" + local value + + for value in $(uci_get "dhcp" "@dnsmasq[0]" "$key"); do + uci_add_list_unique "dhcp" "@dnsmasq[0]" "$backup_key" "$value" + done +} + +restore_dnsmasq_config_option() { + local key="$1" + local backup_key="$2" + local default_value="${3:-}" + local value + + value="$(uci_get "dhcp" "@dnsmasq[0]" "$backup_key")" + if [ -n "$value" ]; then + uci_set "dhcp" "@dnsmasq[0]" "$key" "$value" + uci_remove "dhcp" "@dnsmasq[0]" "$backup_key" + elif [ -n "$default_value" ]; then + uci_set "dhcp" "@dnsmasq[0]" "$key" "$default_value" + else + uci_remove "dhcp" "@dnsmasq[0]" "$key" + fi +} + +restore_dnsmasq_config_list_option() { + local key="$1" + local backup_key="$2" + local value + + uci_remove "dhcp" "@dnsmasq[0]" "$key" + for value in $(uci_get "dhcp" "@dnsmasq[0]" "$backup_key"); do + uci_add_list "dhcp" "@dnsmasq[0]" "$key" "$value" + done + uci_remove "dhcp" "@dnsmasq[0]" "$backup_key" +} + +dnsmasq_server_list_has_podkop_dns() { + local server_list="$1" + local server + + for server in $server_list; do + [ "$server" = "$SB_DNS_INBOUND_ADDRESS" ] && return 0 + done + + return 1 +} + +dnsmasq_default_has_podkop_dns() { + dnsmasq_server_list_has_podkop_dns "$(uci_get "dhcp" "@dnsmasq[0]" "server")" +} + +dnsmasq_split_has_podkop_dns() { + dnsmasq_server_list_has_podkop_dns "$(uci_get "dhcp" "$PODKOP_DNSMASQ_SECTION" "server")" +} + dnsmasq_has_podkop_dns() { - uci -q show dhcp | grep -F ".server='$SB_DNS_INBOUND_ADDRESS'" >/dev/null 2>&1 + dnsmasq_split_has_podkop_dns || dnsmasq_default_has_podkop_dns +} + +dnsmasq_restore_default_instance() { + local server_list backup_servers server legacy_global_dns noresolv cachesize + + server_list="$(uci_get "dhcp" "@dnsmasq[0]" "server")" + backup_servers="$(uci_get "dhcp" "@dnsmasq[0]" "podkop_server")" + legacy_global_dns=0 + dnsmasq_server_list_has_podkop_dns "$server_list" && legacy_global_dns=1 + + uci_remove "dhcp" "@dnsmasq[0]" "server" + if [ -n "$backup_servers" ]; then + for server in $backup_servers; do + uci_add_list "dhcp" "@dnsmasq[0]" "server" "$server" + done + uci_remove "dhcp" "@dnsmasq[0]" "podkop_server" + else + for server in $server_list; do + [ "$server" = "$SB_DNS_INBOUND_ADDRESS" ] && continue + uci_add_list "dhcp" "@dnsmasq[0]" "server" "$server" + done + fi + + noresolv="$(uci_get "dhcp" "@dnsmasq[0]" "podkop_noresolv")" + if [ -n "$noresolv" ]; then + restore_dnsmasq_config_option "noresolv" "podkop_noresolv" + elif [ "$legacy_global_dns" -eq 1 ]; then + uci_set "dhcp" "@dnsmasq[0]" "noresolv" 0 + fi + + cachesize="$(uci_get "dhcp" "@dnsmasq[0]" "podkop_cachesize")" + if [ -n "$cachesize" ]; then + restore_dnsmasq_config_option "cachesize" "podkop_cachesize" + elif [ "$legacy_global_dns" -eq 1 ]; then + uci_set "dhcp" "@dnsmasq[0]" "cachesize" 150 + fi +} + +dnsmasq_configure_split_instance() { + local source_network_interfaces interface + + config_get source_network_interfaces "settings" "source_network_interfaces" "br-lan" + + backup_dnsmasq_config_list_option "notinterface" "podkop_notinterface" + for interface in $source_network_interfaces; do + uci_add_list_unique "dhcp" "@dnsmasq[0]" "notinterface" "$interface" + done + + uci -q delete "dhcp.$PODKOP_DNSMASQ_SECTION" + uci set "dhcp.$PODKOP_DNSMASQ_SECTION=dnsmasq" + uci_set "dhcp" "$PODKOP_DNSMASQ_SECTION" "noresolv" 1 + uci_set "dhcp" "$PODKOP_DNSMASQ_SECTION" "cachesize" 0 + uci_add_list "dhcp" "$PODKOP_DNSMASQ_SECTION" "server" "$SB_DNS_INBOUND_ADDRESS" + + for interface in $source_network_interfaces; do + uci_add_list "dhcp" "$PODKOP_DNSMASQ_SECTION" "interface" "$interface" + done +} + +dnsmasq_restore_split_instance() { + uci -q delete "dhcp.$PODKOP_DNSMASQ_SECTION" + restore_dnsmasq_config_list_option "notinterface" "podkop_notinterface" } dnsmasq_configure() { @@ -1799,7 +1943,7 @@ dnsmasq_configure() { local shutdown_correctly config_get shutdown_correctly "settings" "shutdown_correctly" if [ "$force" != "force" ] && [ "$shutdown_correctly" -eq 0 ]; then - if dnsmasq_has_podkop_dns; then + if dnsmasq_split_has_podkop_dns; then log "Previous shutdown of podkop was not correct, dnsmasq is already configured" return 0 fi @@ -1807,24 +1951,16 @@ dnsmasq_configure() { log "Previous shutdown of podkop was not correct, but dnsmasq is not configured. Applying Podkop DNS settings" fi - log "Backup dnsmasq configuration" - current_servers="$(uci_get "dhcp" "@dnsmasq[0]" "server")" - if [ -n "$current_servers" ]; then - for server in $(uci_get "dhcp" "@dnsmasq[0]" "server"); do - if ! [ "$server" == "$SB_DNS_INBOUND_ADDRESS" ]; then - uci_add_list "dhcp" "@dnsmasq[0]" "podkop_server" "$server" - fi - done - uci_remove "dhcp" "@dnsmasq[0]" "server" - fi - - backup_dnsmasq_config_option "noresolv" "podkop_noresolv" - backup_dnsmasq_config_option "cachesize" "podkop_cachesize" - log "Configure dnsmasq for sing-box" - uci_add_list "dhcp" "@dnsmasq[0]" "server" "$SB_DNS_INBOUND_ADDRESS" - uci_set "dhcp" "@dnsmasq[0]" "noresolv" 1 - uci_set "dhcp" "@dnsmasq[0]" "cachesize" 0 + if dnsmasq_split_has_podkop_dns; then + log "Refreshing existing interface-scoped Podkop DNS settings" + dnsmasq_restore_split_instance + fi + if dnsmasq_default_has_podkop_dns; then + log "Migrating legacy global dnsmasq DNS settings to interface-scoped Podkop DNS" + dnsmasq_restore_default_instance + fi + dnsmasq_configure_split_instance uci_commit "dhcp" /etc/init.d/dnsmasq restart @@ -1844,45 +1980,8 @@ dnsmasq_restore() { log "Previous shutdown of podkop was correct, but Podkop DNS is still present. Restoring dnsmasq" fi - local cachesize noresolv backup_servers resolvfile - log "Restoring cachesize" "debug" - cachesize="$(uci_get "dhcp" "@dnsmasq[0]" "podkop_cachesize")" - if [ -z "$cachesize" ]; then - uci_remove "dhcp" "@dnsmasq[0]" "cachesize" - uci_set "dhcp" "@dnsmasq[0]" "cachesize" 150 - else - uci_set "dhcp" "@dnsmasq[0]" "cachesize" "$cachesize" - uci_remove "dhcp" "@dnsmasq[0]" "podkop_cachesize" - fi - - log "Restoring noresolv" "debug" - noresolv="$(uci_get "dhcp" "@dnsmasq[0]" "podkop_noresolv")" - if [ -z "$noresolv" ]; then - uci_set "dhcp" "@dnsmasq[0]" "noresolv" 0 - else - uci_set "dhcp" "@dnsmasq[0]" "noresolv" "$noresolv" - uci_remove "dhcp" "@dnsmasq[0]" "podkop_noresolv" - fi - - log "Restoring DNS servers" "debug" - uci_remove "dhcp" "@dnsmasq[0]" "server" - resolvfile="/tmp/resolv.conf.d/resolv.conf.auto" - backup_servers="$(uci_get "dhcp" "@dnsmasq[0]" "podkop_server")" - if [ -n "$backup_servers" ]; then - for server in $backup_servers; do - uci_add_list "dhcp" "@dnsmasq[0]" "server" "$server" - done - uci_remove "dhcp" "@dnsmasq[0]" "podkop_server" - elif file_exists "$resolvfile"; then - log "Backup DNS servers not found, using default resolvfile" "debug" - uci_set "dhcp" "@dnsmasq[0]" "resolvfile" "$resolvfile" - if [ -n "$noresolv" ] && [ "$noresolv" -eq 1 ]; then - log "Disabling noresolv option to use system resolvfile" "debug" - uci_set "dhcp" "@dnsmasq[0]" "noresolv" 0 - fi - else - log "Backup DNS servers and default resolvfile not found, possible resolving issues" "warn" - fi + dnsmasq_restore_split_instance + dnsmasq_restore_default_instance uci_commit "dhcp" @@ -4388,25 +4487,32 @@ check_dns_available() { fi fi - # Check if /etc/config/dhcp has server 127.0.0.42 + # Check if dnsmasq sends only selected source interfaces through Podkop DNS. config_load dhcp - config_foreach check_dhcp_has_podkop_dns dnsmasq - config_load "$PODKOP_CONFIG" + check_dhcp_has_podkop_dns + config_load "$PODKOP_CONFIG_NAME" echo "{\"dns_type\":\"$dns_type\",\"dns_server\":\"$display_dns_server\",\"dns_status\":$dns_status,\"dns_on_router\":$dns_on_router,\"bootstrap_dns_server\":\"$bootstrap_dns_server\",\"bootstrap_dns_status\":$bootstrap_dns_status,\"dhcp_config_status\":$dhcp_config_status}" | jq . } check_dhcp_has_podkop_dns() { - local server_list cachesize noresolv server_found - config_get server_list "$1" "server" - config_get cachesize "$1" "cachesize" - config_get noresolv "$1" "noresolv" + local source_network_interfaces podkop_interfaces default_notinterfaces server_list cachesize noresolv + local server server_found interface + + source_network_interfaces="$(uci_get "$PODKOP_CONFIG_NAME" "settings" "source_network_interfaces")" + [ -n "$source_network_interfaces" ] || source_network_interfaces="br-lan" + + server_list="$(uci_get "dhcp" "$PODKOP_DNSMASQ_SECTION" "server")" + cachesize="$(uci_get "dhcp" "$PODKOP_DNSMASQ_SECTION" "cachesize")" + noresolv="$(uci_get "dhcp" "$PODKOP_DNSMASQ_SECTION" "noresolv")" + podkop_interfaces="$(uci_get "dhcp" "$PODKOP_DNSMASQ_SECTION" "interface")" + default_notinterfaces="$(uci_get "dhcp" "@dnsmasq[0]" "notinterface")" server_found=0 if [ -n "$server_list" ]; then for server in $server_list; do - if [ "$server" = "127.0.0.42" ]; then + if [ "$server" = "$SB_DNS_INBOUND_ADDRESS" ]; then server_found=1 break fi @@ -4415,6 +4521,19 @@ check_dhcp_has_podkop_dns() { if [ "$cachesize" != "0" ] || [ "$noresolv" != "1" ] || [ "$server_found" != "1" ]; then dhcp_config_status=0 + return 0 + fi + + for interface in $source_network_interfaces; do + if ! list_has_item "$podkop_interfaces" "$interface" || + ! list_has_item "$default_notinterfaces" "$interface"; then + dhcp_config_status=0 + return 0 + fi + done + + if dnsmasq_default_has_podkop_dns; then + dhcp_config_status=0 fi }