tun_windows_endpoint.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. //go:build windows
  2. package tun
  3. import (
  4. "context"
  5. "errors"
  6. _ "unsafe"
  7. "golang.org/x/sys/windows"
  8. "gvisor.dev/gvisor/pkg/buffer"
  9. "gvisor.dev/gvisor/pkg/tcpip"
  10. "gvisor.dev/gvisor/pkg/tcpip/header"
  11. "gvisor.dev/gvisor/pkg/tcpip/stack"
  12. )
  13. // WintunEndpoint implements GVisor stack.LinkEndpoint
  14. var _ stack.LinkEndpoint = (*WintunEndpoint)(nil)
  15. type WintunEndpoint struct {
  16. tun *WindowsTun
  17. dispatcherCancel context.CancelFunc
  18. }
  19. var ErrUnsupportedNetworkProtocol = errors.New("unsupported ip version")
  20. //go:linkname procyield runtime.procyield
  21. func procyield(cycles uint32)
  22. func (e *WintunEndpoint) MTU() uint32 {
  23. return e.tun.MTU
  24. }
  25. func (e *WintunEndpoint) SetMTU(mtu uint32) {
  26. // not Implemented, as it is not expected GVisor will be asking tun device to be modified
  27. }
  28. func (e *WintunEndpoint) MaxHeaderLength() uint16 {
  29. return 0
  30. }
  31. func (e *WintunEndpoint) LinkAddress() tcpip.LinkAddress {
  32. return ""
  33. }
  34. func (e *WintunEndpoint) SetLinkAddress(addr tcpip.LinkAddress) {
  35. // not Implemented, as it is not expected GVisor will be asking tun device to be modified
  36. }
  37. func (e *WintunEndpoint) Capabilities() stack.LinkEndpointCapabilities {
  38. return stack.CapabilityRXChecksumOffload
  39. }
  40. func (e *WintunEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
  41. if e.dispatcherCancel != nil {
  42. e.dispatcherCancel()
  43. e.dispatcherCancel = nil
  44. }
  45. if dispatcher != nil {
  46. ctx, cancel := context.WithCancel(context.Background())
  47. go e.dispatchLoop(ctx, dispatcher)
  48. e.dispatcherCancel = cancel
  49. }
  50. }
  51. func (e *WintunEndpoint) IsAttached() bool {
  52. return e.dispatcherCancel != nil
  53. }
  54. func (e *WintunEndpoint) Wait() {
  55. }
  56. func (e *WintunEndpoint) ARPHardwareType() header.ARPHardwareType {
  57. return header.ARPHardwareNone
  58. }
  59. func (e *WintunEndpoint) AddHeader(buffer *stack.PacketBuffer) {
  60. // tun interface doesn't have link layer header, it will be added by the OS
  61. }
  62. func (e *WintunEndpoint) ParseHeader(ptr *stack.PacketBuffer) bool {
  63. return true
  64. }
  65. func (e *WintunEndpoint) Close() {
  66. if e.dispatcherCancel != nil {
  67. e.dispatcherCancel()
  68. e.dispatcherCancel = nil
  69. }
  70. }
  71. func (e *WintunEndpoint) SetOnCloseAction(f func()) {
  72. }
  73. func (e *WintunEndpoint) WritePackets(packetBufferList stack.PacketBufferList) (int, tcpip.Error) {
  74. var n int
  75. // for all packets in the list to send
  76. for _, packetBuffer := range packetBufferList.AsSlice() {
  77. // request buffer from Wintun
  78. packet, err := e.tun.session.AllocateSendPacket(packetBuffer.Size())
  79. if err != nil {
  80. return n, &tcpip.ErrAborted{}
  81. }
  82. // copy the bytes of slices that compose the packet into the allocated buffer
  83. var index int
  84. for _, packetElement := range packetBuffer.AsSlices() {
  85. index += copy(packet[index:], packetElement)
  86. }
  87. // signal Wintun to send that buffer as the packet
  88. e.tun.session.SendPacket(packet)
  89. n++
  90. }
  91. return n, nil
  92. }
  93. func (e *WintunEndpoint) readPacket() (tcpip.NetworkProtocolNumber, *stack.PacketBuffer, error) {
  94. packet, err := e.tun.session.ReceivePacket()
  95. if err != nil {
  96. return 0, nil, err
  97. }
  98. var networkProtocol tcpip.NetworkProtocolNumber
  99. switch header.IPVersion(packet) {
  100. case header.IPv4Version:
  101. networkProtocol = header.IPv4ProtocolNumber
  102. case header.IPv6Version:
  103. networkProtocol = header.IPv6ProtocolNumber
  104. default:
  105. e.tun.session.ReleaseReceivePacket(packet)
  106. return 0, nil, ErrUnsupportedNetworkProtocol
  107. }
  108. packetBuffer := buffer.MakeWithView(buffer.NewViewWithData(packet))
  109. pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
  110. Payload: packetBuffer,
  111. IsForwardedPacket: true,
  112. OnRelease: func() {
  113. e.tun.session.ReleaseReceivePacket(packet)
  114. },
  115. })
  116. return networkProtocol, pkt, nil
  117. }
  118. func (e *WintunEndpoint) dispatchLoop(ctx context.Context, dispatcher stack.NetworkDispatcher) {
  119. readWait := e.tun.session.ReadWaitEvent()
  120. for {
  121. select {
  122. case <-ctx.Done():
  123. return
  124. default:
  125. networkProtocolNumber, packet, err := e.readPacket()
  126. // read queue empty, yield slightly, wait for the spinlock, retry
  127. if errors.Is(err, windows.ERROR_NO_MORE_ITEMS) {
  128. procyield(1)
  129. _, _ = windows.WaitForSingleObject(readWait, windows.INFINITE)
  130. continue
  131. }
  132. // discard unknown network protocol packet
  133. if errors.Is(err, ErrUnsupportedNetworkProtocol) {
  134. continue
  135. }
  136. // stop dispatcher loop on any other interface failure
  137. if err != nil {
  138. e.Attach(nil)
  139. continue
  140. }
  141. // dispatch the buffer to the stack
  142. dispatcher.DeliverNetworkPacket(networkProtocolNumber, packet)
  143. // signal the buffer that it can be released
  144. packet.DecRef()
  145. }
  146. }
  147. }