/* SPDX-License-Identifier: MIT * * Copyright (C) 2017-2025 WireGuard LLC. All Rights Reserved. */ package device import ( "fmt" "net" "runtime" "golang.zx2c4.com/wireguard/conn" "golang.zx2c4.com/wireguard/tun" ) // MultiPathConfig represents configuration for multi-path networking type MultiPathConfig struct { // InterfaceIndexes are the network interface indexes to bind to // If empty, uses default interface selection InterfaceIndexes []uint32 // BindFactory creates new Bind instances. If nil, uses conn.NewStdNetBind() BindFactory func() conn.Bind } // NewMultiPathDevice creates a new WireGuard device with multi-path networking // It creates separate bind instances for each specified network interface func NewMultiPathDevice(tunDevice tun.Device, config MultiPathConfig, logger *Logger) (*Device, error) { if len(config.InterfaceIndexes) == 0 { return nil, fmt.Errorf("MultiPathConfig must specify at least one interface index") } // Use default bind factory if none specified bindFactory := config.BindFactory if bindFactory == nil { bindFactory = func() conn.Bind { return conn.NewStdNetBind() } } // Create a bind for each interface binds := make([]conn.Bind, len(config.InterfaceIndexes)) for i := range config.InterfaceIndexes { binds[i] = bindFactory() } // Create multi-path bind multiPathBind := conn.NewMultiPathBind(binds) // Configure each bind to use its specific interface for i, interfaceIndex := range config.InterfaceIndexes { err := multiPathBind.BindToInterface(i, interfaceIndex, false) if err != nil { logger.Errorf("Failed to bind to interface %d: %v", interfaceIndex, err) // Continue with other interfaces rather than failing completely } else { logger.Verbosef("Bound network path %d to interface index %d", i, interfaceIndex) } } // Create device with multi-path bind device := NewDevice(tunDevice, multiPathBind, logger) logger.Verbosef("Created multi-path WireGuard device with %d network paths", len(config.InterfaceIndexes)) return device, nil } // NewMultiPathDeviceByNames creates a multi-path device using interface names instead of indexes func NewMultiPathDeviceByNames(tunDevice tun.Device, interfaceNames []string, logger *Logger) (*Device, error) { if len(interfaceNames) == 0 { return nil, fmt.Errorf("must specify at least one interface name") } // Convert interface names to indexes interfaceIndexes := make([]uint32, len(interfaceNames)) for i, name := range interfaceNames { iface, err := net.InterfaceByName(name) if err != nil { return nil, fmt.Errorf("failed to find interface %s: %w", name, err) } interfaceIndexes[i] = uint32(iface.Index) logger.Verbosef("Interface %s has index %d", name, iface.Index) } config := MultiPathConfig{ InterfaceIndexes: interfaceIndexes, } return NewMultiPathDevice(tunDevice, config, logger) } // GetNetworkInterfaceInfo returns information about available network interfaces func GetNetworkInterfaceInfo() ([]NetworkInterfaceInfo, error) { interfaces, err := net.Interfaces() if err != nil { return nil, fmt.Errorf("failed to list network interfaces: %w", err) } result := make([]NetworkInterfaceInfo, 0, len(interfaces)) for _, iface := range interfaces { // Skip loopback and down interfaces for multi-path networking if iface.Flags&net.FlagLoopback != 0 || iface.Flags&net.FlagUp == 0 { continue } addrs, _ := iface.Addrs() addrStrings := make([]string, len(addrs)) for i, addr := range addrs { addrStrings[i] = addr.String() } result = append(result, NetworkInterfaceInfo{ Index: uint32(iface.Index), Name: iface.Name, Addresses: addrStrings, MTU: iface.MTU, Flags: iface.Flags, }) } return result, nil } // NetworkInterfaceInfo represents information about a network interface type NetworkInterfaceInfo struct { Index uint32 Name string Addresses []string MTU int Flags net.Flags } // String returns a human-readable description of the interface func (nii NetworkInterfaceInfo) String() string { return fmt.Sprintf("Interface %s (index %d): MTU=%d, Addresses=%v, Flags=%v", nii.Name, nii.Index, nii.MTU, nii.Addresses, nii.Flags) } // Example usage function func ExampleMultiPathUsage(logger *Logger) { // Print available interfaces interfaces, err := GetNetworkInterfaceInfo() if err != nil { logger.Errorf("Failed to get interface info: %v", err) return } logger.Verbosef("Available network interfaces:") for _, iface := range interfaces { logger.Verbosef(" %s", iface.String()) } // Example: Create multi-path device using specific interface names // This would send each packet through both eth0 and wlan0 interfaceNames := []string{"eth0", "wlan0"} // Note: You would need to create/configure your TUN device // tunDevice, err := tun.CreateTUN("wg0", 1420) // if err != nil { // logger.Errorf("Failed to create TUN: %v", err) // return // } // // device, err := NewMultiPathDeviceByNames(tunDevice, interfaceNames, logger) // if err != nil { // logger.Errorf("Failed to create multi-path device: %v", err) // return // } // // logger.Verbosef("Multi-path WireGuard device created successfully") }