mirror of
https://github.com/systemd/systemd.git
synced 2024-11-25 03:03:34 +08:00
dhcp,network: implement RFC 4833 (DHCP Timezone option)
This one is simply to add: encode the tzdata timezone in the DHCP options and optionally make use of it.
This commit is contained in:
parent
43f447b121
commit
8eb9058dc1
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user