Пример #1
0
Файл: conf.c Проект: sthen/nsh
void conf_rdomain(FILE *output, int ifs, char *ifname)
{
	int rdomainid;

	rdomainid = get_rdomain(ifs, ifname);
	if (rdomainid > 0)
		fprintf(output, " rdomain %d\n", rdomainid);
}
Пример #2
0
int
main(int argc, char *argv[])
{
	int			 ch, no_daemon = 0, opt, rdomain;
	extern char		*__progname;
	struct server_list	*sp = NULL;
	struct passwd		*pw;
	struct sockaddr_in	 laddr;

	/* Initially, log errors to stderr as well as to syslogd. */
	openlog(__progname, LOG_NDELAY, DHCPD_LOG_FACILITY);
	setlogmask(LOG_UPTO(LOG_INFO));

	while ((ch = getopt(argc, argv, "adi:o")) != -1) {
		switch (ch) {
		case 'd':
			no_daemon = 1;
			break;
		case 'i':
			if (interfaces != NULL)
				usage();
			if ((interfaces = calloc(1,
			    sizeof(struct interface_info))) == NULL)
				error("calloc");
			strlcpy(interfaces->name, optarg,
			    sizeof(interfaces->name));
			break;
		case 'o':
			/* add the relay agent information option */
			oflag++;
			break;
			
		default:
			usage();
			/* not reached */
		}
	}

	argc -= optind;
	argv += optind;

	if (argc < 1)
		usage();

	while (argc > 0) {
		struct hostent		*he;
		struct in_addr		 ia, *iap = NULL;

		if (inet_aton(argv[0], &ia))
			iap = &ia;
		else {
			he = gethostbyname(argv[0]);
			if (!he)
				warning("%s: host unknown", argv[0]);
			else
				iap = ((struct in_addr *)he->h_addr_list[0]);
		}
		if (iap) {
			if ((sp = calloc(1, sizeof *sp)) == NULL)
				error("calloc");
			sp->next = servers;
			servers = sp;
			memcpy(&sp->to.sin_addr, iap, sizeof *iap);
		}
		argc--;
		argv++;
	}

	if (!no_daemon)
		log_perror = 0;

	if (interfaces == NULL)
		error("no interface given");

	/* Default DHCP/BOOTP ports. */
	server_port = htons(SERVER_PORT);
	client_port = htons(CLIENT_PORT);

	/* We need at least one server. */
	if (!sp)
		usage();

	discover_interfaces(interfaces);

	rdomain = get_rdomain(interfaces->name);

	/* Enable the relay agent option by default for enc0 */
	if (interfaces->hw_address.htype == HTYPE_IPSEC_TUNNEL)
		oflag++;

	bzero(&laddr, sizeof laddr);
	laddr.sin_len = sizeof laddr;
	laddr.sin_family = AF_INET;
	laddr.sin_port = server_port;
	laddr.sin_addr.s_addr = interfaces->primary_address.s_addr;
	/* Set up the server sockaddrs. */
	for (sp = servers; sp; sp = sp->next) {
		sp->to.sin_port = server_port;
		sp->to.sin_family = AF_INET;
		sp->to.sin_len = sizeof sp->to;
		sp->fd = socket(AF_INET, SOCK_DGRAM, 0);
		if (sp->fd == -1)
			error("socket: %m");
		opt = 1;
		if (setsockopt(sp->fd, SOL_SOCKET, SO_REUSEPORT,
		    &opt, sizeof(opt)) == -1)
			error("setsockopt: %m");
		if (setsockopt(sp->fd, SOL_SOCKET, SO_RTABLE, &rdomain,
		    sizeof(rdomain)) == -1)
			error("setsockopt: %m");
		if (bind(sp->fd, (struct sockaddr *)&laddr, sizeof laddr) == -1)
			error("bind: %m");
		if (connect(sp->fd, (struct sockaddr *)&sp->to,
		    sizeof sp->to) == -1)
			error("connect: %m");
		add_protocol("server", sp->fd, got_response, sp);
	}

	/* Socket used to forward packets to the DHCP client */
	if (interfaces->hw_address.htype == HTYPE_IPSEC_TUNNEL) {
		laddr.sin_addr.s_addr = INADDR_ANY;
		server_fd = socket(AF_INET, SOCK_DGRAM, 0);
		if (server_fd == -1)
			error("socket: %m");
		opt = 1;
		if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEPORT,
		    &opt, sizeof(opt)) == -1)
			error("setsockopt: %m");
		if (setsockopt(server_fd, SOL_SOCKET, SO_RTABLE, &rdomain,
		    sizeof(rdomain)) == -1)
			error("setsockopt: %m");
		if (bind(server_fd, (struct sockaddr *)&laddr,
		    sizeof(laddr)) == -1)
			error("bind: %m");
	}

	tzset();

	time(&cur_time);
	bootp_packet_handler = relay;
	if (!no_daemon)
		daemon(0, 0);

	if ((pw = getpwnam("_dhcp")) == NULL)
		error("user \"_dhcp\" not found");
	if (chroot(_PATH_VAREMPTY) == -1)
		error("chroot: %m");
	if (chdir("/") == -1)
		error("chdir(\"/\"): %m");
	if (setgroups(1, &pw->pw_gid) ||
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
		error("can't drop privileges: %m");

	dispatch();
	/* not reached */

	exit(0);
}
Пример #3
0
int
subnet_exists(struct client_lease *l)
{
	struct option_data *opt;
	struct ifaddrs *ifap, *ifa;
	struct in_addr mymask, myaddr, mynet, hismask, hisaddr, hisnet;
	int myrdomain, hisrdomain;

	opt = &l->options[DHO_SUBNET_MASK];
	if (opt->len == sizeof(mymask))
		mymask.s_addr = ((struct in_addr *)opt->data)->s_addr;
	else
		mymask.s_addr = INADDR_ANY;
	myaddr.s_addr = l->address.s_addr;
	mynet.s_addr = mymask.s_addr & myaddr.s_addr;

	myrdomain = get_rdomain(ifi->name);

	if (getifaddrs(&ifap) != 0)
		error("getifaddrs failed");

	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
		if (strcmp(ifi->name, ifa->ifa_name) == 0)
			continue;

		if (ifa->ifa_addr->sa_family != AF_INET)
			continue;

		hisrdomain = get_rdomain(ifa->ifa_name);
		if (hisrdomain != myrdomain)
			continue;

		memcpy(&hismask,
		    &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr,
		    sizeof(hismask));
		memcpy(&hisaddr,
		    &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
		    sizeof(hisaddr));
		hisnet.s_addr = hisaddr.s_addr & hismask.s_addr;

		if (hisnet.s_addr == INADDR_ANY)
			continue;

		/* Would his packets go out *my* interface? */
		if (mynet.s_addr == (hisaddr.s_addr & mymask.s_addr)) {
			note("interface %s already has the offered subnet!",
			    ifa->ifa_name);
			return (1);
		}
		
		/* Would my packets go out *his* interface? */
		if (hisnet.s_addr == (myaddr.s_addr & hismask.s_addr)) {
			note("interface %s already has the offered subnet!",
			    ifa->ifa_name);
			return (1);
		}
	}

	freeifaddrs(ifap);

	return (0);
}
Пример #4
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);
}
Пример #5
0
/*
 * Loop waiting for packets, timeouts or routing messages.
 */
