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("");

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,

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>

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)?;

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