printing u_int64_t caused segfault on 32-bit platforms
[strongswan.git] / src / charon / plugins / stroke / stroke_list.c
index 9ce89dc..7aa80dc 100644 (file)
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * for more details.
- *
- * $Id$
  */
 
 #include "stroke_list.h"
 
+#include <time.h>
+
 #include <daemon.h>
 #include <utils/linked_list.h>
 #include <credentials/certificates/x509.h>
@@ -45,24 +45,12 @@ struct private_stroke_list_t {
         * timestamp of daemon start
         */
        time_t uptime;
-};
-
-/**
- * get the authentication class of a config
- */
-auth_class_t get_auth_class(peer_cfg_t *config)
-{
-       auth_class_t *class;
-       auth_info_t *auth_info;
        
-       auth_info = config->get_auth(config);
-       if (auth_info->get_item(auth_info, AUTHN_AUTH_CLASS, (void**)&class))
-       {
-               return *class;
-       }
-       /* fallback to pubkey authentication */
-       return AUTH_CLASS_PUBKEY;
-}
+       /**
+        * strokes attribute provider
+        */
+       stroke_attribute_t *attribute;
+};
 
 /**
  * log an IKE_SA to out
@@ -70,36 +58,69 @@ auth_class_t get_auth_class(peer_cfg_t *config)
 static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
 {
        ike_sa_id_t *id = ike_sa->get_id(ike_sa);
-
-       fprintf(out, "%12s[%d]: %N, %H[%D]...%H[%D]\n",
+       time_t now = time(NULL);
+       
+       fprintf(out, "%12s[%d]: %N",
                        ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
-                       ike_sa_state_names, ike_sa->get_state(ike_sa),
+                       ike_sa_state_names, ike_sa->get_state(ike_sa));
+       
+       if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED)
+       {
+               time_t established;
+               
+               established = ike_sa->get_statistic(ike_sa, STAT_ESTABLISHED);
+               fprintf(out, " %V ago", &now, &established);
+       }
+       
+       fprintf(out, ", %H[%Y]...%H[%Y]\n",
                        ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa),
                        ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa));
        
        if (all)
        {
-               char *ike_proposal = ike_sa->get_proposal(ike_sa);
-
+               proposal_t *ike_proposal;
+               
+               ike_proposal = ike_sa->get_proposal(ike_sa);
+               
                fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s",
                                ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
                                id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "",
                                id->get_responder_spi(id), id->is_initiator(id) ? "" : "*");
-       
-
+               
+               
                if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED)
                {
-                       u_int32_t rekey = ike_sa->get_statistic(ike_sa, STAT_REKEY_TIME);
-                       u_int32_t reauth = ike_sa->get_statistic(ike_sa, STAT_REAUTH_TIME);
-
+                       time_t rekey, reauth;
+                       peer_cfg_t *peer_cfg;
+                       
+                       rekey = ike_sa->get_statistic(ike_sa, STAT_REKEY);
+                       reauth = ike_sa->get_statistic(ike_sa, STAT_REAUTH);
+                       peer_cfg = ike_sa->get_peer_cfg(ike_sa);
+                       
                        if (rekey)
                        {
-                               fprintf(out, ", rekeying in %V", &rekey);
+                               fprintf(out, ", rekeying in %V", &rekey, &now);
                        }
                        if (reauth)
                        {
-                               fprintf(out, ", %N reauthentication in %V", auth_class_names,
-                                               get_auth_class(ike_sa->get_peer_cfg(ike_sa)), &reauth);
+                               bool first = TRUE;
+                               enumerator_t *enumerator;
+                               auth_cfg_t *auth;
+                               
+                               fprintf(out, ", ");
+                               enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, TRUE);
+                               while (enumerator->enumerate(enumerator, &auth))
+                               {
+                                       if (!first)
+                                       {
+                                               fprintf(out, "+");
+                                       }
+                                       first = FALSE;
+                                       fprintf(out, "%N", auth_class_names,
+                                                       auth->get(auth, AUTH_RULE_AUTH_CLASS));
+                               }
+                               enumerator->destroy(enumerator);
+                               fprintf(out, " reauthentication in %V", &reauth, &now);
                        }
                        if (!rekey && !reauth)
                        {
@@ -107,13 +128,16 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
                        }
                }
                fprintf(out, "\n");
-
+               
                if (ike_proposal)
                {
+                       char buf[BUF_LEN];
+                       
+                       snprintf(buf, BUF_LEN, "%P", ike_proposal);
                        fprintf(out, "%12s[%d]: IKE proposal: %s\n",
                                        ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
-                                       ike_proposal);
-               }               
+                                       buf+4);
+               }
        }
 }
 
@@ -122,113 +146,206 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
  */
 static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
 {
-       u_int32_t rekey, now = time(NULL);
-       u_int32_t use_in, use_out;
-       encryption_algorithm_t encr_alg;
-       integrity_algorithm_t int_alg;
-       chunk_t encr_key, int_key;
+       time_t use_in, use_out, rekey, now = time(NULL);
+       u_int64_t bytes_in, bytes_out;
+       proposal_t *proposal;
+       child_cfg_t *config = child_sa->get_config(child_sa);
        
-       fprintf(out, "%12s{%d}:  %N, %N", 
+       fprintf(out, "%12s{%d}:  %N, %N%s", 
                        child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
                        child_sa_state_names, child_sa->get_state(child_sa),
-                       ipsec_mode_names, child_sa->get_mode(child_sa));
+                       ipsec_mode_names, child_sa->get_mode(child_sa),
+                       config->use_proxy_mode(config) ? "_PROXY" : "");
        
        if (child_sa->get_state(child_sa) == CHILD_INSTALLED)
        {
-               u_int16_t my_cpi    = child_sa->get_cpi(child_sa, TRUE);
-               u_int16_t other_cpi = child_sa->get_cpi(child_sa, FALSE);               
-
-               fprintf(out, ", %N SPIs: %.8x_i %.8x_o",
+               fprintf(out, ", %N%s SPIs: %.8x_i %.8x_o",
                                protocol_id_names, child_sa->get_protocol(child_sa),
+                               child_sa->has_encap(child_sa) ? " in UDP" : "",
                                ntohl(child_sa->get_spi(child_sa, TRUE)),
                                ntohl(child_sa->get_spi(child_sa, FALSE)));
-
-               /* Is IPCOMP activated ? */
-               if (my_cpi && other_cpi)
+               
+               if (child_sa->get_ipcomp(child_sa) != IPCOMP_NONE)
                {
                        fprintf(out, ", IPCOMP CPIs: %.4x_i %.4x_o",
-                                       ntohs(my_cpi), ntohs(other_cpi));
+                                       ntohs(child_sa->get_cpi(child_sa, TRUE)),
+                                       ntohs(child_sa->get_cpi(child_sa, FALSE)));
                }
-
+               
                if (all)
                {
                        fprintf(out, "\n%12s{%d}:  ", child_sa->get_name(child_sa), 
                                        child_sa->get_reqid(child_sa));
                        
-                       if (child_sa->get_protocol(child_sa) == PROTO_ESP)
+                       proposal = child_sa->get_proposal(child_sa);
+                       if (proposal)
                        {
-                               encr_alg = child_sa->get_encryption(child_sa, TRUE, &encr_key);
-                       
-                               switch (encr_alg)
+                               u_int16_t encr_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED;
+                               u_int16_t encr_size = 0, int_size = 0;
+                               
+                               proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM,
+                                                                               &encr_alg, &encr_size);
+                               proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM,
+                                                                               &int_alg, &int_size);
+                               
+                               if (encr_alg != ENCR_UNDEFINED)
                                {
-                                       /* Algorithms with variable key size.
-                                        * GCM/CCM keys are actually shorted than their key data. */
-                                       case ENCR_AES_GCM_ICV8:
-                                       case ENCR_AES_GCM_ICV12:
-                                       case ENCR_AES_GCM_ICV16:
-                                               encr_key.len -= 1;
-                                               /* FALL */
-                                       case ENCR_AES_CCM_ICV8:
-                                       case ENCR_AES_CCM_ICV12:
-                                       case ENCR_AES_CCM_ICV16:
-                                               encr_key.len -= 3;
-                                               /* FALL */
-                                       case ENCR_AES_CBC:
-                                               fprintf(out, "%N-%d", encryption_algorithm_names,
-                                                               encr_alg, encr_key.len * 8);
-                                               break;
-                                       default:
-                                               fprintf(out, "%N", encryption_algorithm_names, encr_alg);
-                                               break;
+                                       fprintf(out, "%N", encryption_algorithm_names, encr_alg);
+                                       if (encr_size)
+                                       {
+                                               fprintf(out, "_%u", encr_size);
+                                       }
+                               }
+                               if (int_alg != AUTH_UNDEFINED)
+                               {
+                                       fprintf(out, "/%N", integrity_algorithm_names, int_alg);
+                                       if (int_size)
+                                       {
+                                               fprintf(out, "_%u", int_size);
+                                       }
                                }
                        }
-                       int_alg = child_sa->get_integrity(child_sa, TRUE, &int_key);
-                       switch (int_alg)
+
+                       child_sa->get_usestats(child_sa, TRUE, &use_in, &bytes_in);
+                       fprintf(out, ", %u bytes_i", (u_int)bytes_in);
+                       if (use_in)
                        {
-                               case AUTH_UNDEFINED:
-                                       break;
-                               default:
-                                       fprintf(out, "/%N", integrity_algorithm_names, int_alg);
-                                       break;
+                               fprintf(out, " (%ds ago)", now - use_in);
+                       }
+
+                       child_sa->get_usestats(child_sa, FALSE, &use_out, &bytes_out);
+                       fprintf(out, ", %u bytes_o", (u_int)bytes_out);
+                       if (use_out)
+                       {
+                               fprintf(out, " (%ds ago)", now - use_out);
                        }
                        fprintf(out, ", rekeying ");
                        
                        rekey = child_sa->get_lifetime(child_sa, FALSE);
                        if (rekey)
                        {
-                               fprintf(out, "in %#V", &now, &rekey);
+                               if (now > rekey)
+                               {
+                                       fprintf(out, "active");
+                               }
+                               else
+                               {
+                                       fprintf(out, "in %V", &now, &rekey);
+                               }
                        }
                        else
                        {
                                fprintf(out, "disabled");
                        }
                        
-                       fprintf(out, ", last use: ");
-                       use_in = child_sa->get_usetime(child_sa, TRUE);
-                       if (use_in)
+               }
+       }
+       
+       fprintf(out, "\n%12s{%d}:   %#R=== %#R\n",
+                       child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
+                       child_sa->get_traffic_selectors(child_sa, TRUE),
+                       child_sa->get_traffic_selectors(child_sa, FALSE));
+}
+
+/**
+ * Log a configs local or remote authentication config to out
+ */
+static void log_auth_cfgs(FILE *out, peer_cfg_t *peer_cfg, bool local)
+{
+       enumerator_t *enumerator, *rules;
+       auth_rule_t rule;
+       auth_cfg_t *auth;
+       auth_class_t auth_class;
+       identification_t *id;
+       certificate_t *cert;
+       cert_validation_t valid;
+       char *name;
+       
+       name = peer_cfg->get_name(peer_cfg);
+       
+       enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local);
+       while (enumerator->enumerate(enumerator, &auth))
+       {
+               fprintf(out, "%12s:   %s [%Y] uses ", name,     local ? "local: " : "remote:",
+                               auth->get(auth, AUTH_RULE_IDENTITY));
+
+               auth_class = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS);
+               if (auth_class != AUTH_CLASS_EAP)
+               {
+                       fprintf(out, "%N authentication\n", auth_class_names, auth_class);
+               }
+               else
+               {
+                       if ((uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE) == EAP_NAK)
                        {
-                               fprintf(out, "%ds_i ", now - use_in);
+                               fprintf(out, "EAP authentication");
                        }
                        else
                        {
-                               fprintf(out, "no_i ");
+                               if ((uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR))
+                               {
+                                       fprintf(out, "EAP_%d-%d authentication",
+                                               (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE),
+                                               (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR));
+                               }
+                               else
+                               {
+                                       fprintf(out, "%N authentication", eap_type_names,
+                                               (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE));
+                               }
                        }
-                       use_out = child_sa->get_usetime(child_sa, FALSE);
-                       if (use_out)
+                       id = auth->get(auth, AUTH_RULE_EAP_IDENTITY);
+                       if (id)
                        {
-                               fprintf(out, "%ds_o ", now - use_out);
+                               fprintf(out, " with EAP identity '%Y'", id);
                        }
-                       else
+                       fprintf(out, "\n");
+               }
+
+               cert = auth->get(auth, AUTH_RULE_CA_CERT);
+               if (cert)
+               {
+                       fprintf(out, "%12s:    ca:    \"%Y\"\n", name, cert->get_subject(cert));
+               }
+
+               cert = auth->get(auth, AUTH_RULE_IM_CERT);
+               if (cert)
+               {
+                       fprintf(out, "%12s:    im-ca: \"%Y\"\n", name, cert->get_subject(cert));
+               }
+
+               cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
+               if (cert)
+               {
+                       fprintf(out, "%12s:    cert:  \"%Y\"\n", name,
+                                       cert->get_subject(cert));
+               }
+
+               valid = (uintptr_t)auth->get(auth, AUTH_RULE_OCSP_VALIDATION);
+               if (valid != VALIDATION_FAILED)
+               {
+                       fprintf(out, "%12s:    ocsp:  status must be GOOD%s\n", name,
+                                       (valid == VALIDATION_SKIPPED) ? " or SKIPPED" : "");
+               }
+               
+               valid = (uintptr_t)auth->get(auth, AUTH_RULE_CRL_VALIDATION);
+               if (valid != VALIDATION_FAILED)
+               {
+                       fprintf(out, "%12s:    crl:   status must be GOOD%s\n", name,
+                                       (valid == VALIDATION_SKIPPED) ? " or SKIPPED" : "");
+               }
+
+               rules = auth->create_enumerator(auth);
+               while (rules->enumerate(rules, &rule, &id))
+               {
+                       if (rule == AUTH_RULE_AC_GROUP)
                        {
-                               fprintf(out, "no_o ");
+                               fprintf(out, "%12s:    group: %Y\n", name, id);
                        }
                }
+               rules->destroy(rules);
        }
-       
-       fprintf(out, "\n%12s{%d}:   %#R=== %#R\n",
-                       child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
-                       child_sa->get_traffic_selectors(child_sa, TRUE),
-                       child_sa->get_traffic_selectors(child_sa, FALSE));
+       enumerator->destroy(enumerator);
 }
 
 /**
@@ -239,20 +356,22 @@ static void status(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out, bo
        enumerator_t *enumerator, *children;
        ike_cfg_t *ike_cfg;
        child_cfg_t *child_cfg;
+       child_sa_t *child_sa;
        ike_sa_t *ike_sa;
-       bool found = FALSE;
+       bool first, found = FALSE;
        char *name = msg->status.name;
        
        if (all)
        {
                peer_cfg_t *peer_cfg;
-               char *plugin;
+               char *plugin, *pool;
                host_t *host;
                u_int32_t dpd;
-               time_t uptime = time(NULL) - this->uptime;
-
-               fprintf(out, "Performance:\n");
-               fprintf(out, "  uptime: %V, since %#T\n", &uptime, &this->uptime, FALSE);
+               time_t now = time(NULL);
+               u_int size, online, offline;
+               
+               fprintf(out, "Status of IKEv2 charon daemon (strongSwan "VERSION"):\n");
+               fprintf(out, "  uptime: %V, since %T\n", &now, &this->uptime, &this->uptime, FALSE);
                fprintf(out, "  worker threads: %d idle of %d,",
                                charon->processor->get_idle_threads(charon->processor),
                                charon->processor->get_total_threads(charon->processor));
@@ -269,6 +388,23 @@ static void status(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out, bo
                enumerator->destroy(enumerator);
                fprintf(out, "\n");
                
+               first = TRUE;
+               enumerator = this->attribute->create_pool_enumerator(this->attribute);
+               while (enumerator->enumerate(enumerator, &pool, &size, &online, &offline))
+               {
+                       if (name && !streq(name, pool))
+                       {
+                               continue;
+                       }
+                       if (first)
+                       {
+                               first = FALSE;
+                               fprintf(out, "Virtual IP pools (size/online/offline):\n");
+                       }
+                       fprintf(out, "  %s: %u/%u/%u\n", pool, size, online, offline);
+               }
+               enumerator->destroy(enumerator);
+               
                enumerator = charon->kernel_interface->create_address_enumerator(
                                                                charon->kernel_interface, FALSE, FALSE);
                fprintf(out, "Listening IP addresses:\n");
@@ -279,138 +415,42 @@ static void status(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out, bo
                enumerator->destroy(enumerator);
        
                fprintf(out, "Connections:\n");
-               enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends);
-               while (enumerator->enumerate(enumerator, (void**)&peer_cfg))
-               {
-                       void *ptr;
-                       certificate_t *cert;
-                       auth_item_t item;
-                       auth_info_t *auth;
-                       enumerator_t *auth_enumerator;
-                       identification_t *my_ca = NULL, *other_ca = NULL;
-                       identification_t *eap_identity = NULL;
-                       u_int32_t *eap_type = NULL;
-                       bool ac_groups = FALSE;
-
+               enumerator = charon->backends->create_peer_cfg_enumerator(
+                                                                       charon->backends, NULL, NULL, NULL, NULL);
+               while (enumerator->enumerate(enumerator, &peer_cfg))
+               {
                        if (peer_cfg->get_ike_version(peer_cfg) != 2 ||
                                (name && !streq(name, peer_cfg->get_name(peer_cfg))))
                        {
                                continue;
                        }
                        
-                       /* determine any required CAs, EAP type, EAP identity,
-                        * and the presence of AC groups
-                        */
-                       auth = peer_cfg->get_auth(peer_cfg);
-                       auth_enumerator = auth->create_item_enumerator(auth);
-                       while (auth_enumerator->enumerate(auth_enumerator, &item, &ptr))
-                       {
-                               switch (item)
-                               {
-                                       case AUTHN_EAP_TYPE:
-                                               eap_type = (u_int32_t *)ptr;
-                                               break;
-                                       case AUTHN_EAP_IDENTITY:
-                                               eap_identity = (identification_t *)ptr;
-                                               break;
-                                       case AUTHN_CA_CERT:
-                                               cert = (certificate_t *)ptr;
-                                               my_ca = cert->get_subject(cert);
-                                               break;
-                                       case AUTHN_CA_CERT_NAME:
-                                               my_ca = (identification_t *)ptr;
-                                               break;
-                                       case AUTHZ_CA_CERT:
-                                               cert = (certificate_t *)ptr;
-                                               other_ca = cert->get_subject(cert);
-                                               break;
-                                       case AUTHZ_CA_CERT_NAME:
-                                               other_ca = (identification_t *)ptr;
-                                               break;
-                                       case AUTHZ_AC_GROUP:
-                                               ac_groups = TRUE;
-                                               break;
-                                       default:
-                                               break;
-                               }
-                       }
-                       auth_enumerator->destroy(auth_enumerator);
-
                        ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
