Skip to content

Instantly share code, notes, and snippets.

@makotom
Last active July 1, 2022 05:47
Show Gist options
  • Save makotom/9bab3eccbd5eccc82011dd9730a8825a to your computer and use it in GitHub Desktop.
Save makotom/9bab3eccbd5eccc82011dd9730a8825a to your computer and use it in GitHub Desktop.
IPv6 link-local addresses are not selected by RFC 3484/RFC 6724 destination address selection on Linux
$ uname -a
Linux *****.makotom.org 5.18.7-arch1-1 #1 SMP PREEMPT_DYNAMIC Sat, 25 Jun 2022 20:22:01 +0000 x86_64 GNU/Linux
$ curl -fsSJL https://gist.github.com/makotom/9bab3eccbd5eccc82011dd9730a8825a/raw/try-connect.c | gcc -o try-connect -x c -
$ ./try-connect 2001:db8::1234:5678
connecting 2001:db8::1234:5678...connected
src_addr: 240b:10:****:****:****:****:****:****
$ ./try-connect fe80::1234:5678
connecting fe80::1234:5678...EINVAL (22): Invalid argument
$ ./try-connect "$(ip -6 addr | grep 'scope link' | head -n 1 | awk '{ print $2 }' | awk -F/ '{ print $1 }')"
connecting fe80::****:****:****:****...EINVAL (22): Invalid argument
$ ./try-connect fe80::1234:5678%lo
connecting fe80::1234:5678%lo...connected
src_addr: ::1
$ ./try-connect ::1
connecting ::1...connected
src_addr: ::1
$ ./try-connect ::
connecting ::...connected
src_addr: ::1
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
extern int errno;
int try_connect(char *dst_addr_str)
{
int con_ret = -1;
char src_addr_str[40];
// https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/posix/getaddrinfo.c;h=18dccd5924e88a67d856ca60552ab3491166db46#l2335
int fd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_IP);
struct sockaddr_in6 dst_addr, src_addr;
int sl = sizeof(src_addr);
memset(&dst_addr, '\0', sizeof(dst_addr));
memset(&src_addr, '\0', sizeof(src_addr));
memset(src_addr_str, '\0', 40);
dst_addr.sin6_family = AF_INET6;
inet_pton(AF_INET6, dst_addr_str, &dst_addr.sin6_addr);
// https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/posix/getaddrinfo.c;h=18dccd5924e88a67d856ca60552ab3491166db46#l362
dst_addr.sin6_port = 0;
printf("connecting %s...", dst_addr_str);
// https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/posix/getaddrinfo.c;h=18dccd5924e88a67d856ca60552ab3491166db46#l2345
if ((con_ret = connect(fd, (struct sockaddr *)&dst_addr, sizeof(dst_addr))) == 0)
{
printf("connected\n");
if (getsockname(fd, (struct sockaddr *)&src_addr, &sl) == 0)
{
inet_ntop(AF_INET6, (struct sockaddr *)&src_addr.sin6_addr, src_addr_str, 40);
printf("src_addr: %s\n", src_addr_str);
return 0;
}
}
else
{
printf("%s (%d): %s\n", strerrorname_np(errno), errno, strerror(errno));
}
return 1;
}
int main(int argc, char *argv[])
{
if (argc == 2)
{
return try_connect(argv[1]);
}
return -1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment