There seems to be an annoying bug in iked NAT traversal which leads to an iked falsely seeing a NAT when the "local" IP is not explicitly set in the config, as a result two ikeds will switch from port 500 to 4500 with the first CREATE_CHILD_SA exchange. The diff adds a new flag to the message and enables udpencap based on whether the last message contained a NAT detection notify.
Ok? Index: iked.h =================================================================== RCS file: /mount/openbsd/cvs/src/sbin/iked/iked.h,v retrieving revision 1.122 diff -u -p -u -r1.122 iked.h --- iked.h 12 Aug 2019 07:40:45 -0000 1.122 +++ iked.h 13 Aug 2019 13:16:32 -0000 @@ -514,6 +514,7 @@ struct iked_message { int msg_valid; int msg_natt; int msg_natt_rcvd; + int msg_nat_detected; int msg_error; int msg_e; struct iked_message *msg_parent; Index: ikev2.c =================================================================== RCS file: /mount/openbsd/cvs/src/sbin/iked/ikev2.c,v retrieving revision 1.172 diff -u -p -u -r1.172 ikev2.c --- ikev2.c 12 Aug 2019 07:40:45 -0000 1.172 +++ ikev2.c 13 Aug 2019 13:18:30 -0000 @@ -855,7 +855,7 @@ ikev2_init_recv(struct iked *env, struct if (!ikev2_msg_frompeer(msg)) return; - if (sa->sa_udpencap && sa->sa_natt == 0 && + if (sa && msg->msg_nat_detected && sa->sa_natt == 0 && (sock = ikev2_msg_getsocket(env, sa->sa_local.addr_af, 1)) != NULL) { /* @@ -872,9 +872,10 @@ ikev2_init_recv(struct iked *env, struct msg->msg_fd = sa->sa_fd = sock->sock_fd; msg->msg_sock = sock; sa->sa_natt = 1; + sa->sa_udpencap = 1; - log_debug("%s: NAT detected, updated SA to " - "peer %s local %s", __func__, + log_debug("%s: detected NAT, enabling UDP encapsulation," + " updated SA to 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)); } @@ -2439,6 +2440,11 @@ ikev2_resp_ike_sa_init(struct iked *env, if (sa->sa_hdr.sh_initiator) { log_debug("%s: called by initiator", __func__); return (-1); + } + if (msg->msg_nat_detected && sa->sa_udpencap == 0) { + log_debug("%s: detected NAT, enabling UDP encapsulation", + __func__); + sa->sa_udpencap = 1; } if ((buf = ikev2_msg_init(env, &resp, Index: ikev2_pld.c =================================================================== RCS file: /mount/openbsd/cvs/src/sbin/iked/ikev2_pld.c,v retrieving revision 1.72 diff -u -p -u -r1.72 ikev2_pld.c --- ikev2_pld.c 12 Aug 2019 07:40:45 -0000 1.72 +++ ikev2_pld.c 13 Aug 2019 13:16:32 -0000 @@ -1023,18 +1023,12 @@ ikev2_pld_notify(struct iked *env, struc if (ikev2_nat_detection(env, msg, md, sizeof(md), type) == -1) return (-1); if (memcmp(buf, md, len) != 0) { - log_debug("%s: %s detected NAT, enabling " - "UDP encapsulation", __func__, + log_debug("%s: %s detected NAT", __func__, print_map(type, ikev2_n_map)); - - /* - * Enable UDP encapsulation of ESP packages if - * the check detected NAT. - */ - if (msg->msg_sa != NULL) - msg->msg_sa->sa_udpencap = 1; + msg->msg_parent->msg_nat_detected = 1; /* Send keepalive, since we are behind a NAT-gw */ - if (type == IKEV2_N_NAT_DETECTION_DESTINATION_IP) + if (msg->msg_sa != NULL && + type == IKEV2_N_NAT_DETECTION_DESTINATION_IP) msg->msg_sa->sa_usekeepalive = 1; } print_hex(md, 0, sizeof(md));