summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorHans Dedecker <dedeckeh@gmail.com>2018-08-22 11:45:53 +0200
committerHans Dedecker <hans.dedecker@technicolor.com>2018-09-05 10:35:42 +0200
commit881f66b0c2526bff6a2a51b30d314c512df813b4 (patch)
tree234850b1775f67884468265dd15485881d69cdbb /src
parent3e17fd926ff0f8feae97ff7c86dd5ce282315490 (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>
Diffstat (limited to 'src')
-rw-r--r--src/config.c5
-rw-r--r--src/dhcpv4.c5
-rw-r--r--src/dhcpv6-ia.c16
-rw-r--r--src/odhcpd.c35
-rw-r--r--src/odhcpd.h8
-rw-r--r--src/ubus.c3
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);
diff --git a/src/ubus.c b/src/ubus.c
index 5be6bbe..1aec590 100644
--- a/src/ubus.c
+++ b/src/ubus.c
@@ -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);