Exemplo n.º 1
0
static int
parse_addr(struct in_addr *addr, struct in_addr *net, const char *arg)
{
	char *p;
	int i;

	if (arg == NULL || *arg == '\0') {
		if (addr != NULL)
			addr->s_addr = 0;
		if (net != NULL)
			net->s_addr = 0;
		return 0;
	}
	if ((p = strchr(arg, '/')) != NULL) {
		*p++ = '\0';
		if (net != NULL &&
		    (sscanf(p, "%d", &i) != 1 ||
			inet_cidrtoaddr(i, net) != 0))
		{
			syslog(LOG_ERR, "`%s' is not a valid CIDR", p);
			return -1;
		}
	}

	if (addr != NULL && inet_aton(arg, addr) == 0) {
		syslog(LOG_ERR, "`%s' is not a valid IP address", arg);
		return -1;
	}
	if (p != NULL)
		*--p = '/';
	else if (net != NULL && addr != NULL)
		net->s_addr = ipv4_getnetmask(addr->s_addr);
	return 0;
}
Exemplo n.º 2
0
int main(int argc, char **argv)
{
	options_t options;
	int doversion = 0;
	int dohelp = 0;
	int userclasses = 0;
	int opt;
	int option_index = 0;
	char prefix[IF_NAMESIZE + 3];
	pid_t pid;
	int debug = 0;
	int i;
	int pidfd = -1;
	int sig = 0;

	const struct option longopts[] = {
		{"arp",         no_argument,        NULL, 'a'},
		{"script",      required_argument,  NULL, 'c'},
		{"debug",       no_argument,        NULL, 'd'},
		{"hostname",    optional_argument,  NULL, 'h'},
		{"classid",     optional_argument,  NULL, 'i'},
		{"release",     no_argument,        NULL, 'k'},
		{"leasetime",   required_argument,  NULL, 'l'},
		{"metric",      required_argument,  NULL, 'm'},
		{"renew",       no_argument,        NULL, 'n'},
		{"persistent",  no_argument,        NULL, 'p'},
		{"inform",      optional_argument,  NULL, 's'},
		{"request",     optional_argument,  NULL, 'r'},
		{"timeout",     required_argument,  NULL, 't'},
		{"userclass",   required_argument,  NULL, 'u'},
		{"exit",        no_argument,        NULL, 'x'},
		{"lastlease",   no_argument,        NULL, 'E'},
		{"fqdn",        required_argument,  NULL, 'F'},
		{"nogateway",   no_argument,        NULL, 'G'},
		{"sethostname", no_argument,        NULL, 'H'},
		{"clientid",    optional_argument,  NULL, 'I'},
		{"noipv4ll",	no_argument,		NULL, 'L'},
		{"nomtu",       no_argument,        NULL, 'M'},
		{"nontp",       no_argument,        NULL, 'N'},
		{"nodns",       no_argument,        NULL, 'R'},
		{"test",        no_argument,        NULL, 'T'},
		{"nonis",       no_argument,        NULL, 'Y'},
		{"help",        no_argument,        &dohelp, 1},
		{"version",     no_argument,        &doversion, 1},
		{NULL,          0,                  NULL, 0}
	};

	/* Close any un-needed fd's */
	for (i = getdtablesize() - 1; i >= 3; --i)
		close (i);

	openlog (PACKAGE, LOG_PID, LOG_LOCAL0);

	memset (&options, 0, sizeof (options_t));
	options.script = (char *) DEFAULT_SCRIPT;
	snprintf (options.classid, CLASS_ID_MAX_LEN, "%s %s", PACKAGE, VERSION);
	options.classid_len = strlen (options.classid);

	options.doarp = true;
	options.dodns = true;
	options.domtu = true;
	options.donis = true;
	options.dontp = true;
	options.dogateway = true;
	options.daemonise = true;
	options.doinform = false;
	options.doipv4ll = true;
	options.timeout = DEFAULT_TIMEOUT;

	gethostname (options.hostname, sizeof (options.hostname));
	if (strcmp (options.hostname, "(none)") == 0 ||
		strcmp (options.hostname, "localhost") == 0)
		memset (options.hostname, 0, sizeof (options.hostname));

	/* Don't set any optional arguments here so we retain POSIX
	 * compatibility with getopt */
	while ((opt = getopt_long(argc, argv, "c:dh:i:kl:m:npr:s:t:u:xAEF:GHI:LMNRTY",
							  longopts, &option_index)) != -1)
	{
		switch (opt) {
			case 0:
				if (longopts[option_index].flag)
					break;
				logger (LOG_ERR, "option `%s' should set a flag",
						longopts[option_index].name);
				exit (EXIT_FAILURE);
				break;
			case 'c':
				options.script = optarg;
				break;
			case 'd':
				debug++;
				switch (debug) {
					case 1:
						setloglevel (LOG_DEBUG);
						break;
					case 2:
						options.daemonise = false;
						break;
				}
				break;
			case 'h':
				if (! optarg)
					memset (options.hostname, 0, sizeof (options.hostname));
				else if (strlen (optarg) > MAXHOSTNAMELEN) {
					logger (LOG_ERR, "`%s' too long for HostName string, max is %d",
							optarg, MAXHOSTNAMELEN);
					exit (EXIT_FAILURE);
				} else
					strlcpy (options.hostname, optarg, sizeof (options.hostname));
				break;
			case 'i':
				if (! optarg) {
					memset (options.classid, 0, sizeof (options.classid));
					options.classid_len = 0;
				} else if (strlen (optarg) > CLASS_ID_MAX_LEN) {
					logger (LOG_ERR, "`%s' too long for ClassID string, max is %d",
							optarg, CLASS_ID_MAX_LEN);
					exit (EXIT_FAILURE);
				} else
					options.classid_len = strlcpy (options.classid, optarg,
												   sizeof (options.classid));
				break;
			case 'k':
				sig = SIGHUP;
				break;
			case 'l':
				STRINGINT (optarg, options.leasetime);
				if (options.leasetime <= 0) {
					logger (LOG_ERR, "leasetime must be a positive value");
					exit (EXIT_FAILURE);
				}
				break;
			case 'm':
				STRINGINT (optarg, options.metric);
				break;
			case 'n':
				sig = SIGALRM;
				break;
			case 'p':
				options.persistent = true;
				break;
			case 's':
				options.doinform = true;
				if (! optarg || strlen (optarg) == 0) {
					options.request_address.s_addr = 0;
					break;
				} else {
					char *slash = strchr (optarg, '/');
					if (slash) {
						int cidr;
						/* nullify the slash, so the -r option can read the
						 * address */
						*slash++ = '\0';
						if (sscanf (slash, "%d", &cidr) != 1) {
							logger (LOG_ERR, "`%s' is not a valid CIDR", slash);
							exit (EXIT_FAILURE);
						}
						options.request_netmask = inet_cidrtoaddr (cidr);
					}
					/* fall through */
				}
			case 'r':
				if (! options.doinform)
					options.dorequest = true;
				if (strlen (optarg) > 0 &&
					! inet_aton (optarg, &options.request_address))
				{ 
					logger (LOG_ERR, "`%s' is not a valid IP address", optarg);
					exit (EXIT_FAILURE);
				}
				break;
			case 't':
				STRINGINT (optarg, options.timeout);
				if (options.timeout < 0) {
					logger (LOG_ERR, "timeout must be a positive value");
					exit (EXIT_FAILURE);
				}
				break;
			case 'u':
				{
					int offset = 0;
					for (i = 0; i < userclasses; i++)
						offset += (int) options.userclass[offset] + 1;
					if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN) {
						logger (LOG_ERR, "userclass overrun, max is %d",
								USERCLASS_MAX_LEN);
						exit (EXIT_FAILURE);
					}
					userclasses++;
					memcpy (options.userclass + offset + 1 , optarg, strlen (optarg));
					options.userclass[offset] = strlen (optarg);
					options.userclass_len += (strlen (optarg)) + 1;
				}
				break;
			case 'x':
				sig = SIGTERM;
				break;
			case 'A':
#ifndef ENABLE_ARP
				logger (LOG_ERR, "arp support not compiled into dhcpcd");
				exit (EXIT_FAILURE);
#endif
				options.doarp = false;
				break;
			case 'E':
#ifndef ENABLE_INFO
				logger (LOG_ERR, "info support not compiled into dhcpcd");
				exit (EXIT_FAILURE);
#endif
				options.dolastlease = true;
				break;
			case 'F':
				if (strncmp (optarg, "none", strlen (optarg)) == 0)
					options.fqdn = FQDN_NONE;
				else if (strncmp (optarg, "ptr", strlen (optarg)) == 0)
					options.fqdn = FQDN_PTR;
				else if (strncmp (optarg, "both", strlen (optarg)) == 0)
					options.fqdn = FQDN_BOTH;
				else {
					logger (LOG_ERR, "invalid value `%s' for FQDN", optarg);
					exit (EXIT_FAILURE);
				}
				break;
			case 'G':
				options.dogateway = false;
				break;
			case 'H':
				options.dohostname++;
				break;
			case 'I':
				if (optarg) {
					if (strlen (optarg) > CLIENT_ID_MAX_LEN) {
						logger (LOG_ERR, "`%s' is too long for ClientID, max is %d",
								optarg, CLIENT_ID_MAX_LEN);
						exit (EXIT_FAILURE);
					}
					options.clientid_len = strlcpy (options.clientid, optarg,
													sizeof (options.clientid));
					/* empty string disabled duid */
					if (options.clientid_len == 0)
						options.clientid_len = -1;
				} else {
					memset (options.clientid, 0, sizeof (options.clientid));
					options.clientid_len = -1;
				}
				break;
			case 'L':
				options.doipv4ll = false;
				break;
			case 'M':
				options.domtu = false;
				break;
			case 'N':
				options.dontp = false;
				break;
			case 'R':
				options.dodns = false;
				break;
			case 'T':
#ifndef ENABLE_INFO
				logger (LOG_ERR, "info support not compiled into dhcpcd");
				exit (EXIT_FAILURE);
#endif
				options.test = true;
				options.persistent = true;
				break;
			case 'Y':
				options.donis = false;
				break;
			case '?':
				usage ();
				exit (EXIT_FAILURE);
			default:
				usage ();
				exit (EXIT_FAILURE);
		}
	}
	if (doversion)
		printf (""PACKAGE" "VERSION"\n");

	if (dohelp)
		usage ();

	if (optind < argc) {
		if (strlen (argv[optind]) > IF_NAMESIZE) {
			logger (LOG_ERR, "`%s' is too long for an interface name (max=%d)",
					argv[optind], IF_NAMESIZE);
			exit (EXIT_FAILURE);
		}
		strlcpy (options.interface, argv[optind],
				 sizeof (options.interface));
	} else {
		/* If only version was requested then exit now */
		if (doversion || dohelp)
			exit (EXIT_SUCCESS);

		logger (LOG_ERR, "no interface specified");
		exit (EXIT_FAILURE);
	}

	if (strchr (options.hostname, '.')) {
		if (options.fqdn == FQDN_DISABLE)
			options.fqdn = FQDN_BOTH;
	} else
		options.fqdn = FQDN_DISABLE;

	if (options.request_address.s_addr == 0 && options.doinform) {
		if ((options.request_address.s_addr = get_address (options.interface)) != 0)
			options.keep_address = true;
	}

	if (geteuid ()) {
		logger (LOG_ERR, "you need to be root to run "PACKAGE);
		exit (EXIT_FAILURE);
	}

	snprintf (prefix, IF_NAMESIZE, "%s: ", options.interface);
	setlogprefix (prefix);
	snprintf (options.pidfile, sizeof (options.pidfile), PIDFILE,
			  options.interface);

	chdir ("/");
	umask (022);

	if (mkdir (CONFIGDIR, S_IRUSR |S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP
			   | S_IROTH | S_IXOTH) && errno != EEXIST )
	{
		logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", CONFIGDIR, strerror (errno));
		exit (EXIT_FAILURE);
	}

	if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP
			   | S_IROTH | S_IXOTH) && errno != EEXIST )
	{
		logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", ETCDIR, strerror (errno));
		exit (EXIT_FAILURE);
	}

	if (options.test) {
		if (options.dorequest || options.doinform) {
			logger (LOG_ERR, "cannot test with --inform or --request");
			exit (EXIT_FAILURE);
		}

		if (options.dolastlease) {
			logger (LOG_ERR, "cannot test with --lastlease");
			exit (EXIT_FAILURE);
		}

		if (sig != 0) {
			logger (LOG_ERR, "cannot test with --release or --renew");
			exit (EXIT_FAILURE);
		}
	}

	if (sig != 0 ) {
		int killed = -1;
		pid = read_pid (options.pidfile);
		if (pid != 0)
			logger (LOG_INFO, "sending signal %d to pid %d", sig, pid);

		if (! pid || (killed = kill (pid, sig)))
			logger (sig == SIGALRM ? LOG_INFO : LOG_ERR, ""PACKAGE" not running");

		if (pid != 0 && (sig != SIGALRM || killed != 0))
			unlink (options.pidfile);

		if (killed == 0)
			exit (EXIT_SUCCESS);

		if (sig != SIGALRM)
			exit (EXIT_FAILURE);
	}

	if (! options.test) {
		if ((pid = read_pid (options.pidfile)) > 0 && kill (pid, 0) == 0) {
			logger (LOG_ERR, ""PACKAGE" already running on pid %d (%s)",
					pid, options.pidfile);
			exit (EXIT_FAILURE);
		}

		pidfd = open (options.pidfile, O_WRONLY | O_CREAT | O_NONBLOCK, 0660);
		if (pidfd == -1) {
			logger (LOG_ERR, "open `%s': %s", options.pidfile, strerror (errno));
			exit (EXIT_FAILURE);
		}

		/* Lock the file so that only one instance of dhcpcd runs on an interface */
		if (flock (pidfd, LOCK_EX | LOCK_NB) == -1) {
			logger (LOG_ERR, "flock `%s': %s", options.pidfile, strerror (errno));
			exit (EXIT_FAILURE);
		}

		/* dhcpcd.sh should not interhit this fd */
		if ((i = fcntl (pidfd, F_GETFD, 0)) == -1 ||
			fcntl (pidfd, F_SETFD, i | FD_CLOEXEC) == -1)
			logger (LOG_ERR, "fcntl: %s", strerror (errno));

		logger (LOG_INFO, PACKAGE " " VERSION " starting");
	}

	/* Seed random */
	srandomdev ();

	if (dhcp_run (&options, &pidfd)) {
		if (pidfd > -1)
			close (pidfd);
		unlink (options.pidfile);
		exit (EXIT_FAILURE);
	}

	exit (EXIT_SUCCESS);
}
Exemplo n.º 3
0
int main(int argc, char **argv)
{
	options_t *options;
	int userclasses = 0;
	int opt;
	int option_index = 0;
	char *prefix;
	pid_t pid;
	int debug = 0;
	int i;
	int pidfd = -1;
	int sig = 0;

	/* Close any un-needed fd's */
	for (i = getdtablesize() - 1; i >= 3; --i)
		close (i);

	openlog (PACKAGE, LOG_PID, LOG_LOCAL0);

	options = xmalloc (sizeof (options_t));
	memset (options, 0, sizeof (options_t));
	options->script = (char *) DEFAULT_SCRIPT;
	snprintf (options->classid, CLASS_ID_MAX_LEN, "%s %s", PACKAGE, VERSION);
	options->classid_len = strlen (options->classid);

	options->doarp = true;
	options->dodns = true;
	options->domtu = true;
	options->donis = true;
	options->dontp = true;
	options->dogateway = true;
	options->daemonise = true;
	options->doinform = false;
	options->doipv4ll = true;
	options->timeout = DEFAULT_TIMEOUT;

	gethostname (options->hostname, sizeof (options->hostname));
	if (strcmp (options->hostname, "(none)") == 0 ||
		strcmp (options->hostname, "localhost") == 0)
		memset (options->hostname, 0, sizeof (options->hostname));

	/* Don't set any optional arguments here so we retain POSIX
	 * compatibility with getopt */
	while ((opt = getopt_long(argc, argv, EXTRA_OPTS
							  "c:dh:i:kl:m:npr:s:t:u:xAEF:GHI:LMNRTY",
							  longopts, &option_index)) != -1)
	{
		switch (opt) {
			case 0:
				if (longopts[option_index].flag)
					break;
				logger (LOG_ERR, "option `%s' should set a flag",
						longopts[option_index].name);
				exit (EXIT_FAILURE);
				break;
			case 'c':
				options->script = optarg;
				break;
			case 'd':
				debug++;
				switch (debug) {
					case 1:
						setloglevel (LOG_DEBUG);
						break;
					case 2:
						options->daemonise = false;
						break;
				}
				break;
#ifdef THERE_IS_NO_FORK
			case 'f':
				options->daemonised = true;
				close_fds ();
				break;
			case 'g':
				dhcpcd_skiproutes = xstrdup (optarg);
				break;
#endif
			case 'h':
				if (! optarg)
					memset (options->hostname, 0, sizeof (options->hostname));
				else if (strlen (optarg) > MAXHOSTNAMELEN) {
					logger (LOG_ERR, "`%s' too long for HostName string, max is %d",
							optarg, MAXHOSTNAMELEN);
					exit (EXIT_FAILURE);
				} else
					strlcpy (options->hostname, optarg, sizeof (options->hostname));
				break;
			case 'i':
				if (! optarg) {
					memset (options->classid, 0, sizeof (options->classid));
					options->classid_len = 0;
				} else if (strlen (optarg) > CLASS_ID_MAX_LEN) {
					logger (LOG_ERR, "`%s' too long for ClassID string, max is %d",
							optarg, CLASS_ID_MAX_LEN);
					exit (EXIT_FAILURE);
				} else
					options->classid_len = strlcpy (options->classid, optarg,
												   sizeof (options->classid));
				break;
			case 'k':
				sig = SIGHUP;
				break;
			case 'l':
				STRINGINT (optarg, options->leasetime);
				if (options->leasetime <= 0) {
					logger (LOG_ERR, "leasetime must be a positive value");
					exit (EXIT_FAILURE);
				}
				break;
			case 'm':
				STRINGINT (optarg, options->metric);
				break;
			case 'n':
				sig = SIGALRM;
				break;
			case 'p':
				options->persistent = true;
				break;
			case 's':
				options->doinform = true;
				options->doarp = false;
				if (! optarg || strlen (optarg) == 0) {
					options->request_address.s_addr = 0;
					break;
				} else {
					char *slash = strchr (optarg, '/');
					if (slash) {
						int cidr;
						/* nullify the slash, so the -r option can read the
						 * address */
						*slash++ = '\0';
						if (sscanf (slash, "%d", &cidr) != 1 ||
							inet_cidrtoaddr (cidr, &options->request_netmask) != 0) {
							logger (LOG_ERR, "`%s' is not a valid CIDR", slash);
							exit (EXIT_FAILURE);
						}
					}
					/* fall through */
				}
			case 'r':
				if (! options->doinform)
					options->dorequest = true;
				if (strlen (optarg) > 0 &&
					! inet_aton (optarg, &options->request_address))
				{ 
					logger (LOG_ERR, "`%s' is not a valid IP address", optarg);
					exit (EXIT_FAILURE);
				}
				break;
			case 't':
				STRINGINT (optarg, options->timeout);
				if (options->timeout < 0) {
					logger (LOG_ERR, "timeout must be a positive value");
					exit (EXIT_FAILURE);
				}
				break;
			case 'u':
				{
					int offset = 0;
					for (i = 0; i < userclasses; i++)
						offset += (int) options->userclass[offset] + 1;
					if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN) {
						logger (LOG_ERR, "userclass overrun, max is %d",
								USERCLASS_MAX_LEN);
						exit (EXIT_FAILURE);
					}
					userclasses++;
					memcpy (options->userclass + offset + 1 , optarg, strlen (optarg));
					options->userclass[offset] = strlen (optarg);
					options->userclass_len += (strlen (optarg)) + 1;
				}
				break;
			case 'x':
				sig = SIGTERM;
				break;
			case 'A':
#ifndef ENABLE_ARP
				logger (LOG_ERR, "arp support not compiled into dhcpcd");
				exit (EXIT_FAILURE);
#endif
				options->doarp = false;
				break;
			case 'E':
#ifndef ENABLE_INFO
				logger (LOG_ERR, "info support not compiled into dhcpcd");
				exit (EXIT_FAILURE);
#endif
				options->dolastlease = true;
				break;
			case 'F':
				if (strncmp (optarg, "none", strlen (optarg)) == 0)
					options->fqdn = FQDN_NONE;
				else if (strncmp (optarg, "ptr", strlen (optarg)) == 0)
					options->fqdn = FQDN_PTR;
				else if (strncmp (optarg, "both", strlen (optarg)) == 0)
					options->fqdn = FQDN_BOTH;
				else {
					logger (LOG_ERR, "invalid value `%s' for FQDN", optarg);
					exit (EXIT_FAILURE);
				}
				break;
			case 'G':
				options->dogateway = false;
				break;
			case 'H':
				options->dohostname++;
				break;
			case 'I':
				if (optarg) {
					if (strlen (optarg) > CLIENT_ID_MAX_LEN) {
						logger (LOG_ERR, "`%s' is too long for ClientID, max is %d",
								optarg, CLIENT_ID_MAX_LEN);
						exit (EXIT_FAILURE);
					}
					options->clientid_len = strlcpy (options->clientid, optarg,
													sizeof (options->clientid));
					/* empty string disabled duid */
					if (options->clientid_len == 0)
						options->clientid_len = -1;
				} else {
					memset (options->clientid, 0, sizeof (options->clientid));
					options->clientid_len = -1;
				}
				break;
			case 'L':
				options->doipv4ll = false;
				break;
			case 'M':
				options->domtu = false;
				break;
			case 'N':
				options->dontp = false;
				break;
			case 'R':
				options->dodns = false;
				break;
			case 'T':
#ifndef ENABLE_INFO
				logger (LOG_ERR, "info support not compiled into dhcpcd");
				exit (EXIT_FAILURE);
#endif
				options->test = true;
				options->persistent = true;
				break;
			case 'Y':
				options->donis = false;
				break;
			case '?':
				usage ();
				exit (EXIT_FAILURE);
			default:
				usage ();
				exit (EXIT_FAILURE);
		}
	}
	if (doversion) {
		printf (""PACKAGE" "VERSION"\n");
		printf ("Compile time options:"
#ifdef ENABLE_ARP
				" ARP"
#endif
#ifdef ENABLE_DUID
				" DUID"
#endif
#ifdef ENABLE_INFO
				" INFO"
#endif
#ifdef ENABLE_INFO_COMPAT
				" INFO_COMPAT"
#endif
#ifdef ENABLE_IPV4LL
				" IPV4LL"
#endif
#ifdef ENABLE_NIS
				" NIS"
#endif
#ifdef ENABLE_NTP
				" NTP"
#endif
#ifdef THERE_IS_NO_FORK
				" THERE_IS_NO_FORK"
#endif
				"\n");
	}

	if (dohelp)
		usage ();

