首页 > 解决方案 > 如何检测源地址是 IPv4 还是 IPv6

问题描述

有什么方法可以检测到源地址是 IPv4 还是 IPv6?
我写了类似的东西

let listener = TcpListener::bind("[::]:33333").unwrap();
for res in listener.incoming() {
  match res {
    Ok(stream) => {thread::spawn(move||{handler(stream);},
    Err(_) => {println!("error");},
  }
}

处理函数如下:

fn handler(mut stream: TcpStream) -> Result<(),Error> {
  if stream.peer_addr().unwrap().is_ipv4() {
    println!("peer is IPv4");
  }
  else {
    println!("peer is IPv6");
  }

在处理函数中,我使用 stream.peer_addr().unwrap().is_ipv4() 来查找对等地址是 IPv4 还是 IPv6。但所有地址都是 IPv6。当我连接到 127.0.0.1 的服务器时,对等地址是 IPv4 映射的 IPv6 地址:V6([::ffff:127.0.0.1]:33333)。如果服务器绑定到 0.0.0.0:33333,我无法连接到其 IPv6 地址(例如 ::1)。无论如何,服务器是否接受来自 IPv4 和 IPv6 对等方的连接并且也不使用 IPv4 映射的 IPv6 地址?我正在使用 Ubuntu 20.04.1。谢谢你,ei

标签: rust

解决方案


不,它们是不兼容的协议,您必须将 IPv4 映射到 IPv6。

IPv6 不向后兼容,但映射到 IPv6 的 IPv4 有特殊表示。

80 位设置为 0,然后 16 位设置为 1,然后是 IPv4 地址的 32 位。

换句话说,您可以像这样检查它的 ipv4 是否映射到 ipv6:

fn is_mapped_to_ipv6(addr: SocketAddr) -> bool {
    match addr {
        SocketAddr::V6(v6) => match v6.ip().segments() {
            // 5 * 16 `0` bits, 16 `1` bits, leftover is actual IPv4 addr
            [0, 0, 0, 0, 0, 0xFFFF, ..] => true,
            _ => false,
        },
        _ => false,
    }
}

推荐阅读