Exemple #1
0
/*
 * 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);
}
Exemple #2
0
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);
}