XTLS/Xray-core · error · errors.Error

unable to get destination

Error message

unable to get destination

What it means

The dokodemo-door process callback derives the real destination either from config (address), from UDP session targets, or from the original-destination info on the connection (SO_ORIGINAL_DST / recvfrom). If none yields a valid destination (dest invalid or nil address), processing aborts with this error. This is the classic transparent-proxy failure: the inbound cannot discover where the intercepted connection originally headed.

Source

Thrown at proxy/dokodemo/dokodemo.go:135

			if ob.Target.IsValid() {
				dest = ob.Target
				destinationOverridden = true
			}
		}
		iConn := stat.TryUnwrapStatsConn(conn)
		if tlsConn, ok := iConn.(tls.Interface); ok && !destinationOverridden {
			if serverName := tlsConn.HandshakeContextServerName(ctx); serverName != "" {
				dest.Address = net.DomainAddress(serverName)
				destinationOverridden = true
				ctx = session.ContextWithMitmServerName(ctx, serverName)
			}
			if tlsConn.NegotiatedProtocol() != "h2" {
				ctx = session.ContextWithMitmAlpn11(ctx, true)
			}
		}
	}
	if !dest.IsValid() || dest.Address == nil {
		return errors.New("unable to get destination")
	}

	inbound := session.InboundFromContext(ctx)
	inbound.Name = "dokodemo-door"
	inbound.CanSpliceCopy = 1
	inbound.User = &protocol.MemoryUser{
		Level: d.config.UserLevel,
	}

	ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
		From:   conn.RemoteAddr(),
		To:     dest,
		Status: log.AccessAccepted,
		Reason: "",
	})
	errors.LogInfo(ctx, "received request for ", conn.RemoteAddr())

	var reader buf.Reader

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Verify redirect rules exist and match the traffic: iptables -t nat -L -n / nft list ruleset; REDIRECT for nat path, TPROXY with mangle for tproxy path
  2. Ensure the dokodemo inbound option matches the redirection method (followRedirect vs tproxy setting)
  3. If you do not need original-destination, set an explicit "address" (and "port") in inbound settings so dest is always known
  4. Cover IPv6 (ip6tables/nft inet family) if clients connect over v6

Example fix

# before: plain DNAT loses original destination
iptables -t nat -A PREROUTING -p tcp -d $EXT_IP --dport 80 -j DNAT --to-destination 127.0.0.1:1080

# after: REDIRECT preserves it for followRedirect
iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 80 -j REDIRECT --to-ports 1080
Defensive patterns

Strategy: validation

Validate before calling

// pre-flight: ensure original-destination retrieval works for this traffic
if followRedirect {
    if !redirectRulesExist("nat") { fatal("missing iptables REDIRECT rules") }
} else if settings.Address == nil {
    fatal("dokodemo needs address or original-destination mode")
}

Try / catch

if err := d.process(ctx, link, dialer); err != nil {
    if err.Error() == "unable to get destination" { logCaptureHintAndDrop(ctx); return nil }
    return err
}

Prevention

When it happens

Trigger: Using dokodemo with followRedirect/followOriginalDestination but traffic reaches it via plain DNAT/REDIRECT without proper iptables/nftables REDIRECT target, no TPROXY mark, or a protocol (e.g. ICMP) exposing no original destination; also "address" left empty when not following destination.

Common situations: Missing or wrong iptables rules (NAT table REDIRECT vs mangle TPROXY), Docker NAT'd traffic losing original dst, IPv6 traffic not covered by the rules, or misordered rules after firewall refresh; TLS serverName extraction path (seen in source) only applies when MITM is active.

Related errors


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/c16e6776aa323b93. Report an issue: GitHub.