Merge branch 'radius-ext'
authorMartin Willi <martin@revosec.ch>
Mon, 18 Mar 2013 09:13:36 +0000 (10:13 +0100)
committerMartin Willi <martin@revosec.ch>
Mon, 18 Mar 2013 09:13:36 +0000 (10:13 +0100)
Bring some extensions to eap-radius, namely a virtual IP address provider based
on received Framed-IPs, forwarding of Cisco Unity banners, Interim Accounting
updates and the reporting of sent/received packets.

13 files changed:
src/ipsec/_ipsec.in
src/libcharon/control/controller.c
src/libcharon/plugins/stroke/stroke_control.c
src/libcharon/plugins/stroke/stroke_counter.c
src/libcharon/plugins/stroke/stroke_counter.h
src/libcharon/plugins/stroke/stroke_socket.c
src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c
src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.h
src/stroke/stroke.c
src/stroke/stroke_keywords.h
src/stroke/stroke_keywords.txt
src/stroke/stroke_msg.h

index 8b6ad66..6b406f6 100644 (file)
@@ -59,7 +59,8 @@ case "$1" in
        echo "  listalgs|listpubkeys|listcerts [--utc]"
        echo "  listcacerts|listaacerts|listocspcerts [--utc]"
        echo "  listacerts|listgroups|listcainfos [--utc]"
-       echo "  listcrls|listocsp|listcards|listplugins|listcounters|listall [--utc]"
+       echo "  listcrls|listocsp|listcards|listplugins|listall [--utc]"
+       echo "  listcounters|resetcounters [name]"
        echo "  leases [<poolname> [<address>]]"
        echo "  rereadsecrets|rereadgroups"
        echo "  rereadcacerts|rereadaacerts|rereadocspcerts"
@@ -149,10 +150,10 @@ leases)
 listalgs|listpubkeys|listplugins|\
 listcerts|listcacerts|listaacerts|\
 listacerts|listgroups|listocspcerts|\
-listcainfos|listcrls|listocsp|listcounters|listall|\
+listcainfos|listcrls|listocsp|listall|\
 rereadsecrets|rereadcacerts|rereadaacerts|\
 rereadacerts|rereadocspcerts|rereadcrls|\
-rereadall|purgeocsp)
+rereadall|purgeocsp|listcounters|resetcounters)
        op="$1"
        rc=7
        shift
index 77d73db..0ee99c4 100644 (file)
@@ -363,7 +363,10 @@ METHOD(job_t, initiate_execute, job_requeue_t,
 
        if (ike_sa->initiate(ike_sa, listener->child_cfg, 0, NULL, NULL) == SUCCESS)
        {
-               listener->status = SUCCESS;
+               if (!listener->logger.callback)
+               {
+                       listener->status = SUCCESS;
+               }
                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
        }
        else
@@ -454,7 +457,10 @@ METHOD(job_t, terminate_ike_execute, job_requeue_t,
        }
        else
        {
-               listener->status = SUCCESS;
+               if (!listener->logger.callback)
+               {
+                       listener->status = SUCCESS;
+               }
                charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
                                                                                                        ike_sa);
        }
@@ -561,7 +567,10 @@ METHOD(job_t, terminate_child_execute, job_requeue_t,
        if (ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa),
                                        child_sa->get_spi(child_sa, TRUE), FALSE) != DESTROY_ME)
        {
-               listener->status = SUCCESS;
+               if (!listener->logger.callback)
+               {
+                       listener->status = SUCCESS;
+               }
                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
        }
        else
@@ -657,4 +666,3 @@ controller_t *controller_create(void)
 
        return &this->public;
 }
-
index 233d408..91130d1 100644 (file)
@@ -33,6 +33,11 @@ struct private_stroke_control_t {
         * public functions
         */
        stroke_control_t public;
+
+       /**
+        * Timeout for stroke commands, im ms
+        */
+       u_int timeout;
 };
 
 
@@ -97,8 +102,8 @@ static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
 /**
  * call the charon controller to initiate the connection
  */
-static void charon_initiate(peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
-                                                       stroke_msg_t *msg, FILE *out)
+static void charon_initiate(private_stroke_control_t *this, peer_cfg_t *peer_cfg,
+                                                       child_cfg_t *child_cfg, stroke_msg_t *msg, FILE *out)
 {
        if (msg->output_verbosity < 0)
        {
@@ -108,9 +113,27 @@ static void charon_initiate(peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
        else
        {
                stroke_log_info_t info = { msg->output_verbosity, out };
+               status_t status;
 
-               charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
-                                                                        (controller_cb_t)stroke_log, &info, 0);
+               status = charon->controller->initiate(charon->controller,
+                                                       peer_cfg, child_cfg, (controller_cb_t)stroke_log,
+                                                       &info, this->timeout);
+               switch (status)
+               {
+                       case SUCCESS:
+                               fprintf(out, "connection '%s' established successfully\n",
+                                               msg->initiate.name);
+                               break;
+                       case OUT_OF_RES:
+                               fprintf(out, "connection '%s' not established after %dms, "
+                                               "detaching\n", msg->initiate.name, this->timeout);
+                               break;
+                       default:
+                       case FAILED:
+                               fprintf(out, "establishing connection '%s' failed\n",
+                                               msg->initiate.name);
+                               break;
+               }
        }
 }
 
@@ -133,7 +156,7 @@ METHOD(stroke_control_t, initiate, void,
                        while (enumerator->enumerate(enumerator, &child_cfg))
                        {
                                empty = FALSE;
-                               charon_initiate(peer_cfg->get_ref(peer_cfg),
+                               charon_initiate(this, peer_cfg->get_ref(peer_cfg),
                                                                child_cfg->get_ref(child_cfg), msg, out);
                        }
                        enumerator->destroy(enumerator);
@@ -169,7 +192,7 @@ METHOD(stroke_control_t, initiate, void,
                        return;
                }
        }
-       charon_initiate(peer_cfg, child_cfg, msg, out);
+       charon_initiate(this, peer_cfg, child_cfg, msg, out);
 }
 
 /**
@@ -239,6 +262,41 @@ static bool parse_specifier(char *string, u_int32_t *id,
        return TRUE;
 }
 
+/**
+ * Report the result of a terminate() call to console
+ */
+static void report_terminate_status(private_stroke_control_t *this,
+                                               status_t status, FILE *out, u_int32_t id, bool child)
+{
+       char *prefix, *postfix;
+
+       if (child)
+       {
+               prefix = "CHILD_SA {";
+               postfix = "}";
+       }
+       else
+       {
+               prefix = "IKE_SA [";
+               postfix = "]";
+       }
+
+       switch (status)
+       {
+               case SUCCESS:
+                       fprintf(out, "%s%d%s closed successfully\n", prefix, id, postfix);
+                       break;
+               case OUT_OF_RES:
+                       fprintf(out, "%s%d%s not closed after %dms, detaching\n",
+                                       prefix, id, postfix, this->timeout);
+                       break;
+               default:
+               case FAILED:
+                       fprintf(out, "closing %s%d%s failed\n", prefix, id, postfix);
+                       break;
+       }
+}
+
 METHOD(stroke_control_t, terminate, void,
        private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
 {
@@ -250,6 +308,7 @@ METHOD(stroke_control_t, terminate, void,
        linked_list_t *ike_list, *child_list;
        stroke_log_info_t info;
        uintptr_t del;
+       status_t status;
 
        if (!parse_specifier(msg->terminate.name, &id, &name, &child, &all))
        {
@@ -264,15 +323,15 @@ METHOD(stroke_control_t, terminate, void,
        {
                if (child)
                {
-                       charon->controller->terminate_child(charon->controller, id,
-                                                                       (controller_cb_t)stroke_log, &info, 0);
+                       status = charon->controller->terminate_child(charon->controller, id,
+                                                       (controller_cb_t)stroke_log, &info, this->timeout);
                }
                else
                {
-                       charon->controller->terminate_ike(charon->controller, id,
-                                                                       (controller_cb_t)stroke_log, &info, 0);
+                       status = charon->controller->terminate_ike(charon->controller, id,
+                                                       (controller_cb_t)stroke_log, &info, this->timeout);
                }
-               return;
+               return report_terminate_status(this, status, out, id, child);
        }
 
        ike_list = linked_list_create();
@@ -320,16 +379,18 @@ METHOD(stroke_control_t, terminate, void,
        enumerator = child_list->create_enumerator(child_list);
        while (enumerator->enumerate(enumerator, &del))
        {
-               charon->controller->terminate_child(charon->controller, del,
-                                                                       (controller_cb_t)stroke_log, &info, 0);
+               status = charon->controller->terminate_child(charon->controller, del,
+                                                       (controller_cb_t)stroke_log, &info, this->timeout);
+               report_terminate_status(this, status, out, del, TRUE);
        }
        enumerator->destroy(enumerator);
 
        enumerator = ike_list->create_enumerator(ike_list);
        while (enumerator->enumerate(enumerator, &del))
        {
-               charon->controller->terminate_ike(charon->controller, del,
-                                                                       (controller_cb_t)stroke_log, &info, 0);
+               status = charon->controller->terminate_ike(charon->controller, del,
+                                                       (controller_cb_t)stroke_log, &info, this->timeout);
+               report_terminate_status(this, status, out, del, FALSE);
        }
        enumerator->destroy(enumerator);
 
@@ -487,6 +548,7 @@ METHOD(stroke_control_t, purge_ike, void,
        linked_list_t *list;
        uintptr_t del;
        stroke_log_info_t info;
+       status_t status;
 
        info.out = out;
        info.level = msg->output_verbosity;
@@ -509,8 +571,9 @@ METHOD(stroke_control_t, purge_ike, void,
        enumerator = list->create_enumerator(list);
        while (enumerator->enumerate(enumerator, &del))
        {
-               charon->controller->terminate_ike(charon->controller, del,
-                                                                       (controller_cb_t)stroke_log, &info, 0);
+               status = charon->controller->terminate_ike(charon->controller, del,
+                                                       (controller_cb_t)stroke_log, &info, this->timeout);
+               report_terminate_status(this, status, out, del, TRUE);
        }
        enumerator->destroy(enumerator);
        list->destroy(list);
@@ -670,8 +733,9 @@ stroke_control_t *stroke_control_create()
                        .unroute = _unroute,
                        .destroy = _destroy,
                },
+               .timeout = lib->settings->get_int(lib->settings,
+                                                               "%s.plugins.stroke.timeout", 0, charon->name),
        );
 
        return &this->public;
 }
-
index 56eda94..ff4746b 100644 (file)
@@ -16,6 +16,7 @@
 #include "stroke_counter.h"
 
 #include <threading/spinlock.h>
+#include <collections/hashtable.h>
 
 ENUM(stroke_counter_type_names,
        COUNTER_INIT_IKE_SA_REKEY, COUNTER_OUT_INFORMATIONAL_RSP,
@@ -55,16 +56,111 @@ struct private_stroke_counter_t {
        stroke_counter_t public;
 
        /**
-        * Counter values
+        * Global counter values
         */
        u_int64_t counter[COUNTER_MAX];
 
        /**
+        * Counters for specific connection names, char* => entry_t
+        */
+       hashtable_t *conns;
+
+       /**
         * Lock for counter values
         */
        spinlock_t *lock;
 };
 
+/**
+ * Counters for a specific connection name
+ */
+typedef struct {
+       /** connection name */
+       char *name;
+       /** counter values for connection */
+       u_int64_t counter[COUNTER_MAX];
+} entry_t;
+
+/**
+ * Destroy named entry
+ */
+static void destroy_entry(entry_t *this)
+{
+       free(this->name);
+       free(this);
+}
+
+/**
+ * Hashtable hash function
+ */
+static u_int hash(char *name)
+{
+       return chunk_hash(chunk_from_str(name));
+}
+
+/**
+ * Hashtable equals function
+ */
+static bool equals(char *a, char *b)
+{
+       return streq(a, b);
+}
+
+/**
+ * Get the name of an IKE_SA, but return NULL if it is not known yet
+ */
+static char *get_ike_sa_name(ike_sa_t *ike_sa)
+{
+       peer_cfg_t *peer_cfg;
+
+       peer_cfg = ike_sa->get_peer_cfg(ike_sa);
+       if (peer_cfg)
+       {
+               return peer_cfg->get_name(peer_cfg);
+       }
+       return NULL;
+}
+
+/**
+ * Increase a counter for a named entry
+ */
+static void count_named(private_stroke_counter_t *this,
+                                               ike_sa_t *ike_sa, stroke_counter_type_t type)
+{
+       entry_t *entry;
+       char *name;
+
+       name = get_ike_sa_name(ike_sa);
+       if (name)
+       {
+               entry = this->conns->get(this->conns, name);
+               if (!entry)
+               {
+                       INIT(entry,
+                               .name = strdup(name),
+                       );
+                       this->conns->put(this->conns, entry->name, entry);
+               }
+               entry->counter[type]++;
+       }
+}
+
+/**
+ * Get a counter value for a specific connection name
+ */
+static u_int64_t get_named_count(private_stroke_counter_t *this,
+                                                                char *name, stroke_counter_type_t type)
+{
+       entry_t *entry;
+
+       entry = this->conns->get(this->conns, name);
+       if (entry)
+       {
+               return entry->counter[type];
+       }
+       return 0;
+}
+
 METHOD(listener_t, alert, bool,
        private_stroke_counter_t *this, ike_sa_t *ike_sa,
        alert_t alert, va_list args)
@@ -86,6 +182,7 @@ METHOD(listener_t, alert, bool,
 
        this->lock->lock(this->lock);
        this->counter[type]++;
+       count_named(this, ike_sa, type);
        this->lock->unlock(this->lock);
 
        return TRUE;
@@ -109,6 +206,7 @@ METHOD(listener_t, ike_rekey, bool,
 
        this->lock->lock(this->lock);
        this->counter[type]++;
+       count_named(this, old, type);
        this->lock->unlock(this->lock);
 
        return TRUE;
@@ -120,6 +218,7 @@ METHOD(listener_t, child_rekey, bool,
 {
        this->lock->lock(this->lock);
        this->counter[COUNTER_CHILD_SA_REKEY]++;
+       count_named(this, ike_sa, COUNTER_CHILD_SA_REKEY);
        this->lock->unlock(this->lock);
 
        return TRUE;
@@ -194,13 +293,14 @@ METHOD(listener_t, message_hook, bool,
 
        this->lock->lock(this->lock);
        this->counter[type]++;
+       count_named(this, ike_sa, type);
        this->lock->unlock(this->lock);
 
        return TRUE;
 }
 
 METHOD(stroke_counter_t, print, void,
-       private_stroke_counter_t *this, FILE *out)
+       private_stroke_counter_t *this, FILE *out, char *name)
 {
        u_int64_t counter[COUNTER_MAX];
        int i;
@@ -209,11 +309,25 @@ METHOD(stroke_counter_t, print, void,
        this->lock->lock(this->lock);
        for (i = 0; i < countof(this->counter); i++)
        {
-               counter[i] = this->counter[i];
+               if (name)
+               {
+                       counter[i] = get_named_count(this, name, i);
+               }
+               else
+               {
+                       counter[i] = this->counter[i];
+               }
        }
        this->lock->unlock(this->lock);
 
-       fprintf(out, "\nList of IKE counters:\n\n");
+       if (name)
+       {
+               fprintf(out, "\nList of IKE counters for '%s':\n\n", name);
+       }
+       else
+       {
+               fprintf(out, "\nList of IKE counters:\n\n");
+       }
 
        /* but do blocking write without the lock. */
        for (i = 0; i < countof(this->counter); i++)
@@ -222,9 +336,41 @@ METHOD(stroke_counter_t, print, void,
        }
 }
 
+METHOD(stroke_counter_t, reset, void,
+       private_stroke_counter_t *this, char *name)
+{
+       this->lock->lock(this->lock);
+       if (name)
+       {
+               entry_t *entry;
+
+               entry = this->conns->remove(this->conns, name);
+               if (entry)
+               {
+                       destroy_entry(entry);
+               }
+       }
+       else
+       {
+               memset(&this->counter, 0, sizeof(this->counter));
+       }
+       this->lock->unlock(this->lock);
+}
+
 METHOD(stroke_counter_t, destroy, void,
        private_stroke_counter_t *this)
 {
+       enumerator_t *enumerator;
+       char *name;
+       entry_t *entry;
+
+       enumerator = this->conns->create_enumerator(this->conns);
+       while (enumerator->enumerate(enumerator, &name, &entry))
+       {
+               destroy_entry(entry);
+       }
+       enumerator->destroy(enumerator);
+       this->conns->destroy(this->conns);
        this->lock->destroy(this->lock);
        free(this);
 }
@@ -245,8 +391,11 @@ stroke_counter_t *stroke_counter_create()
                                .message = _message_hook,
                        },
                        .print = _print,
+                       .reset = _reset,
                        .destroy = _destroy,
                },
+               .conns = hashtable_create((hashtable_hash_t)hash,
+                                                                 (hashtable_equals_t)equals, 4),
                .lock = spinlock_create(),
        );
 
index efaae0d..fecf39f 100644 (file)
@@ -87,8 +87,16 @@ struct stroke_counter_t {
         * Print counter values to an output stream.
         *
         * @param out           output stream to write to
+        * @param name          connection name to get counters for, NULL for global
         */
-       void (*print)(stroke_counter_t *this, FILE *out);
+       void (*print)(stroke_counter_t *this, FILE *out, char *name);
+
+       /**
+        * Reset global or connection specific counters.
+        *
+        * @param name          name of connection counters to reset, NULL for global
+        */
+       void (*reset)(stroke_counter_t *this, char *name);
 
        /**
         * Destroy a stroke_counter_t.
index e31616c..aa5c73b 100644 (file)
@@ -388,17 +388,14 @@ static void stroke_status(private_stroke_socket_t *this,
 /**
  * list various information
  */
-static void stroke_list(private_stroke_socket_t *this, stroke_msg_t *msg, FILE *out)
+static void stroke_list(private_stroke_socket_t *this, stroke_msg_t *msg,
+                                               FILE *out)
 {
        if (msg->list.flags & LIST_CAINFOS)
        {
                this->ca->list(this->ca, msg, out);
        }
        this->list->list(this->list, msg, out);
-       if (msg->list.flags & LIST_COUNTERS)
-       {
-               this->counter->print(this->counter, out);
-       }
 }
 
 /**
@@ -505,6 +502,24 @@ static void stroke_user_creds(private_stroke_socket_t *this,
 }
 
 /**
+ * Print stroke counter values
+ */
+static void stroke_counters(private_stroke_socket_t *this,
+                                                         stroke_msg_t *msg, FILE *out)
+{
+       pop_string(msg, &msg->counters.name);
+
+       if (msg->counters.reset)
+       {
+               this->counter->reset(this->counter, msg->counters.name);
+       }
+       else
+       {
+               this->counter->print(this->counter, out, msg->counters.name);
+       }
+}
+
+/**
  * set the verbosity debug output
  */
 static void stroke_loglevel(private_stroke_socket_t *this,
@@ -672,6 +687,9 @@ static job_requeue_t process(stroke_job_context_t *ctx)
                case STR_USER_CREDS:
                        stroke_user_creds(this, msg, out);
                        break;
+               case STR_COUNTERS:
+                       stroke_counters(this, msg, out);
+                       break;
                default:
                        DBG1(DBG_CFG, "received unknown stroke");
                        break;
@@ -862,4 +880,3 @@ stroke_socket_t *stroke_socket_create()
 
        return &this->public;
 }
-
index 8e90e01..9b4ade5 100644 (file)
 #define XFRM_RTA(nlh, x) ((struct rtattr*)(NLMSG_DATA(nlh) + \
                                                                                   NLMSG_ALIGN(sizeof(x))))
 /**
- * Returns a pointer to the next rtattr following rta.
- * !!! Do not use this to parse messages. Use RTA_NEXT and RTA_OK instead !!!
- */
-#define XFRM_RTA_NEXT(rta) ((struct rtattr*)(((char*)(rta)) + \
-                                                                                        RTA_ALIGN((rta)->rta_len)))
-/**
  * Returns the total size of attached rta data
  * (after 'usual' netlink data x like 'struct xfrm_usersa_info')
  */
@@ -176,8 +170,6 @@ ENUM(xfrm_attr_type_names, XFRMA_UNSPEC, XFRMA_REPLAY_ESN_VAL,
        "XFRMA_REPLAY_ESN_VAL",
 );
 
-#define END_OF_LIST -1
-
 /**
  * Algorithms for encryption
  */
@@ -208,7 +200,6 @@ static kernel_algorithm_t encryption_algs[] = {
 /*     {ENCR_CAMELLIA_CCM_ICV16,       "***"                           }, */
        {ENCR_SERPENT_CBC,                      "serpent"                       },
        {ENCR_TWOFISH_CBC,                      "twofish"                       },
-       {END_OF_LIST,                           NULL                            }
 };
 
 /**
@@ -226,7 +217,6 @@ static kernel_algorithm_t integrity_algs[] = {
 /*     {AUTH_DES_MAC,                          "***"                           }, */
 /*     {AUTH_KPDK_MD5,                         "***"                           }, */
        {AUTH_AES_XCBC_96,                      "xcbc(aes)"                     },
-       {END_OF_LIST,                           NULL                            }
 };
 
 /**
@@ -237,7 +227,6 @@ static kernel_algorithm_t compression_algs[] = {
        {IPCOMP_DEFLATE,                        "deflate"                       },
        {IPCOMP_LZS,                            "lzs"                           },
        {IPCOMP_LZJH,                           "lzjh"                          },
-       {END_OF_LIST,                           NULL                            }
 };
 
 /**
@@ -246,33 +235,39 @@ static kernel_algorithm_t compression_algs[] = {
 static char* lookup_algorithm(transform_type_t type, int ikev2)
 {
        kernel_algorithm_t *list;
-       char *name = NULL;
+       int i, count;
+       char *name;
 
        switch (type)
        {
                case ENCRYPTION_ALGORITHM:
                        list = encryption_algs;
+                       count = countof(encryption_algs);
                        break;
                case INTEGRITY_ALGORITHM:
                        list = integrity_algs;
+                       count = countof(integrity_algs);
                        break;
                case COMPRESSION_ALGORITHM:
                        list = compression_algs;
+                       count = countof(compression_algs);
                        break;
                default:
                        return NULL;
        }
-       while (list->ikev2 != END_OF_LIST)
+       for (i = 0; i < count; i++)
        {
-               if (list->ikev2 == ikev2)
+               if (list[i].ikev2 == ikev2)
                {
-                       return list->name;
+                       return list[i].name;
                }
-               list++;
        }
-       hydra->kernel_interface->lookup_algorithm(hydra->kernel_interface, ikev2,
-                                                                                         type, NULL, &name);
-       return name;
+       if (hydra->kernel_interface->lookup_algorithm(hydra->kernel_interface,
+                                                                                                 ikev2, type, NULL, &name))
+       {
+               return name;
+       }
+       return NULL;
 }
 
 typedef struct private_kernel_netlink_ipsec_t private_kernel_netlink_ipsec_t;
@@ -1150,6 +1145,26 @@ METHOD(kernel_ipsec_t, get_cpi, status_t,
        return SUCCESS;
 }
 
+/**
+ * Add a XFRM mark to message if required
+ */
+static bool add_mark(struct nlmsghdr *hdr, int buflen, mark_t mark)
+{
+       if (mark.value)
+       {
+               struct xfrm_mark *xmrk;
+
+               xmrk = netlink_reserve(hdr, buflen, XFRMA_MARK, sizeof(*xmrk));
+               if (!xmrk)
+               {
+                       return FALSE;
+               }
+               xmrk->v = mark.value;
+               xmrk->m = mark.mask;
+       }
+       return TRUE;
+}
+
 METHOD(kernel_ipsec_t, add_sa, status_t,
        private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
        u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
@@ -1222,8 +1237,6 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
        sa->lft.soft_use_expires_seconds = 0;
        sa->lft.hard_use_expires_seconds = 0;
 
-       struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_info);
-
        switch (enc_alg)
        {
                case ENCR_UNDEFINED:
@@ -1256,23 +1269,17 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                        DBG2(DBG_KNL, "  using encryption algorithm %N with key size %d",
                                 encryption_algorithm_names, enc_alg, enc_key.len * 8);
 
-                       rthdr->rta_type = XFRMA_ALG_AEAD;
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) +
-                                                                               enc_key.len);
-                       hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
-                       if (hdr->nlmsg_len > sizeof(request))
+                       algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AEAD,
+                                                                  sizeof(*algo) + enc_key.len);
+                       if (!algo)
                        {
                                goto failed;
                        }
-
-                       algo = (struct xfrm_algo_aead*)RTA_DATA(rthdr);
                        algo->alg_key_len = enc_key.len * 8;
                        algo->alg_icv_len = icv_size;
                        strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
                        algo->alg_name[sizeof(algo->alg_name) - 1] = '\0';
                        memcpy(algo->alg_key, enc_key.ptr, enc_key.len);
-
-                       rthdr = XFRM_RTA_NEXT(rthdr);
                        break;
                }
                default:
@@ -1289,21 +1296,16 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                        DBG2(DBG_KNL, "  using encryption algorithm %N with key size %d",
                                 encryption_algorithm_names, enc_alg, enc_key.len * 8);
 
-                       rthdr->rta_type = XFRMA_ALG_CRYPT;
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + enc_key.len);
-                       hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
-                       if (hdr->nlmsg_len > sizeof(request))
+                       algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_CRYPT,
+                                                                  sizeof(*algo) + enc_key.len);
+                       if (!algo)
                        {
                                goto failed;
                        }
