268 lines
7.6 KiB
Markdown
268 lines
7.6 KiB
Markdown
# Multi-Path WireGuard Implementation
|
|
|
|
This document describes the multi-path networking feature for WireGuard-Go, which allows sending the same packet through multiple network interfaces simultaneously.
|
|
|
|
## Overview
|
|
|
|
The multi-path implementation extends WireGuard-Go to support redundant packet transmission through multiple network paths. When configured, each outbound packet is sent through ALL specified network interfaces, providing:
|
|
|
|
- **Increased Reliability**: If one network path fails, communication continues through other paths
|
|
- **Better Performance**: Multiple paths can provide better throughput and lower latency
|
|
- **Redundancy**: Critical for scenarios where network reliability is paramount
|
|
|
|
## How It Works
|
|
|
|
### Architecture
|
|
|
|
The multi-path functionality is implemented through several key components:
|
|
|
|
1. **MultiPathBind** (`conn/multipath_bind.go`):
|
|
- Implements the `conn.Bind` interface
|
|
- Manages multiple underlying `Bind` instances
|
|
- Sends packets through ALL configured network paths
|
|
- Receives packets through the primary path only
|
|
|
|
2. **Multi-Path Device Creation** (`device/multipath.go`):
|
|
- Helper functions to create WireGuard devices with multiple network interfaces
|
|
- Interface discovery and configuration utilities
|
|
|
|
3. **Network Transmission Flow**:
|
|
```
|
|
TUN Device → Peer Lookup → Packet Staging → Sequential Sender →
|
|
SendBuffers → MultiPathBind.Send() → [Bind1, Bind2, Bind3, ...] → Network
|
|
```
|
|
|
|
### Code Locations
|
|
|
|
The actual network transmission happens in these key locations:
|
|
|
|
- **Primary Send Method**: `device/peer.go:135` - `peer.device.net.bind.Send(buffers, endpoint)`
|
|
- **Multi-Path Send**: `conn/multipath_bind.go:95` - Sends through all configured binds
|
|
- **Socket Transmission**: `conn/bind_std.go:339` - Individual socket transmission
|
|
|
|
## Usage
|
|
|
|
### Basic Usage
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"golang.zx2c4.com/wireguard/device"
|
|
"golang.zx2c4.com/wireguard/tun"
|
|
)
|
|
|
|
func main() {
|
|
// Create TUN device
|
|
tunDevice, err := tun.CreateTUN("wg-multipath", 1420)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer tunDevice.Close()
|
|
|
|
// Create logger
|
|
logger := device.NewLogger(device.LogLevelVerbose, "multipath: ")
|
|
|
|
// Create multi-path device using interface names
|
|
interfaceNames := []string{"eth0", "wlan0"}
|
|
wgDevice, err := device.NewMultiPathDeviceByNames(tunDevice, interfaceNames, logger)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer wgDevice.Close()
|
|
|
|
// Device is ready - configure with wg(8) tools and bring up
|
|
err = wgDevice.Up()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Now all outbound packets will be sent through both eth0 and wlan0
|
|
}
|
|
```
|
|
|
|
### Advanced Configuration
|
|
|
|
```go
|
|
// Using interface indexes instead of names
|
|
config := device.MultiPathConfig{
|
|
InterfaceIndexes: []uint32{2, 3, 4}, // eth0, wlan0, usb0
|
|
BindFactory: func() conn.Bind {
|
|
return conn.NewStdNetBind() // or custom bind implementation
|
|
},
|
|
}
|
|
|
|
wgDevice, err := device.NewMultiPathDevice(tunDevice, config, logger)
|
|
```
|
|
|
|
### Command Line Example
|
|
|
|
Build and run the example program:
|
|
|
|
```bash
|
|
# Build the example
|
|
go build -o multipath-example ./examples/multipath/
|
|
|
|
# List available interfaces
|
|
sudo ./multipath-example
|
|
|
|
# Create multi-path tunnel using eth0 and wlan0
|
|
sudo ./multipath-example eth0 wlan0
|
|
```
|
|
|
|
## Configuration
|
|
|
|
### Interface Discovery
|
|
|
|
Use the helper function to discover available network interfaces:
|
|
|
|
```go
|
|
interfaces, err := device.GetNetworkInterfaceInfo()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
for _, iface := range interfaces {
|
|
fmt.Printf("Interface: %s (index %d)\n", iface.Name, iface.Index)
|
|
fmt.Printf(" Addresses: %v\n", iface.Addresses)
|
|
fmt.Printf(" MTU: %d\n", iface.MTU)
|
|
}
|
|
```
|
|
|
|
### WireGuard Configuration
|
|
|
|
After creating the multi-path device, configure it normally with `wg(8)`:
|
|
|
|
```bash
|
|
# Generate keys
|
|
wg genkey | tee private.key | wg pubkey > public.key
|
|
|
|
# Configure the device
|
|
sudo wg set wg-multipath private-key private.key
|
|
sudo wg set wg-multipath peer <PEER_PUBLIC_KEY> \
|
|
endpoint <PEER_IP>:<PORT> \
|
|
allowed-ips 0.0.0.0/0
|
|
|
|
# Assign IP and bring up
|
|
sudo ip addr add 10.0.0.2/24 dev wg-multipath
|
|
sudo ip link set wg-multipath up
|
|
|
|
# Route traffic through the tunnel
|
|
sudo ip route add default dev wg-multipath
|
|
```
|
|
|
|
## Technical Details
|
|
|
|
### Packet Duplication
|
|
|
|
When `MultiPathBind.Send()` is called:
|
|
|
|
1. The same packet buffers are sent through ALL configured network binds
|
|
2. Each bind may be bound to a different network interface
|
|
3. The method succeeds if at least one bind successfully sends the packet
|
|
4. Errors from individual binds are logged but don't stop other binds
|
|
|
|
### Receiving
|
|
|
|
- Only the primary bind (first in the list) is used for receiving packets
|
|
- This prevents duplicate packet reception
|
|
- All receive functions come from the primary bind
|
|
|
|
### Error Handling
|
|
|
|
- Individual bind failures don't stop transmission through other binds
|
|
- At least one successful transmission is required for overall success
|
|
- Failed binds are logged for debugging
|
|
|
|
### Performance Considerations
|
|
|
|
- **CPU Usage**: Sending through multiple interfaces increases CPU usage proportionally
|
|
- **Memory**: Each bind maintains its own buffers and state
|
|
- **Network Bandwidth**: Total bandwidth usage is multiplied by the number of interfaces
|
|
- **Latency**: Latency is determined by the fastest responding interface
|
|
|
|
## Limitations
|
|
|
|
1. **Packet Duplication**: Receiving peer will see duplicate packets (WireGuard's replay protection handles this)
|
|
2. **Bandwidth Usage**: Network usage increases proportionally with number of interfaces
|
|
3. **Interface Binding**: Requires platform support for binding sockets to specific interfaces
|
|
4. **Receive Path**: Only receives through primary interface (no multi-path receiving)
|
|
|
|
## Platform Support
|
|
|
|
The multi-path functionality works on platforms that support:
|
|
- Socket binding to specific network interfaces
|
|
- Multiple UDP sockets on the same port (with SO_REUSEPORT or similar)
|
|
|
|
Tested on:
|
|
- Linux (fully supported)
|
|
- macOS (limited support)
|
|
- Windows (limited support)
|
|
|
|
## Example Scenarios
|
|
|
|
### Dual-WAN Setup
|
|
Use both your main internet connection and backup cellular connection:
|
|
```go
|
|
interfaces := []string{"eth0", "wwan0"} // Ethernet + Cellular
|
|
```
|
|
|
|
### WiFi + Ethernet Redundancy
|
|
For laptops with both WiFi and Ethernet:
|
|
```go
|
|
interfaces := []string{"eth0", "wlan0"} // Ethernet + WiFi
|
|
```
|
|
|
|
### Multi-Homed Server
|
|
Server with multiple network interfaces:
|
|
```go
|
|
interfaces := []string{"eth0", "eth1", "eth2"} // Multiple Ethernet
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Interface Binding Issues
|
|
```bash
|
|
# Check interface exists and is up
|
|
ip link show eth0
|
|
|
|
# Check interface has IP address
|
|
ip addr show eth0
|
|
|
|
# Test basic connectivity
|
|
ping -I eth0 8.8.8.8
|
|
```
|
|
|
|
### Permission Issues
|
|
Multi-path binding typically requires root privileges:
|
|
```bash
|
|
sudo ./your-wireguard-program
|
|
```
|
|
|
|
### Debugging
|
|
Enable verbose logging to see multi-path operations:
|
|
```go
|
|
logger := device.NewLogger(device.LogLevelVerbose, "multipath: ")
|
|
```
|
|
|
|
## Building
|
|
|
|
Ensure you have the modified WireGuard-Go source and build normally:
|
|
|
|
```bash
|
|
go mod tidy
|
|
go build ./...
|
|
|
|
# Build example
|
|
go build -o multipath-example ./examples/multipath/
|
|
```
|
|
|
|
## Future Enhancements
|
|
|
|
Potential improvements for the multi-path implementation:
|
|
|
|
1. **Load Balancing**: Distribute packets across interfaces rather than duplicating
|
|
2. **Health Monitoring**: Automatic detection and handling of failed interfaces
|
|
3. **Quality Metrics**: Choose best interface based on latency/bandwidth measurements
|
|
4. **Receive Multi-Path**: Receive from multiple interfaces and handle reordering
|
|
5. **Configuration API**: Runtime configuration of interface sets |