]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dhcp,network: implement RFC 4833 (DHCP Timezone option)
authorLennart Poettering <lennart@poettering.net>
Wed, 26 Aug 2015 17:19:32 +0000 (19:19 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 26 Aug 2015 18:44:20 +0000 (20:44 +0200)
This one is simply to add: encode the tzdata timezone in the DHCP
options and optionally make use of it.

15 files changed:
src/libsystemd-network/dhcp-lease-internal.h
src/libsystemd-network/dhcp-protocol.h
src/libsystemd-network/dhcp-server-internal.h
src/libsystemd-network/sd-dhcp-lease.c
src/libsystemd-network/sd-dhcp-server.c
src/libsystemd/sd-network/sd-network.c
src/network/networkctl.c
src/network/networkd-dhcp4.c
src/network/networkd-link.c
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd.h
src/systemd/sd-dhcp-lease.h
src/systemd/sd-dhcp-server.h
src/systemd/sd-network.h

index 5a3fcddb1b513c369019c8f1c0b90d35663e8104..6e247e98655064aaf435eb9a5641da3ca131949f 100644 (file)
@@ -83,6 +83,7 @@ struct sd_dhcp_lease {
         size_t client_id_len;
         uint8_t *vendor_specific;
         size_t vendor_specific_len;
+        char *timezone;
         LIST_HEAD(struct sd_dhcp_raw_option, private_options);
 };
 
index 4308723f9106e25fb6301c80a0dd5f9c6a9b6938..88a81d2866a7312d04198b9f23342aff47c5c586 100644 (file)
@@ -137,6 +137,8 @@ enum {
         DHCP_OPTION_REBINDING_T2_TIME           = 59,
         DHCP_OPTION_VENDOR_CLASS_IDENTIFIER     = 60,
         DHCP_OPTION_CLIENT_IDENTIFIER           = 61,
+        DHCP_OPTION_NEW_POSIX_TIMEZONE          = 100,
+        DHCP_OPTION_NEW_TZDB_TIMEZONE           = 101,
         DHCP_OPTION_CLASSLESS_STATIC_ROUTE      = 121,
         DHCP_OPTION_PRIVATE_BASE                = 224,
         DHCP_OPTION_PRIVATE_LAST                = 254,
index 58750c441813807a0f44cc42baeed9e6aaf7999c..24f99f801d2ee13d53082ed247538756c02cfb5f 100644 (file)
@@ -62,6 +62,8 @@ struct sd_dhcp_server {
         size_t pool_size;
         size_t next_offer;
 
+        char *timezone;
+
         Hashmap *leases_by_client_id;
         DHCPLease **bound_leases;
 };
index 57369a353de8803e259814c874a292210f1fffc6..c312c7cad06d04efb636d2e5b0ca778dff6c77ee 100644 (file)
@@ -608,6 +608,22 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
 
                 break;
 
+        case DHCP_OPTION_NEW_TZDB_TIMEZONE: {
+                _cleanup_free_ char *tz = NULL;
+
+                r = lease_parse_string(option, len, &tz);
+                if (r < 0)
+                        return r;
+
+                if (!timezone_is_valid(tz))
+                        return -EINVAL;
+
+                free(lease->timezone);
+                lease->timezone = tz;
+                tz = NULL;
+                break;
+        }
+
         case DHCP_OPTION_VENDOR_SPECIFIC:
                 if (len >= 1) {
                         free(lease->vendor_specific);
@@ -757,6 +773,10 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
         if (r >= 0)
                 serialize_dhcp_routes(f, "ROUTES", routes, r);
 
+        r = sd_dhcp_lease_get_timezone(lease, &string);
+        if (r >= 0)
+                fprintf(f, "TIMEZONE=%s\n", string);
+
         r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
         if (r >= 0) {
                 _cleanup_free_ char *client_id_hex;
@@ -840,6 +860,7 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
                            "ROOT_PATH", &lease->root_path,
                            "ROUTES", &routes,
                            "CLIENTID", &client_id_hex,
+                           "TIMEZONE", &lease->timezone,
                            "VENDOR_SPECIFIC", &vendor_specific_hex,
                            "OPTION_224", &options[0],
                            "OPTION_225", &options[1],
@@ -1026,3 +1047,14 @@ int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id,
 
         return 0;
 }
+
+int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone) {
+        assert_return(lease, -EINVAL);
+        assert_return(timezone, -EINVAL);
+
+        if (!lease->timezone)
+                return -ENXIO;
+
+        *timezone = lease->timezone;
+        return 0;
+}
index faeab0fd309bfa73661227537c08ee3694c68cfa..730d95e2c0d372955920e57833fab1f5c50a0614 100644 (file)
@@ -136,6 +136,8 @@ sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) {
 
         sd_event_unref(server->event);
 
+        free(server->timezone);
+
         while ((lease = hashmap_steal_first(server->leases_by_client_id)))
                 dhcp_lease_free(lease);
         hashmap_free(server->leases_by_client_id);
@@ -474,6 +476,15 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
         if (r < 0)
                 return r;
 
+        if (server->timezone) {
+                r = dhcp_option_append(
+                                &packet->dhcp, req->max_optlen, &offset, 0,
+                                DHCP_OPTION_NEW_TZDB_TIMEZONE,
+                                strlen(server->timezone), server->timezone);
+                if (r < 0)
+                        return r;
+        }
+
         r = dhcp_server_send_packet(server, req, packet, DHCP_ACK, offset);
         if (r < 0)
                 return r;
@@ -993,3 +1004,19 @@ int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
 
         return r;
 }
+
+int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *timezone) {
+        int r;
+
+        assert_return(server, -EINVAL);
+        assert_return(timezone_is_valid(timezone), -EINVAL);
+
+        if (streq_ptr(timezone, server->timezone))
+                return 0;
+
+        r = free_and_strdup(&server->timezone, timezone);
+        if (r < 0)
+                return r;
+
+        return 1;
+}
index b63fdf8fcbfd7a39dd647e0bdd2635b2a4bc9b1e..87d87359b857180cc40403952d40eb3e82e1af23 100644 (file)
@@ -214,6 +214,28 @@ _public_ int sd_network_link_get_lldp(int ifindex, char **lldp) {
         return 0;
 }
 
