shadowsocks/shadowsocks-rust · error

not supported udp transparent proxy type

Error message

not supported udp transparent proxy type

What it means

bind() on Linux UDP transparent proxy only supports RedirType::TProxy for UDP; any other RedirType (e.g. Redirect) yields InvalidInput. It is a compile-time-style runtime guard ensuring the caller picks a UDP-capable transparent proxy mode.

Source

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

                libc::setsockopt(
                    socket.as_raw_fd(),
                    libc::SOL_SOCKET,
                    libc::SO_MARK,
                    &mark as *const _ as *const _,
                    mem::size_of_val(&mark) as libc::socklen_t,
                )
            };
            if ret != 0 {
                return Err(Error::last_os_error());
            }
        }

        Ok(socket)
    }

    fn bind(ty: RedirType, addr: SocketAddr, reuse_port: bool) -> io::Result<Self> {
        if ty != RedirType::TProxy {
            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 && let Err(err) = socket.set_reuse_port(true) {
            if let Some(libc::ENOPROTOOPT) = err.raw_os_error() {
                // SO_REUSEPORT is supported after 3.9
                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 the UDP transparent proxy type to 'tproxy' in the local server configuration
  2. Add iptables TPROXY rules (mangle table, PREROUTING with TPROXY target) so tproxy mode actually works
  3. If only plain redirect is available, do not instantiate the UDP relay with the redirect type
  4. Verify the RedirType enum value passed in comes from parsed config, not a default

Example fix

// before
let ty = RedirType::Redirect;
UdpRedirSocket::bind(ty, addr, false)?;
// after
let ty = RedirType::TProxy; // UDP on Linux requires tproxy
UdpRedirSocket::bind(ty, addr, false)?;
Defensive patterns

Strategy: validation

Validate before calling

if redir_type != RedirType::TProxy {
    return Err("Linux UDP transparent proxy requires redir-type=tproxy");
}

Type guard

fn udp_supported(ty: RedirType) -> bool { matches!(ty, RedirType::TProxy) }

Try / catch

match UdpRedirSocket::bind(ty, addr, reuse) { Err(e) if e.kind()==InvalidInput => bail!("configure udp redir-type=tproxy"), r => r }

Prevention

When it happens

Trigger: Calling UdpRedirSocket::bind (directly or via bind_nonlocal) with ty set to anything other than RedirType::TProxy on Linux — typically because the config's udp redir type was set to 'redirect' or left as NotSupported.

Common situations: Configuring the local redir server with redir-type=redirect for TCP but reusing the same type for UDP; on Linux UDP requires tproxy (TPROXY iptables rules).

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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