#ifdef THERE_IS_NO_FORK
	dhcpcd_argv = argv;
	dhcpcd_argc = argc;

	/* We need the full path to the dhcpcd */
	if (*argv[0] == '/')
		strlcpy (dhcpcd, argv[0], sizeof (dhcpcd));
	else {
		char pwd[PATH_MAX];
		if (! getcwd (pwd, PATH_MAX)) {
			logger (LOG_ERR, "getcwd: %s", strerror (errno));
			exit (EXIT_FAILURE);
		}
		snprintf (dhcpcd, sizeof (dhcpcd), "%s/%s", pwd, argv[0]);
	}

#endif

	if (optind < argc) {
		if (strlen (argv[optind]) > IF_NAMESIZE) {
			logger (LOG_ERR, "`%s' is too long for an interface name (max=%d)",
					argv[optind], IF_NAMESIZE);
			exit (EXIT_FAILURE);
		}
		strlcpy (options->interface, argv[optind],
				 sizeof (options->interface));
	} else {
		/* If only version was requested then exit now */
		if (doversion || dohelp)
			exit (EXIT_SUCCESS);

		logger (LOG_ERR, "no interface specified");
		exit (EXIT_FAILURE);
	}

	if (strchr (options->hostname, '.')) {
		if (options->fqdn == FQDN_DISABLE)
			options->fqdn = FQDN_BOTH;
	} else
		options->fqdn = FQDN_DISABLE;

	if (options->request_address.s_addr == 0 && options->doinform) {
		if ((options->request_address.s_addr = get_address (options->interface)) != 0)
			options->keep_address = true;
	}

	if (IN_LINKLOCAL (options->request_address.s_addr)) {
		logger (LOG_ERR, "you are not allowed to request a link local address");
		exit (EXIT_FAILURE);
	}

	if (geteuid ()) {
		logger (LOG_ERR, "you need to be root to run "PACKAGE);
		exit (EXIT_FAILURE);
	}

	prefix = xmalloc (sizeof (char) * (IF_NAMESIZE + 3));
	snprintf (prefix, IF_NAMESIZE, "%s: ", options->interface);
	setlogprefix (prefix);
	snprintf (options->pidfile, sizeof (options->pidfile), PIDFILE,
			  options->interface);
	free (prefix);

	chdir ("/");
	umask (022);
	
	if (mkdir (CONFIGDIR, S_IRUSR |S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP
			   | S_IROTH | S_IXOTH) && errno != EEXIST )
	{
		logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", CONFIGDIR, strerror (errno));
		exit (EXIT_FAILURE);
	}

	if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP
			   | S_IROTH | S_IXOTH) && errno != EEXIST )
	{
		logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", ETCDIR, strerror (errno));
		exit (EXIT_FAILURE);
	}

	if (options->test) {
		if (options->dorequest || options->doinform) {
			logger (LOG_ERR, "cannot test with --inform or --request");
			exit (EXIT_FAILURE);
		}

		if (options->dolastlease) {
			logger (LOG_ERR, "cannot test with --lastlease");
			exit (EXIT_FAILURE);
		}

		if (sig != 0) {
			logger (LOG_ERR, "cannot test with --release or --renew");
			exit (EXIT_FAILURE);
		}
	}

	if (sig != 0) {
		int killed = -1;
		pid = read_pid (options->pidfile);
		if (pid != 0)
			logger (LOG_INFO, "sending signal %d to pid %d", sig, pid);

		if (! pid || (killed = kill (pid, sig)))
			logger (sig == SIGALRM ? LOG_INFO : LOG_ERR, ""PACKAGE" not running");

		if (pid != 0 && (sig != SIGALRM || killed != 0))
			unlink (options->pidfile);

		if (killed == 0)
			exit (EXIT_SUCCESS);

		if (sig != SIGALRM)
			exit (EXIT_FAILURE);
	}

	if (! options->test && ! options->daemonised) {
		if ((pid = read_pid (options->pidfile)) > 0 && kill (pid, 0) == 0) {
			logger (LOG_ERR, ""PACKAGE" already running on pid %d (%s)",
					pid, options->pidfile);
			exit (EXIT_FAILURE);
		}

		pidfd = open (options->pidfile, O_WRONLY | O_CREAT | O_NONBLOCK, 0660);
		if (pidfd == -1) {
			logger (LOG_ERR, "open `%s': %s", options->pidfile, strerror (errno));
			exit (EXIT_FAILURE);
		}

		/* Lock the file so that only one instance of dhcpcd runs on an interface */
		if (flock (pidfd, LOCK_EX | LOCK_NB) == -1) {
			logger (LOG_ERR, "flock `%s': %s", options->pidfile, strerror (errno));
			exit (EXIT_FAILURE);
		}

		/* dhcpcd.sh should not interhit this fd */
		if ((i = fcntl (pidfd, F_GETFD, 0)) == -1 ||
			fcntl (pidfd, F_SETFD, i | FD_CLOEXEC) == -1)
			logger (LOG_ERR, "fcntl: %s", strerror (errno));

		writepid (pidfd, getpid ());
		logger (LOG_INFO, PACKAGE " " VERSION " starting");
	}

	/* Seed random */
	srandomdev ();

	i = EXIT_FAILURE;
	if (dhcp_run (options, &pidfd) == 0)
		i = EXIT_SUCCESS;

	/* If we didn't daemonise then we need to punt the pidfile now */
	if (pidfd > -1) {
		close (pidfd);
		unlink (options->pidfile);
	}

	free (options);