-
-                       algo = (struct xfrm_algo*)RTA_DATA(rthdr);
                        algo->alg_key_len = enc_key.len * 8;
                        strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
                        algo->alg_name[sizeof(algo->alg_name) - 1] = '\0';
                        memcpy(algo->alg_key, enc_key.ptr, enc_key.len);
-
-                       rthdr = XFRM_RTA_NEXT(rthdr);
                }
        }
 
@@ -1341,17 +1343,12 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                        /* the kernel uses SHA256 with 96 bit truncation by default,
                         * use specified truncation size supported by newer kernels.
                         * also use this for untruncated MD5 and SHA1. */
-                       rthdr->rta_type = XFRMA_ALG_AUTH_TRUNC;
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_auth) +
-                                                                               int_key.len);
-
-                       hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
-                       if (hdr->nlmsg_len > sizeof(request))
+                       algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AUTH_TRUNC,
+                                                                  sizeof(*algo) + int_key.len);
+                       if (!algo)
                        {
                                goto failed;
                        }
-
-                       algo = (struct xfrm_algo_auth*)RTA_DATA(rthdr);
                        algo->alg_key_len = int_key.len * 8;
                        algo->alg_trunc_len = trunc_len;
                        strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
@@ -1362,27 +1359,23 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                {
                        struct xfrm_algo* algo;
 
-                       rthdr->rta_type = XFRMA_ALG_AUTH;
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + int_key.len);
-
-                       hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
-                       if (hdr->nlmsg_len > sizeof(request))
+                       algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_AUTH,
+                                                                  sizeof(*algo) + int_key.len);
+                       if (!algo)
                        {
                                goto failed;
                        }
