85 lines
2.1 KiB
Go
85 lines
2.1 KiB
Go
package clientwg
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"sync"
|
|
|
|
"golang.zx2c4.com/wireguard/conn"
|
|
"golang.zx2c4.com/wireguard/device"
|
|
"golang.zx2c4.com/wireguard/tun"
|
|
)
|
|
|
|
// Device owns the MuxTun, wireguard-go engine, and transport bind.
|
|
type Device struct {
|
|
tun *MuxTun
|
|
wireguard *device.Device
|
|
closeOnce sync.Once
|
|
}
|
|
|
|
// NewDevice transfers ownership of base to a new embedded wireguard-go Device.
|
|
func NewDevice(base tun.Device, logger *slog.Logger) (*Device, error) {
|
|
if base == nil {
|
|
return nil, errors.New("base TUN device must not be nil")
|
|
}
|
|
mux := NewMuxTun(base)
|
|
wireguard := device.NewDevice(mux, conn.NewDefaultBind(), wireGuardLogger(logger))
|
|
return &Device{tun: mux, wireguard: wireguard}, nil
|
|
}
|
|
|
|
// Configure atomically replaces the single Server peer through wireguard-go UAPI.
|
|
func (d *Device) Configure(config Config) error {
|
|
uapi, err := config.uapi()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := d.wireguard.IpcSet(uapi); err != nil {
|
|
return fmt.Errorf("configure embedded wireguard-go: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Up starts the embedded WireGuard device after configuration.
|
|
func (d *Device) Up() error {
|
|
if err := d.wireguard.Up(); err != nil {
|
|
return fmt.Errorf("bring embedded wireguard-go up: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// UAPIState returns wireguard-go's current UAPI state for diagnostics.
|
|
func (d *Device) UAPIState() (string, error) {
|
|
return d.wireguard.IpcGet()
|
|
}
|
|
|
|
// MuxTun returns the single packet boundary used by Session transport.
|
|
func (d *Device) MuxTun() *MuxTun { return d.tun }
|
|
|
|
// Close is idempotent and stops wireguard-go, MuxTun, and the base Wintun.
|
|
func (d *Device) Close() {
|
|
if d == nil || d.wireguard == nil {
|
|
return
|
|
}
|
|
d.closeOnce.Do(func() {
|
|
d.wireguard.Close()
|
|
})
|
|
}
|
|
|
|
func wireGuardLogger(logger *slog.Logger) *device.Logger {
|
|
if logger == nil {
|
|
return &device.Logger{
|
|
Verbosef: device.DiscardLogf,
|
|
Errorf: device.DiscardLogf,
|
|
}
|
|
}
|
|
return &device.Logger{
|
|
Verbosef: func(format string, args ...any) {
|
|
logger.Debug(fmt.Sprintf(format, args...))
|
|
},
|
|
Errorf: func(format string, args ...any) {
|
|
logger.Error(fmt.Sprintf(format, args...))
|
|
},
|
|
}
|
|
}
|