Skip to content

Commit c573cd6

Browse files
committed
amneziawg client support
1 parent bbdf41c commit c573cd6

16 files changed

+232
-91
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package configurer
2+
3+
// AmneziaConfig describes AmneziaWG obfuscation parameters.
4+
// If nil or all fields are zero, it behaves as standard WireGuard.
5+
type AmneziaConfig interface {
6+
IsEmpty() bool
7+
GetJc() int32
8+
GetJmin() int32
9+
GetJmax() int32
10+
GetS1() int32
11+
GetS2() int32
12+
GetH1() uint32
13+
GetH2() uint32
14+
GetH3() uint32
15+
GetH4() uint32
16+
GetI1() string
17+
GetI2() string
18+
GetI3() string
19+
GetI4() string
20+
GetI5() string
21+
}

client/iface/configurer/usp.go

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,17 @@ type WGUSPConfigurer struct {
4141
device *device.Device
4242
deviceName string
4343
activityRecorder *bind.ActivityRecorder
44+
amneziaConfig AmneziaConfig
4445

4546
uapiListener net.Listener
4647
}
4748

48-
func NewUSPConfigurer(device *device.Device, deviceName string, activityRecorder *bind.ActivityRecorder) *WGUSPConfigurer {
49+
func NewUSPConfigurer(device *device.Device, deviceName string, activityRecorder *bind.ActivityRecorder, amneziaConfig AmneziaConfig) *WGUSPConfigurer {
4950
wgCfg := &WGUSPConfigurer{
5051
device: device,
5152
deviceName: deviceName,
5253
activityRecorder: activityRecorder,
54+
amneziaConfig: amneziaConfig,
5355
}
5456
wgCfg.startUAPI()
5557
return wgCfg
@@ -69,7 +71,7 @@ func (c *WGUSPConfigurer) ConfigureInterface(privateKey string, port int) error
6971
ListenPort: &port,
7072
}
7173

72-
return c.device.IpcSet(toWgUserspaceString(config))
74+
return c.device.IpcSet(c.toWgUserspaceString(config))
7375
}
7476