-
-                       algo = (struct xfrm_algo*)RTA_DATA(rthdr);
                        algo->alg_key_len = int_key.len * 8;
                        strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
                        algo->alg_name[sizeof(algo->alg_name) - 1] = '\0';
                        memcpy(algo->alg_key, int_key.ptr, int_key.len);
                }
-               rthdr = XFRM_RTA_NEXT(rthdr);
        }
 
        if (ipcomp != IPCOMP_NONE)
        {
-               rthdr->rta_type = XFRMA_ALG_COMP;
+               struct xfrm_algo* algo;
+
                alg_name = lookup_algorithm(COMPRESSION_ALGORITHM, ipcomp);
                if (alg_name == NULL)
                {
@@ -1393,35 +1386,26 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                DBG2(DBG_KNL, "  using compression algorithm %N",
                         ipcomp_transform_names, ipcomp);
 
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo));
-               hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               algo = netlink_reserve(hdr, sizeof(request), XFRMA_ALG_COMP,
+                                                          sizeof(*algo));
+               if (!algo)
                {
                        goto failed;
                }
-
-               struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr);
                algo->alg_key_len = 0;
                strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name));
                algo->alg_name[sizeof(algo->alg_name) - 1] = '\0';
-
-               rthdr = XFRM_RTA_NEXT(rthdr);
        }
 
        if (encap)
        {
                struct xfrm_encap_tmpl *tmpl;
 
-               rthdr->rta_type = XFRMA_ENCAP;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl));
-
-               hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP, sizeof(*tmpl));
+               if (!tmpl)
                {
                        goto failed;
                }
