summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiklas Hallqvist <niklas@cvs.openbsd.org>1999-02-26 03:48:33 +0000
committerNiklas Hallqvist <niklas@cvs.openbsd.org>1999-02-26 03:48:33 +0000
commit5452ee60b5fccc492b3a48603e80845ee56bf35d (patch)
tree7d44a6a0d50286e9b543b5d15ccc109f27379328
parent80d13aee9caf01ff6d5019ea376f6f5ac00a7c3c (diff)
Merge from the Ericsson repository
| revision 1.44 | date: 1999/02/25 14:03:54; author: niklas; state: Exp; lines: +13 -13 | do not use the app_socket name. correct some LOG_* syms | ---------------------------- | revision 1.43 | date: 1999/02/25 11:39:17; author: niklas; state: Exp; lines: +3 -2 | include sysdep.h everywhere | ---------------------------- | revision 1.42 | date: 1999/02/25 09:30:28; author: niklas; state: Exp; lines: +3 -3 | Replay protection window configurable | ---------------------------- | revision 1.41 | date: 1999/02/14 00:17:15; author: niklas; state: Exp; lines: +68 -28 | Better PF_ENCAP expiration and SA request handling | ---------------------------- | revision 1.40 | date: 1999/02/06 15:08:33; author: niklas; state: Exp; lines: +6 -1 | Drop SA request notifies if an exchange or SA already exist | ---------------------------- | revision 1.39 | date: 1999/01/31 01:20:37; author: niklas; state: Exp; lines: +217 -51 | on-demand keying | ----------------------------
-rw-r--r--sbin/isakmpd/pf_encap.c378
1 files changed, 295 insertions, 83 deletions
diff --git a/sbin/isakmpd/pf_encap.c b/sbin/isakmpd/pf_encap.c
index 476d55f1840..aaf7f9648d5 100644
--- a/sbin/isakmpd/pf_encap.c
+++ b/sbin/isakmpd/pf_encap.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: pf_encap.c,v 1.4 1998/12/21 01:02:26 niklas Exp $ */
-/* $EOM: pf_encap.c,v 1.38 1998/12/17 07:56:33 niklas Exp $ */
+/* $OpenBSD: pf_encap.c,v 1.5 1999/02/26 03:48:32 niklas Exp $ */
+/* $EOM: pf_encap.c,v 1.44 1999/02/25 14:03:54 niklas Exp $ */
/*
* Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
@@ -36,7 +36,10 @@
#include <sys/param.h>
#include <sys/mbuf.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
#include <sys/time.h>
+#include <net/route.h>
#include <netinet/in.h>
#include <net/encap.h>
#include <netinet/ip_ah.h>
@@ -48,8 +51,10 @@
#include <string.h>
#include <unistd.h>
-#include "app.h"
+#include "sysdep.h"
+
#include "conf.h"
+#include "exchange.h"
#include "hash.h"
#include "ipsec.h"
#include "ipsec_num.h"
@@ -57,11 +62,38 @@
#include "log.h"
#include "pf_encap.h"
#include "sa.h"
-#include "sysdep.h"
#include "timer.h"
#include "transport.h"
-void pf_encap_request_sa (struct encap_msghdr *);
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long))
+
+static void pf_encap_deregister_on_demand_connection (in_addr_t, char *);
+static char *pf_encap_on_demand_connection (in_addr_t);
+static int pf_encap_register_on_demand_connection (in_addr_t, char *);
+static void pf_encap_request_sa (struct encap_msghdr *);
+
+struct on_demand_connection {
+ /* Connections are linked together. */
+ LIST_ENTRY (on_demand_connection) link;
+
+ /* The security gateway's IP-address. */
+ in_addr_t dst;
+
+ /* The name of a phase 2 connection associated with the security gateway. */
+ char *conn;
+};
+
+static LIST_HEAD (on_demand_connection_list_list, on_demand_connection)
+ on_demand_connections;
+
+static int pf_encap_socket;
+
+void
+pf_encap_init ()
+{
+ LIST_INIT (&on_demand_connections);
+}
int
pf_encap_open ()
@@ -81,9 +113,37 @@ pf_encap_open ()
static void
pf_encap_expire (struct encap_msghdr *emsg)
{
- /* XXX not implemented yet. */
+ struct sa *sa;
+
+ log_debug (LOG_PF_ENCAP, 20,
+ "pf_encap_handler: NOTIFY_%s_EXPIRE dst %s spi %x sproto %d",
+ emsg->em_not_type == NOTIFY_SOFT_EXPIRE ? "SOFT" : "HARD",
+ inet_ntoa (emsg->em_not_dst), emsg->em_not_spi,
+ emsg->em_not_sproto);
- /* Identify the IPsec SA and rekey that one. */
+ /*
+ * Fin the IPsec SA. The IPsec stack has two SAs for every IKE SA,
+ * one outgoing and one incoming, we regard expirations for any of
+ * them as an expiration of the full IKE SA. Likewise, in
+ * protection suites consisitng of more than one protocol, any
+ * expired individual IPsec stack SA will be seen as an expiration
+ * of the full suite.
+ *
+ * XXX When anything else than AH and ESP is supported this needs to change.
+ */
+ sa = ipsec_sa_lookup (emsg->em_not_dst.s_addr, emsg->em_not_spi,
+ emsg->em_not_sproto == IPPROTO_ESP
+ ? IPSEC_PROTO_IPSEC_ESP : IPSEC_PROTO_IPSEC_AH);
+
+ /* If the SA is already gone, don't do anything. */
+ if (!sa)
+ return;
+
+ /* XXX We need to reestablish the on-demand route here. */
+
+ /* If this was a hard expire, remove the SA. */
+ if (emsg->em_not_type == NOTIFY_HARD_EXPIRE)
+ sa_free (sa);
}
static void
@@ -96,27 +156,20 @@ pf_encap_notify (struct encap_msghdr *emsg)
{
case NOTIFY_SOFT_EXPIRE:
case NOTIFY_HARD_EXPIRE:
- log_debug (LOG_PF_ENCAP, 20,
- "pf_encap_handler: NOTIFY_%s_EXPIRE dst %s spi %x sproto %d",
- emsg->em_not_type == NOTIFY_SOFT_EXPIRE ? "SOFT" : "HARD",
- inet_ntoa (emsg->em_not_dst), emsg->em_not_spi,
- emsg->em_not_sproto);
pf_encap_expire (emsg);
+ free (emsg);
break;
case NOTIFY_REQUEST_SA:
- log_debug (LOG_PF_ENCAP, 10,
- "pf_encap_handler: SA requested for %s type %d",
- inet_ntoa (emsg->em_not_dst), emsg->em_not_satype);
pf_encap_request_sa (emsg);
break;
default:
log_print ("pf_encap_handler: unknown notify message type (%d)",
emsg->em_not_type);
+ free (emsg);
break;
}
- free (emsg);
}
void
@@ -164,41 +217,6 @@ pf_encap_handler (int fd)
pf_encap_notify (emsg);
}
-void
-pf_encap_request_sa (struct encap_msghdr *emsg)
-{
- struct transport *transport;
- struct sa *isakmp_sa;
- char addr[20];
- in_port_t port;
- struct sockaddr *taddr;
- int taddr_len;
-
- /*
- * XXX I'd really want some more flexible way to map the IPv4 address in
- * this message to a general transport endpoint. For now we hardcode
- * the ISAKMP peer to be at the same IP and talking UDP.
- */
- port = conf_get_num (inet_ntoa (emsg->em_not_dst), "port");
- if (!port)
- port = UDP_DEFAULT_PORT;
- snprintf (addr, 20, "%s:%d", inet_ntoa (emsg->em_not_dst), port);
- transport = transport_create ("udp", addr);
- if (!transport)
- {
- log_print ("pf_encap_request_sa: "
- "transport \"udp %s\" could not be created",
- transport, addr);
- return;
- }
-
- /* Check if we already have an ISAKMP SA setup. */
- transport->vtbl->get_dst (transport, &taddr, &taddr_len);
- isakmp_sa = sa_isakmp_lookup_by_peer (taddr, taddr_len);
- if (!isakmp_sa)
- /* XXX transport_free (transport) */ ;
-}
-
/* Write a PF_ENCAP request down to the kernel. */
static int
pf_encap_write (struct encap_msghdr *em)
@@ -209,20 +227,55 @@ pf_encap_write (struct encap_msghdr *em)
log_debug_buf (LOG_PF_ENCAP, 30, "pf_encap_write: em", (u_int8_t *)em,
em->em_msglen);
- n = write (app_socket, em, em->em_msglen);
+ n = write (pf_encap_socket, em, em->em_msglen);
if (n == -1)
{
- log_error ("write (%d, ...) failed", app_socket);
+ log_error ("write (%d, ...) failed", pf_encap_socket);
return -1;
}
if ((size_t)n != em->em_msglen)
{
- log_error ("write (%d, ...) returned prematurely", app_socket);
+ log_error ("write (%d, ...) returned prematurely", pf_encap_socket);
return -1;
}
return 0;
}
+static void
+pf_encap_finalize_request_sa (void *v_emsg)
+{
+ struct encap_msghdr *emsg = v_emsg;
+
+ pf_encap_write (emsg);
+ free (emsg);
+}
+
+static void
+pf_encap_request_sa (struct encap_msghdr *emsg)
+{
+ char *conn;
+
+ log_debug (LOG_PF_ENCAP, 10, "pf_encap_handler: SA requested for %s type %d",
+ inet_ntoa (emsg->em_not_dst), emsg->em_not_satype);
+
+ /* XXX pf_encap_on_demand_connection should return a list of connections. */
+ conn = pf_encap_on_demand_connection (emsg->em_not_dst.s_addr);
+ if (!conn)
+ /* Not ours. */
+ return;
+
+ /*
+ * If a connection or an SA for this connections already exists, drop it.
+ * XXX Perhaps this test is better to have in exchange_establish.
+ * XXX We are leaking emsg here.
+ */
+ if (exchange_lookup_by_name (conn, 2) || sa_lookup_by_name (conn, 2))
+ return;
+
+ if (conn)
+ exchange_establish (conn, pf_encap_finalize_request_sa, emsg);
+}
+
/*
* Read a PF_ENCAP non-notify packet (e.g. an answer to a request of ours)
* If we see a notify queue it up as a timeout timing out NOW for the main
@@ -247,18 +300,17 @@ pf_encap_read ()
while (1)
{
- /* XXX Should we have a static pf_encap_socket instead? */
- n = read (app_socket, buf, EMT_NOTIFY_FLEN);
+ n = read (pf_encap_socket, buf, EMT_NOTIFY_FLEN);
if (n == -1)
{
- log_error ("read (%d, ...) failed", app_socket);
+ log_error ("read (%d, ...) failed", pf_encap_socket);
goto cleanup;
}
if ((size_t)n < EMT_GENLEN || (size_t)n != emsg->em_msglen)
{
log_print ("read (%d, ...) returned short packet (%d bytes)",
- app_socket, n);
+ pf_encap_socket, n);
goto cleanup;
}
@@ -293,6 +345,10 @@ pf_encap_read ()
return 0;
}
+/*
+ * Generate a SPI for protocol PROTO and the destination signified by
+ * ID & ID_SZ. Stash the SPI size in SZ.
+ */
u_int8_t *
pf_encap_get_spi (size_t *sz, u_int8_t proto, void *id, size_t id_sz)
{
@@ -325,7 +381,7 @@ pf_encap_get_spi (size_t *sz, u_int8_t proto, void *id, size_t id_sz)
memcpy (spi, &emsg->em_gen_spi, *sz);
free (emsg);
- log_debug_buf (LOG_MISC, 50, "pf_encap_get_spi: spi", spi, *sz);
+ log_debug_buf (LOG_PF_ENCAP, 50, "pf_encap_get_spi: spi", spi, *sz);
return spi;
@@ -368,7 +424,7 @@ pf_encap_group_spis (struct sa *sa, struct proto *proto1, struct proto *proto2,
goto cleanup;
free (emsg);
- log_debug (LOG_MISC, 50, "pf_encap_group_spis: done");
+ log_debug (LOG_PF_ENCAP, 50, "pf_encap_group_spis: done");
return 0;
@@ -454,7 +510,7 @@ pf_encap_set_spi (struct sa *sa, struct proto *proto, int role, int initiator)
edx->edx_ivlen = 8;
edx->edx_confkeylen = keylen;
edx->edx_authkeylen = hashlen;
- edx->edx_wnd = 16;
+ edx->edx_wnd = iproto->replay_window;
edx->edx_flags = iproto->auth ? ESP_NEW_FLAG_AUTH : 0;
memcpy (edx->edx_data + 8, iproto->keymat[role], keylen);
if (iproto->auth)
@@ -491,7 +547,7 @@ pf_encap_set_spi (struct sa *sa, struct proto *proto, int role, int initiator)
}
amx->amx_keylen = hashlen;
- amx->amx_wnd = 16;
+ amx->amx_wnd = iproto->replay_window;
memcpy (amx->amx_key, iproto->keymat[role], hashlen);
break;
@@ -586,7 +642,7 @@ pf_encap_delete_spi (struct sa *sa, struct proto *proto, int initiator)
goto cleanup;
free (emsg);
- log_debug (LOG_MISC, 50, "pf_encap_delete_spi: done");
+ log_debug (LOG_PF_ENCAP, 50, "pf_encap_delete_spi: done");
return 0;
@@ -596,41 +652,54 @@ pf_encap_delete_spi (struct sa *sa, struct proto *proto, int initiator)
return -1;
}
-/* Enable a flow. */
+/* Enable a flow given a SA. */
int
-pf_encap_enable_spi (struct sa *sa, int initiator)
+pf_encap_enable_sa (struct sa *sa, int initiator)
{
struct ipsec_sa *isa = sa->data;
- struct encap_msghdr *emsg = 0;
- struct sockaddr *dst, *src;
- int dstlen, srclen;
+ struct sockaddr *dst;
+ int dstlen;
struct proto *proto = TAILQ_FIRST (&sa->protos);
+ sa->transport->vtbl->get_dst (sa->transport, &dst, &dstlen);
+
+ /* XXX Check why byte ordering is backwards. */
+ return pf_encap_enable_spi (htonl (isa->src_net), htonl (isa->src_mask),
+ htonl (isa->dst_net), htonl (isa->dst_mask),
+ proto->spi[!initiator], proto->proto,
+ ((struct sockaddr_in *)dst)->sin_addr.s_addr);
+}
+
+/* Enable a flow. */
+int
+pf_encap_enable_spi (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr,
+ in_addr_t rmask, u_int8_t *spi, u_int8_t proto,
+ in_addr_t dst)
+{
+ struct encap_msghdr *emsg = 0;
+
emsg = calloc (1, EMT_ENABLESPI_FLEN);
if (!emsg)
+ /* XXX Log? */
return -1;
emsg->em_msglen = EMT_ENABLESPI_FLEN;
emsg->em_type = EMT_ENABLESPI;
- sa->transport->vtbl->get_dst (sa->transport, &dst, &dstlen);
- sa->transport->vtbl->get_src (sa->transport, &src, &srclen);
-
- memcpy (&emsg->em_ena_spi, proto->spi[!initiator], sizeof emsg->em_ena_spi);
- emsg->em_ena_dst = ((struct sockaddr_in *)dst)->sin_addr;
+ memcpy (&emsg->em_ena_spi, spi, sizeof emsg->em_ena_spi);
+ emsg->em_ena_dst.s_addr = dst;
log_debug (LOG_PF_ENCAP, 50, "pf_encap_enable_spi: src %x %x dst %x %x",
- isa->src_net, isa->src_mask, isa->dst_net, isa->dst_mask);
- /* XXX Check why byte ordering is backwards. */
- emsg->em_ena_isrc.s_addr = htonl (isa->src_net);
- emsg->em_ena_ismask.s_addr = htonl (isa->src_mask);
- emsg->em_ena_idst.s_addr = htonl (isa->dst_net);
- emsg->em_ena_idmask.s_addr = htonl (isa->dst_mask);
+ laddr, lmask, raddr, rmask);
+ emsg->em_ena_isrc.s_addr = laddr;
+ emsg->em_ena_ismask.s_addr = lmask;
+ emsg->em_ena_idst.s_addr = raddr;
+ emsg->em_ena_idmask.s_addr = rmask;
emsg->em_ena_flags = ENABLE_FLAG_REPLACE;
/* XXX What if IPCOMP etc. comes along? */
emsg->em_ena_sproto
- = proto->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH;
+ = proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH;
if (pf_encap_write (emsg))
goto cleanup;
@@ -650,9 +719,7 @@ pf_encap_enable_spi (struct sa *sa, int initiator)
goto cleanup;
}
free (emsg);
-
- log_debug (LOG_MISC, 50, "pf_encap_enable_spi: done");
-
+ log_debug (LOG_PF_ENCAP, 50, "pf_encap_enable_spi: done");
return 0;
cleanup:
@@ -660,3 +727,148 @@ pf_encap_enable_spi (struct sa *sa, int initiator)
free (emsg);
return -1;
}
+
+/*
+ * Establish an encap route.
+ * XXX We should add delete support here a la ipsecadm/xf_flow.c the day
+ * we want to clean up after us.
+ */
+int
+pf_encap_route (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr,
+ in_addr_t rmask, u_int8_t spi, in_addr_t dst, char *conn)
+{
+ int s = -1;
+ int off, err;
+ struct sockaddr_encap *ddst, *msk, *gw;
+ struct rt_msghdr *rtmsg = 0;
+
+ err = pf_encap_register_on_demand_connection (dst, conn);
+ if (err)
+ return -1;
+
+ rtmsg = calloc (1, EMT_ENABLESPI_FLEN);
+ if (!rtmsg)
+ /* XXX Log? */
+ goto fail;
+
+ s = socket (PF_ROUTE, SOCK_RAW, AF_UNSPEC);
+ if (s == -1)
+ {
+ log_error ("pf_encap_route: "
+ "socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC) failed");
+ goto fail;
+ }
+
+ off = sizeof *rtmsg;
+ ddst = (struct sockaddr_encap *)((char *)rtmsg + off);
+ off = ROUNDUP (off + SENT_IP4_LEN);
+ gw = (struct sockaddr_encap *)((char *)rtmsg + off);
+ off = ROUNDUP (off + SENT_IPSP_LEN);
+ msk = (struct sockaddr_encap *)((char *)rtmsg + off);
+ bzero (rtmsg, off + SENT_IP4_LEN);
+
+ rtmsg->rtm_version = RTM_VERSION;
+ rtmsg->rtm_type = RTM_ADD;
+ rtmsg->rtm_index = 0;
+ rtmsg->rtm_pid = getpid ();
+ rtmsg->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
+ rtmsg->rtm_errno = 0;
+ rtmsg->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
+ rtmsg->rtm_inits = 0;
+
+ ddst->sen_len = SENT_IP4_LEN;
+ ddst->sen_family = AF_ENCAP;
+ ddst->sen_type = SENT_IP4;
+ ddst->sen_ip_src.s_addr = laddr & lmask;
+ ddst->sen_ip_dst.s_addr = raddr & rmask;
+ ddst->sen_proto = ddst->sen_sport = ddst->sen_dport = 0;
+
+ gw->sen_len = SENT_IPSP_LEN;
+ gw->sen_family = AF_ENCAP;
+ gw->sen_type = SENT_IPSP;
+ gw->sen_ipsp_dst.s_addr = dst;
+ gw->sen_ipsp_spi = htonl(spi);
+ gw->sen_ipsp_sproto = 0; /* XXX Correct? */
+
+ msk->sen_len = SENT_IP4_LEN;
+ msk->sen_family = AF_ENCAP;
+ msk->sen_type = SENT_IP4;
+ msk->sen_ip_src.s_addr = lmask;
+ msk->sen_ip_dst.s_addr = rmask;
+
+ rtmsg->rtm_msglen = off + msk->sen_len;
+
+ if (write(s, (caddr_t)rtmsg, rtmsg->rtm_msglen) == -1)
+ {
+ log_error("write(%d, ...) failed", s);
+ goto fail;
+ }
+
+ /* XXX Local packet route should be setup here. */
+
+ /*
+ * Setup a reverse map, address -> name, we can use when getting SA
+ * requests back from the stack.
+ */
+
+ close (s);
+ free (rtmsg);
+ return 0;
+
+ fail:
+ if (s != -1)
+ close (s);
+ if (rtmsg)
+ free (rtmsg);
+ pf_encap_deregister_on_demand_connection (dst, conn);
+ return -1;
+}
+
+/*
+ * Register an IP-address to Phase 2 connection name mapping.
+ */
+static int
+pf_encap_register_on_demand_connection (in_addr_t dst, char *conn)
+{
+ struct on_demand_connection *node;
+
+ node = malloc (sizeof *node);
+ if (!node)
+ return -1;
+ node->dst = dst;
+ node->conn = conn;
+ LIST_INSERT_HEAD (&on_demand_connections, node, link);
+ return 0;
+}
+
+/*
+ * Remove an IP-address to Phase 2 connection name mapping.
+ */
+static void
+pf_encap_deregister_on_demand_connection (in_addr_t dst, char *conn)
+{
+ struct on_demand_connection *node;
+
+ for (node = LIST_FIRST (&on_demand_connections); node;
+ node = LIST_NEXT (node, link))
+ if (dst == node->dst && conn == node->conn)
+ {
+ LIST_REMOVE (node, link);
+ }
+}
+
+/*
+ * Return a phase 2 connection name given a security gateway's IP-address.
+ * XXX Does only handle 1-1 mappings so far.
+ */
+static char *
+pf_encap_on_demand_connection (in_addr_t dst)
+{
+ struct on_demand_connection *node;
+
+ for (node = LIST_FIRST (&on_demand_connections); node;
+ node = LIST_NEXT (node, link))
+ if (dst == node->dst)
+ return node->conn;
+ return 0;
+}