networkd: DHCP client add support to send RELEASE packet
authorSusant Sahani <ssahani@gmail.com>
Mon, 13 May 2019 14:30:28 +0000 (20:00 +0530)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 14 May 2019 07:03:01 +0000 (09:03 +0200)
closes #10820

man/systemd.network.xml
src/libsystemd-network/sd-dhcp-client.c
src/network/networkd-dhcp4.c
src/network/networkd-network-gperf.gperf
src/network/networkd-network.h
src/systemd/sd-dhcp-client.h
test/fuzz/fuzz-network-parser/directives.network

index ca82f33..2f94dc5 100644 (file)
         </varlistentry>
 
         <varlistentry>
+          <term><varname>SendRelease=</varname></term>
+          <listitem>
+            <para>When true, the DHCPv4 client sends a DHCP release packet when it stops.
+            Defaults to false.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
           <term><varname>RapidCommit=</varname></term>
           <listitem>
             <para>Takes a boolean. The DHCPv6 client can obtain configuration parameters from a DHCPv6 server through
index 84ce8e0..6e077c0 100644 (file)
@@ -606,7 +606,7 @@ static int client_message_init(
         assert(ret);
         assert(_optlen);
         assert(_optoffset);
-        assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST));
+        assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE));
 
         optlen = DHCP_MIN_OPTIONS_SIZE;
         size = sizeof(DHCPPacket) + optlen;
@@ -697,7 +697,7 @@ static int client_message_init(
            MAY contain the Parameter Request List option. */
         /* NOTE: in case that there would be an option to do not send
          * any PRL at all, the size should be checked before sending */
-        if (client->req_opts_size > 0) {
+        if (client->req_opts_size > 0 && type != DHCP_RELEASE) {
                 r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
                                        SD_DHCP_OPTION_PARAMETER_REQUEST_LIST,
                                        client->req_opts_size, client->req_opts);
@@ -729,7 +729,7 @@ static int client_message_init(
          */
         /* RFC7844 section 3:
            SHOULD NOT contain any other option. */
-        if (!client->anonymize) {
+        if (!client->anonymize && type != DHCP_RELEASE) {
                 max_size = htobe16(size);
                 r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
                                        SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
@@ -861,6 +861,41 @@ static int client_send_discover(sd_dhcp_client *client) {
         return 0;
 }
 
+static int client_send_release(sd_dhcp_client *client) {
+        _cleanup_free_ DHCPPacket *release = NULL;
+        size_t optoffset, optlen;
+        int r;
+
+        assert(client);
+        assert(!IN_SET(client->state, DHCP_STATE_STOPPED));
+
+        r = client_message_init(client, &release, DHCP_RELEASE,
+                                &optlen, &optoffset);
+        if (r < 0)
+                return r;
+
+        /* Fill up release IP and MAC */
+        release->dhcp.ciaddr = client->lease->address;
+        memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
+
+        r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
+                               SD_DHCP_OPTION_END, 0, NULL);
+        if (r < 0)
+                return r;
+
+        r = dhcp_network_send_udp_socket(client->fd,
+                                         client->lease->server_address,
+                                         DHCP_PORT_SERVER,
+                                         &release->dhcp,
+                                         sizeof(DHCPMessage) + optoffset);
+        if (r < 0)
+                return r;
+
+        log_dhcp_client(client, "RELEASE");
+
+        return 0;
+}
+
 static int client_send_request(sd_dhcp_client *client) {
         _cleanup_free_ DHCPPacket *request = NULL;
         size_t optoffset, optlen;
@@ -1858,6 +1893,14 @@ int sd_dhcp_client_start(sd_dhcp_client *client) {
         return r;
 }
 
+int sd_dhcp_client_send_release(sd_dhcp_client *client) {
+        assert_return(client, -EINVAL);
+
+        client_send_release(client);
+
+        return 0;
+}
+
 int sd_dhcp_client_stop(sd_dhcp_client *client) {
         DHCP_CLIENT_DONT_DESTROY(client);
 
index 85e088e..81c6948 100644 (file)
@@ -564,6 +564,9 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
                                         return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
                         }
 
+                        if (link->network->dhcp_send_release)
+                                (void) sd_dhcp_client_send_release(client);
+
                         _fallthrough_;
                 case SD_DHCP_CLIENT_EVENT_EXPIRED:
                 case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
index a57d939..cbb1dd8 100644 (file)
@@ -149,6 +149,7 @@ DHCP.RouteTable,                        config_parse_section_route_table,
 DHCP.UseTimezone,                       config_parse_bool,                               0,                             offsetof(Network, dhcp_use_timezone)
 DHCP.IAID,                              config_parse_iaid,                               0,                             0
 DHCP.ListenPort,                        config_parse_uint16,                             0,                             offsetof(Network, dhcp_client_port)
+DHCP.SendRelease,                       config_parse_bool,                               0,                             offsetof(Network, dhcp_send_release)
 DHCP.RapidCommit,                       config_parse_bool,                               0,                             offsetof(Network, rapid_commit)
 DHCP.BlackList,                         config_parse_dhcp_black_listed_ip_address,       0,                             0
 DHCP.ForceDHCPv6PDOtherInformation,     config_parse_bool,                               0,                             offsetof(Network, dhcp6_force_pd_other_information)
index 9217e83..d00062f 100644 (file)
@@ -128,6 +128,7 @@ struct Network {
         bool rapid_commit;
         bool dhcp_use_hostname;
         bool dhcp_route_table_set;
+        bool dhcp_send_release;
         DHCPUseDomains dhcp_use_domains;
         Set *dhcp_black_listed_ip;
 
index 5dbfe8e..ab62368 100644 (file)
@@ -176,6 +176,7 @@ int sd_dhcp_client_get_lease(
 
 int sd_dhcp_client_stop(sd_dhcp_client *client);
 int sd_dhcp_client_start(sd_dhcp_client *client);
+int sd_dhcp_client_send_release(sd_dhcp_client *client);
 
 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client);
 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client);
index 5d48f08..3742d02 100644 (file)
@@ -64,6 +64,7 @@ ListenPort=
 UseTimezone=
 RouteTable=
 BlackList=
+SendRelease=
 [Route]
 Destination=
 Protocol=