-                       fprintf(out, "%12s:  %s[%D]...%s[%D]\n", peer_cfg->get_name(peer_cfg),
-                                       ike_cfg->get_my_addr(ike_cfg), peer_cfg->get_my_id(peer_cfg),
-                                       ike_cfg->get_other_addr(ike_cfg), peer_cfg->get_other_id(peer_cfg));
-                       if (my_ca || other_ca)
-                       {
-                               fprintf(out, "%12s:  CAs: ", peer_cfg->get_name(peer_cfg));
-                               if (my_ca)
-                               {
-                                       fprintf(out, "\"%D\"...", my_ca);
-                               }
-                               else
-                               {
-                                       fprintf(out, "%%any...");
-                               }
-                               if (other_ca)
-                               {
-                                       fprintf(out, "\"%D\"\n", other_ca);
-                               }
-                               else
-                               {
-                                       fprintf(out, "%%any\n");
-                               }
-                       }
-
-                       if (ac_groups)
-                       {
-                               bool first = TRUE;
-
-                               fprintf(out, "%12s:  groups: ",  peer_cfg->get_name(peer_cfg));
-                               auth_enumerator = auth->create_item_enumerator(auth);
-                               while (auth_enumerator->enumerate(auth_enumerator, &item, &ptr))
-                               {
-                                       if (item == AUTHZ_AC_GROUP)
-                                       {
-                                               identification_t *group = (identification_t *)ptr;
-
-                                               fprintf(out, "%s%D", first? "":", ", group);
-                                               first = FALSE;
-                                       }
-                               }
-                               auth_enumerator->destroy(auth_enumerator);
-                               fprintf(out, "\n");
-                       }
-
-                       fprintf(out, "%12s:  %N ",  peer_cfg->get_name(peer_cfg),
-                                       auth_class_names, get_auth_class(peer_cfg));
-                       if (eap_type)
-                       {
-                               fprintf(out, "and %N ", eap_type_names, *eap_type);
-                       }
-                       fprintf(out, "authentication");
-                       if (eap_identity)
-                       {
-                               fprintf(out, ", EAP identity: '%D'", eap_identity);
-                       }
+                       fprintf(out, "%12s:  %s...%s", peer_cfg->get_name(peer_cfg),
+                               ike_cfg->get_my_addr(ike_cfg), ike_cfg->get_other_addr(ike_cfg));
+                       
                        dpd = peer_cfg->get_dpd(peer_cfg);
                        if (dpd)
                        {
                                fprintf(out, ", dpddelay=%us", dpd);
                        }
                        fprintf(out, "\n");
