mirror of
https://github.com/qdm12/gluetun.git
synced 2026-05-07 04:20:12 +02:00
feat(wireguard): amneziawg implementation (#3150)
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type AmneziaSettings struct {
|
||||
JunkPacketCount uint16
|
||||
JunkPacketMin uint16
|
||||
JunkPacketMax uint16
|
||||
PaddingS1 uint16
|
||||
PaddingS2 uint16
|
||||
PaddingS3 uint16
|
||||
PaddingS4 uint16
|
||||
HeaderH1 string
|
||||
HeaderH2 string
|
||||
HeaderH3 string
|
||||
HeaderH4 string
|
||||
InitPacketI1 string
|
||||
InitPacketI2 string
|
||||
InitPacketI3 string
|
||||
InitPacketI4 string
|
||||
InitPacketI5 string
|
||||
}
|
||||
|
||||
func (s AmneziaSettings) uapiConfig() string {
|
||||
uintFields := map[string]uint16{
|
||||
"jc": s.JunkPacketCount,
|
||||
"jmin": s.JunkPacketMin,
|
||||
"jmax": s.JunkPacketMax,
|
||||
"s1": s.PaddingS1,
|
||||
"s2": s.PaddingS2,
|
||||
"s3": s.PaddingS3,
|
||||
"s4": s.PaddingS4,
|
||||
}
|
||||
stringFields := map[string]string{
|
||||
"h1": s.HeaderH1,
|
||||
"h2": s.HeaderH2,
|
||||
"h3": s.HeaderH3,
|
||||
"h4": s.HeaderH4,
|
||||
"i1": s.InitPacketI1,
|
||||
"i2": s.InitPacketI2,
|
||||
"i3": s.InitPacketI3,
|
||||
"i4": s.InitPacketI4,
|
||||
"i5": s.InitPacketI5,
|
||||
}
|
||||
lines := make([]string, 0, len(uintFields)+len(stringFields))
|
||||
|
||||
for key, val := range uintFields {
|
||||
lines = append(lines, fmt.Sprintf("%s=%d", key, val))
|
||||
}
|
||||
|
||||
for key, val := range stringFields {
|
||||
lines = append(lines, key+"="+val)
|
||||
}
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
type tunDevice interface {
|
||||
Close() error
|
||||
Name() (string, error)
|
||||
}
|
||||
|
||||
type bind interface {
|
||||
Close() error
|
||||
}
|
||||
|
||||
type userspaceDevice interface {
|
||||
Close()
|
||||
Wait() chan struct{}
|
||||
IpcHandle(net.Conn)
|
||||
IpcSet(string) error
|
||||
}
|
||||
|
||||
type userSpaceBackend struct {
|
||||
createTun func(string, int) (tunDevice, error)
|
||||
createBind func() bind
|
||||
createDevice func(tunDevice, bind, Logger) userspaceDevice
|
||||
preStart func(userspaceDevice, Settings) error
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"golang.zx2c4.com/wireguard/device"
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination=log_mock_test.go -package wireguard . Logger
|
||||
|
||||
type Logger interface {
|
||||
@@ -13,10 +9,3 @@ type Logger interface {
|
||||
Error(s string)
|
||||
Errorf(format string, args ...interface{})
|
||||
}
|
||||
|
||||
func makeDeviceLogger(logger Logger) (deviceLogger *device.Logger) {
|
||||
return &device.Logger{
|
||||
Verbosef: logger.Debugf,
|
||||
Errorf: logger.Errorf,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
func Test_makeDeviceLogger(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
logger := NewMockLogger(ctrl)
|
||||
|
||||
deviceLogger := makeDeviceLogger(logger)
|
||||
|
||||
logger.EXPECT().Debugf("test %d", 1)
|
||||
deviceLogger.Verbosef("test %d", 1)
|
||||
|
||||
logger.EXPECT().Errorf("test %d", 2)
|
||||
deviceLogger.Errorf("test %d", 2)
|
||||
}
|
||||
+22
-13
@@ -7,9 +7,6 @@ import (
|
||||
"net"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/netlink"
|
||||
"golang.zx2c4.com/wireguard/conn"
|
||||
"golang.zx2c4.com/wireguard/device"
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
"golang.zx2c4.com/wireguard/wgctrl"
|
||||
)
|
||||
|
||||
@@ -29,6 +26,7 @@ var (
|
||||
ErrRouteAdd = errors.New("cannot add route for interface")
|
||||
ErrDeviceWaited = errors.New("device waited for")
|
||||
ErrKernelSupport = errors.New("kernel does not support Wireguard")
|
||||
ErrAmneziaConfigure = errors.New("cannot configure AmneziaWG")
|
||||
)
|
||||
|
||||
// See https://git.zx2c4.com/wireguard-go/tree/main.go
|
||||
@@ -39,7 +37,8 @@ func (w *Wireguard) Run(ctx context.Context, waitError chan<- error, ready chan<
|
||||
return
|
||||
}
|
||||
|
||||
setupFunction := setupUserSpace
|
||||
userspaceBackend := defaultUserSpaceBackend()
|
||||
setupFunction := setupUserSpaceCommon
|
||||
switch w.settings.Implementation {
|
||||
case "auto": //nolint:goconst
|
||||
if !kernelSupported {
|
||||
@@ -55,6 +54,8 @@ func (w *Wireguard) Run(ctx context.Context, waitError chan<- error, ready chan<
|
||||
return
|
||||
}
|
||||
setupFunction = setupKernelSpace
|
||||
case "amneziawg":
|
||||
userspaceBackend = amneziaUserSpaceBackend()
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown implementation %q", w.settings.Implementation))
|
||||
}
|
||||
@@ -71,7 +72,7 @@ func (w *Wireguard) Run(ctx context.Context, waitError chan<- error, ready chan<
|
||||
defer closers.cleanup(w.logger)
|
||||
|
||||
linkIndex, waitAndCleanup, err := setupFunction(ctx,
|
||||
w.settings.InterfaceName, w.netlink, w.settings.MTU, &closers, w.logger)
|
||||
w.settings.InterfaceName, w.netlink, w.settings.MTU, &closers, w.logger, w.settings, userspaceBackend)
|
||||
if err != nil {
|
||||
waitError <- err
|
||||
return
|
||||
@@ -136,7 +137,7 @@ type waitAndCleanupFunc func() error
|
||||
|
||||
func setupKernelSpace(ctx context.Context,
|
||||
interfaceName string, netLinker NetLinker, mtu uint32,
|
||||
closers *closers, logger Logger) (
|
||||
closers *closers, logger Logger, _ Settings, _ userSpaceBackend) (
|
||||
linkIndex uint32, waitAndCleanup waitAndCleanupFunc, err error,
|
||||
) {
|
||||
links, err := netLinker.LinkList()
|
||||
@@ -178,12 +179,14 @@ func setupKernelSpace(ctx context.Context,
|
||||
return linkIndex, waitAndCleanup, nil
|
||||
}
|
||||
|
||||
func setupUserSpace(ctx context.Context,
|
||||
func setupUserSpaceCommon(ctx context.Context,
|
||||
interfaceName string, netLinker NetLinker, mtu uint32,
|
||||
closers *closers, logger Logger) (
|
||||
closers *closers, logger Logger,
|
||||
settings Settings, b userSpaceBackend,
|
||||
) (
|
||||
linkIndex uint32, waitAndCleanup waitAndCleanupFunc, err error,
|
||||
) {
|
||||
tun, err := tun.CreateTUN(interfaceName, int(mtu))
|
||||
tun, err := b.createTun(interfaceName, int(mtu))
|
||||
if err != nil {
|
||||
return 0, nil, fmt.Errorf("%w: %s", ErrCreateTun, err)
|
||||
}
|
||||
@@ -206,12 +209,11 @@ func setupUserSpace(ctx context.Context,
|
||||
return netLinker.LinkDel(link.Index)
|
||||
})
|
||||
|
||||
bind := conn.NewDefaultBind()
|
||||
bind := b.createBind()
|
||||
|
||||
closers.add("closing bind", stepSeven, bind.Close)
|
||||
|
||||
deviceLogger := makeDeviceLogger(logger)
|
||||
device := device.NewDevice(tun, bind, deviceLogger)
|
||||
device := b.createDevice(tun, bind, logger)
|
||||
|
||||
closers.add("closing Wireguard device", stepSix, func() error {
|
||||
device.Close()
|
||||
@@ -232,6 +234,13 @@ func setupUserSpace(ctx context.Context,
|
||||
|
||||
closers.add("closing UAPI listener", stepTwo, uapiListener.Close)
|
||||
|
||||
if b.preStart != nil {
|
||||
err = b.preStart(device, settings)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// acceptAndHandle exits when uapiListener is closed
|
||||
uapiAcceptErrorCh := make(chan error)
|
||||
go acceptAndHandle(uapiListener, device, uapiAcceptErrorCh)
|
||||
@@ -255,7 +264,7 @@ func setupUserSpace(ctx context.Context,
|
||||
return link.Index, waitAndCleanup, nil
|
||||
}
|
||||
|
||||
func acceptAndHandle(uapi net.Listener, device *device.Device,
|
||||
func acceptAndHandle(uapi net.Listener, device userspaceDevice,
|
||||
uapiAcceptErrorCh chan<- error,
|
||||
) {
|
||||
for { // stopped by uapiFile.Close()
|
||||
|
||||
@@ -46,8 +46,11 @@ type Settings struct {
|
||||
// It defaults to false if left unset.
|
||||
IPv6 *bool
|
||||
// Implementation is the implementation to use.
|
||||
// It can be auto, kernelspace or userspace, and defaults to auto.
|
||||
// It can be auto, kernelspace, userspace or amneziawg,
|
||||
// and defaults to auto.
|
||||
Implementation string
|
||||
// AmneziaWG settings are extra obfuscation parameters
|
||||
AmneziaWG AmneziaSettings
|
||||
}
|
||||
|
||||
func (s *Settings) SetDefaults() {
|
||||
@@ -178,7 +181,7 @@ func (s *Settings) Check() (err error) {
|
||||
}
|
||||
|
||||
switch s.Implementation {
|
||||
case "auto", "kernelspace", "userspace":
|
||||
case "auto", "kernelspace", "userspace", "amneziawg":
|
||||
default:
|
||||
return fmt.Errorf("%w: %s", ErrImplementationInvalid, s.Implementation)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
amneziaconn "github.com/amnezia-vpn/amneziawg-go/conn"
|
||||
amneziadevice "github.com/amnezia-vpn/amneziawg-go/device"
|
||||
amneziatun "github.com/amnezia-vpn/amneziawg-go/tun"
|
||||
wgconn "golang.zx2c4.com/wireguard/conn"
|
||||
wgdevice "golang.zx2c4.com/wireguard/device"
|
||||
wgtun "golang.zx2c4.com/wireguard/tun"
|
||||
)
|
||||
|
||||
func defaultUserSpaceBackend() userSpaceBackend {
|
||||
return userSpaceBackend{
|
||||
createTun: func(name string, mtu int) (tunDevice, error) {
|
||||
return wgtun.CreateTUN(name, mtu)
|
||||
},
|
||||
createBind: func() bind {
|
||||
return wgconn.NewDefaultBind()
|
||||
},
|
||||
createDevice: func(td tunDevice, b bind, logger Logger) userspaceDevice {
|
||||
wgtun, _ := td.(wgtun.Device)
|
||||
wgBind, _ := b.(wgconn.Bind)
|
||||
wgLogger := wgdevice.Logger{
|
||||
Verbosef: logger.Debugf,
|
||||
Errorf: logger.Errorf,
|
||||
}
|
||||
device := wgdevice.NewDevice(wgtun, wgBind, &wgLogger)
|
||||
return device
|
||||
},
|
||||
preStart: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func amneziaUserSpaceBackend() userSpaceBackend {
|
||||
return userSpaceBackend{
|
||||
createTun: func(name string, mtu int) (tunDevice, error) {
|
||||
return amneziatun.CreateTUN(name, mtu)
|
||||
},
|
||||
createBind: func() bind {
|
||||
return amneziaconn.NewDefaultBind()
|
||||
},
|
||||
createDevice: func(td tunDevice, b bind, logger Logger) userspaceDevice {
|
||||
wgamneziaTun, _ := td.(amneziatun.Device)
|
||||
wgamneziaBind, _ := b.(amneziaconn.Bind)
|
||||
wgamneziaLogger := amneziadevice.Logger{
|
||||
Verbosef: logger.Debugf,
|
||||
Errorf: logger.Errorf,
|
||||
}
|
||||
device := amneziadevice.NewDevice(wgamneziaTun, wgamneziaBind, &wgamneziaLogger)
|
||||
return device
|
||||
},
|
||||
preStart: func(ud userspaceDevice, s Settings) error {
|
||||
uapiConfig := s.AmneziaWG.uapiConfig()
|
||||
err := ud.IpcSet(uapiConfig)
|
||||
return err
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user