shadowsocks/shadowsocks-rust · error

not supported udp transparent proxy type

Error message

not supported udp transparent proxy type

What it means

UdpRedirSocket::bind on the BSD freebsd path rejects RedirType::NotSupported with InvalidInput. NotSupported is the placeholder used when the platform/config has no UDP transparent proxy capability, so binding a UDP redir socket with it is always a programming or configuration error.

Source

Thrown at crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/freebsd.rs:45

impl UdpRedirSocket {
    /// Create a new UDP socket binded to `addr`
    ///
    /// This will allow listening to `addr` that is not in local host
    pub fn listen(ty: RedirType, addr: SocketAddr) -> io::Result<UdpRedirSocket> {
        UdpRedirSocket::bind(ty, addr, false)
    }

    /// Create a new UDP socket binded to `addr`
    ///
    /// This will allow binding to `addr` that is not in local host
    pub fn bind_nonlocal(ty: RedirType, addr: SocketAddr, _: &RedirSocketOpts) -> io::Result<UdpRedirSocket> {
        UdpRedirSocket::bind(ty, addr, true)
    }

    fn bind(ty: RedirType, addr: SocketAddr, reuse_port: bool) -> io::Result<UdpRedirSocket> {
        if ty == RedirType::NotSupported {
            return Err(Error::new(
                ErrorKind::InvalidInput,
                "not supported udp transparent proxy type",
            ));
        }

        let socket = Socket::new(Domain::for_address(addr), Type::DGRAM, Some(Protocol::UDP))?;
        set_socket_before_bind(&addr, &socket)?;

        socket.set_nonblocking(true)?;
        socket.set_reuse_address(true)?;
        if reuse_port {
            if let Err(err) = socket.set_reuse_port(true) {
                if let Some(libc::ENOPROTOOPT) = err.raw_os_error() {
                    trace!("failed to set SO_REUSEPORT, error: {}", err);
                } else {
                    error!("failed to set SO_REUSEPORT, error: {}", err);
                    return Err(err);
                }

View on GitHub (pinned to 8eb0f0a65b)

Solutions

  1. Set an explicit supported UDP redir type in the config (e.g. packet-filter on FreeBSD).
  2. Check RedirType::udp_support()/feature flags before constructing a UDP redir listener.
  3. Disable the UDP portion of the redir inbound if the platform lacks UDP transparent proxying.
  4. Upgrade the library/platform if you expect UDP redir support here.

Example fix

// before
let sock = UdpRedirSocket::bind_nonlocal(redir_type, addr, &opts)?; // redir_type == NotSupported
// after
if RedirType::udp_default() == RedirType::NotSupported {
    eprintln!("UDP transparent proxy not supported on this platform; skipping UDP redir");
} else {
    let sock = UdpRedirSocket::bind_nonlocal(RedirType::udp_default(), addr, &opts)?;
}
Defensive patterns

Strategy: validation

Validate before calling

// check platform UDP support before binding
if RedirType::udp_default() == RedirType::NotSupported {
    return Err(io::Error::new(io::ErrorKind::Unsupported, "udp redir unavailable"));
}

Type guard

fn udp_redir_available(ty: &RedirType) -> bool { *ty != RedirType::NotSupported }

Try / catch

match UdpRedirSocket::bind_nonlocal(ty, addr, &opts) {
    Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => {
        tracing::warn!("UDP transparent proxy unsupported; running TCP-only");
        None
    }
    r => Some(r?),
}

Prevention

When it happens

Trigger: Calling UdpRedirSocket::bind/bind_nonlocal with ty == RedirType::NotSupported — e.g. UDP transparent proxy disabled at build time (cfg-gated) or the config omitted a udp redir type so the resolved type defaulted to NotSupported.

Common situations: Configs enabling a UDP redir inbound on platforms/versions where UDP redir isn't supported, or code paths that propagate a NotSupported default instead of erroring earlier at config parsing.

Related errors


AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09). Data as JSON: /api/errors/7d59dfa56902e31c. Report an issue: GitHub.