Jump to content
  • 0

​Маршрутизация по доменам через DNS прокси (keen-dns-proxy)


belt0ev

Question

Приветствую всех 🙂

Искал способ маршрутизации "на лету", чтобы не нужно было ставить entware пакеты на роутере. Заодно хотел задействовать домашний сервер. Не нашёл ничего готового, поэтому написал своё: так появилась идея dns прокси для обхода блокировок.

Возможности решения:

  • Добавление ip адресов только при фактическом запросе к домену из списка
  • Удаление неактуальных ip адресов
  • Маршрутизация к разным vpn интерфейсам (в зависимости от домена)
  • Указание правил по маске домена (wildcard - куда же без него)

IP адреса добавляются/удаляются на роутере (команда: "ip route <ip> <interface>")

Настройка DNS сервера

Настраивается и запускается буквально за пару минут.

Из требований: нужен docker + compose, и компонент ssh сервера на роутере. Потребление ram: 20-30 Мб.

1. Нужно создать файл docker-compose.yml

version: '3'
services:
  keen-dns-proxy:
    container_name: keen-dns-proxy
    image: belt0ev/keen-dns-proxy
    volumes:
      - /home/home-dns/data:/app/data
    restart: unless-stopped
    privileged: true
    network_mode: host

"network_mode: host" - нужно для того, чтобы у контейнера был доступ к сети хоста, чтобы он мог обращаться к роутеру. В volumes указываете путь к папке data, где будет лежать конфиг и файл с доменами для роутинга.

В принципе, на этом этапе уже можно запустить "docker compose up -d" - сервер начнёт слушать запросы на порту 8053 и резолвить их через сервер Яндекса (77.88.8.8), и создаст пустой файл domains.txt в папке data. Больше ничего делать не будет.

2. Создать файл конфига appsettings.json в папке data

{
  "port": 8053,
  "interface": "Wireguard1",
  "dns": "192.168.1.43:6053",
  
  "ssh": {
    "address": "192.168.1.1",
    "username": "<username>",
    "password": "<password>"
  }
}

Это пример полностью заполненного конфига. Кратко по полям:

  • port - порт, который будет слушать сервер.
    Опциональное поле (можно не указывать, если устраивает порт по умолчанию - 8053)
  • interface - интерфейс в роутере по умолчанию, на который будут перенаправляться запросы.
    Тоже опциональное поле: интерфейсы можно указывать непосредственно в файле domains.txt
    Важно: нужно брать "системное" название интерфейса. Посмотреть можно в cli роутера командой "show interface"
  • dns - DNS сервер, который будет фактически резолвить запросы.
    Можно указать просто ip адрес (тогда будет использоваться порт 53). Если не заполнить, запросы будут резолвиться через сервер Яндекса (77.88.8.8).
    Поддерживает только udp сервера. Я использую adguard home, поэтому тут указываю его адрес.
  • ssh.address - адрес роутера, куда будут отправляться запросы на добавление/удаление ip адресов. Если не заполнить, будет использоваться адрес по умолчанию - 192.168.1.1
  • ssh.username - имя пользователя для ssh подключения.
    Если не заполнить, запросы на обновление ip адресов отправляться не будут
  • ssh.password - пароль для ssh подключения.
    Если не заполнить, запросы на обновление ip адресов отправляться не будут

3. Файл domains.txt

Его можно создать вручную в папке data, либо он будет создан при первом запуске сервера.

Пример заполнения:

# Можно использовать wildcard правила
*kino.pub
*openai*

# Можно указывать непосредственно домен
forum.keenetic.com

# Можно указать любой интерфейс для маппинга 
2ip.ru|Wireguard0
*google.com|Openvpn1