+int sd_network_link_get_timezone(int ifindex, char **ret) {
+        _cleanup_free_ char *s = NULL, *p = NULL;
+        int r;
+
+        assert_return(ifindex > 0, -EINVAL);
+        assert_return(ret, -EINVAL);
+
+        if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
+                return -ENOMEM;
+
+        r = parse_env_file(p, NEWLINE, "TIMEZONE", &s, NULL);
+        if (r == -ENOENT)
+                return -ENODATA;
+        if (r < 0)
+                return r;
+        if (isempty(s))
+                return -ENODATA;
+
+        *ret = s;
+        s = NULL;
+        return 0;
+}
 
 static int network_get_link_strv(const char *key, int ifindex, char ***ret) {
         _cleanup_free_ char *p = NULL, *s = NULL;
index c9b53dc3f629ff69a2d37104a3c80f2086e51dd2..2281d4b718f72bce77eb5040c39461fb9f69d913 100644 (file)
@@ -497,7 +497,7 @@ static int link_status_one(
                 sd_hwdb *hwdb,
                 const char *name) {
         _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
-        _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
+        _cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *timezone = NULL;
         _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
         _cleanup_device_unref_ sd_device *d = NULL;
         char devid[2 + DECIMAL_STR_MAX(int)];
@@ -570,7 +570,6 @@ static int link_status_one(
         setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
 
         sd_network_link_get_dns(ifindex, &dns);
-        sd_network_link_get_ntp(ifindex, &ntp);
         sd_network_link_get_domains(ifindex, &domains);
         r = sd_network_link_get_wildcard_domain(ifindex);
         if (r > 0) {
@@ -652,6 +651,8 @@ static int link_status_one(
                 dump_list("             DNS: ", dns);
         if (!strv_isempty(domains))
                 dump_list("          Domain: ", domains);
+
+        (void) sd_network_link_get_ntp(ifindex, &ntp);
         if (!strv_isempty(ntp))
                 dump_list("             NTP: ", ntp);
 
@@ -661,6 +662,10 @@ static int link_status_one(
         if (!strv_isempty(carrier_bound_by))
                 dump_list("Carrier Bound By: ", carrier_bound_by);
 
+        (void) sd_network_link_get_timezone(ifindex, &timezone);
+        if (timezone)
+                printf("       Time Zone: %s", timezone);
+
         return 0;
 }
 
index 1b2ff7c76976562142408222753445c939f7d76a..7fce389fa2acbe3926a72b2b11827a8de28e4475 100644 (file)
@@ -624,6 +624,11 @@ int dhcp4_configure(Link *link) {
                         return r;
         }
 
+        /* Always acquire the timezone */
+        r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_NEW_TZDB_TIMEZONE);
+        if (r < 0)
+                return r;
+
         if (link->network->dhcp_sendhost) {
                 _cleanup_free_ char *hostname = NULL;
                 const char *hn = NULL;
index cc9dc393c6a61af478bd728caee25c0d4aee413b..c179aafebb8a11ee6383175a6ac061d8f8ad5893 100644 (file)
@@ -672,6 +672,27 @@ static int link_enter_set_addresses(Link *link) {
                         return r;
                 */
 
+                if (link->network->dhcp_server_emit_timezone) {
+                        _cleanup_free_ char *buffer = NULL;
+                        const char *tz;
+
+                        if (link->network->dhcp_server_timezone)
+                                tz = link->network->dhcp_server_timezone;
+                        else {
+                                r = get_timezone(&buffer);
+                                if (r < 0)
+                                        log_warning_errno(r, "Failed to determine timezone: %m");
+                                else
+                                        tz = buffer;
+                        }
+
+                        if (tz) {
+                                r = sd_dhcp_server_set_timezone(link->dhcp_server, tz);
+                                if (r < 0)
+                                        return r;
+                        }
+                }
+
                 r = sd_dhcp_server_start(link->dhcp_server);
                 if (r < 0) {
                         log_link_warning_errno(link, r, "Could not start DHCPv4 server instance: %m");
@@ -2413,6 +2434,14 @@ int link_save(Link *link) {
                 fputs("\n", f);
         }
 
+        if (link->dhcp_lease) {
+                const char *tz = NULL;
+
+                r = sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
+                if (r >= 0)
+                        fprintf(f, "TIMEZONE=%s\n", tz);
+        }
+
         if (link->dhcp_lease) {
                 assert(link->network);
 
index 7ac7ef1ea3a2342b6f209c89c8940f7c3f9580f1..c8c612d4ebafe6504a69f763ab2b19913e9ef179 100644 (file)
@@ -73,6 +73,9 @@ DHCP.RequestBroadcast,         config_parse_bool,                              0
 DHCP.CriticalConnection,       config_parse_bool,                              0,                             offsetof(Network, dhcp_critical)
 DHCP.VendorClassIdentifier,    config_parse_string,                            0,                             offsetof(Network, dhcp_vendor_class_identifier)
 DHCP.RouteMetric,              config_parse_unsigned,                          0,                             offsetof(Network, dhcp_route_metric)
+DHCP.UseTimezone,              config_parse_bool,                              0,                             offsetof(Network, dhcp_timezone)
+DHCPServer.EmitTimezone,       config_parse_bool,                              0,                             offsetof(Network, dhcp_server_emit_timezone)
+DHCPServer.Timezone,           config_parse_timezone,                          0,                             offsetof(Network, dhcp_server_timezone)
 Bridge.Cost,                   config_parse_unsigned,                          0,                             offsetof(Network, cost)
 Bridge.UseBPDU,                config_parse_bool,                              0,                             offsetof(Network, use_bpdu)
 Bridge.HairPin,                config_parse_bool,                              0,                             offsetof(Network, hairpin)
index 8f773e738d0a78e794774c93756972f73683be86..3619e3160c8e01a99776c7e628b55eb368d2d4fe 100644 (file)
@@ -124,7 +124,8 @@ static int network_load_one(Manager *manager, const char *filename) {
                          "Address\0"
                          "Route\0"
                          "DHCP\0"
-                         "DHCPv4\0"
+                         "DHCPv4\0" /* compat */
+                         "DHCPServer\0"
                          "Bridge\0"
                          "BridgeFDB\0",
                          config_item_perf_lookup, network_network_gperf_lookup,
@@ -258,6 +259,8 @@ void network_free(Network *network) {
         condition_free_list(network->match_kernel);
         condition_free_list(network->match_arch);
 
+        free(network->dhcp_server_timezone);
+
         free(network);
 }
 
@@ -849,3 +852,38 @@ int config_parse_hostname(
         *hostname = hostname_cleanup(hn);
         return 0;
 }
+
+int config_parse_timezone(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        char **timezone = data, *tz = NULL;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+
+        r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata);
+        if (r < 0)
+                return r;
+
+        if (!timezone_is_valid(tz)) {
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Timezone is not valid, ignoring assignment: %s", rvalue);
+                free(tz);
+                return 0;
+        }
+
+        free(*timezone);
+        *timezone = tz;
+
+        return 0;
+}
index 5340922bf1479cd43bc8e6de5776db8eceec1eed..a337ea7bf03d6fd8d314d1d3b8d5b772a329f658 100644 (file)
@@ -143,12 +143,15 @@ struct Network {
         bool dhcp_broadcast;
         bool dhcp_critical;
         bool dhcp_routes;
+        bool dhcp_timezone;
         unsigned dhcp_route_metric;
         AddressFamilyBoolean link_local;
         bool ipv4ll_route;
         union in_addr_union ipv6_token;
 
         bool dhcp_server;
+        char *dhcp_server_timezone;
+        bool dhcp_server_emit_timezone;
 
         bool use_bpdu;
         bool hairpin;
@@ -461,3 +464,5 @@ int config_parse_ipv6_privacy_extensions(const char *unit, const char *filename,
 
 /* Hostname */
 int config_parse_hostname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+
+int config_parse_timezone(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
index 5afa50a9d0e729cf7e734db256028cecbf955074..6e109e03fd25e502d1d6c7558b48bff257dd6632 100644 (file)
@@ -49,6 +49,7 @@ int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const uint8_t **data
                                       size_t *data_len);
 int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
                                 size_t *client_id_len);
+int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone);
 
 int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file);
 int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file);
index 9af3b6532d952125da52c547beb0f10637f4b43b..a2e1995cf9edc9c411d5f279305f1b3139a6dc3d 100644 (file)
@@ -47,5 +47,7 @@ int sd_dhcp_server_stop(sd_dhcp_server *server);
 int sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr *address, unsigned char prefixlen);
 int sd_dhcp_server_set_lease_pool(sd_dhcp_server *server, struct in_addr *start, size_t size);
 
+int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *timezone);
+
 int sd_dhcp_server_forcerenew(sd_dhcp_server *server);
 #endif
index 4d96c867d958c91a0585242d7800fa56299d2abf..4179015fbfd068f3e52a48929e8c752d0b0e750e 100644 (file)
@@ -122,6 +122,9 @@ int sd_network_link_get_carrier_bound_to(int ifindex, char ***carriers);
 /* Get the CARRIERS that are bound to current link. */
 int sd_network_link_get_carrier_bound_by(int ifindex, char ***carriers);
 
+/* Get the timezone that was learnt on a specific link. */
+int sd_network_link_get_timezone(int ifindex, char **timezone);
+
 /* Returns whether or not domains that don't match any link should be resolved
  * on this link. 1 for yes, 0 for no and negative value for error */
 int sd_network_link_get_wildcard_domain(int ifindex);