Skip to content

疑似 uot v1 v2 实现问题,及其解决方案。 #113

@sealszzz

Description

@sealszzz

我在使用shoes作为anytls服务端,surge作为客户端时发现shoes日志有错误
unknown UoT ATYP: 2
经人指点后,把shoes和sing-box的uot源码扔给AI,得出shoes的uot实现可能有问题的结论。
下面是AI给出的解决代码
之后编译了一下shoes,AnyTLS再没有报错,其他支持uot的协议没有测试。
shoes的trace日志显示
Shadowrocket:V2(connect=1)
Surge:V2(connect=0)

Shadowrocket在编译前后的使用都没有问题,或许shoes的uot对connect=0的兼容有问题。

  1. src/uot/uot_v1_server_stream.rs
- use super::uot_common::{parse_uot_address, write_uot_address};
+ use super::uot_common::{parse_uot_addrparser_address, write_uot_addrparser_address};

-         let (location, addr_len) = match parse_uot_address(data)? {
+         let (location, addr_len) = match parse_uot_addrparser_address(data)? {

-         let offset = write_uot_address(&mut this.write_buf, source);
+         let offset = write_uot_addrparser_address(&mut this.write_buf, source);

  1. src/uot/uot_common.rs 都是+
// NEW: Parse AddrParser format
#[inline]
pub fn parse_uot_addrparser_address(data: &[u8]) -> std::io::Result<Option<(NetLocation, usize)>> {
    if data.is_empty() {
        return Ok(None);
    }

    let atyp = data[0];
    match atyp {
        ADDRPARSER_ATYP_IPV4 => {
            if data.len() < 7 {
                return Ok(None);
            }
            let ip = Ipv4Addr::new(data[1], data[2], data[3], data[4]);
            let port = u16::from_be_bytes([data[5], data[6]]);
            Ok(Some((NetLocation::new(Address::Ipv4(ip), port), 7)))
        }
        ADDRPARSER_ATYP_IPV6 => {
            if data.len() < 19 {
                return Ok(None);
            }
            let ip_bytes: [u8; 16] = data[1..17].try_into().unwrap();
            let ip = Ipv6Addr::from(ip_bytes);
            let port = u16::from_be_bytes([data[17], data[18]]);
            Ok(Some((NetLocation::new(Address::Ipv6(ip), port), 19)))
        }
        ADDRPARSER_ATYP_DOMAIN => {
            if data.len() < 2 {
                return Ok(None);
            }
            let domain_len = data[1] as usize;
            let total_len = 1 + 1 + domain_len + 2;
            if data.len() < total_len {
                return Ok(None);
            }
            let domain = std::str::from_utf8(&data[2..2 + domain_len])
                .map_err(|e| std::io::Error::other(format!("invalid domain: {e}")))?;
            let port = u16::from_be_bytes([data[2 + domain_len], data[3 + domain_len]]);
            Ok(Some((
                NetLocation::new(Address::Hostname(domain.to_string()), port),
                total_len,
            )))
        }
        _ => Err(std::io::Error::other(format!("unknown UoT AddrParser ATYP: {atyp}"))),
    }
}

// NEW: Write AddrParser format
#[inline]
pub fn write_uot_addrparser_address(buf: &mut [u8], addr: &SocketAddr) -> usize {
    match addr {
        SocketAddr::V4(v4) => {
            buf[0] = ADDRPARSER_ATYP_IPV4;
            buf[1..5].copy_from_slice(&v4.ip().octets());
            buf[5..7].copy_from_slice(&v4.port().to_be_bytes());
            7
        }
        SocketAddr::V6(v6) => {
            buf[0] = ADDRPARSER_ATYP_IPV6;
            buf[1..17].copy_from_slice(&v6.ip().octets());
            buf[17..19].copy_from_slice(&v6.port().to_be_bytes());
            19
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions