pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-upf/+/41482?usp=email )
Change subject: Validate session remote CP F-SEID and use it to transmit session requests ......................................................................
Validate session remote CP F-SEID and use it to transmit session requests
Change-Id: Ifccd4d2b8d500c9928778400bb096baaa12c9a31 --- M include/osmocom/upf/pfcp_entity_peer.h M src/osmo-upf/pfcp_entity_peer.c M src/osmo-upf/up_endpoint.c M src/osmo-upf/up_session.c 4 files changed, 155 insertions(+), 34 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-upf refs/changes/82/41482/1
diff --git a/include/osmocom/upf/pfcp_entity_peer.h b/include/osmocom/upf/pfcp_entity_peer.h index d2727e5..ae771eb 100644 --- a/include/osmocom/upf/pfcp_entity_peer.h +++ b/include/osmocom/upf/pfcp_entity_peer.h @@ -73,9 +73,12 @@
char *pfcp_entity_peer_remote_addr_str(struct pfcp_entity_peer *entity_peer);
-struct osmo_pfcp_msg *pfcp_entity_peer_init_tx(struct pfcp_entity_peer *entity_peer, - struct osmo_pfcp_msg *in_reply_to, - enum osmo_pfcp_message_type message_type); +struct osmo_pfcp_msg *pfcp_entity_peer_init_tx_req(struct pfcp_entity_peer *peer, + const struct osmo_sockaddr *dst_addr, + enum osmo_pfcp_message_type message_type); +struct osmo_pfcp_msg *pfcp_entity_peer_init_tx_resp(struct pfcp_entity_peer *peer, + struct osmo_pfcp_msg *in_reply_to, + enum osmo_pfcp_message_type message_type);
struct up_session *pfcp_entity_peer_find_up_session_by_up_seid(struct pfcp_entity_peer *entity_peer, uint64_t up_seid); struct up_session *pfcp_entity_peer_find_up_session_by_cp_f_seid(struct pfcp_entity_peer *entity_peer, const struct osmo_pfcp_ie_f_seid *cp_f_seid); diff --git a/src/osmo-upf/pfcp_entity_peer.c b/src/osmo-upf/pfcp_entity_peer.c index db02f78..7b8c28d 100644 --- a/src/osmo-upf/pfcp_entity_peer.c +++ b/src/osmo-upf/pfcp_entity_peer.c @@ -194,15 +194,22 @@ m->ctx.peer_use_token = NULL; }
-struct osmo_pfcp_msg *pfcp_entity_peer_init_tx(struct pfcp_entity_peer *peer, - struct osmo_pfcp_msg *in_reply_to, - enum osmo_pfcp_message_type message_type) +struct osmo_pfcp_msg *pfcp_entity_peer_init_tx_req(struct pfcp_entity_peer *peer, + const struct osmo_sockaddr *dst_addr, + enum osmo_pfcp_message_type message_type) { struct osmo_pfcp_msg *tx; - if (in_reply_to) - tx = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, in_reply_to, message_type); - else - tx = osmo_pfcp_msg_alloc_tx_req(OTC_SELECT, &peer->remote_addr, message_type); + tx = osmo_pfcp_msg_alloc_tx_req(OTC_SELECT, dst_addr, message_type); + pfcp_entity_peer_set_msg_ctx(peer, tx); + return tx; +} + +struct osmo_pfcp_msg *pfcp_entity_peer_init_tx_resp(struct pfcp_entity_peer *peer, + struct osmo_pfcp_msg *in_reply_to, + enum osmo_pfcp_message_type message_type) +{ + struct osmo_pfcp_msg *tx; + tx = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, in_reply_to, message_type); pfcp_entity_peer_set_msg_ctx(peer, tx); return tx; } @@ -211,7 +218,7 @@ { struct osmo_pfcp_msg *resp;
- resp = pfcp_entity_peer_init_tx(entity_peer, m, OSMO_PFCP_MSGT_ASSOC_SETUP_RESP); + resp = pfcp_entity_peer_init_tx_resp(entity_peer, m, OSMO_PFCP_MSGT_ASSOC_SETUP_RESP);
resp->ies.assoc_setup_resp = (struct osmo_pfcp_msg_assoc_setup_resp) { .cause = cause, @@ -232,7 +239,7 @@ { struct osmo_pfcp_msg *resp;
- resp = pfcp_entity_peer_init_tx(peer, m, OSMO_PFCP_MSGT_ASSOC_RELEASE_RESP); + resp = pfcp_entity_peer_init_tx_resp(peer, m, OSMO_PFCP_MSGT_ASSOC_RELEASE_RESP);
resp->ies.assoc_release_resp = (struct osmo_pfcp_msg_assoc_release_resp) { .cause = cause, @@ -307,7 +314,9 @@ { enum osmo_pfcp_cause cause = OSMO_PFCP_CAUSE_REQUEST_ACCEPTED; struct osmo_pfcp_msg *resp; - struct up_session *session = pfcp_entity_peer_find_up_session_by_cp_f_seid(peer, &m->ies.session_est_req.cp_f_seid); + struct up_session *session; + + session = pfcp_entity_peer_find_up_session_by_cp_f_seid(peer, &m->ies.session_est_req.cp_f_seid); if (!session) session = up_session_alloc(peer, &m->ies.session_est_req.cp_f_seid); if (!session) { @@ -324,7 +333,7 @@ return;
nack_response: - resp = pfcp_entity_peer_init_tx(peer, m, OSMO_PFCP_MSGT_SESSION_EST_RESP); + resp = pfcp_entity_peer_init_tx_resp(peer, m, OSMO_PFCP_MSGT_SESSION_EST_RESP); resp->h.seid = m->ies.session_est_req.cp_f_seid.seid; resp->h.seid_present = true; resp->ies.session_est_resp = (struct osmo_pfcp_msg_session_est_resp){ diff --git a/src/osmo-upf/up_endpoint.c b/src/osmo-upf/up_endpoint.c index f53dc50..8161042 100644 --- a/src/osmo-upf/up_endpoint.c +++ b/src/osmo-upf/up_endpoint.c @@ -166,61 +166,137 @@ OSMO_PFCP_CAUSE_SERVICE_NOT_SUPPORTED); }
+/* Validate received F-SEID IP address */ +static enum osmo_pfcp_cause up_ep_validate_cp_f_seid_addr(const struct up_endpoint *up_ep, + const struct osmo_pfcp_ie_f_seid *f_seid) +{ + const struct osmo_sockaddr *local_addr; + + OSMO_ASSERT(up_ep); + OSMO_ASSERT(f_seid) + + /* Validate the F-SEID contains an IP address we can send requests to later on: */ + local_addr = osmo_pfcp_endpoint_get_local_addr(up_ep->pfcp_ep); + OSMO_ASSERT(local_addr); + switch (local_addr->u.sa.sa_family) { + case AF_INET: + if (!f_seid->ip_addr.v4_present) + return OSMO_PFCP_CAUSE_MANDATORY_IE_INCORRECT; + break; + case AF_INET6: + if (!f_seid->ip_addr.v4_present && + !f_seid->ip_addr.v6_present) + return OSMO_PFCP_CAUSE_MANDATORY_IE_INCORRECT; + break; + default: + OSMO_ASSERT(0); + } + return OSMO_PFCP_CAUSE_REQUEST_ACCEPTED; +} + static void up_ep_rx_session_est_req(struct up_endpoint *up_ep, const struct osmo_pfcp_msg *m) { - if (!m->ctx.peer_fi) { - struct osmo_pfcp_msg *tx; - OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Peer is not associated, cannot establish session\n"); - tx = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, m, OSMO_PFCP_MSGT_SESSION_EST_RESP); - tx->ies.session_est_resp.cause = OSMO_PFCP_CAUSE_NO_ESTABLISHED_PFCP_ASSOC; - osmo_pfcp_endpoint_tx(up_ep->pfcp_ep, tx); - return; + struct osmo_pfcp_msg *resp; + enum osmo_pfcp_cause cause; + + cause = up_ep_validate_cp_f_seid_addr(up_ep, &m->ies.session_est_req.cp_f_seid); + if (cause != OSMO_PFCP_CAUSE_REQUEST_ACCEPTED) { + OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Remote CP F-SEID IP address invalid\n"); + goto nack_response; } + + if (!m->ctx.peer_fi) { + OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Peer is not associated, cannot establish session\n"); + cause = OSMO_PFCP_CAUSE_NO_ESTABLISHED_PFCP_ASSOC; + goto nack_response; + } + osmo_fsm_inst_dispatch(m->ctx.peer_fi, PFCP_ENTITY_PEER_EV_RX_SESSION_EST_REQ, (void *)m); + return; + +nack_response: + resp = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, m, OSMO_PFCP_MSGT_SESSION_EST_RESP); + resp->ies.session_est_resp.cause = cause; + osmo_pfcp_endpoint_tx(up_ep->pfcp_ep, resp); }
static void up_ep_rx_session_mod_req(struct up_endpoint *up_ep, const struct osmo_pfcp_msg *m) { + struct osmo_pfcp_msg *resp; + enum osmo_pfcp_cause cause; + + if (m->ies.session_mod_req.cp_f_seid_present) { + cause = up_ep_validate_cp_f_seid_addr(up_ep, &m->ies.session_mod_req.cp_f_seid); + if (cause != OSMO_PFCP_CAUSE_REQUEST_ACCEPTED) { + OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Remote CP F-SEID IP address invalid\n"); + goto nack_response; + } + } + if (!m->ctx.session_fi) { /* Session not found. */ - struct osmo_pfcp_msg *tx; - tx = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, m, OSMO_PFCP_MSGT_SESSION_MOD_RESP); if (!m->ctx.peer_fi) { /* Not even the peer is associated. */ OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Peer is not associated, cannot modify session\n"); - tx->ies.session_mod_resp.cause = OSMO_PFCP_CAUSE_NO_ESTABLISHED_PFCP_ASSOC; + cause = OSMO_PFCP_CAUSE_NO_ESTABLISHED_PFCP_ASSOC; + goto nack_response; } else { OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "No established session with SEID=0x%"PRIx64", cannot modify\n", m->h.seid); - tx->ies.session_mod_resp.cause = OSMO_PFCP_CAUSE_SESSION_CTX_NOT_FOUND; + cause = OSMO_PFCP_CAUSE_SESSION_CTX_NOT_FOUND; + goto nack_response; } - osmo_pfcp_endpoint_tx(up_ep->pfcp_ep, tx); - return; } + osmo_fsm_inst_dispatch(m->ctx.session_fi, UP_SESSION_EV_RX_SESSION_MOD_REQ, (void *)m); + return; + +nack_response: + resp = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, m, OSMO_PFCP_MSGT_SESSION_MOD_RESP); + resp->ies.session_mod_resp.cause = cause; + osmo_pfcp_endpoint_tx(up_ep->pfcp_ep, resp); }
static void up_ep_rx_session_del_req(struct up_endpoint *up_ep, const struct osmo_pfcp_msg *m) { + struct osmo_pfcp_msg *resp; + enum osmo_pfcp_cause cause; + +#if 0 + /* Can be enabled once libosmo-pfcp struct osmo_pfcp_msg_session_del_req supports the IE: */ + if (m->ies.session_del_req.cp_f_seid_present) { + cause = up_ep_validate_cp_f_seid_addr(up_ep, &m->ies.session_mod_req.cp_f_seid); + if (cause != OSMO_PFCP_CAUSE_REQUEST_ACCEPTED) { + OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Remote CP F-SEID IP address invalid\n"); + goto nack_response; + } + } +#endif + if (!m->ctx.session_fi) { /* Session not found. */ - struct osmo_pfcp_msg *tx; - tx = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, m, OSMO_PFCP_MSGT_SESSION_DEL_RESP); if (!m->ctx.peer_fi) { /* Not even the peer is associated. */ OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Peer is not associated, cannot delete session\n"); - tx->ies.session_del_resp.cause = OSMO_PFCP_CAUSE_NO_ESTABLISHED_PFCP_ASSOC; + cause = OSMO_PFCP_CAUSE_NO_ESTABLISHED_PFCP_ASSOC; + goto nack_response; } else { OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "No established session with SEID=0x%"PRIx64", cannot delete\n", m->h.seid); - tx->ies.session_del_resp.cause = OSMO_PFCP_CAUSE_SESSION_CTX_NOT_FOUND; + cause = OSMO_PFCP_CAUSE_SESSION_CTX_NOT_FOUND; + goto nack_response; } - osmo_pfcp_endpoint_tx(up_ep->pfcp_ep, tx); - return; } + osmo_fsm_inst_dispatch(m->ctx.session_fi, UP_SESSION_EV_RX_SESSION_DEL_REQ, (void *)m); + return; + +nack_response: + resp = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, m, OSMO_PFCP_MSGT_SESSION_DEL_RESP); + resp->ies.session_del_resp.cause = cause; + osmo_pfcp_endpoint_tx(up_ep->pfcp_ep, resp); }
static void up_ep_rx_session_rep_req(struct up_endpoint *up_ep, const struct osmo_pfcp_msg *m) diff --git a/src/osmo-upf/up_session.c b/src/osmo-upf/up_session.c index 5f406d5..9693745 100644 --- a/src/osmo-upf/up_session.c +++ b/src/osmo-upf/up_session.c @@ -90,10 +90,43 @@ return 1; }
+/* Return as dst IP address the IP address from remote's CP F-SEID that matches + * our local endpoint configuration. + * Asserts regarding cp_f_seid are validated during session establishment/modification/deletion, + * see pfcp_entityt_peer_validate_cp_f_seid(). */ +static const struct osmo_sockaddr *up_session_req_dst_addr(const struct up_session *session) +{ + const struct osmo_sockaddr *src_addr = osmo_pfcp_endpoint_get_local_addr(session->entity_peer->node_peer->up_endpoint->pfcp_ep); + switch (src_addr->u.sa.sa_family) { + case AF_INET: + OSMO_ASSERT(session->cp_f_seid.ip_addr.v4_present); + return &session->cp_f_seid.ip_addr.v4; + case AF_INET6: + if (session->cp_f_seid.ip_addr.v6_present) + return &session->cp_f_seid.ip_addr.v6; + if (session->cp_f_seid.ip_addr.v4_present) + return &session->cp_f_seid.ip_addr.v4; + OSMO_ASSERT(0); + break; + default: + OSMO_ASSERT(0); + break; + } + return NULL; +} + struct osmo_pfcp_msg *up_session_init_tx(struct up_session *session, struct osmo_pfcp_msg *in_reply_to, enum osmo_pfcp_message_type message_type) { - struct osmo_pfcp_msg *tx = pfcp_entity_peer_init_tx(session->entity_peer, in_reply_to, message_type); + struct osmo_pfcp_msg *tx; + if (in_reply_to) { + /* Use req src IP address as resp dst IP address: */ + tx = pfcp_entity_peer_init_tx_resp(session->entity_peer, in_reply_to, message_type); + } else { + const struct osmo_sockaddr *dst_addr = up_session_req_dst_addr(session); + /* Use IP address from remote's CP F-SEID as dst IP address: */ + tx = pfcp_entity_peer_init_tx_req(session->entity_peer, dst_addr, message_type); + } tx->h.seid = session->cp_f_seid.seid; tx->h.seid_present = true; up_session_set_msg_ctx(session, tx);