Documentation
¶
Overview ¶
Package server реализует серверную половину туннеля: принимает QUIC-соединения, проверяет пиров по списку доступа, раздаёт виртуальные адреса и маршрутизирует пакеты между клиентами и внешней сетью.
Index ¶
Constants ¶
const DefaultAdminSocket = "/run/lvpn/admin.sock"
DefaultAdminSocket - сокет управления по умолчанию.
const DefaultListen = ":443"
DefaultListen - порт по умолчанию. UDP/443 выбран ради маскировки: это порт HTTP/3, где QUIC-трафик выглядит уместно. Канонический порт WireGuard (51820) - наоборот, самый профилированный VPN-порт.
const DefaultMTU = 1200
DefaultMTU выбран по бюджету, который доступен с первого пакета.
Ограничение задаёт не путь, а QUIC: до определения MTU пути quic-go шлёт пакеты по 1280 байт. Из них уходит ~25 на заголовок и тег, ~3 на кадр датаграммы и 25 на нашу обвязку - остаётся около 1227 байт внутреннего пакета. Всё, что больше, отбрасывается, пока определение MTU не поднимет размер пакета, а оно срабатывает не всегда: путь может резать MTU молча, без ICMP.
Отсюда 1200 - значение, которое работает сразу и везде. Верхняя граница на пути в 1500 байт около 1419, но это потолок уже после определения MTU пути, а не безопасный старт.
Есть и обратная сторона: детекторы VPN смотрят на MSS в TCP-заголовке, и 1200 - характерная примета IPsec. Поднимать значение стоит, только убедившись, что путь держит: проверяется через ping -M do (см. README).
const DefaultPeerStore = "/var/lib/lvpn/peers.json"
DefaultPeerStore - изменяемое состояние демона по умолчанию.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// Listen - адрес UDP-сокета QUIC, например ":51820".
Listen string `json:"listen"`
// PrivateKey - статический ключ сервера; его публичную часть прописывают клиенты.
PrivateKey noise.PrivateKey `json:"private_key"`
// Subnet - адресное пространство туннеля, например "10.9.0.0/24".
Subnet netip.Prefix `json:"subnet"`
// Address - виртуальный адрес самого сервера. По умолчанию первый в подсети.
Address netip.Addr `json:"address,omitempty"`
// TLSServerName - имя в самоподписанном сертификате. Пассивный DPI его
// не видит, но активный пробинг сервера - да, поэтому имя лучше выбрать
// правдоподобное и совпадающее с sni у клиентов.
TLSServerName string `json:"tls_server_name,omitempty"`
// TunName - имя интерфейса; пустое значение отдаёт выбор ядру.
TunName string `json:"tun_name,omitempty"`
// MTU туннеля. Оставляет запас под заголовки QUIC и AEAD.
MTU int `json:"mtu,omitempty"`
// Routes - подсети, которые сервер просит клиентов завернуть в туннель.
// Пустой список означает доступ только к самой подсети туннеля.
Routes []netip.Prefix `json:"routes,omitempty"`
// DNS - резолверы, предлагаемые клиентам.
DNS []netip.Addr `json:"dns,omitempty"`
// EgressInterface - внешний интерфейс для NAT, например "eth0".
EgressInterface string `json:"egress_interface,omitempty"`
// SetupNAT включает ip_forward и правило MASQUERADE при старте.
SetupNAT bool `json:"setup_nat,omitempty"`
// AllowPeerToPeer разрешает клиентам общаться между собой через сервер.
AllowPeerToPeer bool `json:"allow_peer_to_peer,omitempty"`
// PeerStorePath - файл с пирами, добавленными на работающем сервере.
// Это изменяемое состояние демона, поэтому по умолчанию оно в /var/lib,
// а не рядом с конфигурацией, которую правит человек.
PeerStorePath string `json:"peer_store,omitempty"`
// AdminSocket - unix-сокет управления списком доступа.
AdminSocket string `json:"admin_socket,omitempty"`
// Peers - список доступа.
Peers []PeerConfig `json:"peers"`
}
Config - конфигурация сервера.
func LoadConfig ¶
LoadConfig читает конфигурацию из JSON-файла и проверяет её.
type PeerConfig ¶
type PeerConfig struct {
Name string `json:"name"`
PublicKey noise.PublicKey `json:"public_key"`
// Address закрепляет за пиром постоянный виртуальный адрес.
// Если не задан, адрес выдаётся из пула.
Address netip.Addr `json:"address,omitempty"`
// Role по умолчанию зависит от источника: пиры из конфигурации -
// администраторы, пиры из хранилища - обычные пользователи. Пир из
// конфигурации можно явно понизить до "user".
Role Role `json:"role,omitempty"`
// ExpiresAt - момент окончания доступа. Пустое значение означает
// бессрочный доступ. Просроченный пир не проходит рукопожатие,
// а уже подключённый отключается при следующей проверке.
ExpiresAt *time.Time `json:"expires_at,omitempty"`
// QuotaBytes - лимит трафика в байтах, считая обе стороны. Ноль
// означает безлимит.
QuotaBytes uint64 `json:"quota_bytes,omitempty"`
// UsedBytes - израсходованный трафик. Поле изменяемое: сервер
// накапливает его по ходу работы и сохраняет в хранилище, иначе
// перезапуск обнулял бы расход и лимит ничего бы не значил.
UsedBytes uint64 `json:"used_bytes,omitempty"`
}
PeerConfig - запись списка доступа. Клиент без своего публичного ключа в этом списке не пройдёт рукопожатие.
func (PeerConfig) AccessDenied ¶
func (p PeerConfig) AccessDenied(now time.Time) string
AccessDenied объединяет причины отказа в доступе; пустая строка означает, что пир вправе подключаться.
func (PeerConfig) Expired ¶
func (p PeerConfig) Expired(now time.Time) bool
Expired сообщает, что срок доступа пира истёк.
func (PeerConfig) QuotaExceeded ¶
func (p PeerConfig) QuotaExceeded() bool
QuotaExceeded сообщает, что пир исчерпал лимит трафика.
type PeerUpdate ¶
PeerUpdate описывает изменение подписки. Указатели отличают «не трогать» от «выставить значение», а флаги очистки - от «снять ограничение».
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server держит состояние работающего туннеля.
func New ¶
New готовит сервер по конфигурации, ещё не трогая сеть. configPath нужен для перечитывания списка пиров по SIGHUP; пустое значение отключает эту возможность.
func (*Server) PublicKey ¶
PublicKey возвращает статический публичный ключ сервера - его прописывают клиенты.