/* * Use getifaddrs() to get a list of all the attached interfaces. For * each interface that's of type INET and not the loopback interface, * register that interface with the network I/O software, figure out * what subnet it's on, and add it to the list of interfaces. */ void discover_interfaces(struct interface_info *iface) { struct ifaddrs *ifap, *ifa; struct sockaddr_in foo; struct ifreq *tif; if (getifaddrs(&ifap) != 0) error("getifaddrs failed"); for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { if ((ifa->ifa_flags & IFF_LOOPBACK) || (ifa->ifa_flags & IFF_POINTOPOINT) || (!(ifa->ifa_flags & IFF_UP))) continue; if (strcmp(iface->name, ifa->ifa_name)) continue; /* * If we have the capability, extract link information * and record it in a linked list. */ if (ifa->ifa_addr->sa_family == AF_LINK) { struct sockaddr_dl *foo = (struct sockaddr_dl *)ifa->ifa_addr; iface->index = foo->sdl_index; iface->hw_address.hlen = foo->sdl_alen; iface->hw_address.htype = HTYPE_ETHER; /* XXX */ memcpy(iface->hw_address.haddr, LLADDR(foo), foo->sdl_alen); } else if (ifa->ifa_addr->sa_family == AF_INET) { struct iaddr addr; memcpy(&foo, ifa->ifa_addr, sizeof(foo)); if (foo.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) continue; if (!iface->ifp) { int len = IFNAMSIZ + ifa->ifa_addr->sa_len; if ((tif = malloc(len)) == NULL) error("no space to remember ifp"); strlcpy(tif->ifr_name, ifa->ifa_name, IFNAMSIZ); memcpy(&tif->ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len); iface->ifp = tif; iface->primary_address = foo.sin_addr; } addr.len = 4; memcpy(addr.iabuf, &foo.sin_addr.s_addr, addr.len); } } if (!iface->ifp) error("%s: not found", iface->name); /* Register the interface... */ if_register_receive(iface); if_register_send(iface); add_protocol(iface->name, iface->rfdesc, got_one, iface); freeifaddrs(ifap); }
void discover_interfaces(int *rdomain) { struct interface_info *tmp; struct interface_info *last, *next; struct subnet *subnet; struct shared_network *share; struct sockaddr_in foo; int ir = 0, ird; struct ifreq *tif; struct ifaddrs *ifap, *ifa; if (getifaddrs(&ifap) != 0) error("getifaddrs failed"); /* * If we already have a list of interfaces, the interfaces were * requested. */ if (interfaces != NULL) ir = 1; else /* must specify an interface when rdomains are used */ *rdomain = 0; /* Cycle through the list of interfaces looking for IP addresses. */ for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { /* * See if this is the sort of interface we want to * deal with. Skip loopback, point-to-point and down * interfaces, except don't skip down interfaces if we're * trying to get a list of configurable interfaces. */ if ((ifa->ifa_flags & IFF_LOOPBACK) || (ifa->ifa_flags & IFF_POINTOPOINT) || (!(ifa->ifa_flags & IFF_UP)) || (!(ifa->ifa_flags & IFF_BROADCAST))) continue; /* See if we've seen an interface that matches this one. */ for (tmp = interfaces; tmp; tmp = tmp->next) if (!strcmp(tmp->name, ifa->ifa_name)) break; /* If we are looking for specific interfaces, ignore others. */ if (tmp == NULL && ir) continue; ird = get_rdomain(ifa->ifa_name); if (*rdomain == -1) *rdomain = ird; else if (*rdomain != ird && ir) error("Interface %s is not in rdomain %d", tmp->name, *rdomain); else if (*rdomain != ird && !ir) continue; /* If there isn't already an interface by this name, allocate one. */ if (tmp == NULL) { tmp = calloc(1, sizeof *tmp); if (!tmp) error("Insufficient memory to %s %s", "record interface", ifa->ifa_name); strlcpy(tmp->name, ifa->ifa_name, sizeof(tmp->name)); tmp->next = interfaces; tmp->noifmedia = tmp->dead = tmp->errors = 0; interfaces = tmp; } /* If we have the capability, extract link information and record it in a linked list. */ if (ifa->ifa_addr->sa_family == AF_LINK) { struct sockaddr_dl *foo = ((struct sockaddr_dl *)(ifa->ifa_addr)); tmp->index = foo->sdl_index; tmp->hw_address.hlen = foo->sdl_alen; tmp->hw_address.htype = HTYPE_ETHER; /* XXX */ memcpy(tmp->hw_address.haddr, LLADDR(foo), foo->sdl_alen); } else if (ifa->ifa_addr->sa_family == AF_INET) { struct iaddr addr; /* Get a pointer to the address... */ memcpy(&foo, ifa->ifa_addr, sizeof(foo)); /* We don't want the loopback interface. */ if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK)) continue; /* If this is the first real IP address we've found, keep a pointer to ifreq structure in which we found it. */ if (!tmp->ifp) { int len = (IFNAMSIZ + ifa->ifa_addr->sa_len); tif = (struct ifreq *)malloc(len); if (!tif) error("no space to remember ifp."); strlcpy(tif->ifr_name, ifa->ifa_name, IFNAMSIZ); memcpy(&tif->ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len); tmp->ifp = tif; tmp->primary_address = foo.sin_addr; } /* Grab the address... */ addr.len = 4; memcpy(addr.iabuf, &foo.sin_addr.s_addr, addr.len); /* If there's a registered subnet for this address, connect it together... */ if ((subnet = find_subnet(addr))) { /* If this interface has multiple aliases on the same subnet, ignore all but the first we encounter. */ if (!subnet->interface) { subnet->interface = tmp; subnet->interface_address = addr; } else if (subnet->interface != tmp) { warning("Multiple %s %s: %s %s", "interfaces match the", "same subnet", subnet->interface->name, tmp->name); } share = subnet->shared_network; if (tmp->shared_network && tmp->shared_network != share) { warning("Interface %s matches %s", tmp->name, "multiple shared networks"); } else { tmp->shared_network = share; } if (!share->interface) { share->interface = tmp; } else if (share->interface != tmp) { warning("Multiple %s %s: %s %s", "interfaces match the", "same shared network", share->interface->name, tmp->name); } } } } /* Discard interfaces we can't listen on. */ last = NULL; for (tmp = interfaces; tmp; tmp = next) { next = tmp->next; if (!tmp->ifp) { warning("Can't listen on %s - it has no IP address.", tmp->name); /* Remove tmp from the list of interfaces. */ if (!last) interfaces = interfaces->next; else last->next = tmp->next; continue; } memcpy(&foo, &tmp->ifp->ifr_addr, sizeof tmp->ifp->ifr_addr); if (!tmp->shared_network) { warning("Can't listen on %s - dhcpd.conf has no subnet " "declaration for %s.", tmp->name, inet_ntoa(foo.sin_addr)); /* Remove tmp from the list of interfaces. */ if (!last) interfaces = interfaces->next; else last->next = tmp->next; continue; } last = tmp; /* Find subnets that don't have valid interface addresses. */ for (subnet = (tmp->shared_network ? tmp->shared_network->subnets : NULL); subnet; subnet = subnet->next_sibling) { if (!subnet->interface_address.len) { /* * Set the interface address for this subnet * to the first address we found. */ subnet->interface_address.len = 4; memcpy(subnet->interface_address.iabuf, &foo.sin_addr.s_addr, 4); } } /* Register the interface... */ if_register_receive(tmp); if_register_send(tmp); note("Listening on %s (%s).", tmp->name, inet_ntoa(foo.sin_addr)); } if (interfaces == NULL) error("No interfaces to listen on."); /* Now register all the remaining interfaces as protocols. */ for (tmp = interfaces; tmp; tmp = tmp->next) add_protocol(tmp->name, tmp->rfdesc, got_one, tmp); freeifaddrs(ifap); }