diff options
-rw-r--r-- | man/systemd.netdev.xml | 14 | ||||
-rw-r--r-- | man/systemd.network.xml | 12 | ||||
-rw-r--r-- | man/systemd.special.xml | 2 | ||||
-rw-r--r-- | src/libsystemd-network/dhcp6-internal.h | 7 | ||||
-rw-r--r-- | src/libsystemd-network/dhcp6-lease-internal.h | 20 | ||||
-rw-r--r-- | src/libsystemd-network/dhcp6-option.c | 102 | ||||
-rw-r--r-- | src/libsystemd-network/dhcp6-protocol.h | 8 | ||||
-rw-r--r-- | src/libsystemd-network/network-internal.c | 15 | ||||
-rw-r--r-- | src/libsystemd-network/network-internal.h | 2 | ||||
-rw-r--r-- | src/libsystemd-network/sd-dhcp6-client.c | 43 | ||||
-rw-r--r-- | src/libsystemd-network/sd-dhcp6-lease.c | 196 | ||||
-rw-r--r-- | src/libsystemd-network/test-dhcp6-client.c | 65 | ||||
-rw-r--r-- | src/network/networkd-link.c | 62 | ||||
-rw-r--r-- | src/systemd/sd-dhcp6-lease.h | 8 | ||||
-rw-r--r-- | src/timedate/timedatectl.c | 2 |
15 files changed, 544 insertions, 14 deletions
diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index a78ceb1252..2680627a78 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -986,6 +986,20 @@ Name=veth-peer</programlisting> </example> <example> + <title>/etc/systemd/network/bond.netdev</title> + <programlisting>[NetDev] +Name=bond1 +Kind=bond + +[Bond] +Mode=802.3ad +TransmitHashPolicy=layer3+4 +MIIMonitorSec=1s +LACPTransmitRate=fast +</programlisting> + </example> + + <example> <title>/etc/systemd/network/dummy.netdev</title> <programlisting>[NetDev] Name=dummy-test diff --git a/man/systemd.network.xml b/man/systemd.network.xml index e44491cc2e..e8a164d22d 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -828,6 +828,18 @@ Name=em1 [Network] Tunnel=vti-tun</programlisting> </example> + + <example> + <title>/etc/systemd/network/bond.network</title> + + <programlisting>[Match] +Name=bond1 + +[Network] +DHCP=yes +</programlisting> + </example> + </refsect1> <refsect1> diff --git a/man/systemd.special.xml b/man/systemd.special.xml index c90b0366c1..e4700d950b 100644 --- a/man/systemd.special.xml +++ b/man/systemd.special.xml @@ -852,7 +852,7 @@ <varlistentry> <term><filename>system.slice</filename></term> <listitem> - <para>By default, all services services started by + <para>By default, all system services started by <command>systemd</command> are found in this slice.</para> </listitem> </varlistentry> diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h index 4f54ad89a6..83e8192f58 100644 --- a/src/libsystemd-network/dhcp6-internal.h +++ b/src/libsystemd-network/dhcp6-internal.h @@ -5,7 +5,7 @@ /*** This file is part of systemd. - Copyright (C) 2014 Intel Corporation. All rights reserved. + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -68,6 +68,11 @@ int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen, uint8_t **optvalue); int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype, DHCP6IA *ia); +int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen, + struct in6_addr **addrs, size_t count, + size_t *allocated); +int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, + char ***str_arr); int dhcp6_network_bind_udp_socket(int index, struct in6_addr *address); int dhcp6_network_send_udp_socket(int s, struct in6_addr *address, diff --git a/src/libsystemd-network/dhcp6-lease-internal.h b/src/libsystemd-network/dhcp6-lease-internal.h index 109e0f4f21..037f580eb6 100644 --- a/src/libsystemd-network/dhcp6-lease-internal.h +++ b/src/libsystemd-network/dhcp6-lease-internal.h @@ -6,7 +6,7 @@ This file is part of systemd. Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Intel Corporation. All rights reserved. + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -40,6 +40,17 @@ struct sd_dhcp6_lease { DHCP6IA ia; DHCP6Address *addr_iter; + + struct in6_addr *dns; + size_t dns_count; + size_t dns_allocated; + char **domains; + size_t domains_count; + struct in6_addr *ntp; + size_t ntp_count; + size_t ntp_allocated; + char **ntp_fqdn; + size_t ntp_fqdn_count; }; int dhcp6_lease_clear_timers(DHCP6IA *ia); @@ -56,6 +67,13 @@ int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit); int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid); +int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen); +int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval, + size_t optlen); +int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen); +int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval, + size_t optlen) ; + int dhcp6_lease_new(sd_dhcp6_lease **ret); DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp6_lease*, sd_dhcp6_lease_unref); diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index ea863f45e4..6da7ea7e27 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -3,7 +3,7 @@ /*** This file is part of systemd. - Copyright (C) 2014 Intel Corporation. All rights reserved. + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -26,9 +26,11 @@ #include "sparse-endian.h" #include "unaligned.h" #include "util.h" +#include "strv.h" #include "dhcp6-internal.h" #include "dhcp6-protocol.h" +#include "dns-domain.h" #define DHCP6_OPTION_IA_NA_LEN 12 #define DHCP6_OPTION_IA_TA_LEN 4 @@ -317,3 +319,101 @@ error: return r; } + +int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen, + struct in6_addr **addrs, size_t count, + size_t *allocated) { + + if (optlen == 0 || optlen % sizeof(struct in6_addr) != 0) + return -EINVAL; + + if (!GREEDY_REALLOC(*addrs, *allocated, + count * sizeof(struct in6_addr) + optlen)) + return -ENOMEM; + + memcpy(*addrs + count, optval, optlen); + + count += optlen / sizeof(struct in6_addr); + + return count; +} + +int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, + char ***str_arr) +{ + size_t pos = 0, idx = 0; + _cleanup_free_ char **names = NULL; + int r; + + assert_return(optlen > 1, -ENODATA); + assert_return(optval[optlen] == '\0', -EINVAL); + + while (pos < optlen) { + _cleanup_free_ char *ret = NULL; + size_t n = 0, allocated = 0; + bool first = true; + + for (;;) { + uint8_t c; + + c = optval[pos++]; + + if (c == 0) + /* End of name */ + break; + else if (c <= 63) { + _cleanup_free_ char *t = NULL; + const char *label; + + /* Literal label */ + label = (const char *)&optval[pos]; + pos += c; + if (pos > optlen) + return -EMSGSIZE; + + r = dns_label_escape(label, c, &t); + if (r < 0) + goto fail; + + if (!GREEDY_REALLOC0(ret, allocated, n + !first + strlen(t) + 1)) { + r = -ENOMEM; + goto fail; + } + + if (!first) + ret[n++] = '.'; + else + first = false; + + memcpy(ret + n, t, r); + n += r; + continue; + } else { + r = -EBADMSG; + goto fail; + } + } + + if (!GREEDY_REALLOC(ret, allocated, n + 1)) { + r = -ENOMEM; + goto fail; + } + + ret[n] = 0; + + r = strv_extend(&names, ret); + if (r < 0) + goto fail; + + ret = NULL; + idx++; + } + + *str_arr = names; + names = NULL; + + return idx; + +fail: + return r; +} diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h index 3e0f339237..b3a28f88b4 100644 --- a/src/libsystemd-network/dhcp6-protocol.h +++ b/src/libsystemd-network/dhcp6-protocol.h @@ -123,7 +123,7 @@ enum { DHCP6_OPTION_DNS_SERVERS = 23, /* RFC 3646 */ DHCP6_OPTION_DOMAIN_LIST = 24, /* RFC 3646 */ - DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075 */ + DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075, deprecated */ /* option code 35 is unassigned */ @@ -134,6 +134,12 @@ enum { }; enum { + DHCP6_NTP_SUBOPTION_SRV_ADDR = 1, + DHCP6_NTP_SUBOPTION_MC_ADDR = 2, + DHCP6_NTP_SUBOPTION_SRV_FQDN = 3, +}; + +enum { DHCP6_STATUS_SUCCESS = 0, DHCP6_STATUS_UNSPEC_FAIL = 1, DHCP6_STATUS_NO_ADDRS_AVAIL = 2, diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 3d78bf8b35..d8357c687e 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -32,6 +32,7 @@ #include "conf-parser.h" #include "condition.h" #include "network-internal.h" +#include "sd-icmp6-nd.h" const char *net_get_name(struct udev_device *device) { const char *name, *field; @@ -384,6 +385,20 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) { return size; } +void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, + size_t size) { + unsigned i; + + assert(f); + assert(addresses); + assert(size); + + for (i = 0; i < size; i++) + fprintf(f, SD_ICMP6_ADDRESS_FORMAT_STR"%s", + SD_ICMP6_ADDRESS_FORMAT_VAL(addresses[i]), + (i < (size - 1)) ? " ": ""); +} + int deserialize_in6_addrs(struct in6_addr **ret, const char *string) { _cleanup_free_ struct in6_addr *addresses = NULL; int size = 0; diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index 7aaecbb10d..dca82646ce 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -67,6 +67,8 @@ const char *net_get_name(struct udev_device *device); void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size); int deserialize_in_addrs(struct in_addr **addresses, const char *string); +void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, + size_t size); int deserialize_in6_addrs(struct in6_addr **addresses, const char *string); /* don't include "dhcp-lease-internal.h" as it causes conflicts between netinet/ip.h and linux/ip.h */ diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index e2f5862851..bc17c6adc5 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -3,7 +3,7 @@ /*** This file is part of systemd. - Copyright (C) 2014 Intel Corporation. All rights reserved. + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -73,6 +73,7 @@ static const uint16_t default_req_opts[] = { DHCP6_OPTION_DNS_SERVERS, DHCP6_OPTION_DOMAIN_LIST, DHCP6_OPTION_NTP_SERVER, + DHCP6_OPTION_SNTP_SERVERS, }; const char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = { @@ -272,6 +273,11 @@ static void client_notify(sd_dhcp6_client *client, int event) { static int client_reset(sd_dhcp6_client *client) { assert_return(client, -EINVAL); + if (client->lease) { + dhcp6_lease_clear_timers(&client->lease->ia); + client->lease = sd_dhcp6_lease_unref(client->lease); + } + client->receive_message = sd_event_source_unref(client->receive_message); @@ -748,7 +754,36 @@ static int client_parse_message(sd_dhcp6_client *client, return r; break; + + case DHCP6_OPTION_DNS_SERVERS: + r = dhcp6_lease_set_dns(lease, optval, optlen); + if (r < 0) + return r; + + break; + + case DHCP6_OPTION_DOMAIN_LIST: + r = dhcp6_lease_set_domains(lease, optval, optlen); + if (r < 0) + return r; + + break; + + case DHCP6_OPTION_NTP_SERVER: + r = dhcp6_lease_set_ntp(lease, optval, optlen); + if (r < 0) + return r; + + break; + + case DHCP6_OPTION_SNTP_SERVERS: + r = dhcp6_lease_set_sntp(lease, optval, optlen); + if (r < 0) + return r; + + break; } + } if (r == -ENOMSG) @@ -802,10 +837,8 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, client->lease = sd_dhcp6_lease_unref(client->lease); } - if (client->state != DHCP6_STATE_INFORMATION_REQUEST) { - client->lease = lease; - lease = NULL; - } + client->lease = lease; + lease = NULL; return DHCP6_STATE_BOUND; } diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c index 2442269a3f..f0494b3c91 100644 --- a/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libsystemd-network/sd-dhcp6-lease.c @@ -1,8 +1,10 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + /*** This file is part of systemd. Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Intel Corporation. All rights reserved. + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -20,9 +22,11 @@ #include <errno.h> +#include "strv.h" #include "util.h" #include "dhcp6-lease-internal.h" +#include "dhcp6-protocol.h" int dhcp6_lease_clear_timers(DHCP6IA *ia) { assert_return(ia, -EINVAL); @@ -173,6 +177,189 @@ void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease) { lease->addr_iter = lease->ia.addresses; } +int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) { + int r; + + assert_return(lease, -EINVAL); + assert_return(optval, -EINVAL); + + if (!optlen) + return 0; + + r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->dns, + lease->dns_count, + &lease->dns_allocated); + if (r < 0) { + log_dhcp6_client(client, "Invalid DNS server option: %s", + strerror(-r)); + + return r; + } + + lease->dns_count = r; + + return 0; +} + +int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, struct in6_addr **addrs) { + assert_return(lease, -EINVAL); + assert_return(addrs, -EINVAL); + + if (lease->dns_count) { + *addrs = lease->dns; + return lease->dns_count; + } + + return -ENOENT; +} + +int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval, + size_t optlen) { + int r; + char **domains; + + assert_return(lease, -EINVAL); + assert_return(optval, -EINVAL); + + if (!optlen) + return 0; + + r = dhcp6_option_parse_domainname(optval, optlen, &domains); + if (r < 0) + return 0; + + free(lease->domains); + lease->domains = domains; + lease->domains_count = r; + + return r; +} + +int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains) { + assert_return(lease, -EINVAL); + assert_return(domains, -EINVAL); + + if (lease->domains_count) { + *domains = lease->domains; + return lease->domains_count; + } + + return -ENOENT; +} + +int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) +{ + int r; + uint16_t subopt; + size_t sublen; + uint8_t *subval; + + assert_return(lease, -EINVAL); + assert_return(optval, -EINVAL); + + free(lease->ntp); + lease->ntp_count = 0; + lease->ntp_allocated = 0; + + while ((r = dhcp6_option_parse(&optval, &optlen, &subopt, &sublen, + &subval)) >= 0) { + int s; + char **servers; + + switch(subopt) { + case DHCP6_NTP_SUBOPTION_SRV_ADDR: + case DHCP6_NTP_SUBOPTION_MC_ADDR: + if (sublen != 16) + return 0; + + s = dhcp6_option_parse_ip6addrs(subval, sublen, + &lease->ntp, + lease->ntp_count, + &lease->ntp_allocated); + if (s < 0) + return s; + + lease->ntp_count = s; + + break; + + case DHCP6_NTP_SUBOPTION_SRV_FQDN: + r = dhcp6_option_parse_domainname(subval, sublen, + &servers); + if (r < 0) + return 0; + + lease->ntp_fqdn = strv_free(lease->ntp_fqdn); + lease->ntp_fqdn = servers; + lease->ntp_fqdn_count = r; + + break; + } + } + + if (r != -ENOMSG) + return r; + + return 0; +} + +int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) { + int r; + + assert_return(lease, -EINVAL); + assert_return(optval, -EINVAL); + + if (!optlen) + return 0; + + if (lease->ntp || lease->ntp_fqdn) { + log_dhcp6_client(client, "NTP information already provided"); + + return 0; + } + + log_dhcp6_client(client, "Using deprecated SNTP information"); + + r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->ntp, + lease->ntp_count, + &lease->ntp_allocated); + if (r < 0) { + log_dhcp6_client(client, "Invalid SNTP server option: %s", + strerror(-r)); + + return r; + } + + lease->ntp_count = r; + + return 0; +} + +int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, + struct in6_addr **addrs) { + assert_return(lease, -EINVAL); + assert_return(addrs, -EINVAL); + + if (lease->ntp_count) { + *addrs = lease->ntp; + return lease->ntp_count; + } + + return -ENOENT; +} + +int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn) { + assert_return(lease, -EINVAL); + assert_return(ntp_fqdn, -EINVAL); + + if (lease->ntp_fqdn_count) { + *ntp_fqdn = lease->ntp_fqdn; + return lease->ntp_fqdn_count; + } + + return -ENOENT; +} + sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease) { if (lease) assert_se(REFCNT_INC(lease->n_ref) >= 2); @@ -185,6 +372,13 @@ sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) { free(lease->serverid); dhcp6_lease_free_ia(&lease->ia); + free(lease->dns); + + lease->domains = strv_free(lease->domains); + + free(lease->ntp); + + lease->ntp_fqdn = strv_free(lease->ntp_fqdn); free(lease); } diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c index 761854714b..6e62262443 100644 --- a/src/libsystemd-network/test-dhcp6-client.c +++ b/src/libsystemd-network/test-dhcp6-client.c @@ -73,7 +73,7 @@ static int test_client_basic(sd_event *e) { assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_CLIENTID) == -EINVAL); assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DNS_SERVERS) == -EEXIST); assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_NTP_SERVER) == -EEXIST); - assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_SNTP_SERVERS) == 0); + assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_SNTP_SERVERS) == -EEXIST); assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DOMAIN_LIST) == -EEXIST); assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL); @@ -216,6 +216,8 @@ static int test_advertise_option(sd_event *e) { uint32_t lt_pref, lt_valid; int r; bool opt_clientid = false; + struct in6_addr *addrs; + char **domains; if (verbose) printf("* %s\n", __FUNCTION__); @@ -276,6 +278,24 @@ static int test_advertise_option(sd_event *e) { break; + case DHCP6_OPTION_DNS_SERVERS: + assert_se(optlen == 16); + assert_se(dhcp6_lease_set_dns(lease, optval, + optlen) >= 0); + break; + + case DHCP6_OPTION_DOMAIN_LIST: + assert_se(optlen == 11); + assert_se(dhcp6_lease_set_domains(lease, optval, + optlen) >= 0); + break; + + case DHCP6_OPTION_SNTP_SERVERS: + assert_se(optlen == 16); + assert_se(dhcp6_lease_set_sntp(lease, optval, + optlen) >= 0); + break; + default: break; } @@ -315,6 +335,19 @@ static int test_advertise_option(sd_event *e) { assert_se(dhcp6_lease_get_preference(lease, &preference) >= 0); assert_se(preference == 0); + r = sd_dhcp6_lease_get_dns(lease, &addrs); + assert_se(r == 1); + assert_se(!memcmp(addrs, &msg_advertise[124], r * 16)); + + r = sd_dhcp6_lease_get_domains(lease, &domains); + assert_se(r == 1); + assert_se(!strcmp("lab.intra", domains[0])); + assert_se(domains[1] == NULL); + + r = sd_dhcp6_lease_get_ntp_addrs(lease, &addrs); + assert_se(r == 1); + assert_se(!memcmp(addrs, &msg_advertise[159], r * 16)); + return 0; } @@ -339,10 +372,25 @@ int detect_virtualization(const char **id) { static void test_client_solicit_cb(sd_dhcp6_client *client, int event, void *userdata) { sd_event *e = userdata; + sd_dhcp6_lease *lease; + struct in6_addr *addrs; + char **domains; assert_se(e); assert_se(event == DHCP6_EVENT_IP_ACQUIRE); + assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0); + + assert_se(sd_dhcp6_lease_get_domains(lease, &domains) == 1); + assert_se(!strcmp("lab.intra", domains[0])); + assert_se(domains[1] == NULL); + + assert_se(sd_dhcp6_lease_get_dns(lease, &addrs) == 1); + assert_se(!memcmp(addrs, &msg_advertise[124], 16)); + + assert_se(sd_dhcp6_lease_get_ntp_addrs(lease, &addrs) == 1); + assert_se(!memcmp(addrs, &msg_advertise[159], 16)); + assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DNS_SERVERS) == -EBUSY); if (verbose) @@ -524,10 +572,25 @@ static int test_client_verify_solicit(DHCP6Message *solicit, uint8_t *option, static void test_client_information_cb(sd_dhcp6_client *client, int event, void *userdata) { sd_event *e = userdata; + sd_dhcp6_lease *lease; + struct in6_addr *addrs; + char **domains; assert_se(e); assert_se(event == DHCP6_EVENT_INFORMATION_REQUEST); + assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0); + + assert_se(sd_dhcp6_lease_get_domains(lease, &domains) == 1); + assert_se(!strcmp("lab.intra", domains[0])); + assert_se(domains[1] == NULL); + + assert_se(sd_dhcp6_lease_get_dns(lease, &addrs) == 1); + assert_se(!memcmp(addrs, &msg_advertise[124], 16)); + + assert_se(sd_dhcp6_lease_get_ntp_addrs(lease, &addrs) == 1); + assert_se(!memcmp(addrs, &msg_advertise[159], 16)); + if (verbose) printf(" got DHCPv6 event %d\n", event); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 78e96c4e5b..91b9cdf30d 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2240,6 +2240,14 @@ int link_save(Link *link) { if (link->network) { char **address, **domain; bool space; + sd_dhcp6_lease *dhcp6_lease = NULL; + + if (link->dhcp6_client) { + r = sd_dhcp6_client_get_lease(link->dhcp6_client, + &dhcp6_lease); + if (r < 0) + log_link_debug(link, "No DHCPv6 lease"); + } fprintf(f, "NETWORK_FILE=%s\n", link->network->filename); @@ -2261,6 +2269,19 @@ int link_save(Link *link) { if (space) fputc(' ', f); serialize_in_addrs(f, addresses, r); + space = true; + } + } + + if (link->network->dhcp_dns && dhcp6_lease) { + struct in6_addr *in6_addrs; + + r = sd_dhcp6_lease_get_dns(dhcp6_lease, &in6_addrs); + if (r > 0) { + if (space) + fputc(' ', f); + serialize_in6_addrs(f, in6_addrs, r); + space = true; } } @@ -2284,6 +2305,32 @@ int link_save(Link *link) { if (space) fputc(' ', f); serialize_in_addrs(f, addresses, r); + space = true; + } + } + + if (link->network->dhcp_ntp && dhcp6_lease) { + struct in6_addr *in6_addrs; + char **hosts; + char **hostname; + + r = sd_dhcp6_lease_get_ntp_addrs(dhcp6_lease, + &in6_addrs); + if (r > 0) { + if (space) + fputc(' ', f); + serialize_in6_addrs(f, in6_addrs, r); + space = true; + } + + r = sd_dhcp6_lease_get_ntp_fqdn(dhcp6_lease, &hosts); + if (r > 0) { + STRV_FOREACH(hostname, hosts) { + if (space) + fputc(' ', f); + fputs(*hostname, f); + space = true; + } } } @@ -2307,6 +2354,21 @@ int link_save(Link *link) { if (space) fputc(' ', f); fputs(domainname, f); + space = true; + } + } + + if (link->network->dhcp_domains && dhcp6_lease) { + char **domains; + + r = sd_dhcp6_lease_get_domains(dhcp6_lease, &domains); + if (r >= 0) { + STRV_FOREACH(domain, domains) { + if (space) + fputc(' ', f); + fputs(*domain, f); + space = true; + } } } diff --git a/src/systemd/sd-dhcp6-lease.h b/src/systemd/sd-dhcp6-lease.h index 716d7678f1..dc3df3bbf7 100644 --- a/src/systemd/sd-dhcp6-lease.h +++ b/src/systemd/sd-dhcp6-lease.h @@ -7,7 +7,7 @@ This file is part of systemd. Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Intel Corporation. All rights reserved. + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -33,6 +33,12 @@ int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, uint32_t *lifetime_preferred, uint32_t *lifetime_valid); +int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, struct in6_addr **addrs); +int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains); +int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, + struct in6_addr **addrs); +int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn); + sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease); sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease); diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c index 8ec6adb493..1c3f03c803 100644 --- a/src/timedate/timedatectl.c +++ b/src/timedate/timedatectl.c @@ -96,7 +96,7 @@ static void print_status_info(const StatusInfo *i) { old_tz = strdupa(tz); /* Set the new $TZ */ - if (i->timezone && setenv("TZ", i->timezone, true) < 0) + if (setenv("TZ", isempty(i->timezone) ? "UTC" : i->timezone, true) < 0) log_warning_errno(errno, "Failed to set TZ environment variable, ignoring: %m"); else tzset(); |