github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/supervisor/daemon/wireguard/wginterface/interface.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 wginterface
    19  
    20  import (
    21  	"bufio"
    22  	"fmt"
    23  	"net"
    24  	"strings"
    25  
    26  	"github.com/rs/zerolog/log"
    27  	"golang.zx2c4.com/wireguard/conn"
    28  	"golang.zx2c4.com/wireguard/device"
    29  
    30  	"github.com/mysteriumnetwork/node/services/wireguard/connection/dns"
    31  	"github.com/mysteriumnetwork/node/services/wireguard/wgcfg"
    32  	"github.com/mysteriumnetwork/node/utils/netutil"
    33  )
    34  
    35  // WgInterface represents WireGuard tunnel with underlying device.
    36  type WgInterface struct {
    37  	Name       string
    38  	Device     *device.Device
    39  	uapi       net.Listener
    40  	dnsManager dns.Manager
    41  }
    42  
    43  // New creates new WgInterface instance.
    44  func New(cfg wgcfg.DeviceConfig, uid string) (*WgInterface, error) {
    45  	tunnel, interfaceName, err := createTunnel(cfg.IfaceName, cfg.DNS)
    46  	if err != nil {
    47  		return nil, fmt.Errorf("failed to create TUN device %s: %w", cfg.IfaceName, err)
    48  	}
    49  
    50  	logger := device.NewLogger(device.LogLevelVerbose, fmt.Sprintf("(%s) ", interfaceName))
    51  	logger.Verbosef("Starting wireguard-go")
    52  
    53  	logger.Verbosef("Starting device")
    54  	wgDevice := device.NewDevice(tunnel, conn.NewDefaultBind(), logger)
    55  
    56  	log.Info().Msg("Creating UAPI listener")
    57  	uapi, err := newUAPIListener(interfaceName)
    58  	if err != nil {
    59  		return nil, fmt.Errorf("failed to listen on UAPI socket: %w", err)
    60  	}
    61  
    62  	log.Info().Msg("Applying interface configuration")
    63  	if err := wgDevice.IpcSetOperation(bufio.NewReader(strings.NewReader(cfg.Encode()))); err != nil {
    64  		down(uapi, wgDevice, nil)
    65  		return nil, fmt.Errorf("could not set device uapi config: %w", err)
    66  	}
    67  
    68  	log.Info().Msg("Bringing device up")
    69  	wgDevice.Up()
    70  
    71  	log.Info().Msg("Configuring network")
    72  	dnsManager := dns.NewManager()
    73  	if err := configureNetwork(cfg, dnsManager); err != nil {
    74  		down(uapi, wgDevice, dnsManager)
    75  		return nil, fmt.Errorf("could not setup network: %w", err)
    76  	}
    77  
    78  	if err := applySocketPermissions(interfaceName, uid); err != nil {
    79  		down(uapi, wgDevice, dnsManager)
    80  		return nil, fmt.Errorf("could not apply socket permissions: %w", err)
    81  	}
    82  
    83  	wgInterface := &WgInterface{
    84  		Name:       interfaceName,
    85  		Device:     wgDevice,
    86  		uapi:       uapi,
    87  		dnsManager: dnsManager,
    88  	}
    89  	log.Info().Msg("Accepting UAPI requests")
    90  	go wgInterface.accept()
    91  
    92  	return wgInterface, nil
    93  }
    94  
    95  // Reconfigure applies new configuration for the existing wireguard interface.
    96  func (a *WgInterface) Reconfigure(cfg wgcfg.DeviceConfig) error {
    97  	log.Info().Msgf("Applying interface configuration")
    98  	if err := a.Device.IpcSetOperation(bufio.NewReader(strings.NewReader(cfg.Encode()))); err != nil {
    99  		return fmt.Errorf("could not set device uapi config: %w", err)
   100  	}
   101  
   102  	log.Info().Msg("Bringing device up")
   103  	a.Device.Up()
   104  
   105  	log.Info().Msg("Configuring network")
   106  	dnsManager := dns.NewManager()
   107  	if err := configureNetwork(cfg, dnsManager); err != nil {
   108  		return fmt.Errorf("could not setup network: %w", err)
   109  	}
   110  
   111  	return nil
   112  }
   113  
   114  // Accept listens for WireGuard configuration changes via user space socket.
   115  func (a *WgInterface) accept() {
   116  	for {
   117  		conn, err := a.uapi.Accept()
   118  		if err != nil {
   119  			log.Err(err).Msg("Failed to close UAPI listener")
   120  			return
   121  		}
   122  		go a.Device.IpcHandle(conn)
   123  	}
   124  }
   125  
   126  func down(uapi net.Listener, d *device.Device, dnsManager dns.Manager) {
   127  	if uapi != nil {
   128  		if err := uapi.Close(); err != nil {
   129  			log.Warn().Err(err).Msg("Could not close uapi socket")
   130  		}
   131  	}
   132  	if d != nil {
   133  		d.Close()
   134  	}
   135  
   136  	disableFirewall()
   137  
   138  	if dnsManager != nil {
   139  		if err := dnsManager.Clean(); err != nil {
   140  			log.Err(err).Msg("Could not clean DNS")
   141  		}
   142  	}
   143  }
   144  
   145  // Down closes device and user space api socket.
   146  func (a *WgInterface) Down() {
   147  	down(a.uapi, a.Device, a.dnsManager)
   148  }
   149  
   150  func configureNetwork(cfg wgcfg.DeviceConfig, dnsManager dns.Manager) error {
   151  	if err := netutil.AssignIP(cfg.IfaceName, cfg.Subnet); err != nil {
   152  		return fmt.Errorf("failed to assign IP address: %w", err)
   153  	}
   154  
   155  	if cfg.Peer.Endpoint != nil {
   156  		if err := netutil.AddDefaultRoute(cfg.IfaceName); err != nil {
   157  			return fmt.Errorf("could not add default route for %s: %w", cfg.IfaceName, err)
   158  		}
   159  	}
   160  
   161  	if err := dnsManager.Set(dns.Config{
   162  		ScriptDir: cfg.DNSScriptDir,
   163  		IfaceName: cfg.IfaceName,
   164  		DNS:       cfg.DNS,
   165  	}); err != nil {
   166  		return fmt.Errorf("could not set DNS: %w", err)
   167  	}
   168  
   169  	return nil
   170  }