Commit 6b102db5 authored by David Ahern's avatar David Ahern Committed by David S. Miller

net: Add device index to tcp_md5sig

Add support for userspace to specify a device index to limit the scope
of an entry via the TCP_MD5SIG_EXT setsockopt. The existing __tcpm_pad
is renamed to tcpm_ifindex and the new field is only checked if the new
TCP_MD5SIG_FLAG_IFINDEX is set in tcpm_flags. For now, the device index
must point to an L3 master device (e.g., VRF). The API and error
handling are setup to allow the constraint to be relaxed in the future
to any device index.
Signed-off-by: default avatarDavid Ahern <dsahern@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent dea53bb8
...@@ -317,14 +317,15 @@ enum { ...@@ -317,14 +317,15 @@ enum {
#define TCP_MD5SIG_MAXKEYLEN 80 #define TCP_MD5SIG_MAXKEYLEN 80
/* tcp_md5sig extension flags for TCP_MD5SIG_EXT */ /* tcp_md5sig extension flags for TCP_MD5SIG_EXT */
#define TCP_MD5SIG_FLAG_PREFIX 1 /* address prefix length */ #define TCP_MD5SIG_FLAG_PREFIX 0x1 /* address prefix length */
#define TCP_MD5SIG_FLAG_IFINDEX 0x2 /* ifindex set */
struct tcp_md5sig { struct tcp_md5sig {
struct __kernel_sockaddr_storage tcpm_addr; /* address associated */ struct __kernel_sockaddr_storage tcpm_addr; /* address associated */
__u8 tcpm_flags; /* extension flags */ __u8 tcpm_flags; /* extension flags */
__u8 tcpm_prefixlen; /* address prefix */ __u8 tcpm_prefixlen; /* address prefix */
__u16 tcpm_keylen; /* key length */ __u16 tcpm_keylen; /* key length */
__u32 __tcpm_pad; /* zero */ int tcpm_ifindex; /* device index for scope */
__u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */ __u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */
}; };
......
...@@ -1196,6 +1196,24 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, int optname, ...@@ -1196,6 +1196,24 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, int optname,
return -EINVAL; return -EINVAL;
} }
if (optname == TCP_MD5SIG_EXT &&
cmd.tcpm_flags & TCP_MD5SIG_FLAG_IFINDEX) {
struct net_device *dev;
rcu_read_lock();
dev = dev_get_by_index_rcu(sock_net(sk), cmd.tcpm_ifindex);
if (dev && netif_is_l3_master(dev))
l3index = dev->ifindex;
rcu_read_unlock();
/* ok to reference set/not set outside of rcu;
* right now device MUST be an L3 master
*/
if (!dev || !l3index)
return -EINVAL;
}
addr = (union tcp_md5_addr *)&sin->sin_addr.s_addr; addr = (union tcp_md5_addr *)&sin->sin_addr.s_addr;
if (!cmd.tcpm_keylen) if (!cmd.tcpm_keylen)
......
...@@ -578,10 +578,28 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, int optname, ...@@ -578,10 +578,28 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, int optname,
prefixlen = ipv6_addr_v4mapped(&sin6->sin6_addr) ? 32 : 128; prefixlen = ipv6_addr_v4mapped(&sin6->sin6_addr) ? 32 : 128;
} }
if (optname == TCP_MD5SIG_EXT &&
cmd.tcpm_flags & TCP_MD5SIG_FLAG_IFINDEX) {
struct net_device *dev;
rcu_read_lock();
dev = dev_get_by_index_rcu(sock_net(sk), cmd.tcpm_ifindex);
if (dev && netif_is_l3_master(dev))
l3index = dev->ifindex;
rcu_read_unlock();
/* ok to reference set/not set outside of rcu;
* right now device MUST be an L3 master
*/
if (!dev || !l3index)
return -EINVAL;
}
if (!cmd.tcpm_keylen) { if (!cmd.tcpm_keylen) {
if (ipv6_addr_v4mapped(&sin6->sin6_addr)) if (ipv6_addr_v4mapped(&sin6->sin6_addr))
return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3], return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],
AF_INET, prefixlen, l3index); AF_INET, prefixlen,
l3index);
return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr, return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr,
AF_INET6, prefixlen, l3index); AF_INET6, prefixlen, l3index);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment