relay.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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. if errors.Is(err, errMismatchedSessionSPIs) {
  85. // A reconnect can reuse the same NAT mapping while the ePDG still
  86. // has packets queued for the previous IKE SA. Those packets are
  87. // unrelated to this authenticated session and must be discarded;
  88. // treating one as fatal tears down the newly established CHILD_SA.
  89. continue
  90. }
  91. relay.fail(err)
  92. return
  93. }
  94. continue
  95. }
  96. if len(packet) == 1 && packet[0] == 0xff {
  97. // Peer NAT keepalive.
  98. continue
  99. }
  100. if len(packet) < 8 {
  101. // Unauthenticated network input must not tear down the session.
  102. continue
  103. }
  104. select {
  105. case relay.esp <- packet:
  106. default:
  107. // Keep the sole socket reader available for IKE/DPD if the
  108. // data-plane consumer falls behind.
  109. case <-relay.ctx.Done():
  110. return
  111. }
  112. }
  113. }
  114. var errMismatchedSessionSPIs = errors.New("ike: session packet has mismatched SPIs")
  115. func (relay *sessionRelay) handleIKE(packet []byte) error {
  116. header, _, err := parseIKEPacket(packet)
  117. if err != nil {
  118. return err
  119. }
  120. if header.InitiatorSPI != relay.spii || header.ResponderSPI != relay.spir {
  121. return errMismatchedSessionSPIs
  122. }
  123. if header.Flags&flagResponse != 0 {
  124. return nil
  125. }
  126. if header.Exchange != exchangeInformational {
  127. return fmt.Errorf("ike: unsupported responder-initiated exchange %d", header.Exchange)
  128. }
  129. decryptedHeader, payloads, err := decryptPayloads(packet, relay.suite, relay.keys.SKer, relay.keys.SKar)
  130. if err != nil {
  131. return err
  132. }
  133. if len(payloads) != 0 {
  134. return errors.New("ike: responder INFORMATIONAL request is not an empty DPD probe")
  135. }
  136. response, err := encryptPayloads(ikeHeader{
  137. InitiatorSPI: relay.spii,
  138. ResponderSPI: relay.spir,
  139. Exchange: exchangeInformational,
  140. Flags: flagInitiator | flagResponse,
  141. MessageID: decryptedHeader.MessageID,
  142. }, nil, relay.suite, relay.keys.SKei, relay.keys.SKai, nil)
  143. if err != nil {
  144. return err
  145. }
  146. return relay.transport.SendSessionPacket(relay.ctx, response, true)
  147. }
  148. func (relay *sessionRelay) fail(err error) {
  149. relay.mu.Lock()
  150. if relay.lastErr == nil {
  151. relay.lastErr = err
  152. }
  153. relay.mu.Unlock()
  154. relay.cancel()
  155. }
  156. func (relay *sessionRelay) SendESP(ctx context.Context, packet []byte) error {
  157. if ctx == nil {
  158. ctx = context.Background()
  159. }
  160. select {
  161. case <-relay.done:
  162. return relay.terminalError()
  163. default:
  164. }
  165. return relay.transport.SendSessionPacket(ctx, packet, false)
  166. }
  167. func (relay *sessionRelay) ReceiveESP(ctx context.Context, buffer []byte) (int, error) {
  168. if ctx == nil {
  169. ctx = context.Background()
  170. }
  171. select {
  172. case <-ctx.Done():
  173. return 0, ctx.Err()
  174. case packet, ok := <-relay.esp:
  175. if !ok {
  176. return 0, relay.terminalError()
  177. }
  178. if len(packet) > len(buffer) {
  179. return 0, errors.New("ike: ESP receive buffer is too small")
  180. }
  181. copy(buffer, packet)
  182. return len(packet), nil
  183. }
  184. }
  185. func (relay *sessionRelay) terminalError() error {
  186. relay.mu.Lock()
  187. defer relay.mu.Unlock()
  188. if relay.lastErr != nil {
  189. return relay.lastErr
  190. }
  191. return net.ErrClosed
  192. }
  193. func (relay *sessionRelay) Close() error {
  194. relay.cancel()
  195. <-relay.done
  196. return relay.terminalErrorIfFailure()
  197. }
  198. func (relay *sessionRelay) terminalErrorIfFailure() error {
  199. relay.mu.Lock()
  200. defer relay.mu.Unlock()
  201. return relay.lastErr
  202. }
  203. var _ NATTPacketRelay = (*sessionRelay)(nil)