forwarder.go 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243
  1. package amneziawgnet
  2. import (
  3. "net/netip"
  4. "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
  5. "gvisor.dev/gvisor/pkg/tcpip/stack"
  6. "gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
  7. "gvisor.dev/gvisor/pkg/waiter"
  8. )
  9. // AttachTCPForwarder attaches a TCP forwarder to gstack in promiscuous +
  10. // spoofing mode, so it accepts connections addressed to any destination --
  11. // not just the stack's own configured local address -- and hands the
  12. // handler both the accepted connection and the tunnel client's real,
  13. // dynamically-arbitrary destination (recovered from the connection's own
  14. // TransportEndpointID, not from any preconfigured routing table). This is
  15. // the mechanism the whole embedded-AmneziaWG design depends on: what the
  16. // handler does with that destination (dial it directly, relay it into
  17. // Xray's SOCKS5 inbound, ...) is entirely up to the caller.
  18. //
  19. // Adapted from xtls/xray-core's proxy/wireguard/tun.go createForwarder (MIT).
  20. func AttachTCPForwarder(gstack *stack.Stack, handler func(conn *gonet.TCPConn, dest netip.AddrPort)) {
  21. enablePromiscuousRouting(gstack)
  22. fwd := tcp.NewForwarder(gstack, 0, 65535, func(r *tcp.ForwarderRequest) {
  23. go func(r *tcp.ForwarderRequest) {
  24. var wq waiter.Queue
  25. id := r.ID()
  26. ep, err := r.CreateEndpoint(&wq)
  27. if err != nil {
  28. r.Complete(true)
  29. return
  30. }
  31. dest := netip.AddrPortFrom(addrFromTcpip(id.LocalAddress), id.LocalPort)
  32. handler(gonet.NewTCPConn(&wq, ep), dest)
  33. ep.Close()
  34. r.Complete(false)
  35. }(r)
  36. })
  37. gstack.SetTransportProtocolHandler(tcp.ProtocolNumber, fwd.HandlePacket)
  38. }