-
+                       
+                       log_auth_cfgs(out, peer_cfg, TRUE);
+                       log_auth_cfgs(out, peer_cfg, FALSE);
+                       
                        children = peer_cfg->create_child_cfg_enumerator(peer_cfg);
                        while (children->enumerate(children, &child_cfg))
                        {
                                linked_list_t *my_ts, *other_ts;
-
+                               
                                my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL);
                                other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL);
-                               fprintf(out, "%12s:    %#R=== %#R", child_cfg->get_name(child_cfg),
+                               fprintf(out, "%12s:   child:  %#R=== %#R", child_cfg->get_name(child_cfg),
                                                my_ts, other_ts);
                                my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
                                other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
-
+                               
                                if (dpd)
                                {
                                        fprintf(out, ", dpdaction=%N", action_names,
@@ -422,13 +462,25 @@ static void status(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out, bo
                }
                enumerator->destroy(enumerator);
        }
+
+       first = TRUE;   
+       enumerator = charon->traps->create_enumerator(charon->traps);
+       while (enumerator->enumerate(enumerator, NULL, &child_sa))
+       {
+               if (first)
+               {
+                       fprintf(out, "Routed Connections:\n");
+                       first = FALSE;
+               }
+               log_child_sa(out, child_sa, all);
+       }
+       enumerator->destroy(enumerator);
        
        fprintf(out, "Security Associations:\n");
        enumerator = charon->controller->create_ike_sa_enumerator(charon->controller);
        while (enumerator->enumerate(enumerator, &ike_sa))
        {
                bool ike_printed = FALSE;
-               child_sa_t *child_sa;
                iterator_t *children = ike_sa->create_child_sa_iterator(ike_sa);
                
                if (name == NULL || streq(name, ike_sa->get_name(ike_sa)))
@@ -554,8 +606,8 @@ static void stroke_list_pubkeys(linked_list_t *list, bool utc, FILE *out)
                                        key_type_names, public->get_type(public),
                                        public->get_keysize(public) * 8,
                                        private ? ", has private key" : "");
-                       fprintf(out, "  keyid:     %D\n", keyid);
-                       fprintf(out, "  subjkey:   %D\n", id);
+                       fprintf(out, "  keyid:     %Y\n", keyid);
+                       fprintf(out, "  subjkey:   %Y\n", id);
                        DESTROY_IF(private);
                        public->destroy(public);
                }
@@ -611,7 +663,7 @@ static void stroke_list_certs(linked_list_t *list, char *label,
                                {
                                        fprintf(out, ", ");
                                }
-                               fprintf(out, "%D", altName);
+                               fprintf(out, "%Y", altName);
                        }
                        if (!first_altName)
                        {
@@ -619,32 +671,32 @@ static void stroke_list_certs(linked_list_t *list, char *label,
                        }
                        enumerator->destroy(enumerator);
 
-                       fprintf(out, "  subject:  \"%D\"\n", cert->get_subject(cert));
-                       fprintf(out, "  issuer:   \"%D\"\n", cert->get_issuer(cert));
+                       fprintf(out, "  subject:  \"%Y\"\n", cert->get_subject(cert));
+                       fprintf(out, "  issuer:   \"%Y\"\n", cert->get_issuer(cert));
                        fprintf(out, "  serial:    %#B\n", &serial);
 
                        /* list validity */
                        cert->get_validity(cert, &now, &notBefore, &notAfter);
-                       fprintf(out, "  validity:  not before %#T, ", &notBefore, utc);
+                       fprintf(out, "  validity:  not before %T, ", &notBefore, utc);
                        if (now < notBefore)
                        {
-                               fprintf(out, "not valid yet (valid in %#V)\n", &now, &notBefore);
+                               fprintf(out, "not valid yet (valid in %V)\n", &now, &notBefore);
                        }
                        else
                        {
                                fprintf(out, "ok\n");
                        }
-                       fprintf(out, "             not after  %#T, ", &notAfter, utc);
+                       fprintf(out, "             not after  %T, ", &notAfter, utc);
                        if (now > notAfter)
                        {
-                               fprintf(out, "expired (%#V ago)\n", &now, &notAfter);
+                               fprintf(out, "expired (%V ago)\n", &now, &notAfter);
                        }
                        else
                        {
                                fprintf(out, "ok");
                                if (now > notAfter - CERT_WARNING_INTERVAL * 60 * 60 * 24)
                                {
-                                       fprintf(out, " (expires in %#V)", &now, &notAfter);
+                                       fprintf(out, " (expires in %V)", &now, &notAfter);
                                }
                                fprintf(out, " \n");
                        }
@@ -665,8 +717,8 @@ static void stroke_list_certs(linked_list_t *list, char *label,
                                                key_type_names, public->get_type(public),
                                                public->get_keysize(public) * 8,
                                                private ? ", has private key" : "");
-                               fprintf(out, "  keyid:     %D\n", keyid);
-                               fprintf(out, "  subjkey:   %D\n", id);
+                               fprintf(out, "  keyid:     %Y\n", keyid);
+                               fprintf(out, "  subjkey:   %Y\n", id);
                                DESTROY_IF(private);
                                public->destroy(public);
                        }
@@ -674,7 +726,7 @@ static void stroke_list_certs(linked_list_t *list, char *label,
                        /* list optional authorityKeyIdentifier */
                        if (authkey)
                        {
-                               fprintf(out, "  authkey:   %D\n", authkey);
+                               fprintf(out, "  authkey:   %Y\n", authkey);
                        }
                }
        }
