Merge branch 'mptcp-userspace-pm-create-sockets-for-the-right-family'
Matthieu Baerts says: ==================== mptcp: userspace pm: create sockets for the right family Before these patches, the Userspace Path Manager would allow the creation of subflows with wrong families: taking the one of the MPTCP socket instead of the provided ones and resulting in the creation of subflows with likely not the right source and/or destination IPs. It would also allow the creation of subflows between different families or not respecting v4/v6-only socket attributes. Patch 1 lets the userspace PM select the proper family to avoid creating subflows with the wrong source and/or destination addresses because the family is not the expected one. Patch 2 makes sure the userspace PM doesn't allow the userspace to create subflows for a family that is not allowed. Patch 3 validates scenarios with a mix of v4 and v6 subflows for the same MPTCP connection. These patches fix issues introduced in v5.19 when the userspace path manager has been introduced. ==================== Link: https://lore.kernel.org/r/20230112-upstream-net-20230112-netlink-v4-v6-v1-0-6a8363a221d2@tessares.net Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
da263fcb86
@ -420,6 +420,31 @@ void mptcp_pm_subflow_chk_stale(const struct mptcp_sock *msk, struct sock *ssk)
|
||||
}
|
||||
}
|
||||
|
||||
/* if sk is ipv4 or ipv6_only allows only same-family local and remote addresses,
|
||||
* otherwise allow any matching local/remote pair
|
||||
*/
|
||||
bool mptcp_pm_addr_families_match(const struct sock *sk,
|
||||
const struct mptcp_addr_info *loc,
|
||||
const struct mptcp_addr_info *rem)
|
||||
{
|
||||
bool mptcp_is_v4 = sk->sk_family == AF_INET;
|
||||
|
||||
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
||||
bool loc_is_v4 = loc->family == AF_INET || ipv6_addr_v4mapped(&loc->addr6);
|
||||
bool rem_is_v4 = rem->family == AF_INET || ipv6_addr_v4mapped(&rem->addr6);
|
||||
|
||||
if (mptcp_is_v4)
|
||||
return loc_is_v4 && rem_is_v4;
|
||||
|
||||
if (ipv6_only_sock(sk))
|
||||
return !loc_is_v4 && !rem_is_v4;
|
||||
|
||||
return loc_is_v4 == rem_is_v4;
|
||||
#else
|
||||
return mptcp_is_v4 && loc->family == AF_INET && rem->family == AF_INET;
|
||||
#endif
|
||||
}
|
||||
|
||||
void mptcp_pm_data_reset(struct mptcp_sock *msk)
|
||||
{
|
||||
u8 pm_type = mptcp_get_pm_type(sock_net((struct sock *)msk));
|
||||
|
@ -294,6 +294,13 @@ int mptcp_nl_cmd_sf_create(struct sk_buff *skb, struct genl_info *info)
|
||||
}
|
||||
|
||||
sk = (struct sock *)msk;
|
||||
|
||||
if (!mptcp_pm_addr_families_match(sk, &addr_l, &addr_r)) {
|
||||
GENL_SET_ERR_MSG(info, "families mismatch");
|
||||
err = -EINVAL;
|
||||
goto create_err;
|
||||
}
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
err = __mptcp_subflow_connect(sk, &addr_l, &addr_r);
|
||||
|
@ -98,7 +98,7 @@ static int __mptcp_socket_create(struct mptcp_sock *msk)
|
||||
struct socket *ssock;
|
||||
int err;
|
||||
|
||||
err = mptcp_subflow_create_socket(sk, &ssock);
|
||||
err = mptcp_subflow_create_socket(sk, sk->sk_family, &ssock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -641,7 +641,8 @@ bool mptcp_addresses_equal(const struct mptcp_addr_info *a,
|
||||
/* called with sk socket lock held */
|
||||
int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
|
||||
const struct mptcp_addr_info *remote);
|
||||
int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock);
|
||||
int mptcp_subflow_create_socket(struct sock *sk, unsigned short family,
|
||||
struct socket **new_sock);
|
||||
void mptcp_info2sockaddr(const struct mptcp_addr_info *info,
|
||||
struct sockaddr_storage *addr,
|
||||
unsigned short family);
|
||||
@ -776,6 +777,9 @@ int mptcp_pm_parse_addr(struct nlattr *attr, struct genl_info *info,
|
||||
int mptcp_pm_parse_entry(struct nlattr *attr, struct genl_info *info,
|
||||
bool require_family,
|
||||
struct mptcp_pm_addr_entry *entry);
|
||||
bool mptcp_pm_addr_families_match(const struct sock *sk,
|
||||
const struct mptcp_addr_info *loc,
|
||||
const struct mptcp_addr_info *rem);
|
||||
void mptcp_pm_subflow_chk_stale(const struct mptcp_sock *msk, struct sock *ssk);
|
||||
void mptcp_pm_nl_subflow_chk_stale(const struct mptcp_sock *msk, struct sock *ssk);
|
||||
void mptcp_pm_new_connection(struct mptcp_sock *msk, const struct sock *ssk, int server_side);
|
||||
|
@ -1547,7 +1547,7 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
|
||||
if (!mptcp_is_fully_established(sk))
|
||||
goto err_out;
|
||||
|
||||
err = mptcp_subflow_create_socket(sk, &sf);
|
||||
err = mptcp_subflow_create_socket(sk, loc->family, &sf);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
@ -1660,7 +1660,9 @@ static void mptcp_subflow_ops_undo_override(struct sock *ssk)
|
||||
#endif
|
||||
ssk->sk_prot = &tcp_prot;
|
||||
}
|
||||
int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock)
|
||||
|
||||
int mptcp_subflow_create_socket(struct sock *sk, unsigned short family,
|
||||
struct socket **new_sock)
|
||||
{
|
||||
struct mptcp_subflow_context *subflow;
|
||||
struct net *net = sock_net(sk);
|
||||
@ -1673,8 +1675,7 @@ int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock)
|
||||
if (unlikely(!sk->sk_socket))
|
||||
return -EINVAL;
|
||||
|
||||
err = sock_create_kern(net, sk->sk_family, SOCK_STREAM, IPPROTO_TCP,
|
||||
&sf);
|
||||
err = sock_create_kern(net, family, SOCK_STREAM, IPPROTO_TCP, &sf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -752,6 +752,52 @@ test_subflows()
|
||||
"$server4_token" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
test_subflows_v4_v6_mix()
|
||||
{
|
||||
# Attempt to add a listener at 10.0.2.1:<subflow-port>
|
||||
ip netns exec "$ns1" ./pm_nl_ctl listen 10.0.2.1\
|
||||
$app6_port > /dev/null 2>&1 &
|
||||
local listener_pid=$!
|
||||
|
||||
# ADD_ADDR4 from server to client machine reusing the subflow port on
|
||||
# the established v6 connection
|
||||
:>"$client_evts"
|
||||
ip netns exec "$ns1" ./pm_nl_ctl ann 10.0.2.1 token "$server6_token" id\
|
||||
$server_addr_id dev ns1eth2 > /dev/null 2>&1
|
||||
stdbuf -o0 -e0 printf "ADD_ADDR4 id:%d 10.0.2.1 (ns1) => ns2, reuse port\t\t" $server_addr_id
|
||||
sleep 0.5
|
||||
verify_announce_event "$client_evts" "$ANNOUNCED" "$client6_token" "10.0.2.1"\
|
||||
"$server_addr_id" "$app6_port"
|
||||
|
||||
# CREATE_SUBFLOW from client to server machine
|
||||
:>"$client_evts"
|
||||
ip netns exec "$ns2" ./pm_nl_ctl csf lip 10.0.2.2 lid 23 rip 10.0.2.1 rport\
|
||||
$app6_port token "$client6_token" > /dev/null 2>&1
|
||||
sleep 0.5
|
||||
verify_subflow_events "$client_evts" "$SUB_ESTABLISHED" "$client6_token"\
|
||||
"$AF_INET" "10.0.2.2" "10.0.2.1" "$app6_port" "23"\
|
||||
"$server_addr_id" "ns2" "ns1"
|
||||
|
||||
# Delete the listener from the server ns, if one was created
|
||||
kill_wait $listener_pid
|
||||
|
||||
sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts")
|
||||
|
||||
# DESTROY_SUBFLOW from client to server machine
|
||||
:>"$client_evts"
|
||||
ip netns exec "$ns2" ./pm_nl_ctl dsf lip 10.0.2.2 lport "$sport" rip 10.0.2.1 rport\
|
||||
$app6_port token "$client6_token" > /dev/null 2>&1
|
||||
sleep 0.5
|
||||
verify_subflow_events "$client_evts" "$SUB_CLOSED" "$client6_token" \
|
||||
"$AF_INET" "10.0.2.2" "10.0.2.1" "$app6_port" "23"\
|
||||
"$server_addr_id" "ns2" "ns1"
|
||||
|
||||
# RM_ADDR from server to client machine
|
||||
ip netns exec "$ns1" ./pm_nl_ctl rem id $server_addr_id token\
|
||||
"$server6_token" > /dev/null 2>&1
|
||||
sleep 0.5
|
||||
}
|
||||
|
||||
test_prio()
|
||||
{
|
||||
local count
|
||||
@ -861,6 +907,7 @@ make_connection "v6"
|
||||
test_announce
|
||||
test_remove
|
||||
test_subflows
|
||||
test_subflows_v4_v6_mix
|
||||
test_prio
|
||||
test_listener
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user