github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/services/wireguard/endpoint/proxyclient/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 proxyclient 19 20 import ( 21 "bufio" 22 "context" 23 "fmt" 24 "net/http" 25 "net/netip" 26 "strings" 27 "sync" 28 "time" 29 30 "github.com/rs/zerolog/log" 31 "golang.zx2c4.com/wireguard/conn" 32 "golang.zx2c4.com/wireguard/device" 33 34 "github.com/mysteriumnetwork/node/services/wireguard/endpoint/netstack" 35 "github.com/mysteriumnetwork/node/services/wireguard/endpoint/userspace" 36 "github.com/mysteriumnetwork/node/services/wireguard/wgcfg" 37 ) 38 39 type client struct { 40 mu sync.Mutex 41 Device *device.Device 42 proxyClose func() error 43 } 44 45 // New create new WireGuard client which serves requests via proxy. 46 func New() (*client, error) { 47 log.Debug().Msg("Creating proxy wg client") 48 return &client{}, nil 49 } 50 51 func (c *client) ReConfigureDevice(config wgcfg.DeviceConfig) error { 52 return c.ConfigureDevice(config) 53 } 54 55 func (c *client) ConfigureDevice(cfg wgcfg.DeviceConfig) error { 56 localAddr, err := netip.ParseAddr(cfg.Subnet.IP.String()) 57 if err != nil { 58 return fmt.Errorf("could not parse local addr: %w", err) 59 } 60 if len(cfg.DNS) == 0 { 61 return fmt.Errorf("DNS addr list is empty") 62 } 63 dnsAddr, err := netip.ParseAddr(cfg.DNS[0]) 64 if err != nil { 65 return fmt.Errorf("could not parse DNS addr: %w", err) 66 } 67 tunnel, tnet, err := netstack.CreateNetTUN([]netip.Addr{localAddr}, []netip.Addr{dnsAddr}, device.DefaultMTU) 68 if err != nil { 69 return fmt.Errorf("failed to create netstack device %s: %w", cfg.IfaceName, err) 70 } 71 72 logger := device.NewLogger(device.LogLevelVerbose, fmt.Sprintf("(%s) ", cfg.IfaceName)) 73 wgDevice := device.NewDevice(tunnel, conn.NewDefaultBind(), logger) 74 75 log.Info().Msg("Applying interface configuration") 76 if err := wgDevice.IpcSetOperation(bufio.NewReader(strings.NewReader(cfg.Encode()))); err != nil { 77 wgDevice.Close() 78 return fmt.Errorf("could not set device uapi config: %w", err) 79 } 80 81 log.Info().Msg("Bringing device up") 82 wgDevice.Up() 83 84 c.mu.Lock() 85 c.Device = wgDevice 86 c.mu.Unlock() 87 88 if err := c.Proxy(tnet, cfg.ProxyPort); err != nil { 89 wgDevice.Close() 90 return err 91 } 92 93 return nil 94 } 95 96 func (c *client) DestroyDevice(iface string) error { 97 return c.Close() 98 } 99 100 func (c *client) PeerStats(iface string) (wgcfg.Stats, error) { 101 deviceState, err := userspace.ParseUserspaceDevice(c.Device.IpcGetOperation) 102 if err != nil { 103 return wgcfg.Stats{}, fmt.Errorf("could not parse device state: %w", err) 104 } 105 106 stats, statErr := userspace.ParseDevicePeerStats(deviceState) 107 if err != nil { 108 err = statErr 109 log.Warn().Err(err).Msg("Failed to parse device stats, will try again") 110 } else { 111 return stats, nil 112 } 113 114 return wgcfg.Stats{}, fmt.Errorf("could not parse device state: %w", err) 115 } 116 117 func (c *client) Close() (err error) { 118 c.mu.Lock() 119 defer c.mu.Unlock() 120 121 if c.proxyClose != nil { 122 c.proxyClose() 123 } 124 125 if c.Device != nil { 126 go func() { 127 time.Sleep(2 * time.Minute) 128 c.Device.Close() 129 }() 130 } 131 return nil 132 } 133 134 func (c *client) Proxy(tnet *netstack.Net, proxyPort int) error { 135 c.mu.Lock() 136 defer c.mu.Unlock() 137 138 server := http.Server{ 139 Addr: fmt.Sprintf(":%d", proxyPort), 140 Handler: newProxyHandler(60*time.Second, tnet), 141 ReadTimeout: 0, 142 ReadHeaderTimeout: 0, 143 WriteTimeout: 0, 144 IdleTimeout: 0, 145 } 146 147 log.Info().Msgf("Starting proxy server at :%d ...", proxyPort) 148 c.proxyClose = func() error { 149 ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) 150 defer cancel() 151 server.Shutdown(ctx) 152 153 return server.Close() 154 } 155 156 go func() { 157 err := server.ListenAndServe() 158 log.Error().Err(err).Msg("Shutting down proxy server...") 159 }() 160 161 return nil 162 }