Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions backend/wireguard/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type Config struct {
PrivateKey string `json:"private_key"`
PreSharedKey string `json:"pre_shared_key,omitempty"`
ListenPort int `json:"listen_port"`
MTU *int `json:"mtu,omitempty"`
Address []string `json:"address"`
Latency *LatencyConfig `json:"latency,omitempty"`

Expand Down Expand Up @@ -61,6 +62,9 @@ func NewConfig(config string) (*Config, error) {
}

// Validate configuration
if err := validateMTU(wgConfig.MTU); err != nil {
return nil, err
}
if wgConfig.InterfaceName == "" {
wgConfig.InterfaceName = "wg0"
}
Expand All @@ -81,6 +85,13 @@ func NewConfig(config string) (*Config, error) {
return &wgConfig, nil
}

func validateMTU(mtu *int) error {
if mtu != nil && (*mtu < 576 || *mtu > 9000) {
return errors.New("mtu must be an integer between 576 and 9000")
}
return nil
}

// InterfaceNetworks returns CIDR prefixes parsed from the node's core `address` list.
// Used to restrict peer AllowedIPs to subnets this interface actually serves.
func (c *Config) InterfaceNetworks() []*net.IPNet {
Expand Down
66 changes: 61 additions & 5 deletions backend/wireguard/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,14 @@ func wrapPermissionDeniedError(action string, err error) error {

// Manager handles WireGuard interface management using wgctrl
type Manager struct {
client wgClient
iFaceName string
nl netlinkOps
configure configureDeviceFunc
mu sync.RWMutex
client wgClient
iFaceName string
nl netlinkOps
configure configureDeviceFunc
setLinkMTU func(netlink.Link, int) error
defaultMTU int
mtuManaged bool
mu sync.RWMutex
}

// NewManager creates a new WireGuard manager
Expand Down Expand Up @@ -126,9 +129,17 @@ func buildInitialWGConfig(privateKey wgtypes.Key, listenPort int, peers []wgtype

// InitializeWithPeers sets up the WireGuard interface with initial configuration and optional full peer snapshot.
func (m *Manager) InitializeWithPeers(privateKey wgtypes.Key, listenPort int, serverIPs []string, peers []wgtypes.PeerConfig) error {
return m.initializeWithPeers(privateKey, listenPort, serverIPs, peers, nil)
}

func (m *Manager) initializeWithPeers(privateKey wgtypes.Key, listenPort int, serverIPs []string, peers []wgtypes.PeerConfig, mtu *int) error {
m.mu.Lock()
defer m.mu.Unlock()

if err := validateMTU(mtu); err != nil {
return err
}

if m.client == nil {
return fmt.Errorf("wgctrl client is not initialized")
}
Expand Down Expand Up @@ -173,6 +184,11 @@ func (m *Manager) InitializeWithPeers(privateKey wgtypes.Key, listenPort int, se
if err != nil {
return fmt.Errorf("failed to get link: %w", err)
}
m.defaultMTU = 0
m.mtuManaged = false
if err := m.applyMTULocked(mtu); err != nil {
return err
}

for _, addr := range parsedAddrs {
if err := nl.AddrAdd(link2, addr); err != nil {
Expand Down Expand Up @@ -226,17 +242,57 @@ func (m *Manager) ApplyPeersReplaceAll(peers []wgtypes.PeerConfig) error {

// ApplyConfig safely configures the device with the given configuration under lock.
func (m *Manager) ApplyConfig(config wgtypes.Config) error {
return m.applyConfig(config, nil)
}

func (m *Manager) applyConfig(config wgtypes.Config, mtu *int) error {
m.mu.Lock()
defer m.mu.Unlock()

if m.client == nil {
return fmt.Errorf("wgctrl client is not initialized")
}

if err := m.applyMTULocked(mtu); err != nil {
return err
}
configure := m.getConfigureDevice()
return configure(m.client, m.iFaceName, config)
}

// applyMTULocked preserves the kernel default until an explicit MTU is configured.
// Clearing that setting restores the MTU captured before the first override.
func (m *Manager) applyMTULocked(mtu *int) error {
if err := validateMTU(mtu); err != nil {
return err
}
if mtu == nil && !m.mtuManaged {
return nil
}
target := m.defaultMTU
if mtu != nil {
target = *mtu
}
link, err := m.getNetlinkOps().LinkByName(m.iFaceName)
if err != nil {
return fmt.Errorf("failed to get link for MTU update: %w", err)
}
if m.defaultMTU == 0 {
m.defaultMTU = link.Attrs().MTU
}
if link.Attrs().MTU != target {
setMTU := m.setLinkMTU
if setMTU == nil {
setMTU = netlink.LinkSetMTU
}
if err := setMTU(link, target); err != nil {
return fmt.Errorf("failed to set interface MTU: %w", wrapPermissionDeniedError("setting wireguard interface MTU", err))
}
}
m.mtuManaged = mtu != nil
return nil
}

// GetDevice returns the current WireGuard device statistics
func (m *Manager) GetDevice() (*wgtypes.Device, error) {
m.mu.RLock()
Expand Down
7 changes: 5 additions & 2 deletions backend/wireguard/wireguard.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ func newWithManagerFactory(cfg *config.Config, wgConfig *Config, users []*common
}

wg.config = wgConfig
if err := validateMTU(wgConfig.MTU); err != nil {
return nil, err
}

log.Println("config loaded in", time.Since(start).Seconds(), "second.")

Expand Down Expand Up @@ -177,7 +180,7 @@ func newWithManagerFactory(cfg *config.Config, wgConfig *Config, users []*common
}

// Initialize the WireGuard interface with peers in the same kernel configure call.
if err = manager.InitializeWithPeers(privateKey, wgConfig.ListenPort, wgConfig.Address, startupPeerConfigs); err != nil {
if err = manager.initializeWithPeers(privateKey, wgConfig.ListenPort, wgConfig.Address, startupPeerConfigs, wgConfig.MTU); err != nil {
manager.Close()
return nil, fmt.Errorf("failed to initialize interface: %w", err)
}
Expand Down Expand Up @@ -278,7 +281,7 @@ func (wg *WireGuard) restartLocked() error {
ReplacePeers: true,
}

if err := manager.ApplyConfig(config); err != nil {
if err := manager.applyConfig(config, cfg.MTU); err != nil {
return fmt.Errorf("failed to reconfigure interface during restart: %w", err)
}

Expand Down
Loading