-
-               tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr);
                tmpl->encap_type = UDP_ENCAP_ESPINUDP;
                tmpl->encap_sport = htons(src->get_port(src));
                tmpl->encap_dport = htons(dst->get_port(dst));
@@ -1436,44 +1420,24 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                 * No. The reason the kernel ignores NAT-OA is that it recomputes
                 * (or, rather, just ignores) the checksum. If packets pass the IPsec
                 * checks it marks them "checksum ok" so OA isn't needed. */
-               rthdr = XFRM_RTA_NEXT(rthdr);
        }
 
-       if (mark.value)
+       if (!add_mark(hdr, sizeof(request), mark))
        {
-               struct xfrm_mark *mrk;
-
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-
-               hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       goto failed;
-               }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
-               mrk->v = mark.value;
-               mrk->m = mark.mask;
-               rthdr = XFRM_RTA_NEXT(rthdr);
+               goto failed;
        }
 
        if (tfc)
        {
                u_int32_t *tfcpad;
 
-               rthdr->rta_type = XFRMA_TFCPAD;
-               rthdr->rta_len = RTA_LENGTH(sizeof(u_int32_t));
-
-               hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               tfcpad = netlink_reserve(hdr, sizeof(request), XFRMA_TFCPAD,
+                                                                sizeof(*tfcpad));
+               if (!tfcpad)
                {
                        goto failed;
                }
-
-               tfcpad = (u_int32_t*)RTA_DATA(rthdr);
                *tfcpad = tfc;
-               rthdr = XFRM_RTA_NEXT(rthdr);
        }
 
        if (protocol != IPPROTO_COMP)
@@ -1484,24 +1448,18 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                         * XFRMA_REPLAY_ESN_VAL attribute to configure a bitmap */
                        struct xfrm_replay_state_esn *replay;
 
-                       rthdr->rta_type = XFRMA_REPLAY_ESN_VAL;
-                       rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state_esn) +
-                                                                               (this->replay_window + 7) / 8);
-
-                       hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
-                       if (hdr->nlmsg_len > sizeof(request))
+                       replay = netlink_reserve(hdr, sizeof(request), XFRMA_REPLAY_ESN_VAL,
+                                                       sizeof(*replay) + (this->replay_window + 7) / 8);
+                       if (!replay)
                        {
                                goto failed;
                        }
-
-                       replay = (struct xfrm_replay_state_esn*)RTA_DATA(rthdr);
                        /* bmp_len contains number uf __u32's */
                        replay->bmp_len = this->replay_bmp;
                        replay->replay_window = this->replay_window;
                        DBG2(DBG_KNL, "  using replay window of %u packets",
                                 this->replay_window);
 
