Class CompositeOriginalDestinationResolver

java.lang.Object
org.mockserver.netty.proxy.CompositeOriginalDestinationResolver
All Implemented Interfaces:
TransparentProxyHandler.OriginalDestinationResolver

public class CompositeOriginalDestinationResolver extends Object implements TransparentProxyHandler.OriginalDestinationResolver
A composite TransparentProxyHandler.OriginalDestinationResolver that tries an ordered chain of resolution strategies and returns the first non-null result.

Each strategy is invoked in order. If a strategy returns null or throws UnsupportedOperationException (e.g., platform not supported), the next strategy is tried. Any other exception is caught, logged at the calling layer, and treated as a skip (fall through to the next strategy).

Default chain (constructed via defaultChain(Configuration)):

  1. TproxyOriginalDestinationResolver — reads the original destination from channel.localAddress() when TPROXY mode is active (the TPROXY iptables target preserves the original destination as the socket's local address). Returns null when TPROXY mode is not enabled in configuration.
  2. EbpfOriginalDestinationResolver — O(1) BPF hash map lookup keyed by socket cookie. An external BPF program (cgroup/connect4) records the original destination before NAT; this resolver reads and consumes the entry. Returns null when eBPF mode is not enabled or the pinned map is unavailable. Requires Linux + epoll + JNA + CAP_BPF + external BPF program.
  3. SoOriginalDstResolver — O(1) getsockopt(SO_ORIGINAL_DST) via JNA (requires Linux + Netty epoll transport; returns null on NIO channels or non-Linux)
  4. ConntrackOriginalDestinationResolver — O(n) Linux conntrack table lookup (fallback when SO_ORIGINAL_DST is unavailable)
  5. DnsIntentOriginalDestinationResolver — recovers the intended hostname from MockServer's DNS answer cache (DNS-steering mode)

Note: PROXY protocol v1/v2 resolution is handled separately by ProxyProtocolOriginalDestinationHandler in the Netty pipeline (it requires reading inbound bytes, not just channel metadata at channelActive time).

See Also:
  • Constructor Details

  • Method Details

    • defaultChain

      public static CompositeOriginalDestinationResolver defaultChain(Configuration configuration)
      Returns the default chain: [TPROXY, eBPF, SO_ORIGINAL_DST, conntrack, dns-intent].

      TPROXY is first — when TPROXY mode is active (transparentProxyTproxy=true), the local address IS the original destination and no further resolution is needed. When TPROXY is not enabled, the resolver returns null and the chain falls through.

      eBPF is second — when eBPF mode is active (transparentProxyEbpf=true), the resolver reads a pinned BPF hash map populated by an external cgroup BPF program. The lookup is O(1) and captures the original destination before any NAT rewrite, making it more authoritative than SO_ORIGINAL_DST. When eBPF is not enabled or the pinned map is unavailable, the resolver returns null and the chain falls through.

      SO_ORIGINAL_DST (via JNA getsockopt) is tried third — it is an O(1) socket option read, far cheaper than the O(n) conntrack table scan. It requires Linux + Netty epoll transport; on NIO channels or non-Linux it returns null and the chain falls through to conntrack.

      Conntrack is the fourth strategy because a real iptables-REDIRECT original destination is still the most authoritative source when SO_ORIGINAL_DST is unavailable. The DNS-intent resolver fills the gap when all others return null — it recovers the hostname that MockServer's DNS server mapped to the connection's destination IP.

      Parameters:
      configuration - the MockServer configuration (needed by TPROXY and eBPF resolvers)
    • defaultChain

      public static CompositeOriginalDestinationResolver defaultChain()
      Returns the default chain without TPROXY or eBPF: [SO_ORIGINAL_DST, conntrack, dns-intent].

      This overload maintains backward compatibility for callers that do not have a Configuration instance. TPROXY and eBPF resolution are not included (both require configuration).

    • resolve

      public InetSocketAddress resolve(io.netty.channel.Channel channel)
      Tries each strategy in order. Returns the first non-null result.

      If a strategy throws UnsupportedOperationException, it is skipped (expected on unsupported platforms). Any other exception is also caught and skipped (fail-safe: the caller logs at the appropriate level).

      Specified by:
      resolve in interface TransparentProxyHandler.OriginalDestinationResolver
      Parameters:
      channel - the accepted Netty channel
      Returns:
      the resolved original destination, or null if no strategy resolved it
    • strategyCount

      public int strategyCount()
      Returns the number of strategies in this chain (useful for testing).