Поддерживаются комментарии (# в начале строки) и пустые строки. Через символ "|" можно указывать интерфейсы, на которые должно маппиться правило.

После обновления файла нужно перезапустить сервер, чтобы изменения подхватились (команда "docker compose restart")

Ответы на вопросы

  • Можно ли указать несколько серверов в поле dns?
    • Нет, поддерживается только один сервер. В целом, несложно добавить поддержку нескольких серверов, но думаю, что у аудитории такого решения уже есть свой adguard home (или pi-hole), где правила настраиваются более гибко, поэтому сервер никак не усложнялся. Кэширования запросов тоже нет (запросы сразу проксируются)
  • Что будет, если я удалю домены из domains.txt? Удалятся ли добавленные правила на роутере?
    • Нет, сервер не отслеживает правила по удаленным доменам из domains.txt. В таком случае можно вручную точечно удалить правила на странице https://192.168.1.1/controlPanel/staticRoutes, либо удалить все правила и папку data/dbcache, и перезапустить сервер.
  • Если я удалю правило для домена на странице https://192.168.1.1/controlPanel/staticRoutes, dns сервер его добавит снова?
    • Желательно не трогать правила, добавленные сервером. Он хранит историю добавленных правил на своей стороне, поэтому не узнает, что правило было удалено, и не добавит его снова.

Напоследок: решение писалось для себя и под свои нужды, поэтому функционал может показаться небольшим. Но его достаточно для организации выборочной маршрутизации.

Link to comment
Share on other sites

2 answers to this question

Recommended Posts

  • 0
40 минут назад, belt0ev сказал:

Приветствую всех 🙂

Искал способ маршрутизации "на лету", чтобы не нужно было ставить entware пакеты на роутере. Заодно хотел задействовать домашний сервер. Не нашёл ничего готового, поэтому написал своё: так появилась идея dns прокси для обхода блокировок.

Возможности решения:

  • Добавление ip адресов только при фактическом запросе к домену из списка
  • Удаление неактуальных ip адресов
  • Маршрутизация к разным vpn интерфейсам (в зависимости от домена)
  • Указание правил по маске домена (wildcard - куда же без него)

IP адреса добавляются/удаляются на роутере (команда: "ip route <ip> <interface>")

Настройка DNS сервера

Настраивается и запускается буквально за пару минут.

Из требований: нужен docker + compose, и компонент ssh сервера на роутере. Потребление ram: 20-30 Мб.

1. Нужно создать файл docker-compose.yml

version: '3'
services:
  keen-dns-proxy:
    container_name: keen-dns-proxy
    image: belt0ev/keen-dns-proxy
    volumes:
      - /home/home-dns/data:/app/data
    restart: unless-stopped
    privileged: true
    network_mode: host

"network_mode: host" - нужно для того, чтобы у контейнера был доступ к сети хоста, чтобы он мог обращаться к роутеру. В volumes указываете путь к папке data, где будет лежать конфиг и файл с доменами для роутинга.

В принципе, на этом этапе уже можно запустить "docker compose up -d" - сервер начнёт слушать запросы на порту 8053 и резолвить их через сервер Яндекса (77.88.8.8), и создаст пустой файл domains.txt в папке data. Больше ничего делать не будет.

2. Создать файл конфига appsettings.json в папке data

{
  "port": 8053,
  "interface": "Wireguard1",
  "dns": "192.168.1.43:6053",
  
  "ssh": {
    "address": "192.168.1.1",
    "username": "<username>",
    "password": "<password>"
  }
}

Это пример полностью заполненного конфига. Кратко по полям:

  • port - порт, который будет слушать сервер.
    Опциональное поле (можно не указывать, если устраивает порт по умолчанию - 8053)
  • interface - интерфейс в роутере по умолчанию, на который будут перенаправляться запросы.
    Тоже опциональное поле: интерфейсы можно указывать непосредственно в файле domains.txt
    Важно: нужно брать "системное" название интерфейса. Посмотреть можно в cli роутера командой "show interface"
  • dns - DNS сервер, который будет фактически резолвить запросы.
    Можно указать просто ip адрес (тогда будет использоваться порт 53). Если не заполнить, запросы будут резолвиться через сервер Яндекса (77.88.8.8).
    Поддерживает только udp сервера. Я использую adguard home, поэтому тут указываю его адрес.
  • ssh.address - адрес роутера, куда будут отправляться запросы на добавление/удаление ip адресов. Если не заполнить, будет использоваться адрес по умолчанию - 192.168.1.1
  • ssh.username - имя пользователя для ssh подключения.
    Если не заполнить, запросы на обновление ip адресов отправляться не будут
  • ssh.password - пароль для ssh подключения.
    Если не заполнить, запросы на обновление ip адресов отправляться не будут

3. Файл domains.txt

Его можно создать вручную в папке data, либо он будет создан при первом запуске сервера.

Пример заполнения:

# Можно использовать wildcard правила
*kino.pub
*openai*

# Можно указывать непосредственно домен
forum.keenetic.com

# Можно указать любой интерфейс для маппинга 
2ip.ru|Wireguard0
*google.com|Openvpn1

Поддерживаются комментарии (# в начале строки) и пустые строки. Через символ "|" можно указывать интерфейсы, на которые должно маппиться правило.

После обновления файла нужно перезапустить сервер, чтобы изменения подхватились (команда "docker compose restart")

Ответы на вопросы

  • Можно ли указать несколько серверов в поле dns?
    • Нет, поддерживается только один сервер. В целом, несложно добавить поддержку нескольких серверов, но думаю, что у аудитории такого решения уже есть свой adguard home (или pi-hole), где правила настраиваются более гибко, поэтому сервер никак не усложнялся. Кэширования запросов тоже нет (запросы сразу проксируются)
  • Что будет, если я удалю домены из domains.txt? Удалятся ли добавленные правила на роутере?
    • Нет, сервер не отслеживает правила по удаленным доменам из domains.txt. В таком случае можно вручную точечно удалить правила на странице https://192.168.1.1/controlPanel/staticRoutes, либо удалить все правила и папку data/dbcache, и перезапустить сервер.
  • Если я удалю правило для домена на странице https://192.168.1.1/controlPanel/staticRoutes, dns сервер его добавит снова?
    • Желательно не трогать правила, добавленные сервером. Он хранит историю добавленных правил на своей стороне, поэтому не узнает, что правило было удалено, и не добавит его снова.

Напоследок: решение писалось для себя и под свои нужды, поэтому функционал может показаться небольшим. Но его достаточно для организации выборочной маршрутизации.

Велосипед уже давно изобретен. Называется АнтиЗапрет, установите к себе на сервер и будет море счастья. Можете свой список настроить и будет все решаться маршрутизацией, т.к. скрипты антизапрета для сайтов из списка возвращают ип из своей подсети.

Edited by avn
Link to comment
Share on other sites

  • 0
18 минут назад, avn сказал:

Велосипед уже давно изобретен. Называется АнтиЗапрет

Я знаю про антизапрет, но лично мне он не подошёл. Не помню деталей, но основная причина вроде была в том, что он завязан на openvpn. В моём решении можно использовать любой интерфейс (у меня wireguard).

У антизапрета есть плюс с маппингом во внутренние ip адреса. У меня такой необходимости не было, поэтому я такой функционал не добавлял. Но, при желании, можно и такое сделать: достаточно добавить прокси сервер для резолва внутренних ip адресов в настоящие.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...