2

Suppose I'd like a list of all IP addresses on my Linux machine by their interface names, using both IPv6 and IPv4.

The best advice I could find is to use getifaddrs() that should support IPv6, similarly to a post from here. However, the getifaddrs() uses struct ifaddrs which uses struct sockaddr which is incompatible with IPv6. Instead, it should be a pointer to a union with struct in6_addr as well.

How is this handled? How does getifaddrs() support IPv6? Is the documentation obsolete?

Community
  • 1
  • 1
eyalore
  • 21
  • 1
  • 3
  • 4
    What makes you think `sockaddr` is incompatible with IPv6? Are you confusing it with `sockaddr_in`? – Sneftel Dec 11 '14 at 10:29
  • Those are indeed confusing. I unserstood from [here](http://www.beej.us/guide/bgnet/output/html/multipage/sockaddr_inman.html) that 'sockaddr' is very platform dependent, and that generally ipv6 requires distinct structures – eyalore Dec 11 '14 at 11:30
  • 1
    No, `sockaddr` is platform-independent. IPv6 does require different structures than IPv4 (`sockaddr_in6` instead of `sockaddr_in`). But both of those are compatible with `sockaddr`. – Sneftel Dec 11 '14 at 11:53
  • `sockaddr` should be used as the pointer whilst `sockaddr_storage` should be used for the storage and cast or made a union with `sockaddr_in` and `sockaddr_in6`. – Steve-o Dec 12 '14 at 15:49

1 Answers1

4

My C is terribly rusty, and structs with members containing unions (like struct sockaddr_in6) no longer fit in my brain, so in the best cut and paste traditions I adapted chrisaycock's answer (which enumerates the system's IPv4 addresses) to use getnameinfo() instead, with some help from the getifaddrs() man page (which has a better example):

#define _GNU_SOURCE    # required for NI_NUMERICHOST
#include <arpa/inet.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>

int main ()
{
  struct ifaddrs *ifap, *ifa;
  struct sockaddr_in6 *sa;
  char addr[INET6_ADDRSTRLEN];

  if (getifaddrs(&ifap) == -1) {
      perror("getifaddrs");
      exit(1);
  }

  for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
    if (ifa->ifa_addr && ifa->ifa_addr->sa_family==AF_INET6) {
      sa = (struct sockaddr_in6 *) ifa->ifa_addr;
      getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), addr,
                  sizeof(addr), NULL, 0, NI_NUMERICHOST);
      printf("Interface: %s\tAddress: %s\n", ifa->ifa_name, addr);
    }
  }

  freeifaddrs(ifap);
  return 0;
}

The output on my system:

Interface: lo   Address: ::1
Interface: br0  Address: fdbf:e684:d5fb:6:6e62:6dff:fed1:dfad
Interface: br0  Address: 2001:db8:1f80:81c6:6e62:6dff:fed1:dfad
Interface: br0  Address: fe80::6e62:6dff:fed1:dfad%br0
Interface: virbr1       Address: fe80::5054:ff:fece:bfec%virbr1
Interface: virbr0       Address: fe80::5054:ff:fef9:c92e%virbr0
Interface: virbr2       Address: fe80::5054:ff:fedd:ea18%virbr2
Interface: vnet0        Address: fe80::fc54:ff:fe90:de19%vnet0
Interface: vnet1        Address: fe80::fc54:ff:fede:b69c%vnet1

Remember to add error checking to everything; some error checks have been omitted from this example.

Michael Hampton
  • 9,737
  • 4
  • 55
  • 96
  • This program gives segmentation fault on my machine. After some investigation, and according to man on getifaddrs, ifa_addr may contain a null pointer. Add check for this to the if statement: if (ifa->ifa_addr && (ifa->ifa_addr->sa_family==AF_INET6)) – Kim Nyholm Sep 08 '20 at 07:22
  • @KimNyholm Error checking was omitted from this trivial example. In serious code you would also check the return value from `getifaddrs()` to be sure that it had returned valid data. – Michael Hampton Sep 08 '20 at 12:34
  • Saved in a file `"nif-IPv6-Adrs-List.c"` inside my `~/Projects` folder, Compiled on macOS(10.15.x/Catalina) with: `gcc -Wall -o ~/Projects/nif-IPv6-Adrs-List ~/Projects/nif-IPv6-Adrs-List.c` . Shown code as of Sept-8, 2020, has compiled fine & `~/Projects/nif-IPv6-Adrs-List` can run fine w/o any errors. – atErik Sep 09 '20 at 04:20
  • @atErik That's good news. I wasn't even thinking about portability. – Michael Hampton Sep 09 '20 at 17:13