7577
func (c *WGUSPConfigurer) UpdatePeer(peerKey string, allowedIps []netip.Prefix, keepAlive time.Duration, endpoint *net.UDPAddr, preSharedKey *wgtypes.Key) error {
@@ -91,7 +93,7 @@ func (c *WGUSPConfigurer) UpdatePeer(peerKey string, allowedIps []netip.Prefix,
9193
Peers: []wgtypes.PeerConfig{peer},
9294
}
9395

94-
if ipcErr := c.device.IpcSet(toWgUserspaceString(config)); ipcErr != nil {
96+
if ipcErr := c.device.IpcSet(c.toWgUserspaceString(config)); ipcErr != nil {
9597
return ipcErr
9698
}
9799

@@ -145,7 +147,7 @@ func (c *WGUSPConfigurer) RemoveEndpointAddress(peerKey string) error {
145147
config := wgtypes.Config{
146148
Peers: []wgtypes.PeerConfig{peer},
147149
}
148-
if ipcErr := c.device.IpcSet(toWgUserspaceString(config)); ipcErr != nil {
150+
if ipcErr := c.device.IpcSet(c.toWgUserspaceString(config)); ipcErr != nil {
149151
return fmt.Errorf("failed to remove peer: %s", ipcErr)
150152
}
151153

@@ -160,7 +162,7 @@ func (c *WGUSPConfigurer) RemoveEndpointAddress(peerKey string) error {
160162
Peers: []wgtypes.PeerConfig{peer},
161163
}
162164

163-
if err := c.device.IpcSet(toWgUserspaceString(config)); err != nil {
165+
if err := c.device.IpcSet(c.toWgUserspaceString(config)); err != nil {
164166
return fmt.Errorf("remove endpoint address: %w", err)
165167
}
166168

@@ -181,7 +183,7 @@ func (c *WGUSPConfigurer) RemovePeer(peerKey string) error {
181183
config := wgtypes.Config{
182184
Peers: []wgtypes.PeerConfig{peer},
183185
}
184-
ipcErr := c.device.IpcSet(toWgUserspaceString(config))
186+
ipcErr := c.device.IpcSet(c.toWgUserspaceString(config))
185187

186188
c.activityRecorder.Remove(peerKey)
187189
return ipcErr
@@ -208,7 +210,7 @@ func (c *WGUSPConfigurer) AddAllowedIP(peerKey string, allowedIP netip.Prefix) e
208210
Peers: []wgtypes.PeerConfig{peer},
209211
}
210212

211-
return c.device.IpcSet(toWgUserspaceString(config))
213+
return c.device.IpcSet(c.toWgUserspaceString(config))
212214
}
213215

214216
func (c *WGUSPConfigurer) RemoveAllowedIP(peerKey string, allowedIP netip.Prefix) error {
@@ -273,7 +275,7 @@ func (c *WGUSPConfigurer) RemoveAllowedIP(peerKey string, allowedIP netip.Prefix
273275
config := wgtypes.Config{
274276
Peers: []wgtypes.PeerConfig{peer},
275277
}
276-
return c.device.IpcSet(toWgUserspaceString(config))
278+
return c.device.IpcSet(c.toWgUserspaceString(config))
277279
}
278280

279281
func (c *WGUSPConfigurer) FullStats() (*Stats, error) {
@@ -399,23 +401,59 @@ func parseTransfers(ipc string) (map[string]WGStats, error) {
399401
return stats, nil
400402
}
401403

402-
func toWgUserspaceString(wgCfg wgtypes.Config) string {
404+
func (c *WGUSPConfigurer) toWgUserspaceString(wgCfg wgtypes.Config) string {
403405
var sb strings.Builder
404406
if wgCfg.PrivateKey != nil {
405407
hexKey := hex.EncodeToString(wgCfg.PrivateKey[:])
406408
sb.WriteString(fmt.Sprintf("private_key=%s\n", hexKey))
407409

408-
// write amneziawg settings here
409-
// sorry for hardcode
410-
sb.WriteString("jc=8\n")
411-
sb.WriteString("jmin=50\n")
412-
sb.WriteString("jmax=1000\n")
413-
sb.WriteString("s1=30\n")
414-
sb.WriteString("s2=32\n")
415-
sb.WriteString("h1=567134433\n")
416-
sb.WriteString("h2=1497534042\n")
417-
sb.WriteString("h3=862417541\n")
418-
sb.WriteString("h4=1695024432\n")
410+
// Write AmneziaWG settings only if config is not empty
411+
// If nil or empty, acts as standard WireGuard
412+
if !c.amneziaConfig.IsEmpty() {
413+
414+
if val := c.amneziaConfig.GetJc(); val > 0 {
415+
sb.WriteString(fmt.Sprintf("jc=%d\n", val))
416+
}
417+
if val := c.amneziaConfig.GetJmin(); val > 0 {
418+
sb.WriteString(fmt.Sprintf("jmin=%d\n", val))
419+
}
420+
if val := c.amneziaConfig.GetJmax(); val > 0 {
421+
sb.WriteString(fmt.Sprintf("jmax=%d\n", val))
422+
}
423+
if val := c.amneziaConfig.GetS1(); val > 0 {
424+
sb.WriteString(fmt.Sprintf("s1=%d\n", val))
425+
}
426+
if val := c.amneziaConfig.GetS2(); val > 0 {
427+
sb.WriteString(fmt.Sprintf("s2=%d\n", val))
428+
}
429+
if val := c.amneziaConfig.GetH1(); val > 0 {
430+
sb.WriteString(fmt.Sprintf("h1=%d\n", val))
431+
}
432+
if val := c.amneziaConfig.GetH2(); val > 0 {
433+
sb.WriteString(fmt.Sprintf("h2=%d\n", val))
434+
}
435+
if val := c.amneziaConfig.GetH3(); val > 0 {
436+
sb.WriteString(fmt.Sprintf("h3=%d\n", val))
437+
}
438+
if val := c.amneziaConfig.GetH4(); val > 0 {
439+
sb.WriteString(fmt.Sprintf("h4=%d\n", val))
440+
}
441+
if val := c.amneziaConfig.GetI1(); val != "" {
442+
sb.WriteString(fmt.Sprintf("i1=%s\n", val))
443+
}
444+
if val := c.amneziaConfig.GetI2(); val != "" {
445+
sb.WriteString(fmt.Sprintf("i2=%s\n", val))
446+
}
447+
if val := c.amneziaConfig.GetI3(); val != "" {
448+
sb.WriteString(fmt.Sprintf("i3=%s\n", val))
449+
}
450+
if val := c.amneziaConfig.GetI4(); val != "" {
451+
sb.WriteString(fmt.Sprintf("i4=%s\n", val))
452+
}
453+
if val := c.amneziaConfig.GetI5(); val != "" {
454+
sb.WriteString(fmt.Sprintf("i5=%s\n", val))
455+
}
456+
}
419457
}
420458

421459
if wgCfg.ListenPort != nil {

client/iface/device/device_android.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type WGTunDevice struct {
3232
filteredDevice *FilteredDevice
3333
udpMux *udpmux.UniversalUDPMuxDefault
3434
configurer WGConfigurer
35+
amneziaConfig configurer.AmneziaConfig
3536
}
3637

3738
func NewTunDevice(address wgaddr.Address, port int, key string, mtu uint16, iceBind *bind.ICEBind, tunAdapter TunAdapter, disableDNS bool) *WGTunDevice {
@@ -80,7 +81,7 @@ func (t *WGTunDevice) Create(routes []string, dns string, searchDomains []string
8081
// this helps with support for the older NetBird clients that had a hardcoded direct mode
8182
// t.device.DisableSomeRoamingForBrokenMobileSemantics()
8283

83-
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder())
84+
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder(), t.amneziaConfig)
8485
err = t.configurer.ConfigureInterface(t.key, t.port)
8586
if err != nil {
8687
t.device.Close()

client/iface/device/device_darwin.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,18 @@ type TunDevice struct {
2929
filteredDevice *FilteredDevice
3030
udpMux *udpmux.UniversalUDPMuxDefault
3131
configurer WGConfigurer
32+
amneziaConfig AmneziaConfig
3233
}
3334

34-
func NewTunDevice(name string, address wgaddr.Address, port int, key string, mtu uint16, iceBind *bind.ICEBind) *TunDevice {
35+
func NewTunDevice(name string, address wgaddr.Address, port int, key string, mtu uint16, iceBind *bind.ICEBind, amneziaConfig AmneziaConfig) *TunDevice {
3536
return &TunDevice{
36-
name: name,
37-
address: address,
38-
port: port,
39-
key: key,
40-
mtu: mtu,
41-
iceBind: iceBind,
37+
name: name,
38+
address: address,
39+
port: port,
40+
key: key,
41+
mtu: mtu,
42+
iceBind: iceBind,
43+
amneziaConfig: amneziaConfig,
4244
}
4345
}
4446

@@ -62,7 +64,7 @@ func (t *TunDevice) Create() (WGConfigurer, error) {
6264
return nil, fmt.Errorf("error assigning ip: %s", err)
6365
}
6466

65-
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder())
67+
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder(), t.amneziaConfig)
6668
err = t.configurer.ConfigureInterface(t.key, t.port)
6769
if err != nil {
6870
t.device.Close()

client/iface/device/device_ios.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,19 @@ type TunDevice struct {
3131
filteredDevice *FilteredDevice
3232
udpMux *udpmux.UniversalUDPMuxDefault
3333
configurer WGConfigurer
34+
amneziaConfig AmneziaConfig
3435
}
3536

36-
func NewTunDevice(name string, address wgaddr.Address, port int, key string, mtu uint16, iceBind *bind.ICEBind, tunFd int) *TunDevice {
37+
func NewTunDevice(name string, address wgaddr.Address, port int, key string, mtu uint16, iceBind *bind.ICEBind, tunFd int, amneziaConfig AmneziaConfig) *TunDevice {
3738
return &TunDevice{
38-
name: name,
39-
address: address,
40-
port: port,
41-
key: key,
42-
mtu: mtu,
43-
iceBind: iceBind,
44-
tunFd: tunFd,
39+
name: name,
40+
address: address,
41+
port: port,
42+
key: key,
43+
mtu: mtu,
44+
iceBind: iceBind,
45+
tunFd: tunFd,
46+
amneziaConfig: amneziaConfig,
4547
}
4648
}
4749

@@ -74,7 +76,7 @@ func (t *TunDevice) Create() (WGConfigurer, error) {
7476
// this helps with support for the older NetBird clients that had a hardcoded direct mode
7577
// t.device.DisableSomeRoamingForBrokenMobileSemantics()
7678

77-
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder())
79+
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder(), t.amneziaConfig)
7880
err = t.configurer.ConfigureInterface(t.key, t.port)
7981
if err != nil {
8082
t.device.Close()

client/iface/device/device_netstack.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,12 @@ type TunNetstackDevice struct {
3737
nsTun *nbnetstack.NetStackTun
3838
udpMux *udpmux.UniversalUDPMuxDefault
3939
configurer WGConfigurer
40+
amneziaConfig configurer.AmneziaConfig
4041

4142
net *netstack.Net
4243
}
4344

44-
func NewNetstackDevice(name string, address wgaddr.Address, wgPort int, key string, mtu uint16, bind Bind, listenAddress string) *TunNetstackDevice {
45+
func NewNetstackDevice(name string, address wgaddr.Address, wgPort int, key string, mtu uint16, bind Bind, listenAddress string, amneziaConfig configurer.AmneziaConfig) *TunNetstackDevice {
4546
return &TunNetstackDevice{
4647
name: name,
4748
address: address,
@@ -50,6 +51,7 @@ func NewNetstackDevice(name string, address wgaddr.Address, wgPort int, key stri
5051
mtu: mtu,
5152
listenAddress: listenAddress,
5253
bind: bind,
54+
amneziaConfig: amneziaConfig,
5355
}
5456
}
5557

@@ -78,7 +80,7 @@ func (t *TunNetstackDevice) create() (WGConfigurer, error) {
7880
device.NewLogger(wgLogLevel(), "[netbird] "),
7981
)
8082

81-
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.bind.ActivityRecorder())
83+
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.bind.ActivityRecorder(), t.amneziaConfig)
8284
err = t.configurer.ConfigureInterface(t.key, t.port)
8385
if err != nil {
8486
_ = tunIface.Close()

client/iface/device/device_netstack_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package device
33
import (
44
"testing"
55

6+
"github.com/netbirdio/netbird/client/internal/amneziawg"
67
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
78

89
"github.com/netbirdio/netbird/client/iface/bind"
@@ -15,7 +16,7 @@ func TestNewNetstackDevice(t *testing.T) {
1516
wgAddress, _ := wgaddr.ParseWGAddress("1.2.3.4/24")
1617

1718
relayBind := bind.NewRelayBindJS()
18-
nsTun := NewNetstackDevice("wtx", wgAddress, 1234, privateKey.String(), 1500, relayBind, netstack.ListenAddr())
19+
nsTun := NewNetstackDevice("wtx", wgAddress, 1234, privateKey.String(), 1500, relayBind, netstack.ListenAddr(), amneziawg.AmneziaConfig{})
1920

2021
cfgr, err := nsTun.Create()
2122
if err != nil {

client/iface/device/device_usp_unix.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,20 @@ type USPDevice struct {
2828
filteredDevice *FilteredDevice
2929
udpMux *udpmux.UniversalUDPMuxDefault
3030
configurer WGConfigurer
31+
amneziaConfig configurer.AmneziaConfig
3132
}
3233

33-
func NewUSPDevice(name string, address wgaddr.Address, port int, key string, mtu uint16, iceBind *bind.ICEBind) *USPDevice {
34+
func NewUSPDevice(name string, address wgaddr.Address, port int, key string, mtu uint16, iceBind *bind.ICEBind, amneziaConfig configurer.AmneziaConfig) *USPDevice {
3435
log.Infof("using userspace bind mode")
3536

3637
return &USPDevice{
37-
name: name,
38-
address: address,
39-
port: port,
40-
key: key,
41-
mtu: mtu,
42-
iceBind: iceBind,
38+
name: name,
39+
address: address,
40+
port: port,
41+
key: key,
42+
mtu: mtu,
43+
iceBind: iceBind,
44+
amneziaConfig: amneziaConfig,
4345
}
4446
}
4547

@@ -65,7 +67,7 @@ func (t *USPDevice) Create() (WGConfigurer, error) {
6567
return nil, fmt.Errorf("error assigning ip: %s", err)
6668
}
6769

68-
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder())
70+
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder(), t.amneziaConfig)
6971
err = t.configurer.ConfigureInterface(t.key, t.port)
7072
if err != nil {
7173
t.device.Close()

client/iface/device/device_windows.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,18 @@ type TunDevice struct {
3333
filteredDevice *FilteredDevice
3434
udpMux *udpmux.UniversalUDPMuxDefault
3535
configurer WGConfigurer
36+
amneziaConfig configurer.AmneziaConfig
3637
}
3738

38-
func NewTunDevice(name string, address wgaddr.Address, port int, key string, mtu uint16, iceBind *bind.ICEBind) *TunDevice {
39+
func NewTunDevice(name string, address wgaddr.Address, port int, key string, mtu uint16, iceBind *bind.ICEBind, amneziaConfig configurer.AmneziaConfig) *TunDevice {
3940
return &TunDevice{
40-
name: name,
41-
address: address,
42-
port: port,
43-
key: key,
44-
mtu: mtu,
45-
iceBind: iceBind,
41+
name: name,
42+
address: address,
43+
port: port,
44+
key: key,
45+
mtu: mtu,
46+
iceBind: iceBind,
47+
amneziaConfig: amneziaConfig,
4648
}
4749
}
4850

@@ -96,7 +98,7 @@ func (t *TunDevice) Create() (WGConfigurer, error) {
9698
return nil, fmt.Errorf("error assigning ip: %s", err)
9799
}
98100

99-
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder())
101+
t.configurer = configurer.NewUSPConfigurer(t.device, t.name, t.iceBind.ActivityRecorder(), t.amneziaConfig)
100102
err = t.configurer.ConfigureInterface(t.key, t.port)
101103
if err != nil {
102104
t.device.Close()

0 commit comments

Comments
 (0)