2023-09-15 15:00:15 -04:00
|
|
|
/* SPDX-License-Identifier: MIT
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2019-2021 WireGuard LLC. All Rights Reserved.
|
|
|
|
|
* Copyright (C) 2021 Mozilla Foundation. All Rights Reserved.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"log"
|
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
|
|
"golang.org/x/sys/windows"
|
|
|
|
|
|
2025-02-24 08:53:46 +01:00
|
|
|
"github.com/amnezia-vpn/euphoria/conn"
|
|
|
|
|
"github.com/amnezia-vpn/euphoria/tun"
|
2023-09-15 15:00:15 -04:00
|
|
|
|
2025-02-24 08:53:46 +01:00
|
|
|
"github.com/amnezia-vpn/euphoria-windows/conf"
|
|
|
|
|
"github.com/amnezia-vpn/euphoria-windows/services"
|
|
|
|
|
"github.com/amnezia-vpn/euphoria-windows/tunnel/firewall"
|
|
|
|
|
"github.com/amnezia-vpn/euphoria-windows/tunnel/winipcfg"
|
2023-09-15 15:00:15 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type interfaceWatcherError struct {
|
|
|
|
|
serviceError services.Error
|
|
|
|
|
err error
|
|
|
|
|
}
|
|
|
|
|
type interfaceWatcherEvent struct {
|
|
|
|
|
luid winipcfg.LUID
|
|
|
|
|
family winipcfg.AddressFamily
|
|
|
|
|
}
|
|
|
|
|
type interfaceWatcher struct {
|
|
|
|
|
errors chan interfaceWatcherError
|
|
|
|
|
|
|
|
|
|
binder conn.BindSocketToInterface
|
|
|
|
|
conf *conf.Config
|
|
|
|
|
tun *tun.NativeTun
|
|
|
|
|
|
|
|
|
|
setupMutex sync.Mutex
|
|
|
|
|
interfaceChangeCallback winipcfg.ChangeCallback
|
|
|
|
|
changeCallbacks4 []winipcfg.ChangeCallback
|
|
|
|
|
changeCallbacks6 []winipcfg.ChangeCallback
|
|
|
|
|
storedEvents []interfaceWatcherEvent
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (iw *interfaceWatcher) setup(family winipcfg.AddressFamily) {
|
|
|
|
|
var changeCallbacks *[]winipcfg.ChangeCallback
|
|
|
|
|
var ipversion string
|
|
|
|
|
if family == windows.AF_INET {
|
|
|
|
|
changeCallbacks = &iw.changeCallbacks4
|
|
|
|
|
ipversion = "v4"
|
|
|
|
|
} else if family == windows.AF_INET6 {
|
|
|
|
|
changeCallbacks = &iw.changeCallbacks6
|
|
|
|
|
ipversion = "v6"
|
|
|
|
|
} else {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if len(*changeCallbacks) != 0 {
|
|
|
|
|
for _, cb := range *changeCallbacks {
|
|
|
|
|
cb.Unregister()
|
|
|
|
|
}
|
|
|
|
|
*changeCallbacks = nil
|
|
|
|
|
}
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
log.Printf("Setting device %s addresses", ipversion)
|
|
|
|
|
err = configureInterface(family, iw.conf, iw.tun)
|
|
|
|
|
if err != nil {
|
|
|
|
|
iw.errors <- interfaceWatcherError{services.ErrorSetNetConfig, err}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func watchInterface() (*interfaceWatcher, error) {
|
|
|
|
|
iw := &interfaceWatcher{
|
|
|
|
|
errors: make(chan interfaceWatcherError, 2),
|
|
|
|
|
}
|
|
|
|
|
var err error
|
|
|
|
|
iw.interfaceChangeCallback, err = winipcfg.RegisterInterfaceChangeCallback(func(notificationType winipcfg.MibNotificationType, iface *winipcfg.MibIPInterfaceRow) {
|
|
|
|
|
iw.setupMutex.Lock()
|
|
|
|
|
defer iw.setupMutex.Unlock()
|
|
|
|
|
|
|
|
|
|
if notificationType != winipcfg.MibAddInstance {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if iw.tun == nil {
|
|
|
|
|
iw.storedEvents = append(iw.storedEvents, interfaceWatcherEvent{iface.InterfaceLUID, iface.Family})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if iface.InterfaceLUID != winipcfg.LUID(iw.tun.LUID()) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
iw.setup(iface.Family)
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return iw, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (iw *interfaceWatcher) Configure(binder conn.BindSocketToInterface, conf *conf.Config, tun *tun.NativeTun) {
|
|
|
|
|
iw.setupMutex.Lock()
|
|
|
|
|
defer iw.setupMutex.Unlock()
|
|
|
|
|
|
|
|
|
|
iw.binder, iw.conf, iw.tun = binder, conf, tun
|
|
|
|
|
for _, event := range iw.storedEvents {
|
|
|
|
|
if event.luid == winipcfg.LUID(iw.tun.LUID()) {
|
|
|
|
|
iw.setup(event.family)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
iw.storedEvents = nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (iw *interfaceWatcher) Destroy() {
|
|
|
|
|
iw.setupMutex.Lock()
|
|
|
|
|
changeCallbacks4 := iw.changeCallbacks4
|
|
|
|
|
changeCallbacks6 := iw.changeCallbacks6
|
|
|
|
|
interfaceChangeCallback := iw.interfaceChangeCallback
|
|
|
|
|
tun := iw.tun
|
|
|
|
|
iw.setupMutex.Unlock()
|
|
|
|
|
|
|
|
|
|
if interfaceChangeCallback != nil {
|
|
|
|
|
interfaceChangeCallback.Unregister()
|
|
|
|
|
}
|
|
|
|
|
for _, cb := range changeCallbacks4 {
|
|
|
|
|
cb.Unregister()
|
|
|
|
|
}
|
|
|
|
|
for _, cb := range changeCallbacks6 {
|
|
|
|
|
cb.Unregister()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iw.setupMutex.Lock()
|
|
|
|
|
if interfaceChangeCallback == iw.interfaceChangeCallback {
|
|
|
|
|
iw.interfaceChangeCallback = nil
|
|
|
|
|
}
|
|
|
|
|
for len(changeCallbacks4) > 0 && len(iw.changeCallbacks4) > 0 {
|
|
|
|
|
iw.changeCallbacks4 = iw.changeCallbacks4[1:]
|
|
|
|
|
changeCallbacks4 = changeCallbacks4[1:]
|
|
|
|
|
}
|
|
|
|
|
for len(changeCallbacks6) > 0 && len(iw.changeCallbacks6) > 0 {
|
|
|
|
|
iw.changeCallbacks6 = iw.changeCallbacks6[1:]
|
|
|
|
|
changeCallbacks6 = changeCallbacks6[1:]
|
|
|
|
|
}
|
|
|
|
|
firewall.DisableFirewall()
|
|
|
|
|
if tun != nil && iw.tun == tun {
|
|
|
|
|
// It seems that the Windows networking stack doesn't like it when we destroy interfaces that have active
|
|
|
|
|
// routes, so to be certain, just remove everything before destroying.
|
|
|
|
|
luid := winipcfg.LUID(tun.LUID())
|
|
|
|
|
luid.FlushRoutes(windows.AF_INET)
|
|
|
|
|
luid.FlushIPAddresses(windows.AF_INET)
|
|
|
|
|
luid.FlushDNS(windows.AF_INET)
|
|
|
|
|
luid.FlushRoutes(windows.AF_INET6)
|
|
|
|
|
luid.FlushIPAddresses(windows.AF_INET6)
|
|
|
|
|
luid.FlushDNS(windows.AF_INET6)
|
|
|
|
|
}
|
|
|
|
|
iw.setupMutex.Unlock()
|
|
|
|
|
}
|