Send DHCP RELEASE on virtual IP release
authorMartin Willi <martin@revosec.ch>
Wed, 24 Mar 2010 13:52:11 +0000 (14:52 +0100)
committerMartin Willi <martin@revosec.ch>
Thu, 25 Mar 2010 13:29:10 +0000 (14:29 +0100)
src/libcharon/plugins/dhcp/dhcp_provider.c
src/libcharon/plugins/dhcp/dhcp_socket.c
src/libcharon/plugins/dhcp/dhcp_socket.h

index a3e2690..a3a2895 100644 (file)
@@ -120,6 +120,7 @@ METHOD(attribute_provider_t, release_address, bool,
                this->mutex->unlock(this->mutex);
                if (transaction)
                {
+                       this->socket->release(this->socket, transaction);
                        transaction->destroy(transaction);
                        return TRUE;
                }
index 8921228..b789e11 100644 (file)
@@ -123,7 +123,9 @@ typedef enum {
  * Some DHCP options used
  */
 typedef enum {
+       DHCP_DNS_SERVER = 6,
        DHCP_HOST_NAME = 12,
+       DHCP_NBNS_SERVER = 44,
        DHCP_REQUESTED_IP = 50,
        DHCP_MESSAGE_TYPE = 53,
        DHCP_SERVER_ID = 54,
@@ -144,15 +146,6 @@ typedef enum {
        DHCP_RELEASE = 7,
        DHCP_INFORM = 8,
 } dhcp_message_type_t;
-
-/**
- * DHCP parameters in the DHCP_PARAM_REQ_LIST option
- */
-typedef enum {
-       DHCP_ROUTER = 3,
-       DHCP_DNS_SERVER = 6,
-} dhcp_parameter_t;
-
 /**
  * DHCP option encoding, a TLV
  */
@@ -251,13 +244,6 @@ static int prepare_dhcp(private_dhcp_socket_t *this,
        memcpy(option->data, chunk.ptr, option->len);
        optlen += sizeof(dhcp_option_t) + option->len;
 
-       option = (dhcp_option_t*)&dhcp->options[optlen];
-       option->type = DHCP_PARAM_REQ_LIST;
-       option->len = 2;
-       option->data[0] = DHCP_ROUTER;
-       option->data[1] = DHCP_DNS_SERVER;
-       optlen += sizeof(dhcp_option_t) + option->len;
-
        return optlen;
 }
 
@@ -286,6 +272,7 @@ static bool send_dhcp(private_dhcp_socket_t *this,
 static bool discover(private_dhcp_socket_t *this,
                                         dhcp_transaction_t *transaction)
 {
+       dhcp_option_t *option;
        dhcp_t dhcp;
        int optlen;
 
@@ -293,6 +280,13 @@ static bool discover(private_dhcp_socket_t *this,
 
        DBG1(DBG_CFG, "sending DHCP DISCOVER to %H", this->dst);
 
+       option = (dhcp_option_t*)&dhcp.options[optlen];
+       option->type = DHCP_PARAM_REQ_LIST;
+       option->len = 2;
+       option->data[0] = DHCP_DNS_SERVER;
+       option->data[1] = DHCP_NBNS_SERVER;
+       optlen += sizeof(dhcp_option_t) + option->len;
+
        dhcp.options[optlen++] = DHCP_OPTEND;
 
        if (!send_dhcp(this, transaction, &dhcp, optlen))
@@ -339,6 +333,13 @@ static bool request(private_dhcp_socket_t *this,
        memcpy(option->data, chunk.ptr, min(chunk.len, option->len));
        optlen += sizeof(dhcp_option_t) + option->len;
 
+       option = (dhcp_option_t*)&dhcp.options[optlen];
+       option->type = DHCP_PARAM_REQ_LIST;
+       option->len = 2;
+       option->data[0] = DHCP_DNS_SERVER;
+       option->data[1] = DHCP_NBNS_SERVER;
+       optlen += sizeof(dhcp_option_t) + option->len;
+
        dhcp.options[optlen++] = DHCP_OPTEND;
 
        if (!send_dhcp(this, transaction, &dhcp, optlen))
@@ -402,6 +403,44 @@ METHOD(dhcp_socket_t, enroll, dhcp_transaction_t*,
        return transaction;
 }
 
+METHOD(dhcp_socket_t, release, void,
+       private_dhcp_socket_t *this, dhcp_transaction_t *transaction)
+{
+       dhcp_option_t *option;
+       dhcp_t dhcp;
+       host_t *release, *server;
+       chunk_t chunk;
+       int optlen;
+
+       optlen = prepare_dhcp(this, transaction, DHCP_RELEASE, &dhcp);
+
+       release = transaction->get_address(transaction);
+       server = transaction->get_server(transaction);
+       if (!release || !server)
+       {
+               return;
+       }
+       DBG1(DBG_CFG, "sending DHCP RELEASE for %H to %H", release, server);
+
+       chunk = release->get_address(release);
+       memcpy(&dhcp.client_address, chunk.ptr,
+                  min(chunk.len, sizeof(dhcp.client_address)));
+
+       option = (dhcp_option_t*)&dhcp.options[optlen];
+       option->type = DHCP_SERVER_ID;
+       option->len = 4;
+       chunk = server->get_address(server);
+       memcpy(option->data, chunk.ptr, min(chunk.len, option->len));
+       optlen += sizeof(dhcp_option_t) + option->len;
+
+       dhcp.options[optlen++] = DHCP_OPTEND;
+
+       if (!send_dhcp(this, transaction, &dhcp, optlen))
+       {
+               DBG1(DBG_CFG, "sending DHCP RELEASE failed: %s", strerror(errno));
+       }
+}
+
 /**
  * Handle a DHCP OFFER
  */
@@ -596,6 +635,7 @@ dhcp_socket_t *dhcp_socket_create()
        INIT(this,
                .public = {
                        .enroll = _enroll,
+                       .release = _release,
                        .destroy = _destroy,
                },
                .rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK),
index 687e95b..0a8398a 100644 (file)
@@ -40,6 +40,13 @@ struct dhcp_socket_t {
                                                                  identification_t *identity);
 
        /**
+        * Release an enrolled DHCP address.
+        *
+        * @param transaction   transaction returned by enroll
+        */
+       void (*release)(dhcp_socket_t *this, dhcp_transaction_t *transaction);
+
+       /**
         * Destroy a dhcp_socket_t.
         */
        void (*destroy)(dhcp_socket_t *this);