@@ -710,33 +762,33 @@ static void stroke_list_acerts(linked_list_t *list, bool utc, FILE *out)
 
                if (entityName)
                {
-                       fprintf(out, "  holder:   \"%D\"\n", entityName);
+                       fprintf(out, "  holder:   \"%Y\"\n", entityName);
                }
                if (holderIssuer)
                {
-                       fprintf(out, "  hissuer:  \"%D\"\n", holderIssuer);
+                       fprintf(out, "  hissuer:  \"%Y\"\n", holderIssuer);
                }
                if (holderSerial.ptr)
                {
                        fprintf(out, "  hserial:   %#B\n", &holderSerial);
                }
-               fprintf(out, "  issuer:   \"%D\"\n", cert->get_issuer(cert));
+               fprintf(out, "  issuer:   \"%Y\"\n", cert->get_issuer(cert));
                fprintf(out, "  serial:    %#B\n", &serial);
 
                /* list validity */
                cert->get_validity(cert, &now, &thisUpdate, &nextUpdate);
-               fprintf(out, "  updates:   this %#T\n",  &thisUpdate, utc);
-               fprintf(out, "             next %#T, ", &nextUpdate, utc);
+               fprintf(out, "  updates:   this %T\n",  &thisUpdate, utc);
+               fprintf(out, "             next %T, ", &nextUpdate, utc);
                if (now > nextUpdate)
                {
-                       fprintf(out, "expired (%#V ago)\n", &now, &nextUpdate);
+                       fprintf(out, "expired (%V ago)\n", &now, &nextUpdate);
                }
                else
                {
                        fprintf(out, "ok");
                        if (now > nextUpdate - AC_WARNING_INTERVAL * 60 * 60 * 24)
                        {
-                               fprintf(out, " (expires in %#V)", &now, &nextUpdate);
+                               fprintf(out, " (expires in %V)", &now, &nextUpdate);
                        }
                        fprintf(out, " \n");
                }
