I don't have much knowledge about the IPv6 protocol, so sorry if the question sounds stupid. When I retrieve the list of all IPv6 addresses in my network, I get a field named scope, as shown below :
inet6 addr: 2001:470:1:82::11/64 Scope:Global
inet6 addr: 2001:470:1:82::10/64 Scope:Global
inet6 addr: 2001:470:1:82::13/64 Scope:Global
inet6 addr: fe80::21d:9ff:fe69:2c50/64 Scope:Link
inet6 addr: 2001:470:1:82::12/64 Scope:Global
inet6 addr: 2001:470:1:82::15/64 Scope:Global
inet6 addr: 2001:470:1:82::14/64 Scope:Global
inet6 addr: 2001:470:1:82::5/64 Scope:Global
inet6 addr: 2001:470:1:82::17/64 Scope:Global
inet6 addr: 2001:470:1:82::6/64 Scope:Global
inet6 addr: 2001:470:1:82::16/64 Scope:Global
inet6 addr: 2001:470:1:82::7/64 Scope:Global
inet6 addr: 2001:470:1:82::19/64 Scope:Global
inet6 addr: 2001:470:1:82::8/64 Scope:Global
inet6 addr: 2001:470:1:82::18/64 Scope:Global
inet6 addr: 2001:470:1:82::9/64 Scope:Global
inet6 addr: 2001:470:1:82::1b/64 Scope:Global
inet6 addr: 2001:470:1:82::a/64 Scope:Global
inet6 addr: 2001:470:1:82::1a/64 Scope:Global
inet6 addr: 2001:470:1:82::b/64 Scope:Global
inet6 addr: 2001:470:1:82::1d/64 Scope:Global
inet6 addr: 2001:470:1:82::c/64 Scope:Global
inet6 addr: 2001:470:1:82::1c/64 Scope:Global
inet6 addr: 2001:470:1:82::d/64 Scope:Global
inet6 addr: 2001:470:1:82::1f/64 Scope:Global
inet6 addr: 2001:470:1:82::e/64 Scope:Global
inet6 addr: 2001:470:1:82::1e/64 Scope:Global
inet6 addr: 2001:470:1:82::f/64 Scope:Global
inet6 addr: ::1/128 Scope:Host
In my application, I need to get those addresses for which the scope is 'Link'. I could have used a system call to ifconfig and then parsed the output to extract corresponding addresses. But the problem is, I'm using the call to getifaddrs(), which returns a linked list of structure ifaddr, given as :
struct ifaddrs {
struct ifaddrs *ifa_next; /* Next item in list */
char *ifa_name; /* Name of interface */
unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */
struct sockaddr *ifa_addr; /* Address of interface */
struct sockaddr *ifa_netmask; /* Netmask of interface */
union {
struct sockaddr *ifu_broadaddr;
/* Broadcast address of interface */
struct sockaddr *ifu_dstaddr;
/* Point-to-point destination address */
} ifa_ifu;
#define ifa_broadaddr ifa_ifu.ifu_broadaddr
#define ifa_dstaddr ifa_ifu.ifu_dstaddr
void *ifa_data; /* Address-specific data */
};
The question is : how to get the addresses with 'Link' scope from this list ?
There are helper macros to assist:
struct sockaddr_in6 s6;
if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) {
puts ("link-local");
} else if (IN6_IS_ADDR_SITELOCAL(&s6.sin6_addr)) {
puts ("site-local");
} else if (IN6_IS_ADDR_V4MAPPED(&s6.sin6_addr)) {
puts ("v4mapped");
} else if (IN6_IS_ADDR_V4COMPAT(&s6.sin6_addr)) {
puts ("v4compat");
} else if (IN6_IS_ADDR_LOOPBACK(&s6.sin6_addr)) {
puts ("host");
} else if (IN6_IS_ADDR_UNSPECIFIED(&s6.sin6_addr)) {
puts ("unspecified");
} else {
puts ("global");
}
One way to do this would simply be to check whether the address falls within fe80::/10
. The IPv6 address space is available from IANA, which details the possible scopes available.
I downloaded the source code to net-tools (the source package for ifconfig), and it looks like they parse /proc/net/if_inet6
. (Comments are my own additions in the following code — also the below is extremely abridged and will most certainly not compile.)
/* some defines collected around the place: */
#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
#define IPV6_ADDR_LOOPBACK 0x0010U
#define IPV6_ADDR_LINKLOCAL 0x0020U
#define IPV6_ADDR_SITELOCAL 0x0040U
#define IPV6_ADDR_COMPATv4 0x0080U
int scope; /* among other stuff */
/* looks like here we parse the contents of /proc/net/if_inet6: */
if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
addr6p[0], addr6p[1], addr6p[2], addr6p[3],
addr6p[4], addr6p[5], addr6p[6], addr6p[7],
&if_idx, &plen, &scope, &dad_status, devname) != EOF) {
/* slightly later: */
printf(_(" Scope:"));
switch (scope) {
case 0:
printf(_("Global"));
break;
case IPV6_ADDR_LINKLOCAL:
printf(_("Link"));
break;
case IPV6_ADDR_SITELOCAL:
printf(_("Site"));
break;
case IPV6_ADDR_COMPATv4:
printf(_("Compat"));
break;
case IPV6_ADDR_LOOPBACK:
printf(_("Host"));
break;
default:
printf(_("Unknown"));
}
So let's have a look at what the above is parsing:
$ cat /proc/net/if_inet6
20010db8000008000000000000000001 03 40 00 00 eth0
fe800000000000000000000000004321 03 40 20 80 eth0
00000000000000000000000000000001 01 80 10 80 lo
So you can see the third column from the left (0x00
Global, 0x20
Link-Local, and 0x10
Loopback) is the scope. Using the above constants from the net-tools code you can work out what they mean. Further investigation would be required to determine a more authoritative source for such constants, and also whether parsing /proc/net/if_inet6
is your best option.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With