github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/services/wireguard/service/service.go (about) 1 /* 2 * Copyright (C) 2019 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 service 19 20 import ( 21 "encoding/json" 22 "fmt" 23 "net" 24 "sync" 25 "time" 26 27 "github.com/jinzhu/copier" 28 "github.com/pkg/errors" 29 "github.com/rs/zerolog/log" 30 31 "github.com/mysteriumnetwork/node/config" 32 "github.com/mysteriumnetwork/node/core/ip" 33 "github.com/mysteriumnetwork/node/core/service" 34 "github.com/mysteriumnetwork/node/core/shaper" 35 "github.com/mysteriumnetwork/node/dns" 36 "github.com/mysteriumnetwork/node/eventbus" 37 "github.com/mysteriumnetwork/node/firewall" 38 "github.com/mysteriumnetwork/node/nat" 39 wg "github.com/mysteriumnetwork/node/services/wireguard" 40 "github.com/mysteriumnetwork/node/services/wireguard/endpoint" 41 "github.com/mysteriumnetwork/node/services/wireguard/key" 42 "github.com/mysteriumnetwork/node/services/wireguard/resources" 43 "github.com/mysteriumnetwork/node/services/wireguard/wgcfg" 44 "github.com/mysteriumnetwork/node/utils/netutil" 45 ) 46 47 // NewManager creates new instance of Wireguard service 48 func NewManager( 49 ipResolver ip.Resolver, 50 country string, 51 natService nat.NATService, 52 eventBus eventbus.EventBus, 53 trafficFirewall firewall.IncomingTrafficFirewall, 54 resourcesAllocator *resources.Allocator, 55 wgClientFactory *endpoint.WgClientFactory, 56 dnsProxy *dns.Proxy, 57 ) *Manager { 58 return &Manager{ 59 done: make(chan struct{}), 60 resourcesAllocator: resourcesAllocator, 61 ipResolver: ipResolver, 62 natService: natService, 63 eventBus: eventBus, 64 trafficFirewall: trafficFirewall, 65 dnsProxy: dnsProxy, 66 67 connEndpointFactory: func() (wg.ConnectionEndpoint, error) { 68 return endpoint.NewConnectionEndpoint(resourcesAllocator, wgClientFactory) 69 }, 70 country: country, 71 sessionCleanup: map[string]func(){}, 72 } 73 } 74 75 // Manager represents an instance of Wireguard service 76 type Manager struct { 77 done chan struct{} 78 startStopMu sync.Mutex 79 80 resourcesAllocator *resources.Allocator 81 82 natService nat.NATService 83 eventBus eventbus.EventBus 84 trafficFirewall firewall.IncomingTrafficFirewall 85 86 dnsProxy *dns.Proxy 87 88 connEndpointFactory func() (wg.ConnectionEndpoint, error) 89 90 ipResolver ip.Resolver 91 92 serviceInstance *service.Instance 93 sessionCleanup map[string]func() 94 sessionCleanupMu sync.Mutex 95 96 country string 97 outboundIP string 98 } 99 100 // ProvideConfig provides the config for consumer and handles new WireGuard connection. 101 func (m *Manager) ProvideConfig(sessionID string, sessionConfig json.RawMessage, remoteConn *net.UDPConn) (*service.ConfigParams, error) { 102 log.Info().Msg("Accepting new WireGuard connection") 103 consumerConfig := wg.ConsumerConfig{} 104 err := json.Unmarshal(sessionConfig, &consumerConfig) 105 if err != nil { 106 return nil, errors.Wrap(err, "could not unmarshal wg consumer config") 107 } 108 109 remoteConn.Close() 110 listenPort := remoteConn.LocalAddr().(*net.UDPAddr).Port 111 providerConfig, err := m.createProviderConfig(listenPort, consumerConfig.PublicKey) 112 if err != nil { 113 return nil, fmt.Errorf("could not create provider mode wg config: %w", err) 114 } 115 116 publicIP, err := m.ipResolver.GetPublicIP() 117 if err != nil { 118 return nil, errors.Wrap(err, "could not get public IP") 119 } 120 121 conn, err := m.startNewConnection(publicIP, providerConfig) 122 if err != nil { 123 return nil, errors.Wrap(err, "could not start new connection") 124 } 125 126 config, err := conn.Config() 127 if err != nil { 128 return nil, errors.Wrap(err, "could not get peer config") 129 } 130 131 var dnsIP net.IP 132 var releaseTrafficFirewall firewall.IncomingRuleRemove 133 if m.serviceInstance.PolicyProvider().HasDNSRules() { 134 releaseTrafficFirewall, err = m.trafficFirewall.BlockIncomingTraffic(providerConfig.Subnet) 135 if err != nil { 136 return nil, errors.Wrap(err, "failed to enable traffic blocking") 137 } 138 } 139 140 dnsIP = netutil.FirstIP(config.Consumer.IPAddress) 141 config.Consumer.DNSIPs = dnsIP.String() 142 143 natRules, err := m.natService.Setup(nat.Options{ 144 VPNNetwork: config.Consumer.IPAddress, 145 DNSIP: dnsIP, 146 ProviderExtIP: net.ParseIP(m.outboundIP), 147 }) 148 if err != nil { 149 return nil, errors.Wrap(err, "failed to setup NAT/firewall rules") 150 } 151 152 statsPublisher := newStatsPublisher(m.eventBus, time.Second) 153 go statsPublisher.start(sessionID, conn) 154 155 ifaceName := conn.InterfaceName() 156 s := shaper.New(m.eventBus) 157 err = s.Start(ifaceName) 158 if err != nil { 159 log.Error().Err(err).Msg("Could not start traffic shaper") 160 } 161 162 destroy := func() { 163 log.Info().Msgf("Cleaning up session %s", sessionID) 164 m.sessionCleanupMu.Lock() 165 defer m.sessionCleanupMu.Unlock() 166 _, ok := m.sessionCleanup[sessionID] 167 if !ok { 168 log.Info().Msgf("Session '%s' was already cleaned up, returning without changes", sessionID) 169 return 170 } 171 delete(m.sessionCleanup, sessionID) 172 173 statsPublisher.stop() 174 175 s.Clear(ifaceName) 176 177 if releaseTrafficFirewall != nil { 178 if err := releaseTrafficFirewall(); err != nil { 179 log.Warn().Err(err).Msg("failed to disable traffic blocking") 180 } 181 } 182 183 log.Trace().Msg("Deleting nat rules") 184 if err := m.natService.Del(natRules); err != nil { 185 log.Error().Err(err).Msg("Failed to delete NAT rules") 186 } 187 188 log.Trace().Msg("Stopping connection endpoint") 189 if err := conn.Stop(); err != nil { 190 log.Error().Err(err).Msg("Failed to stop connection endpoint") 191 } 192 193 if err := m.resourcesAllocator.ReleaseIPNet(providerConfig.Subnet); err != nil { 194 log.Error().Err(err).Msg("Failed to release IP network") 195 } 196 } 197 198 m.sessionCleanupMu.Lock() 199 m.sessionCleanup[sessionID] = destroy 200 m.sessionCleanupMu.Unlock() 201 202 return &service.ConfigParams{SessionServiceConfig: config, SessionDestroyCallback: destroy}, nil 203 } 204 205 func (m *Manager) createProviderConfig(listenPort int, peerPublicKey string) (wgcfg.DeviceConfig, error) { 206 network, err := m.resourcesAllocator.AllocateIPNet() 207 if err != nil { 208 return wgcfg.DeviceConfig{}, errors.Wrap(err, "could not allocate provider IP NET") 209 } 210 211 privateKey, err := key.GeneratePrivateKey() 212 if err != nil { 213 return wgcfg.DeviceConfig{}, fmt.Errorf("could not generate private key: %w", err) 214 } 215 216 return wgcfg.DeviceConfig{ 217 IfaceName: "", // Interface name will be generated by connection endpoint. 218 MTU: config.GetInt(config.FlagWireguardMTU), 219 Subnet: network, 220 PrivateKey: privateKey, 221 ListenPort: listenPort, 222 DNSPort: config.GetInt(config.FlagDNSListenPort), 223 DNS: nil, 224 Peer: wgcfg.Peer{ 225 PublicKey: peerPublicKey, 226 // Peer endpoint is set automatically by wg once client does handshake. 227 Endpoint: nil, 228 AllowedIPs: []string{"0.0.0.0/0", "::/0"}, 229 KeepAlivePeriodSeconds: 0, 230 }, 231 ReplacePeers: true, 232 }, nil 233 } 234 235 func (m *Manager) startNewConnection(publicIP string, config wgcfg.DeviceConfig) (wg.ConnectionEndpoint, error) { 236 connEndpoint, err := m.connEndpointFactory() 237 if err != nil { 238 return nil, errors.Wrap(err, "could not run conn endpoint factory") 239 } 240 241 if err := connEndpoint.StartProviderMode(publicIP, config); err != nil { 242 return nil, errors.Wrap(err, "could not start provider wg connection endpoint") 243 } 244 return connEndpoint, nil 245 } 246 247 // Serve starts service - does block 248 func (m *Manager) Serve(instance *service.Instance) error { 249 log.Info().Msg("Wireguard: starting") 250 m.startStopMu.Lock() 251 m.serviceInstance = instance 252 253 var err error 254 m.outboundIP, err = m.ipResolver.GetOutboundIP() 255 if err != nil { 256 return errors.Wrap(err, "could not get outbound IP") 257 } 258 259 if err := m.dnsProxy.Run(); err != nil { 260 log.Error().Err(err).Msg("Provider DNS will not be available") 261 262 return err 263 } 264 265 m.startStopMu.Unlock() 266 log.Info().Msg("Wireguard: started") 267 <-m.done 268 return nil 269 } 270 271 // Stop stops service. 272 func (m *Manager) Stop() error { 273 log.Info().Msg("Wireguard: stopping") 274 m.startStopMu.Lock() 275 defer m.startStopMu.Unlock() 276 277 cleanupWg := sync.WaitGroup{} 278 279 // prevent concurrent iteration and write 280 sessionCleanupCopy := make(map[string]func()) 281 if err := copier.Copy(&sessionCleanupCopy, m.sessionCleanup); err != nil { 282 panic(err) 283 } 284 for k, v := range sessionCleanupCopy { 285 cleanupWg.Add(1) 286 go func(sessionID string, cleanup func()) { 287 defer cleanupWg.Done() 288 cleanup() 289 }(k, v) 290 } 291 cleanupWg.Wait() 292 293 // Stop DNS proxy. 294 if m.dnsProxy != nil { 295 if err := m.dnsProxy.Stop(); err != nil { 296 log.Error().Err(err).Msg("Failed to stop DNS server") 297 } 298 } 299 300 close(m.done) 301 log.Info().Msg("Wireguard: stopped") 302 return nil 303 }