169 lines
5.1 KiB
Go
169 lines
5.1 KiB
Go
/* SPDX-License-Identifier: MIT
|
|
*
|
|
* Copyright (C) 2017-2025 WireGuard LLC. All Rights Reserved.
|
|
*/
|
|
|
|
package device
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
|
|
"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
|
|
|
|
// 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")
|
|
} |