Fixed compiler warning.
[strongswan.git] / src / stroke / stroke.c
index d535722..1cb8cc2 100644 (file)
@@ -1,5 +1,7 @@
 /* Stroke for charon is the counterpart to whack from pluto
- * Copyright (C) 2006 Martin Willi - Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2007 Tobias Brunner
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
 #include <dirent.h>
 #include <errno.h>
 #include <stdio.h>
-#include <linux/stddef.h>
+#include <stddef.h>
+#include <string.h>
 
-#include <types.h>
+#include "stroke_msg.h"
+#include "stroke_keywords.h"
 
-#include "stroke.h"
+struct stroke_token {
+    char *name;
+    stroke_keyword_t kw;
+};
 
 static char* push_string(stroke_msg_t *msg, char *string)
 {
-       u_int string_start = msg->length;
+       unsigned long string_start = msg->length;
 
        if (string == NULL ||  msg->length + strlen(string) >= sizeof(stroke_msg_t))
        {
@@ -46,11 +53,16 @@ static char* push_string(stroke_msg_t *msg, char *string)
 
 static int send_stroke_msg (stroke_msg_t *msg)
 {
-       struct sockaddr_un ctl_addr = { AF_UNIX, STROKE_SOCKET };
+       struct sockaddr_un ctl_addr;
        int sock;
-       char buffer[64];
+       char buffer[512];
        int byte_count;
-       
+
+       ctl_addr.sun_family = AF_UNIX;
+       strcpy(ctl_addr.sun_path, STROKE_SOCKET);
+
+       msg->output_verbosity = 1; /* CONTROL */
+
        sock = socket(AF_UNIX, SOCK_STREAM, 0);
        if (sock < 0)
        {
@@ -64,7 +76,7 @@ static int send_stroke_msg (stroke_msg_t *msg)
                close(sock);
                return -1;
        }
-       
+
        /* send message */
        if (write(sock, msg, msg->length) != msg->length)
        {
@@ -72,64 +84,68 @@ static int send_stroke_msg (stroke_msg_t *msg)
                close(sock);
                return -1;
        }
-       
+
        while ((byte_count = read(sock, buffer, sizeof(buffer)-1)) > 0)
        {
                buffer[byte_count] = '\0';
                printf("%s", buffer);
+
+               /* we prompt if we receive the "Passphrase:" magic keyword */
+               if (byte_count >= 12 &&
+                       strcmp(buffer + byte_count - 12, "Passphrase:\n") == 0)
+               {
+                       if (fgets(buffer, sizeof(buffer), stdin))
+                       {
+                               ignore_result(write(sock, buffer, strlen(buffer)));
+                       }
+               }
        }
        if (byte_count < 0)
        {
                fprintf(stderr, "reading from socket failed: %s\n", strerror(errno));
        }
