From 7933149acf5a629e611a007cbe7c2c46a4a0d154 Mon Sep 17 00:00:00 2001 From: Jack O'Sullivan Date: Mon, 26 Aug 2019 22:46:54 +0100 Subject: [PATCH] Send hostname with persistent DHCP requests --- net-dhcp/network.py | 11 +++++++++-- net-dhcp/udhcpc.py | 20 ++++++++++++++++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/net-dhcp/network.py b/net-dhcp/network.py index 0e830d3..0a93fea 100644 --- a/net-dhcp/network.py +++ b/net-dhcp/network.py @@ -91,6 +91,12 @@ def await_endpoint_container_iface(n, e, timeout=5): raise NetDhcpError('Timed out waiting for container to become availabile') return iface +def endpoint_container_name(n, e): + for info in client.networks.get(n).attrs['Containers'].values(): + if info['EndpointID'] == e: + return info['Name'] + return None + @app.route('/NetworkDriver.GetCapabilities', methods=['POST']) def net_get_capabilities(): return jsonify({ @@ -340,13 +346,14 @@ class ContainerDHCPManager: def run(self): try: iface = await_endpoint_container_iface(self.network, self.endpoint) + hostname = endpoint_container_name(self.network, self.endpoint) - self.dhcp = udhcpc.DHCPClient(iface, event_listener=self._on_event) + self.dhcp = udhcpc.DHCPClient(iface, event_listener=self._on_event, hostname=hostname) logger.info('Starting DHCPv4 client on %s in container namespace %s', iface['ifname'], \ self.dhcp.netns) if self.ipv6: - self.dhcp6 = udhcpc.DHCPClient(iface, v6=True, event_listener=self._on_event) + self.dhcp6 = udhcpc.DHCPClient(iface, v6=True, event_listener=self._on_event, hostname=hostname) logger.info('Starting DHCPv6 client on %s in container namespace %s', iface['ifname'], \ self.dhcp6.netns) except Exception as e: diff --git a/net-dhcp/udhcpc.py b/net-dhcp/udhcpc.py index cefab3e..ebbfb38 100644 --- a/net-dhcp/udhcpc.py +++ b/net-dhcp/udhcpc.py @@ -1,6 +1,8 @@ from enum import Enum import ipaddress import json +import struct +import binascii import os from os import path from select import select @@ -30,7 +32,7 @@ class DHCPClientError(Exception): def _nspopen_wrapper(netns): return lambda *args, **kwargs: NSPopen(netns, *args, **kwargs) class DHCPClient: - def __init__(self, iface, v6=False, once=False, event_listener=None): + def __init__(self, iface, v6=False, once=False, hostname=None, event_listener=None): self.iface = iface self.v6 = v6 self.once = once @@ -47,6 +49,18 @@ class DHCPClient: bin_path = '/usr/bin/udhcpc6' if v6 else '/sbin/udhcpc' cmdline = [bin_path, '-s', HANDLER_SCRIPT, '-i', iface['ifname'], '-f'] cmdline.append('-q' if once else '-R') + if hostname: + cmdline.append('-x') + if v6: + # TODO: We encode the fqdn for DHCPv6 because udhcpc6 seems to be broken + # flags: S bit set (see RFC4704) + enc_hostname = hostname.encode('utf-8') + enc_hostname = struct.pack('BB', 0b0001, len(enc_hostname)) + enc_hostname + enc_hostname = binascii.hexlify(enc_hostname).decode('ascii') + hostname_opt = f'0x27:{enc_hostname}' + else: + hostname_opt = f'hostname:{hostname}' + cmdline.append(hostname_opt) if not v6: cmdline += ['-V', VENDOR_ID] @@ -54,6 +68,8 @@ class DHCPClient: self._event_queue = posix_ipc.MessageQueue(f'/udhcpc{self._suffix}_{iface["address"].replace(":", "_")}', \ flags=os.O_CREAT | os.O_EXCL) self.proc = Popen(cmdline, env={'EVENT_QUEUE': self._event_queue.name}) + if hostname: + logger.debug('[udhcpc%s#%d] using hostname "%s"', self._suffix, self.proc.pid, hostname) self._has_lease = threading.Event() self.ip = None @@ -110,7 +126,7 @@ class DHCPClient: if self._shutdown_event.is_set(): return - if self.proc.returncode != None and (not self.once or self.proc.returncode != 0): + if self.proc.returncode is not None and (not self.once or self.proc.returncode != 0): raise DHCPClientError(f'udhcpc{self._suffix} exited early with code {self.proc.returncode}') if self.once: self.await_ip()