diff options
author | Hans Dedecker <dedeckeh@gmail.com> | 2018-08-22 11:45:53 +0200 |
---|---|---|
committer | Hans Dedecker <hans.dedecker@technicolor.com> | 2018-09-05 10:35:42 +0200 |
commit | 881f66b0c2526bff6a2a51b30d314c512df813b4 (patch) | |
tree | 234850b1775f67884468265dd15485881d69cdbb | |
parent | 3e17fd926ff0f8feae97ff7c86dd5ce282315490 (diff) |
odhcpd: detect broken hostnames
Check hostnames contain valid characters as defined in RFC 952 and RFC 1123.
Invalid hostnames in uci configured host entries will result into a refusal
to create the static lease.
In case a client received hostname contains an invalid character no
<hostname> <IP address> entry will be added to the lease file.
In such case the leaseinfo description in the lease file will still contain
the hostname but preceded by the string broken\x20
Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
-rw-r--r-- | src/config.c | 5 | ||||
-rw-r--r-- | src/dhcpv4.c | 5 | ||||
-rw-r--r-- | src/dhcpv6-ia.c | 16 | ||||
-rw-r--r-- | src/odhcpd.c | 35 | ||||
-rw-r--r-- | src/odhcpd.h | 8 | ||||
-rw-r--r-- | src/ubus.c | 3 |
6 files changed, 64 insertions, 8 deletions
diff --git a/src/config.c b/src/config.c index 6556eac..b36afb1 100644 --- a/src/config.c +++ b/src/config.c @@ -344,8 +344,11 @@ static int set_lease(struct uci_section *s) if (!lease) goto err; - if (hostlen > 1) + if (hostlen > 1) { memcpy(lease->hostname, blobmsg_get_string(c), hostlen); + if (!odhcpd_valid_hostname(lease->hostname)) + goto err; + } if ((c = tb[LEASE_ATTR_IP])) if (inet_pton(AF_INET, blobmsg_get_string(c), &lease->ipaddr) < 0) diff --git a/src/dhcpv4.c b/src/dhcpv4.c index 3386abb..2cc6278 100644 --- a/src/dhcpv4.c +++ b/src/dhcpv4.c @@ -1095,6 +1095,11 @@ static struct dhcpv4_assignment* dhcpv4_lease(struct interface *iface, if (a->hostname) { memcpy(a->hostname, hostname, hostname_len); a->hostname[hostname_len] = 0; + + if (odhcpd_valid_hostname(a->hostname)) + a->flags &= ~OAF_BROKEN_HOSTNAME; + else + a->flags |= OAF_BROKEN_HOSTNAME; } } diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index 4ee6dd2..fb1c228 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -331,7 +331,8 @@ void dhcpv6_write_ia_addr(struct in6_addr *addr, int prefix, _unused uint32_t pr inet_ntop(AF_INET6, addr, ipbuf, sizeof(ipbuf) - 1); - if (ctxt->c->length == 128 && ctxt->c->hostname) { + if (ctxt->c->length == 128 && ctxt->c->hostname && + !(ctxt->c->flags & OAF_BROKEN_HOSTNAME)) { fputs(ipbuf, ctxt->fp); char b[256]; @@ -394,8 +395,9 @@ void dhcpv6_write_statefile(void) odhcpd_hexlify(duidbuf, ctxt.c->clid_data, ctxt.c->clid_len); /* iface DUID iaid hostname lifetime assigned length [addrs...] */ - ctxt.buf_idx = snprintf(ctxt.buf, ctxt.buf_len, "# %s %s %x %s %ld %x %u ", + ctxt.buf_idx = snprintf(ctxt.buf, ctxt.buf_len, "# %s %s %x %s%s %ld %x %u ", ctxt.iface->ifname, duidbuf, ntohl(ctxt.c->iaid), + (ctxt.c->flags & OAF_BROKEN_HOSTNAME) ? "broken\\x20" : "", (ctxt.c->hostname ? ctxt.c->hostname : "-"), (ctxt.c->valid_until > now ? (ctxt.c->valid_until - now + wall_time) : @@ -423,8 +425,9 @@ void dhcpv6_write_statefile(void) odhcpd_hexlify(duidbuf, c->hwaddr, sizeof(c->hwaddr)); /* iface DUID iaid hostname lifetime assigned length [addrs...] */ - ctxt.buf_idx = snprintf(ctxt.buf, ctxt.buf_len, "# %s %s ipv4 %s %ld %x 32 ", + ctxt.buf_idx = snprintf(ctxt.buf, ctxt.buf_len, "# %s %s ipv4 %s%s %ld %x 32 ", ctxt.iface->ifname, duidbuf, + (c->flags & OAF_BROKEN_HOSTNAME) ? "broken\\x20" : "", (c->hostname ? c->hostname : "-"), (c->valid_until > now ? (c->valid_until - now + wall_time) : @@ -434,7 +437,7 @@ void dhcpv6_write_statefile(void) struct in_addr addr = {.s_addr = c->addr}; inet_ntop(AF_INET, &addr, ipbuf, sizeof(ipbuf) - 1); - if (c->hostname) { + if (c->hostname && !(c->flags & OAF_BROKEN_HOSTNAME)) { fputs(ipbuf, ctxt.fp); char b[256]; @@ -1343,6 +1346,11 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface, if (a->hostname) { memcpy(a->hostname, hostname, hostname_len); a->hostname[hostname_len] = 0; + + if (odhcpd_valid_hostname(a->hostname)) + a->flags &= ~OAF_BROKEN_HOSTNAME; + else + a->flags |= OAF_BROKEN_HOSTNAME; } } a->accept_reconf = accept_reconf; diff --git a/src/odhcpd.c b/src/odhcpd.c index fe4dd73..c1d51e7 100644 --- a/src/odhcpd.c +++ b/src/odhcpd.c @@ -581,3 +581,38 @@ bool odhcpd_bitlen2netmask(bool inet6, unsigned int bits, void *mask) return true; } + +bool odhcpd_valid_hostname(const char *name) +{ +#define MAX_LABEL 63 + const char *c, *label, *label_end; + int label_sz = 0; + + for (c = name, label_sz = 0, label = name, label_end = name + strcspn(name, ".") - 1; + *c && label_sz <= MAX_LABEL; c++) { + if ((*c >= '0' && *c <= '9') || + (*c >= 'A' && *c <= 'Z') || + (*c >= 'a' && *c <= 'z')) { + label_sz++; + continue; + } + + if ((*c == '_' || *c == '-') && c != label && c != label_end) { + label_sz++; + continue; + } + + if (*c == '.') { + if (*(c + 1)) { + label = c + 1; + label_end = label + strcspn(label, ".") - 1; + label_sz = 0; + } + continue; + } + + return false; + } + + return (label_sz && label_sz <= MAX_LABEL ? true : false); +} diff --git a/src/odhcpd.h b/src/odhcpd.h index 91fdcbf..ef94cfc 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -129,9 +129,10 @@ enum odhcpd_mode { enum odhcpd_assignment_flags { - OAF_TENTATIVE = (1 << 0), - OAF_BOUND = (1 << 1), - OAF_STATIC = (1 << 2), + OAF_TENTATIVE = (1 << 0), + OAF_BOUND = (1 << 1), + OAF_STATIC = (1 << 2), + OAF_BROKEN_HOSTNAME = (1 << 3), }; struct config { @@ -288,6 +289,7 @@ void odhcpd_bmemcpy(void *av, const void *bv, size_t bits); int odhcpd_netmask2bitlen(bool v6, void *mask); bool odhcpd_bitlen2netmask(bool v6, unsigned int bits, void *mask); +bool odhcpd_valid_hostname(const char *name); int config_parse_interface(void *data, size_t len, const char *iname, bool overwrite); @@ -53,6 +53,9 @@ static int handle_dhcpv4_leases(struct ubus_context *ctx, _unused struct ubus_ob if (c->flags & OAF_STATIC) blobmsg_add_string(&b, NULL, "static"); + + if (c->flags & OAF_BROKEN_HOSTNAME) + blobmsg_add_string(&b, NULL, "broken-hostname"); blobmsg_close_array(&b, m); buf = blobmsg_alloc_string_buffer(&b, "address", INET_ADDRSTRLEN); |