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
1441 u8 keylen;1441 u8 keylen;
1442 u8 family; /* AF_INET or AF_INET6 */1442 u8 family; /* AF_INET or AF_INET6 */
1443 union tcp_md5_addr addr;1443 union tcp_md5_addr addr;
1444 u8 prefixlen;
1444 u8 key[TCP_MD5SIG_MAXKEYLEN];1445 u8 key[TCP_MD5SIG_MAXKEYLEN];
1445 struct rcu_head rcu;1446 struct rcu_head rcu;
1446};1447};
@@ -1484,9 +1485,10 @@ struct tcp_md5sig_pool { · 37 unmodified lines
1484int tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key,1485int tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key,
1485 const struct sock *sk, const struct sk_buff *skb);1486 const struct sock *sk, const struct sk_buff *skb);
1486int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,1487int 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);
1488int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr,1490int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr,
1489 int family);1491 int family, u8 prefixlen);
1490struct tcp_md5sig_key *tcp_v4_md5_lookup(const struct sock *sk,1492struct tcp_md5sig_key *tcp_v4_md5_lookup(const struct sock *sk,
1491 const struct sock *addr_sk);1493 const struct sock *addr_sk);
1492 1494
net/ipv4/tcp_ipv4.c+59−9
@@ -80,6 +80,7 @@ · 79 unmodified lines
80#include <linux/stddef.h>80#include <linux/stddef.h>
81#include <linux/proc_fs.h>81#include <linux/proc_fs.h>
82#include <linux/seq_file.h>82#include <linux/seq_file.h>
83#include <linux/inetdevice.h>
83 84
84#include <crypto/hash.h>85#include <crypto/hash.h>
85#include <linux/scatterlist.h>86#include <linux/scatterlist.h>
@@ -908,6 +909,9 @@ struct tcp_md5sig_key *tcp_md5_do_lookup(const struct sock *sk, · 822 unmodified lines
908 struct tcp_md5sig_key *key;909 struct tcp_md5sig_key *key;
909 unsigned int size = sizeof(struct in_addr);910 unsigned int size = sizeof(struct in_addr);
910 const struct tcp_md5sig_info *md5sig;911 const struct tcp_md5sig_info *md5sig;
912 __be32 mask;
913 struct tcp_md5sig_key *best_match = NULL;
914 bool match;
911 915
912 /* caller either holds rcu_read_lock() or socket lock */916 /* caller either holds rcu_read_lock() or socket lock */
913 md5sig = rcu_dereference_check(tp->md5sig_info,917 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
921 hlist_for_each_entry_rcu(key, &md5sig->head, node) {925 hlist_for_each_entry_rcu(key, &md5sig->head, node) {
922 if (key->family != family)926 if (key->family != family)
923 continue;927 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}
948EXPORT_SYMBOL(tcp_md5_do_lookup);
949
950struct 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)
925 return key;973 return key;
926 }974 }
927 return NULL;975 return NULL;
928}976}
929EXPORT_SYMBOL(tcp_md5_do_lookup);
930 977
931struct tcp_md5sig_key *tcp_v4_md5_lookup(const struct sock *sk,978struct tcp_md5sig_key *tcp_v4_md5_lookup(const struct sock *sk,
932 const struct sock *addr_sk)979 const struct sock *addr_sk)
@@ -940,14 +987,15 @@ EXPORT_SYMBOL(tcp_v4_md5_lookup); · 7 unmodified lines
940 987
941/* This can be called on a newly created socket, from other files */988/* This can be called on a newly created socket, from other files */
942int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,989int 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)
944{992{
945 /* Add Key to the list */993 /* Add Key to the list */
946 struct tcp_md5sig_key *key;994 struct tcp_md5sig_key *key;
947 struct tcp_sock *tp = tcp_sk(sk);995 struct tcp_sock *tp = tcp_sk(sk);
948 struct tcp_md5sig_info *md5sig;996 struct tcp_md5sig_info *md5sig;
949 997
950 key = tcp_md5_do_lookup(sk, addr, family);998 key = tcp_md5_do_lookup_exact(sk, addr, family, prefixlen);
951 if (key) {999 if (key) {
952 /* Pre-existing entry - just update that one. */1000 /* Pre-existing entry - just update that one. */
953 memcpy(key->key, newkey, newkeylen);1001 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
978 memcpy(key->key, newkey, newkeylen);1026 memcpy(key->key, newkey, newkeylen);
979 key->keylen = newkeylen;1027 key->keylen = newkeylen;
980 key->family = family;1028 key->family = family;
1029 key->prefixlen = prefixlen;
981 memcpy(&key->addr, addr,1030 memcpy(&key->addr, addr,
982 (family == AF_INET6) ? sizeof(struct in6_addr) :1031 (family == AF_INET6) ? sizeof(struct in6_addr) :
983 sizeof(struct in_addr));1032 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
986}1035}
987EXPORT_SYMBOL(tcp_md5_do_add);1036EXPORT_SYMBOL(tcp_md5_do_add);
988 1037
989int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family)1038int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family,
1039 u8 prefixlen)
990{1040{
991 struct tcp_md5sig_key *key;1041 struct tcp_md5sig_key *key;
992 1042
993 key = tcp_md5_do_lookup(sk, addr, family);1043 key = tcp_md5_do_lookup_exact(sk, addr, family, prefixlen);
994 if (!key)1044 if (!key)
995 return -ENOENT;1045 return -ENOENT;
996 hlist_del_rcu(&key->node);1046 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
1033 1083
1034 if (!cmd.tcpm_keylen)1084 if (!cmd.tcpm_keylen)
1035 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr,1085 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr,
1036 AF_INET);1086 AF_INET, 32);
1037 1087
1038 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)1088 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
1039 return -EINVAL;1089 return -EINVAL;
1040 1090
1041 return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr,1091 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,
1043 GFP_KERNEL);1093 GFP_KERNEL);
1044}1094}
1045 1095
@@ -1342,7 +1392,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, · 296 unmodified lines
1342 * across. Shucks.1392 * across. Shucks.
1343 */1393 */
1344 tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newinet->inet_daddr,1394 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);
1346 sk_nocaps_add(newsk, NETIF_F_GSO_MASK);1396 sk_nocaps_add(newsk, NETIF_F_GSO_MASK);
1347 }1397 }
1348#endif1398#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
533 if (!cmd.tcpm_keylen) {533 if (!cmd.tcpm_keylen) {
534 if (ipv6_addr_v4mapped(&sin6->sin6_addr))534 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
535 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],535 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],
536 AF_INET);536 AF_INET, 32);
537 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr,537 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr,
538 AF_INET6);538 AF_INET6, 128);
539 }539 }
540 540
541 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)541 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
543 543
544 if (ipv6_addr_v4mapped(&sin6->sin6_addr))544 if (ipv6_addr_v4mapped(&sin6->sin6_addr))
545 return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],545 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);
547 548
548 return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr,549 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);
550}552}
551 553
552static int tcp_v6_md5_hash_headers(struct tcp_md5sig_pool *hp,554static 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
1186 * across. Shucks.1188 * across. Shucks.
1187 */1189 */
1188 tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newsk->sk_v6_daddr,1190 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,
1190 sk_gfp_mask(sk, GFP_ATOMIC));1192 sk_gfp_mask(sk, GFP_ATOMIC));
1191 }1193 }
1192#endif1194#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