relay.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. package ike
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "net"
  7. "sync"
  8. "time"
  9. )
  10. type sessionRelay struct {
  11. transport datagramTransport
  12. suite negotiatedSuite
  13. keys ikeKeys
  14. spii [8]byte
  15. spir [8]byte
  16. natt bool
  17. keepalive time.Duration
  18. ctx context.Context
  19. cancel context.CancelFunc
  20. done chan struct{}
  21. esp chan []byte
  22. mu sync.Mutex
  23. lastErr error
  24. }
  25. func newSessionRelay(
  26. transport datagramTransport,
  27. suite negotiatedSuite,
  28. keys ikeKeys,
  29. initiatorSPI [8]byte,
  30. responderSPI [8]byte,
  31. natt bool,
  32. keepalive time.Duration,
  33. ) *sessionRelay {
  34. if keepalive <= 0 {
  35. keepalive = 20 * time.Second
  36. }
  37. ctx, cancel := context.WithCancel(context.Background())
  38. relay := &sessionRelay{
  39. transport: transport,
  40. suite: suite,
  41. keys: keys,
  42. spii: initiatorSPI,
  43. spir: responderSPI,
  44. natt: natt,
  45. keepalive: keepalive,
  46. ctx: ctx,
  47. cancel: cancel,
  48. done: make(chan struct{}),
  49. esp: make(chan []byte, 64),
  50. }
  51. go relay.run()
  52. return relay
  53. }
  54. func (relay *sessionRelay) run() {
  55. defer close(relay.done)
  56. defer close(relay.esp)
  57. buffer := make([]byte, 65535)
  58. lastKeepalive := time.Now()
  59. for {
  60. if err := relay.ctx.Err(); err != nil {
  61. return
  62. }
  63. n, isIKE, err := relay.transport.ReceiveSessionPacket(relay.ctx, buffer)
  64. if err != nil {
  65. if errors.Is(err, context.Canceled) || errors.Is(err, net.ErrClosed) {
  66. return
  67. }
  68. if timeout, ok := err.(net.Error); ok && timeout.Timeout() {
  69. if relay.natt && time.Since(lastKeepalive) >= relay.keepalive {
  70. if sendErr := relay.transport.SendSessionPacket(relay.ctx, []byte{0xff}, false); sendErr != nil {
  71. relay.fail(sendErr)
  72. return
  73. }
  74. lastKeepalive = time.Now()
  75. }
  76. continue
  77. }
  78. relay.fail(err)
  79. return
  80. }
  81. packet := append([]byte(nil), buffer[:n]...)
  82. if isIKE {
  83. if err := relay.handleIKE(packet); err != nil {
  84. relay.fail(err)
  85. return
  86. }
  87. continue
  88. }
  89. if len(packet) == 1 && packet[0] == 0xff {
  90. // Peer NAT keepalive.
  91. continue
  92. }
  93. if len(packet) < 8 {
  94. // Unauthenticated network input must not tear down the session.
  95. continue
  96. }
  97. select {
  98. case relay.esp <- packet:
  99. default:
  100. // Keep the sole socket reader available for IKE/DPD if the
  101. // data-plane consumer falls behind.
  102. case <-relay.ctx.Done():
  103. return
  104. }
  105. }
  106. }
  107. func (relay *sessionRelay) handleIKE(packet []byte) error {
  108. header, _, err := parseIKEPacket(packet)
  109. if err != nil {
  110. return err
  111. }
  112. if header.InitiatorSPI != relay.spii || header.ResponderSPI != relay.spir {
  113. return errors.New("ike: session packet has mismatched SPIs")
  114. }
  115. if header.Flags&flagResponse != 0 {
  116. return nil
  117. }
  118. if header.Exchange != exchangeInformational {
  119. return fmt.Errorf("ike: unsupported responder-initiated exchange %d", header.Exchange)
  120. }
  121. decryptedHeader, payloads, err := decryptPayloads(packet, relay.suite, relay.keys.SKer, relay.keys.SKar)
  122. if err != nil {
  123. return err
  124. }
  125. if len(payloads) != 0 {
  126. return errors.New("ike: responder INFORMATIONAL request is not an empty DPD probe")
  127. }
  128. response, err := encryptPayloads(ikeHeader{
  129. InitiatorSPI: relay.spii,
  130. ResponderSPI: relay.spir,
  131. Exchange: exchangeInformational,
  132. Flags: flagInitiator | flagResponse,
  133. MessageID: decryptedHeader.MessageID,
  134. }, nil, relay.suite, relay.keys.SKei, relay.keys.SKai, nil)
  135. if err != nil {
  136. return err
  137. }
  138. return relay.transport.SendSessionPacket(relay.ctx, response, true)
  139. }
  140. func (relay *sessionRelay) fail(err error) {
  141. relay.mu.Lock()
  142. if relay.lastErr == nil {
  143. relay.lastErr = err
  144. }
  145. relay.mu.Unlock()
  146. relay.cancel()
  147. }
  148. func (relay *sessionRelay) SendESP(ctx context.Context, packet []byte) error {
  149. if ctx == nil {
  150. ctx = context.Background()
  151. }
  152. select {
  153. case <-relay.done:
  154. return relay.terminalError()
  155. default:
  156. }
  157. return relay.transport.SendSessionPacket(ctx, packet, false)
  158. }
  159. func (relay *sessionRelay) ReceiveESP(ctx context.Context, buffer []byte) (int, error) {
  160. if ctx == nil {
  161. ctx = context.Background()
  162. }
  163. select {
  164. case <-ctx.Done():
  165. return 0, ctx.Err()
  166. case packet, ok := <-relay.esp:
  167. if !ok {
  168. return 0, relay.terminalError()
  169. }
  170. if len(packet) > len(buffer) {
  171. return 0, errors.New("ike: ESP receive buffer is too small")
  172. }
  173. copy(buffer, packet)
  174. return len(packet), nil
  175. }
  176. }
  177. func (relay *sessionRelay) terminalError() error {
  178. relay.mu.Lock()
  179. defer relay.mu.Unlock()
  180. if relay.lastErr != nil {
  181. return relay.lastErr
  182. }
  183. return net.ErrClosed
  184. }
  185. func (relay *sessionRelay) Close() error {
  186. relay.cancel()
  187. <-relay.done
  188. return relay.terminalErrorIfFailure()
  189. }
  190. func (relay *sessionRelay) terminalErrorIfFailure() error {
  191. relay.mu.Lock()
  192. defer relay.mu.Unlock()
  193. return relay.lastErr
  194. }
  195. var _ NATTPacketRelay = (*sessionRelay)(nil)