aboutsummaryrefslogtreecommitdiffstats
path: root/dhcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'dhcp.c')
-rw-r--r--dhcp.c126
1 files changed, 101 insertions, 25 deletions
diff --git a/dhcp.c b/dhcp.c
index 1169993..c22e767 100644
--- a/dhcp.c
+++ b/dhcp.c
@@ -1,6 +1,6 @@
/*
* dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@@ -50,6 +50,7 @@
#define RFC3361 (1 << 10)
#define RFC3397 (1 << 11)
#define RFC3442 (1 << 12)
+#define RFC5969 (1 << 13)
#define IPV4R IPV4 | REQUEST
@@ -163,6 +164,8 @@ static const struct dhcp_opt const dhcp_opts[] = {
{ 114, STRING, "default_url" },
{ 118, IPV4, "subnet_selection" },
{ 119, STRING | RFC3397, "domain_search" },
+ { 120, STRING | RFC3361, "sip_server" },
+ { 212, RFC5969, "sixrd" },
{ 0, 0, NULL }
};
@@ -270,18 +273,17 @@ valid_length(uint8_t option, int dl, int *type)
*type = opt->type;
if (opt->type == 0 ||
- opt->type & STRING ||
- opt->type & RFC3442)
+ opt->type & (STRING | RFC3442 | RFC5969))
return 0;
sz = 0;
- if (opt->type & UINT32 || opt->type & IPV4)
+ if (opt->type & (UINT32 | IPV4))
sz = sizeof(uint32_t);
if (opt->type & UINT16)
sz = sizeof(uint16_t);
if (opt->type & UINT8)
sz = sizeof(uint8_t);
- if (opt->type & IPV4 || opt->type & ARRAY)
+ if (opt->type & (IPV4 | ARRAY))
return dl % sz;
return (dl == sz ? 0 : -1);
}
@@ -428,7 +430,7 @@ get_option_uint8(uint8_t *i, const struct dhcp_message *dhcp, uint8_t option)
* separated string. Returns length of string (including
* terminating zero) or zero on error. out may be NULL
* to just determine output length. */
-static ssize_t
+ssize_t
decode_rfc3397(char *out, ssize_t len, int pl, const uint8_t *p)
{
const uint8_t *r, *q = p;
@@ -624,11 +626,11 @@ decode_rfc3361(int dl, const uint8_t *data)
addr.s_addr = INADDR_BROADCAST;
l = ((dl / sizeof(addr.s_addr)) * ((4 * 4) + 1)) + 1;
sip = p = xmalloc(l);
- while (l != 0) {
+ while (dl != 0) {
memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
data += sizeof(addr.s_addr);
p += snprintf(p, l - (p - sip), "%s ", inet_ntoa(addr));
- l -= sizeof(addr.s_addr);
+ dl -= sizeof(addr.s_addr);
}
*--p = '\0';
break;
@@ -640,6 +642,74 @@ decode_rfc3361(int dl, const uint8_t *data)
return sip;
}
+/* Decode an RFC5969 6rd order option into a space
+ * separated string. Returns length of string (including
+ * terminating zero) or zero on error. */
+static ssize_t
+decode_rfc5969(char *out, ssize_t len, int pl, const uint8_t *p)
+{
+ uint8_t ipv4masklen, ipv6prefixlen;
+ uint8_t ipv6prefix[16];
+ uint8_t br[4];
+ int i;
+ ssize_t b, bytes = 0;
+
+ if (pl < 22) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ ipv4masklen = *p++;
+ pl--;
+ ipv6prefixlen = *p++;
+ pl--;
+
+ for (i = 0; i < 16; i++) {
+ ipv6prefix[i] = *p++;
+ pl--;
+ }
+ if (out) {
+ b= snprintf(out, len,
+ "%d %d "
+ "%02x%02x:%02x%02x:"
+ "%02x%02x:%02x%02x:"
+ "%02x%02x:%02x%02x:"
+ "%02x%02x:%02x%02x",
+ ipv4masklen, ipv6prefixlen,
+ ipv6prefix[0], ipv6prefix[1], ipv6prefix[2], ipv6prefix[3],
+ ipv6prefix[4], ipv6prefix[5], ipv6prefix[6], ipv6prefix[7],
+ ipv6prefix[8], ipv6prefix[9], ipv6prefix[10],ipv6prefix[11],
+ ipv6prefix[12],ipv6prefix[13],ipv6prefix[14], ipv6prefix[15]
+ );
+
+ len -= b;
+ out += b;
+ bytes += b;
+ } else {
+ bytes += 16 * 2 + 8 + 2 + 1 + 2;
+ }
+
+ while (pl >= 4) {
+ br[0] = *p++;
+ br[1] = *p++;
+ br[2] = *p++;
+ br[3] = *p++;
+ pl -= 4;
+
+ if (out) {
+ b= snprintf(out, len, " %d.%d.%d.%d",
+ br[0], br[1], br[2], br[3]);
+ len -= b;
+ out += b;
+ bytes += b;
+ } else {
+ bytes += (4 * 4);
+ }
+ }
+
+ return bytes;
+}
+
char *
get_option_string(const struct dhcp_message *dhcp, uint8_t option)
{
@@ -706,7 +776,7 @@ route_netmask(uint32_t ip_in)
* Otherwise we add static routes and then routers. */
struct rt *
get_option_routes(const struct dhcp_message *dhcp,
- const char *ifname, int *opts)
+ const char *ifname, unsigned long long *opts)
{
const uint8_t *p;
const uint8_t *e;
@@ -721,11 +791,13 @@ get_option_routes(const struct dhcp_message *dhcp,
p = get_option(dhcp, DHO_MSCSR, &len, NULL);
if (p) {
routes = decode_rfc3442_rt(len, p);
- if (routes && !(*opts & DHCPCD_CSR_WARNED)) {
- syslog(LOG_DEBUG,
- "%s: using Classless Static Routes (RFC3442)",
- ifname);
- *opts |= DHCPCD_CSR_WARNED;
+ if (routes) {
+ if (!(*opts & DHCPCD_CSR_WARNED)) {
+ syslog(LOG_DEBUG,
+ "%s: using Classless Static Routes",
+ ifname);
+ *opts |= DHCPCD_CSR_WARNED;
+ }
return routes;
}
}
@@ -1154,7 +1226,9 @@ print_string(char *s, ssize_t len, int dl, const uint8_t *data)
case '\'': /* FALLTHROUGH */
case '$': /* FALLTHROUGH */
case '`': /* FALLTHROUGH */
- case '\\':
+ case '\\': /* FALLTHROUGH */
+ case '|': /* FALLTHROUGH */
+ case '&':
if (s) {
if (len < 3) {
errno = ENOBUFS;
@@ -1204,9 +1278,21 @@ print_option(char *s, ssize_t len, int type, int dl, const uint8_t *data)
return l;
}
+ if (type & RFC3361) {
+ if ((tmp = decode_rfc3361(dl, data)) == NULL)
+ return -1;
+ l = strlen(tmp);
+ l = print_string(s, len, l - 1, (uint8_t *)tmp);
+ free(tmp);
+ return l;
+ }
+
if (type & RFC3442)
return decode_rfc3442(s, len, dl, data);
+ if (type & RFC5969)
+ return decode_rfc5969(s, len, dl, data);
+
if (type & STRING) {
/* Some DHCP servers return NULL strings */
if (*data == '\0')
@@ -1284,16 +1370,6 @@ print_option(char *s, ssize_t len, int type, int dl, const uint8_t *data)
return bytes;
}
-static void
-setvar(char ***e, const char *prefix, const char *var, const char *value)
-{
- size_t len = strlen(prefix) + strlen(var) + strlen(value) + 4;
-
- **e = xmalloc(len);
- snprintf(**e, len, "%s_%s=%s", prefix, var, value);
- (*e)++;
-}
-
ssize_t
configure_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
const struct if_options *ifo)