Commit Diff


commit - a31f717839e7e343ae5cc75e7e4e24b7ff703ccc
commit + 04c17184efd215346c23e7ef65b85bcca0d98aa9
blob - d71a7330b615a2751313d4717e6d18e45af1b46e
blob + 9a322d7b4c7008b8e7ce1879817609cbb3783a80
--- ctl.c
+++ ctl.c
@@ -27,6 +27,7 @@
 #include <sys/stat.h>
 #include <sys/socket.h>
 #include <sys/syslimits.h>
+#include <net/if.h>
 #include "externs.h"
 #include "editing.h"
 #include "ctl.h"
@@ -66,6 +67,7 @@ void edit_crontab(char *);
 void install_crontab(char *);
 void edit_motd(char *);
 void call_editor(char *, char **, char *);
+void start_dhcpd(char *, char *, char *, char *, char *);
 int edit_file(char *, mode_t, char *, char **);
 void ctl_symlink(char *, char *, char *);
 int rule_writeline(char *, mode_t, char *);
@@ -416,8 +418,8 @@ struct ctl ctl_nppp[] = {
 /* dhcpd */
 struct ctl2 ctl_dhcp[] = {
 	{ "enable",        "enable DHCPd daemon",
-	    { DHCPD, "-c", REQTEMP, "-l", DHCPLEASES, NULL }, { NULL, }, NULL,
-	    DB_X_ENABLE, T_EXEC },
+	    { DHCPD, "-c", REQTEMP, "-l", DHCPLEASES, NULL }, { NULL, },
+	    start_dhcpd, DB_X_ENABLE, T_HANDLER },
 	{ "disable",       "disable DHCPd daemon",
 	    { PKILL, table, "dhcpd", NULL }, { NULL, }, NULL,
 	    DB_X_DISABLE, T_EXEC },
@@ -1154,4 +1156,86 @@ rmtemp(char *file)
 		if (errno != ENOENT)
 			printf("%% Unable to remove temporary file %s: %s\n",
 			    file, strerror(errno));
+}
+
+void
+start_dhcpd(char *arg0, char *arg1, char *arg2, char *arg3, char *arg4)
+{
+	struct if_nameindex *ifn_list, *ifnp;
+	char **dhcpd_args = NULL;
+	size_t niface = 0;
+	int ifs, i;
+	char leasedb[PATH_MAX];
+
+	/*
+	 * For rdomains other than zero dhcpd(8) expects a list of
+	 * interfaces on its command line. If no interface arguments
+	 * are given then dhcpd will move itself into rdomain zero
+	 * so we really must specify a list here.
+	 *
+	 * All named interfaces must be part of the same rdomain. We
+	 * provide the list of all interfaces in our current rdomain.
+	 * dhcpd will listen on any with matching subnets in dhcpd.conf.
+	 */
+	if ((ifn_list = if_nameindex()) == NULL) {
+		printf("%% %s: if_nameindex failed\n", __func__);
+		return;
+	}
+
+	if ((ifs = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+		printf("%% %s socket: %s\n", __func__, strerror(errno));
+		goto done;
+	}
+
+	for (ifnp = ifn_list; ifnp->if_name != NULL; ifnp++) {
+		int flags, rdomain;
+
+		flags = get_ifflags(ifnp->if_name, ifs);
+		if ((flags & IFF_LOOPBACK) ||
+		    (flags & IFF_POINTOPOINT) ||
+		    (!(flags & IFF_BROADCAST)))
+			continue;
+
+		rdomain = get_rdomain(ifs, ifnp->if_name);
+		if (rdomain == cli_rtable)
+			niface++;
+	}
+
+	dhcpd_args = calloc(5 + niface + 1, sizeof(char *));
+	if (dhcpd_args == NULL) {
+		printf("%% calloc: %s\n", strerror(errno));
+		goto done;
+	}
+
+	i = 0;
+	dhcpd_args[i++] = arg0; /* dhcpd */
+	dhcpd_args[i++] = arg1; /* -c */
+	dhcpd_args[i++] = arg2; /* dhcpd.conf */
+	dhcpd_args[i++] = arg3; /* -l */
+	if (cli_rtable != 0) {
+		snprintf(leasedb, sizeof(leasedb), "%s.%d",
+		    arg4, cli_rtable);
+		dhcpd_args[i++] = leasedb; /* rdomain's leasedb */
+	} else 
+		dhcpd_args[i++] = arg4; /* default leasedb */
+
+	for (ifnp = ifn_list; ifnp->if_name != NULL; ifnp++) {
+		int flags, rdomain;
+
+		flags = get_ifflags(ifnp->if_name, ifs);
+		if ((flags & IFF_LOOPBACK) ||
+		    (flags & IFF_POINTOPOINT) ||
+		    (!(flags & IFF_BROADCAST)))
+			continue;
+
+		rdomain = get_rdomain(ifs, ifnp->if_name);
+		if (rdomain == cli_rtable)
+			dhcpd_args[i++] = ifnp->if_name;
+	}
+	dhcpd_args[i] = NULL;
+
+	cmdargs(arg0, dhcpd_args);
+done:
+	if_freenameindex(ifn_list);
+	free(dhcpd_args);
 }