-                       rthdr = XFRM_RTA_NEXT(rthdr);
                        if (esn)
                        {
                                DBG2(DBG_KNL, "  using extended sequence numbers (ESN)");
@@ -1573,22 +1531,9 @@ static void get_replay_state(private_kernel_netlink_ipsec_t *this,
        aevent_id->sa_id.proto = protocol;
        aevent_id->sa_id.family = dst->get_family(dst);
 
-       if (mark.value)
+       if (!add_mark(hdr, sizeof(request), mark))
        {
-               struct xfrm_mark *mrk;
-               struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_aevent_id);
-
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-               hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       return;
-               }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
-               mrk->v = mark.value;
-               mrk->m = mark.mask;
+               return;
        }
 
        if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
@@ -1675,22 +1620,9 @@ METHOD(kernel_ipsec_t, query_sa, status_t,
        sa_id->proto = protocol;
        sa_id->family = dst->get_family(dst);
 
-       if (mark.value)
+       if (!add_mark(hdr, sizeof(request), mark))
        {
-               struct xfrm_mark *mrk;
-               struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_id);
-
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-               hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       return FAILED;
-               }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
-               mrk->v = mark.value;
-               mrk->m = mark.mask;
+               return FAILED;
        }
 
        if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
@@ -1785,22 +1717,9 @@ METHOD(kernel_ipsec_t, del_sa, status_t,
        sa_id->proto = protocol;
        sa_id->family = dst->get_family(dst);
 
-       if (mark.value)
+       if (!add_mark(hdr, sizeof(request), mark))
        {
-               struct xfrm_mark *mrk;
-               struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_id);
-
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-               hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       return FAILED;
-               }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
-               mrk->v = mark.value;
-               mrk->m = mark.mask;
+               return FAILED;
        }
 
        switch (this->socket_xfrm->send_ack(this->socket_xfrm, hdr))
@@ -1832,7 +1751,6 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
        bool old_encap, bool new_encap, mark_t mark)
 {
        netlink_buf_t request;
-       u_char *pos;
        struct nlmsghdr *hdr, *out = NULL;
        struct xfrm_usersa_id *sa_id;
        struct xfrm_usersa_info *out_sa = NULL, *sa;
@@ -1867,22 +1785,9 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
        sa_id->proto = protocol;
        sa_id->family = dst->get_family(dst);
 
-       if (mark.value)
+       if (!add_mark(hdr, sizeof(request), mark))
        {
-               struct xfrm_mark *mrk;
-               struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_usersa_id);
-
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-               hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       return FAILED;
-               }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
-               mrk->v = mark.value;
-               mrk->m = mark.mask;
+               return FAILED;
        }
 
        if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
@@ -1933,11 +1838,11 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
                                   ntohl(spi), src, dst, new_src, new_dst);
        /* copy over the SA from out to request */
        hdr = (struct nlmsghdr*)request;
-       memcpy(hdr, out, min(out->nlmsg_len, sizeof(request)));
        hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
        hdr->nlmsg_type = XFRM_MSG_NEWSA;
        hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
        sa = NLMSG_DATA(hdr);
+       memcpy(sa, NLMSG_DATA(out), sizeof(struct xfrm_usersa_info));
        sa->family = new_dst->get_family(new_dst);
 
        if (!src->ip_equals(src, new_src))
@@ -1951,75 +1856,60 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 
        rta = XFRM_RTA(out, struct xfrm_usersa_info);
        rtasize = XFRM_PAYLOAD(out, struct xfrm_usersa_info);
-       pos = (u_char*)XFRM_RTA(hdr, struct xfrm_usersa_info);
-       while(RTA_OK(rta, rtasize))
+       while (RTA_OK(rta, rtasize))
        {
                /* copy all attributes, but not XFRMA_ENCAP if we are disabling it */
                if (rta->rta_type != XFRMA_ENCAP || new_encap)
                {
                        if (rta->rta_type == XFRMA_ENCAP)
                        {       /* update encap tmpl */
-                               tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta);
+                               tmpl = RTA_DATA(rta);
                                tmpl->encap_sport = ntohs(new_src->get_port(new_src));
                                tmpl->encap_dport = ntohs(new_dst->get_port(new_dst));
                        }
-                       memcpy(pos, rta, rta->rta_len);
-                       pos += RTA_ALIGN(rta->rta_len);
-                       hdr->nlmsg_len += RTA_ALIGN(rta->rta_len);
+                       netlink_add_attribute(hdr, rta->rta_type,
+                                                                 chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta)),
+                                                                 sizeof(request));
                }
                rta = RTA_NEXT(rta, rtasize);
        }
 
-       rta = (struct rtattr*)pos;
        if (tmpl == NULL && new_encap)
        {       /* add tmpl if we are enabling it */
-               rta->rta_type = XFRMA_ENCAP;
-               rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl));
-
-               hdr->nlmsg_len += RTA_ALIGN(rta->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP, sizeof(*tmpl));
+               if (!tmpl)
                {
                        goto failed;
                }
-
-               tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta);
                tmpl->encap_type = UDP_ENCAP_ESPINUDP;
                tmpl->encap_sport = ntohs(new_src->get_port(new_src));
                tmpl->encap_dport = ntohs(new_dst->get_port(new_dst));
                memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t));
-
-               rta = XFRM_RTA_NEXT(rta);
        }
 
        if (replay_esn)
        {
-               rta->rta_type = XFRMA_REPLAY_ESN_VAL;
-               rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state_esn) +
-                                                                 this->replay_bmp);
+               struct xfrm_replay_state_esn *state;
 
-               hdr->nlmsg_len += RTA_ALIGN(rta->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               state = netlink_reserve(hdr, sizeof(request), XFRMA_REPLAY_ESN_VAL,
+                                                               sizeof(*state) + this->replay_bmp);
+               if (!state)
                {
                        goto failed;
                }
-               memcpy(RTA_DATA(rta), replay_esn,
-                          sizeof(struct xfrm_replay_state_esn) + this->replay_bmp);
-
-               rta = XFRM_RTA_NEXT(rta);
+               memcpy(state, replay_esn, sizeof(*state) + this->replay_bmp);
        }
        else if (replay)
        {
-               rta->rta_type = XFRMA_REPLAY_VAL;
-               rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state));
+               struct xfrm_replay_state *state;
 
