netguard

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 17, 2026 License: GPL-3.0 Imports: 11 Imported by: 0

Documentation

Overview

Package netguard уводит собственные сокеты ядра мимо туннеля (architecture.md §05, дорожка 2).

Когда datapath забирает весь трафик системы (tun, external), сокеты ядра по общей таблице маршрутов попали бы в тот же туннель, и туннель зависел бы от самого себя. Guard.Control ставится в поле Control у net.Dialer и привязывает сокет к физическому интерфейсу: на Windows — опциями IP_UNICAST_IF / IPV6_UNICAST_IF, на Linux — SO_BINDTOIFINDEX. На других системах Control пока ничего не делает (macOS — этап Э4).

watch.go — слежение за сменой сети (задача S2 Э2, architecture.md §07).

Физический интерфейс выбирается при запуске (SelectInterfaces), но сеть меняется на ходу: Wi-Fi → Ethernet, отключение кабеля, сон и пробуждение. Watch ловит изменения маршрутов и интерфейсов, сворачивает их серию в одно решение, ставит новые индексы и говорит вызывающему, что сеть сменилась, — перезапуск туннеля его дело.

Index

Constants

View Source
const DefaultMaxWait = 10 * time.Second

DefaultMaxWait — потолок ожидания тишины: сеть, которая шумит без конца, всё равно получает решение.

View Source
const DefaultSettle = 2 * time.Second

DefaultSettle — сколько тишины после последнего события ждать, прежде чем решать. Переключение Wi-Fi → Ethernet даёт серию событий маршрутов и интерфейсов за секунду-другую; решение по первому из них дало бы несколько перезапусков подряд (§07).

View Source
const SocketMark uint32 = 0x1074

SocketMark — значение Mark для сокетов qwdtt-cli. Свободно от известных пользователей меток: wg-quick (0xca6c), kube-proxy (0x4000, 0x8000), Tailscale (маска 0xff0000), Calico (маска 0xffff0000), Cilium (маска 0xf00). Маршрутизации по метке qwdtt-cli не заводит — только опознание.

Variables

This section is empty.

Functions

This section is empty.

Types

type Choice

type Choice struct {
	Index4, Index6 uint32
	// Alias4, Alias6 — имена интерфейсов для вывода («Ethernet 3», «Wi-Fi»,
	// «eth0»).
	Alias4, Alias6 string
}

Choice — выбор физического интерфейса для обоих семейств. Индекс 0 — маршрута по умолчанию для семейства нет.

func (Choice) Empty

func (c Choice) Empty() bool

Empty — сети нет: маршрута по умолчанию нет ни для одного семейства.

func (Choice) Same

func (c Choice) Same(o Choice) bool

Same — тот же выбор: индексы совпадают. Имена не сравниваются, их переименование сети не меняет.

func (Choice) String

func (c Choice) String() string

String — выбор словами: «IPv4 — Ethernet 3 (индекс 3), IPv6 — нет маршрута».

type Guard

type Guard struct {

	// Logf, если задан, получает строку на каждый привязанный сокет:
	// «[NETGUARD] tcp4 203.0.113.80:443 → интерфейс 3». Главный инструмент
	// отладки петли; CLI ставит его при -v. Задаётся до первого сокета.
	// Имени хоста в строке нет: в Control адрес приходит уже разрешённым.
	Logf func(format string, args ...any)

	// Mark, если не 0, ставится сокетам опцией SO_MARK (только Linux): по
	// ней защита DNS узнаёт сокеты qwdtt-cli и пропускает их запросы к DNS для
	// доменов VK (plan-e4.md, D1). Метке нужен CAP_NET_ADMIN, без него
	// сокет не создаётся (EPERM), поэтому CLI ставит её, только когда
	// защита DNS включена. Задаётся до первого сокета. На Windows не
	// используется: там защита DNS пропускает весь процесс qwdtt-cli.
	Mark uint32

	// NoIPv6 — сокетам ядра IPv6 не давать: выбор интерфейса IPv6
	// отбрасывается, и сокет IPv6 не создаётся, а Go уходит на IPv4. Нужно,
	// когда ответы IPv6 на физический интерфейс отбросит обратный фильтр
	// (firewalld, plan-e4.md, T3). Задаётся до SelectInterfaces и Watch.
	NoIPv6 bool
	// contains filtered or unexported fields
}

Guard хранит индексы физического интерфейса для IPv4 и IPv6. Нулевое значение готово к работе, но сокеты не пропускает: ни один интерфейс ещё не выбран. Индексы меняются на ходу (смена сети): новые сокеты берут новый индекс, уже открытые доживают со старым.

func (*Guard) Choice

func (g *Guard) Choice() Choice

Choice — последний выбор, который поставил SelectInterfaces или Watch.

func (*Guard) Control

func (g *Guard) Control(network, address string, c syscall.RawConn) error

Control — хук под поле Control у net.Dialer и net.ListenConfig.

func (*Guard) Interfaces

func (g *Guard) Interfaces() (index4, index6 uint32)

Interfaces возвращает текущие индексы для IPv4 и IPv6.

func (*Guard) SelectInterfaces

func (g *Guard) SelectInterfaces(exclude uint64) (string, error)

SelectInterfaces выбирает физический интерфейс маршрута по умолчанию для IPv4 и IPv6 и ставит их индексы. exclude — свой адаптер (AdapterID datapath: на Windows — LUID, на Linux — индекс), 0 — исключать нечего. Возвращает выбор словами для вывода.

Сети нет вовсе — не ошибка: индексы обнуляются, и сокеты ядра откажут с понятным текстом, а не уйдут в туннель. Ошибка — только отказ системы отдать таблицу маршрутов.

func (*Guard) SetInterfaces

func (g *Guard) SetInterfaces(index4, index6 uint32)

SetInterfaces задаёт индексы физического интерфейса. 0 — для этого семейства интерфейса нет, и сокеты этого семейства не создаются.

func (*Guard) Watch

func (g *Guard) Watch(opts WatchOptions) (stop func(), err error)

Watch следит за сменой сети, пока не вызвана stop. Начинает с выбора, который поставил SelectInterfaces. stop ждёт конца уже идущего Changed.

type WatchOptions

type WatchOptions struct {
	// Exclude — свой адаптер на момент события (AdapterID datapath: на
	// Windows — LUID, на Linux — индекс интерфейса); 0 или nil —
	// исключать нечего. События этого интерфейса пропускаются, и в выбор он
	// не попадает: иначе туннель, ставя свои маршруты, перезапускал бы
	// себя сам.
	Exclude func() uint64

	// Changed получает новый и прежний выбор — один раз на свёрнутую серию,
	// когда новые индексы уже стоят. Выборы могут совпасть: интерфейс
	// пропадал и вернулся (сон, переподключение Wi-Fi), и открытые через
	// него сокеты уже мертвы. Вызовы не перекрываются. Обязателен.
	Changed func(now, before Choice)

	// Settle и MaxWait — окно сворачивания; 0 — DefaultSettle
	// и DefaultMaxWait.
	Settle, MaxWait time.Duration
}

WatchOptions — настройки Watch.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL