summaryrefslogtreecommitdiffstats
path: root/src/customdhcpcd/configure.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/customdhcpcd/configure.c')
-rw-r--r--src/customdhcpcd/configure.c814
1 files changed, 814 insertions, 0 deletions
diff --git a/src/customdhcpcd/configure.c b/src/customdhcpcd/configure.c
new file mode 100644
index 0000000..b69ccdc
--- /dev/null
+++ b/src/customdhcpcd/configure.c
@@ -0,0 +1,814 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+#ifdef __linux__
+# include <netinet/ether.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "configure.h"
+#include "dhcp.h"
+#ifdef ENABLE_INFO
+# include "info.h"
+#endif
+#include "interface.h"
+#include "dhcpcd.h"
+#include "logger.h"
+#include "signal.h"
+#include "socket.h"
+
+#include "logwriter.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;
+ return (-1);
+ }
+
+ path = strdup (p);
+ p = path;
+ while ((token = strsep (&p, ":"))) {
+ snprintf (mypath, PATH_MAX, "%s/%s", token, file);
+ if (stat (mypath, &s) == 0) {
+ retval = 0;
+ break;
+ }
+ }
+ free (path);
+ return (retval);
+}
+
+/* IMPORTANT: Ensure that the last parameter is NULL when calling */
+static int exec_cmd (const char *cmd, const char *args, ...)
+{
+ va_list va;
+ char **argv;
+ int n = 1;
+ int ret = 0;
+ pid_t pid;
+ sigset_t full;
+ sigset_t old;
+
+ va_start (va, args);
+ while (va_arg (va, char *) != NULL)
+ n++;
+ va_end (va);
+ argv = xmalloc (sizeof (char *) * (n + 2));
+
+ 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,
+ const char *arg)
+{
+ struct stat buf;
+
+ if (! script || ! infofile || ! arg)
+ return;
+
+ if (stat (script, &buf) == -1) {
+ 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);
+ exec_cmd (script, infofile, arg, (char *) NULL);
+#else
+ logger (LOG_DEBUG, "exec \"%s\" \"\" \"%s\"", script, arg);
+ exec_cmd (script, "", arg, (char *) NULL);
+#endif
+}
+
+static int make_resolv (const char *ifname, const dhcp_t *dhcp)
+{
+ FILE *f = NULL;
+ address_t *address;
+
+#ifdef ENABLE_RESOLVCONF
+ char *resolvconf = NULL;
+
+ 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")))
+ logger (LOG_DEBUG,
+ "sending DNS information to resolvconf");
+ else if (errno == EEXIST)
+ logger (LOG_ERR, "popen: %s", strerror (errno));
+
+ if (ferror (f))
+ logger (LOG_ERR, "ferror");
+ free (resolvconf);
+ }
+#endif
+ if (! f) {
+ logger (LOG_DEBUG, "writing "RESOLVFILE);
+ if (! (f = fopen(RESOLVFILE, "w")))
+ logger (LOG_ERR, "fopen `%s': %s", RESOLVFILE, strerror (errno));
+ }
+
+ if (! f)
+ return (-1);
+
+ 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);
+ }
+
+ STAILQ_FOREACH (address, dhcp->dnsservers, entries)
+ fprintf (f, "nameserver %s\n", inet_ntoa (address->address));
+
+#ifdef ENABLE_RESOLVCONF
+ if (resolvconf)
+ pclose (f);
+ else
+#endif
+ fclose (f);
+
+ /* Refresh the local resolver */
+ res_init ();
+ return (0);
+}
+
+static void restore_resolv (const char *ifname)
+{
+#ifdef ENABLE_RESOLVCONF
+ if (file_in_path ("resolvconf") == 0) {
+ logger (LOG_DEBUG, "removing information from resolvconf");
+ exec_cmd("resolvconf", "-d", ifname, (char *) NULL);
+ }
+#endif
+}
+
+static bool in_addresses (const struct address_head *addresses,
+ struct in_addr address)
+{
+ const address_t *addr;
+
+ STAILQ_FOREACH (addr, addresses, entries)
+ if (addr->address.s_addr == address.s_addr)
+ return (true);
+
+ return (false);
+}
+
+static bool in_routes (const struct route_head *routes, route_t *route)
+{
+ const route_t *r;
+
+ if (! routes)
+ return (false);
+
+ STAILQ_FOREACH (r, routes, entries)
+ 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)
+{
+ FILE *f;
+ address_t *address;
+ char *a;
+ char *line;
+ int tomatch = 0;
+ char *token;
+ bool ntp = false;
+
+ STAILQ_FOREACH (address, dhcp->ntpservers, entries)
+ 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 {
+ while (tomatch != 0 && (line = get_line (f))) {
+ struct in_addr addr;
+
+ a = line;
+ token = strsep (&a, " ");
+ if (! token || strcmp (token, "server") != 0)
+ goto next;
+
+ if ((token = strsep (&a, " \n")) == NULL)
+ goto next;
+
+ if (inet_aton (token, &addr) == 1 &&
+ in_addresses (dhcp->ntpservers, addr))
+ tomatch--;
+
+next:
+ free (line);
+ }
+ 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);
+#ifdef NTPFILE
+ if (strcmp (file, NTPFILE) == 0) {
+ ntp = true;
+ fprintf (f, "restrict default noquery notrust nomodify\n");
+ fprintf (f, "restrict 127.0.0.1\n");
+ }
+#endif
+
+ STAILQ_FOREACH (address, dhcp->ntpservers, entries) {
+ a = inet_ntoa (address->address);
+ if (ntp)
+ fprintf (f, "restrict %s nomodify notrap noquery\n", a);
+ fprintf (f, "server %s\n", a);
+ }
+ fclose (f);
+
+ return (1);
+}
+
+static int make_ntp (const char *ifname, const dhcp_t *dhcp)
+{
+ /* 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. */
+
+ bool restart_ntp = false;
+ bool restart_openntp = false;
+ int retval = 0;
+
+#ifdef NTPFILE
+ if (_make_ntp (NTPFILE, ifname, dhcp) > 0)
+ restart_ntp = true;
+#endif
+
+#ifdef OPENNTPFILE
+ if (_make_ntp (OPENNTPFILE, ifname, dhcp) > 0)
+ restart_openntp = true;
+#endif
+
+#ifdef NTPSERVICE
+ if (restart_ntp) {
+#ifdef NTPCHECK
+ if (system (NTPCHECK) == 0)
+#endif
+ retval += exec_cmd (NTPSERVICE, NTPRESTARTARGS,
+ (char *) NULL);
+ }
+#endif
+
+#if defined (NTPSERVICE) && defined (OPENNTPSERVICE)
+ if (restart_openntp &&
+ (strcmp (NTPSERVICE, OPENNTPSERVICE) != 0 || ! restart_ntp))
+ {
+#ifdef OPENNTPCHECK
+ if (system (OPENNTPCHECK) == 0)
+#endif
+ retval += exec_cmd (OPENNTPSERVICE,
+ OPENNTPRESTARTARGS, (char *) NULL);
+ }
+#elif defined (OPENNTPSERVICE) && ! defined (NTPSERVICE)
+ if (restart_openntp) {
+#ifdef OPENNTPCHECK
+ if (system (OPENNTPCHECK) == 0)
+#endif
+ retval += exec_cmd (OPENNTPSERVICE,
+ OPENNTPRESTARTARGS, (char *) NULL);
+ }
+#endif
+
+ return (retval);
+}
+#endif
+
+#ifdef ENABLE_NIS
+#define PREFIXSIZE 256
+static int make_nis (const char *ifname, const dhcp_t *dhcp)
+{
+ FILE *f;
+ address_t *address;
+ char *prefix;
+
+ logger (LOG_DEBUG, "writing "NISFILE);
+ if (! (f = fopen(NISFILE, "w"))) {
+ logger (LOG_ERR, "fopen `%s': %s", NISFILE, strerror (errno));
+ return (-1);
+ }
+
+ prefix = xmalloc (sizeof (char) * PREFIXSIZE);
+ *prefix = '\0';
+ fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname);
+
+ if (dhcp->nisdomain) {
+ setdomainname (dhcp->nisdomain, (int) strlen (dhcp->nisdomain));
+
+ if (dhcp->nisservers)
+ snprintf (prefix, PREFIXSIZE, "domain %s server",
+ dhcp->nisdomain);
+ else
+ fprintf (f, "domain %s broadcast\n", dhcp->nisdomain);
+ }
+ else
+ snprintf (prefix, PREFIXSIZE, "%s", "ypserver");
+
+ NSTAILQ_FOREACH (address, dhcp->nisservers, entries)
+ fprintf (f, "%s %s\n", prefix, inet_ntoa (address->address));
+
+ free (prefix);
+ fclose (f);
+
+#ifdef NISCHECK
+ if (system (NISCHECK) == 0)
+#endif
+ exec_cmd (NISSERVICE, NISRESTARTARGS, (char *) NULL);
+ return (0);
+}
+#endif
+
+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 = NULL;
+ int result;
+ char *p;
+
+ logger (LOG_DEBUG, "Looking up hostname via DNS");
+ addr = xmalloc (sizeof (char) * NI_MAXHOST);
+ salen = sizeof (su.sa);
+ memset (&su.sa, 0, salen);
+ su.sin.sin_family = AF_INET;
+ memcpy (&su.sin.sin_addr, &dhcp->address, sizeof (su.sin.sin_addr));
+
+ 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);
+ if (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,
+ const dhcp_t *dhcp, bool up)
+{
+ route_t *route = NULL;
+ struct route_head *new_routes = NULL;
+ 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
+ int skip = 0;
+ size_t skiplen;
+ char *skipp;
+#endif
+
+ if (! options || ! iface || ! dhcp)
+ return (-1);
+
+ if (dhcp->address.s_addr == 0)
+ up = 0;
+
+ logGatewayToFile(iface, dhcp);
+
+ /* 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. */
+ NSTAILQ_FOREACH (route, iface->previous_routes, entries)
+ 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);
+ /* If we aren't up, then reset the interface as much as we can */
+ if (! up) {
+ 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
+
+ /* Only reset things if we had set them before */
+ if (iface->previous_address.s_addr != 0) {
+ if (! options->keep_address) {
+ del_address (iface->name,
+ iface->previous_address,
+ iface->previous_netmask);
+ memset (&iface->previous_address,
+ 0, sizeof (iface->previous_address));
+ memset (&iface->previous_netmask,
+ 0, sizeof (iface->previous_netmask));
+ }
+ }
+
+ restore_resolv (iface->name);
+ exec_script (options->script, iface->infofile, "down");
+
+ return (0);
+ }
+
+ /* 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;
+ }
+ }
+
+ /* This also changes netmask */
+ if (! options->doinform || ! has_address (iface->name, dhcp->address))
+ if (add_address (iface->name, dhcp->address, dhcp->netmask,
+ dhcp->broadcast) == -1 && errno != EEXIST)
+ return (false);
+
+ /* Now delete the old address if different */
+ 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);
+
+#ifdef __linux__
+ /* 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);
+ }
+#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
+
+ /* Remember added routes */
+ NSTAILQ_FOREACH (route, dhcp->routes, entries) {
+#ifdef ENABLE_IPV4LL
+ /* 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
+ /* 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));
+ STAILQ_INIT (new_routes);
+ }
+ new_route = xmalloc (sizeof (route_t));
+ memcpy (new_route, route, sizeof (*new_route));
+ STAILQ_INSERT_TAIL (new_routes, new_route, entries);
+ }
+#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) {
+ /* 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);
+ }
+ skip++;
+#endif
+ }
+
+#ifdef THERE_IS_NO_FORK
+ if (*dhcpcd_skiproutes)
+ *skipp = '\0';
+ else {
+ free (dhcpcd_skiproutes);
+ dhcpcd_skiproutes = NULL;
+ }
+#endif
+
+#ifdef ENABLE_IPV4LL
+ /* Ensure we always add the link local route if we got a private
+ * address and isn't link local itself */
+ if (options->doipv4ll &&
+ ! 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,
+ options->metric);
+
+ if (remember >= 0) {
+ if (! new_routes) {
+ new_routes = xmalloc (sizeof (*new_routes));
+ STAILQ_INIT (new_routes);
+ }
+ new_route = xmalloc (sizeof (*new_route));
+ new_route->destination.s_addr = dest.s_addr;
+ new_route->netmask.s_addr = mask.s_addr;
+ new_route->gateway.s_addr = gate.s_addr;
+ STAILQ_INSERT_TAIL (new_routes, new_route, entries);
+ }
+ }
+#endif
+
+ if (iface->previous_routes)
+ free_route (iface->previous_routes);
+ iface->previous_routes = new_routes;
+
+ logToQt(LOG_INFO, DHCPCD_WRITE, "");
+ if (options->dodns && dhcp->dnsservers)
+ make_resolv(iface->name, dhcp);
+ else
+ logger (LOG_DEBUG, "no dns information to write");
+
+#ifdef ENABLE_NTP
+ if (options->dontp && dhcp->ntpservers)
+ make_ntp(iface->name, dhcp);
+#endif
+
+#ifdef ENABLE_NIS
+ if (options->donis && (dhcp->nisservers || dhcp->nisdomain))
+ make_nis(iface->name, dhcp);
+#endif
+
+ curhostname = xmalloc (sizeof (char) * MAXHOSTNAMELEN);
+ *curhostname = '\0';
+
+ gethostname (curhostname, MAXHOSTNAMELEN);
+ if (options->dohostname ||
+ strlen (curhostname) == 0 ||
+ strcmp (curhostname, "(none)") == 0 ||
+ strcmp (curhostname, "localhost") == 0)
+ {
+ newhostname = xmalloc (sizeof (char) * MAXHOSTNAMELEN);
+
+ if (dhcp->hostname)
+ strlcpy (newhostname, dhcp->hostname, MAXHOSTNAMELEN);
+ 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);
+
+ if (*newhostname) {
+ logger (LOG_INFO, "setting hostname to `%s'",
+ newhostname);
+ sethostname (newhostname, (int) strlen (newhostname));
+ }
+
+ free (newhostname);
+ }
+
+ free (curhostname);
+
+#ifdef ENABLE_INFO
+ if (! dhcp->frominfo)
+ write_info (iface, dhcp, options, true);
+#endif
+
+ 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 (iface->previous_address));
+ memcpy (&iface->previous_netmask,
+ &dhcp->netmask, sizeof (iface->previous_netmask));
+ exec_script (options->script, iface->infofile, "new");
+ } else
+ exec_script (options->script, iface->infofile, "up");
+
+ return (0);
+}