-               hdr->nlmsg_len += RTA_ALIGN(rta->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
+               state = netlink_reserve(hdr, sizeof(request), XFRMA_REPLAY_VAL,
+                                                               sizeof(*state));
+               if (!state)
                {
                        goto failed;
                }
-               memcpy(RTA_DATA(rta), replay, sizeof(struct xfrm_replay_state));
-
-               rta = XFRM_RTA_NEXT(rta);
+               memcpy(state, replay, sizeof(*state));
        }
        else
        {
@@ -2116,11 +2006,9 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
        policy_info->lft.soft_use_expires_seconds = 0;
        policy_info->lft.hard_use_expires_seconds = 0;
 
-       struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_info);
-
        if (mapping->type == POLICY_IPSEC)
        {
-               struct xfrm_user_tmpl *tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rthdr);
+               struct xfrm_user_tmpl *tmpl;
                struct {
                        u_int8_t proto;
                        bool use;
@@ -2130,25 +2018,29 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
                        { IPPROTO_AH, ipsec->cfg.ah.use },
                };
                ipsec_mode_t proto_mode = ipsec->cfg.mode;
-
-               rthdr->rta_type = XFRMA_TMPL;
-               rthdr->rta_len = 0; /* actual length is set below */
+               int count = 0;
 
                for (i = 0; i < countof(protos); i++)
                {
-                       if (!protos[i].use)
+                       if (protos[i].use)
                        {
-                               continue;
+                               count++;
                        }
+               }
+               tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_TMPL,
+                                                          count * sizeof(*tmpl));
+               if (!tmpl)
+               {
+                       this->mutex->unlock(this->mutex);
+                       return FAILED;
+               }
 
-                       rthdr->rta_len += RTA_LENGTH(sizeof(struct xfrm_user_tmpl));
-                       hdr->nlmsg_len += RTA_ALIGN(RTA_LENGTH(sizeof(struct xfrm_user_tmpl)));
-                       if (hdr->nlmsg_len > sizeof(request))
+               for (i = 0; i < countof(protos); i++)
+               {
+                       if (!protos[i].use)
                        {
-                               this->mutex->unlock(this->mutex);
-                               return FAILED;
+                               continue;
                        }
-
                        tmpl->reqid = ipsec->cfg.reqid;
                        tmpl->id.proto = protos[i].proto;
                        tmpl->aalgos = tmpl->ealgos = tmpl->calgos = ~0;
@@ -2168,27 +2060,12 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
                        /* use transport mode for other SAs */
                        proto_mode = MODE_TRANSPORT;
                }
-
-               rthdr = XFRM_RTA_NEXT(rthdr);
        }
 
-       if (ipsec->mark.value)
+       if (!add_mark(hdr, sizeof(request), ipsec->mark))
        {
-               struct xfrm_mark *mrk;
-
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-
-               hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       this->mutex->unlock(this->mutex);
-                       return FAILED;
-               }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
-               mrk->v = ipsec->mark.value;
-               mrk->m = ipsec->mark.mask;
+               this->mutex->unlock(this->mutex);
+               return FAILED;
        }
        this->mutex->unlock(this->mutex);
 
@@ -2415,23 +2292,9 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
        policy_id->sel = ts2selector(src_ts, dst_ts);
        policy_id->dir = direction;
 
-       if (mark.value)
+       if (!add_mark(hdr, sizeof(request), mark))
        {
-               struct xfrm_mark *mrk;
-               struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_id);
-
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-
-               hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       return FAILED;
-               }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
-               mrk->v = mark.value;
-               mrk->m = mark.mask;
+               return FAILED;
        }
 
        if (this->socket_xfrm->send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
@@ -2587,23 +2450,9 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
        policy_id->sel = current->sel;
        policy_id->dir = direction;
 
-       if (mark.value)
+       if (!add_mark(hdr, sizeof(request), mark))
        {
-               struct xfrm_mark *mrk;
-               struct rtattr *rthdr = XFRM_RTA(hdr, struct xfrm_userpolicy_id);
-
-               rthdr->rta_type = XFRMA_MARK;
-               rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_mark));
-               hdr->nlmsg_len += RTA_ALIGN(rthdr->rta_len);
-               if (hdr->nlmsg_len > sizeof(request))
-               {
-                       this->mutex->unlock(this->mutex);
-                       return FAILED;
-               }
-
-               mrk = (struct xfrm_mark*)RTA_DATA(rthdr);
-               mrk->v = mark.value;
-               mrk->m = mark.mask;
+               return FAILED;
        }
 
        if (current->route)
index 561e852..fd00c23 100644 (file)
@@ -292,7 +292,7 @@ void netlink_add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data,
 {
        struct rtattr *rta;
 
-       if (NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(data.len) > buflen)
+       if (NLMSG_ALIGN(hdr->nlmsg_len) + RTA_LENGTH(data.len) > buflen)
        {
                DBG1(DBG_KNL, "unable to add attribute, buffer too small");
                return;
@@ -304,3 +304,24 @@ void netlink_add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data,
        memcpy(RTA_DATA(rta), data.ptr, data.len);
        hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + rta->rta_len;
 }
+
+/**
+ * Described in header.
+ */
+void* netlink_reserve(struct nlmsghdr *hdr, int buflen, int type, int len)
+{
+       struct rtattr *rta;
+
+       if (NLMSG_ALIGN(hdr->nlmsg_len) + RTA_LENGTH(len) > buflen)
+       {
+               DBG1(DBG_KNL, "unable to add attribute, buffer too small");
+               return NULL;
+       }
+
+       rta = ((void*)hdr) + NLMSG_ALIGN(hdr->nlmsg_len);
+       rta->rta_type = type;
+       rta->rta_len = RTA_LENGTH(len);
+       hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + rta->rta_len;
+
+       return RTA_DATA(rta);
+}
index dfd27a2..8be935b 100644 (file)
@@ -42,7 +42,8 @@ struct netlink_socket_t {
         * @param       out     received netlink message
         * @param       out_len length of the received message
         */
-       status_t (*send)(netlink_socket_t *this, struct nlmsghdr *in, struct nlmsghdr **out, size_t *out_len);
+       status_t (*send)(netlink_socket_t *this, struct nlmsghdr *in,
+                                        struct nlmsghdr **out, size_t *out_len);
 
        /**
         * Send a netlink message and wait for its acknowledge.
@@ -67,11 +68,23 @@ netlink_socket_t *netlink_socket_create(int protocol);
 /**
  * Creates an rtattr and adds it to the given netlink message.
  *
- * @param      hdr                     netlink message
- * @param      rta_type        type of the rtattr
- * @param      data            data to add to the rtattr
- * @param      buflen          length of the netlink message buffer
+ * @param hdr                  netlink message
+ * @param rta_type             type of the rtattr
+ * @param data                 data to add to the rtattr
+ * @param buflen               length of the netlink message buffer
  */
-void netlink_add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data, size_t buflen);
+void netlink_add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data,
+                                                  size_t buflen);
+
+/**
+ * Reserve space in a netlink message for given size and type, returning buffer.
+ *
+ * @param hdr                  netlink message
+ * @param buflen               size of full netlink buffer
+ * @param type                 RTA type
+ * @param len                  length of RTA data
+ * @return                             buffer to len bytes of attribute data, NULL on error
+ */
+void* netlink_reserve(struct nlmsghdr *hdr, int buflen, int type, int len);
 
 #endif /* KERNEL_NETLINK_SHARED_H_ */
