Add a NAT-T keepalive timer in case we are behind a NAT gateway.
authorpatrick <patrick@openbsd.org>
Thu, 13 Apr 2017 07:04:09 +0000 (07:04 +0000)
committerpatrick <patrick@openbsd.org>
Thu, 13 Apr 2017 07:04:09 +0000 (07:04 +0000)
See RFC 5996, section 2.23, NAT Traversal:
  In the case of a mismatching NAT_DETECTION_DESTINATION_IP hash, it
  means that the system receiving the NAT_DETECTION_DESTINATION_IP
  payload is behind a NAT and that system SHOULD start sending
  keepalive packets as defined in [UDPENCAPS].

With markus@, ok reyk@

sbin/iked/config.c
sbin/iked/iked.h
sbin/iked/ikev2.c
sbin/iked/ikev2_pld.c

index d24da14..590e4d7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: config.c,v 1.47 2017/03/27 10:43:53 mikeb Exp $       */
+/*     $OpenBSD: config.c,v 1.48 2017/04/13 07:04:09 patrick Exp $     */
 
 /*
  * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -97,6 +97,7 @@ void
 config_free_sa(struct iked *env, struct iked_sa *sa)
 {
        timer_del(env, &sa->sa_timer);
+       timer_del(env, &sa->sa_keepalive);
        timer_del(env, &sa->sa_rekey);
 
        config_free_proposals(&sa->sa_proposals, 0);
index 25e81ea..7e77d20 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: iked.h,v 1.113 2017/03/27 17:17:49 mikeb Exp $        */
+/*     $OpenBSD: iked.h,v 1.114 2017/04/13 07:04:09 patrick Exp $      */
 
 /*
  * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -376,6 +376,7 @@ struct iked_sa {
 
        int                              sa_natt;       /* for IKE messages */
        int                              sa_udpencap;   /* for pfkey */
+       int                              sa_usekeepalive;/* NAT-T keepalive */
 
        int                              sa_state;
        unsigned int                     sa_stateflags;
