Include configuration payloads for DNS/WINS server received via DHCP
authorMartin Willi <martin@revosec.ch>
Wed, 24 Mar 2010 14:28:14 +0000 (15:28 +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_transaction.c
src/libcharon/plugins/dhcp/dhcp_transaction.h

index a3a2895..dbcceb6 100644 (file)
@@ -131,7 +131,23 @@ METHOD(attribute_provider_t, release_address, bool,
 METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
        private_dhcp_provider_t *this, identification_t *id, host_t *vip)
 {
-       return enumerator_create_empty();
+       dhcp_transaction_t *transaction;
+
+       if (!vip)
+       {
+               return NULL;
+       }
+       this->mutex->lock(this->mutex);
+       transaction = this->transactions->get(this->transactions,
+                                                                                 (void*)hash_id_host(id, vip));
+       if (!transaction)
+       {
+               this->mutex->unlock(this->mutex);
+               return NULL;
+       }
+       return enumerator_create_cleaner(
+                                               transaction->create_attribute_enumerator(transaction),
+                                               (void*)this->mutex->unlock, this->mutex);
 }
 
 METHOD(dhcp_provider_t, destroy, void,
index b789e11..190024c 100644 (file)
@@ -446,7 +446,7 @@ METHOD(dhcp_socket_t, release, void,
  */
 static void handle_offer(private_dhcp_socket_t *this, dhcp_t *dhcp, int optlen)
 {
-       dhcp_transaction_t *transaction;
+       dhcp_transaction_t *transaction = NULL;
        enumerator_t *enumerator;
        host_t *offer, *server;
 
@@ -470,6 +470,34 @@ static void handle_offer(private_dhcp_socket_t *this, dhcp_t *dhcp, int optlen)
                }
        }
        enumerator->destroy(enumerator);
+
+       if (transaction)
+       {
+               int optsize, optpos = 0, pos;
+               dhcp_option_t *option;
+
+               while (optlen > sizeof(dhcp_option_t))
+               {
+                       option = (dhcp_option_t*)&dhcp->options[optpos];
+                       optsize = sizeof(dhcp_option_t) + option->len;
+                       if (option->type == DHCP_OPTEND || optlen < optsize)
+                       {
+                               break;
+                       }
+                       if (option->type == DHCP_DNS_SERVER ||
+                               option->type == DHCP_NBNS_SERVER)
+                       {
+                               for (pos = 0; pos + 4 <= option->len; pos += 4)
+                               {
+                                       transaction->add_attribute(transaction, option->type ==
+                                               DHCP_DNS_SERVER ? INTERNAL_IP4_DNS : INTERNAL_IP4_NBNS,
+                                               chunk_create((char*)&option->data[pos], 4));
+                               }
+                       }
+                       optlen -= optsize;
+                       optpos += optsize;
+               }
+       }
        this->mutex->unlock(this->mutex);
        this->condvar->broadcast(this->condvar);
        offer->destroy(offer);
index 27235ff..83f822d 100644 (file)
@@ -15,6 +15,8 @@
 
 #include "dhcp_transaction.h"
 
+#include <utils/linked_list.h>
+
 typedef struct private_dhcp_transaction_t private_dhcp_transaction_t;
 
 /**
@@ -46,8 +48,21 @@ struct private_dhcp_transaction_t {
         * discovered DHCP server address
         */
        host_t *server;
+
+       /**
+        * List of added attributes, as attribute_entry_t
+        */
+       linked_list_t *attributes;
 };
 
+/**
+ * Entry for an added attribute
+ */
+typedef struct {
+       configuration_attribute_type_t type;
+       chunk_t data;
+} attribute_entry_t;
+
 METHOD(dhcp_transaction_t, get_id, u_int32_t,
        private_dhcp_transaction_t *this)
 {
@@ -86,12 +101,56 @@ METHOD(dhcp_transaction_t, get_server, host_t*,
        return this->server;
 }
 
+METHOD(dhcp_transaction_t, add_attribute, void,
+       private_dhcp_transaction_t *this, configuration_attribute_type_t type,
+       chunk_t data)
+{
+       attribute_entry_t *entry;
+
+       INIT(entry,
+               .type = type,
+               .data = chunk_clone(data),
+       );
+       this->attributes->insert_last(this->attributes, entry);
+}
+
+/**
+ * Filter function to map entries to type/data
+ */
+static bool attribute_filter(void *null, attribute_entry_t **entry,
+                                                        configuration_attribute_type_t *type,
+                                                        void **dummy, chunk_t *data)
+{
+       *type = (*entry)->type;
+       *data = (*entry)->data;
+       return TRUE;
+}
+
+METHOD(dhcp_transaction_t, create_attribute_enumerator, enumerator_t*,
+       private_dhcp_transaction_t *this)
+{
+       return enumerator_create_filter(
+                                               this->attributes->create_enumerator(this->attributes),
+                                               (void*)attribute_filter, NULL, NULL);
+}
+
+/**
+ * Clean up an attribute entry
+ */
+static void attribute_entry_destroy(attribute_entry_t *entry)
+{
+       free(entry->data.ptr);
+       free(entry);
+}
+
 METHOD(dhcp_transaction_t, destroy, void,
        private_dhcp_transaction_t *this)
 {
        this->identity->destroy(this->identity);
        DESTROY_IF(this->address);
        DESTROY_IF(this->server);
+       this->attributes->destroy_function(this->attributes,
+                                                                          (void*)attribute_entry_destroy);
        free(this);
 }
 
@@ -111,10 +170,13 @@ dhcp_transaction_t *dhcp_transaction_create(u_int32_t id,
                        .get_address = _get_address,
                        .set_server = _set_server,
                        .get_server = _get_server,
+                       .add_attribute = _add_attribute,
+                       .create_attribute_enumerator = _create_attribute_enumerator,
                        .destroy = _destroy,
                },
                .id = id,
                .identity = identity->clone(identity),
+               .attributes = linked_list_create(),
        );
 
        return &this->public;
index e205720..19c163f 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <utils/host.h>
 #include <utils/identification.h>
+#include <attributes/attributes.h>
 
 typedef struct dhcp_transaction_t dhcp_transaction_t;
 
@@ -74,6 +75,22 @@ struct dhcp_transaction_t {
        host_t* (*get_server)(dhcp_transaction_t *this);
 
        /**
+        * An an additional attribute to serve to peer.
+        *
+        * @param type          type of attribute
+        * @param data          attribute data
+        */
+       void (*add_attribute)(dhcp_transaction_t *this,
+                                                 configuration_attribute_type_t type, chunk_t data);
+
+       /**
+        * Create an enumerator over added attributes.
+        *
+        * @return                      enumerator over (configuration_attribute_t, chunk_t)
+        */
+       enumerator_t* (*create_attribute_enumerator)(dhcp_transaction_t *this);
+
+       /**
         * Destroy a dhcp_transaction_t.
         */
        void (*destroy)(dhcp_transaction_t *this);