index c2a5051..3273aed 100644 (file)
@@ -268,7 +268,6 @@ static int list_flags[] = {
        LIST_OCSP,
        LIST_ALGS,
        LIST_PLUGINS,
-       LIST_COUNTERS,
        LIST_ALL
 };
 
@@ -367,6 +366,18 @@ static int user_credentials(char *name, char *user, char *pass)
        return send_stroke_msg(&msg);
 }
 
+static int counters(int reset, char *name)
+{
+       stroke_msg_t msg;
+
+       msg.type = STR_COUNTERS;
+       msg.length = offsetof(stroke_msg_t, buffer);
+       msg.counters.name = push_string(&msg, name);
+       msg.counters.reset = reset;
+
+       return send_stroke_msg(&msg);
+}
+
 static int set_loglevel(char *type, u_int level)
 {
        stroke_msg_t msg;
@@ -421,7 +432,7 @@ static void exit_usage(char *error)
        printf("  Show list of authority and attribute certificates:\n");
        printf("    stroke listcacerts|listocspcerts|listaacerts|listacerts\n");
        printf("  Show list of end entity certificates, ca info records  and crls:\n");
-       printf("    stroke listcerts|listcainfos|listcrls|listcounters|listall\n");
+       printf("    stroke listcerts|listcainfos|listcrls|listall\n");
        printf("  Show list of supported algorithms:\n");
        printf("    stroke listalgs\n");
        printf("  Reload authority and attribute certificates:\n");
@@ -447,6 +458,8 @@ static void exit_usage(char *error)
        printf("    where: NAME is a connection name added with \"stroke add\"\n");
        printf("           USERNAME is the username\n");
        printf("           PASSWORD is the optional password, you'll be asked to enter it if not given\n");
+       printf("  Show IKE counters:\n");
+       printf("    stroke listcounters [connection-name]\n");
        exit_error(error);
 }
 
@@ -555,7 +568,6 @@ int main(int argc, char *argv[])
                case STROKE_LIST_OCSP:
                case STROKE_LIST_ALGS:
                case STROKE_LIST_PLUGINS:
-               case STROKE_LIST_COUNTERS:
                case STROKE_LIST_ALL:
                        res = list(token->kw, argc > 2 && strcmp(argv[2], "--utc") == 0);
                        break;
@@ -596,6 +608,11 @@ int main(int argc, char *argv[])
                        }
                        res = user_credentials(argv[2], argv[3], argc > 4 ? argv[4] : NULL);
                        break;
+               case STROKE_COUNTERS:
+               case STROKE_COUNTERS_RESET:
+                       res = counters(token->kw == STROKE_COUNTERS_RESET,
+                                                  argc > 2 ? argv[2] : NULL);
+                       break;
                default:
                        exit_usage(NULL);
        }
index 0ad87b7..f5979a0 100644 (file)
@@ -42,7 +42,6 @@ typedef enum {
        STROKE_LIST_OCSP,
        STROKE_LIST_ALGS,
        STROKE_LIST_PLUGINS,
-       STROKE_LIST_COUNTERS,
        STROKE_LIST_ALL,
        STROKE_REREAD_SECRETS,
        STROKE_REREAD_CACERTS,
@@ -59,6 +58,8 @@ typedef enum {
        STROKE_LEASES,
        STROKE_MEMUSAGE,
        STROKE_USER_CREDS,
+       STROKE_COUNTERS,
+       STROKE_COUNTERS_RESET,
 } stroke_keyword_t;
 
 #define STROKE_LIST_FIRST              STROKE_LIST_PUBKEYS
@@ -71,4 +72,3 @@ typedef struct stroke_token stroke_token_t;
 extern const stroke_token_t* in_word_set(register const char *str, register unsigned int len);
 
 #endif /* _STROKE_KEYWORDS_H_ */
-
index 95b2981..5d2ebd9 100644 (file)
@@ -49,7 +49,6 @@ listcrls,        STROKE_LIST_CRLS
 listocsp,        STROKE_LIST_OCSP
 listalgs,        STROKE_LIST_ALGS
 listplugins,     STROKE_LIST_PLUGINS
-listcounters,    STROKE_LIST_COUNTERS
 listall,         STROKE_LIST_ALL
 rereadsecrets,   STROKE_REREAD_SECRETS
 rereadcacerts,   STROKE_REREAD_CACERTS
@@ -66,3 +65,5 @@ exportx509,      STROKE_EXPORT_X509
 leases,          STROKE_LEASES
 memusage,        STROKE_MEMUSAGE
 user-creds,      STROKE_USER_CREDS
+listcounters,    STROKE_COUNTERS
+resetcounters,   STROKE_COUNTERS_RESET
index a9c6f23..5cee916 100644 (file)
@@ -67,10 +67,8 @@ enum list_flag_t {
        LIST_ALGS =                     0x0400,
        /** list plugin information */
        LIST_PLUGINS =          0x0800,
-       /** list IKE counters */
-       LIST_COUNTERS =         0x1000,
        /** all list options */
-       LIST_ALL =                      0x1FFF,
+       LIST_ALL =                      0x0FFF,
 };
 
 typedef enum reread_flag_t reread_flag_t;
@@ -226,6 +224,8 @@ struct stroke_msg_t {
                STR_MEMUSAGE,
                /* set username and password for a connection */
                STR_USER_CREDS,
+               /* print/reset counters */
+               STR_COUNTERS,
                /* more to come */
        } type;
 
@@ -356,6 +356,13 @@ struct stroke_msg_t {
                        char *username;
                        char *password;
                } user_creds;
+
+               /* data for STR_COUNTERS */
+               struct {
+                       /* reset or print counters? */
+                       int reset;
+                       char *name;
+               } counters;
        };
        char buffer[STROKE_BUF_LEN];
 };