@@ -446,6 +447,9 @@ struct iked_sa {
 #define IKED_IKE_SA_DELETE_TIMEOUT      120            /* 2 minutes */
 #define IKED_IKE_SA_ALIVE_TIMEOUT       60             /* 1 minute */
 
+       struct iked_timer                sa_keepalive;  /* keepalive timer */
+#define IKED_IKE_SA_KEEPALIVE_TIMEOUT   20
+
        struct iked_timer                sa_rekey;      /* rekey timeout */
 
        struct iked_msgqueue             sa_requests;   /* request queue */
index cd8b0d8..078886c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ikev2.c,v 1.152 2017/03/30 15:48:30 patrick Exp $     */
+/*     $OpenBSD: ikev2.c,v 1.153 2017/04/13 07:04:09 patrick Exp $     */
 
 /*
  * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -89,6 +89,7 @@ void   ikev2_ike_sa_rekey_timeout(struct iked *, void *);
 void    ikev2_ike_sa_rekey_schedule(struct iked *, struct iked_sa *);
 void    ikev2_ike_sa_timeout(struct iked *env, void *);
 void    ikev2_ike_sa_alive(struct iked *, void *);
+void    ikev2_ike_sa_keepalive(struct iked *, void *);
 
 int     ikev2_sa_initiator(struct iked *, struct iked_sa *,
            struct iked_sa *, struct iked_message *);
@@ -1200,6 +1201,10 @@ ikev2_init_done(struct iked *env, struct iked_sa *sa)
                timer_del(env, &sa->sa_timer);
                timer_set(env, &sa->sa_timer, ikev2_ike_sa_alive, sa);
                timer_add(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT);
+               timer_set(env, &sa->sa_keepalive, ikev2_ike_sa_keepalive, sa);
+               if (sa->sa_usekeepalive)
+                       timer_add(env, &sa->sa_keepalive,
+                           IKED_IKE_SA_KEEPALIVE_TIMEOUT);
                timer_set(env, &sa->sa_rekey, ikev2_ike_sa_rekey, sa);
                if (sa->sa_policy->pol_rekey)
                        ikev2_ike_sa_rekey_schedule(env, sa);
@@ -2473,6 +2478,10 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa)
                timer_del(env, &sa->sa_timer);
                timer_set(env, &sa->sa_timer, ikev2_ike_sa_alive, sa);
                timer_add(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT);
+               timer_set(env, &sa->sa_keepalive, ikev2_ike_sa_keepalive, sa);
+               if (sa->sa_usekeepalive)
+                       timer_add(env, &sa->sa_keepalive,
+                           IKED_IKE_SA_KEEPALIVE_TIMEOUT);
                timer_set(env, &sa->sa_rekey, ikev2_ike_sa_rekey, sa);
                if (sa->sa_policy->pol_rekey)
                        ikev2_ike_sa_rekey_schedule(env, sa);
@@ -3142,6 +3151,7 @@ ikev2_ikesa_enable(struct iked *env, struct iked_sa *sa, struct iked_sa *nsa)
        nsa->sa_fd = sa->sa_fd;
        nsa->sa_natt = sa->sa_natt;
        nsa->sa_udpencap = sa->sa_udpencap;
+       nsa->sa_usekeepalive = sa->sa_usekeepalive;
 
        /* Transfer old addresses */
        memcpy(&nsa->sa_local, &sa->sa_local, sizeof(nsa->sa_local));
@@ -3226,6 +3236,10 @@ ikev2_ikesa_enable(struct iked *env, struct iked_sa *sa, struct iked_sa *nsa)
        sa_state(env, nsa, IKEV2_STATE_ESTABLISHED);
        timer_set(env, &nsa->sa_timer, ikev2_ike_sa_alive, nsa);
        timer_add(env, &nsa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT);
+       timer_set(env, &nsa->sa_keepalive, ikev2_ike_sa_keepalive, nsa);
+       if (nsa->sa_usekeepalive)
+               timer_add(env, &nsa->sa_keepalive,
+                   IKED_IKE_SA_KEEPALIVE_TIMEOUT);
        timer_set(env, &nsa->sa_rekey, ikev2_ike_sa_rekey, nsa);
        if (nsa->sa_policy->pol_rekey)
                ikev2_ike_sa_rekey_schedule(env, nsa);
@@ -3234,6 +3248,7 @@ ikev2_ikesa_enable(struct iked *env, struct iked_sa *sa, struct iked_sa *nsa)
        /* unregister DPD keep alive timer & rekey first */
        if (sa->sa_state == IKEV2_STATE_ESTABLISHED) {
                timer_del(env, &sa->sa_rekey);
+               timer_del(env, &sa->sa_keepalive);
                timer_del(env, &sa->sa_timer);
        }
 
@@ -3626,6 +3641,26 @@ ikev2_ike_sa_alive(struct iked *env, void *arg)
        timer_add(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT);
 }
 
+void
+ikev2_ike_sa_keepalive(struct iked *env, void *arg)
+{
+       struct iked_sa                  *sa = arg;
+       uint8_t                          marker = 0xff;
+
+       if (sendtofrom(sa->sa_fd, &marker, sizeof(marker), 0,
+           (struct sockaddr *)&sa->sa_peer.addr, sa->sa_peer.addr.ss_len,
+           (struct sockaddr *)&sa->sa_local.addr, sa->sa_local.addr.ss_len)
+           == -1)
+               log_warn("%s: sendtofrom: peer %s local %s", __func__,
+                   print_host((struct sockaddr *)&sa->sa_peer.addr, NULL, 0),
+                   print_host((struct sockaddr *)&sa->sa_local.addr, NULL, 0));
+       else
+               log_debug("%s: peer %s local %s", __func__,
+                   print_host((struct sockaddr *)&sa->sa_peer.addr, NULL, 0),
+                   print_host((struct sockaddr *)&sa->sa_local.addr, NULL, 0));
+       timer_add(env, &sa->sa_keepalive, IKED_IKE_SA_KEEPALIVE_TIMEOUT);
+}
+
 int
 ikev2_send_informational(struct iked *env, struct iked_message *msg)
 {
index 86086e5..5724520 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ikev2_pld.c,v 1.61 2017/03/27 17:17:49 mikeb Exp $    */
+/*     $OpenBSD: ikev2_pld.c,v 1.62 2017/04/13 07:04:09 patrick Exp $  */
 
 /*
  * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -1148,6 +1148,9 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld,
                         */
                        if (msg->msg_sa != NULL)
                                msg->msg_sa->sa_udpencap = 1;
+                       /* Send keepalive, since we are behind a NAT-gw */
+                       if (type == IKEV2_N_NAT_DETECTION_DESTINATION_IP)
+                               msg->msg_sa->sa_usekeepalive = 1;
                }
                print_hex(md, 0, sizeof(md));
                break;