server

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 29, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Overview

Package server реализует серверную половину туннеля: принимает QUIC-соединения, проверяет пиров по списку доступа, раздаёт виртуальные адреса и маршрутизирует пакеты между клиентами и внешней сетью.

Index

Constants

View Source
const DefaultAdminSocket = "/run/lvpn/admin.sock"

DefaultAdminSocket - сокет управления по умолчанию.

View Source
const DefaultListen = ":443"

DefaultListen - порт по умолчанию. UDP/443 выбран ради маскировки: это порт HTTP/3, где QUIC-трафик выглядит уместно. Канонический порт WireGuard (51820) - наоборот, самый профилированный VPN-порт.

View Source
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).

View Source
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

func LoadConfig(path string) (Config, error)

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

type PeerUpdate struct {
	ExpiresAt   *time.Time
	ClearExpiry bool
	QuotaBytes  *uint64
	ResetUsage  bool
}

PeerUpdate описывает изменение подписки. Указатели отличают «не трогать» от «выставить значение», а флаги очистки - от «снять ограничение».

func (PeerUpdate) Empty

func (u PeerUpdate) Empty() bool

Empty сообщает, что менять нечего.

type Role

type Role string

Role определяет полномочия пира.

const (
	// RoleAdmin - пир вправе управлять списком доступа по туннелю.
	RoleAdmin Role = "admin"
	// RoleUser - обычный пир, только доступ в сеть.
	RoleUser Role = "user"
)

func (Role) Valid

func (r Role) Valid() bool

Valid сообщает, что роль известна.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server держит состояние работающего туннеля.

func New

func New(cfg Config, configPath string, log *slog.Logger) (*Server, error)

New готовит сервер по конфигурации, ещё не трогая сеть. configPath нужен для перечитывания списка пиров по SIGHUP; пустое значение отключает эту возможность.

func (*Server) PublicKey

func (s *Server) PublicKey() noise.PublicKey

PublicKey возвращает статический публичный ключ сервера - его прописывают клиенты.

func (*Server) Reload

func (s *Server) Reload() error

Reload перечитывает конфигурацию и обновляет список пиров.

Обновляется только список доступа: подсеть, MTU и параметры сети менять на работающем туннеле нельзя, не порвав все подключения, для этого сервер перезапускают.

func (*Server) Run

func (s *Server) Run(ctx context.Context) error

Run поднимает туннель и работает до отмены контекста или фатальной ошибки.

Jump to

Keyboard shortcuts

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