Как автоматически изменять DNS при подключении к Wi-Fi на macOS

Константин Докучаев
Константин Докучаев
Как автоматически изменять DNS при подключении к Wi-Fi на macOS

Если по каким-то причинам вам нужно изменять параметры DNS в зависимости от Wi-Fi сети, то это сделать достаточно легко. Пока вы не пытаетесь настроить это на macOS. На этой операционке сделать автоматическую смену DNS будет не так просто, но всё же можно.

Первое, что вам нужно сделать, — установить приложение Hammerspoon. Это приложение для автоматизации различных действий в macOS, которое позволяет обрабатывать системные API с помощью LUA.

Звучит непонятно, но на самом деле всё достаточно просто. По крайней мере, для нашей задачи.

После установки в Строке меню нажмите на иконку Hammerspoon и выберите пункт Open Config.

Затем скопируйте туда следующий конфиг:

local wifi = hs.wifi
local notify = hs.notify
local timer = hs.timer

local SERVICE_NAME = "Wi-Fi"

local ssidToDns = {
    ["HomeWiFi"]   = {"1.1.1.1", "8.8.8.8"},
    ["OfficeWiFi"] = {"192.168.1.1"},
    ["CoffeeShop"] = "Empty",
}

local function joinDnsList(dnsTable)
    return table.concat(dnsTable, " ")
end

local function setDnsForService(service, dns)
    local cmd
    if type(dns) == "string" and dns:lower() == "empty" then
        cmd = string.format('networksetup -setdnsservers "%s" Empty', service)
    else
        local dnsArgs = joinDnsList(dns)
        cmd = string.format('networksetup -setdnsservers "%s" %s', service, dnsArgs)
    end

    local applescript = string.format('do shell script "%s" with administrator privileges', cmd:gsub('"','\\"'))
    local success, out, raw = hs.osascript.applescript(applescript)
    return success, out
end

local function applyDnsForCurrentNetwork()
    local ssid = wifi.currentNetwork()
    if not ssid then
        notify.new({title="Hammerspoon DNS", informativeText="Нет подключения к Wi-Fi"}):send()
        hs.printf("[autodns] no wifi connection")
        return
    end

    local desired = ssidToDns[ssid]
    if not desired then
        notify.new({title="Hammerspoon DNS", informativeText=string.format("SSID '%s'", ssid)}):send()
        hs.printf("[autodns] ssid '%s' — no rule", ssid)
        return
    end

    hs.printf("[autodns] Applying DNS for SSID '%s' -> %s", ssid, (type(desired)=="table" and joinDnsList(desired) or desired))
    local ok, out = setDnsForService(SERVICE_NAME, desired)
    if ok then
        notify.new({title="Hammerspoon DNS", informativeText=string.format("DNS для '%s' установлен", ssid)}):send()
        hs.printf("[autodns] success: %s", out or "")
    else
        notify.new({title="Hammerspoon DNS", informativeText=string.format("Ошибка при установке DNS для '%s'", ssid)}):send()
        hs.printf("[autodns] failed: %s", tostring(out))
    end
end

local wifiWatcher = nil
wifiWatcher = wifi.watcher.new(function(event)
    -- события: ssidChanged, powerOn, powerOff, scanDone
    hs.timer.doAfter(0.5, function()
        hs.printf("[autodns] wifi event: %s", tostring(event))
        applyDnsForCurrentNetwork()
    end)
end)

wifiWatcher:start()
hs.timer.doAfter(0.5, applyDnsForCurrentNetwork)

hs.alert.show("Auto DNS: ready")

Теперь в нём нужно указать желаемые параметры DNS для каждой Wi-Fi сети. Делается это в блоке:

local ssidToDns = {
    ["HomeWiFi"]   = {"1.1.1.1", "8.8.8.8"},
    ["OfficeWiFi"] = {"192.168.1.1"},
    ["CoffeeShop"] = "Empty",
}

Например, для сети HomeWiFi будут применены параметры 1.1.1.1 и 8.8.8.8.

Теперь остаётся только сохранить скрипт, чтобы при переключении сети автоматически изменялись желаемые параметры DNS.



Great! Next, complete checkout for full access to All-In-One Person
Welcome back! You've successfully signed in
You've successfully subscribed to All-In-One Person
Success! Your account is fully activated, you now have access to all content
Success! Your billing info has been updated
Your billing was not updated