tun_windows.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. //go:build windows
  2. package tun
  3. import (
  4. "errors"
  5. _ "unsafe"
  6. "golang.org/x/sys/windows"
  7. "golang.zx2c4.com/wintun"
  8. "gvisor.dev/gvisor/pkg/buffer"
  9. "gvisor.dev/gvisor/pkg/tcpip"
  10. "gvisor.dev/gvisor/pkg/tcpip/stack"
  11. )
  12. //go:linkname procyield runtime.procyield
  13. func procyield(cycles uint32)
  14. // WindowsTun is an object that handles tun network interface on Windows
  15. // current version is heavily stripped to do nothing more,
  16. // then create a network interface, to be provided as endpoint to gVisor ip stack
  17. type WindowsTun struct {
  18. options TunOptions
  19. adapter *wintun.Adapter
  20. session wintun.Session
  21. readWait windows.Handle
  22. MTU uint32
  23. }
  24. // WindowsTun implements Tun
  25. var _ Tun = (*WindowsTun)(nil)
  26. // WindowsTun implements GVisorTun
  27. var _ GVisorTun = (*WindowsTun)(nil)
  28. // WindowsTun implements GVisorDevice
  29. var _ GVisorDevice = (*WindowsTun)(nil)
  30. // NewTun creates a Wintun interface with the given name. Should a Wintun
  31. // interface with the same name exist, it tried to be reused.
  32. func NewTun(options TunOptions) (Tun, error) {
  33. // instantiate wintun adapter
  34. adapter, err := open(options.Name)
  35. if err != nil {
  36. return nil, err
  37. }
  38. // start the interface with ring buffer capacity of 8 MiB
  39. session, err := adapter.StartSession(0x800000)
  40. if err != nil {
  41. _ = adapter.Close()
  42. return nil, err
  43. }
  44. tun := &WindowsTun{
  45. options: options,
  46. adapter: adapter,
  47. session: session,
  48. readWait: session.ReadWaitEvent(),
  49. // there is currently no iphndl.dll support, which is the netlink library for windows
  50. // so there is nowhere to change MTU for the Wintun interface, and we take its default value
  51. MTU: wintun.PacketSizeMax,
  52. }
  53. return tun, nil
  54. }
  55. func open(name string) (*wintun.Adapter, error) {
  56. var guid *windows.GUID
  57. // try to open existing adapter by name
  58. adapter, err := wintun.OpenAdapter(name)
  59. if err == nil {
  60. return adapter, nil
  61. }
  62. // try to create adapter anew
  63. adapter, err = wintun.CreateAdapter(name, "Xray", guid)
  64. if err == nil {
  65. return adapter, nil
  66. }
  67. return nil, err
  68. }
  69. func (t *WindowsTun) Start() error {
  70. return nil
  71. }
  72. func (t *WindowsTun) Close() error {
  73. t.session.End()
  74. _ = t.adapter.Close()
  75. return nil
  76. }
  77. // WritePacket implements GVisorDevice method to write one packet to the tun device
  78. func (t *WindowsTun) WritePacket(packetBuffer *stack.PacketBuffer) tcpip.Error {
  79. // request buffer from Wintun
  80. packet, err := t.session.AllocateSendPacket(packetBuffer.Size())
  81. if err != nil {
  82. return &tcpip.ErrAborted{}
  83. }
  84. // copy the bytes of slices that compose the packet into the allocated buffer
  85. var index int
  86. for _, packetElement := range packetBuffer.AsSlices() {
  87. index += copy(packet[index:], packetElement)
  88. }
  89. // signal Wintun to send that buffer as the packet
  90. t.session.SendPacket(packet)
  91. return nil
  92. }
  93. // ReadPacket implements GVisorDevice method to read one packet from the tun device
  94. // It is expected that the method will not block, rather return ErrQueueEmpty when there is nothing on the line,
  95. // which will make the stack call Wait which should implement desired push-back
  96. func (t *WindowsTun) ReadPacket() (byte, *stack.PacketBuffer, error) {
  97. packet, err := t.session.ReceivePacket()
  98. if errors.Is(err, windows.ERROR_NO_MORE_ITEMS) {
  99. return 0, nil, ErrQueueEmpty
  100. }
  101. if err != nil {
  102. return 0, nil, err
  103. }
  104. version := packet[0] >> 4
  105. packetBuffer := buffer.MakeWithView(buffer.NewViewWithData(packet))
  106. return version, stack.NewPacketBuffer(stack.PacketBufferOptions{
  107. Payload: packetBuffer,
  108. IsForwardedPacket: true,
  109. OnRelease: func() {
  110. t.session.ReleaseReceivePacket(packet)
  111. },
  112. }), nil
  113. }
  114. func (t *WindowsTun) Wait() {
  115. procyield(1)
  116. _, _ = windows.WaitForSingleObject(t.readWait, windows.INFINITE)
  117. }
  118. func (t *WindowsTun) newEndpoint() (stack.LinkEndpoint, error) {
  119. return &LinkEndpoint{deviceMTU: t.options.MTU, device: t}, nil
  120. }