| 312 | } |
| 313 | |
| 314 | func (s *Server) handleTunnel(w http.ResponseWriter, r *http.Request) { |
| 315 | if r.Method != http.MethodPost { |
| 316 | w.WriteHeader(http.StatusMethodNotAllowed) |
| 317 | return |
| 318 | } |
| 319 | s.stats.requests.Add(1) |
| 320 | body, err := readTunnelRequestBody(r.Body, r.ContentLength, maxRequestBodyBytes) |
| 321 | if err != nil { |
| 322 | log.Printf("[exit] read body: %v", err) |
| 323 | if errors.Is(err, errRequestTooLarge) { |
| 324 | w.WriteHeader(http.StatusRequestEntityTooLarge) |
| 325 | } else { |
| 326 | w.WriteHeader(http.StatusBadRequest) |
| 327 | } |
| 328 | return |
| 329 | } |
| 330 | |
| 331 | clientID, rxFrames, err := frame.DecodeBatch(s.aead, body) |
| 332 | if err != nil { |
| 333 | s.stats.decodeFailures.Add(1) |
| 334 | // Decode failure on the very first batch from a client almost always |
| 335 | // means the AES key on the client does not match this server's key. |
| 336 | log.Printf("[exit] decode batch failed: %v (likely tunnel_key mismatch — confirm client config matches this server's tunnel_key)", err) |
| 337 | w.WriteHeader(http.StatusNoContent) |
| 338 | return |
| 339 | } |
| 340 | |
| 341 | if len(rxFrames) > 0 { |
| 342 | var bytesIn uint64 |
| 343 | for _, f := range rxFrames { |
| 344 | bytesIn += uint64(len(f.Payload)) |
| 345 | } |
| 346 | s.stats.framesIn.Add(uint64(len(rxFrames))) |
| 347 | s.stats.bytesIn.Add(bytesIn) |
| 348 | } |
| 349 | |
| 350 | // Process SYN frames in parallel — each routeIncoming on a SYN may dial |
| 351 | // upstream synchronously, and a single bad target (typo'd / stale DNS / |
| 352 | // unroutable IP) used to block every other SYN behind it for the full |
| 353 | // dial timeout. Non-SYN frames are still routed sequentially after the |
| 354 | // SYN goroutines finish so a DATA frame that lands in the same batch as |
| 355 | // its own SYN doesn't race the openSession registration. |
| 356 | var synWG sync.WaitGroup |
| 357 | for _, f := range rxFrames { |
| 358 | if f.HasFlag(frame.FlagSYN) { |
| 359 | synWG.Add(1) |
| 360 | go func(f *frame.Frame) { |
| 361 | defer synWG.Done() |
| 362 | s.routeIncoming(f, clientID) |
| 363 | }(f) |
| 364 | } |
| 365 | } |
| 366 | synWG.Wait() |
| 367 | for _, f := range rxFrames { |
| 368 | if !f.HasFlag(frame.FlagSYN) { |
| 369 | s.routeIncoming(f, clientID) |
| 370 | } |
| 371 | } |