aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dhcp-common.c65
-rw-r--r--dhcp-common.h1
2 files changed, 31 insertions, 35 deletions
diff --git a/dhcp-common.c b/dhcp-common.c
index a3764f1..588684e 100644
--- a/dhcp-common.c
+++ b/dhcp-common.c
@@ -522,51 +522,43 @@ print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl)
return (ssize_t)bytes;
}
-#define ADDRSZ 4
#define ADDR6SZ 16
static size_t
dhcp_optlen(const struct dhcp_opt *opt, size_t dl)
{
size_t sz;
- if (dl == 0)
+ if (opt->type & ADDRIPV6)
+ sz = ADDR6SZ;
+ else if (opt->type & (UINT32 | ADDRIPV4))
+ sz = sizeof(uint32_t);
+ else if (opt->type & UINT16)
+ sz = sizeof(uint16_t);
+ else if (opt->type & (UINT8 | BITFLAG))
+ sz = sizeof(uint8_t);
+ else if (opt->type & FLAG)
return 0;
-
- if (opt->type == 0 ||
- opt->type & (STRING | BINHEX | RFC3442 | RFC5969))
- {
+ else {
+ /* All other types are variable length */
if (opt->len) {
- if ((size_t)opt->len > dl)
- return 0;
- return (size_t)opt->len;
+ if ((size_t)opt->len > dl) {
+ errno = ENODATA;
+ return -1;
+ }
+ return (ssize_t)opt->len;
}
- return dl;
- }
-
- if ((opt->type & (ADDRIPV4 | ARRAY)) == (ADDRIPV4 | ARRAY)) {
- if (dl < ADDRSZ)
- return 0;
- return dl - (dl % ADDRSZ);
+ return (ssize_t)dl;
}
-
- if ((opt->type & (ADDRIPV6 | ARRAY)) == (ADDRIPV6 | ARRAY)) {
- if (dl < ADDR6SZ)
- return 0;
- return dl - (dl % ADDR6SZ);
+ if (dl < sz) {
+ errno = ENODATA;
+ return -1;
}
- if (opt->type & (UINT32 | ADDRIPV4))
- sz = sizeof(uint32_t);
- else if (opt->type & UINT16)
- sz = sizeof(uint16_t);
- else if (opt->type & UINT8)
- sz = sizeof(uint8_t);
- else if (opt->type & ADDRIPV6)
- sz = ADDR6SZ;
- else
- /* If we don't know the size, assume it's valid */
- return dl;
- return (dl < sz ? 0 : sz);
+ /* Trim any extra data.
+ * Maybe we need a settng to reject DHCP options with extra data? */
+ if (opt->type & ARRAY)
+ return (ssize_t)(dl - (dl % sz));
+ return (ssize_t)sz;
}
#ifdef INET6
@@ -766,8 +758,11 @@ dhcp_envoption1(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
size_t e;
char *v, *val;
- if (opt->len && opt->len < ol)
- ol = opt->len;
+ /* Ensure a valid length */
+ ol = (size_t)dhcp_optlen(opt, ol);
+ if ((ssize_t)ol == -1)
+ return 0;
+
len = print_option(NULL, 0, opt->type, od, ol, ifname);
if (len < 0)
return 0;
diff --git a/dhcp-common.h b/dhcp-common.h
index a3d62fc..a87d32a 100644
--- a/dhcp-common.h
+++ b/dhcp-common.h
@@ -66,6 +66,7 @@
#define RAW (1 << 23)
#define ESCSTRING (1 << 24)
#define ESCFILE (1 << 25)
+#define BITFLAG (1 << 26)
struct dhcp_opt {
uint32_t option; /* Also used for IANA Enterpise Number */