-       
+
        close(sock);
        return 0;
 }
 
 static int add_connection(char *name,
-                                                 char *my_id, char *other_id, 
+                                                 char *my_id, char *other_id,
                                                  char *my_addr, char *other_addr,
-                                                 char *my_net, char *other_net,
-                                                 u_int my_netmask, u_int other_netmask)
+                                                 char *my_nets, char *other_nets)
 {
        stroke_msg_t msg;
-       
+
+       memset(&msg, 0, sizeof(msg));
        msg.length = offsetof(stroke_msg_t, buffer);
        msg.type = STR_ADD_CONN;
-       
+
        msg.add_conn.name = push_string(&msg, name);
        msg.add_conn.ikev2 = 1;
-       
-       msg.add_conn.rekey.ipsec_lifetime = 0;
-       msg.add_conn.rekey.ike_lifetime = 0;
-       msg.add_conn.rekey.margin = 0;
-       msg.add_conn.rekey.tries = 0;
-       msg.add_conn.rekey.fuzz = 0;
-       
+       msg.add_conn.auth_method = 2;
+       msg.add_conn.mode = 1;
+       msg.add_conn.mobike = 1;
+       msg.add_conn.dpd.action = 1;
+
        msg.add_conn.me.id = push_string(&msg, my_id);
        msg.add_conn.me.address = push_string(&msg, my_addr);
-       msg.add_conn.me.subnet = push_string(&msg, my_net);
-       msg.add_conn.me.subnet_mask = my_netmask;
-       msg.add_conn.me.cert = NULL;
-       msg.add_conn.me.ca = NULL;
-       msg.add_conn.me.sendcert = CERT_SEND_IF_ASKED;
-       
+       msg.add_conn.me.ikeport = 500;
+       msg.add_conn.me.subnets = push_string(&msg, my_nets);
+       msg.add_conn.me.sendcert = 1;
+
        msg.add_conn.other.id = push_string(&msg, other_id);
        msg.add_conn.other.address = push_string(&msg, other_addr);
-       msg.add_conn.other.subnet = push_string(&msg, other_net);
-       msg.add_conn.other.subnet_mask = other_netmask;
-       msg.add_conn.other.cert = NULL;
-       msg.add_conn.other.ca = NULL;
-       msg.add_conn.other.sendcert = CERT_SEND_IF_ASKED;
-       
+       msg.add_conn.other.ikeport = 500;
+       msg.add_conn.other.subnets = push_string(&msg, other_nets);
+       msg.add_conn.other.sendcert = 1;
+
        return send_stroke_msg(&msg);
 }
 
 static int del_connection(char *name)
 {
        stroke_msg_t msg;
-       
+
        msg.length = offsetof(stroke_msg_t, buffer);
        msg.type = STR_DEL_CONN;
        msg.initiate.name = push_string(&msg, name);
@@ -139,7 +155,7 @@ static int del_connection(char *name)
 static int initiate_connection(char *name)
 {
        stroke_msg_t msg;
-       
+
        msg.length = offsetof(stroke_msg_t, buffer);
        msg.type = STR_INITIATE;
        msg.initiate.name = push_string(&msg, name);
@@ -149,55 +165,134 @@ static int initiate_connection(char *name)
 static int terminate_connection(char *name)
 {
        stroke_msg_t msg;
-       
+
        msg.type = STR_TERMINATE;
        msg.length = offsetof(stroke_msg_t, buffer);
        msg.initiate.name = push_string(&msg, name);
        return send_stroke_msg(&msg);
 }
 
-static int show_status(char *mode, char *connection)
+static int terminate_connection_srcip(char *start, char *end)
 {
        stroke_msg_t msg;
-       
-       if (strcmp(mode, "statusall") == 0)
-               msg.type = STR_STATUS_ALL;
-       else
-               msg.type = STR_STATUS;
 
+       msg.type = STR_TERMINATE_SRCIP;
+       msg.length = offsetof(stroke_msg_t, buffer);
+       msg.terminate_srcip.start = push_string(&msg, start);
+       msg.terminate_srcip.end = push_string(&msg, end);
+       return send_stroke_msg(&msg);
+}
+
+static int route_connection(char *name)
+{
+       stroke_msg_t msg;
+
+       msg.type = STR_ROUTE;
+       msg.length = offsetof(stroke_msg_t, buffer);
+       msg.route.name = push_string(&msg, name);
+       return send_stroke_msg(&msg);
+}
+
+static int unroute_connection(char *name)
+{
+       stroke_msg_t msg;
+
+       msg.type = STR_UNROUTE;
+       msg.length = offsetof(stroke_msg_t, buffer);
+       msg.unroute.name = push_string(&msg, name);
+       return send_stroke_msg(&msg);
+}
+
+static int show_status(stroke_keyword_t kw, char *connection)
+{
+       stroke_msg_t msg;
+
+       msg.type = (kw == STROKE_STATUS)? STR_STATUS:STR_STATUS_ALL;
        msg.length = offsetof(stroke_msg_t, buffer);
        msg.status.name = push_string(&msg, connection);
        return send_stroke_msg(&msg);
 }
 
-static int list_certs(void)
+static int list_flags[] = {
+       LIST_PUBKEYS,
+       LIST_CERTS,
+       LIST_CACERTS,
+       LIST_OCSPCERTS,
+       LIST_AACERTS,
+       LIST_ACERTS,
+       LIST_GROUPS,
+       LIST_CAINFOS,
+       LIST_CRLS,
+       LIST_OCSP,
+       LIST_ALGS,
+       LIST_ALL
+};
+
+static int list(stroke_keyword_t kw, int utc)
 {
        stroke_msg_t msg;
-       
-       msg.type = STR_LIST_CERTS;
+
+       msg.type = STR_LIST;
        msg.length = offsetof(stroke_msg_t, buffer);
+       msg.list.utc = utc;
+       msg.list.flags = list_flags[kw - STROKE_LIST_FIRST];
        return send_stroke_msg(&msg);
 }
 
-static int set_logtype(char *context, char *type, int enable)
+static int reread_flags[] = {
+       REREAD_SECRETS,
+       REREAD_CACERTS,
+       REREAD_OCSPCERTS,
+       REREAD_AACERTS,
+       REREAD_ACERTS,
+       REREAD_CRLS,
+       REREAD_ALL
+};
+
+static int reread(stroke_keyword_t kw)
 {
        stroke_msg_t msg;
-       
-       msg.type = STR_LOGTYPE;
+
+       msg.type = STR_REREAD;
        msg.length = offsetof(stroke_msg_t, buffer);
-       msg.logtype.context = push_string(&msg, context);
-       msg.logtype.type = push_string(&msg, type);
-       msg.logtype.enable = enable;
+       msg.reread.flags = reread_flags[kw - STROKE_REREAD_FIRST];
        return send_stroke_msg(&msg);
 }
 
-static int set_loglevel(char *context, u_int level)
+static int purge_flags[] = {
+       PURGE_OCSP,
+       PURGE_IKE,
+};
+
+static int purge(stroke_keyword_t kw)
 {
        stroke_msg_t msg;
-       
+
+       msg.type = STR_PURGE;
+       msg.length = offsetof(stroke_msg_t, buffer);
+       msg.purge.flags = purge_flags[kw - STROKE_PURGE_FIRST];
+       return send_stroke_msg(&msg);
+}
+
+static int leases(stroke_keyword_t kw, char *pool, char *address)
+{
+
+       stroke_msg_t msg;
+
+       msg.type = STR_LEASES;
+       msg.length = offsetof(stroke_msg_t, buffer);
+       msg.leases.pool = push_string(&msg, pool);
+       msg.leases.address = push_string(&msg, address);
+       return send_stroke_msg(&msg);
+}
+
+static int set_loglevel(char *type, u_int level)
+{
+       stroke_msg_t msg;
+
        msg.type = STR_LOGLEVEL;
        msg.length = offsetof(stroke_msg_t, buffer);
-       msg.loglevel.context = push_string(&msg, context);
+       msg.loglevel.type = push_string(&msg, type);
        msg.loglevel.level = level;
        return send_stroke_msg(&msg);
 }
@@ -219,8 +314,7 @@ static void exit_usage(char *error)
        printf("           MY_NET OTHER_NET MY_NETBITS OTHER_NETBITS\n");
        printf("    where: ID is any IKEv2 ID \n");
        printf("           ADDR is a IPv4 address\n");
-       printf("           NET is a IPv4 address of the subnet to tunnel\n");
-       printf("           NETBITS is the size of the subnet, as the \"24\" in 192.168.0.0/24\n");
+       printf("           NET is a IPv4 subnet in CIDR notation\n");
        printf("  Delete a connection:\n");
        printf("    stroke delete NAME\n");
        printf("    where: NAME is a connection name added with \"stroke add\"\n");
@@ -230,100 +324,149 @@ static void exit_usage(char *error)
        printf("  Terminate a connection:\n");
        printf("    stroke down NAME\n");
        printf("    where: NAME is a connection name added with \"stroke add\"\n");
-       printf("  Set logtype for a logging context:\n");
-       printf("    stroke logtype CONTEXT TYPE ENABLE\n");
-       printf("    where: CONTEXT is PARSR|GNRAT|IKESA|SAMGR|CHDSA|MESSG|TPOOL|WORKR|SCHED|\n");
-       printf("                      SENDR|RECVR|SOCKT|TESTR|DAEMN|CONFG|ENCPL|PAYLD\n");
-       printf("           TYPE is CONTROL|ERROR|AUDIT|RAW|PRIVATE\n");
-       printf("           ENABLE is 0|1\n");
-       printf("  Set loglevel for a logging context:\n");
-       printf("    stroke loglevel CONTEXT LEVEL\n");
-       printf("    where: CONTEXT is PARSR|GNRAT|IKESA|SAMGR|CHDSA|MESSG|TPOOL|WORKR|SCHED|\n");
-       printf("                      SENDR|RECVR|SOCKT|TESTR|DAEMN|CONFG|ENCPL|PAYLD\n");
-       printf("           LEVEL is 0|1|2|3\n");
+       printf("  Terminate a connection by remote srcip:\n");
+       printf("    stroke down-srcip START [END]\n");
+       printf("    where: START and optional END define the clients source IP\n");
+       printf("  Set loglevel for a logging type:\n");
+       printf("    stroke loglevel TYPE LEVEL\n");
+       printf("    where: TYPE is any|dmn|mgr|ike|chd|job|cfg|knl|net|enc|lib\n");
+       printf("           LEVEL is -1|0|1|2|3|4\n");
        printf("  Show connection status:\n");
        printf("    stroke status\n");
-       printf("  Show list of locally loaded certificates:\n");
-       printf("    stroke listcerts\n");
+       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|listall\n");
+       printf("  Show list of supported algorithms:\n");
+       printf("    stroke listalgs\n");
+       printf("  Reload authority and attribute certificates:\n");
+       printf("    stroke rereadcacerts|rereadocspcerts|rereadaacerts|rereadacerts\n");
+       printf("  Reload secrets and crls:\n");
+       printf("    stroke rereadsecrets|rereadcrls|rereadall\n");
+       printf("  Purge ocsp cache entries:\n");
+       printf("    stroke purgeocsp\n");
+       printf("  Purge IKE_SAs without a CHILD_SA:\n");
+       printf("    stroke purgeike\n");
+       printf("  Show leases of a pool:\n");
+       printf("    stroke leases [POOL [ADDRESS]]\n");
        exit_error(error);
 }
 
 int main(int argc, char *argv[])
 {
+       const stroke_token_t *token;
        int res = 0;
-       char *op;
-       
+
        if (argc < 2)
        {
                exit_usage(NULL);
        }
-       
-       op = argv[1];
 
-       if (streq(op, "status") || streq(op, "statusall"))
-       {
-               res = show_status(op, argc > 2 ? argv[2] : NULL);
-       }
-       else if (streq(op, "listcerts") || streq(op, "listall"))
-       {
-               res = list_certs();
-       }
-       else if (streq(op, "up"))
-       {
-               if (argc < 3)
-               {
-                       exit_usage("\"up\" needs a connection name");
-               }
-               res = initiate_connection(argv[2]);
-       }
-       else if (streq(op, "down"))
-       {
-               if (argc < 3)
-               {
-                       exit_usage("\"down\" needs a connection name");
-               }
-               res = terminate_connection(argv[2]);
-       }
-       else if (streq(op, "add"))
-       {
-               if (argc < 11)
-               {
-                       exit_usage("\"add\" needs more parameters...");
-               }
-               res = add_connection(argv[2],
-                                                        argv[3], argv[4], 
-                                                        argv[5], argv[6], 
-                                                        argv[7], argv[8], 
-                                                        atoi(argv[9]), atoi(argv[10]));
-       }
-       else if (streq(op, "delete"))
-       {
-               if (argc < 3)
-               {
-                       exit_usage("\"delete\" needs a connection name");
-               }
-               res = del_connection(argv[2]);
-       }
-       else if (streq(op, "logtype"))
+       token = in_word_set(argv[1], strlen(argv[1]));
+
+       if (token == NULL)
        {
-               if (argc < 5)
-               {
-                       exit_usage("\"logtype\" needs more parameters...");
-               }
-               res = set_logtype(argv[2], argv[3], atoi(argv[4])); 
+               exit_usage("unknown keyword");
        }
-       else if (streq(op, "loglevel"))
-       {
-               if (argc < 4)
-               {
-                       exit_usage("\"logtype\" needs more parameters...");
-               }
-               res = set_loglevel(argv[2], atoi(argv[3])); 
-       }
-       else
+
+       switch (token->kw)
        {
-               exit_usage(NULL);
+               case STROKE_ADD:
+                       if (argc < 11)
+                       {
+                               exit_usage("\"add\" needs more parameters...");
+                       }
+                       res = add_connection(argv[2],
+                                                                argv[3], argv[4],
+                                                                argv[5], argv[6],
+                                                                argv[7], argv[8]);
+                       break;
+               case STROKE_DELETE:
+               case STROKE_DEL:
+                       if (argc < 3)
+                       {
+                               exit_usage("\"delete\" needs a connection name");
+                       }
+                       res = del_connection(argv[2]);
+                       break;
+               case STROKE_UP:
+                       if (argc < 3)
+                       {
+                               exit_usage("\"up\" needs a connection name");
+                       }
+                       res = initiate_connection(argv[2]);
+                       break;
+               case STROKE_DOWN:
+                       if (argc < 3)
+                       {
+                               exit_usage("\"down\" needs a connection name");
+                       }
+                       res = terminate_connection(argv[2]);
+                       break;
+               case STROKE_DOWN_SRCIP:
+                       if (argc < 3)
+                       {
+                               exit_usage("\"down-srcip\" needs start and optional end address");
+                       }
+                       res = terminate_connection_srcip(argv[2], argc > 3 ? argv[3] : NULL);
+                       break;
+               case STROKE_ROUTE:
+                       if (argc < 3)
+                       {
+                               exit_usage("\"route\" needs a connection name");
+                       }
+                       res = route_connection(argv[2]);
+                       break;
+               case STROKE_UNROUTE:
+                       if (argc < 3)
+                       {
+                               exit_usage("\"unroute\" needs a connection name");
+                       }
+                       res = unroute_connection(argv[2]);
+                       break;
+               case STROKE_LOGLEVEL:
+                       if (argc < 4)
+                       {
+                               exit_usage("\"logtype\" needs more parameters...");
+                       }
+                       res = set_loglevel(argv[2], atoi(argv[3]));
+                       break;
+               case STROKE_STATUS:
+               case STROKE_STATUSALL:
+                       res = show_status(token->kw, argc > 2 ? argv[2] : NULL);
+                       break;
+               case STROKE_LIST_PUBKEYS:
+               case STROKE_LIST_CERTS:
+               case STROKE_LIST_CACERTS:
+               case STROKE_LIST_OCSPCERTS:
+               case STROKE_LIST_AACERTS:
+               case STROKE_LIST_ACERTS:
+               case STROKE_LIST_CAINFOS:
+               case STROKE_LIST_CRLS:
+               case STROKE_LIST_OCSP:
+               case STROKE_LIST_ALGS:
+               case STROKE_LIST_ALL:
+                       res = list(token->kw, argc > 2 && strcmp(argv[2], "--utc") == 0);
+                       break;
+               case STROKE_REREAD_SECRETS:
+               case STROKE_REREAD_CACERTS:
+               case STROKE_REREAD_OCSPCERTS:
+               case STROKE_REREAD_AACERTS:
+               case STROKE_REREAD_ACERTS:
+               case STROKE_REREAD_CRLS:
+               case STROKE_REREAD_ALL:
+                       res = reread(token->kw);
+                       break;
+               case STROKE_PURGE_OCSP:
+               case STROKE_PURGE_IKE:
+                       res = purge(token->kw);
+                       break;
+               case STROKE_LEASES:
+                       res = leases(token->kw, argc > 2 ? argv[2] : NULL,
+                                                argc > 3 ? argv[3] : NULL);
+                       break;
+               default:
+                       exit_usage(NULL);
        }
-       
        return res;
 }