nebula/overlay/tun_wintun_windows.go

175 lines
3.7 KiB
Go
Raw Normal View History

2021-11-11 15:37:29 -07:00
package overlay
2021-11-08 11:36:31 -07:00
import (
"crypto"
"fmt"
"io"
"net"
"unsafe"
"github.com/slackhq/nebula/cidr"
"github.com/slackhq/nebula/iputil"
2021-11-08 11:36:31 -07:00
"github.com/slackhq/nebula/wintun"
"golang.org/x/sys/windows"
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
)
const tunGUIDLabel = "Fixed Nebula Windows GUID v1"
type winTun struct {
Device string
Cidr *net.IPNet
MTU int
Routes []Route
cidrTree *cidr.Tree4
2021-11-08 11:36:31 -07:00
tun *wintun.NativeTun
}
func generateGUIDByDeviceName(name string) (*windows.GUID, error) {
// GUID is 128 bit
hash := crypto.MD5.New()
_, err := hash.Write([]byte(tunGUIDLabel))
if err != nil {
return nil, err
}
_, err = hash.Write([]byte(name))
if err != nil {
return nil, err
}
sum := hash.Sum(nil)
return (*windows.GUID)(unsafe.Pointer(&sum[0])), nil
}
func newWinTun(deviceName string, cidr *net.IPNet, defaultMTU int, routes []Route) (*winTun, error) {
2021-11-08 11:36:31 -07:00
guid, err := generateGUIDByDeviceName(deviceName)
if err != nil {
return nil, fmt.Errorf("generate GUID failed: %w", err)
2021-11-08 11:36:31 -07:00
}
tunDevice, err := wintun.CreateTUNWithRequestedGUID(deviceName, guid, defaultMTU)
if err != nil {
return nil, fmt.Errorf("create TUN device failed: %w", err)
2021-11-08 11:36:31 -07:00
}
cidrTree, err := makeCidrTree(routes, false)
if err != nil {
return nil, err
}
return &winTun{
Device: deviceName,
Cidr: cidr,
MTU: defaultMTU,
Routes: routes,
cidrTree: cidrTree,
2021-11-08 11:36:31 -07:00
tun: tunDevice.(*wintun.NativeTun),
}, nil
2021-11-08 11:36:31 -07:00
}
func (t *winTun) Activate() error {
luid := winipcfg.LUID(t.tun.LUID())
2021-11-08 11:36:31 -07:00
if err := luid.SetIPAddresses([]net.IPNet{*t.Cidr}); err != nil {
2021-11-08 11:36:31 -07:00
return fmt.Errorf("failed to set address: %w", err)
}
foundDefault4 := false
routes := make([]*winipcfg.RouteData, 0, len(t.Routes)+1)
for _, r := range t.Routes {
if r.Via == nil {
// We don't allow route MTUs so only install routes with a via
continue
}
2021-11-08 11:36:31 -07:00
if !foundDefault4 {
if ones, bits := r.Cidr.Mask.Size(); ones == 0 && bits != 0 {
2021-11-08 11:36:31 -07:00
foundDefault4 = true
}
}
// Add our unsafe route
routes = append(routes, &winipcfg.RouteData{
2021-11-11 15:37:29 -07:00
Destination: *r.Cidr,
NextHop: *r.Via,
Metric: uint32(r.Metric),
2021-11-08 11:36:31 -07:00
})
}
if err := luid.AddRoutes(routes); err != nil {
return fmt.Errorf("failed to add routes: %w", err)
}
ipif, err := luid.IPInterface(windows.AF_INET)
if err != nil {
return fmt.Errorf("failed to get ip interface: %w", err)
}
ipif.NLMTU = uint32(t.MTU)
2021-11-08 11:36:31 -07:00
if foundDefault4 {
ipif.UseAutomaticMetric = false
ipif.Metric = 0
}
if err := ipif.Set(); err != nil {
return fmt.Errorf("failed to set ip interface: %w", err)
}
return nil
}
func (t *winTun) RouteFor(ip iputil.VpnIp) iputil.VpnIp {
r := t.cidrTree.MostSpecificContains(ip)
if r != nil {
return r.(iputil.VpnIp)
}
return 0
}
func (t *winTun) CidrNet() *net.IPNet {
return t.Cidr
2021-11-08 11:36:31 -07:00
}
func (t *winTun) DeviceName() string {
return t.Device
2021-11-08 11:36:31 -07:00
}
func (t *winTun) Read(b []byte) (int, error) {
return t.tun.Read(b, 0)
2021-11-08 11:36:31 -07:00
}
func (t *winTun) Write(b []byte) (int, error) {
return t.tun.Write(b, 0)
2021-11-08 11:36:31 -07:00
}
func (t *winTun) WriteRaw(b []byte) error {
_, err := t.Write(b)
2021-11-08 11:36:31 -07:00
return err
}
func (t *winTun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
2021-11-08 11:36:31 -07:00
return nil, fmt.Errorf("TODO: multiqueue not implemented for windows")
}
func (t *winTun) Close() error {
2021-11-08 11:36:31 -07:00
// 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(t.tun.LUID())
2021-11-08 11:36:31 -07:00
_ = luid.FlushRoutes(windows.AF_INET)
_ = luid.FlushIPAddresses(windows.AF_INET)
/* We don't support IPV6 yet
_ = luid.FlushRoutes(windows.AF_INET6)
_ = luid.FlushIPAddresses(windows.AF_INET6)
*/
_ = luid.FlushDNS(windows.AF_INET)
return t.tun.Close()
2021-11-08 11:36:31 -07:00
}