From: Tom Gundersen Date: Mon, 13 Jan 2014 22:48:28 +0000 (+0100) Subject: sd-dhcp-client/networkd: add transient hostname support X-Git-Tag: v209~415 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=1346b1f0388f4100bb3c2a2bb23bc881769c020c;hp=6fc73498945da749744041d4e10cf8dfac5c3bc6 sd-dhcp-client/networkd: add transient hostname support --- diff --git a/man/systemd-networkd.service.xml b/man/systemd-networkd.service.xml index 02a211e37..2209737f4 100644 --- a/man/systemd-networkd.service.xml +++ b/man/systemd-networkd.service.xml @@ -260,6 +260,13 @@ from the DHCP server will be used on the current link. + + UseHostname + + When true (the default) the hostname received from the DHCP server + will be used as the transient hostname. + + diff --git a/src/libsystemd/sd-dhcp-client.c b/src/libsystemd/sd-dhcp-client.c index 76abcbd2a..c5d8371a9 100644 --- a/src/libsystemd/sd-dhcp-client.c +++ b/src/libsystemd/sd-dhcp-client.c @@ -43,6 +43,7 @@ struct DHCPLease { be32_t router; struct in_addr **dns; uint16_t mtu; + char *hostname; }; typedef struct DHCPLease DHCPLease; @@ -241,6 +242,33 @@ int sd_dhcp_client_get_dns(sd_dhcp_client *client, struct in_addr ***addr) return 0; } +int sd_dhcp_client_get_hostname(sd_dhcp_client *client, const char **hostname) +{ + assert_return(client, -EINVAL); + assert_return(hostname, -EINVAL); + + switch (client->state) { + case DHCP_STATE_INIT: + case DHCP_STATE_SELECTING: + case DHCP_STATE_INIT_REBOOT: + case DHCP_STATE_REBOOTING: + case DHCP_STATE_REQUESTING: + return -EADDRNOTAVAIL; + + case DHCP_STATE_BOUND: + case DHCP_STATE_RENEWING: + case DHCP_STATE_REBINDING: + if (client->lease->hostname) + *hostname = client->lease->hostname; + else + return -ENOENT; + + break; + } + + return 0; +} + int sd_dhcp_client_prefixlen(const struct in_addr *addr) { int len = 0; @@ -829,6 +857,14 @@ static int client_parse_offer(uint8_t code, uint8_t len, const uint8_t *option, break; + case DHCP_OPTION_HOST_NAME: + if (len >= 1) { + free(lease->hostname); + lease->hostname = strndup((const char *)option, len); + } + + break; + case DHCP_OPTION_RENEWAL_T1_TIME: if (len == 4) { memcpy(&val, option, 4); diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf index d4c7a26c8..7686cdf33 100644 --- a/src/network/networkd-gperf.gperf +++ b/src/network/networkd-gperf.gperf @@ -32,5 +32,6 @@ Route.Gateway, config_parse_gateway, 0, 0 Route.Destination, config_parse_destination, 0, 0 DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) +DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname) Bridge.Description, config_parse_string, 0, offsetof(Bridge, description) Bridge.Name, config_parse_ifname, 0, offsetof(Bridge, name) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 296886daa..444af8f6d 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -25,6 +25,7 @@ #include "networkd.h" #include "libudev-private.h" #include "util.h" +#include "bus-util.h" int link_new(Manager *manager, struct udev_device *device, Link **ret) { _cleanup_link_free_ Link *link = NULL; @@ -310,6 +311,46 @@ static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdat return 1; } +static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { + int r; + + r = sd_bus_message_get_errno(m); + if (r < 0) + log_warning("Could not set hostname: %s", strerror(-r)); + + return 1; +} + +static int set_hostname(sd_bus *bus, const char *hostname) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + int r = 0; + + assert(bus); + assert(hostname); + + log_debug("Setting transient hostname: '%s'", hostname); + + r = sd_bus_message_new_method_call( + bus, + "org.freedesktop.hostname1", + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + "SetHostname", + &m); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "sb", hostname, false); + if (r < 0) + return r; + + r = sd_bus_call_async(bus, m, set_hostname_handler, NULL, 0, NULL); + if (r < 0) + log_error("Could not set transient hostname: %s", strerror(-r)); + + return r; +} + static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { Link *link = userdata; int r; @@ -370,6 +411,7 @@ static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) { assert(link); assert(link->network); + assert(link->manager); if (link->state == LINK_STATE_FAILED) return; @@ -410,6 +452,12 @@ static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) { } } } + + if (link->network->dhcp_hostname) { + r = set_hostname(link->manager->bus, ""); + if (r < 0) + log_error("Failed to reset transient hostname"); + } } r = sd_dhcp_client_get_address(client, &address); @@ -507,6 +555,18 @@ static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) { } } + if (link->network->dhcp_hostname) { + const char *hostname; + + r = sd_dhcp_client_get_hostname(client, &hostname); + if (r >= 0) { + r = set_hostname(link->manager->bus, hostname); + if (r < 0) + log_error("Failed to set transient hostname " + "to '%s'", hostname); + } + } + link_enter_set_addresses(link); } diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 90328a1b5..ca781e2bb 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -54,6 +54,10 @@ int manager_new(Manager **ret) { if (r < 0) return r; + r = sd_bus_default_system(&m->bus); + if (r < 0) + return r; + m->udev = udev_new(); if (!m->udev) return -ENOMEM; @@ -85,6 +89,7 @@ void manager_free(Manager *m) { udev_monitor_unref(m->udev_monitor); udev_unref(m->udev); + sd_bus_unref(m->bus); sd_event_source_unref(m->udev_event_source); sd_event_unref(m->event); @@ -280,6 +285,16 @@ int manager_rtnl_listen(Manager *m) { return 0; } +int manager_bus_listen(Manager *m) { + int r; + + r = sd_bus_attach_event(m->bus, m->event, 0); + if (r < 0) + return r; + + return 0; +} + static void append_dns(FILE *f, struct in_addr *dns, unsigned char family, unsigned *count) { char buf[INET6_ADDRSTRLEN]; const char *address; diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 02ffdb1a7..ff5442322 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -67,6 +67,7 @@ static int network_load_one(Manager *manager, const char *filename) { network->dhcp_dns = true; network->dhcp_mtu = true; + network->dhcp_hostname = true; r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0DHCPv4\0", config_item_perf_lookup, (void*) network_gperf_lookup, false, false, network); diff --git a/src/network/networkd.c b/src/network/networkd.c index 0e3892007..00e9a5f3d 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c @@ -70,6 +70,12 @@ int main(int argc, char *argv[]) { goto out; } + r = manager_bus_listen(m); + if (r < 0) { + log_error("Could not connect to system bus: %s", strerror(-r)); + goto out; + } + /* write out empty resolv.conf to avoid a * dangling symlink */ r = manager_update_resolv_conf(m); diff --git a/src/network/networkd.h b/src/network/networkd.h index 5bd7e750e..89f4cf24e 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -26,6 +26,7 @@ #include "sd-event.h" #include "sd-rtnl.h" +#include "sd-bus.h" #include "sd-dhcp-client.h" #include "udev.h" @@ -87,6 +88,7 @@ struct Network { bool dhcp; bool dhcp_dns; bool dhcp_mtu; + bool dhcp_hostname; LIST_HEAD(Address, static_addresses); LIST_HEAD(Route, static_routes); @@ -174,6 +176,7 @@ struct Link { struct Manager { sd_rtnl *rtnl; sd_event *event; + sd_bus *bus; struct udev *udev; struct udev_monitor *udev_monitor; sd_event_source *udev_event_source; @@ -199,6 +202,7 @@ int manager_udev_enumerate_links(Manager *m); int manager_udev_listen(Manager *m); int manager_rtnl_listen(Manager *m); +int manager_bus_listen(Manager *m); int manager_update_resolv_conf(Manager *m); diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index a14808419..e387d5404 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -56,6 +56,7 @@ int sd_dhcp_client_prefixlen(const struct in_addr *addr); int sd_dhcp_client_get_router(sd_dhcp_client *client, struct in_addr *addr); int sd_dhcp_client_get_dns(sd_dhcp_client *client, struct in_addr ***addr); int sd_dhcp_client_get_mtu(sd_dhcp_client *client, uint16_t *mtu); +int sd_dhcp_client_get_hostname(sd_dhcp_client *client, const char **hostname); int sd_dhcp_client_stop(sd_dhcp_client *client); int sd_dhcp_client_start(sd_dhcp_client *client); diff --git a/units/systemd-networkd.service.in b/units/systemd-networkd.service.in index c12f3983e..850193b53 100644 --- a/units/systemd-networkd.service.in +++ b/units/systemd-networkd.service.in @@ -9,6 +9,7 @@ Description=Network Service Documentation=man:systemd-networkd.service(8) DefaultDependencies=no +After=dbus.socket Before=network.target Wants=network.target ConditionCapability=CAP_NET_ADMIN