@@ -744,7 +796,7 @@ static void stroke_list_acerts(linked_list_t *list, bool utc, FILE *out)
                /* list optional authorityKeyIdentifier */
                if (authkey)
                {
-                       fprintf(out, "  authkey:   %D\n", authkey);
+                       fprintf(out, "  authkey:   %Y\n", authkey);
                }
        }
        enumerator->destroy(enumerator);
@@ -774,7 +826,7 @@ static void stroke_list_crls(linked_list_t *list, bool utc, FILE *out)
                }
                fprintf(out, "\n");
 
-               fprintf(out, "  issuer:   \"%D\"\n", cert->get_issuer(cert));
+               fprintf(out, "  issuer:   \"%Y\"\n", cert->get_issuer(cert));
 
                /* list optional crlNumber */
                if (serial.ptr)
@@ -798,18 +850,18 @@ static void stroke_list_crls(linked_list_t *list, bool utc, FILE *out)
 
                /* list validity */
                cert->get_validity(cert, &now, &thisUpdate, &nextUpdate);
-               fprintf(out, "  updates:   this %#T\n",  &thisUpdate, utc);
-               fprintf(out, "             next %#T, ", &nextUpdate, utc);
+               fprintf(out, "  updates:   this %T\n",  &thisUpdate, utc);
+               fprintf(out, "             next %T, ", &nextUpdate, utc);
                if (now > nextUpdate)
                {
-                       fprintf(out, "expired (%#V ago)\n", &now, &nextUpdate);
+                       fprintf(out, "expired (%V ago)\n", &now, &nextUpdate);
                }
                else
                {
                        fprintf(out, "ok");
                        if (now > nextUpdate - CRL_WARNING_INTERVAL * 60 * 60 * 24)
                        {
-                               fprintf(out, " (expires in %#V)", &now, &nextUpdate);
+                               fprintf(out, " (expires in %V)", &now, &nextUpdate);
                        }
                        fprintf(out, " \n");
                }
