2006-11-28 04:23:22 +08:00
|
|
|
/*
|
|
|
|
* dhcpcd - DHCP client daemon -
|
2007-01-17 01:54:07 +08:00
|
|
|
* Copyright 2006-2007 Roy Marples <uberlord@gentoo.org>
|
2006-11-28 04:23:22 +08:00
|
|
|
*
|
|
|
|
* dhcpcd is an RFC2131 compliant DHCP client daemon.
|
|
|
|
*
|
|
|
|
* This is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
* See the GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
|
|
|
2007-10-04 17:57:50 +08:00
|
|
|
#ifdef __linux__
|
|
|
|
# define _GNU_SOURCE /* for asprinf */
|
|
|
|
#endif
|
|
|
|
|
2006-11-28 04:23:22 +08:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
2006-12-15 07:17:27 +08:00
|
|
|
#include <netinet/in.h>
|
2006-11-28 04:23:22 +08:00
|
|
|
#ifdef __linux__
|
2007-09-04 20:48:40 +08:00
|
|
|
# include <netinet/ether.h>
|
2006-11-28 04:23:22 +08:00
|
|
|
#endif
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <resolv.h>
|
2007-01-17 01:54:07 +08:00
|
|
|
#include <stdarg.h>
|
2006-11-28 04:23:22 +08:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2007-05-10 17:39:26 +08:00
|
|
|
#include "config.h"
|
2006-11-28 04:23:22 +08:00
|
|
|
#include "common.h"
|
2006-12-15 07:17:27 +08:00
|
|
|
#include "configure.h"
|
2006-11-28 04:23:22 +08:00
|
|
|
#include "dhcp.h"
|
2007-05-10 17:39:26 +08:00
|
|
|
#ifdef ENABLE_INFO
|
2007-09-04 20:48:40 +08:00
|
|
|
# include "info.h"
|
2007-05-10 17:39:26 +08:00
|
|
|
#endif
|
2006-11-28 04:23:22 +08:00
|
|
|
#include "interface.h"
|
|
|
|
#include "dhcpcd.h"
|
|
|
|
#include "logger.h"
|
|
|
|
#include "socket.h"
|
|
|
|
|
2007-01-17 01:54:07 +08:00
|
|
|
/* IMPORTANT: Ensure that the last parameter is NULL when calling */
|
|
|
|
static int exec_cmd (const char *cmd, const char *args, ...)
|
|
|
|
{
|
2007-04-11 21:18:33 +08:00
|
|
|
va_list va;
|
|
|
|
pid_t pid;
|
|
|
|
char **argv;
|
|
|
|
int n = 1;
|
|
|
|
|
|
|
|
va_start (va, args);
|
|
|
|
while (va_arg (va, char *) != NULL)
|
|
|
|
n++;
|
|
|
|
va_end (va);
|
2007-09-04 20:48:40 +08:00
|
|
|
argv = xmalloc (sizeof (char *) * (n + 2));
|
2007-04-11 21:18:33 +08:00
|
|
|
|
|
|
|
va_start (va, args);
|
|
|
|
n = 2;
|
|
|
|
argv[0] = (char *) cmd;
|
|
|
|
argv[1] = (char *) args;
|
|
|
|
while ((argv[n] = va_arg (va, char *)) != NULL)
|
|
|
|
n++;
|
|
|
|
va_end (va);
|
|
|
|
|
2007-04-16 02:41:14 +08:00
|
|
|
if ((pid = vfork ()) == 0) {
|
2007-04-11 21:18:33 +08:00
|
|
|
if (execv (cmd, argv) && errno != ENOENT)
|
|
|
|
logger (LOG_ERR, "error executing \"%s\": %s",
|
|
|
|
cmd, strerror (errno));
|
2007-04-16 02:41:14 +08:00
|
|
|
_exit (0);
|
2007-09-04 20:48:40 +08:00
|
|
|
} else if (pid == -1) {
|
2007-04-16 02:41:14 +08:00
|
|
|
logger (LOG_ERR, "vfork: %s", strerror (errno));
|
2007-09-04 20:48:40 +08:00
|
|
|
free (argv);
|
|
|
|
return (-1);
|
|
|
|
}
|
2007-04-11 21:18:33 +08:00
|
|
|
|
2007-09-04 20:48:40 +08:00
|
|
|
free (argv);
|
2007-05-14 18:01:56 +08:00
|
|
|
return (0);
|
2007-01-17 01:54:07 +08:00
|
|
|
}
|
|
|
|
|
2006-12-15 07:17:27 +08:00
|
|
|
static void exec_script (const char *script, const char *infofile,
|
2007-04-11 21:18:33 +08:00
|
|
|
const char *arg)
|
2006-11-28 04:23:22 +08:00
|
|
|
{
|
2007-04-11 21:18:33 +08:00
|
|
|
struct stat buf;
|
2006-12-15 22:47:01 +08:00
|
|
|
|
2007-04-11 21:18:33 +08:00
|
|
|
if (! script || ! infofile || ! arg)
|
|
|
|
return;
|
2006-11-28 04:23:22 +08:00
|
|
|
|
2007-07-18 19:35:50 +08:00
|
|
|
if (stat (script, &buf) == -1) {
|
2007-04-11 21:18:33 +08:00
|
|
|
if (strcmp (script, DEFAULT_SCRIPT) != 0)
|
|
|
|
logger (LOG_ERR, "`%s': %s", script, strerror (ENOENT));
|
|
|
|
return;
|
|
|
|
}
|
2006-12-15 22:47:01 +08:00
|
|
|
|
2007-05-14 01:43:56 +08:00
|
|
|
logger (LOG_DEBUG, "exec \"%s\" \"%s\" \"%s\"", script, infofile, arg);
|
2007-04-11 21:18:33 +08:00
|
|
|
exec_cmd (script, infofile, arg, (char *) NULL);
|
2006-11-28 04:23:22 +08:00
|
|
|
}
|
|
|
|
|
2006-12-15 07:17:27 +08:00
|
|
|
static int make_resolv (const char *ifname, const dhcp_t *dhcp)
|
2006-11-28 04:23:22 +08:00
|
|
|
{
|
2007-04-11 21:18:33 +08:00
|
|
|
FILE *f;
|
|
|
|
struct stat buf;
|
|
|
|
char resolvconf[PATH_MAX] = {0};
|
|
|
|
address_t *address;
|
2006-11-28 04:23:22 +08:00
|
|
|
|
2007-04-03 15:03:04 +08:00
|
|
|
#ifdef RESOLVCONF
|
2007-04-11 21:18:33 +08:00
|
|
|
if (stat (RESOLVCONF, &buf) == 0) {
|
|
|
|
logger (LOG_DEBUG, "sending DNS information to resolvconf");
|
|
|
|
snprintf (resolvconf, PATH_MAX, RESOLVCONF" -a %s", ifname);
|
|
|
|
f = popen (resolvconf, "w");
|
|
|
|
|
|
|
|
if (! f)
|
|
|
|
logger (LOG_ERR, "popen: %s", strerror (errno));
|
|
|
|
} else
|
2007-04-03 15:03:04 +08:00
|
|
|
#endif
|
2007-04-11 21:18:33 +08:00
|
|
|
{
|
|
|
|
logger (LOG_DEBUG, "writing "RESOLVFILE);
|
|
|
|
if (! (f = fopen(RESOLVFILE, "w")))
|
|
|
|
logger (LOG_ERR, "fopen `%s': %s", RESOLVFILE, strerror (errno));
|
|
|
|
}
|
|
|
|
|
2007-05-14 18:01:56 +08:00
|
|
|
if (! f)
|
|
|
|
return (-1);
|
2007-04-11 21:18:33 +08:00
|
|
|
|
2007-05-14 18:01:56 +08:00
|
|
|
fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname);
|
|
|
|
if (dhcp->dnssearch)
|
|
|
|
fprintf (f, "search %s\n", dhcp->dnssearch);
|
|
|
|
else if (dhcp->dnsdomain) {
|
|
|
|
fprintf (f, "search %s\n", dhcp->dnsdomain);
|
|
|
|
}
|
2007-04-11 21:18:33 +08:00
|
|
|
|
2007-05-14 18:01:56 +08:00
|
|
|
for (address = dhcp->dnsservers; address; address = address->next)
|
|
|
|
fprintf (f, "nameserver %s\n", inet_ntoa (address->address));
|
|
|
|
|
|
|
|
if (*resolvconf)
|
|
|
|
pclose (f);
|
|
|
|
else
|
|
|
|
fclose (f);
|
2007-04-11 21:18:33 +08:00
|
|
|
|
|
|
|
/* Refresh the local resolver */
|
|
|
|
res_init ();
|
2007-05-14 18:01:56 +08:00
|
|
|
return (0);
|
2006-11-28 04:23:22 +08:00
|
|
|
}
|
|
|
|
|
2006-12-15 07:17:27 +08:00
|
|
|
static void restore_resolv(const char *ifname)
|
2006-11-28 04:23:22 +08:00
|
|
|
{
|
2007-04-03 15:03:04 +08:00
|
|
|
#ifdef RESOLVCONF
|
2007-04-11 21:18:33 +08:00
|
|
|
struct stat buf;
|
2006-11-28 04:23:22 +08:00
|
|
|
|
2007-07-18 19:35:50 +08:00
|
|
|
if (stat (RESOLVCONF, &buf) == -1)
|
2007-04-11 21:18:33 +08:00
|
|
|
return;
|
2006-11-28 04:23:22 +08:00
|
|
|
|
2007-04-11 21:18:33 +08:00
|
|
|
logger (LOG_DEBUG, "removing information from resolvconf");
|
|
|
|
exec_cmd (RESOLVCONF, "-d", ifname, (char *) NULL);
|
2007-04-03 15:03:04 +08:00
|
|
|
#endif
|
2006-11-28 04:23:22 +08:00
|
|
|
}
|
|
|
|
|
2007-04-03 15:03:04 +08:00
|
|
|
#ifdef ENABLE_NTP
|
|
|
|
static int _make_ntp (const char *file, const char *ifname, const dhcp_t *dhcp)
|
2006-11-28 04:23:22 +08:00
|
|
|
{
|
2007-04-11 21:18:33 +08:00
|
|
|
FILE *f;
|
|
|
|
address_t *address;
|
|
|
|
char *a;
|
|
|
|
char buffer[1024];
|
|
|
|
int tomatch = 0;
|
|
|
|
char *token;
|
|
|
|
bool ntp = false;
|
|
|
|
|
|
|
|
for (address = dhcp->ntpservers; address; address = address->next)
|
|
|
|
tomatch++;
|
|
|
|
|
|
|
|
/* Check that we really need to update the servers
|
|
|
|
We do this because ntp has to be restarted to work with a changed config */
|
|
|
|
if (! (f = fopen (file, "r"))) {
|
|
|
|
if (errno != ENOENT) {
|
|
|
|
logger (LOG_ERR, "fopen `%s': %s", file, strerror (errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
memset (buffer, 0, sizeof (buffer));
|
|
|
|
while (fgets (buffer, sizeof (buffer), f)) {
|
|
|
|
a = buffer;
|
|
|
|
token = strsep (&a, " ");
|
|
|
|
if (! token || strcmp (token, "server") != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((token = strsep (&a, " \n")) == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (address = dhcp->ntpservers; address; address = address->next)
|
|
|
|
if (strcmp (token, inet_ntoa (address->address)) == 0) {
|
|
|
|
tomatch--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tomatch == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
fclose (f);
|
|
|
|
|
|
|
|
/* File has the same name servers that we do, so no need to restart ntp */
|
|
|
|
if (tomatch == 0) {
|
|
|
|
logger (LOG_DEBUG, "%s already configured, skipping", file);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
logger (LOG_DEBUG, "writing %s", file);
|
|
|
|
if (! (f = fopen (file, "w"))) {
|
|
|
|
logger (LOG_ERR, "fopen `%s': %s", file, strerror (errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname);
|
2007-04-03 15:03:04 +08:00
|
|
|
#ifdef NTPFILE
|
2007-04-11 21:18:33 +08:00
|
|
|
if (strcmp (file, NTPFILE) == 0) {
|
|
|
|
ntp = true;
|
|
|
|
fprintf (f, "restrict default noquery notrust nomodify\n");
|
|
|
|
fprintf (f, "restrict 127.0.0.1\n");
|
|
|
|
}
|
2007-04-03 15:03:04 +08:00
|
|
|
#endif
|
2006-11-28 04:23:22 +08:00
|
|
|
|
2007-04-11 21:18:33 +08:00
|
|
|
for (address = dhcp->ntpservers; address; address = address->next) {
|
|
|
|
a = inet_ntoa (address->address);
|
|
|
|
if (ntp)
|
|
|
|
fprintf (f, "restrict %s nomodify notrap noquery\n", a);
|
|
|
|
fprintf (f, "server %s\n", a);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ntp) {
|
|
|
|
fprintf (f, "driftfile " NTPDRIFTFILE "\n");
|
|
|
|
fprintf (f, "logfile " NTPLOGFILE "\n");
|
|
|
|
}
|
|
|
|
fclose (f);
|
|
|
|
|
|
|
|
return 1;
|
2007-04-03 15:03:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int make_ntp (const char *ifname, const dhcp_t *dhcp)
|
|
|
|
{
|
2007-04-11 21:18:33 +08:00
|
|
|
/* On some systems we have only have one ntp service, but we don't know
|
|
|
|
which configuration file we're using. So we need to write to both and
|
|
|
|
restart accordingly. */
|
2007-04-03 15:03:04 +08:00
|
|
|
|
2007-04-11 21:18:33 +08:00
|
|
|
bool restart_ntp = false;
|
|
|
|
bool restart_openntp = false;
|
|
|
|
int retval = 0;
|
2007-04-03 15:03:04 +08:00
|
|
|
|
|
|
|
#ifdef NTPFILE
|
2007-04-11 21:18:33 +08:00
|
|
|
if (_make_ntp (NTPFILE, ifname, dhcp) > 0)
|
|
|
|
restart_ntp = true;
|
2007-04-03 15:03:04 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef OPENNTPFILE
|
2007-04-11 21:18:33 +08:00
|
|
|
if (_make_ntp (OPENNTPFILE, ifname, dhcp) > 0)
|
|
|
|
restart_openntp = true;
|
2007-04-03 15:03:04 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef NTPSERVICE
|
2007-04-11 21:18:33 +08:00
|
|
|
if (restart_ntp)
|
|
|
|
retval += exec_cmd (NTPSERVICE, NTPRESTARTARGS, (char *) NULL);
|
2007-04-03 15:03:04 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined (NTPSERVICE) && defined (OPENNTPSERVICE)
|
2007-04-11 21:18:33 +08:00
|
|
|
if (restart_openntp &&
|
|
|
|
(strcmp (NTPSERVICE, OPENNTPSERVICE) != 0 || ! restart_ntp))
|
|
|
|
retval += exec_cmd (OPENNTPSERVICE, OPENNTPRESTARTARGS, (char *) NULL);
|
2007-04-03 15:03:04 +08:00
|
|
|
#elif defined (OPENNTPSERVICE) && ! defined (NTPSERVICE)
|
2007-04-11 21:18:33 +08:00
|
|
|
if (restart_openntp)
|
|
|
|
retval += exec_cmd (OPENNTPSERVICE, OPENNTPRESTARTARGS, (char *) NULL);
|
2007-04-03 15:03:04 +08:00
|
|
|
#endif
|
|
|
|
|
2007-04-11 21:18:33 +08:00
|
|
|
return retval;
|
2006-11-28 04:23:22 +08:00
|
|
|
}
|
2007-04-03 15:03:04 +08:00
|
|
|
#endif
|
2006-11-28 04:23:22 +08:00
|
|
|
|
2007-04-03 15:03:04 +08:00
|
|
|
#ifdef ENABLE_NIS
|
2006-12-15 07:17:27 +08:00
|
|
|
static int make_nis (const char *ifname, const dhcp_t *dhcp)
|
2006-11-28 04:23:22 +08:00
|
|
|
{
|
2007-04-11 21:18:33 +08:00
|
|
|
FILE *f;
|
|
|
|
address_t *address;
|
|
|
|
char prefix[256] = {0};
|
|
|
|
|
|
|
|
logger (LOG_DEBUG, "writing "NISFILE);
|
|
|
|
if (! (f = fopen(NISFILE, "w"))) {
|
|
|
|
logger (LOG_ERR, "fopen `%s': %s", NISFILE, strerror (errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname);
|
|
|
|
if (dhcp->nisdomain) {
|
|
|
|
setdomainname (dhcp->nisdomain, strlen (dhcp->nisdomain));
|
|
|
|
|
|
|
|
if (dhcp->nisservers)
|
|
|
|
snprintf (prefix, sizeof (prefix), "domain %s server", dhcp->nisdomain);
|
|
|
|
else
|
|
|
|
fprintf (f, "domain %s broadcast\n", dhcp->nisdomain);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
snprintf (prefix, sizeof (prefix), "%s", "ypserver");
|
|
|
|
|
|
|
|
for (address = dhcp->nisservers; address; address = address->next)
|
|
|
|
fprintf (f, "%s %s\n", prefix, inet_ntoa (address->address));
|
|
|
|
|
|
|
|
fclose (f);
|
|
|
|
|
|
|
|
exec_cmd (NISSERVICE, NISRESTARTARGS, (char *) NULL);
|
|
|
|
return 0;
|
2006-11-28 04:23:22 +08:00
|
|
|
}
|
2007-04-03 15:03:04 +08:00
|
|
|
#endif
|
|
|
|
|
2006-12-15 07:17:27 +08:00
|
|
|
int configure (const options_t *options, interface_t *iface,
|
2007-05-14 18:01:56 +08:00
|
|
|
const dhcp_t *dhcp, bool up)
|
2006-11-28 04:23:22 +08:00
|
|
|
{
|
2007-04-11 21:18:33 +08:00
|
|
|
route_t *route = NULL;
|
|
|
|
route_t *new_route = NULL;
|
|
|
|
route_t *old_route = NULL;
|
2007-04-18 23:14:55 +08:00
|
|
|
char newhostname[MAXHOSTNAMELEN] = {0};
|
|
|
|
char curhostname[MAXHOSTNAMELEN] = {0};
|
2007-04-11 21:18:33 +08:00
|
|
|
|
|
|
|
if (! options || ! iface || ! dhcp)
|
2007-05-14 18:01:56 +08:00
|
|
|
return (-1);
|
|
|
|
|
|
|
|
if (dhcp->address.s_addr == 0)
|
|
|
|
up = 0;
|
2007-04-11 21:18:33 +08:00
|
|
|
|
|
|
|
/* Remove old routes
|
|
|
|
Always do this as the interface may have >1 address not added by us
|
|
|
|
so the routes we added may still exist */
|
|
|
|
if (iface->previous_routes) {
|
|
|
|
for (route = iface->previous_routes; route; route = route->next)
|
|
|
|
if (route->destination.s_addr || options->dogateway) {
|
|
|
|
int have = 0;
|
2007-05-14 18:01:56 +08:00
|
|
|
if (up)
|
2007-04-11 21:18:33 +08:00
|
|
|
for (new_route = dhcp->routes; new_route; new_route = new_route->next)
|
|
|
|
if (new_route->destination.s_addr == route->destination.s_addr
|
|
|
|
&& new_route->netmask.s_addr == route->netmask.s_addr
|
|
|
|
&& new_route->gateway.s_addr == route->gateway.s_addr)
|
|
|
|
{
|
|
|
|
have = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (! have)
|
|
|
|
del_route (iface->name, route->destination, route->netmask,
|
|
|
|
route->gateway, options->metric);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-14 18:01:56 +08:00
|
|
|
/* If we aren't up, then reset the interface as much as we can */
|
|
|
|
if (! up) {
|
2007-04-11 21:18:33 +08:00
|
|
|
if (iface->previous_routes) {
|
|
|
|
free_route (iface->previous_routes);
|
|
|
|
iface->previous_routes = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Restore the original MTU value */
|
|
|
|
if (iface->mtu && iface->previous_mtu != iface->mtu) {
|
|
|
|
set_mtu (iface->name, iface->mtu);
|
|
|
|
iface->previous_mtu = iface->mtu;
|
|
|
|
}
|
|
|
|
|
2007-05-14 01:43:56 +08:00
|
|
|
#ifdef ENABLE_INFO
|
|
|
|
/* If we haven't created an info file, do so now */
|
2007-05-14 18:01:56 +08:00
|
|
|
if (! dhcp->frominfo)
|
|
|
|
write_info (iface, dhcp, options, false);
|
2007-05-14 01:43:56 +08:00
|
|
|
#endif
|
|
|
|
|
2007-04-11 21:18:33 +08:00
|
|
|
/* Only reset things if we had set them before */
|
|
|
|
if (iface->previous_address.s_addr != 0) {
|
2007-05-12 03:55:00 +08:00
|
|
|
if (! options->keep_address) {
|
|
|
|
del_address (iface->name, iface->previous_address,
|
|
|
|
iface->previous_netmask);
|
|
|
|
memset (&iface->previous_address, 0, sizeof (struct in_addr));
|
|
|
|
memset (&iface->previous_netmask, 0, sizeof (struct in_addr));
|
|
|
|
}
|
2007-05-14 01:43:56 +08:00
|
|
|
}
|
2007-04-11 21:18:33 +08:00
|
|
|
|
2007-05-14 01:43:56 +08:00
|
|
|
restore_resolv (iface->name);
|
|
|
|
/* we currently don't have a resolvconf style programs for ntp/nis */
|
|
|
|
|
|
|
|
exec_script (options->script, iface->infofile, "down");
|
2007-04-11 21:18:33 +08:00
|
|
|
|
2007-05-14 18:01:56 +08:00
|
|
|
return (0);
|
2007-04-11 21:18:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the MTU requested.
|
|
|
|
If the DHCP server no longer sends one OR it's invalid then we restore
|
|
|
|
the original MTU */
|
|
|
|
if (options->domtu) {
|
|
|
|
unsigned short mtu = iface->mtu;
|
|
|
|
if (dhcp->mtu)
|
|
|
|
mtu = dhcp->mtu;
|
|
|
|
|
|
|
|
if (mtu != iface->previous_mtu) {
|
|
|
|
if (set_mtu (iface->name, mtu) == 0)
|
|
|
|
iface->previous_mtu = mtu;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-15 21:34:17 +08:00
|
|
|
/* This also changes netmask */
|
2007-05-12 03:55:00 +08:00
|
|
|
if (! options->doinform || ! has_address (iface->name, dhcp->address))
|
|
|
|
if (add_address (iface->name, dhcp->address, dhcp->netmask,
|
2007-07-18 19:35:50 +08:00
|
|
|
dhcp->broadcast) == -1 && errno != EEXIST)
|
2007-05-14 18:01:56 +08:00
|
|
|
return (false);
|
2007-05-15 21:34:17 +08:00
|
|
|
|
2007-04-11 21:18:33 +08:00
|
|
|
/* Now delete the old address if different */
|
2007-05-15 21:34:17 +08:00
|
|
|
if (iface->previous_address.s_addr != dhcp->address.s_addr) {
|
|
|
|
if (iface->previous_address.s_addr != 0 && ! options->keep_address)
|
|
|
|
del_address (iface->name, iface->previous_address, iface->previous_netmask);
|
|
|
|
}
|
2006-11-28 04:23:22 +08:00
|
|
|
|
|
|
|
#ifdef __linux__
|
2007-04-11 21:18:33 +08:00
|
|
|
/* On linux, we need to change the subnet route to have our metric. */
|
|
|
|
if (iface->previous_address.s_addr != dhcp->address.s_addr
|
|
|
|
&& options->metric > 0 && dhcp->netmask.s_addr != INADDR_BROADCAST)
|
|
|
|
{
|
|
|
|
struct in_addr td;
|
|
|
|
struct in_addr tg;
|
|
|
|
memset (&td, 0, sizeof (td));
|
|
|
|
memset (&tg, 0, sizeof (tg));
|
|
|
|
td.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr;
|
|
|
|
add_route (iface->name, td, dhcp->netmask, tg, options->metric);
|
|
|
|
del_route (iface->name, td, dhcp->netmask, tg, 0);
|
|
|
|
}
|
2006-11-28 04:23:22 +08:00
|
|
|
#endif
|
|
|
|
|
2007-10-04 17:57:50 +08:00
|
|
|
#ifdef THERE_IS_NO_FORK
|
|
|
|
free (dhcpcd_skiproutes);
|
|
|
|
dhcpcd_skiproutes = NULL;
|
|
|
|
#endif
|
|
|
|
|
2007-04-11 21:18:33 +08:00
|
|
|
/* Remember added routes */
|
|
|
|
if (dhcp->routes) {
|
|
|
|
route_t *new_routes = NULL;
|
|
|
|
int remember;
|
2007-10-04 17:57:50 +08:00
|
|
|
#ifdef THERE_IS_NO_FORK
|
|
|
|
int skip = 0;
|
|
|
|
#endif
|
2007-04-11 21:18:33 +08:00
|
|
|
|
|
|
|
for (route = dhcp->routes; route; route = route->next) {
|
|
|
|
/* Don't set default routes if not asked to */
|
|
|
|
if (route->destination.s_addr == 0 && route->netmask.s_addr == 0
|
|
|
|
&& ! options->dogateway)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
remember = add_route (iface->name, route->destination,
|
|
|
|
route->netmask, route->gateway,
|
|
|
|
options->metric);
|
|
|
|
/* If we failed to add the route, we may have already added it
|
|
|
|
ourselves. If so, remember it again. */
|
|
|
|
if (remember < 0)
|
|
|
|
for (old_route = iface->previous_routes; old_route;
|
|
|
|
old_route = old_route->next)
|
|
|
|
if (old_route->destination.s_addr == route->destination.s_addr
|
|
|
|
&& old_route->netmask.s_addr == route->netmask.s_addr
|
|
|
|
&& old_route->gateway.s_addr == route->gateway.s_addr)
|
|
|
|
{
|
|
|
|
remember = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (remember >= 0) {
|
|
|
|
if (! new_routes) {
|
|
|
|
new_routes = xmalloc (sizeof (route_t));
|
|
|
|
memset (new_routes, 0, sizeof (route_t));
|
|
|
|
new_route = new_routes;
|
|
|
|
} else {
|
|
|
|
new_route->next = xmalloc (sizeof (route_t));
|
|
|
|
new_route = new_route->next;
|
|
|
|
}
|
|
|
|
memcpy (new_route, route, sizeof (route_t));
|
|
|
|
new_route -> next = NULL;
|
|
|
|
}
|
2007-10-04 17:57:50 +08:00
|
|
|
#ifdef THERE_IS_NO_FORK
|
|
|
|
/* If we have daemonised yet we need to record which routes
|
|
|
|
* we failed to add so we can skip them */
|
|
|
|
else if (! options->daemonised) {
|
|
|
|
if (dhcpcd_skiproutes) {
|
|
|
|
char *p = NULL;
|
|
|
|
asprintf (&p, "%s,%d", dhcpcd_skiproutes, skip);
|
|
|
|
free (dhcpcd_skiproutes);
|
|
|
|
dhcpcd_skiproutes = p;
|
|
|
|
} else {
|
|
|
|
asprintf (&dhcpcd_skiproutes, "%d", skip);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
skip++;
|
|
|
|
#endif
|
2007-04-11 21:18:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (iface->previous_routes)
|
|
|
|
free_route (iface->previous_routes);
|
|
|
|
|
|
|
|
iface->previous_routes = new_routes;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options->dodns && dhcp->dnsservers)
|
|
|
|
make_resolv(iface->name, dhcp);
|
|
|
|
else
|
|
|
|
logger (LOG_DEBUG, "no dns information to write");
|
2006-11-28 04:23:22 +08:00
|
|
|
|
2007-04-03 15:03:04 +08:00
|
|
|
#ifdef ENABLE_NTP
|
2007-04-11 21:18:33 +08:00
|
|
|
if (options->dontp && dhcp->ntpservers)
|
|
|
|
make_ntp(iface->name, dhcp);
|
2007-04-03 15:03:04 +08:00
|
|
|
#endif
|
2006-11-28 04:23:22 +08:00
|
|
|
|
2007-04-03 15:03:04 +08:00
|
|
|
#ifdef ENABLE_NIS
|
2007-04-11 21:18:33 +08:00
|
|
|
if (options->donis && (dhcp->nisservers || dhcp->nisdomain))
|
|
|
|
make_nis(iface->name, dhcp);
|
2007-04-03 15:03:04 +08:00
|
|
|
#endif
|
2006-11-28 04:23:22 +08:00
|
|
|
|
2007-04-27 00:16:56 +08:00
|
|
|
/* Now we have made a resolv.conf we can obtain a hostname if we need it */
|
2007-05-30 17:27:53 +08:00
|
|
|
if (options->dohostname && (! dhcp->hostname || options->dohostname > 3)) {
|
2007-04-18 18:16:51 +08:00
|
|
|
union {
|
|
|
|
struct sockaddr sa;
|
|
|
|
struct sockaddr_in sin;
|
|
|
|
} su;
|
|
|
|
socklen_t salen;
|
|
|
|
char addr[NI_MAXHOST];
|
|
|
|
struct addrinfo hints, *res;
|
2007-04-27 00:16:56 +08:00
|
|
|
int result;
|
2007-04-18 18:16:51 +08:00
|
|
|
|
|
|
|
salen = sizeof (struct sockaddr);
|
|
|
|
memset (&su.sa, 0, salen);
|
|
|
|
su.sin.sin_family = AF_INET;
|
|
|
|
memcpy (&su.sin.sin_addr, &dhcp->address, sizeof (struct in_addr));
|
|
|
|
|
2007-04-27 00:16:56 +08:00
|
|
|
logger (LOG_DEBUG, "Looking up hostname via DNS");
|
|
|
|
if ((result = getnameinfo (&su.sa, salen, addr, sizeof (addr),
|
|
|
|
NULL, 0, NI_NAMEREQD)) != 0)
|
|
|
|
logger (LOG_ERR, "Failed to lookup hostname via DNS: %s", gai_strerror (result));
|
|
|
|
else {
|
|
|
|
/* Check for a malicious PTR record */
|
2007-04-18 18:16:51 +08:00
|
|
|
memset (&hints, 0, sizeof (hints));
|
|
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
|
|
hints.ai_flags = AI_NUMERICHOST;
|
|
|
|
if (getaddrinfo (addr, "0", &hints, &res) == 0) {
|
|
|
|
freeaddrinfo (res);
|
|
|
|
addr[0] = '\0';
|
2007-04-18 20:03:23 +08:00
|
|
|
logger (LOG_ERR, "malicious PTR record detected");
|
2007-05-28 20:15:27 +08:00
|
|
|
} else if (*addr) {
|
2007-05-30 17:27:53 +08:00
|
|
|
char *p = strchr (addr, '.');
|
|
|
|
if (p) {
|
|
|
|
switch (options->dohostname) {
|
|
|
|
case 1: /* -H */
|
|
|
|
case 4: /* -HHHH */
|
|
|
|
break;
|
|
|
|
case 2: /* -HH */
|
|
|
|
case 5: /* -HHHHH */
|
|
|
|
/* Strip out the domain if it matches */
|
|
|
|
p++;
|
|
|
|
if (*p && dhcp->dnssearch) {
|
|
|
|
char *s = xstrdup (dhcp->dnssearch);
|
|
|
|
char *sp = s;
|
|
|
|
char *t;
|
|
|
|
|
|
|
|
while ((t = strsep (&sp, " ")))
|
|
|
|
if (strcmp (t, p) == 0) {
|
|
|
|
*--p = '\0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
free (s);
|
|
|
|
} else if (dhcp->dnsdomain) {
|
|
|
|
if (strcmp (dhcp->dnsdomain, p) == 0)
|
2007-05-28 20:15:27 +08:00
|
|
|
*--p = '\0';
|
2007-05-30 17:27:53 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3: /* -HHH */
|
|
|
|
case 6: /* -HHHHHH */
|
|
|
|
/* Just strip the domain */
|
|
|
|
*p = '\0';
|
|
|
|
break;
|
|
|
|
default: /* Too many H! */
|
|
|
|
break;
|
2007-05-28 20:15:27 +08:00
|
|
|
}
|
|
|
|
}
|
2007-05-23 22:48:02 +08:00
|
|
|
strlcpy (newhostname, addr, sizeof (newhostname));
|
2007-05-28 20:15:27 +08:00
|
|
|
}
|
2007-04-11 21:18:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gethostname (curhostname, sizeof (curhostname));
|
|
|
|
|
|
|
|
if (options->dohostname
|
|
|
|
|| strlen (curhostname) == 0
|
|
|
|
|| strcmp (curhostname, "(none)") == 0
|
|
|
|
|| strcmp (curhostname, "localhost") == 0)
|
|
|
|
{
|
|
|
|
if (dhcp->hostname)
|
|
|
|
strlcpy (newhostname, dhcp->hostname, sizeof (newhostname));
|
|
|
|
|
|
|
|
if (*newhostname) {
|
|
|
|
logger (LOG_INFO, "setting hostname to `%s'", newhostname);
|
|
|
|
sethostname (newhostname, strlen (newhostname));
|
|
|
|
}
|
|
|
|
}
|
2006-11-28 04:23:22 +08:00
|
|
|
|
2007-04-03 15:03:04 +08:00
|
|
|
#ifdef ENABLE_INFO
|
2007-05-10 17:39:26 +08:00
|
|
|
if (! dhcp->frominfo)
|
2007-05-14 18:01:56 +08:00
|
|
|
write_info (iface, dhcp, options, true);
|
2007-04-03 15:03:04 +08:00
|
|
|
#endif
|
2006-11-28 04:23:22 +08:00
|
|
|
|
2007-04-11 21:18:33 +08:00
|
|
|
if (iface->previous_address.s_addr != dhcp->address.s_addr ||
|
|
|
|
iface->previous_netmask.s_addr != dhcp->netmask.s_addr)
|
|
|
|
{
|
|
|
|
memcpy (&iface->previous_address,
|
|
|
|
&dhcp->address, sizeof (struct in_addr));
|
|
|
|
memcpy (&iface->previous_netmask,
|
|
|
|
&dhcp->netmask, sizeof (struct in_addr));
|
|
|
|
exec_script (options->script, iface->infofile, "new");
|
|
|
|
} else
|
|
|
|
exec_script (options->script, iface->infofile, "up");
|
|
|
|
|
2007-05-14 18:01:56 +08:00
|
|
|
return (0);
|
2006-11-28 04:23:22 +08:00
|
|
|
}
|
|
|
|
|