summaryrefslogtreecommitdiffstats
path: root/main/ipsec-tools/50-reverse-connect.patch
diff options
context:
space:
mode:
Diffstat (limited to 'main/ipsec-tools/50-reverse-connect.patch')
-rw-r--r--main/ipsec-tools/50-reverse-connect.patch207
1 files changed, 207 insertions, 0 deletions
diff --git a/main/ipsec-tools/50-reverse-connect.patch b/main/ipsec-tools/50-reverse-connect.patch
new file mode 100644
index 00000000..c49eae34
--- /dev/null
+++ b/main/ipsec-tools/50-reverse-connect.patch
@@ -0,0 +1,207 @@
+When new ISAKMP is required, allow incoming reverse connection to take
+
+From: Timo Teras <timo.teras@iki.fi>
+
+over pending phase1:s. Useful when the other party is firewalled or NATted.
+---
+
+ src/racoon/admin.c | 12 ++++++++++++
+ src/racoon/evt.c | 13 +++++++++++++
+ src/racoon/evt.h | 3 +++
+ src/racoon/handler.c | 28 +++++++++++++++++++++-------
+ src/racoon/isakmp.c | 39 ++++++++++++++++++++++++++++++++++-----
+ 5 files changed, 83 insertions(+), 12 deletions(-)
+
+
+diff --git a/src/racoon/admin.c b/src/racoon/admin.c
+index b67e545..710c9bf 100644
+--- a/src/racoon/admin.c
++++ b/src/racoon/admin.c
+@@ -414,11 +414,23 @@ admin_process(so2, combuf)
+ struct sockaddr *dst;
+ struct sockaddr *src;
+ char *name = NULL;
++ char *loc, *rem;
+
+ ndx = (struct admin_com_indexes *) ((caddr_t)com + sizeof(*com));
+ src = (struct sockaddr *) &ndx->src;
+ dst = (struct sockaddr *) &ndx->dst;
+
++ loc = racoon_strdup(saddr2str(src));
++ rem = racoon_strdup(saddr2str(dst));
++ STRDUP_FATAL(loc);
++ STRDUP_FATAL(rem);
++
++ plog(LLV_INFO, LOCATION, NULL,
++ "admin establish-sa %x %s %s\n",
++ com->ac_proto, loc, rem);
++ racoon_free(loc);
++ racoon_free(rem);
++
+ if (com->ac_cmd == ADMIN_ESTABLISH_SA &&
+ com->ac_len > sizeof(*com) + sizeof(*ndx))
+ name = (char *) ((caddr_t) ndx + sizeof(*ndx));
+diff --git a/src/racoon/evt.c b/src/racoon/evt.c
+index 4ce1334..000c1f8 100644
+--- a/src/racoon/evt.c
++++ b/src/racoon/evt.c
+@@ -396,4 +396,17 @@ evt_list_cleanup(list)
+ evt_unsubscribe(LIST_FIRST(list));
+ }
+
++void
++evt_list_move(from, to)
++ struct evt_listener_list *from, *to;
++{
++ struct evt_listener *l;
++
++ while (!LIST_EMPTY(from)) {
++ l = LIST_FIRST(from);
++ LIST_REMOVE(l, ll_chain);
++ LIST_INSERT_HEAD(to, l, ll_chain);
++ }
++}
++
+ #endif /* ENABLE_ADMINPORT */
+diff --git a/src/racoon/evt.h b/src/racoon/evt.h
+index 0ce65bd..ba7fb57 100644
+--- a/src/racoon/evt.h
++++ b/src/racoon/evt.h
+@@ -124,6 +124,8 @@ void evt_phase2 __P((const struct ph2handle *ph2, int type, vchar_t *optdata));
+ vchar_t *evt_dump __P((void));
+
+ int evt_subscribe __P((struct evt_listener_list *list, int fd));
++void evt_list_move __P((struct evt_listener_list *from,
++ struct evt_listener_list *to));
+ void evt_list_init __P((struct evt_listener_list *list));
+ void evt_list_cleanup __P((struct evt_listener_list *list));
+
+@@ -136,6 +138,7 @@ void evt_list_cleanup __P((struct evt_listener_list *list));
+ #define evt_phase2(ph2, type, optdata) ;
+
+ #define evt_subscribe(eventlist, fd) ;
++#deifne evt_list_move(from, to) ;
+ #define evt_list_init(eventlist) ;
+ #define evt_list_cleanup(eventlist) ;
+ #define evt_get_fdmask(nfds, fdset) nfds
+diff --git a/src/racoon/handler.c b/src/racoon/handler.c
+index b33986f..9fd3817 100644
+--- a/src/racoon/handler.c
++++ b/src/racoon/handler.c
+@@ -269,26 +269,40 @@ migrate_ph12(old_iph1, new_iph1)
+ }
+
+ /*
+- * the iph1 is new, migrate all phase2s that belong to a dying or dead ph1
++ * the iph1 is new, migrate all phase2s that belong to a dying or dead ph1.
+ */
+ void migrate_dying_ph12(iph1)
+ struct ph1handle *iph1;
+ {
+- struct ph1handle *p;
++ struct ph1handle *p, *next;
+
+- LIST_FOREACH(p, &ph1tree, chain) {
++ for (p = LIST_FIRST(&ph1tree); p; p = next) {
++ next = LIST_NEXT(p, chain);
+ if (p == iph1)
+ continue;
+- if (p->status < PHASE1ST_DYING)
++
++ /* Same remote? */
++ if (cmpsaddr(iph1->local, p->local) > CMPSADDR_WOP_MATCH ||
++ cmpsaddr(iph1->remote, p->remote) > CMPSADDR_WOP_MATCH ||
++ iph1->rmconf != p->rmconf)
+ continue;
+
+- if (cmpsaddr(iph1->local, p->local) == 0
+- && cmpsaddr(iph1->remote, p->remote) == 0)
++ /* migrate phase2:s from expiring entries */
++ if (p->status >= PHASE1ST_DYING)
+ migrate_ph12(p, iph1);
++
++ /* and allow reverse connections to release
++ * pending connections that do not work due
++ * to firewall or nat */
++ if (iph1->side == RESPONDER && p->side == INITIATOR &&
++ p->status < PHASE1ST_MSG3RECEIVED) {
++ evt_list_move(&p->evt_listeners, &iph1->evt_listeners);
++ remph1(p);
++ delph1(p);
++ }
+ }
+ }
+
+-
+ /*
+ * dump isakmp-sa
+ */
+diff --git a/src/racoon/isakmp.c b/src/racoon/isakmp.c
+index 0de16d1..2dfda2f 100644
+--- a/src/racoon/isakmp.c
++++ b/src/racoon/isakmp.c
+@@ -2138,13 +2138,33 @@ isakmp_ph2delete(iph2)
+
+ remph2(iph2);
+ delph2(iph2);
+-
+- return;
+ }
+
+ /* %%%
+ * Interface between PF_KEYv2 and ISAKMP
+ */
++
++static void
++isakmp_chkph2there(p)
++ struct sched *p;
++{
++ struct ph2handle *iph2 = container_of(p, struct ph2handle, sce);
++ struct ph2handle *tmp;
++
++ /* Check if a similar phase2 appared meanwhile */
++ remph2(iph2);
++ tmp = getph2byid(iph2->src, iph2->dst, iph2->spid);
++ if (tmp == NULL) {
++ /* Nope, lets start this then */
++ insph2(iph2);
++ isakmp_chkph1there(iph2);
++ } else {
++ /* Yes, delete this initiation attempt as redundant */
++ evt_phase2(iph2, EVT_PHASE2_UP, NULL);
++ delph2(iph2);
++ }
++}
++
+ /*
+ * receive ACQUIRE from kernel, and begin either phase1 or phase2.
+ * if phase1 has been finished, begin phase2.
+@@ -2220,8 +2240,14 @@ isakmp_post_acquire(iph2)
+ /*NOTREACHED*/
+ }
+
+- /* found established ISAKMP-SA */
+- /* i.e. iph1->status == PHASE1ST_ESTABLISHED */
++ /* found established ISAKMP-SA, if this is a RESPONDER ISAKMP-SA
++ * add a small delay; this will make sure the initiator gets
++ * an first attempt at rekeying, and usually avoids duplicate ph2:s */
++ if (iph1->side == RESPONDER) {
++ iph2->retry_checkph1 = 1;
++ sched_schedule(&iph2->sce, 1, isakmp_chkph2there);
++ return 0;
++ }
+
+ /* found ISAKMP-SA. */
+ plog(LLV_DEBUG, LOCATION, NULL, "begin QUICK mode.\n");
+@@ -2388,7 +2414,10 @@ isakmp_chkph1there(iph2)
+ plog(LLV_DEBUG2, LOCATION, NULL, "dst: %s\n", saddr2str(iph2->dst));
+
+ /* begin quick mode */
+- (void)isakmp_ph2begin_i(iph1, iph2);
++ if (isakmp_ph2begin_i(iph1, iph2)) {
++ remph2(iph2);
++ delph2(iph2);
++ }
+ return;
+ }
+