@@ -817,7 +869,7 @@ static void stroke_list_crls(linked_list_t *list, bool utc, FILE *out)
                /* list optional authorityKeyIdentifier */
                if (authkey)
                {
-                       fprintf(out, "  authkey:   %D\n", authkey);
+                       fprintf(out, "  authkey:   %Y\n", authkey);
                }
        }
        enumerator->destroy(enumerator);
@@ -842,7 +894,7 @@ static void stroke_list_ocsp(linked_list_t* list, bool utc, FILE *out)
                        first = FALSE;
                }
 
-               fprintf(out, "  signer:   \"%D\"\n", cert->get_issuer(cert));
+               fprintf(out, "  signer:   \"%Y\"\n", cert->get_issuer(cert));
        }
        enumerator->destroy(enumerator);
 }
@@ -967,6 +1019,77 @@ static void list(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out)
 }
 
 /**
+ * Print leases of a single pool
+ */
+static void pool_leases(private_stroke_list_t *this, FILE *out, char *pool,
+                                               host_t *address, u_int size, u_int online, u_int offline)
+{
+       enumerator_t *enumerator;
+       identification_t *id;
+       host_t *lease;
+       bool on;
+       int found = 0;
+       
+       fprintf(out, "Leases in pool '%s', usage: %lu/%lu, %lu online\n",
+                       pool, online + offline, size, online);
+       enumerator = this->attribute->create_lease_enumerator(this->attribute, pool);
+       while (enumerator && enumerator->enumerate(enumerator, &id, &lease, &on))
+       {
+               if (!address || address->ip_equals(address, lease))
+               {
+                       fprintf(out, "  %15H   %s   '%Y'\n",
+                                       lease, on ? "online" : "offline", id);
+                       found++;
+               }
+       }
+       enumerator->destroy(enumerator);
+       if (!found)
+       {
+               fprintf(out, "  no matching leases found\n");
+       }
+}
+
+/**
+ * Implementation of stroke_list_t.leases
+ */
+static void leases(private_stroke_list_t *this, stroke_msg_t *msg, FILE *out)
+{
+       enumerator_t *enumerator;
+       u_int size, offline, online;
+       host_t *address = NULL;
+       char *pool;
+       int found = 0;
+       
+       if (msg->leases.address)
+       {
+               address = host_create_from_string(msg->leases.address, 0);
+       }
+       
+       enumerator = this->attribute->create_pool_enumerator(this->attribute);
+       while (enumerator->enumerate(enumerator, &pool, &size, &online, &offline))
+       {
+               if (!msg->leases.pool || streq(msg->leases.pool, pool))
+               {
+                       pool_leases(this, out, pool, address, size, online, offline);
+                       found++;
+               }
+       }
+       enumerator->destroy(enumerator);
+       if (!found)
+       {
+               if (msg->leases.pool)
+               {
+                       fprintf(out, "pool '%s' not found\n", msg->leases.pool);
+               }
+               else
+               {
+                       fprintf(out, "no pools found\n");
+               }
+       }
+       DESTROY_IF(address);
+}
+
+/**
  * Implementation of stroke_list_t.destroy
  */
 static void destroy(private_stroke_list_t *this)
@@ -977,15 +1100,17 @@ static void destroy(private_stroke_list_t *this)
 /*
  * see header file
  */
-stroke_list_t *stroke_list_create()
+stroke_list_t *stroke_list_create(stroke_attribute_t *attribute)
 {
        private_stroke_list_t *this = malloc_thing(private_stroke_list_t);
        
        this->public.list = (void(*)(stroke_list_t*, stroke_msg_t *msg, FILE *out))list;
        this->public.status = (void(*)(stroke_list_t*, stroke_msg_t *msg, FILE *out,bool))status;
+       this->public.leases = (void(*)(stroke_list_t*, stroke_msg_t *msg, FILE *out))leases;
        this->public.destroy = (void(*)(stroke_list_t*))destroy;
        
        this->uptime = time(NULL);
+       this->attribute = attribute;
        
        return &this->public;
 }