tun_wintun_windows.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. package nebula
  2. import (
  3. "crypto"
  4. "fmt"
  5. "io"
  6. "net"
  7. "unsafe"
  8. "github.com/slackhq/nebula/wintun"
  9. "golang.org/x/sys/windows"
  10. "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
  11. )
  12. const tunGUIDLabel = "Fixed Nebula Windows GUID v1"
  13. type WinTun struct {
  14. Device string
  15. Cidr *net.IPNet
  16. MTU int
  17. UnsafeRoutes []route
  18. tun *wintun.NativeTun
  19. }
  20. func generateGUIDByDeviceName(name string) (*windows.GUID, error) {
  21. // GUID is 128 bit
  22. hash := crypto.MD5.New()
  23. _, err := hash.Write([]byte(tunGUIDLabel))
  24. if err != nil {
  25. return nil, err
  26. }
  27. _, err = hash.Write([]byte(name))
  28. if err != nil {
  29. return nil, err
  30. }
  31. sum := hash.Sum(nil)
  32. return (*windows.GUID)(unsafe.Pointer(&sum[0])), nil
  33. }
  34. func newWinTun(deviceName string, cidr *net.IPNet, defaultMTU int, unsafeRoutes []route, txQueueLen int) (ifce *WinTun, err error) {
  35. guid, err := generateGUIDByDeviceName(deviceName)
  36. if err != nil {
  37. return nil, fmt.Errorf("Generate GUID failed: %w", err)
  38. }
  39. tunDevice, err := wintun.CreateTUNWithRequestedGUID(deviceName, guid, defaultMTU)
  40. if err != nil {
  41. return nil, fmt.Errorf("Create TUN device failed: %w", err)
  42. }
  43. ifce = &WinTun{
  44. Device: deviceName,
  45. Cidr: cidr,
  46. MTU: defaultMTU,
  47. UnsafeRoutes: unsafeRoutes,
  48. tun: tunDevice.(*wintun.NativeTun),
  49. }
  50. return ifce, nil
  51. }
  52. func (c *WinTun) Activate() error {
  53. luid := winipcfg.LUID(c.tun.LUID())
  54. if err := luid.SetIPAddresses([]net.IPNet{*c.Cidr}); err != nil {
  55. return fmt.Errorf("failed to set address: %w", err)
  56. }
  57. foundDefault4 := false
  58. routes := make([]*winipcfg.RouteData, 0, len(c.UnsafeRoutes)+1)
  59. for _, r := range c.UnsafeRoutes {
  60. if !foundDefault4 {
  61. if cidr, bits := r.route.Mask.Size(); cidr == 0 && bits != 0 {
  62. foundDefault4 = true
  63. }
  64. }
  65. // Add our unsafe route
  66. routes = append(routes, &winipcfg.RouteData{
  67. Destination: *r.route,
  68. NextHop: *r.via,
  69. Metric: uint32(r.metric),
  70. })
  71. }
  72. if err := luid.AddRoutes(routes); err != nil {
  73. return fmt.Errorf("failed to add routes: %w", err)
  74. }
  75. ipif, err := luid.IPInterface(windows.AF_INET)
  76. if err != nil {
  77. return fmt.Errorf("failed to get ip interface: %w", err)
  78. }
  79. ipif.NLMTU = uint32(c.MTU)
  80. if foundDefault4 {
  81. ipif.UseAutomaticMetric = false
  82. ipif.Metric = 0
  83. }
  84. if err := ipif.Set(); err != nil {
  85. return fmt.Errorf("failed to set ip interface: %w", err)
  86. }
  87. return nil
  88. }
  89. func (c *WinTun) CidrNet() *net.IPNet {
  90. return c.Cidr
  91. }
  92. func (c *WinTun) DeviceName() string {
  93. return c.Device
  94. }
  95. func (c *WinTun) Read(b []byte) (int, error) {
  96. return c.tun.Read(b, 0)
  97. }
  98. func (c *WinTun) Write(b []byte) (int, error) {
  99. return c.tun.Write(b, 0)
  100. }
  101. func (c *WinTun) WriteRaw(b []byte) error {
  102. _, err := c.Write(b)
  103. return err
  104. }
  105. func (c *WinTun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
  106. return nil, fmt.Errorf("TODO: multiqueue not implemented for windows")
  107. }
  108. func (c *WinTun) Close() error {
  109. // It seems that the Windows networking stack doesn't like it when we destroy interfaces that have active routes,
  110. // so to be certain, just remove everything before destroying.
  111. luid := winipcfg.LUID(c.tun.LUID())
  112. _ = luid.FlushRoutes(windows.AF_INET)
  113. _ = luid.FlushIPAddresses(windows.AF_INET)
  114. /* We don't support IPV6 yet
  115. _ = luid.FlushRoutes(windows.AF_INET6)
  116. _ = luid.FlushIPAddresses(windows.AF_INET6)
  117. */
  118. _ = luid.FlushDNS(windows.AF_INET)
  119. return c.tun.Close()
  120. }