diff options
author | 2012-10-22 10:25:17 +0000 | |
---|---|---|
committer | 2012-10-22 10:25:17 +0000 | |
commit | 12c9fd313ce8391f5d86ec0f745cbf6ee4c4eb45 (patch) | |
tree | 3c556259e416d0c34e5d5de97fcdc34b1f1e59b9 | |
parent | Add flow control support. (diff) | |
download | wireguard-openbsd-12c9fd313ce8391f5d86ec0f745cbf6ee4c4eb45.tar.xz wireguard-openbsd-12c9fd313ce8391f5d86ec0f745cbf6ee4c4eb45.zip |
Fix NAT-T support in iked, both on the initiator and the responder
side. Also add a new command line option -t to optionally enforce
NAT-T with UDP encapsulation on port 4500.
Tested by mikeb@ and me
ok mikeb@
-rw-r--r-- | sbin/iked/config.c | 13 | ||||
-rw-r--r-- | sbin/iked/iked.8 | 8 | ||||
-rw-r--r-- | sbin/iked/iked.c | 25 | ||||
-rw-r--r-- | sbin/iked/iked.h | 11 | ||||
-rw-r--r-- | sbin/iked/ikev2.c | 75 | ||||
-rw-r--r-- | sbin/iked/ikev2_msg.c | 25 | ||||
-rw-r--r-- | sbin/iked/ikev2_pld.c | 4 | ||||
-rw-r--r-- | sbin/iked/types.h | 5 |
8 files changed, 117 insertions, 49 deletions
diff --git a/sbin/iked/config.c b/sbin/iked/config.c index ccf0531d616..3b957c965be 100644 --- a/sbin/iked/config.c +++ b/sbin/iked/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.16 2012/09/18 12:07:59 reyk Exp $ */ +/* $OpenBSD: config.c,v 1.17 2012/10/22 10:25:17 reyk Exp $ */ /* $vantronix: config.c,v 1.30 2010/05/28 15:34:35 reyk Exp $ */ /* @@ -504,7 +504,7 @@ int config_getsocket(struct iked *env, struct imsg *imsg, void (*cb)(int, short, void *)) { - struct iked_socket *sock, **sptr; + struct iked_socket *sock, **sptr, **nptr; log_debug("%s: received socket fd %d", __func__, imsg->fd); @@ -519,10 +519,12 @@ config_getsocket(struct iked *env, struct imsg *imsg, switch (sock->sock_addr.ss_family) { case AF_INET: - sptr = &env->sc_sock4; + sptr = &env->sc_sock4[0]; + nptr = &env->sc_sock4[1]; break; case AF_INET6: - sptr = &env->sc_sock6; + sptr = &env->sc_sock6[0]; + nptr = &env->sc_sock6[1]; break; default: fatal("config_getsocket: socket af"); @@ -530,6 +532,9 @@ config_getsocket(struct iked *env, struct imsg *imsg, } if (*sptr == NULL) *sptr = sock; + if (*nptr == NULL && + socket_getport(&sock->sock_addr) == IKED_NATT_PORT) + *nptr = sock; event_set(&sock->sock_ev, sock->sock_fd, EV_READ|EV_PERSIST, cb, sock); diff --git a/sbin/iked/iked.8 b/sbin/iked/iked.8 index 03357a43131..2a0c4b4c365 100644 --- a/sbin/iked/iked.8 +++ b/sbin/iked/iked.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: iked.8,v 1.8 2012/09/22 20:09:43 jmc Exp $ +.\" $OpenBSD: iked.8,v 1.9 2012/10/22 10:25:17 reyk Exp $ .\" $vantronix: iked.8,v 1.5 2010/06/02 14:38:08 reyk Exp $ .\" .\" Copyright (c) 2010 Reyk Floeter <reyk@openbsd.org> @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: September 22 2012 $ +.Dd $Mdocdate: October 22 2012 $ .Dt IKED 8 .Os .Sh NAME @@ -90,6 +90,10 @@ option in for more information. .It Fl T Disable NAT-Traversal and do not propose NAT-Traversal support to the peers. +.It Fl t +Enforce NAT-Traversal and only listen to NAT-Traversal messages. +This option is only recommended for testing, the default is to +negotiate NAT-Traversal with the peers. .It Fl v Produce more verbose output. .El diff --git a/sbin/iked/iked.c b/sbin/iked/iked.c index e225652ac21..583f1c93986 100644 --- a/sbin/iked/iked.c +++ b/sbin/iked/iked.c @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.c,v 1.12 2012/09/18 12:07:59 reyk Exp $ */ +/* $OpenBSD: iked.c,v 1.13 2012/10/22 10:25:17 reyk Exp $ */ /* $vantronix: iked.c,v 1.22 2010/06/02 14:43:30 reyk Exp $ */ /* @@ -65,7 +65,7 @@ usage(void) { extern char *__progname; - fprintf(stderr, "usage: %s [-dnSTv] [-D macro=value] " + fprintf(stderr, "usage: %s [-dnSTtv] [-D macro=value] " "[-f file]\n", __progname); exit(1); } @@ -82,7 +82,7 @@ main(int argc, char *argv[]) log_init(1); - while ((c = getopt(argc, argv, "dD:nf:vST")) != -1) { + while ((c = getopt(argc, argv, "dD:nf:vSTt")) != -1) { switch (c) { case 'd': debug++; @@ -109,6 +109,9 @@ main(int argc, char *argv[]) case 'T': opts |= IKED_OPT_NONATT; break; + case 't': + opts |= IKED_OPT_NATT; + break; default: usage(); } @@ -125,6 +128,10 @@ main(int argc, char *argv[]) ps = &env->sc_ps; ps->ps_env = env; + if ((opts & (IKED_OPT_NONATT|IKED_OPT_NATT)) == + (IKED_OPT_NONATT|IKED_OPT_NATT)) + errx(1, "conflicting NAT-T options"); + if (strlcpy(env->sc_conffile, conffile, MAXPATHLEN) >= MAXPATHLEN) errx(1, "config file exceeds MAXPATHLEN"); @@ -204,14 +211,18 @@ parent_configure(struct iked *env) bzero(&ss, sizeof(ss)); ss.ss_family = AF_INET; - config_setsocket(env, &ss, ntohs(IKED_IKE_PORT), PROC_IKEV2); - config_setsocket(env, &ss, ntohs(IKED_NATT_PORT), PROC_IKEV2); + if ((env->sc_opts & IKED_OPT_NATT) == 0) + config_setsocket(env, &ss, ntohs(IKED_IKE_PORT), PROC_IKEV2); + if ((env->sc_opts & IKED_OPT_NONATT) == 0) + config_setsocket(env, &ss, ntohs(IKED_NATT_PORT), PROC_IKEV2); bzero(&ss, sizeof(ss)); ss.ss_family = AF_INET6; - config_setsocket(env, &ss, ntohs(IKED_IKE_PORT), PROC_IKEV2); - config_setsocket(env, &ss, ntohs(IKED_NATT_PORT), PROC_IKEV2); + if ((env->sc_opts & IKED_OPT_NATT) == 0) + config_setsocket(env, &ss, ntohs(IKED_IKE_PORT), PROC_IKEV2); + if ((env->sc_opts & IKED_OPT_NONATT) == 0) + config_setsocket(env, &ss, ntohs(IKED_NATT_PORT), PROC_IKEV2); config_setcoupled(env, env->sc_decoupled ? 0 : 1); config_setmode(env, env->sc_passive ? 1 : 0); diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h index eff1bc27498..02516c4300b 100644 --- a/sbin/iked/iked.h +++ b/sbin/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.53 2012/09/18 12:07:59 reyk Exp $ */ +/* $OpenBSD: iked.h,v 1.54 2012/10/22 10:25:17 reyk Exp $ */ /* $vantronix: iked.h,v 1.61 2010/06/03 07:57:33 reyk Exp $ */ /* @@ -526,8 +526,8 @@ struct iked { u_int8_t sc_certreqtype; struct ibuf *sc_certreq; - struct iked_socket *sc_sock4; - struct iked_socket *sc_sock6; + struct iked_socket *sc_sock4[2]; + struct iked_socket *sc_sock6[2]; struct iked_timer sc_inittmr; #define IKED_INITIATOR_INITIAL 2 @@ -689,7 +689,8 @@ struct ibuf * ikev2_prfplus(struct iked_hash *, struct ibuf *, struct ibuf *, size_t); ssize_t ikev2_psk(struct iked_sa *, u_int8_t *, size_t, u_int8_t **); -ssize_t ikev2_nat_detection(struct iked_message *, void *, size_t, u_int); +ssize_t ikev2_nat_detection(struct iked *, struct iked_message *, + void *, size_t, u_int); int ikev2_send_informational(struct iked *, struct iked_message *); int ikev2_send_ike_e(struct iked *, struct iked_sa *, struct ibuf *, u_int8_t, u_int8_t, int); @@ -737,7 +738,7 @@ struct ibuf * int ikev2_msg_integr(struct iked *, struct iked_sa *, struct ibuf *); int ikev2_msg_frompeer(struct iked_message *); struct iked_socket * - ikev2_msg_getsocket(struct iked *, int); + ikev2_msg_getsocket(struct iked *, int, int); int ikev2_msg_retransmit_response(struct iked *, struct iked_sa *, struct iked_message *); void ikev2_msg_prevail(struct iked *, struct iked_msgqueue *, diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c index f9e0f1cf856..5c2113f3cbe 100644 --- a/sbin/iked/ikev2.c +++ b/sbin/iked/ikev2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.c,v 1.77 2012/09/18 12:07:59 reyk Exp $ */ +/* $OpenBSD: ikev2.c,v 1.78 2012/10/22 10:25:17 reyk Exp $ */ /* $vantronix: ikev2.c,v 1.101 2010/06/03 07:57:33 reyk Exp $ */ /* @@ -376,11 +376,6 @@ ikev2_recv(struct iked *env, struct iked_message *msg) if ((sa = msg->msg_sa) == NULL) goto done; - log_debug("%s: updating msg, natt %d", __func__, msg->msg_natt); - - if (msg->msg_natt) - sa->sa_natt = 1; - if (hdr->ike_exchange == IKEV2_EXCHANGE_CREATE_CHILD_SA) flag = IKED_REQ_CHILDSA; if (hdr->ike_exchange == IKEV2_EXCHANGE_INFORMATIONAL) @@ -432,7 +427,7 @@ ikev2_recv(struct iked *env, struct iked_message *msg) sa->sa_fd = msg->msg_fd; - log_debug("%s: updated SA peer %s local %s", __func__, + log_debug("%s: updated SA to peer %s local %s", __func__, print_host(&sa->sa_peer.addr, NULL, 0), print_host(&sa->sa_local.addr, NULL, 0)); @@ -577,6 +572,8 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, struct ike_header *hdr) { struct iked_sa *sa; + in_port_t port; + struct iked_socket *sock; if (ikev2_msg_valid_ike_sa(env, hdr, msg) == -1) { log_debug("%s: unknown SA", __func__); @@ -615,6 +612,29 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, if (!ikev2_msg_frompeer(msg)) return; + if (sa->sa_udpencap && sa->sa_natt == 0 && + (sock = ikev2_msg_getsocket(env, + sa->sa_local.addr_af, 1)) != NULL) { + /* + * Update address information and use the NAT-T + * port and socket, if available. + */ + port = htons(socket_getport(&sock->sock_addr)); + sa->sa_local.addr_port = port; + sa->sa_peer.addr_port = port; + (void)socket_af((struct sockaddr *)&sa->sa_local.addr, port); + (void)socket_af((struct sockaddr *)&sa->sa_peer.addr, port); + + msg->msg_fd = sa->sa_fd = sock->sock_fd; + msg->msg_sock = sock; + sa->sa_natt = 1; + + log_debug("%s: NAT detected, updated SA to " + "peer %s local %s", __func__, + print_host(&sa->sa_peer.addr, NULL, 0), + print_host(&sa->sa_local.addr, NULL, 0)); + } + switch (hdr->ike_exchange) { case IKEV2_EXCHANGE_IKE_SA_INIT: (void)ikev2_init_auth(env, msg); @@ -678,7 +698,7 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, struct iked_socket *sock; in_port_t port; - if ((sock = ikev2_msg_getsocket(env, peer->addr_af)) == NULL) + if ((sock = ikev2_msg_getsocket(env, peer->addr_af, 0)) == NULL) return (-1); /* Create a new initiator SA */ @@ -751,6 +771,12 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, len = ibuf_size(sa->sa_inonce); if ((env->sc_opts & IKED_OPT_NONATT) == 0) { + if (ntohs(port) == IKED_NATT_PORT) { + /* Enforce NAT-T on the initiator side */ + log_debug("%s: enforcing NAT-T", __func__); + req.msg_natt = sa->sa_natt = 1; + } + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NOTIFY) == -1) goto done; @@ -760,10 +786,10 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, if ((n = ibuf_advance(buf, sizeof(*n))) == NULL) goto done; n->n_type = htobe16(IKEV2_N_NAT_DETECTION_SOURCE_IP); - len = ikev2_nat_detection(&req, NULL, 0, 0); + len = ikev2_nat_detection(env, &req, NULL, 0, 0); if ((ptr = ibuf_advance(buf, len)) == NULL) goto done; - if ((len = ikev2_nat_detection(&req, ptr, len, + if ((len = ikev2_nat_detection(env, &req, ptr, len, betoh16(n->n_type))) == -1) goto done; len += sizeof(*n); @@ -776,10 +802,10 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, if ((n = ibuf_advance(buf, sizeof(*n))) == NULL) goto done; n->n_type = htobe16(IKEV2_N_NAT_DETECTION_DESTINATION_IP); - len = ikev2_nat_detection(&req, NULL, 0, 0); + len = ikev2_nat_detection(env, &req, NULL, 0, 0); if ((ptr = ibuf_advance(buf, len)) == NULL) goto done; - if ((len = ikev2_nat_detection(&req, ptr, len, + if ((len = ikev2_nat_detection(env, &req, ptr, len, betoh16(n->n_type))) == -1) goto done; len += sizeof(*n); @@ -1258,8 +1284,8 @@ ikev2_next_payload(struct ikev2_payload *pld, size_t length, } ssize_t -ikev2_nat_detection(struct iked_message *msg, void *ptr, size_t len, - u_int type) +ikev2_nat_detection(struct iked *env, struct iked_message *msg, + void *ptr, size_t len, u_int type) { EVP_MD_CTX ctx; struct ike_header *hdr; @@ -1273,6 +1299,7 @@ ikev2_nat_detection(struct iked_message *msg, void *ptr, size_t len, u_int64_t rspi, ispi; struct ibuf *buf; int frompeer = 0; + u_int32_t rnd; if (ptr == NULL) return (mdlen); @@ -1340,6 +1367,12 @@ ikev2_nat_detection(struct iked_message *msg, void *ptr, size_t len, goto done; } + if (env->sc_opts & IKED_OPT_NATT) { + /* Enforce NAT-T/UDP-encapsulation by distorting the digest */ + rnd = arc4random(); + EVP_DigestUpdate(&ctx, &rnd, sizeof(rnd)); + } + EVP_DigestFinal_ex(&ctx, md, &mdlen); if (len < mdlen) @@ -1644,6 +1677,11 @@ ikev2_resp_recv(struct iked *env, struct iked_message *msg, if ((sa = msg->msg_sa) == NULL) return; + if (msg->msg_natt && sa->sa_natt == 0) { + log_debug("%s: NAT-T message received, updated SA", __func__); + sa->sa_natt = 1; + } + switch (hdr->ike_exchange) { case IKEV2_EXCHANGE_IKE_SA_INIT: if (ikev2_sa_responder(env, sa, NULL, msg) != 0) { @@ -1710,6 +1748,7 @@ ikev2_resp_ike_sa_init(struct iked *env, struct iked_message *msg) resp.msg_sa = sa; resp.msg_fd = msg->msg_fd; + resp.msg_natt = msg->msg_natt; resp.msg_msgid = 0; /* IKE header */ @@ -1763,10 +1802,10 @@ ikev2_resp_ike_sa_init(struct iked *env, struct iked_message *msg) if ((n = ibuf_advance(buf, sizeof(*n))) == NULL) goto done; n->n_type = htobe16(IKEV2_N_NAT_DETECTION_SOURCE_IP); - len = ikev2_nat_detection(&resp, NULL, 0, 0); + len = ikev2_nat_detection(env, &resp, NULL, 0, 0); if ((ptr = ibuf_advance(buf, len)) == NULL) goto done; - if ((len = ikev2_nat_detection(&resp, ptr, len, + if ((len = ikev2_nat_detection(env, &resp, ptr, len, betoh16(n->n_type))) == -1) goto done; len += sizeof(*n); @@ -1779,10 +1818,10 @@ ikev2_resp_ike_sa_init(struct iked *env, struct iked_message *msg) if ((n = ibuf_advance(buf, sizeof(*n))) == NULL) goto done; n->n_type = htobe16(IKEV2_N_NAT_DETECTION_DESTINATION_IP); - len = ikev2_nat_detection(&resp, NULL, 0, 0); + len = ikev2_nat_detection(env, &resp, NULL, 0, 0); if ((ptr = ibuf_advance(buf, len)) == NULL) goto done; - if ((len = ikev2_nat_detection(&resp, ptr, len, + if ((len = ikev2_nat_detection(env, &resp, ptr, len, betoh16(n->n_type))) == -1) goto done; len += sizeof(*n); diff --git a/sbin/iked/ikev2_msg.c b/sbin/iked/ikev2_msg.c index 7b1df69dfe2..aed848d608f 100644 --- a/sbin/iked/ikev2_msg.c +++ b/sbin/iked/ikev2_msg.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_msg.c,v 1.21 2012/09/18 12:07:59 reyk Exp $ */ +/* $OpenBSD: ikev2_msg.c,v 1.22 2012/10/22 10:25:17 reyk Exp $ */ /* $vantronix: ikev2.c,v 1.101 2010/06/03 07:57:33 reyk Exp $ */ /* @@ -136,11 +136,15 @@ ikev2_msg_copy(struct iked *env, struct iked_message *msg) { struct iked_message *m = NULL; struct ibuf *buf; + ssize_t len; + void *ptr; - if ((m = malloc(sizeof(*m))) == NULL || + if ((len = ibuf_size(msg->msg_data) - msg->msg_offset) <= 0 || + (ptr = ibuf_seek(msg->msg_data, msg->msg_offset, len)) == NULL || + (m = malloc(sizeof(*m))) == NULL || (buf = ikev2_msg_init(env, m, &msg->msg_peer, msg->msg_peerlen, &msg->msg_local, msg->msg_locallen, msg->msg_response)) == NULL || - ibuf_add(buf, ibuf_data(msg->msg_data), ibuf_size(msg->msg_data))) + ibuf_add(buf, ptr, len)) return (NULL); m->msg_fd = msg->msg_fd; @@ -253,6 +257,7 @@ ikev2_msg_send(struct iked *env, struct iked_message *msg) struct iked_sa *sa = msg->msg_sa; struct ibuf *buf = msg->msg_data; u_int32_t natt = 0x00000000; + int isnatt = 0; struct ike_header *hdr; struct iked_message *m; @@ -260,13 +265,15 @@ ikev2_msg_send(struct iked *env, struct iked_message *msg) msg->msg_offset, sizeof(*hdr))) == NULL) return (-1); - log_info("%s: %s from %s to %s, %ld bytes", __func__, + isnatt = (msg->msg_natt || (msg->msg_sa && msg->msg_sa->sa_natt)); + + log_info("%s: %s from %s to %s, %ld bytes%s", __func__, print_map(hdr->ike_exchange, ikev2_exchange_map), print_host(&msg->msg_local, NULL, 0), print_host(&msg->msg_peer, NULL, 0), - ibuf_length(buf)); + ibuf_length(buf), isnatt ? ", NAT-T" : ""); - if (msg->msg_natt || (msg->msg_sa && msg->msg_sa->sa_natt)) { + if (isnatt) { if (ibuf_prepend(buf, &natt, sizeof(natt)) == -1) { log_debug("%s: failed to set NAT-T", __func__); return (-1); @@ -874,13 +881,13 @@ ikev2_msg_frompeer(struct iked_message *msg) } struct iked_socket * -ikev2_msg_getsocket(struct iked *env, int af) +ikev2_msg_getsocket(struct iked *env, int af, int natt) { switch (af) { case AF_INET: - return (env->sc_sock4); + return (env->sc_sock4[natt ? 1 : 0]); case AF_INET6: - return (env->sc_sock6); + return (env->sc_sock6[natt ? 1 : 0]); } log_debug("%s: af socket %d not available", __func__, af); diff --git a/sbin/iked/ikev2_pld.c b/sbin/iked/ikev2_pld.c index ccc76faa059..1a3193b7edc 100644 --- a/sbin/iked/ikev2_pld.c +++ b/sbin/iked/ikev2_pld.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_pld.c,v 1.27 2012/09/18 12:07:59 reyk Exp $ */ +/* $OpenBSD: ikev2_pld.c,v 1.28 2012/10/22 10:25:17 reyk Exp $ */ /* $vantronix: ikev2.c,v 1.101 2010/06/03 07:57:33 reyk Exp $ */ /* @@ -666,7 +666,7 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, switch (type) { case IKEV2_N_NAT_DETECTION_SOURCE_IP: case IKEV2_N_NAT_DETECTION_DESTINATION_IP: - if (ikev2_nat_detection(msg, md, sizeof(md), type) == -1) + if (ikev2_nat_detection(env, msg, md, sizeof(md), type) == -1) return (-1); if (len != sizeof(md) || memcmp(buf, md, len) != 0) { log_debug("%s: %s detected NAT, enabling " diff --git a/sbin/iked/types.h b/sbin/iked/types.h index c46cf886f33..e9db578f90c 100644 --- a/sbin/iked/types.h +++ b/sbin/iked/types.h @@ -1,4 +1,4 @@ -/* $OpenBSD: types.h,v 1.13 2012/10/11 08:23:12 reyk Exp $ */ +/* $OpenBSD: types.h,v 1.14 2012/10/22 10:25:17 reyk Exp $ */ /* $vantronix: types.h,v 1.24 2010/05/11 12:05:56 reyk Exp $ */ /* @@ -40,7 +40,8 @@ #define IKED_OPT_VERBOSE 0x00000001 #define IKED_OPT_NOACTION 0x00000002 #define IKED_OPT_NONATT 0x00000004 -#define IKED_OPT_PASSIVE 0x00000008 +#define IKED_OPT_NATT 0x00000008 +#define IKED_OPT_PASSIVE 0x00000010 #define IKED_IKE_PORT 500 #define IKED_NATT_PORT 4500 |