LINUX.ORG.RU

IPv6 multicast - что делаю не так?

 , , ,


1

5

ЛОР, нужна консультация эксперта по сетевому программированию и IPv6. Стал ковырять реализацию UPnP на растишке. Пилю обнаружение устройств через мультикаст. Через IPv4 работает норм, с IPv6 пока фигня [читать дальше...]

В UPnP для обнаружения устройств по IPv6 юзаются два мультикаст-адреса: ff02::c и ff05::C. Пытаюсь создать сокет, чтобы получать мультикаст-пакеты:

use std::net;

static SSDP_PORT: u16 = 1900;
static SSDP_MULTICAST_ADDR: &str = "ff02::c";     // падает
// static SSDP_MULTICAST_ADDR: &str = "ff05::c";  // а так работает

fn main() {
    let addr: net::Ipv6Addr = SSDP_MULTICAST_ADDR.parse().unwrap();
    let socket_addr = net::SocketAddr::new(addr.into(), SSDP_PORT);
    let socket = net::UdpSocket::bind(&socket_addr).expect(&format!("cannot bind to {}", socket_addr));
    socket.join_multicast_v6(&addr, 0).expect(&format!("Cannot join multicast group {}", addr));
}

Со адресом ff05::c всё работает, с адресом ff02::c падает с EINVAL при попытке забиндить сокет:

cargo run --bin test                                                                                                                                                               ~/src/sbox/rust-multicast
    Finished dev [unoptimized + debuginfo] target(s) in 0.06s
     Running `target/debug/test`
thread 'main' panicked at 'cannot bind to [ff02::c]:1900: Os { code: 22, kind: InvalidInput, message: "Invalid argument" }', libcore/result.rs:945:5

Что делаю не так?

В интернетах говорят, что EINVAL при использовании ff02::* может получаться, если у твоего интерфейса нет link-local адреса (fe80::*).

ilammy ★★★
()
Ответ на: комментарий от ilammy

Вроде есть:

$ ip addr show dev enp4s0
2: enp4s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether f2:3d:e6:8b:e1:5f brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.4/24 brd 10.0.0.255 scope global dynamic noprefixroute enp4s0
       valid_lft 86387sec preferred_lft 86387sec
    inet6 fe80::8f31:365e:e107:49a2/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
HeipaVai1o
() автор топика

Разобрался, man ipv6 говорит, что для link-local адресов нужно дополнительно указывать индекс интерфейса в поле sockaddr_in6.sin6_scope_id. В растишке это делается через SocketAddrV6::set_scope_id() или через SocketAddrV6::new().

Так работает:

use std::net;

static SSDP_PORT: u16 = 1900;
static SSDP_MULTICAST_ADDR: &str = "ff02::c";

fn main() {
    let addr: net::Ipv6Addr = SSDP_MULTICAST_ADDR.parse().unwrap();
    let socket_addr = net::SocketAddrV6::new(addr, SSDP_PORT, 0, 2);  // 2 - индекс моего интерфейса enp4s0
    let socket = net::UdpSocket::bind(&socket_addr).expect(&format!("cannot bind to {}", socket_addr));
    socket.join_multicast_v6(&addr, 0).expect(&format!("Cannot join multicast group {}", addr));
}
HeipaVai1o
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.