#ifdef THERE_IS_NO_FORK
	/* There may have been an error before the dhcp_run function
	 * clears this, so just do it here to be safe */
	free (dhcpcd_skiproutes);
#endif

	logger (LOG_INFO, "exiting");
	
	exit (i);
}
Exemplo n.º 4
0
static int
link_addr(struct dhcpcd_ctx *ctx, struct interface *ifp, struct nlmsghdr *nlm)
{
	size_t len;
	struct rtattr *rta;
	struct ifaddrmsg *ifa;
	struct priv *priv;
#ifdef INET
	struct in_addr addr, net, brd;
#endif
#ifdef INET6
	struct in6_addr addr6;
#endif

	if (nlm->nlmsg_type != RTM_DELADDR && nlm->nlmsg_type != RTM_NEWADDR)
		return 0;

	len = nlm->nlmsg_len - sizeof(*nlm);
	if (len < sizeof(*ifa)) {
		errno = EBADMSG;
		return -1;
	}

	/* Ignore messages we sent. */
	priv = (struct priv*)ctx->priv;
	if (nlm->nlmsg_pid == priv->route_pid)
		return 0;

	ifa = NLMSG_DATA(nlm);
	if ((ifp = if_findindex(ctx->ifaces, ifa->ifa_index)) == NULL) {
		/* We don't know about the interface the address is for
		 * so it's not really an error */
		return 1;
	}
	rta = (struct rtattr *)IFA_RTA(ifa);
	len = NLMSG_PAYLOAD(nlm, sizeof(*ifa));
	switch (ifa->ifa_family) {
#ifdef INET
	case AF_INET:
		addr.s_addr = brd.s_addr = INADDR_ANY;
		inet_cidrtoaddr(ifa->ifa_prefixlen, &net);
		while (RTA_OK(rta, len)) {
			switch (rta->rta_type) {
			case IFA_ADDRESS:
				if (ifp->flags & IFF_POINTOPOINT) {
					memcpy(&brd.s_addr, RTA_DATA(rta),
					    sizeof(brd.s_addr));
				}
				break;
			case IFA_BROADCAST:
				memcpy(&brd.s_addr, RTA_DATA(rta),
				    sizeof(brd.s_addr));
				break;
			case IFA_LOCAL:
				memcpy(&addr.s_addr, RTA_DATA(rta),
				    sizeof(addr.s_addr));
				break;
			}
			rta = RTA_NEXT(rta, len);
		}
		ipv4_handleifa(ctx, nlm->nlmsg_type, NULL, ifp->name,
		    &addr, &net, &brd, ifa->ifa_flags, (pid_t)nlm->nlmsg_pid);
		break;
#endif
#ifdef INET6
	case AF_INET6:
		memset(&addr6, 0, sizeof(addr6));
		while (RTA_OK(rta, len)) {
			switch (rta->rta_type) {
			case IFA_ADDRESS:
				memcpy(&addr6.s6_addr, RTA_DATA(rta),
				       sizeof(addr6.s6_addr));
				break;
			}
			rta = RTA_NEXT(rta, len);
		}
		ipv6_handleifa(ctx, nlm->nlmsg_type, NULL, ifp->name,
		    &addr6, ifa->ifa_prefixlen, ifa->ifa_flags,
		    (pid_t)nlm->nlmsg_pid);
		break;
#endif
	}
	return 0;
}
Exemplo n.º 5
0
static int
link_addr(struct nlmsghdr *nlm)
{
	int len;
	struct rtattr *rta;
	struct ifaddrmsg *ifa;
	char ifn[IF_NAMESIZE + 1];
	struct interface *iface;
#ifdef INET
	struct in_addr addr, net, dest;
#endif
#ifdef INET6
	struct in6_addr addr6;
#endif

	if (nlm->nlmsg_type != RTM_DELADDR && nlm->nlmsg_type != RTM_NEWADDR)
		return 0;

	len = nlm->nlmsg_len - sizeof(*nlm);
	if ((size_t)len < sizeof(*ifa)) {
		errno = EBADMSG;
		return -1;
	}
//	if (nlm->nlmsg_pid == (uint32_t)getpid())
//		return 1;
	ifa = NLMSG_DATA(nlm);
	if (if_indextoname(ifa->ifa_index, ifn) == NULL)
		return -1;
	iface = find_interface(ifn);
	if (iface == NULL)
		return 1;
	rta = (struct rtattr *) IFA_RTA(ifa);
	len = NLMSG_PAYLOAD(nlm, sizeof(*ifa));
	switch (ifa->ifa_family) {
#ifdef INET
	case AF_INET:
		addr.s_addr = dest.s_addr = INADDR_ANY;
		dest.s_addr = INADDR_ANY;
		inet_cidrtoaddr(ifa->ifa_prefixlen, &net);
		while (RTA_OK(rta, len)) {
			switch (rta->rta_type) {
			case IFA_ADDRESS:
				if (iface->flags & IFF_POINTOPOINT) {
					memcpy(&dest.s_addr, RTA_DATA(rta),
					       sizeof(addr.s_addr));
				}
				break;
			case IFA_LOCAL:
				memcpy(&addr.s_addr, RTA_DATA(rta),
				       sizeof(addr.s_addr));
				break;
			}
			rta = RTA_NEXT(rta, len);
		}
		ipv4_handleifa(nlm->nlmsg_type, NULL, ifn, &addr, &net, &dest);
		break;
#endif
#ifdef INET6
	case AF_INET6:
		memset(&addr6, 0, sizeof(addr6));
		while (RTA_OK(rta, len)) {
			switch (rta->rta_type) {
			case IFA_ADDRESS:
				memcpy(&addr6.s6_addr, RTA_DATA(rta),
				       sizeof(addr6.s6_addr));
				break;
			}
			rta = RTA_NEXT(rta, len);
		}
		ipv6_handleifa(nlm->nlmsg_type, NULL, ifn,
		    &addr6, ifa->ifa_flags);
		break;
#endif
	}
	return 1;
}
Exemplo n.º 6
0
static int
link_route(struct nlmsghdr *nlm)
{
	int len, idx, metric;
	struct rtattr *rta;
	struct rtmsg *rtm;
	struct rt rt;
	char ifn[IF_NAMESIZE + 1];

	if (nlm->nlmsg_type != RTM_DELROUTE)
		return 0;

	len = nlm->nlmsg_len - sizeof(*nlm);
	if ((size_t)len < sizeof(*rtm)) {
		errno = EBADMSG;
		return -1;
	}
	rtm = NLMSG_DATA(nlm);
	if (rtm->rtm_type != RTN_UNICAST ||
	    rtm->rtm_table != RT_TABLE_MAIN ||
	    rtm->rtm_family != AF_INET ||
	    nlm->nlmsg_pid == (uint32_t)getpid())
		return 1;
	rta = (struct rtattr *)(void *)((char *)rtm +NLMSG_ALIGN(sizeof(*rtm)));
	len = NLMSG_PAYLOAD(nlm, sizeof(*rtm));
	memset(&rt, 0, sizeof(rt));
	rt.dest.s_addr = INADDR_ANY;
	rt.net.s_addr = INADDR_ANY;
	rt.gate.s_addr = INADDR_ANY;
	metric = 0;
	while (RTA_OK(rta, len)) {
		switch (rta->rta_type) {
		case RTA_DST:
			memcpy(&rt.dest.s_addr, RTA_DATA(rta),
			    sizeof(rt.dest.s_addr));
			break;
		case RTA_GATEWAY:
			memcpy(&rt.gate.s_addr, RTA_DATA(rta),
			    sizeof(rt.gate.s_addr));
			break;
		case RTA_OIF:
			idx = *(int *)RTA_DATA(rta);
			if (if_indextoname(idx, ifn))
				rt.iface = find_interface(ifn);
			break;
		case RTA_PRIORITY:
			metric = *(int *)RTA_DATA(rta);
			break;
		}
		rta = RTA_NEXT(rta, len);
	}
	if (rt.iface != NULL) {
		if (metric == rt.iface->metric) {
#ifdef INET
			inet_cidrtoaddr(rtm->rtm_dst_len, &rt.net);
			ipv4_routedeleted(&rt);
#endif
		}
	}
	return 1;
}