github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/services/wireguard/endpoint/remoteclient/client.go (about) 1 /* 2 * Copyright (C) 2020 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 remoteclient 19 20 import ( 21 "encoding/base64" 22 "encoding/json" 23 "fmt" 24 "os/user" 25 "sync" 26 27 "github.com/rs/zerolog/log" 28 29 "github.com/mysteriumnetwork/node/services/wireguard/wgcfg" 30 supervisorclient "github.com/mysteriumnetwork/node/supervisor/client" 31 "github.com/mysteriumnetwork/node/utils" 32 ) 33 34 type client struct { 35 mu sync.Mutex 36 iface string 37 } 38 39 // New create new remote WireGuard client which communicates with supervisor. 40 func New() (*client, error) { 41 log.Debug().Msg("Creating remote wg client") 42 return &client{}, nil 43 } 44 45 func (c *client) ReConfigureDevice(config wgcfg.DeviceConfig) error { 46 return c.ConfigureDevice(config) 47 } 48 49 func (c *client) ConfigureDevice(config wgcfg.DeviceConfig) error { 50 c.mu.Lock() 51 defer c.mu.Unlock() 52 c.iface = config.IfaceName 53 currentUser, err := user.Current() 54 if err != nil { 55 return fmt.Errorf("could not get current OS user: %w", err) 56 } 57 58 jsonCfg, err := json.Marshal(config) 59 if err != nil { 60 return fmt.Errorf("could not marshal device config to JSON: %w", err) 61 } 62 63 // Convert config to base64 to prevent nasty parsing issues on supervisor. 64 jsonb64 := base64.StdEncoding.EncodeToString(jsonCfg) 65 66 actualIface, err := supervisorclient.Command("wg-up", "-uid", currentUser.Uid, "-config", jsonb64) 67 if err != nil { 68 return fmt.Errorf("failed to create wg interface: %w", err) 69 } 70 log.Debug().Msgf("Tunnel interface created: %s", actualIface) 71 return nil 72 } 73 74 func (c *client) DestroyDevice(iface string) error { 75 _, err := supervisorclient.Command("wg-down", "-iface", iface) 76 if err != nil { 77 return fmt.Errorf("failed to destroy wg interface: %w", err) 78 } 79 return nil 80 } 81 82 func (c *client) PeerStats(iface string) (wgcfg.Stats, error) { 83 statsJSON, err := supervisorclient.Command("wg-stats", "-iface", iface) 84 if err != nil { 85 return wgcfg.Stats{}, fmt.Errorf("failed to get wg stats: %w", err) 86 } 87 88 stats := wgcfg.Stats{} 89 if err := json.Unmarshal([]byte(statsJSON), &stats); err != nil { 90 return wgcfg.Stats{}, fmt.Errorf("could not unmarshal stats: %w", err) 91 } 92 return stats, nil 93 } 94 95 func (c *client) Close() (err error) { 96 c.mu.Lock() 97 defer c.mu.Unlock() 98 99 errs := utils.ErrorCollection{} 100 if err := c.DestroyDevice(c.iface); err != nil { 101 errs.Add(err) 102 } 103 if err := errs.Error(); err != nil { 104 return fmt.Errorf("could not close client: %w", err) 105 } 106 return nil 107 }