Hi,

I recently ran into a rather surprising issue with using ipsecctl / ipsec.conf, 
where evidently phase 2 parameters from the remote side were accepted 
unconditionally.  Here's my post in misc@ I'd for a little more context:

<http://thread.gmane.org/gmane.os.openbsd.misc/228012>

The thing is that ipsec.conf has enough struture to generate a reasonable 
isakmpd.policy, so I took a crack at a POC.  It's minimally tested, but 
basically it works for me(tm), so I figured it's time to get some feedback.

Known issues:
  - Unspecified parameters don't have constraints corresponding to their 
defaults.
  - Clobbers /etc/isakmpd/isakmpd.policy; I may try a similar strategy as 
resolv.conf.tail's.
  - No way to opt out of auto-generating policy.
  - No address constraints, except for the "unsubtle" case Stuart Henderson 
cited from my thread in misc@.
  - ipsec.conf man page not updated.

Index: sbin/ipsecctl/ike.c
===================================================================
RCS file: /cvs/src/sbin/ipsecctl/ike.c,v
retrieving revision 1.81
diff -u -p -r1.81 ike.c
--- sbin/ipsecctl/ike.c 9 Dec 2015 21:41:50 -0000       1.81
+++ sbin/ipsecctl/ike.c 11 Jan 2016 08:31:58 -0000
@@ -52,6 +52,7 @@ int           ike_ipsec_establish(int, struct ips
 #define        ADD     "C add "
 #define        DELETE  "C rms "
 #define        RMV     "C rmv "
+#define        REINIT  "R"
 
 #define CONF_DFLT_DYNAMIC_DPD_CHECK_INTERVAL   5
 #define CONF_DFLT_DYNAMIC_CHECK_INTERVAL       30
@@ -845,6 +846,9 @@ ike_ipsec_establish(int action, struct i
                break;
        case ACTION_DELETE:
                ret = ike_delete_config(r, fdp);
+               break;
+       case ACTION_REINIT:
+               fprintf(fdp, REINIT);
                break;
        default:
                ret = -1;
Index: sbin/ipsecctl/ipsecctl.c
===================================================================
RCS file: /cvs/src/sbin/ipsecctl/ipsecctl.c,v
retrieving revision 1.80
diff -u -p -r1.80 ipsecctl.c
--- sbin/ipsecctl/ipsecctl.c    10 Dec 2015 17:27:00 -0000      1.80
+++ sbin/ipsecctl/ipsecctl.c    11 Jan 2016 08:31:58 -0000
@@ -33,6 +33,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <libgen.h>
 
 #include "ipsecctl.h"
 #include "pfkey.h"
@@ -40,6 +41,11 @@
 int             ipsecctl_rules(char *, int);
 FILE           *ipsecctl_fopen(const char *, const char *);
 int             ipsecctl_commit(int, struct ipsecctl *);
+static void     ipsecctl_set_policy(const struct ipsecctl *const);
+static void     ipsecctl_commit_policy(const char *const, const int,
+    FILE *const);
+static void     ipsecctl_build_policy(const struct ipsec_rule *const,
+    unsigned int *const, FILE *const);
 int             ipsecctl_add_rule(struct ipsecctl *, struct ipsec_rule *);
 void            ipsecctl_free_rule(struct ipsec_rule *);
 void            ipsecctl_print_addr(struct ipsec_addr_wrap *);
@@ -63,6 +69,9 @@ int            sacompare(const void *, const void
 const char     *showopt;
 char           *isakmpd_fifo = "/var/run/isakmpd.fifo";
 
+static const char isakmpd_conf_d[] = "/etc/isakmpd/";
+static const char isakmpd_policy[] = "isakmpd.policy";
+
 int             first_title = 1;
 
 static const char *showopt_list[] = {
@@ -178,7 +187,169 @@ ipsecctl_commit(int action, struct ipsec
                }
        }
 
+       ipsecctl_set_policy(ipsec);
+
        return (ret);
+}
+
+#define ERR(call) \
+    err(2, "%s: %s: %d: " call, __func__, basename(__FILE__), __LINE__ - 1)
+#define WP(...) \
+    fprintf(temp_policy_fp, __VA_ARGS__)
+
+static void
+ipsecctl_set_policy(const struct ipsecctl *const ipsec)
+{
+       const struct ipsec_rule *r = NULL;
+       unsigned int n_pols = 0;
+       char temp_policy[
+           sizeof(isakmpd_conf_d) - 1 +
+           sizeof(isakmpd_policy) - 1 +
+           10 + /* mkstemp padding */
+           1
+       ];
+       int temp_policy_fd;
+       FILE *temp_policy_fp;
+
+       strlcpy(temp_policy, isakmpd_conf_d, sizeof(temp_policy));
+       strlcat(temp_policy, isakmpd_policy, sizeof(temp_policy));
+       strlcat(temp_policy, "XXXXXXXXXX", sizeof(temp_policy));
+
+       if ((temp_policy_fd = mkstemp(temp_policy)) == -1) {
+               ERR("mkstemp");
+       }
+       if ((temp_policy_fp = fdopen(temp_policy_fd, "w")) == NULL) {
+               ERR("fdopen");
+       }
+
+       WP(
+           "Comment: auto-generated by ipsecctl(8)\n"
+           "Authorizer: \"POLICY\"\n"
+           "Conditions: app_domain==\"IPsec policy\";\n"
+       );
+
+       TAILQ_FOREACH(r, &ipsec->rule_queue, rule_entry) {
+               if (n_pols == 0) {
+                       WP("Licensees: ");
+               } else {
+                       WP(" || ");
+               }
+               WP("\"subpolicy%u\"", n_pols);
+               ++n_pols;
+       }
+       if (n_pols == 0) {
+               return;
+       } else {
+               WP("\n");
+       }
+
+       n_pols = 0;
+       TAILQ_FOREACH(r, &ipsec->rule_queue, rule_entry) {
+               if (r->p2xfs) {
+                       ipsecctl_build_policy(r, &n_pols, temp_policy_fp);
+               }
+               ++n_pols;
+       }
+
+       ipsecctl_commit_policy(temp_policy, temp_policy_fd, temp_policy_fp);
+}
+
+static void
+ipsecctl_commit_policy(const char *const temp_policy,
+    const int temp_policy_fd, FILE *const temp_policy_fp)
+{
+       char policy[
+           sizeof(isakmpd_conf_d) - 1 +
+           sizeof(isakmpd_policy) - 1 +
+           1
+       ];
+       int isakmpd_conf_d_fd;
+
+       if (fflush(temp_policy_fp) != 0) {
+               ERR("fflush");
+       }
+       if (fsync(temp_policy_fd) == -1) {
+               ERR("fsync");
+       }
+
+       strlcpy(policy, isakmpd_conf_d, sizeof(policy));
+       strlcat(policy, isakmpd_policy, sizeof(policy));
+       if (rename(temp_policy, policy) == -1) {
+               ERR("rename");
+       }
+
+       if (fclose(temp_policy_fp) != 0) {
+               ERR("fclose");
+       }
+
+       isakmpd_conf_d_fd = open(isakmpd_conf_d, O_RDONLY | O_DIRECTORY);
+       if (isakmpd_conf_d_fd == -1) {
+               err(2, "%s: %s: %d: open", __func__, basename(__FILE__),
+                   __LINE__ - 2);
+       }
+       if (fsync(isakmpd_conf_d_fd) == -1) {
+               ERR("fsync");
+       }
+       if (close(isakmpd_conf_d_fd) == -1) {
+               ERR("close");
+       }
+
+       ike_ipsec_establish(ACTION_REINIT, NULL, isakmpd_fifo);
+}
+
+static void
+ipsecctl_build_policy(const struct ipsec_rule *const r,
+    unsigned int *const n_pols, FILE *const temp_policy_fp)
+{
+       /* null checked in ipsecctl_set_policy */
+       const struct ipsec_transforms *p2xfs = r->p2xfs;
+       const struct ipsec_xf *xfs[] = {
+               p2xfs->authxf,
+               p2xfs->encxf,
+               p2xfs->groupxf
+       };
+       unsigned int i;
+
+       for (i = 0; i < sizeof(xfs) / sizeof(xfs[0]); ++i) {
+               if (xfs[i] == NULL || xfs[i]->policy == NULL)
+                       continue;
+
+               if (i == 0) {
+                       WP("\n"
+                          "Authorizer: \"subpolicy%u\"\n"
+                          "Conditions: %s_present==\"yes\" &&\n"
+                          "  %s_encapsulation==\"%s\" &&\n"
+                          "  ",
+                          *n_pols,
+                          satype[r->satype],
+                          satype[r->satype],
+                          tmode[r->tmode]
+                       );
+
+                       /* TODO: better address discrimination */
+                       if (r->src && r->src->next == NULL &&
+                           r->src->name != NULL && r->src->af == AF_INET &&
+                           r->src->address.v4.s_addr != INADDR_ANY) {
+                               WP("remote_filter_type==\"IPv4 address\"");
+                               WP(" &&\n  ");
+                       }
+               } else {
+                       WP("  ");
+               }
+
+               if (xfs[i] != p2xfs->encxf) {
+                       WP(satype[r->satype]);
+               }
+               fprintf(temp_policy_fp, xfs[i]->policy);
+
+               if (i != sizeof(xfs) / sizeof(xfs[0]) - 1) {
+                       WP(" &&\n");
+               } else {
+                       WP(";");
+               }
+       }
+
+       WP("\n");
 }
 
 int
Index: sbin/ipsecctl/ipsecctl.h
===================================================================
RCS file: /cvs/src/sbin/ipsecctl/ipsecctl.h,v
retrieving revision 1.69
diff -u -p -r1.69 ipsecctl.h
--- sbin/ipsecctl/ipsecctl.h    9 Dec 2015 21:41:50 -0000       1.69
+++ sbin/ipsecctl/ipsecctl.h    11 Jan 2016 08:31:58 -0000
@@ -31,7 +31,7 @@
 #define IPSECCTL_OPT_SHOWKEY           0x0800
 
 enum {
-       ACTION_ADD, ACTION_DELETE
+       ACTION_ADD, ACTION_DELETE, ACTION_REINIT
 };
 
 #define RULE_FLOW      0x01
@@ -145,6 +145,7 @@ struct ipsec_xf {
        size_t           keymax;
        u_int8_t         noauth;
        u_int8_t         nostatic;
+       char            *policy;
 };
 
 struct ipsec_transforms {
Index: sbin/ipsecctl/parse.y
===================================================================
RCS file: /cvs/src/sbin/ipsecctl/parse.y,v
retrieving revision 1.164
diff -u -p -r1.164 parse.y
--- sbin/ipsecctl/parse.y       9 Dec 2015 21:41:50 -0000       1.164
+++ sbin/ipsecctl/parse.y       11 Jan 2016 08:31:58 -0000
@@ -89,70 +89,179 @@ int                 cmdline_symset(char *);
 static struct ipsecctl *ipsec = NULL;
 static int              debug = 0;
 
+/* Either ah_auth_alg or esp_auth_alg */
 const struct ipsec_xf authxfs[] = {
-       { "unknown",            AUTHXF_UNKNOWN,         0,      0 },
-       { "none",               AUTHXF_NONE,            0,      0 },
-       { "hmac-md5",           AUTHXF_HMAC_MD5,        16,     0 },
-       { "hmac-ripemd160",     AUTHXF_HMAC_RIPEMD160,  20,     0 },
-       { "hmac-sha1",          AUTHXF_HMAC_SHA1,       20,     0 },
-       { "hmac-sha2-256",      AUTHXF_HMAC_SHA2_256,   32,     0 },
-       { "hmac-sha2-384",      AUTHXF_HMAC_SHA2_384,   48,     0 },
-       { "hmac-sha2-512",      AUTHXF_HMAC_SHA2_512,   64,     0 },
-       { NULL,                 0,                      0,      0 },
+       { "unknown",            AUTHXF_UNKNOWN,         0,      0, 0, 0,
+         NULL
+       },
+       { "none",               AUTHXF_NONE,            0,      0, 0, 0,
+         NULL
+       },
+       { "hmac-md5",           AUTHXF_HMAC_MD5,        16,     0, 0, 0,
+         "_auth_alg==\"hmac-md5\""
+       },
+       { "hmac-ripemd160",     AUTHXF_HMAC_RIPEMD160,  20,     0, 0, 0,
+         "_auth_alg==\"hmac-ripemd\""
+       },
+       { "hmac-sha1",          AUTHXF_HMAC_SHA1,       20,     0, 0, 0,
+         "_auth_alg==\"hmac-sha\"",
+       },
+       { "hmac-sha2-256",      AUTHXF_HMAC_SHA2_256,   32,     0, 0, 0,
+         "_auth_alg==\"hmac-sha2-256\""
+       },
+       { "hmac-sha2-384",      AUTHXF_HMAC_SHA2_384,   48,     0, 0, 0,
+         "_auth_alg==\"hmac-sha2-384\""
+       },
+       { "hmac-sha2-512",      AUTHXF_HMAC_SHA2_512,   64,     0, 0, 0,
+         "_auth_alg==\"hmac-sha2-512\""
+       },
+       { NULL,                 0,                      0,      0, 0, 0,
+         NULL
+       },
 };
 
+/* TODO: modify isakmpd/policy.c so you could tell the cipher modes apart. */
 const struct ipsec_xf encxfs[] = {
-       { "unknown",            ENCXF_UNKNOWN,          0,      0,      0, 0 },
-       { "none",               ENCXF_NONE,             0,      0,      0, 0 },
-       { "3des-cbc",           ENCXF_3DES_CBC,         24,     24,     0, 0 },
-       { "aes",                ENCXF_AES,              16,     32,     0, 0 },
-       { "aes-128",            ENCXF_AES_128,          16,     16,     0, 0 },
-       { "aes-192",            ENCXF_AES_192,          24,     24,     0, 0 },
-       { "aes-256",            ENCXF_AES_256,          32,     32,     0, 0 },
-       { "aesctr",             ENCXF_AESCTR,           16+4,   32+4,   0, 1 },
-       { "aes-128-ctr",        ENCXF_AES_128_CTR,      16+4,   16+4,   0, 1 },
-       { "aes-192-ctr",        ENCXF_AES_192_CTR,      24+4,   24+4,   0, 1 },
-       { "aes-256-ctr",        ENCXF_AES_256_CTR,      32+4,   32+4,   0, 1 },
-       { "aes-128-gcm",        ENCXF_AES_128_GCM,      16+4,   16+4,   1, 1 },
-       { "aes-192-gcm",        ENCXF_AES_192_GCM,      24+4,   24+4,   1, 1 },
-       { "aes-256-gcm",        ENCXF_AES_256_GCM,      32+4,   32+4,   1, 1 },
-       { "aes-128-gmac",       ENCXF_AES_128_GMAC,     16+4,   16+4,   1, 1 },
-       { "aes-192-gmac",       ENCXF_AES_192_GMAC,     24+4,   24+4,   1, 1 },
-       { "aes-256-gmac",       ENCXF_AES_256_GMAC,     32+4,   32+4,   1, 1 },
-       { "blowfish",           ENCXF_BLOWFISH,         5,      56,     0, 0 },
-       { "cast128",            ENCXF_CAST128,          5,      16,     0, 0 },
-       { "chacha20-poly1305",  ENCXF_CHACHA20_POLY1305, 32+4,  32+4,   1, 1 },
-       { "null",               ENCXF_NULL,             0,      0,      0, 0 },
-       { NULL,                 0,                      0,      0,      0, 0 },
+       { "unknown",            ENCXF_UNKNOWN,          0,      0,      0, 0,
+         NULL
+       },
+       { "none",               ENCXF_NONE,             0,      0,      0, 0,
+         NULL
+       },
+       { "3des-cbc",           ENCXF_3DES_CBC,         24,     24,     0, 0,
+         "esp_enc_alg==\"3des\""
+       },
+       { "aes",                ENCXF_AES,              16,     32,     0, 0,
+         "esp_enc_alg==\"aes\" && esp_key_length==\"128\""
+       },
+       { "aes-128",            ENCXF_AES_128,          16,     16,     0, 0,
+         "esp_enc_alg==\"aes\" && esp_key_length==\"128\""
+       },
+       { "aes-192",            ENCXF_AES_192,          24,     24,     0, 0,
+         "esp_enc_alg==\"aes\" && esp_key_length==\"192\""
+       },
+       { "aes-256",            ENCXF_AES_256,          32,     32,     0, 0,
+         "esp_enc_alg==\"aes\" && esp_key_length==\"256\""
+       },
+       { "aesctr",             ENCXF_AESCTR,           16+4,   32+4,   0, 1,
+         "esp_enc_alg==\"aes\" && esp_key_length==\"128\""
+       },
+       { "aes-128-ctr",        ENCXF_AES_128_CTR,      16+4,   16+4,   0, 1,
+         "esp_enc_alg==\"aes\" && esp_key_length==\"128\""
+       },
+       { "aes-192-ctr",        ENCXF_AES_192_CTR,      24+4,   24+4,   0, 1,
+         "esp_enc_alg==\"aes\" && esp_key_length==\"192\""
+       },
+       { "aes-256-ctr",        ENCXF_AES_256_CTR,      32+4,   32+4,   0, 1,
+         "esp_enc_alg==\"aes\" && esp_key_length==\"256\""
+       },
+       { "aes-128-gcm",        ENCXF_AES_128_GCM,      16+4,   16+4,   1, 1,
+         "esp_enc_alg==\"aes\" && esp_key_length==\"128\""
+       },
+       { "aes-192-gcm",        ENCXF_AES_192_GCM,      24+4,   24+4,   1, 1,
+         "esp_enc_alg==\"aes\" && esp_key_length==\"192\""
+       },
+       { "aes-256-gcm",        ENCXF_AES_256_GCM,      32+4,   32+4,   1, 1,
+         "esp_enc_alg==\"aes\" && esp_key_length==\"256\""
+       },
+       { "aes-128-gmac",       ENCXF_AES_128_GMAC,     16+4,   16+4,   1, 1,
+         "esp_enc_alg==\"aes\" && esp_key_length==\"128\""
+       },
+       { "aes-192-gmac",       ENCXF_AES_192_GMAC,     24+4,   24+4,   1, 1,
+         "esp_enc_alg==\"aes\" && esp_key_length==\"192\""
+       },
+       { "aes-256-gmac",       ENCXF_AES_256_GMAC,     32+4,   32+4,   1, 1,
+         "esp_enc_alg==\"aes\" && esp_key_length==\"256\""
+       },
+       { "blowfish",           ENCXF_BLOWFISH,         5,      56,     0, 0,
+         "esp_enc_alg==\"blowfish\""
+       },
+       { "cast128",            ENCXF_CAST128,          5,      16,     0, 0,
+         "esp_enc_alg==\"cast\""
+       },
+       { "chacha20-poly1305",  ENCXF_CHACHA20_POLY1305, 32+4,  32+4,   1, 1,
+         NULL /* TODO: modify isakmpd/policy.c */
+       },
+       { "null",               ENCXF_NULL,             0,      0,      0, 0,
+         "esp_enc_alg==\"null\""
+       },
+       { NULL,                 0,                      0,      0,      0, 0,
+       },
 };
 
 const struct ipsec_xf compxfs[] = {
-       { "unknown",            COMPXF_UNKNOWN,         0,      0 },
-       { "deflate",            COMPXF_DEFLATE,         0,      0 },
-       { "lzs",                COMPXF_LZS,             0,      0 },
-       { NULL,                 0,                      0,      0 },
+       { "unknown",            COMPXF_UNKNOWN,         0,      0, 0, 0,
+         NULL
+       },
+       { "deflate",            COMPXF_DEFLATE,         0,      0, 0, 0,
+         "comp_alg==\"deflate\""
+       },
+       { "lzs",                COMPXF_LZS,             0,      0, 0, 0,
+         "comp_alg==\"lzs\""
+       },
+       { NULL,                 0,                      0,      0, 0, 0,
+       },
 };
 
+/* ah_group_desc, esp_group_desc, comp_group_desc, or phase1_group_desc */
 const struct ipsec_xf groupxfs[] = {
-       { "unknown",            GROUPXF_UNKNOWN,        0,      0 },
-       { "none",               GROUPXF_NONE,           0,      0 },
-       { "modp768",            GROUPXF_768,            768,    0 },
-       { "grp1",               GROUPXF_768,            768,    0 },
-       { "modp1024",           GROUPXF_1024,           1024,   0 },
-       { "grp2",               GROUPXF_1024,           1024,   0 },
-       { "modp1536",           GROUPXF_1536,           1536,   0 },
-       { "grp5",               GROUPXF_1536,           1536,   0 },
-       { "modp2048",           GROUPXF_2048,           2048,   0 },
-       { "grp14",              GROUPXF_2048,           2048,   0 },
-       { "modp3072",           GROUPXF_3072,           3072,   0 },
-       { "grp15",              GROUPXF_3072,           3072,   0 },
-       { "modp4096",           GROUPXF_4096,           4096,   0 },
-       { "grp16",              GROUPXF_4096,           4096,   0 },
-       { "modp6144",           GROUPXF_6144,           6144,   0 },
-       { "grp17",              GROUPXF_6144,           6144,   0 },
-       { "modp8192",           GROUPXF_8192,           8192,   0 },
-       { "grp18",              GROUPXF_8192,           8192,   0 },
-       { NULL,                 0,                      0,      0 },
+       { "unknown",            GROUPXF_UNKNOWN,        0,      0, 0, 0,
+         NULL
+       },
+       { "none",               GROUPXF_NONE,           0,      0, 0, 0,
+         NULL
+       },
+       { "modp768",            GROUPXF_768,            768,    0, 0, 0,
+         "_group_desc==\"1\" && pfs==\"yes\""
+       },
+       { "grp1",               GROUPXF_768,            768,    0, 0, 0,
+         "_group_desc==\"1\" && pfs==\"yes\""
+       },
+       { "modp1024",           GROUPXF_1024,           1024,   0, 0, 0,
+         "_group_desc==\"2\" && pfs==\"yes\""
+       },
+       { "grp2",               GROUPXF_1024,           1024,   0, 0, 0,
+         "_group_desc==\"2\" && pfs==\"yes\""
+       },
+       { "modp1536",           GROUPXF_1536,           1536,   0, 0, 0,
+         "_group_desc==\"5\" && pfs==\"yes\""
+       },
+       { "grp5",               GROUPXF_1536,           1536,   0, 0, 0,
+         "_group_desc==\"5\" && pfs==\"yes\""
+       },
+       { "modp2048",           GROUPXF_2048,           2048,   0, 0, 0,
+         "_group_desc==\"14\" && pfs==\"yes\""
+       },
+       { "grp14",              GROUPXF_2048,           2048,   0, 0, 0,
+         "_group_desc==\"14\" && pfs==\"yes\""
+       },
+       { "modp3072",           GROUPXF_3072,           3072,   0, 0, 0,
+         "_group_desc==\"15\" && pfs==\"yes\""
+       },
+       { "grp15",              GROUPXF_3072,           3072,   0, 0, 0,
+         "_group_desc==\"15\" && pfs==\"yes\""
+       },
+       { "modp4096",           GROUPXF_4096,           4096,   0, 0, 0,
+         "_group_desc==\"16\" && pfs==\"yes\""
+       },
+       { "grp16",              GROUPXF_4096,           4096,   0, 0, 0,
+         "_group_desc==\"16\" && pfs==\"yes\""
+       },
+       { "modp6144",           GROUPXF_6144,           6144,   0, 0, 0,
+         "_group_desc==\"17\" && pfs==\"yes\""
+       },
+       { "grp17",              GROUPXF_6144,           6144,   0, 0, 0,
+         "_group_desc==\"17\" && pfs==\"yes\""
+       },
+       { "modp8192",           GROUPXF_8192,           8192,   0, 0, 0,
+         "_group_desc==\"18\" && pfs==\"yes\""
+       },
+       { "grp18",              GROUPXF_8192,           8192,   0, 0, 0,
+         "_group_desc==\"18\" && pfs==\"yes\""
+       },
+       { NULL,                 0,                      0,      0, 0, 0,
+         NULL
+       },
 };
 
 int                     atoul(char *, u_long *);


Reply via email to