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 *);