History

tcp: md5: add an address prefix for key lookup

This allows the keys used for TCP MD5 signature to be used for whole range of addresses, specified with a prefix length, instead of only one address as it currently is.

Ivan Delalande committed 9 years ago

Commit 67973181 parent 91060383 files · +70 −16Browse files

Unified · Split

3 files
  1. include/net/tcp.h +4 −2
  2. net/ipv4/tcp_ipv4.c +59 −9
  3. net/ipv6/tcp_ipv6.c +7 −5
include/net/tcp.h+4−2
@@ -1441,6 +1441,7 @@ struct tcp_md5sig_key { · 1440 unmodified lines
14411441 u8 keylen;
14421442 u8 family; /* AF_INET or AF_INET6 */
14431443 union tcp_md5_addr addr;
1444+ u8 prefixlen;
14441445 u8 key[TCP_MD5SIG_MAXKEYLEN];
14451446 struct rcu_head rcu;
14461447 };
@@ -1484,9 +1485,10 @@ struct tcp_md5sig_pool { · 37 unmodified lines
14841485 int tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key,
14851486 const struct sock *sk, const struct sk_buff *skb);
14861487 int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
1487− int family, const u8 *newkey, u8 newkeylen, gfp_t gfp);
1488+ int family, u8 prefixlen, const u8 *newkey, u8 newkeylen,
1489+ gfp_t gfp);
14881490 int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr,
1489− int family);
1491+ int family, u8 prefixlen);
14901492 struct tcp_md5sig_key *tcp_v4_md5_lookup(const struct sock *sk,
14911493 const struct sock *addr_sk);
14921494
net/ipv4/tcp_ipv4.c+59−9
@@ -80,6 +80,7 @@ · 79 unmodified lines
8080 #include <linux/stddef.h>
8181 #include <linux/proc_fs.h>
8282 #include <linux/seq_file.h>
83+#include <linux/inetdevice.h>
8384
8485 #include <crypto/hash.h>
8586 #include <linux/scatterlist.h>
@@ -908,6 +909,9 @@ struct tcp_md5sig_key *tcp_md5_do_lookup(const struct sock *sk, · 822 unmodified lines
908909 struct tcp_md5sig_key *key;
909910 unsigned int size = sizeof(struct in_addr);
910911 const struct tcp_md5sig_info *md5sig;
912+ __be32 mask;
913+ struct tcp_md5sig_key *best_match = NULL;
914+ bool match;
911915
912916 /* caller either holds rcu_read_lock() or socket lock */
913917 md5sig = rcu_dereference_check(tp->md5sig_info,
@@ -921,12 +925,55 @@ struct tcp_md5sig_key *tcp_md5_do_lookup(const struct sock *sk, · 7 unmodified lines
921925 hlist_for_each_entry_rcu(key, &md5sig->head, node) {
922926 if (key->family != family)
923927 continue;
924− if (!memcmp(&key->addr, addr, size))
928+
929+ if (family == AF_INET) {
930+ mask = inet_make_mask(key->prefixlen);
931+ match = (key->addr.a4.s_addr & mask) ==
932+ (addr->a4.s_addr & mask);
933+#if IS_ENABLED(CONFIG_IPV6)
934+ } else if (family == AF_INET6) {
935+ match = ipv6_prefix_equal(&key->addr.a6, &addr->a6,
936+ key->prefixlen);
937+#endif
938+ } else {
939+ match = false;
940+ }
941+
942+ if (match && (!best_match ||
943+ key->prefixlen > best_match->prefixlen))
944+ best_match = key;
945+ }
946+ return best_match;
947+}
948+EXPORT_SYMBOL(tcp_md5_do_lookup);
949+
950+struct tcp_md5sig_key *tcp_md5_do_lookup_exact(const struct sock *sk,
951+ const union tcp_md5_addr *addr,
952+ int family, u8 prefixlen)
953+{
954+ const struct tcp_sock *tp = tcp_sk(sk);
955+ struct tcp_md5sig_key *key;
956+ unsigned int size = sizeof(struct in_addr);
957+ const struct tcp_md5sig_info *md5sig;
958+
959+ /* caller either holds rcu_read_lock() or socket lock */
960+ md5sig = rcu_dereference_check(tp->md5sig_info,
961+ lockdep_sock_is_held(sk));
962+ if (!md5sig)
963+ return NULL;
964+#if IS_ENABLED(CONFIG_IPV6)
965+ if (family == AF_INET6)
966+ size = sizeof(struct in6_addr);
967+#endif
968+ hlist_for_each_entry_rcu(key, &md5sig->head, node) {
969+ if (key->family != family)
970+ continue;
971+ if (!memcmp(&key->addr, addr, size) &&
972+ key->prefixlen == prefixlen)
925973 return key;
926974 }
927975 return NULL;
928976 }
929−EXPORT_SYMBOL(tcp_md5_do_lookup);
930977
931978 struct tcp_md5sig_key *tcp_v4_md5_lookup(const struct sock *sk,
932979 const struct sock *addr_sk)
@@ -940,14 +987,15 @@ EXPORT_SYMBOL(tcp_v4_md5_lookup); · 7 unmodified lines
940987
941988 /* This can be called on a newly created socket, from other files */
942989 int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
943− int family, const u8 *newkey, u8 newkeylen, gfp_t gfp)
990+ int family, u8 prefixlen, const u8 *newkey, u8 newkeylen,
991+ gfp_t gfp)
944992 {
945993 /* Add Key to the list */
946994 struct tcp_md5sig_key *key;
947995 struct tcp_sock *tp = tcp_sk(sk);
948996 struct tcp_md5sig_info *md5sig;
949997
950− key = tcp_md5_do_lookup(sk, addr, family);
998+ key = tcp_md5_do_lookup_exact(sk, addr, family, prefixlen);
951999 if (key) {
9521000 /* Pre-existing entry - just update that one. */
9531001 memcpy(key->key, newkey, newkeylen);
@@ -978,6 +1026,7 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, · 24 unmodified lines
9781026 memcpy(key->key, newkey, newkeylen);
9791027 key->keylen = newkeylen;
9801028 key->family = family;
1029+ key->prefixlen = prefixlen;
9811030 memcpy(&key->addr, addr,
9821031 (family == AF_INET6) ? sizeof(struct in6_addr) :
9831032 sizeof(struct in_addr));
@@ -986,11 +1035,12 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, · 2 unmodified lines
9861035 }
9871036 EXPORT_SYMBOL(tcp_md5_do_add);
9881037
989−int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family)
1038+int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family,
1039+ u8 prefixlen)
9901040 {
9911041 struct tcp_md5sig_key *key;
9921042
993− key = tcp_md5_do_lookup(sk, addr, family);
1043+ key = tcp_md5_do_lookup_exact(sk, addr, family, prefixlen);
9941044 if (!key)
9951045 return -ENOENT;
9961046 hlist_del_rcu(&key->node);
@@ -1033,13 +1083,13 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, · 36 unmodified lines
10331083
10341084 if (!cmd.tcpm_keylen)
10351085 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr,
1036− AF_INET);
1086+ AF_INET, 32);
10371087
10381088 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
10391089 return -EINVAL;
10401090
10411091 return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr,
1042− AF_INET, cmd.tcpm_key, cmd.tcpm_keylen,
1092+ AF_INET, 32, cmd.tcpm_key, cmd.tcpm_keylen,
10431093 GFP_KERNEL);
10441094 }
10451095
@@ -1342,7 +1392,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, · 296 unmodified lines
13421392 * across. Shucks.
13431393 */
13441394 tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newinet->inet_daddr,
1345− AF_INET, key->key, key->keylen, GFP_ATOMIC);
1395+ AF_INET, 32, key->key, key->keylen, GFP_ATOMIC);
13461396 sk_nocaps_add(newsk, NETIF_F_GSO_MASK);
13471397 }
13481398 #endif
net/ipv6/tcp_ipv6.c+7−5
@@ -533,9 +533,9 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, char __user *optval, · 532 unmodified lines
533533 if (!cmd.tcpm_keylen) {
534534 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
535535 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],
536− AF_INET);
536+ AF_INET, 32);
537537 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr,
538− AF_INET6);
538+ AF_INET6, 128);
539539 }
540540
541541 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
@@ -543,10 +543,12 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, char __user *optval, · 1 unmodified line
543543
544544 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
545545 return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],
546− AF_INET, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
546+ AF_INET, 32, cmd.tcpm_key,
547+ cmd.tcpm_keylen, GFP_KERNEL);
547548
548549 return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr,
549− AF_INET6, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
550+ AF_INET6, 128, cmd.tcpm_key, cmd.tcpm_keylen,
551+ GFP_KERNEL);
550552 }
551553
552554 static int tcp_v6_md5_hash_headers(struct tcp_md5sig_pool *hp,
@@ -1186,7 +1188,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff * · 633 unmodified lines
11861188 * across. Shucks.
11871189 */
11881190 tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newsk->sk_v6_daddr,
1189− AF_INET6, key->key, key->keylen,
1191+ AF_INET6, 128, key->key, key->keylen,
11901192 sk_gfp_mask(sk, GFP_ATOMIC));
11911193 }
11921194 #endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t