diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 2000-10-16 23:26:21 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 2000-10-16 23:26:21 +0000 |
commit | 4d613ead133566d1737cd5762c80b4a3e82f8259 (patch) | |
tree | c82b6fb2596e263d7e4dd9cbb1091a1dbafb09c1 /sbin/isakmpd | |
parent | 1a2e8187b2eb660c984a2258104199be2beab5c1 (diff) |
Merge with EOM 1.59
author: provos
better referencing. okay niklas@
author: niklas
Name collissions introduced by me, DOH!
author: niklas
Allow new and old style configuration simultaneously
author: niklas
Backward compatibility with old style configuration
author: niklas
remove redundant ifdefs
author: niklas
facistoid style and naming pedantery
author: angelos
Construct the ISAKMP-peer section such that it actually contains the
src/dst Phase 1 IDs (so we don't have to worry about configuration
conflicts). I should update the manpage....
author: angelos
Use local-address, not listen-address.
author: angelos
First cut of ACQUIRE handling, fully functional but not entirely
dynamic (it depends on the pre-defined Transforms and
Suites). Nonetheless, it is possible to use isakmpd without a
configuration file when using certificates for authentication.
author: angelos
Add RIPEMD negotiation/configuration.
Diffstat (limited to 'sbin/isakmpd')
-rw-r--r-- | sbin/isakmpd/pf_key_v2.c | 795 |
1 files changed, 670 insertions, 125 deletions
diff --git a/sbin/isakmpd/pf_key_v2.c b/sbin/isakmpd/pf_key_v2.c index fee9dd06a9b..523d33220be 100644 --- a/sbin/isakmpd/pf_key_v2.c +++ b/sbin/isakmpd/pf_key_v2.c @@ -1,5 +1,5 @@ -/* $OpenBSD: pf_key_v2.c,v 1.32 2000/10/10 13:34:58 niklas Exp $ */ -/* $EOM: pf_key_v2.c,v 1.49 2000/10/10 13:30:26 niklas Exp $ */ +/* $OpenBSD: pf_key_v2.c,v 1.33 2000/10/16 23:26:20 niklas Exp $ */ +/* $EOM: pf_key_v2.c,v 1.59 2000/10/16 18:16:59 provos Exp $ */ /* * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. @@ -65,6 +65,14 @@ #include "timer.h" #include "transport.h" +#define IN6_IS_ADDR_FULL(a) \ + ((*(u_int32_t *)(void *)(&(a)->s6_addr[0]) == 0xffff) \ + && (*(u_int32_t *)(void *)(&(a)->s6_addr[4]) == 0xffff) \ + && (*(u_int32_t *)(void *)(&(a)->s6_addr[8]) == 0xffff) \ + && (*(u_int32_t *)(void *)(&(a)->s6_addr[12]) == 0xffff)) + +#define ADDRESS_MAX sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255" + /* * PF_KEY v2 always work with 64-bit entities and aligns on 64-bit boundaries. */ @@ -89,6 +97,9 @@ TAILQ_HEAD (pf_key_v2_msg, pf_key_v2_node); #define PF_KEY_V2_NODE_MALLOCED 1 #define PF_KEY_V2_NODE_MARK 2 +/* Used to derive "unique" connection identifiers */ +int connection_seq = 0; + #ifdef KAME /* * KAME requires the sadb_msg_seq of an UPDATE be the same of that of the @@ -582,6 +593,7 @@ pf_key_v2_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, struct sadb_address *addr = 0; struct sadb_spirange spirange; struct pf_key_v2_msg *getspi = 0, *ret = 0; + struct pf_key_v2_node *ext; u_int8_t *spi = 0; int len, err; #ifdef KAME @@ -602,7 +614,7 @@ pf_key_v2_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, goto cleanup; } /* - * XXX When we have acquires working, the sequence number have to be set + * XXX When we have acquires working, the sequence number has to be set * from the acquire message. */ msg.sadb_msg_seq = 0; @@ -611,9 +623,9 @@ pf_key_v2_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, goto cleanup; #ifdef KAME - memset(&ssa2, 0, sizeof(ssa2)); + memset(&ssa2, 0, sizeof ssa2); ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - ssa2.sadb_x_sa2_len = sizeof(ssa2) / PF_KEY_V2_CHUNK; + ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK; ssa2.sadb_x_sa2_mode = 0; if (pf_key_v2_msg_add (getspi, (struct sadb_ext *)&ssa2, 0) == -1) goto cleanup; @@ -681,12 +693,13 @@ pf_key_v2_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, goto cleanup; } - sa = (struct sadb_sa *)pf_key_v2_find_ext (ret, SADB_EXT_SA)->seg; - if (!sa) + ext = pf_key_v2_find_ext (ret, SADB_EXT_SA); + if (!ext) { log_print ("pf_key_v2_get_spi: no SA extension found"); goto cleanup; } + sa = ext->seg; *sz = sizeof sa->sadb_sa_spi; spi = malloc (*sz); @@ -778,7 +791,7 @@ pf_key_v2_set_spi (struct sa *sa, struct proto *proto, int incoming) #endif default: - /* XXX Log? */ + LOG_DBG ((LOG_SYSDEP, 50, "pf_key_v2_set_spi: unknown encryption algorithm %d", proto->id)); return -1; } @@ -800,9 +813,16 @@ pf_key_v2_set_spi (struct sa *sa, struct proto *proto, int incoming) #endif break; +#ifndef KAME + case IPSEC_AUTH_HMAC_RIPEMD: + ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC96; + break; +#endif + case IPSEC_AUTH_DES_MAC: case IPSEC_AUTH_KPDK: - /* XXX Log? */ + /* XXX We should be supporting KPDK */ + LOG_DBG ((LOG_SYSDEP, 50, "pf_key_v2_set_spi: unknown authentication algorithm %d", iproto->auth)); return -1; default: @@ -834,8 +854,14 @@ pf_key_v2_set_spi (struct sa *sa, struct proto *proto, int incoming) #endif break; +#ifndef KAME + case IPSEC_AH_RIPEMD: + ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC96; + break; +#endif + default: - /* XXX Log? */ + LOG_DBG ((LOG_SYSDEP, 50, "pf_key_v2_set_spi: unknown authentication algorithm %d", proto->id)); goto cleanup; } break; @@ -862,9 +888,9 @@ pf_key_v2_set_spi (struct sa *sa, struct proto *proto, int incoming) goto cleanup; #ifdef KAME - memset(&ssa2, 0, sizeof(ssa2)); + memset(&ssa2, 0, sizeof ssa2); ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - ssa2.sadb_x_sa2_len = sizeof(ssa2) / PF_KEY_V2_CHUNK; + ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK; ssa2.sadb_x_sa2_mode = 0; if (pf_key_v2_msg_add (update, (struct sadb_ext *)&ssa2, 0) == -1) goto cleanup; @@ -898,7 +924,7 @@ pf_key_v2_set_spi (struct sa *sa, struct proto *proto, int incoming) life->sadb_lifetime_bytes = sa->kilobytes * 1024; /* * XXX I am not sure which one is best in security respect. Maybe the - * RFCs actually mandate what a lifetime reaaly is. + * RFCs actually mandate what a lifetime really is. */ #if 0 life->sadb_lifetime_addtime = 0; @@ -943,7 +969,7 @@ pf_key_v2_set_spi (struct sa *sa, struct proto *proto, int incoming) /* * Setup the ADDRESS extensions. * - * XXX Addresses has to be thought through. Assumes IPv4. + * XXX Addresses have to be thought through. Assumes IPv4. */ if (incoming) sa->transport->vtbl->get_dst (sa->transport, &src, &srclen); @@ -1111,9 +1137,6 @@ pf_key_v2_mask_to_bits (u_int32_t mask) return (33 - ffs (~mask + 1)) % 33; } -#undef OPENBSD_IPSEC_API_VERSION - -#ifndef OPENBSD_IPSEC_API_VERSION /* * Enable/disable a flow. * XXX Assumes OpenBSD {ADD,DEL}FLOW extensions. @@ -1126,17 +1149,15 @@ pf_key_v2_flow (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr, { #if defined (SADB_X_ADDFLOW) && defined (SADB_X_DELFLOW) struct sadb_msg msg; - struct sadb_sa ssa; #ifdef SADB_X_EXT_FLOW_TYPE struct sadb_protocol flowtype; +#else + struct sadb_sa ssa; #endif struct sadb_address *addr = 0; struct pf_key_v2_msg *flow = 0, *ret = 0; size_t len; int err; -#ifdef KAME - struct sadb_x_sa2 ssa2; -#endif #if !defined (SADB_X_SAFLAGS_INGRESS_FLOW) && !defined(SADB_X_EXT_FLOW_TYPE) if (ingress) @@ -1161,15 +1182,17 @@ pf_key_v2_flow (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr, if (!flow) goto cleanup; -#ifdef KAME - memset(&ssa2, 0, sizeof(ssa2)); - ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - ssa2.sadb_x_sa2_len = sizeof(ssa2) / PF_KEY_V2_CHUNK; - ssa2.sadb_x_sa2_mode = 0; - if (pf_key_v2_msg_add (flow, (struct sadb_ext *)&ssa2, 0) == -1) - goto cleanup; -#endif +#ifdef SADB_X_EXT_FLOW_TYPE + /* Setup the flow type extension. */ + flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE; + flowtype.sadb_protocol_len = sizeof flowtype / PF_KEY_V2_CHUNK; + flowtype.sadb_protocol_direction + = ingress ? IPSP_DIRECTION_IN : IPSP_DIRECTION_OUT; + flowtype.sadb_protocol_proto = FLOW_X_TYPE_REQUIRE; + if (pf_key_v2_msg_add (flow, (struct sadb_ext *)&flowtype, 0) == -1) + goto cleanup; +#else /* SADB_X_EXT_FLOW_TYPE */ /* Setup the SA extension. */ ssa.sadb_sa_exttype = SADB_EXT_SA; ssa.sadb_sa_len = sizeof ssa / PF_KEY_V2_CHUNK; @@ -1190,23 +1213,12 @@ pf_key_v2_flow (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr, if (pf_key_v2_msg_add (flow, (struct sadb_ext *)&ssa, 0) == -1) goto cleanup; - -#ifdef SADB_X_EXT_FLOW_TYPE - /* Setup the flow type extension. */ - flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE; - flowtype.sadb_protocol_len = sizeof flowtype / PF_KEY_V2_CHUNK; - flowtype.sadb_protocol_direction - = ingress ? IPSP_DIRECTION_IN : IPSP_DIRECTION_OUT; - flowtype.sadb_protocol_proto = FLOW_X_TYPE_REQUIRE; - - if (pf_key_v2_msg_add (flow, (struct sadb_ext *)&flowtype, 0) == -1) - goto cleanup; -#endif +#endif /* SADB_X_EXT_FLOW_TYPE */ /* * Setup the ADDRESS extensions. * - * XXX Addresses has to be thought through. Assumes IPv4. + * XXX Addresses have to be thought through. Assumes IPv4. */ len = sizeof *addr + PF_KEY_V2_ROUND (sizeof (struct sockaddr_in)); if (!delete || ingress) @@ -1216,10 +1228,6 @@ pf_key_v2_flow (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr, goto cleanup; addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifndef __OpenBSD__ - addr->sadb_address_proto = 0; - addr->sadb_address_prefixlen = 0; -#endif addr->sadb_address_reserved = 0; memset (addr + 1, '\0', sizeof (struct sockaddr_in)); ((struct sockaddr_in *)(addr + 1))->sin_len @@ -1243,10 +1251,6 @@ pf_key_v2_flow (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr, goto cleanup; addr->sadb_address_exttype = SADB_X_EXT_SRC_FLOW; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifndef __OpenBSD__ - addr->sadb_address_proto = 0; - addr->sadb_address_prefixlen = 0; -#endif addr->sadb_address_reserved = 0; memset (addr + 1, '\0', sizeof (struct sockaddr_in)); ((struct sockaddr_in *)(addr + 1))->sin_len = sizeof (struct sockaddr_in); @@ -1263,10 +1267,6 @@ pf_key_v2_flow (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr, goto cleanup; addr->sadb_address_exttype = SADB_X_EXT_SRC_MASK; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifndef __OpenBSD__ - addr->sadb_address_proto = 0; - addr->sadb_address_prefixlen = 0; -#endif addr->sadb_address_reserved = 0; memset (addr + 1, '\0', sizeof (struct sockaddr_in)); ((struct sockaddr_in *)(addr + 1))->sin_len = sizeof (struct sockaddr_in); @@ -1283,10 +1283,6 @@ pf_key_v2_flow (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr, goto cleanup; addr->sadb_address_exttype = SADB_X_EXT_DST_FLOW; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifndef __OpenBSD__ - addr->sadb_address_proto = 0; - addr->sadb_address_prefixlen = 0; -#endif addr->sadb_address_reserved = 0; memset (addr + 1, '\0', sizeof (struct sockaddr_in)); ((struct sockaddr_in *)(addr + 1))->sin_len = sizeof (struct sockaddr_in); @@ -1303,10 +1299,6 @@ pf_key_v2_flow (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr, goto cleanup; addr->sadb_address_exttype = SADB_X_EXT_DST_MASK; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifndef __OpenBSD__ - addr->sadb_address_proto = 0; - addr->sadb_address_prefixlen = 0; -#endif addr->sadb_address_reserved = 0; memset (addr + 1, '\0', sizeof (struct sockaddr_in)); ((struct sockaddr_in *)(addr + 1))->sin_len = sizeof (struct sockaddr_in); @@ -1329,12 +1321,10 @@ pf_key_v2_flow (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr, err = ((struct sadb_msg *)TAILQ_FIRST (ret)->seg)->sadb_msg_errno; if (err) { -#ifdef __OpenBSD__ if (err == ESRCH) /* These are common and usually harmless. */ LOG_DBG ((LOG_SYSDEP, 10, "pf_key_v2_flow: %sFLOW: %s", delete ? "DEL" : "ADD", strerror (err))); else -#endif log_print ("pf_key_v2_flow: %sFLOW: %s", delete ? "DEL" : "ADD", strerror (err)); goto cleanup; @@ -1358,6 +1348,7 @@ pf_key_v2_flow (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr, struct sadb_msg msg; struct sadb_x_policy *policy = 0; struct sadb_x_ipsecrequest *ipsecrequest; + struct sadb_x_sa2 ssa2; struct sadb_address *addr = 0; struct sockaddr_in *saddr; u_int8_t @@ -1365,9 +1356,6 @@ pf_key_v2_flow (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr, struct pf_key_v2_msg *flow = 0, *ret = 0; size_t len; int err; -#ifdef KAME - struct sadb_x_sa2 ssa2; -#endif msg.sadb_msg_type = delete ? SADB_X_SPDDELETE : SADB_X_SPDADD; msg.sadb_msg_satype = SADB_SATYPE_UNSPEC; @@ -1376,19 +1364,17 @@ pf_key_v2_flow (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr, if (!flow) goto cleanup; -#ifdef KAME - memset(&ssa2, 0, sizeof(ssa2)); + memset(&ssa2, 0, sizeof ssa2); ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - ssa2.sadb_x_sa2_len = sizeof(ssa2) / PF_KEY_V2_CHUNK; + ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK; ssa2.sadb_x_sa2_mode = 0; if (pf_key_v2_msg_add (flow, (struct sadb_ext *)&ssa2, 0) == -1) goto cleanup; -#endif /* * Setup the ADDRESS extensions. * - * XXX Addresses has to be thought through. Assumes IPv4. + * XXX Addresses have to be thought through. Assumes IPv4. */ len = sizeof *addr + PF_KEY_V2_ROUND (sizeof (struct sockaddr_in)); addr = malloc (len); @@ -1396,10 +1382,8 @@ pf_key_v2_flow (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr, goto cleanup; addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifndef __OpenBSD__ addr->sadb_address_proto = IPSEC_ULPROTO_ANY; addr->sadb_address_prefixlen = pf_key_v2_mask_to_bits (ntohl (lmask)); -#endif addr->sadb_address_reserved = 0; memset (addr + 1, '\0', sizeof (struct sockaddr_in)); ((struct sockaddr_in *)(addr + 1))->sin_len = sizeof (struct sockaddr_in); @@ -1416,10 +1400,8 @@ pf_key_v2_flow (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr, goto cleanup; addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; -#ifndef __OpenBSD__ addr->sadb_address_proto = IPSEC_ULPROTO_ANY; addr->sadb_address_prefixlen = pf_key_v2_mask_to_bits (ntohl (rmask)); -#endif addr->sadb_address_reserved = 0; memset (addr + 1, '\0', sizeof (struct sockaddr_in)); ((struct sockaddr_in *)(addr + 1))->sin_len = sizeof (struct sockaddr_in); @@ -1514,16 +1496,11 @@ pf_key_v2_flow (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr, return -1; #endif } -#endif /* Enable a flow given a SA. */ int pf_key_v2_enable_sa (struct sa *sa) { -#if OPENBSD_IPSEC_API_VERSION == 1 - /* We don't mess with flows */ - return 0; -#else struct ipsec_sa *isa = sa->data; struct sockaddr *dst, *src; int dstlen, srclen, error; @@ -1580,10 +1557,8 @@ pf_key_v2_enable_sa (struct sa *sa) isa->src_mask, proto->spi[1], proto->proto, ((struct sockaddr_in *)src)->sin_addr.s_addr, ((struct sockaddr_in *)dst)->sin_addr.s_addr, 0, 1); -#endif } -#ifndef OPENBSD_IPSEC_API_VERSION /* Disable a flow given a SA. */ static int pf_key_v2_disable_sa (struct sa *sa, int incoming) @@ -1646,7 +1621,6 @@ pf_key_v2_disable_sa (struct sa *sa, int incoming) 1, 1); } } -#endif /* * Delete the IPSec SA represented by the INCOMING direction in protocol PROTO @@ -1655,9 +1629,6 @@ pf_key_v2_disable_sa (struct sa *sa, int incoming) int pf_key_v2_delete_spi (struct sa *sa, struct proto *proto, int incoming) { -#if OPENBSD_IPSEC_API_VERSION == 1 - return 0; -#else struct sadb_msg msg; struct sadb_sa ssa; struct sadb_address *addr = 0; @@ -1672,8 +1643,10 @@ pf_key_v2_delete_spi (struct sa *sa, struct proto *proto, int incoming) * If the SA was outbound and it has not yet been replaced, or it's * incoming, remove the flow associated with it. * We ignore any errors from the disabling of the flow, it does not matter. + * Only remove flows if it was not an SA acquired by the kernel. */ - if ((!incoming && !(sa->flags & SA_FLAG_REPLACED)) || incoming) + if (((!incoming && !(sa->flags & SA_FLAG_REPLACED)) || incoming) + && !(sa->flags & SA_FLAG_ONDEMAND)) pf_key_v2_disable_sa (sa, incoming); msg.sadb_msg_type = SADB_DELETE; @@ -1707,9 +1680,9 @@ pf_key_v2_delete_spi (struct sa *sa, struct proto *proto, int incoming) goto cleanup; #ifdef KAME - memset(&ssa2, 0, sizeof(ssa2)); + memset(&ssa2, 0, sizeof ssa2); ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - ssa2.sadb_x_sa2_len = sizeof(ssa2) / PF_KEY_V2_CHUNK; + ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK; ssa2.sadb_x_sa2_mode = 0; if (pf_key_v2_msg_add (delete, (struct sadb_ext *)&ssa2, 0) == -1) goto cleanup; @@ -1718,7 +1691,7 @@ pf_key_v2_delete_spi (struct sa *sa, struct proto *proto, int incoming) /* * Setup the ADDRESS extensions. * - * XXX Addresses has to be thought through. Assumes IPv4. + * XXX Addresses have to be thought through. Assumes IPv4. */ if (incoming) sa->transport->vtbl->get_dst (sa->transport, &saddr, &saddrlen); @@ -1790,7 +1763,6 @@ pf_key_v2_delete_spi (struct sa *sa, struct proto *proto, int incoming) if (ret) pf_key_v2_msg_free (ret); return -1; -#endif } static void @@ -1830,20 +1802,36 @@ pf_key_v2_expire (struct pf_key_v2_msg *pmsg) struct sockaddr *dstaddr; struct sadb_lifetime *life; struct sa *sa; - struct pf_key_v2_node *lifenode; + struct pf_key_v2_node *lifenode, *ext; msg = (struct sadb_msg *)TAILQ_FIRST (pmsg)->seg; - ssa = pf_key_v2_find_ext (pmsg, SADB_EXT_SA)->seg; - dst = pf_key_v2_find_ext (pmsg, SADB_EXT_ADDRESS_DST)->seg; + ext = pf_key_v2_find_ext (pmsg, SADB_EXT_SA); + if (!ext) + { + log_print ("pf_key_v2_expire: no SA extension found"); + return; + } + ssa = ext->seg; + ext = pf_key_v2_find_ext (pmsg, SADB_EXT_ADDRESS_DST); + if (!ext) + { + log_print ("pf_key_v2_expire: no destination address extension found"); + return; + } + dst = ext->seg; dstaddr = (struct sockaddr *)(dst + 1); lifenode = pf_key_v2_find_ext (pmsg, SADB_EXT_LIFETIME_HARD); if (!lifenode) lifenode = pf_key_v2_find_ext (pmsg, SADB_EXT_LIFETIME_SOFT); + if (!lifenode) + { + log_print ("pf_key_v2_expire: no lifetime extension found"); + return; + } life = lifenode->seg; /* XXX IPv4 specific. */ - LOG_DBG ((LOG_SYSDEP, 20, - "pf_key_v2_expire: %s dst %s SPI %x sproto %d", + LOG_DBG ((LOG_SYSDEP, 20, "pf_key_v2_expire: %s dst %s SPI %x sproto %d", life->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT ? "SOFT" : "HARD", inet_ntoa (((struct sockaddr_in *)dstaddr)->sin_addr), @@ -1881,12 +1869,12 @@ pf_key_v2_expire (struct pf_key_v2_msg *pmsg) if (life->sadb_lifetime_exttype == SADB_EXT_LIFETIME_HARD) { - /* - * XXX We need to reestablish the on-demand route here. This we need - * even if we have started a new negotiation, considering it might - * fail. + /* This SA is still referenced by the software timeout. + * However, sa_free will clean up all timeouts and + * decrement reference counters. We need to reference it + * so that sa_release() works. */ - + sa_reference (sa); /* Remove the old SA, it isn't useful anymore. */ sa_free (sa); } @@ -1896,40 +1884,597 @@ pf_key_v2_expire (struct pf_key_v2_msg *pmsg) static void pf_key_v2_acquire (struct pf_key_v2_msg *pmsg) { - struct sadb_msg *msg; - struct sadb_address *dst, *src; - struct sockaddr *dstaddr, *srcaddr; - struct sadb_comb *scmb; - struct sadb_prop *sprp; - char adbuf[40]; +#if !defined (SADB_X_ASKPOLICY) + return; +#else + struct sadb_msg *msg, askpolicy_msg; + struct pf_key_v2_msg *askpolicy = 0, *ret = 0; + struct sadb_policy policy; + struct sadb_address *dst = 0, *src = 0; + struct sockaddr *dstaddr, *srcaddr = 0; + struct sadb_comb *scmb = 0; + struct sadb_prop *sprp = 0; + struct sadb_ident *srcident = 0, *dstident = 0; + char dstbuf[ADDRESS_MAX], srcbuf[ADDRESS_MAX], *peer = 0, conn[22]; + char confname[120]; + char *srcid = 0, *dstid = 0, *prefstring = 0; + int slen, af; + struct sockaddr *smask, *sflow, *dmask, *dflow; + struct sadb_protocol *sproto; + char ssflow[ADDRESS_MAX], sdflow[ADDRESS_MAX]; + char sdmask[ADDRESS_MAX], ssmask[ADDRESS_MAX]; + char lname[90], dname[90], configname[30]; + int shostflag = 0, dhostflag = 0; + struct pf_key_v2_node *ext; msg = (struct sadb_msg *)TAILQ_FIRST (pmsg)->seg; - dst = pf_key_v2_find_ext (pmsg, SADB_EXT_ADDRESS_DST)->seg; - src = pf_key_v2_find_ext (pmsg, SADB_EXT_ADDRESS_SRC)->seg; - sprp = pf_key_v2_find_ext (pmsg, SADB_EXT_PROPOSAL)->seg; - scmb = (struct sadb_comb *)(sprp + 1); + + ext = pf_key_v2_find_ext (pmsg, SADB_EXT_ADDRESS_DST); + if (!ext) + { + log_print ("pf_key_v2_acquire: no destination address specified"); + return; + } + dst = ext->seg; + + ext = pf_key_v2_find_ext (pmsg, SADB_EXT_ADDRESS_SRC); + if (ext) + src = ext->seg; + + ext = pf_key_v2_find_ext (pmsg, SADB_EXT_PROPOSAL); + if (ext) + { + sprp = ext->seg; + scmb = (struct sadb_comb *)(sprp + 1); + } + + ext = pf_key_v2_find_ext (pmsg, SADB_EXT_IDENTITY_SRC); + if (ext) + srcident = ext->seg; + + ext = pf_key_v2_find_ext (pmsg, SADB_EXT_IDENTITY_DST); + if (ext) + dstident = ext->seg; + + /* Ask the kernel for the matching policy */ + bzero (&askpolicy_msg, sizeof askpolicy_msg); + askpolicy_msg.sadb_msg_type = SADB_X_ASKPOLICY; + askpolicy = pf_key_v2_msg_new (&askpolicy_msg, 0); + if (!askpolicy) + goto fail; + + policy.sadb_policy_exttype = SADB_X_EXT_POLICY; + policy.sadb_policy_len = sizeof policy / PF_KEY_V2_CHUNK; + policy.sadb_policy_seq = msg->sadb_msg_seq; + if (pf_key_v2_msg_add (askpolicy, (struct sadb_ext *)&policy, 0) == -1) + goto fail; + + ret = pf_key_v2_call (askpolicy); + if (!ret) + goto fail; + + /* Now we have all the information needed */ + + ext = pf_key_v2_find_ext (ret, SADB_X_EXT_SRC_FLOW); + if (!ext) + { + log_print ("pf_key_v2_acquire: no source flow extension found"); + goto fail; + } + sflow = (struct sockaddr *) (((struct sadb_address *)ext->seg) + 1); + + ext = pf_key_v2_find_ext (ret, SADB_X_EXT_DST_FLOW); + if (!ext) + { + log_print ("pf_key_v2_acquire: no destination flow extension found"); + goto fail; + } + dflow = (struct sockaddr *)(((struct sadb_address *)ext->seg) + 1); + + ext = pf_key_v2_find_ext (ret, SADB_X_EXT_SRC_MASK); + if (!ext) + { + log_print ("pf_key_v2_acquire: no source mask extension found"); + goto fail; + } + smask = (struct sockaddr *)(((struct sadb_address *)ext->seg) + 1); + + ext = pf_key_v2_find_ext (ret, SADB_X_EXT_DST_MASK); + if (!ext) + { + log_print ("pf_key_v2_acquire: no destination mask extension found"); + goto fail; + } + dmask = (struct sockaddr *)(((struct sadb_address *)ext->seg) + 1); + + ext = pf_key_v2_find_ext (pmsg, SADB_X_EXT_FLOW_TYPE); + if (!ext) + { + log_print ("pf_key_v2_acquire: no flow type extension found"); + goto fail; + } + sproto = ext->seg; + + bzero (ssflow, sizeof ssflow); + bzero (sdflow, sizeof sdflow); + bzero (ssmask, sizeof ssmask); + bzero (sdmask, sizeof sdmask); + + switch (sflow->sa_family) + { + case AF_INET: + if (inet_ntop (AF_INET, &((struct sockaddr_in *)sflow)->sin_addr, ssflow, + ADDRESS_MAX) == NULL) + { + log_error ("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + if (inet_ntop (AF_INET, &((struct sockaddr_in *)dflow)->sin_addr, sdflow, + ADDRESS_MAX) == NULL) + { + log_error ("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + if (inet_ntop (AF_INET, &((struct sockaddr_in *)smask)->sin_addr, ssmask, + ADDRESS_MAX) == NULL) + { + log_error ("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + if (inet_ntop (AF_INET, &((struct sockaddr_in *)dmask)->sin_addr, sdmask, + ADDRESS_MAX) == NULL) + { + log_error ("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + if (((struct sockaddr_in *)smask)->sin_addr.s_addr == INADDR_BROADCAST) + shostflag = 1; + if (((struct sockaddr_in *)dmask)->sin_addr.s_addr == INADDR_BROADCAST) + dhostflag = 1; + break; + + case AF_INET6: + if (inet_ntop (AF_INET6, &((struct sockaddr_in6 *)sflow)->sin6_addr, + ssflow, ADDRESS_MAX) == NULL) + { + log_error ("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + if (inet_ntop (AF_INET6, &((struct sockaddr_in6 *)dflow)->sin6_addr, + sdflow, ADDRESS_MAX) == NULL) + { + log_error ("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + if (inet_ntop (AF_INET6, &((struct sockaddr_in6 *)smask)->sin6_addr, + ssmask, ADDRESS_MAX) == NULL) + { + log_error ("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + if (inet_ntop (AF_INET6, &((struct sockaddr_in6 *)dmask)->sin6_addr, + sdmask, ADDRESS_MAX) == NULL) + { + log_error ("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + if (IN6_IS_ADDR_FULL (&((struct sockaddr_in6 *)smask)->sin6_addr)) + shostflag = 1; + if (IN6_IS_ADDR_FULL (&((struct sockaddr_in6 *)dmask)->sin6_addr)) + dhostflag = 1; + break; + } dstaddr = (struct sockaddr *)(dst + 1); - srcaddr = (struct sockaddr *)(src + 1); + bzero (dstbuf, sizeof dstbuf); switch (dstaddr->sa_family) { case AF_INET: - LOG_DBG ((LOG_SYSDEP, 20, "pf_key_v2_acquire: dst=%s sproto %d", - inet_ntop(AF_INET, &((struct sockaddr_in *)dstaddr)->sin_addr, - adbuf, 16), msg->sadb_msg_satype)); + if (inet_ntop (AF_INET, &((struct sockaddr_in *)dstaddr)->sin_addr, + dstbuf, ADDRESS_MAX) == NULL) + { + log_error ("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + LOG_DBG ((LOG_SYSDEP, 20, "pf_key_v2_acquire: dst=%s sproto %d", dstbuf, + msg->sadb_msg_satype)); break; case AF_INET6: - LOG_DBG ((LOG_SYSDEP, 20, "pf_key_v2_acquire: dst=%s sproto %d", - inet_ntop(AF_INET6 - , &((struct sockaddr_in6 *)dstaddr)->sin6_addr, - adbuf, 16), msg->sadb_msg_satype)); + if (inet_ntop (AF_INET6, &((struct sockaddr_in6 *)dstaddr)->sin6_addr, + dstbuf, ADDRESS_MAX) == NULL) + { + log_error ("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + LOG_DBG ((LOG_SYSDEP, 20, "pf_key_v2_acquire: dst=%s sproto %d", dstbuf, + msg->sadb_msg_satype)); break; } - /* XXX Only support one proposal for now */ - /* XXX Finish it */ + if (src) + { + srcaddr = (struct sockaddr *)(src + 1); + bzero (srcbuf, sizeof srcbuf); + + switch (srcaddr->sa_family) + { + case AF_INET: + if (inet_ntop (AF_INET, &((struct sockaddr_in *)srcaddr)->sin_addr, + srcbuf, ADDRESS_MAX) == NULL) + { + log_error ("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + break; + + case AF_INET6: + if (inet_ntop (AF_INET6, + &((struct sockaddr_in6 *)srcaddr)->sin6_addr, srcbuf, + ADDRESS_MAX) == NULL) + { + log_error ("pf_key_v2_acquire: inet_ntop failed"); + goto fail; + } + break; + } + } + + /* Insert source ID */ + if (srcident) + { + /* Check for valid type */ + switch (srcident->sadb_ident_type) + { + case SADB_IDENTTYPE_PREFIX: + /* XXX Process the address */ + break; + + case SADB_IDENTTYPE_FQDN: + prefstring = "FQDN"; + /* Fall through */ + + case SADB_IDENTTYPE_MBOX: + slen = (srcident->sadb_ident_len * sizeof (u_int64_t)) + - sizeof (struct sadb_ident); + if (!prefstring) + prefstring = "USER_FQDN"; + + srcid = malloc (slen + strlen (prefstring) + 1 + strlen ("ID:/")); + if (!srcid) + { + log_error ("pf_key_v2_acquire: malloc (%d) failed", + slen + strlen (prefstring) + 1 + strlen ("ID:/")); + goto fail; + } + + sprintf (srcid, "ID:%s/", prefstring); + strlcat (srcid + strlen ("ID:/") + strlen (prefstring), + (char *)(srcident + 1), + slen + strlen (prefstring) + 1 + strlen ("ID:/")); + + /* Set the section if it doesn't already exist */ + if (!conf_get_str (srcid, "ID-type")) + { + af = conf_begin (); + if (conf_set (af, srcid, "ID-type", prefstring, 0, 0) + || conf_set (af, srcid, "Name", + srcid + strlen ("ID:/") + strlen (prefstring), + 0, 0)) + { + conf_end (af, 0); + goto fail; + } + + conf_end (af, 1); + } + + break; + + default: + LOG_DBG ((LOG_SYSDEP, 20, + "pf_key_v2_acquire: invalid source ID type %d", + srcident->sadb_ident_type)); + goto fail; + } + + LOG_DBG ((LOG_SYSDEP, 50, + "pf_key_v2_acquire: constructed source ID \"%s\"", srcid)); + prefstring = 0; + } + + /* Insert destination ID */ + if (dstident) + { + /* Check for valid type */ + switch (dstident->sadb_ident_type) + { + case SADB_IDENTTYPE_PREFIX: + /* XXX Process the address */ + break; + + case SADB_IDENTTYPE_FQDN: + prefstring = "FQDN"; + /* Fall through */ + + case SADB_IDENTTYPE_MBOX: + slen = (dstident->sadb_ident_len * sizeof (u_int64_t)) + - sizeof (struct sadb_ident); + if (!prefstring) + prefstring = "USER_FQDN"; + + dstid = malloc (slen + strlen (prefstring) + 1 + strlen ("ID:/")); + if (!dstid) + { + log_error ("pf_key_v2_acquire: malloc (%d) failed", + slen + strlen (prefstring) + 1 + strlen ("ID:/")); + goto fail; + } + + sprintf (dstid, "ID:%s/", prefstring); + strlcat (dstid + strlen ("ID:/") + strlen (prefstring), + (char *) (dstident + 1), + slen + strlen (prefstring) + 1 + strlen ("ID:/")); + + /* Set the section if it doesn't already exist */ + if (!conf_get_str (dstid, "ID-type")) + { + af = conf_begin (); + if (conf_set (af, dstid, "ID-type", prefstring, 0, 0) + || conf_set (af, dstid, "Name", + dstid + strlen ("ID:/") + strlen (prefstring), + 0, 0)) + { + conf_end (af, 0); + goto fail; + } + + conf_end (af, 1); + } + + break; + + default: + LOG_DBG ((LOG_SYSDEP, 20, + "pf_key_v2_acquire: invalid destination ID type %d", + dstident->sadb_ident_type)); + goto fail; + } + + LOG_DBG ((LOG_SYSDEP, 50, + "pf_key_v2_acquire: constructed destination ID \"%s\"", + dstid)); + } + + /* Now we've placed the necessary IDs in the configuration space */ + + /* Get a new connection sequence number */ + for (;; connection_seq++) + { + sprintf (conn, "Connection-%d", connection_seq); + sprintf (configname, "Config-Phase2-%d", connection_seq); + + /* Does it exist ? */ + if (!conf_get_str (conn, "Phase") + && !conf_get_str (configname, "Suites")) + break; + } + + /* + * Set the IPsec connection entry. In particular, the following fields: + * - Phase + * - ISAKMPD-peer + * - Local-ID/Remote-ID (if provided) + * + * Also set the following section: + * [Peer-dstaddr(/srcaddr)(-srcid)(/dstid)] + * with these fields: + * - Phase + * - ID (if provided) + * - Remote-ID (if provided) + * - Listen-address (if provided) + * - Address + * - Configuration (if an entry "ISAKMP-configuration-dstaddr(/srcaddr)" + * exists -- otherwise use the defaults) + */ + + peer = malloc (strlen (dstbuf) + strlen (srcbuf) + srcid ? strlen (srcid) : 0 + + dstid ? strlen (dstid) : 0 + strlen ("Peer-/-/") + 1); + if (!peer) + goto fail; + + /* + * The various cases: + * - Peer-dstaddr + * - Peer-dstaddr/srcaddr + * - Peer-dstaddr/srcaddr-srcid + * - Peer-dstaddr/srcaddr-srcid/dstid + * - Peer-dstaddr/srcaddr-/dstid + * - Peer-dstaddr-srcid/dstid + * - Peer-dstaddr-/dstid + * - Peer-dstaddr-srcid + */ + sprintf (peer, "Peer-%s%s%s%s%s%s%s", dstbuf, srcaddr ? "/" : "", + srcaddr ? srcbuf : "", srcid ? "-" : "", srcid ? srcid : "", + dstid ? (srcid ? "/" : "-/") : "", dstid ? dstid : ""); + + /* Set the IPsec connection section */ + af = conf_begin (); + if (conf_set (af, conn, "Phase", "2", 0, 0) + || conf_set (af, conn, "Flags", "__ondemand", 0 ,0) + || conf_set (af, conn, "ISAKMP-peer", peer, 0, 0)) + { + conf_end (af, 0); + goto fail; + } + + /* Set Phase 2 IDs -- this is the Local-ID section */ + sprintf (lname, "Phase2-ID:%s/%s", ssflow, ssmask); + if (conf_set (af, conn, "Local-ID", lname, 0, 0)) + { + conf_end (af, 0); + goto fail; + } + + if (!conf_get_str (lname, "ID-type")) + { + if (shostflag) + { + if (conf_set (af, lname, "ID-type", "IPV4_ADDR", 0, 0) + || conf_set (af, lname, "Address", ssflow, 0, 0)) + { + conf_end (af, 0); + goto fail; + } + } + else + { + if (conf_set (af, lname, "ID-type", "IPV4_SUBNET", 0, 0) + || conf_set (af, lname, "Network", ssflow, 0, 0) + || conf_set (af, lname, "Netmask", ssmask, 0, 0)) + { + conf_end (af, 0); + goto fail; + } + } + } + + /* Set Remote-ID section */ + sprintf (dname, "Phase2-ID:%s/%s", sdflow, sdmask); + if (conf_set (af, conn, "Remote-ID", dname, 0, 0)) + { + conf_end (af, 0); + goto fail; + } + + if (!conf_get_str (dname, "ID-type")) + { + if (dhostflag) + { + if (conf_set (af, dname, "ID-type", "IPV4_ADDR", 0, 0) + || conf_set (af, dname, "Address", sdflow, 0, 0)) + { + conf_end (af, 0); + goto fail; + } + } + else + { + if (conf_set (af, dname, "ID-type", "IPV4_SUBNET", 0, 0) + || conf_set (af, dname, "Network", sdflow, 0, 0) + || conf_set (af, dname, "Netmask", sdmask, 0, 0)) + { + conf_end (af, 0); + goto fail; + } + } + } + + /* + * XXX + * We should be using information from the proposal to set this up. + * At least, we should make this selectable. + */ + + /* Phase 2 configuration */ + if (conf_set (af, conn, "Configuration", configname, 0, 0)) + { + conf_end (af, 0); + goto fail; + } + + if (conf_set (af, configname, "Exchange_type", "Quick_mode", 0, 0) + || conf_set (af, configname, "DOI", "IPSEC", 0, 0) + || conf_set (af, configname, "Suites", + "QM-ESP-3DES-SHA-PFS-SUITE", 0, 0)) + { + conf_end (af, 0); + goto fail; + } + + /* Set the ISAKMP-peer section */ + if (!conf_get_str (peer, "Phase")) + { + if (conf_set (af, peer, "Phase", "1", 0, 0) + || conf_set (af, peer, "Address", dstbuf, 0, 0)) + { + conf_end (af, 0); + goto fail; + } + + if (srcaddr && conf_set (af, peer, "Local-address", srcbuf, 0, 0)) + { + conf_end (af, 0); + goto fail; + } + + sprintf (confname, "ISAKMP-Configuration-%s", peer); + if (conf_set (af, peer, "Configuration", confname, 0, 0)) + { + conf_end (af, 0); + goto fail; + } + + /* XXX Default transform set should be settable */ + /* Phase 1 configuration */ + if (!conf_get_str (confname, "exchange_type")) + { + if (conf_set (af, confname, "exchange_type", "ID_PROT", 0, 0) + || conf_set (af, confname, "DOI", "IPSEC", 0, 0) + || conf_set (af, confname, "Transforms", "3DES-SHA-RSA_SIG", 0, + 0)) + { + conf_end (af, 0); + goto fail; + } + } + + /* The ID we should use in Phase 1 */ + if (srcid && conf_set (af, peer, "ID", srcid, 0, 0)) + { + conf_end (af, 0); + goto fail; + } + + /* The ID the other side should use in Phase 1 */ + if (dstid && conf_set (af, peer, "Remote-ID", dstid, 0, 0)) + { + conf_end (af, 0); + goto fail; + } + } + else + { + /* Phase 1 tag exists, there's nothing more we need to do */ + } + + /* All done */ + conf_end (af, 1); + + /* Let's rock */ + pf_key_v2_connection_check (conn); + + /* + * XXX Need to implement cleanup of sections after SAs expire. In + * particular, we need to expire the IPsec connection section; we + * could keep the ISAKMP-peer, Local-ID/Remote-ID sections. + */ + + /* Fall-through to cleanup */ + fail: + if (ret) + pf_key_v2_msg_free (ret); + if (askpolicy) + pf_key_v2_msg_free (askpolicy); + if (srcid) + free (srcid); + if (dstid) + free (dstid); + if (peer) + free (peer); + return; +#endif } static void @@ -2041,9 +2586,9 @@ pf_key_v2_group_spis (struct sa *sa, struct proto *proto1, if (pf_key_v2_msg_add (grpspis, (struct sadb_ext *)&sa2, 0) == -1) goto cleanup; #else - memset(&kamesa2, 0, sizeof(kamesa2)); + memset(&kamesa2, 0, sizeof kamesa2); kamesa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; - kamesa2.sadb_x_sa2_len = sizeof(kamesa2) / PF_KEY_V2_CHUNK; + kamesa2.sadb_x_sa2_len = sizeof kamesa2 / PF_KEY_V2_CHUNK; kamesa2.sadb_x_sa2_mode = 0; if (pf_key_v2_msg_add (grpspis, (struct sadb_ext *)&kamesa2, 0) == -1) goto cleanup; @@ -2052,7 +2597,7 @@ pf_key_v2_group_spis (struct sa *sa, struct proto *proto1, /* * Setup the ADDRESS extensions. * - * XXX Addresses has to be thought through. Assumes IPv4. + * XXX Addresses have to be thought through. Assumes IPv4. */ if (incoming) sa->transport->vtbl->get_src (sa->transport, &saddr, &saddrlen); |