summaryrefslogtreecommitdiffstats
path: root/src/customdhcpcd/info.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/customdhcpcd/info.c')
-rw-r--r--src/customdhcpcd/info.c472
1 files changed, 472 insertions, 0 deletions
diff --git a/src/customdhcpcd/info.c b/src/customdhcpcd/info.c
new file mode 100644
index 0000000..8369b43
--- /dev/null
+++ b/src/customdhcpcd/info.c
@@ -0,0 +1,472 @@
+/*
+ * 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/stat.h>
+
+#include <arpa/inet.h>
+
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "dhcp.h"
+#include "interface.h"
+#include "logger.h"
+#include "info.h"
+
+#ifdef ENABLE_INFO
+
+/* Create a malloced string of cstr, changing ' to '\''
+ * so the contents work in a shell */
+static char *cleanmetas (const char *cstr)
+{
+ const char *p = cstr;
+ char *new;
+ char *n;
+ size_t len;
+
+ if (cstr == NULL || (len = strlen (cstr)) == 0)
+ return (xstrdup (""));
+
+ n = new = xmalloc (sizeof (char) * len + 2);
+ do
+ if (*p == '\'') {
+ size_t pos = n - new;
+ len += 4;
+ new = xrealloc (new, sizeof (char) * len + 1);
+ n = new + pos;
+ *n++ = '\'';
+ *n++ = '\\';
+ *n++ = '\'';
+ *n++ = '\'';
+ } else
+ *n++ = *p;
+ while (*p++);
+
+ /* Terminate the sucker */
+ *n = '\0';
+
+ return (new);
+}
+
+
+static void print_addresses (FILE *f, const struct address_head *addresses)
+{
+ const address_t *addr;
+
+ STAILQ_FOREACH (addr, addresses, entries) {
+ fprintf (f, "%s", inet_ntoa (addr->address));
+ if (STAILQ_NEXT (addr, entries))
+ fprintf (f, " ");
+ }
+}
+
+static void print_clean (FILE *f, const char *name, const char *value)
+{
+ char *clean;
+
+ if (! value)
+ return;
+
+ clean = cleanmetas (value);
+ fprintf (f, "%s='%s'\n", name, clean);
+ free (clean);
+}
+
+bool write_info(const interface_t *iface, const dhcp_t *dhcp,
+ const options_t *options, bool overwrite)
+{
+ FILE *f;
+ route_t *route;
+ struct stat sb;
+
+ if (options->test)
+ f = stdout;
+ else {
+ if (! overwrite && stat (iface->infofile, &sb) == 0)
+ return (true);
+
+ logger (LOG_DEBUG, "writing %s", iface->infofile);
+ if ((f = fopen (iface->infofile, "w")) == NULL) {
+ logger (LOG_ERR, "fopen `%s': %s",
+ iface->infofile, strerror (errno));
+ return (false);
+ }
+ }
+
+ if (dhcp->address.s_addr) {
+ struct in_addr n;
+ n.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr;
+ fprintf (f, "IPADDR='%s'\n", inet_ntoa (dhcp->address));
+ fprintf (f, "NETMASK='%s'\n", inet_ntoa (dhcp->netmask));
+ fprintf (f, "NETWORK='%s'\n", inet_ntoa (n));
+ fprintf (f, "BROADCAST='%s'\n", inet_ntoa (dhcp->broadcast));
+ }
+ if (dhcp->mtu > 0)
+ fprintf (f, "MTU='%d'\n", dhcp->mtu);
+
+ if (dhcp->routes) {
+ bool doneone = false;
+ fprintf (f, "ROUTES='");
+ STAILQ_FOREACH (route, dhcp->routes, entries) {
+ if (route->destination.s_addr != 0) {
+ if (doneone)
+ fprintf (f, " ");
+ fprintf (f, "%s", inet_ntoa (route->destination));
+ fprintf (f, ",%s", inet_ntoa (route->netmask));
+ fprintf (f, ",%s", inet_ntoa (route->gateway));
+ doneone = true;
+ }
+ }
+ fprintf (f, "'\n");
+
+ doneone = false;
+ fprintf (f, "GATEWAYS='");
+ STAILQ_FOREACH (route, dhcp->routes, entries) {
+ if (route->destination.s_addr == 0) {
+ if (doneone)
+ fprintf (f, " ");
+ fprintf (f, "%s", inet_ntoa (route->gateway));
+ doneone = true;
+ }
+ }
+ fprintf (f, "'\n");
+ }
+
+ print_clean (f, "HOSTNAME", dhcp->hostname);
+ print_clean (f, "DNSDOMAIN", dhcp->dnsdomain);
+ print_clean (f, "DNSSEARCH", dhcp->dnssearch);
+
+ if (dhcp->dnsservers) {
+ fprintf (f, "DNSSERVERS='");
+ print_addresses (f, dhcp->dnsservers);
+ fprintf (f, "'\n");
+ }
+
+ if (dhcp->fqdn) {
+ fprintf (f, "FQDNFLAGS='%u'\n", dhcp->fqdn->flags);
+ fprintf (f, "FQDNRCODE1='%u'\n", dhcp->fqdn->r1);
+ fprintf (f, "FQDNRCODE2='%u'\n", dhcp->fqdn->r2);
+ print_clean (f, "FQDNHOSTNAME", dhcp->fqdn->name);
+ }
+
+ if (dhcp->ntpservers) {
+ fprintf (f, "NTPSERVERS='");
+ print_addresses (f, dhcp->ntpservers);
+ fprintf (f, "'\n");
+ }
+
+ print_clean (f, "NISDOMAIN", dhcp->nisdomain);
+ if (dhcp->nisservers) {
+ fprintf (f, "NISSERVERS='");
+ print_addresses (f, dhcp->nisservers);
+ fprintf (f, "'\n");
+ }
+
+ print_clean (f, "ROOTPATH", dhcp->rootpath);
+ print_clean (f, "SIPSERVERS", dhcp->sipservers);
+
+ if (dhcp->serveraddress.s_addr)
+ fprintf (f, "DHCPSID='%s'\n", inet_ntoa (dhcp->serveraddress));
+ if (dhcp->servername[0])
+ print_clean (f, "DHCPSNAME", dhcp->servername);
+
+ if (! options->doinform && dhcp->address.s_addr) {
+ if (! options->test)
+ fprintf (f, "LEASEDFROM='%u'\n", dhcp->leasedfrom);
+ fprintf (f, "LEASETIME='%u'\n", dhcp->leasetime);
+ fprintf (f, "RENEWALTIME='%u'\n", dhcp->renewaltime);
+ fprintf (f, "REBINDTIME='%u'\n", dhcp->rebindtime);
+ }
+ print_clean (f, "INTERFACE", iface->name);
+ print_clean (f, "CLASSID", options->classid);
+ if (iface->clientid_len > 0) {
+ fprintf (f, "CLIENTID='%s'\n",
+ hwaddr_ntoa (iface->clientid, iface->clientid_len));
+ }
+ fprintf (f, "DHCPCHADDR='%s'\n", hwaddr_ntoa (iface->hwaddr,
+ iface->hwlen));
+
+#ifdef ENABLE_INFO_COMPAT
+ /* Support the old .info settings if we need to */
+ fprintf (f, "\n# dhcpcd-1.x and 2.x compatible variables\n");
+ if (dhcp->dnsservers) {
+ address_t *addr;
+
+ fprintf (f, "DNS='");
+ STAILQ_FOREACH (addr, dhcp->dnsservers, entries) {
+ fprintf (f, "%s", inet_ntoa (addr->address));
+ if (STAILQ_NEXT (addr, entries))
+ fprintf (f, ",");
+ }
+ fprintf (f, "'\n");
+ }
+
+ if (dhcp->routes) {
+ bool doneone = false;
+ fprintf (f, "GATEWAY='");
+ STAILQ_FOREACH (route, dhcp->routes, entries) {
+ if (route->destination.s_addr == 0) {
+ if (doneone)
+ fprintf (f, ",");
+ fprintf (f, "%s", inet_ntoa (route->gateway));
+ doneone = true;
+ }
+ }
+ fprintf (f, "'\n");
+ }
+#endif
+
+ if (! options->test)
+ fclose (f);
+ return (true);
+}
+
+static bool parse_address (struct in_addr *addr,
+ const char *value, const char *var)
+{
+ if (inet_aton (value, addr) == 0) {
+ logger (LOG_ERR, "%s `%s': %s", var, value,
+ strerror (errno));
+ return (false);
+ }
+ return (true);
+}
+
+static bool parse_uint (unsigned int *i,
+ const char *value, const char *var)
+{
+ if (sscanf (value, "%u", i) != 1) {
+ logger (LOG_ERR, "%s `%s': not a valid number",
+ var, value);
+ return (false);
+ }
+ return (true);
+}
+
+static bool parse_ushort (unsigned short *s,
+ const char *value, const char *var)
+{
+ if (sscanf (value, "%hu", s) != 1) {
+ logger (LOG_ERR, "%s `%s': not a valid number",
+ var, value);
+ return (false);
+ }
+ return (true);
+}
+
+static struct address_head *parse_addresses (char *value, const char *var)
+{
+ char *token;
+ char *p = value;
+ struct address_head *head = NULL;
+
+ while ((token = strsep (&p, " "))) {
+ address_t *a = xzalloc (sizeof (*a));
+
+ if (inet_aton (token, &a->address) == 0) {
+ logger (LOG_ERR, "%s: invalid address `%s'", var, token);
+ free_address (head);
+ free (a);
+ return (NULL);
+ }
+
+ if (! head) {
+ head = xmalloc (sizeof (*head));
+ STAILQ_INIT (head);
+ }
+ STAILQ_INSERT_TAIL (head, a, entries);
+ }
+
+ return (head);
+}
+
+bool read_info (const interface_t *iface, dhcp_t *dhcp)
+{
+ FILE *fp;
+ char *line;
+ char *var;
+ char *value;
+ char *p;
+ struct stat sb;
+
+ if (stat (iface->infofile, &sb) != 0) {
+ logger (LOG_ERR, "lease information file `%s' does not exist",
+ iface->infofile);
+ return (false);
+ }
+
+ if (! (fp = fopen (iface->infofile, "r"))) {
+ logger (LOG_ERR, "fopen `%s': %s",
+ iface->infofile, strerror (errno));
+ return (false);
+ }
+
+ dhcp->frominfo = true;
+
+ while ((line = get_line (fp))) {
+ var = line;
+
+ /* Strip leading spaces/tabs */
+ while ((*var == ' ') || (*var == '\t'))
+ var++;
+
+ /* Trim trailing \n */
+ p = var + strlen (var) - 1;
+ if (*p == '\n')
+ *p = 0;
+
+ /* Skip comments */
+ if (*var == '#')
+ goto next;
+
+ /* If we don't have an equals sign then skip it */
+ if (! (p = strchr (var, '=')))
+ goto next;
+
+ /* Terminate the = so we have two strings */
+ *p = 0;
+
+ value = p + 1;
+ /* Strip leading and trailing quotes if present */
+ if (*value == '\'' || *value == '"')
+ value++;
+ p = value + strlen (value) - 1;
+ if (*p == '\'' || *p == '"')
+ *p = 0;
+
+ /* Don't process null vars or values */
+ if (! *var || ! *value)
+ goto next;
+
+ if (strcmp (var, "IPADDR") == 0)
+ parse_address (&dhcp->address, value, "IPADDR");
+ else if (strcmp (var, "NETMASK") == 0)
+ parse_address (&dhcp->netmask, value, "NETMASK");
+ else if (strcmp (var, "BROADCAST") == 0)
+ parse_address (&dhcp->broadcast, value, "BROADCAST");
+ else if (strcmp (var, "MTU") == 0)
+ parse_ushort (&dhcp->mtu, value, "MTU");
+ else if (strcmp (var, "ROUTES") == 0) {
+ p = value;
+ while ((value = strsep (&p, " "))) {
+ char *pp = value;
+ char *dest = strsep (&pp, ",");
+ char *net = strsep (&pp, ",");
+ char *gate = strsep (&pp, ",");
+ route_t *route;
+
+ if (! dest || ! net || ! gate) {
+ logger (LOG_ERR, "read_info ROUTES `%s,%s,%s': invalid route",
+ dest, net, gate);
+ goto next;
+ }
+
+ /* See if we can create a route */
+ route = xzalloc (sizeof (*route));
+ if (inet_aton (dest, &route->destination) == 0) {
+ logger (LOG_ERR, "read_info ROUTES `%s': not a valid destination address",
+ dest);
+ free (route);
+ goto next;
+ }
+ if (inet_aton (dest, &route->netmask) == 0) {
+ logger (LOG_ERR, "read_info ROUTES `%s': not a valid netmask address",
+ net);
+ free (route);
+ goto next;
+ }
+ if (inet_aton (dest, &route->gateway) == 0) {
+ logger (LOG_ERR, "read_info ROUTES `%s': not a valid gateway address",
+ gate);
+ free (route);
+ goto next;
+ }
+
+ /* OK, now add our route */
+ if (! dhcp->routes) {
+ dhcp->routes = xmalloc (sizeof (*dhcp->routes));
+ STAILQ_INIT (dhcp->routes);
+ }
+ STAILQ_INSERT_TAIL (dhcp->routes, route, entries);
+ }
+ } else if (strcmp (var, "GATEWAYS") == 0) {
+ p = value;
+ while ((value = strsep (&p, " "))) {
+ route_t *route = xzalloc (sizeof (*route));
+ if (parse_address (&route->gateway, value, "GATEWAYS")) {
+ if (! dhcp->routes) {
+ dhcp->routes = xmalloc (sizeof (*dhcp->routes));
+ STAILQ_INIT (dhcp->routes);
+ }
+ STAILQ_INSERT_TAIL (dhcp->routes, route, entries);
+ } else
+ free (route);
+ }
+ } else if (strcmp (var, "HOSTNAME") == 0)
+ dhcp->hostname = xstrdup (value);
+ else if (strcmp (var, "DNSDOMAIN") == 0)
+ dhcp->dnsdomain = xstrdup (value);
+ else if (strcmp (var, "DNSSEARCH") == 0)
+ dhcp->dnssearch = xstrdup (value);
+ else if (strcmp (var, "DNSSERVERS") == 0)
+ dhcp->dnsservers = parse_addresses (value, "DNSSERVERS");
+ else if (strcmp (var, "NTPSERVERS") == 0)
+ dhcp->ntpservers = parse_addresses (value, "NTPSERVERS");
+ else if (strcmp (var, "NISDOMAIN") == 0)
+ dhcp->nisdomain = xstrdup (value);
+ else if (strcmp (var, "NISSERVERS") == 0)
+ dhcp->nisservers = parse_addresses (value, "NISSERVERS");
+ else if (strcmp (var, "ROOTPATH") == 0)
+ dhcp->rootpath = xstrdup (value);
+ else if (strcmp (var, "DHCPSID") == 0)
+ parse_address (&dhcp->serveraddress, value, "DHCPSID");
+ else if (strcmp (var, "DHCPSNAME") == 0)
+ strlcpy (dhcp->servername, value, sizeof (dhcp->servername));
+ else if (strcmp (var, "LEASEDFROM") == 0)
+ parse_uint (&dhcp->leasedfrom, value, "LEASEDFROM");
+ else if (strcmp (var, "LEASETIME") == 0)
+ parse_uint (&dhcp->leasetime, value, "LEASETIME");
+ else if (strcmp (var, "RENEWALTIME") == 0)
+ parse_uint (&dhcp->renewaltime, value, "RENEWALTIME");
+ else if (strcmp (var, "REBINDTIME") == 0)
+ parse_uint (&dhcp->rebindtime, value, "REBINDTIME");
+
+next:
+ free (line);
+ }
+
+ fclose (fp);
+ return (true);
+}
+
+#endif
+