dhcpcd/configure.c

810 lines
20 KiB
C
Raw Normal View History

/*
* dhcpcd - DHCP client daemon
2008-01-08 17:51:23 +08:00
* Copyright 2006-2008 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
2006-11-28 04:23:22 +08:00
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/param.h>
2006-11-28 04:23:22 +08:00
#include <sys/socket.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <netinet/in.h>
2006-11-28 04:23:22 +08:00
#ifdef __linux__
# 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>
#include <signal.h>
#include <stdarg.h>
2006-11-28 04:23:22 +08:00
#include <stdlib.h>
#include <unistd.h>
#include "config.h"
2006-11-28 04:23:22 +08:00
#include "common.h"
#include "configure.h"
2006-11-28 04:23:22 +08:00
#include "dhcp.h"
#ifdef ENABLE_INFO
# include "info.h"
#endif
2006-11-28 04:23:22 +08:00
#include "interface.h"
#include "dhcpcd.h"
#include "logger.h"
#include "signal.h"
#include "socket.h"
static int file_in_path (const char *file)
{
char *p = getenv ("PATH");
char *path;
char *token;
struct stat s;
char mypath[PATH_MAX];
int retval = -1;
if (! p) {
errno = ENOENT;
2008-01-17 00:38:47 +08:00
return (-1);
}
path = strdup (p);
p = path;
while ((token = strsep (&p, ":"))) {
snprintf (mypath, PATH_MAX, "%s/%s", token, file);
2007-11-16 21:08:00 +08:00
if (stat (mypath, &s) == 0) {
retval = 0;
break;
}
}
free (path);
2008-01-17 00:38:47 +08:00
return (retval);
}
/* 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;
char **argv;
int n = 1;
int ret;
pid_t pid;
sigset_t full;
sigset_t old;
2007-04-11 21:18:33 +08:00
va_start (va, args);
while (va_arg (va, char *) != NULL)
n++;
va_end (va);
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);
/* OK, we need to block signals */
sigfillset (&full);
sigprocmask (SIG_SETMASK, &full, &old);
#ifdef THERE_IS_NO_FORK
signal_reset ();
pid = vfork ();
#else
pid = fork();
#endif
switch (pid) {
case -1:
logger (LOG_ERR, "vfork: %s", strerror (errno));
ret = -1;
break;
case 0:
#ifndef THERE_IS_NO_FORK
signal_reset ();
#endif
sigprocmask (SIG_SETMASK, &old, NULL);
if (execvp (cmd, argv) && errno != ENOENT)
logger (LOG_ERR, "error executing \"%s\": %s",
cmd, strerror (errno));
_exit (111);
/* NOTREACHED */
}
#ifdef THERE_IS_NO_FORK
signal_setup ();
#endif
/* Restore our signals */
sigprocmask (SIG_SETMASK, &old, NULL);
free (argv);
return (ret);
}
static void exec_script (const char *script, const char *infofile,
2008-01-17 00:38:47 +08:00
const char *arg)
2006-11-28 04:23:22 +08:00
{
2007-04-11 21:18:33 +08:00
struct stat buf;
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;
}
#ifdef ENABLE_INFO
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);
#else
logger (LOG_DEBUG, "exec \"%s\" \"\" \"%s\"", script, arg);
exec_cmd (script, "", arg, (char *) NULL);
#endif
2006-11-28 04:23:22 +08:00
}
static int make_resolv (const char *ifname, const dhcp_t *dhcp)
2006-11-28 04:23:22 +08:00
{
FILE *f = NULL;
2007-04-11 21:18:33 +08:00
address_t *address;
2006-11-28 04:23:22 +08:00
#ifdef ENABLE_RESOLVCONF
char *resolvconf = NULL;
2007-04-11 21:18:33 +08:00
if (file_in_path ("resolvconf") == 0) {
size_t len = strlen ("resolvconf -a ") + strlen (ifname) + 1;
resolvconf = xmalloc (sizeof (char) * len);
snprintf (resolvconf, len, "resolvconf -a %s", ifname);
if ((f = popen (resolvconf , "w")))
2008-01-17 00:38:47 +08:00
logger (LOG_DEBUG,
"sending DNS information to resolvconf");
else if (errno == EEXIST)
2007-04-11 21:18:33 +08:00
logger (LOG_ERR, "popen: %s", strerror (errno));
if (ferror (f))
logger (LOG_ERR, "ferror");
free (resolvconf);
}
#endif
if (! f) {
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));
}
if (! f)
return (-1);
2007-04-11 21:18:33 +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
for (address = dhcp->dnsservers; address; address = address->next)
fprintf (f, "nameserver %s\n", inet_ntoa (address->address));
#ifdef ENABLE_RESOLVCONF
if (resolvconf)
pclose (f);
else
#endif
fclose (f);
2007-04-11 21:18:33 +08:00
/* Refresh the local resolver */
res_init ();
return (0);
2006-11-28 04:23:22 +08:00
}
static void restore_resolv (const char *ifname)
2006-11-28 04:23:22 +08:00
{
#ifdef ENABLE_RESOLVCONF
if (file_in_path ("resolvconf") == 0) {
logger (LOG_DEBUG, "removing information from resolvconf");
exec_cmd("resolvconf", "-d", ifname, (char *) NULL);
}
#endif
2006-11-28 04:23:22 +08:00
}
2008-01-17 00:38:47 +08:00
static bool in_addresses (const address_t *addresses, struct in_addr addr)
{
const address_t *address;
for (address = addresses; address; address = address->next)
if (address->address.s_addr == addr.s_addr)
return (true);
return (false);
}
static bool in_routes (const route_t *routes, route_t *route)
{
const route_t *r;
for (r = routes; r; r=r->next)
if (r->destination.s_addr == route->destination.s_addr &&
r->netmask.s_addr == route->netmask.s_addr &&
r->gateway.s_addr == route->gateway.s_addr)
return (true);
return (false);
}
#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 *line;
2007-04-11 21:18:33 +08:00
int tomatch = 0;
char *token;
bool ntp = false;
for (address = dhcp->ntpservers; address; address = address->next)
tomatch++;
2008-01-29 19:20:55 +08:00
/* Check that we really need to update the servers.
* We do this because ntp has to be restarted to
* work with a changed config. */
2007-04-11 21:18:33 +08:00
if (! (f = fopen (file, "r"))) {
if (errno != ENOENT) {
2008-01-17 00:38:47 +08:00
logger (LOG_ERR, "fopen `%s': %s",
file, strerror (errno));
return (-1);
2007-04-11 21:18:33 +08:00
}
} else {
while (tomatch != 0 && (line = get_line (f))) {
2008-01-17 00:38:47 +08:00
struct in_addr addr;
2008-01-21 23:10:46 +08:00
a = line;
2007-04-11 21:18:33 +08:00
token = strsep (&a, " ");
2008-01-17 00:38:47 +08:00
if (! token || strcmp (token, "server") != 0)
goto next;
2007-04-11 21:18:33 +08:00
2008-01-17 00:38:47 +08:00
if ((token = strsep (&a, " \n")) == NULL)
goto next;
2007-04-11 21:18:33 +08:00
2008-01-21 23:10:46 +08:00
if (inet_aton (token, &addr) == 1 &&
2008-01-17 00:38:47 +08:00
in_addresses (dhcp->ntpservers, addr))
tomatch--;
2007-04-11 21:18:33 +08:00
2008-01-17 00:38:47 +08:00
next:
free (line);
2007-04-11 21:18:33 +08:00
}
fclose (f);
2008-01-17 00:38:47 +08:00
/* File has the same name servers that we do,
* so no need to restart ntp */
2007-04-11 21:18:33 +08:00
if (tomatch == 0) {
2008-01-17 00:38:47 +08:00
logger (LOG_DEBUG, "%s already configured, skipping",
file);
return (0);
2007-04-11 21:18:33 +08:00
}
}
logger (LOG_DEBUG, "writing %s", file);
if (! (f = fopen (file, "w"))) {
logger (LOG_ERR, "fopen `%s': %s", file, strerror (errno));
2008-01-17 00:38:47 +08:00
return (-1);
2007-04-11 21:18:33 +08:00
}
fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname);
#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");
}
#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);
}
fclose (f);
2008-01-17 00:38:47 +08:00
return (1);
}
static int make_ntp (const char *ifname, const dhcp_t *dhcp)
{
2008-01-29 19:20:55 +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-11 21:18:33 +08:00
bool restart_ntp = false;
bool restart_openntp = false;
int retval = 0;
#ifdef NTPFILE
2007-04-11 21:18:33 +08:00
if (_make_ntp (NTPFILE, ifname, dhcp) > 0)
restart_ntp = true;
#endif
#ifdef OPENNTPFILE
2007-04-11 21:18:33 +08:00
if (_make_ntp (OPENNTPFILE, ifname, dhcp) > 0)
restart_openntp = true;
#endif
#ifdef NTPSERVICE
if (restart_ntp) {
#ifdef NTPCHECK
if (system (NTPCHECK) == 0)
#endif
2008-01-17 00:38:47 +08:00
retval += exec_cmd (NTPSERVICE, NTPRESTARTARGS,
(char *) NULL);
}
#endif
#if defined (NTPSERVICE) && defined (OPENNTPSERVICE)
2007-04-11 21:18:33 +08:00
if (restart_openntp &&
2008-01-17 00:38:47 +08:00
(strcmp (NTPSERVICE, OPENNTPSERVICE) != 0 || ! restart_ntp))
{
#ifdef OPENNTPCHECK
if (system (OPENNTPCHECK) == 0)
#endif
2008-01-17 00:38:47 +08:00
retval += exec_cmd (OPENNTPSERVICE,
OPENNTPRESTARTARGS, (char *) NULL);
}
#elif defined (OPENNTPSERVICE) && ! defined (NTPSERVICE)
if (restart_openntp) {
#ifdef OPENNTPCHECK
if (system (OPENNTPCHECK) == 0)
#endif
2008-01-17 00:38:47 +08:00
retval += exec_cmd (OPENNTPSERVICE,
OPENNTPRESTARTARGS, (char *) NULL);
}
#endif
2008-01-17 00:38:47 +08:00
return (retval);
2006-11-28 04:23:22 +08:00
}
#endif
2006-11-28 04:23:22 +08:00
#ifdef ENABLE_NIS
#define PREFIXSIZE 256
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;
2007-04-11 21:18:33 +08:00
logger (LOG_DEBUG, "writing "NISFILE);
if (! (f = fopen(NISFILE, "w"))) {
logger (LOG_ERR, "fopen `%s': %s", NISFILE, strerror (errno));
2008-01-17 00:38:47 +08:00
return (-1);
2007-04-11 21:18:33 +08:00
}
prefix = xmalloc (sizeof (char) * PREFIXSIZE);
*prefix = '\0';
2007-04-11 21:18:33 +08:00
fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname);
2007-04-11 21:18:33 +08:00
if (dhcp->nisdomain) {
2008-01-22 05:19:53 +08:00
setdomainname (dhcp->nisdomain, (int) strlen (dhcp->nisdomain));
2007-04-11 21:18:33 +08:00
if (dhcp->nisservers)
2008-01-17 00:38:47 +08:00
snprintf (prefix, PREFIXSIZE, "domain %s server",
dhcp->nisdomain);
2007-04-11 21:18:33 +08:00
else
fprintf (f, "domain %s broadcast\n", dhcp->nisdomain);
}
else
snprintf (prefix, PREFIXSIZE, "%s", "ypserver");
2007-04-11 21:18:33 +08:00
for (address = dhcp->nisservers; address; address = address->next)
fprintf (f, "%s %s\n", prefix, inet_ntoa (address->address));
free (prefix);
2007-04-11 21:18:33 +08:00
fclose (f);
#ifdef NISCHECK
if (system (NISCHECK) == 0)
#endif
exec_cmd (NISSERVICE, NISRESTARTARGS, (char *) NULL);
2008-01-17 00:38:47 +08:00
return (0);
2006-11-28 04:23:22 +08:00
}
#endif
2008-01-17 00:38:47 +08:00
static char *lookuphostname (char *hostname, const dhcp_t *dhcp,
const options_t *options)
{
union {
struct sockaddr sa;
struct sockaddr_in sin;
} su;
socklen_t salen;
char *addr;
struct addrinfo hints;
struct addrinfo *res;
int result;
char *p;
logger (LOG_DEBUG, "Looking up hostname via DNS");
addr = xmalloc (sizeof (char) * NI_MAXHOST);
salen = sizeof (su.sa);
2008-01-17 00:38:47 +08:00
memset (&su.sa, 0, salen);
su.sin.sin_family = AF_INET;
memcpy (&su.sin.sin_addr, &dhcp->address, sizeof (su.sin.sin_addr));
2008-01-17 00:38:47 +08:00
if ((result = getnameinfo (&su.sa, salen, addr, NI_MAXHOST,
NULL, 0, NI_NAMEREQD)) != 0) {
logger (LOG_ERR,
"Failed to lookup hostname via DNS: %s",
gai_strerror (result));
free (addr);
return (NULL);
}
/* Check for a malicious PTR record */
memset (&hints, 0, sizeof (hints));
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_NUMERICHOST;
result = getaddrinfo (addr, "0", &hints, &res);
freeaddrinfo (res);
if (result == 0)
logger (LOG_ERR, "malicious PTR record detected");
if (result == 0 || ! *addr) {
free (addr);
return (NULL);
}
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)
*--p = '\0';
}
break;
case 3: /* -HHH */
case 6: /* -HHHHHH */
/* Just strip the domain */
*p = '\0';
break;
default: /* Too many H! */
break;
}
}
strlcpy (hostname, addr, MAXHOSTNAMELEN);
free (addr);
return (hostname);
}
int configure (const options_t *options, interface_t *iface,
2008-01-17 00:38:47 +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_routes = NULL;
2007-04-11 21:18:33 +08:00
route_t *new_route = NULL;
char *newhostname = NULL;
char *curhostname = NULL;
int remember;
#ifdef ENABLE_IPV4LL
bool haslinklocal = false;
#endif
#ifdef THERE_IS_NO_FORK
2008-01-17 00:38:47 +08:00
int skip = 0;
size_t skiplen;
char *skipp;
#endif
2007-04-11 21:18:33 +08:00
if (! options || ! iface || ! dhcp)
return (-1);
if (dhcp->address.s_addr == 0)
up = 0;
2007-04-11 21:18:33 +08:00
2008-01-29 19:20:55 +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. */
2008-01-17 00:38:47 +08:00
for (route = iface->previous_routes; route; route = route->next)
if ((route->destination.s_addr || options->dogateway) &&
(! up || ! in_routes (dhcp->routes, route)))
del_route (iface->name, route->destination,
route->netmask, route->gateway,
options->metric);
2007-04-11 21:18:33 +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;
}
#ifdef ENABLE_INFO
/* If we haven't created an info file, do so now */
if (! dhcp->frominfo)
write_info (iface, dhcp, options, false);
#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) {
if (! options->keep_address) {
2008-01-17 00:38:47 +08:00
del_address (iface->name,
iface->previous_address,
iface->previous_netmask);
memset (&iface->previous_address,
0, sizeof (iface->previous_address));
2008-01-17 00:38:47 +08:00
memset (&iface->previous_netmask,
0, sizeof (iface->previous_netmask));
}
}
2007-04-11 21:18:33 +08:00
restore_resolv (iface->name);
exec_script (options->script, iface->infofile, "down");
2007-04-11 21:18:33 +08:00
return (0);
2007-04-11 21:18:33 +08:00
}
/* Set the MTU requested.
2008-01-29 19:20:55 +08:00
* If the DHCP server no longer sends one OR it's invalid then
* we restore the original MTU */
2007-04-11 21:18:33 +08:00
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;
}
}
/* This also changes netmask */
if (! options->doinform || ! has_address (iface->name, dhcp->address))
if (add_address (iface->name, dhcp->address, dhcp->netmask,
2008-01-17 00:38:47 +08:00
dhcp->broadcast) == -1 && errno != EEXIST)
return (false);
2008-01-17 00:38:47 +08:00
2007-04-11 21:18:33 +08:00
/* Now delete the old address if different */
2008-01-17 00:38:47 +08:00
if (iface->previous_address.s_addr != dhcp->address.s_addr &&
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. */
2008-01-17 00:38:47 +08:00
if (iface->previous_address.s_addr != dhcp->address.s_addr &&
options->metric > 0 &&
dhcp->netmask.s_addr != INADDR_BROADCAST)
2007-04-11 21:18:33 +08:00
{
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
#ifdef THERE_IS_NO_FORK
free (dhcpcd_skiproutes);
/* We can never have more than 255 routes. So we need space
* for 255 3 digit numbers and commas */
skiplen = 255 * 4 + 1;
skipp = dhcpcd_skiproutes = xmalloc (sizeof (char) * skiplen);
*skipp = '\0';
#endif
2007-04-11 21:18:33 +08:00
/* Remember added routes */
2008-01-17 00:38:47 +08:00
for (route = dhcp->routes; route; route = route->next) {
#ifdef ENABLE_IPV4LL
2008-01-17 00:38:47 +08:00
/* Check if we have already got a link locale route dished
* out by the DHCP server */
if (route->destination.s_addr == htonl (LINKLOCAL_ADDR) &&
route->netmask.s_addr == htonl (LINKLOCAL_MASK))
haslinklocal = true;
#endif
2008-01-17 00:38:47 +08:00
/* 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 && in_routes (iface->previous_routes, route))
remember = 1;
if (remember >= 0) {
if (! new_routes) {
new_routes = xmalloc (sizeof (*new_routes));
2008-01-17 00:38:47 +08:00
new_route = new_routes;
} else {
new_route->next = xmalloc (sizeof (*new_route));
2008-01-17 00:38:47 +08:00
new_route = new_route->next;
2007-04-11 21:18:33 +08:00
}
memcpy (new_route, route, sizeof (*new_route));
2008-01-17 00:38:47 +08:00
new_route -> next = NULL;
}
#ifdef THERE_IS_NO_FORK
2008-01-17 00:38:47 +08:00
/* If we have daemonised yet we need to record which routes
* we failed to add so we can skip them */
else if (! options->daemonised) {
/* We can never have more than 255 / 4 routes,
* so 3 chars is plently */
if (*skipp)
*skipp++ = ',';
skipp += snprintf (skipp,
dhcpcd_skiproutes + skiplen - skipp,
"%d", skip);
2007-04-11 21:18:33 +08:00
}
2008-01-17 00:38:47 +08:00
skip++;
#endif
}
2007-04-11 21:18:33 +08:00
#ifdef THERE_IS_NO_FORK
if (*dhcpcd_skiproutes)
*skipp = '\0';
else {
free (dhcpcd_skiproutes);
dhcpcd_skiproutes = NULL;
}
#endif
2007-04-11 21:18:33 +08:00
#ifdef ENABLE_IPV4LL
/* Ensure we always add the link local route if we got a private
* address and isn't link local itself */
2007-11-13 22:36:09 +08:00
if (options->doipv4ll &&
2008-01-17 00:38:47 +08:00
! haslinklocal &&
IN_PRIVATE (ntohl (dhcp->address.s_addr)))
{
struct in_addr dest;
struct in_addr mask;
struct in_addr gate;
dest.s_addr = htonl (LINKLOCAL_ADDR);
mask.s_addr = htonl (LINKLOCAL_MASK);
gate.s_addr = 0;
remember = add_route (iface->name, dest, mask, gate,
2008-01-17 00:38:47 +08:00
options->metric);
if (remember >= 0) {
if (! new_routes) {
new_routes = xmalloc (sizeof (*new_routes));
new_route = new_routes;
} else {
new_route->next = xmalloc (sizeof (*new_route));
new_route = new_route->next;
}
new_route->destination.s_addr = dest.s_addr;
new_route->netmask.s_addr = mask.s_addr;
new_route->gateway.s_addr = gate.s_addr;
new_route->next = NULL;
}
2007-04-11 21:18:33 +08:00
}
#endif
if (iface->previous_routes)
free_route (iface->previous_routes);
iface->previous_routes = new_routes;
2007-04-11 21:18:33 +08:00
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
#ifdef ENABLE_NTP
2007-04-11 21:18:33 +08:00
if (options->dontp && dhcp->ntpservers)
make_ntp(iface->name, dhcp);
#endif
2006-11-28 04:23:22 +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);
#endif
2006-11-28 04:23:22 +08:00
curhostname = xmalloc (sizeof (char) * MAXHOSTNAMELEN);
*curhostname = '\0';
2007-04-11 21:18:33 +08:00
gethostname (curhostname, MAXHOSTNAMELEN);
2008-01-17 00:38:47 +08:00
if (options->dohostname ||
strlen (curhostname) == 0 ||
strcmp (curhostname, "(none)") == 0 ||
strcmp (curhostname, "localhost") == 0)
2007-04-11 21:18:33 +08:00
{
2008-01-17 00:38:47 +08:00
newhostname = xmalloc (sizeof (char) * MAXHOSTNAMELEN);
2007-04-11 21:18:33 +08:00
if (dhcp->hostname)
strlcpy (newhostname, dhcp->hostname, MAXHOSTNAMELEN);
2008-01-17 00:38:47 +08:00
else
*newhostname = '\0';
/* Now we have made a resolv.conf we can obtain a hostname
* if we need it */
if (! *newhostname && options->dohostname > 3)
lookuphostname (newhostname, dhcp, options);
2007-04-11 21:18:33 +08:00
if (*newhostname) {
2008-01-17 00:38:47 +08:00
logger (LOG_INFO, "setting hostname to `%s'",
newhostname);
2008-01-22 05:19:53 +08:00
sethostname (newhostname, (int) strlen (newhostname));
2007-04-11 21:18:33 +08:00
}
2008-01-17 00:38:47 +08:00
free (newhostname);
2007-04-11 21:18:33 +08:00
}
2008-01-17 00:38:47 +08:00
free (curhostname);
2006-11-28 04:23:22 +08:00
#ifdef ENABLE_INFO
if (! dhcp->frominfo)
write_info (iface, dhcp, options, true);
#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 ||
2008-01-17 00:38:47 +08:00
iface->previous_netmask.s_addr != dhcp->netmask.s_addr)
2007-04-11 21:18:33 +08:00
{
memcpy (&iface->previous_address,
&dhcp->address, sizeof (iface->previous_address));
2007-04-11 21:18:33 +08:00
memcpy (&iface->previous_netmask,
&dhcp->netmask, sizeof (iface->previous_netmask));
2007-04-11 21:18:33 +08:00
exec_script (options->script, iface->infofile, "new");
} else
exec_script (options->script, iface->infofile, "up");
return (0);
2006-11-28 04:23:22 +08:00
}