Files
Your Name c353e76058 add
2025-07-27 22:55:43 +08:00

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")
}