128 lines
3.1 KiB
Go
128 lines
3.1 KiB
Go
|
//go:build windows
|
||
|
// +build windows
|
||
|
|
||
|
package tun
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"net"
|
||
|
"os/exec"
|
||
|
|
||
|
"github.com/songgao/water"
|
||
|
)
|
||
|
|
||
|
// New creates and returns a new TUN interface for the application.
|
||
|
func New(name string, opts ...Option) (*TUN, error) {
|
||
|
result := TUN{}
|
||
|
|
||
|
// Apply options early to set struct values for interface creation.
|
||
|
err := result.Apply(opts...)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
// TUN on Windows requires address and network to be set on device creation stage
|
||
|
// We also set network to 0.0.0.0/0 so we able to reach networks behind the node
|
||
|
// https://github.com/songgao/water/blob/master/params_windows.go
|
||
|
// https://gitlab.com/openconnect/openconnect/-/blob/master/tun-win32.c
|
||
|
ip, _, err := net.ParseCIDR(result.Src)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
network := net.IPNet{
|
||
|
IP: ip,
|
||
|
Mask: net.IPv4Mask(0, 0, 0, 0),
|
||
|
}
|
||
|
|
||
|
// Setup TUN Config
|
||
|
cfg := water.Config{
|
||
|
DeviceType: water.TUN,
|
||
|
PlatformSpecificParams: water.PlatformSpecificParams{
|
||
|
ComponentID: "tap0901",
|
||
|
InterfaceName: name,
|
||
|
Network: network.String(),
|
||
|
},
|
||
|
}
|
||
|
|
||
|
// Interface should be enabled before creation of water interface
|
||
|
// Otherwise there will be an error "The system cannot find the file specified."
|
||
|
netsh("interface", "set", "interface", "name=", name, "enable")
|
||
|
|
||
|
// Create Water Interface
|
||
|
iface, err := water.New(cfg)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
// Set TUN interface to newly created interface
|
||
|
result.Iface = iface
|
||
|
|
||
|
// Apply options to setup TUN interface configuration
|
||
|
// Setup interface address
|
||
|
err = result.setupAddress(result.Src)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
// Setup interface mtu size
|
||
|
err = result.setupMTU(result.MTU)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return &result, err
|
||
|
}
|
||
|
|
||
|
// setMTU configures the interface's MTU.
|
||
|
func (t *TUN) setMTU(mtu int) error {
|
||
|
t.MTU = mtu
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// setAddress configures the interface's address.
|
||
|
func (t *TUN) setAddress(address string) error {
|
||
|
t.Src = address
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// setupMTU sets the Maximum Tansmission Unit Size for a
|
||
|
// Packet on the interface.
|
||
|
func (t *TUN) setupMTU(mtu int) error {
|
||
|
return netsh("interface", "ipv4", "set", "subinterface", t.Iface.Name(), "mtu=", fmt.Sprintf("%d", mtu))
|
||
|
}
|
||
|
|
||
|
// setupAddress sets the interface's destination address and subnet.
|
||
|
func (t *TUN) setupAddress(address string) error {
|
||
|
return netsh("interface", "ip", "set", "address", "name=", t.Iface.Name(), "static", address)
|
||
|
}
|
||
|
|
||
|
// SetDestAddress isn't supported under Windows.
|
||
|
// You should instead use set address to set the interface to handle
|
||
|
// all addresses within a subnet.
|
||
|
func (t *TUN) setDestAddress(address string) error {
|
||
|
return errors.New("destination addresses are not supported under windows")
|
||
|
}
|
||
|
|
||
|
// Up brings up an interface to allow it to start accepting connections.
|
||
|
func (t *TUN) Up() error {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Down brings down an interface stopping active connections.
|
||
|
func (t *TUN) Down() error {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Delete removes a TUN device from the host.
|
||
|
func Delete(name string) error {
|
||
|
return netsh("interface", "set", "interface", "name=", name, "disable")
|
||
|
}
|
||
|
|
||
|
func netsh(args ...string) (err error) {
|
||
|
cmd := exec.Command("netsh", args...)
|
||
|
err = cmd.Run()
|
||
|
return
|
||
|
}
|