mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-14 05:40:28 +00:00
Configure addresses and MTUs, fix bugs
This commit is contained in:
parent
f5517acc81
commit
235b64345e
@ -40,8 +40,8 @@ func (w *tunWriter) _write(b []byte) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if written-TUN_OFFSET_BYTES != n {
|
if written != n {
|
||||||
w.tun.log.Errorln("TUN iface write mismatch:", written-TUN_OFFSET_BYTES, "bytes written vs", n, "bytes given")
|
w.tun.log.Errorln("TUN iface write mismatch:", written, "bytes written vs", n, "bytes given")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,70 +1,223 @@
|
|||||||
package tuntap
|
package tuntap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"log"
|
||||||
"os/exec"
|
"net"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
|
||||||
wgtun "golang.zx2c4.com/wireguard/tun"
|
wgtun "golang.zx2c4.com/wireguard/tun"
|
||||||
|
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is to catch Windows platforms
|
// This is to catch Windows platforms
|
||||||
|
|
||||||
// Configures the TUN adapter with the correct IPv6 address and MTU.
|
// Configures the TUN adapter with the correct IPv6 address and MTU.
|
||||||
func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error {
|
func (tun *TunAdapter) setup(ifname string, addr string, mtu int) error {
|
||||||
|
var err error
|
||||||
|
err = doAsSystem(func() {
|
||||||
iface, err := wgtun.CreateTUN(ifname, mtu)
|
iface, err := wgtun.CreateTUN(ifname, mtu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
tun.iface = iface
|
tun.iface = iface
|
||||||
if mtu, err := iface.MTU(); err == nil {
|
|
||||||
tun.mtu = getSupportedMTU(mtu)
|
if err := tun.setupAddress(addr); err != nil {
|
||||||
} else {
|
tun.log.Errorln("Failed to set up TUN address:", err)
|
||||||
tun.mtu = 0
|
|
||||||
}
|
}
|
||||||
return tun.setupAddress(addr)
|
if err := tun.setupMTU(getSupportedMTU(mtu)); err != nil {
|
||||||
|
tun.log.Errorln("Failed to set up TUN MTU:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mtu, err = iface.MTU(); err == nil {
|
||||||
|
tun.mtu = mtu
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the MTU of the TAP adapter.
|
// Sets the MTU of the TAP adapter.
|
||||||
func (tun *TunAdapter) setupMTU(mtu int) error {
|
func (tun *TunAdapter) setupMTU(mtu int) error {
|
||||||
if tun.iface == nil || tun.iface.Name() == "" {
|
if tun.iface == nil || tun.Name() == "" {
|
||||||
return errors.New("Can't configure MTU as TAP adapter is not present")
|
return errors.New("Can't configure MTU as TUN adapter is not present")
|
||||||
}
|
}
|
||||||
// Set MTU
|
if intf, ok := tun.iface.(*wgtun.NativeTun); ok {
|
||||||
cmd := exec.Command("netsh", "interface", "ipv6", "set", "subinterface",
|
luid := winipcfg.LUID(intf.LUID())
|
||||||
fmt.Sprintf("interface=%s", tun.iface.Name()),
|
ipfamily, err := luid.IPInterface(windows.AF_INET6)
|
||||||
fmt.Sprintf("mtu=%d", mtu),
|
|
||||||
"store=active")
|
|
||||||
tun.log.Debugln("netsh command:", strings.Join(cmd.Args, " "))
|
|
||||||
output, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tun.log.Errorln("Windows netsh failed:", err)
|
|
||||||
tun.log.Traceln(string(output))
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second) // FIXME artifical delay to give netsh time to take effect
|
|
||||||
|
ipfamily.NLMTU = uint32(mtu)
|
||||||
|
intf.ForceMTU(int(ipfamily.NLMTU))
|
||||||
|
ipfamily.UseAutomaticMetric = false
|
||||||
|
ipfamily.Metric = 0
|
||||||
|
ipfamily.DadTransmits = 0
|
||||||
|
ipfamily.RouterDiscoveryBehavior = winipcfg.RouterDiscoveryDisabled
|
||||||
|
|
||||||
|
if err := ipfamily.Set(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the IPv6 address of the TAP adapter.
|
// Sets the IPv6 address of the TAP adapter.
|
||||||
func (tun *TunAdapter) setupAddress(addr string) error {
|
func (tun *TunAdapter) setupAddress(addr string) error {
|
||||||
if tun.iface == nil || tun.iface.Name() == "" {
|
if tun.iface == nil || tun.Name() == "" {
|
||||||
return errors.New("Can't configure IPv6 address as TAP adapter is not present")
|
return errors.New("Can't configure IPv6 address as TUN adapter is not present")
|
||||||
|
}
|
||||||
|
if intf, ok := tun.iface.(*wgtun.NativeTun); ok {
|
||||||
|
if ipaddr, ipnet, err := net.ParseCIDR(addr); err == nil {
|
||||||
|
luid := winipcfg.LUID(intf.LUID())
|
||||||
|
addresses := append([]net.IPNet{}, net.IPNet{
|
||||||
|
IP: ipaddr,
|
||||||
|
Mask: ipnet.Mask,
|
||||||
|
})
|
||||||
|
|
||||||
|
err := luid.SetIPAddressesForFamily(windows.AF_INET6, addresses)
|
||||||
|
if err == windows.ERROR_OBJECT_ALREADY_EXISTS {
|
||||||
|
cleanupAddressesOnDisconnectedInterfaces(windows.AF_INET6, addresses)
|
||||||
|
err = luid.SetIPAddressesForFamily(windows.AF_INET6, addresses)
|
||||||
}
|
}
|
||||||
// Set address
|
|
||||||
cmd := exec.Command("netsh", "interface", "ipv6", "add", "address",
|
|
||||||
fmt.Sprintf("interface=%s", tun.iface.Name()),
|
|
||||||
fmt.Sprintf("addr=%s", addr),
|
|
||||||
"store=active")
|
|
||||||
tun.log.Debugln("netsh command:", strings.Join(cmd.Args, " "))
|
|
||||||
output, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tun.log.Errorln("Windows netsh failed:", err)
|
|
||||||
tun.log.Traceln(string(output))
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second) // FIXME artifical delay to give netsh time to take effect
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return errors.New("unable to get NativeTUN")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* doAsSystem
|
||||||
|
* SPDX-License-Identifier: LGPL-3.0
|
||||||
|
* Copyright (C) 2017-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
func doAsSystem(f func()) error {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer func() {
|
||||||
|
windows.RevertToSelf()
|
||||||
|
runtime.UnlockOSThread()
|
||||||
|
}()
|
||||||
|
privileges := windows.Tokenprivileges{
|
||||||
|
PrivilegeCount: 1,
|
||||||
|
Privileges: [1]windows.LUIDAndAttributes{
|
||||||
|
{
|
||||||
|
Attributes: windows.SE_PRIVILEGE_ENABLED,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err := windows.LookupPrivilegeValue(nil, windows.StringToUTF16Ptr("SeDebugPrivilege"), &privileges.Privileges[0].Luid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = windows.ImpersonateSelf(windows.SecurityImpersonation)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var threadToken windows.Token
|
||||||
|
err = windows.OpenThreadToken(windows.CurrentThread(), windows.TOKEN_ADJUST_PRIVILEGES, false, &threadToken)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer threadToken.Close()
|
||||||
|
err = windows.AdjustTokenPrivileges(threadToken, false, &privileges, uint32(unsafe.Sizeof(privileges)), nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
processes, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer windows.CloseHandle(processes)
|
||||||
|
|
||||||
|
processEntry := windows.ProcessEntry32{Size: uint32(unsafe.Sizeof(windows.ProcessEntry32{}))}
|
||||||
|
pid := uint32(0)
|
||||||
|
for err = windows.Process32First(processes, &processEntry); err == nil; err = windows.Process32Next(processes, &processEntry) {
|
||||||
|
if strings.ToLower(windows.UTF16ToString(processEntry.ExeFile[:])) == "winlogon.exe" {
|
||||||
|
pid = processEntry.ProcessID
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pid == 0 {
|
||||||
|
return errors.New("unable to find winlogon.exe process")
|
||||||
|
}
|
||||||
|
|
||||||
|
winlogonProcess, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, pid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer windows.CloseHandle(winlogonProcess)
|
||||||
|
var winlogonToken windows.Token
|
||||||
|
err = windows.OpenProcessToken(winlogonProcess, windows.TOKEN_IMPERSONATE|windows.TOKEN_DUPLICATE, &winlogonToken)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer winlogonToken.Close()
|
||||||
|
var duplicatedToken windows.Token
|
||||||
|
err = windows.DuplicateTokenEx(winlogonToken, 0, nil, windows.SecurityImpersonation, windows.TokenImpersonation, &duplicatedToken)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer duplicatedToken.Close()
|
||||||
|
err = windows.SetThreadToken(nil, duplicatedToken)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cleanupAddressesOnDisconnectedInterfaces
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
func cleanupAddressesOnDisconnectedInterfaces(family winipcfg.AddressFamily, addresses []net.IPNet) {
|
||||||
|
if len(addresses) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
includedInAddresses := func(a net.IPNet) bool {
|
||||||
|
// TODO: this makes the whole algorithm O(n^2). But we can't stick net.IPNet in a Go hashmap. Bummer!
|
||||||
|
for _, addr := range addresses {
|
||||||
|
ip := addr.IP
|
||||||
|
if ip4 := ip.To4(); ip4 != nil {
|
||||||
|
ip = ip4
|
||||||
|
}
|
||||||
|
mA, _ := addr.Mask.Size()
|
||||||
|
mB, _ := a.Mask.Size()
|
||||||
|
if bytes.Equal(ip, a.IP) && mA == mB {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
interfaces, err := winipcfg.GetAdaptersAddresses(family, winipcfg.GAAFlagDefault)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, iface := range interfaces {
|
||||||
|
if iface.OperStatus == winipcfg.IfOperStatusUp {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for address := iface.FirstUnicastAddress; address != nil; address = address.Next {
|
||||||
|
ip := address.Address.IP()
|
||||||
|
ipnet := net.IPNet{IP: ip, Mask: net.CIDRMask(int(address.OnLinkPrefixLength), 8*len(ip))}
|
||||||
|
if includedInAddresses(ipnet) {
|
||||||
|
log.Printf("Cleaning up stale address %s from interface ‘%s’", ipnet.String(), iface.FriendlyName())
|
||||||
|
iface.LUID.DeleteIPAddress(ipnet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user