github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/services/wireguard/endpoint/endpoint.go (about) 1 /* 2 * Copyright (C) 2018 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 endpoint 19 20 import ( 21 "fmt" 22 "net" 23 24 "github.com/pkg/errors" 25 "github.com/rs/zerolog/log" 26 27 "github.com/mysteriumnetwork/node/config" 28 wg "github.com/mysteriumnetwork/node/services/wireguard" 29 "github.com/mysteriumnetwork/node/services/wireguard/key" 30 "github.com/mysteriumnetwork/node/services/wireguard/resources" 31 "github.com/mysteriumnetwork/node/services/wireguard/wgcfg" 32 "github.com/mysteriumnetwork/node/utils/netutil" 33 ) 34 35 // NewConnectionEndpoint returns new connection endpoint instance. 36 func NewConnectionEndpoint(resourceAllocator *resources.Allocator, wgClientFactory *WgClientFactory) (wg.ConnectionEndpoint, error) { 37 wgClient, err := wgClientFactory.NewWGClient() 38 if err != nil { 39 return nil, err 40 } 41 42 return &connectionEndpoint{ 43 wgClient: wgClient, 44 resourceAllocator: resourceAllocator, 45 }, nil 46 } 47 48 type connectionEndpoint struct { 49 cfg wgcfg.DeviceConfig 50 endpoint net.UDPAddr 51 resourceAllocator *resources.Allocator 52 wgClient WgClient 53 } 54 55 // StartConsumerMode starts and configure wireguard network interface running in consumer mode. 56 func (ce *connectionEndpoint) StartConsumerMode(cfg wgcfg.DeviceConfig) error { 57 if err := ce.cleanAbandonedInterfaces(); err != nil { 58 return err 59 } 60 61 var iface string 62 var err error 63 if cfg.ProxyPort > 0 { 64 iface = fmt.Sprintf("myst%d", cfg.ProxyPort) 65 } else { 66 iface, err = ce.resourceAllocator.AllocateInterface() 67 if err != nil { 68 return errors.Wrap(err, "could not allocate interface") 69 } 70 } 71 72 log.Debug().Msgf("Allocated interface: %s", iface) 73 74 cfg.IfaceName = iface 75 ce.cfg = cfg 76 77 if err := ce.wgClient.ConfigureDevice(cfg); err != nil { 78 if err1 := ce.resourceAllocator.ReleaseInterface(iface); err1 != nil { 79 log.Error().Err(err1).Msg("Can't release allocated interface " + iface) 80 } 81 return errors.Wrap(err, "could not configure device") 82 } 83 return nil 84 } 85 86 func (ce *connectionEndpoint) ReconfigureConsumerMode(cfg wgcfg.DeviceConfig) error { 87 cfg.IfaceName = ce.cfg.IfaceName 88 ce.cfg = cfg 89 90 if err := ce.wgClient.ReConfigureDevice(cfg); err != nil { 91 return fmt.Errorf("could not reconfigure device: %w", err) 92 } 93 94 return nil 95 } 96 97 func (ce *connectionEndpoint) StartProviderMode(publicIP string, config wgcfg.DeviceConfig) (err error) { 98 if publicIP == "" { 99 return errors.New("public IP is required") 100 } 101 if config.ListenPort == 0 { 102 return errors.New("listen port is required") 103 } 104 105 if err := ce.cleanAbandonedInterfaces(); err != nil { 106 return err 107 } 108 109 iface, err := ce.resourceAllocator.AllocateInterface() 110 if err != nil { 111 return errors.Wrap(err, "could not allocate interface") 112 } 113 114 config.IfaceName = iface 115 config.Subnet.IP = netutil.FirstIP(config.Subnet) 116 ce.cfg = config 117 ce.endpoint = net.UDPAddr{IP: net.ParseIP(publicIP), Port: config.ListenPort} 118 119 if err := ce.wgClient.ConfigureDevice(config); err != nil { 120 if err1 := ce.resourceAllocator.ReleaseInterface(iface); err1 != nil { 121 log.Error().Err(err1).Msg("Can't release allocated interface " + iface) 122 } 123 return errors.Wrap(err, "could not configure device") 124 } 125 return nil 126 } 127 128 // InterfaceName returns a connection endpoint interface name. 129 func (ce *connectionEndpoint) InterfaceName() string { 130 return ce.cfg.IfaceName 131 } 132 133 // PeerStats returns stats information about connected peer. 134 func (ce *connectionEndpoint) PeerStats() (wgcfg.Stats, error) { 135 return ce.wgClient.PeerStats(ce.cfg.IfaceName) 136 } 137 138 // Config provides wireguard service configuration for the current connection endpoint. 139 func (ce *connectionEndpoint) Config() (wg.ServiceConfig, error) { 140 publicKey, err := key.PrivateKeyToPublicKey(ce.cfg.PrivateKey) 141 if err != nil { 142 return wg.ServiceConfig{}, err 143 } 144 145 var config wg.ServiceConfig 146 config.Provider.PublicKey = publicKey 147 config.Provider.Endpoint = ce.endpoint 148 config.Consumer.IPAddress = ce.cfg.Subnet 149 config.Consumer.IPAddress.IP = ce.consumerIP(ce.cfg.Subnet) 150 return config, nil 151 } 152 153 // Stop closes wireguard client and destroys wireguard network interface. 154 func (ce *connectionEndpoint) Stop() error { 155 if err := ce.wgClient.Close(); err != nil { 156 return err 157 } 158 159 return ce.resourceAllocator.ReleaseInterface(ce.cfg.IfaceName) 160 } 161 162 func (ce *connectionEndpoint) cleanAbandonedInterfaces() error { 163 if config.GetBool(config.FlagDVPNMode) { 164 // Do not clean up unknown interfaces in dVPN mode. 165 // There could be several connections at the same time and we should not kill them. 166 return nil 167 } 168 169 ifaces, err := ce.resourceAllocator.AbandonedInterfaces() 170 if err != nil { 171 return err 172 } 173 174 for _, iface := range ifaces { 175 if err := ce.wgClient.DestroyDevice(iface.Name); err != nil { 176 log.Warn().Err(err).Msg("Failed to destroy abandoned interface: " + iface.Name) 177 } 178 log.Info().Msg("Abandoned interface destroyed: " + iface.Name) 179 } 180 181 return nil 182 }