How to connect to an IPv6 link local address

So in some network application, we connect the TCP server like this:

let stream = TcpStream::connect("192.168.0.100:8080");

It works, but if I switch to a IPv6 link local server, it failed, e.g.

let stream = TcpStream::connect("[fe80::aecc:8eff:fee2:65de%eth1]:8080");

So does someone know which is correct way to handle this case? Thanks.

Best Regads,
Hermes

Does it work without the %eth1 part? Do you get any specific error?

Everything here assumes Linux; YMMV for other systems.

Connecting to a link local address requires setting the scope in the address structure (sin6_scope_id in struct sockaddr_in6). Valid scope values are interface indices, obtained by the SIOCGIFINDEX ioctl on an open socket. Here is a small C program to print out the interface index of its first argument (save it as ifix.c):

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>

int
main(int argc, char *argv[])
{
    int s;
    struct ifreq ifr;

    if (argc < 2) {
        fprintf(stderr, "Usage: ifix <ifname>\n");
        return 1;
    }
    s = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (s < 0) {
        perror("ifix: socket");
        return 1;
    }
    ifr.ifr_name[IFNAMSIZ - 1] = '\0';
    strncpy(ifr.ifr_name, argv[1], IFNAMSIZ - 1);
    if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
        perror("ifix: SIOCGIFINDEX");
        return 1;
    }
    printf("%d\n", ifr.ifr_ifindex);
    return 0;
}

Knowing the interface index, you can use it to initialize a SocketAddrV6 struct in Rust and pass it to TcpStream::connect():

use std::error::Error;
use std::net::{SocketAddrV6, TcpStream};

fn main() -> Result<(), Box<dyn Error>> {
    // assume: lo = 1, eth0 = 2,  eth1 = 3
    let sock = SocketAddrV6::new("fe80::aecc:8eff:fee2:65de".parse()?, 8080, 0, 3);
    let _strm = TcpStream::connect(sock)?;
    Ok(())
}

Retrieving the interface index in Rust will require a couple of raw libc calls.

@kornel Trying to connect to a link local address without specifying the outgoing interface, by setting the scope or binding the socket to that interface, will result in an error ("invalid argument" or similar) since the kernel doesn't know where to send the packets.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.