diff options
Diffstat (limited to 'dhcp.c')
-rw-r--r-- | dhcp.c | 126 |
1 files changed, 101 insertions, 25 deletions
@@ -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) |