Enumerate all interfaces and collect their MAC addresses.

def EnumerateInterfacesFromClient(args):
  """Enumerate all interfaces and collect their MAC addresses."""
  del args  # Unused

  libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("c"))
  ifa = Ifaddrs()
  p_ifa = ctypes.pointer(ifa)
  libc.getifaddrs(ctypes.pointer(p_ifa))

  addresses = {}
  macs = {}
  ifs = set()

  m = p_ifa
  while m:
    ifname = ctypes.string_at(m.contents.ifa_name)
    ifs.add(ifname)
    try:
      iffamily = ord(m.contents.ifa_addr[0])

      if iffamily == 0x2:  # AF_INET
        data = ctypes.cast(m.contents.ifa_addr, ctypes.POINTER(Sockaddrin))
        ip4 = bytes(list(data.contents.sin_addr))
        address_type = rdf_client_network.NetworkAddress.Family.INET
        address = rdf_client_network.NetworkAddress(
            address_type=address_type, packed_bytes=ip4)
        addresses.setdefault(ifname, []).append(address)

      if iffamily == 0x11:  # AF_PACKET
        data = ctypes.cast(m.contents.ifa_addr, ctypes.POINTER(Sockaddrll))
        addlen = data.contents.sll_halen
        macs[ifname] = bytes(list(data.contents.sll_addr[:addlen]))

      if iffamily == 0xA:  # AF_INET6
        data = ctypes.cast(m.contents.ifa_addr, ctypes.POINTER(Sockaddrin6))
        ip6 = bytes(list(data.contents.sin6_addr))
        address_type = rdf_client_network.NetworkAddress.Family.INET6
        address = rdf_client_network.NetworkAddress(
            address_type=address_type, packed_bytes=ip6)
        addresses.setdefault(ifname, []).append(address)
    except ValueError:
      # Some interfaces don't have a iffamily and will raise a null pointer
      # exception. We still want to send back the name.
      pass

    m = m.contents.ifa_next

  libc.freeifaddrs(p_ifa)

  for interface in ifs:
    mac = macs.setdefault(interface, b"")
    address_list = addresses.setdefault(interface, b"")
    args = {"ifname": interface}
    if mac:
      args["mac_address"] = mac
    if addresses:
      args["addresses"] = address_list
    yield rdf_client_network.Interface(**args)