void
dispatch(void)
{
	int count, to_msec;
	struct pollfd fds[3];
	time_t cur_time, howlong;
	void (*func)(void);

	while (quit == 0) {
		/*
		 * Call expired timeout, and then if there's still
		 * a timeout registered, time out the select call then.
		 */
another:
		if (!ifi) {
			warning("No interfaces available");
			quit = INTERNALSIG;
			continue;
		}

		if (ifi->rdomain != get_rdomain(ifi->name)) {
			warning("Interface %s:"
			    " rdomain changed out from under us",
			    ifi->name);
			quit = INTERNALSIG;
			continue;
		}

		if (timeout.func) {
			time(&cur_time);
			if (timeout.when <= cur_time) {
				func = timeout.func;
				cancel_timeout();
				(*(func))();
				goto another;
			}
			/*
			 * Figure timeout in milliseconds, and check for
			 * potential overflow, so we can cram into an
			 * int for poll, while not polling with a
			 * negative timeout and blocking indefinitely.
			 */
			howlong = timeout.when - cur_time;
			if (howlong > INT_MAX / 1000)
				howlong = INT_MAX / 1000;
			to_msec = howlong * 1000;
		} else
			to_msec = -1;

		/* Set up the descriptors to be polled. */
		if (!ifi || ifi->rfdesc == -1) {
			warning("No live interface to poll on");
			quit = INTERNALSIG;
			continue;
		}

		fds[0].fd = ifi->rfdesc;
		fds[1].fd = routefd; /* Could be -1, which will be ignored. */
		fds[2].fd = unpriv_ibuf->fd;
		fds[0].events = fds[1].events = fds[2].events = POLLIN;

		if (unpriv_ibuf->w.queued)
			fds[2].events |= POLLOUT;

		/* Wait for a packet or a timeout or unpriv_ibuf->fd. XXX */
		count = poll(fds, 3, to_msec);

		/* Not likely to be transitory. */
		if (count == -1) {
			if (errno == EAGAIN || errno == EINTR) {
				continue;
			} else {
				warning("poll: %s", strerror(errno));
				quit = INTERNALSIG;
				continue;
			}
		}

		if ((fds[0].revents & (POLLIN | POLLHUP))) {
			if (ifi && ifi->linkstat && ifi->rfdesc != -1)
				got_one();
		}
		if ((fds[1].revents & (POLLIN | POLLHUP))) {
			if (ifi)
				routehandler();
		}
		if (fds[2].revents & POLLOUT) {
			if (msgbuf_write(&unpriv_ibuf->w) <= 0 &&
			    errno != EAGAIN) {
				warning("pipe write error to [priv]");
				quit = INTERNALSIG;
				continue;
			}
		}
		if ((fds[2].revents & (POLLIN | POLLHUP))) {
			/* Pipe to [priv] closed. Assume it emitted error. */
			quit = INTERNALSIG;
			continue;
		}
	}

	if (quit == SIGHUP) {
		/* Tell [priv] process that HUP has occurred. */
		sendhup(client->active);
		warning("%s; restarting", strsignal(quit));
		exit (0);
	} else if (quit != INTERNALSIG) {
		warning("%s; exiting", strsignal(quit));
		exit(1);
	}
}