github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/services/wireguard/endpoint/netstack-provider/client.go (about) 1 /* 2 * Copyright (C) 2022 The "MysteriumNetwork/node" Authors. 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 package netstack_provider 19 20 import ( 21 "bufio" 22 "fmt" 23 "net/netip" 24 "strings" 25 "sync" 26 27 "github.com/rs/zerolog/log" 28 "golang.zx2c4.com/wireguard/conn" 29 "golang.zx2c4.com/wireguard/device" 30 31 "github.com/mysteriumnetwork/node/services/wireguard/endpoint/userspace" 32 "github.com/mysteriumnetwork/node/services/wireguard/wgcfg" 33 ) 34 35 type client struct { 36 mu sync.Mutex 37 Device *device.Device 38 } 39 40 // New create new WireGuard client in full userspace environment using netstack. 41 func New() (*client, error) { 42 log.Debug().Msg("Creating userspace wg client") 43 return &client{}, nil 44 } 45 46 func (c *client) ReConfigureDevice(config wgcfg.DeviceConfig) error { 47 return c.ConfigureDevice(config) 48 } 49 50 func (c *client) ConfigureDevice(cfg wgcfg.DeviceConfig) error { 51 tunnel, _, _, err := CreateNetTUNWithStack([]netip.Addr{netip.MustParseAddr(cfg.Subnet.IP.String())}, cfg.DNSPort, device.DefaultMTU) 52 if err != nil { 53 return fmt.Errorf("failed to create netstack device %s: %w", cfg.IfaceName, err) 54 } 55 56 logger := device.NewLogger(device.LogLevelVerbose, fmt.Sprintf("(%s) ", cfg.IfaceName)) 57 wgDevice := device.NewDevice(tunnel, conn.NewDefaultBind(), logger) 58 59 log.Info().Msg("Applying interface configuration") 60 if err := wgDevice.IpcSetOperation(bufio.NewReader(strings.NewReader(cfg.Encode()))); err != nil { 61 wgDevice.Close() 62 return fmt.Errorf("could not set device uapi config: %w", err) 63 } 64 65 log.Info().Msg("Bringing device up") 66 wgDevice.Up() 67 68 c.mu.Lock() 69 c.Device = wgDevice 70 c.mu.Unlock() 71 72 return nil 73 } 74 75 func (c *client) DestroyDevice(iface string) error { 76 return c.Close() 77 } 78 79 func (c *client) PeerStats(iface string) (wgcfg.Stats, error) { 80 deviceState, err := userspace.ParseUserspaceDevice(c.Device.IpcGetOperation) 81 if err != nil { 82 return wgcfg.Stats{}, fmt.Errorf("could not parse device state: %w", err) 83 } 84 85 stats, statErr := userspace.ParseDevicePeerStats(deviceState) 86 if err != nil { 87 err = statErr 88 log.Warn().Err(err).Msg("Failed to parse device stats, will try again") 89 } else { 90 return stats, nil 91 } 92 93 return wgcfg.Stats{}, fmt.Errorf("could not parse device state: %w", err) 94 } 95 96 func (c *client) Close() (err error) { 97 c.mu.Lock() 98 defer c.mu.Unlock() 99 100 if c.Device != nil { 101 c.Device.Close() 102 } 103 104 return nil 105 }