diff options
author | tobhe <tobhe@cvs.openbsd.org> | 2020-10-29 21:49:59 +0000 |
---|---|---|
committer | tobhe <tobhe@cvs.openbsd.org> | 2020-10-29 21:49:59 +0000 |
commit | 83f2ccef17176467707527dabd9216b2afe092c2 (patch) | |
tree | a7d1f38d503ecda00c8b42855567306246965ae1 /sbin/iked | |
parent | df7cbdab60153656c19a828195074a4d83bdb9e0 (diff) |
Add initial support to request IP addresses as IKEv2 initiator.
At the moment the address is only negotiated and printed to the
log. If 'request addr 0.0.0.0' is configured, any address will
be accepted.
ok patrick@
Diffstat (limited to 'sbin/iked')
-rw-r--r-- | sbin/iked/config.c | 5 | ||||
-rw-r--r-- | sbin/iked/iked.h | 6 | ||||
-rw-r--r-- | sbin/iked/ikev2.c | 125 | ||||
-rw-r--r-- | sbin/iked/ikev2_msg.c | 6 | ||||
-rw-r--r-- | sbin/iked/ikev2_pld.c | 71 | ||||
-rw-r--r-- | sbin/iked/parse.y | 17 |
6 files changed, 211 insertions, 19 deletions
diff --git a/sbin/iked/config.c b/sbin/iked/config.c index a3aeec0a14d..5985c5303fa 100644 --- a/sbin/iked/config.c +++ b/sbin/iked/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.71 2020/10/21 17:47:36 tobhe Exp $ */ +/* $OpenBSD: config.c,v 1.72 2020/10/29 21:49:58 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> @@ -173,6 +173,9 @@ config_free_sa(struct iked *env, struct iked_sa *sa) free(sa->sa_eapid); ibuf_release(sa->sa_eapmsk); + free(sa->sa_cp_addr); + free(sa->sa_cp_addr6); + free(sa->sa_tag); free(sa); } diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h index 54583d4180d..36cf161c6b2 100644 --- a/sbin/iked/iked.h +++ b/sbin/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.169 2020/10/24 20:27:59 tobhe Exp $ */ +/* $OpenBSD: iked.h,v 1.170 2020/10/29 21:49:58 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> @@ -423,6 +423,8 @@ struct iked_sa { unsigned int sa_statevalid; /* IKE_AUTH */ int sa_cp; /* XXX */ + struct iked_addr *sa_cp_addr; /* requested address */ + struct iked_addr *sa_cp_addr6; /* requested address */ struct iked_policy *sa_policy; struct timeval sa_timecreated; @@ -603,6 +605,8 @@ struct iked_message { struct ibuf *msg_del_buf; int msg_del_protoid; int msg_cp; + struct iked_addr *msg_cp_addr; /* requested address */ + struct iked_addr *msg_cp_addr6; /* requested address */ /* MOBIKE */ int msg_update_sa_addresses; diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c index 94865246ef3..8632374a119 100644 --- a/sbin/iked/ikev2.c +++ b/sbin/iked/ikev2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.c,v 1.271 2020/10/28 20:54:13 tobhe Exp $ */ +/* $OpenBSD: ikev2.c,v 1.272 2020/10/29 21:49:58 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> @@ -142,7 +142,9 @@ int ikev2_handle_notifies(struct iked *, struct iked_message *); ssize_t ikev2_add_proposals(struct iked *, struct iked_sa *, struct ibuf *, struct iked_proposals *, uint8_t, int, int, int); -ssize_t ikev2_add_cp(struct iked *, struct iked_sa *, struct ibuf *); +ssize_t ikev2_add_cp(struct iked *, struct iked_sa *, int, struct ibuf *); +ssize_t ikev2_init_add_cp(struct iked *, struct iked_sa *, struct ibuf *); +ssize_t ikev2_resp_add_cp(struct iked *, struct iked_sa *, struct ibuf *); ssize_t ikev2_add_transform(struct ibuf *, uint8_t, uint8_t, uint16_t, uint16_t); ssize_t ikev2_add_ts(struct ibuf *, struct ikev2_payload **, ssize_t, @@ -159,6 +161,7 @@ int ikev2_add_buf(struct ibuf *buf, struct ibuf *); int ikev2_cp_setaddr(struct iked *, struct iked_sa *, sa_family_t); int ikev2_cp_fixaddr(struct iked_sa *, struct iked_addr *, struct iked_addr *); +int ikev2_cp_request_configured(struct iked_sa *); ssize_t ikev2_add_sighashnotify(struct ibuf *, struct ikev2_payload **, ssize_t); @@ -924,6 +927,22 @@ ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa, if (msg->msg_cp) sa->sa_cp = msg->msg_cp; + if (msg->msg_cp) { + if (msg->msg_cp_addr) { + sa->sa_cp_addr = msg->msg_cp_addr; + msg->msg_cp_addr = NULL; + log_info("%s: obtained lease: %s", SPI_SA(sa, __func__), + print_host((struct sockaddr *)&sa->sa_cp_addr->addr, NULL, 0)); + } + if (msg->msg_cp_addr6) { + sa->sa_cp_addr6 = msg->msg_cp_addr6; + msg->msg_cp_addr6 = NULL; + log_info("%s: obtained lease: %s", SPI_SA(sa, __func__), + print_host((struct sockaddr *)&sa->sa_cp_addr6->addr, NULL, 0)); + } + sa->sa_cp = msg->msg_cp; + } + /* For EAP and PSK AUTH can be verified without the CA process*/ if ((sa->sa_policy->pol_auth.auth_eap && sa->sa_eapmsk != NULL) || @@ -1429,13 +1448,12 @@ ikev2_init_ike_auth(struct iked *env, struct iked_sa *sa) len = ibuf_size(sa->sa_localauth.id_buf) + sizeof(*auth); /* CP payload */ - if (sa->sa_cp) { + if (ikev2_cp_request_configured(sa)) { if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_CP) == -1) goto done; - if ((pld = ikev2_add_payload(e)) == NULL) goto done; - if ((len = ikev2_add_cp(env, sa, e)) == -1) + if ((len = ikev2_init_add_cp(env, sa, e)) == -1) goto done; } @@ -2176,7 +2194,7 @@ ikev2_add_nat_detection(struct iked *env, struct ibuf *buf, } ssize_t -ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) +ikev2_add_cp(struct iked *env, struct iked_sa *sa, int type, struct ibuf *buf) { struct iked_policy *pol = sa->sa_policy; struct ikev2_cp *cp; @@ -2193,13 +2211,12 @@ ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) return (-1); len = sizeof(*cp); - switch (sa->sa_cp) { + switch (type) { case IKEV2_CP_REQUEST: - cp->cp_type = IKEV2_CP_REPLY; - break; case IKEV2_CP_REPLY: - case IKEV2_CP_SET: - case IKEV2_CP_ACK: + cp->cp_type = type; + break; + default: /* Not yet supported */ return (-1); } @@ -2289,6 +2306,31 @@ ikev2_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) } ssize_t +ikev2_init_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) +{ + return (ikev2_add_cp(env, sa, IKEV2_CP_REQUEST, buf)); +} + +ssize_t +ikev2_resp_add_cp(struct iked *env, struct iked_sa *sa, struct ibuf *buf) +{ + int ret; + + switch (sa->sa_cp) { + case IKEV2_CP_REQUEST: + ret = ikev2_add_cp(env, sa, IKEV2_CP_REPLY, buf); + break; + case IKEV2_CP_REPLY: + case IKEV2_CP_SET: + case IKEV2_CP_ACK: + default: + /* Not yet supported */ + ret = -1; + } + return (ret); +} + +ssize_t ikev2_add_proposals(struct iked *env, struct iked_sa *sa, struct ibuf *buf, struct iked_proposals *proposals, uint8_t protoid, int initiator, int sendikespi, int skipdh) @@ -3541,10 +3583,9 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) if (sa->sa_cp) { if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_CP) == -1) goto done; - if ((pld = ikev2_add_payload(e)) == NULL) goto done; - if ((len = ikev2_add_cp(env, sa, e)) == -1) + if ((len = ikev2_resp_add_cp(env, sa, e)) == -1) goto done; } @@ -6491,6 +6532,7 @@ ikev2_print_id(struct iked_id *id, char *idstr, size_t idstrlen) int ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa, sa_family_t family) { + char idstr[IKED_ID_SIZE]; struct iked_cfg *ikecfg = NULL; struct iked_policy *pol = sa->sa_policy; struct sockaddr_in *in4 = NULL, *cfg4 = NULL; @@ -6499,6 +6541,7 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa, sa_family_t family) struct iked_addr addr; uint32_t mask, host, lower, upper, start, nhost; size_t i; + int requested = 0; switch (family) { case AF_INET: @@ -6548,16 +6591,46 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa, sa_family_t family) switch (addr.addr_af) { case AF_INET: cfg4 = (struct sockaddr_in *)&ikecfg->cfg.address.addr; + mask = prefixlen2mask(ikecfg->cfg.address.addr_mask); + if (sa->sa_cp_addr != NULL) { + memcpy(&addr, sa->sa_cp_addr, sizeof(addr)); + key.sa_addrpool = &addr; + in4 = (struct sockaddr_in *)&addr.addr; + if ((in4->sin_addr.s_addr & mask) != + (cfg4->sin_addr.s_addr & mask)) { + log_info("%s: requested addr out of range: %s", + SPI_SA(sa, __func__), print_host( + (struct sockaddr *)&addr.addr, NULL, 0)); + return (-1); + } else if (RB_FIND(iked_addrpool, &env->sc_addrpool, + &key)) { + log_info("%s: requested addr in use: %s", + SPI_SA(sa, __func__), print_host( + (struct sockaddr *)&addr.addr, NULL, 0)); + } else { + sa->sa_addrpool = sa->sa_cp_addr; + sa->sa_cp_addr = NULL; + RB_INSERT(iked_addrpool, &env->sc_addrpool, sa); + requested = 1; + goto done; + } + free(sa->sa_cp_addr); + sa->sa_cp_addr = NULL; + } in4 = (struct sockaddr_in *)&addr.addr; in4->sin_family = AF_INET; in4->sin_len = sizeof(*in4); - mask = prefixlen2mask(ikecfg->cfg.address.addr_mask); lower = ntohl(cfg4->sin_addr.s_addr & ~mask); key.sa_addrpool = &addr; break; case AF_INET6: cfg6 = (struct sockaddr_in6 *)&ikecfg->cfg.address.addr; in6 = (struct sockaddr_in6 *)&addr.addr; + if (sa->sa_cp_addr6 != NULL) { + /* XXX not yet supported */ + free(sa->sa_cp_addr6); + sa->sa_cp_addr6 = NULL; + } in6->sin6_family = AF_INET6; in6->sin6_len = sizeof(*in6); /* truncate prefixlen to get a 32-bit space */ @@ -6632,9 +6705,33 @@ ikev2_cp_setaddr(struct iked *env, struct iked_sa *sa, sa_family_t family) default: return (-1); } + done: + if (ikev2_print_id(IKESA_DSTID(sa), idstr, sizeof(idstr)) == -1) + bzero(idstr, sizeof(idstr)); + log_info("%sassigned address %s to %s%s", SPI_SA(sa, NULL), + print_host((struct sockaddr *)&addr.addr, NULL, 0), + idstr, requested ? " (requested by peer)" : ""); return (0); } +int +ikev2_cp_request_configured(struct iked_sa *sa) +{ + struct iked_policy *pol = sa->sa_policy; + struct iked_cfg *ikecfg; + unsigned int i; + + for (i = 0; i < pol->pol_ncfg; i++) { + ikecfg = &pol->pol_cfg[i]; + if (ikecfg->cfg_action == IKEV2_CP_REQUEST) { + log_debug("%s: yes", SPI_SA(sa, __func__)); + return 1; + } + } + log_debug("%s: no", SPI_SA(sa, __func__)); + return 0; +} + /* * if 'addr' is 'UNSPECIFIED' replace it with sa_addrpool from * the ip-pool and store the result in 'patched'. diff --git a/sbin/iked/ikev2_msg.c b/sbin/iked/ikev2_msg.c index 13d3c3e6694..ad633a7b347 100644 --- a/sbin/iked/ikev2_msg.c +++ b/sbin/iked/ikev2_msg.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_msg.c,v 1.76 2020/10/09 08:59:16 tobhe Exp $ */ +/* $OpenBSD: ikev2_msg.c,v 1.77 2020/10/29 21:49:58 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> @@ -195,6 +195,8 @@ ikev2_msg_cleanup(struct iked *env, struct iked_message *msg) ibuf_release(msg->msg_cookie2); ibuf_release(msg->msg_del_buf); free(msg->msg_eap.eam_user); + free(msg->msg_cp_addr); + free(msg->msg_cp_addr6); msg->msg_nonce = NULL; msg->msg_ke = NULL; @@ -205,6 +207,8 @@ ikev2_msg_cleanup(struct iked *env, struct iked_message *msg) msg->msg_cookie2 = NULL; msg->msg_del_buf = NULL; msg->msg_eap.eam_user = NULL; + msg->msg_cp_addr = NULL; + msg->msg_cp_addr6 = NULL; config_free_proposals(&msg->msg_proposals, 0); while ((cr = SIMPLEQ_FIRST(&msg->msg_certreqs))) { diff --git a/sbin/iked/ikev2_pld.c b/sbin/iked/ikev2_pld.c index e121140c7fa..e0545260a08 100644 --- a/sbin/iked/ikev2_pld.c +++ b/sbin/iked/ikev2_pld.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_pld.c,v 1.107 2020/10/24 20:27:59 tobhe Exp $ */ +/* $OpenBSD: ikev2_pld.c,v 1.108 2020/10/29 21:49:58 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> @@ -1805,8 +1805,12 @@ ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld, { struct ikev2_cp cp; struct ikev2_cfg *cfg; + struct iked_addr *addr; + struct sockaddr_in *in4; + struct sockaddr_in6 *in6; uint8_t *ptr; size_t len; + uint8_t buf[128]; if (ikev2_validate_cp(msg, offset, left, &cp)) return (-1); @@ -1841,6 +1845,71 @@ ikev2_pld_cp(struct iked *env, struct ikev2_payload *pld, return (-1); } + print_hex(ptr, sizeof(*cfg), betoh16(cfg->cfg_length)); + + switch (betoh16(cfg->cfg_type)) { + case IKEV2_CFG_INTERNAL_IP4_ADDRESS: + if (!ikev2_msg_frompeer(msg)) + break; + if (betoh16(cfg->cfg_length) == 0) + break; + /* XXX multiple-valued */ + if (betoh16(cfg->cfg_length) < 4) { + log_debug("%s: malformed payload: too short " + "for ipv4 addr (%u < %u)", + __func__, betoh16(cfg->cfg_length), 4); + return (-1); + } + if (msg->msg_parent->msg_cp_addr != NULL) { + log_debug("%s: address already set", __func__); + break; + } + if ((addr = calloc(1, sizeof(*addr))) == NULL) { + log_debug("%s: malloc failed", __func__); + break; + } + addr->addr_af = AF_INET; + in4 = (struct sockaddr_in *)&addr->addr; + in4->sin_family = AF_INET; + in4->sin_len = sizeof(*in4); + memcpy(&in4->sin_addr.s_addr, ptr, 4); + print_host((struct sockaddr *)in4, (char *)buf, + sizeof(buf)); + log_debug("%s: cfg %s", __func__, buf); + msg->msg_parent->msg_cp_addr = addr; + break; + case IKEV2_CFG_INTERNAL_IP6_ADDRESS: + if (!ikev2_msg_frompeer(msg)) + break; + if (betoh16(cfg->cfg_length) == 0) + break; + /* XXX multiple-valued */ + if (betoh16(cfg->cfg_length) < 16 + 1) { + log_debug("%s: malformed payload: too short " + "for ipv6 addr w/prefixlen (%u < %u)", + __func__, betoh16(cfg->cfg_length), 16 + 1); + return (-1); + } + if (msg->msg_parent->msg_cp_addr6 != NULL) { + log_debug("%s: address already set", __func__); + break; + } + if ((addr = calloc(1, sizeof(*addr))) == NULL) { + log_debug("%s: malloc failed", __func__); + break; + } + addr->addr_af = AF_INET6; + in6 = (struct sockaddr_in6 *)&addr->addr; + in6->sin6_family = AF_INET6; + in6->sin6_len = sizeof(*in6); + memcpy(&in6->sin6_addr, ptr, 16); + print_host((struct sockaddr *)in6, (char *)buf, + sizeof(buf)); + log_debug("%s: cfg %s/%d", __func__, buf, ptr[16]); + msg->msg_parent->msg_cp_addr6 = addr; + break; + } + ptr += betoh16(cfg->cfg_length); len -= betoh16(cfg->cfg_length); } diff --git a/sbin/iked/parse.y b/sbin/iked/parse.y index 45f2e5eb45b..36b36bd036f 100644 --- a/sbin/iked/parse.y +++ b/sbin/iked/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.114 2020/09/23 14:25:55 tobhe Exp $ */ +/* $OpenBSD: parse.y,v 1.115 2020/10/29 21:49:58 tobhe Exp $ */ /* * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de> @@ -456,6 +456,7 @@ typedef struct { %token ENFORCESINGLEIKESA NOENFORCESINGLEIKESA %token TOLERATE MAXAGE %token CERTPARTIALCHAIN +%token REQUEST %token <v.string> STRING %token <v.number> NUMBER %type <v.string> string @@ -608,6 +609,19 @@ cfg : CONFIG STRING host_spec { $$->type = xf->id; $$->action = IKEV2_CP_REPLY; /* XXX */ } + | REQUEST STRING host_spec { + const struct ipsec_xf *xf; + + if ((xf = parse_xf($2, $3->af, cpxfs)) == NULL) { + yyerror("not a valid ikecfg option"); + free($2); + free($3); + YYERROR; + } + $$ = $3; + $$->type = xf->id; + $$->action = IKEV2_CP_REQUEST; /* XXX */ + } ; name : /* empty */ { $$ = NULL; } @@ -1352,6 +1366,7 @@ lookup(char *s) { "psk", PSK }, { "quick", QUICK }, { "rdomain", RDOMAIN }, + { "request", REQUEST }, { "sa", SA }, { "set", SET }, { "skip", SKIP }, |