Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tcp: md5: add TCP_MD5SIG_EXT socket option to set a key address prefix

Replace first padding in the tcp_md5sig structure with a new flag field
and address prefix length so it can be specified when configuring a new
key for TCP MD5 signature. The tcpm_flags field will only be used if the
socket option is TCP_MD5SIG_EXT to avoid breaking existing programs, and
tcpm_prefixlen only when the TCP_MD5SIG_FLAG_PREFIX flag is set.

Signed-off-by: Bob Gilligan <gilligan@arista.com>
Signed-off-by: Eric Mowat <mowat@arista.com>
Signed-off-by: Ivan Delalande <colona@arista.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Ivan Delalande and committed by
David S. Miller
8917a777 6797318e

+41 -15
+1
include/net/tcp.h
··· 1848 1848 const struct sock *sk, 1849 1849 const struct sk_buff *skb); 1850 1850 int (*md5_parse)(struct sock *sk, 1851 + int optname, 1851 1852 char __user *optval, 1852 1853 int optlen); 1853 1854 #endif
+8 -3
include/uapi/linux/tcp.h
··· 117 117 #define TCP_SAVED_SYN 28 /* Get SYN headers recorded for connection */ 118 118 #define TCP_REPAIR_WINDOW 29 /* Get/set window parameters */ 119 119 #define TCP_FASTOPEN_CONNECT 30 /* Attempt FastOpen with connect */ 120 - #define TCP_ULP 31 /* Attach a ULP to a TCP connection */ 120 + #define TCP_ULP 31 /* Attach a ULP to a TCP connection */ 121 + #define TCP_MD5SIG_EXT 32 /* TCP MD5 Signature with extensions */ 121 122 122 123 struct tcp_repair_opt { 123 124 __u32 opt_code; ··· 236 235 /* for TCP_MD5SIG socket option */ 237 236 #define TCP_MD5SIG_MAXKEYLEN 80 238 237 238 + /* tcp_md5sig extension flags for TCP_MD5SIG_EXT */ 239 + #define TCP_MD5SIG_FLAG_PREFIX 1 /* address prefix length */ 240 + 239 241 struct tcp_md5sig { 240 242 struct __kernel_sockaddr_storage tcpm_addr; /* address associated */ 241 - __u16 __tcpm_pad1; /* zero */ 243 + __u8 tcpm_flags; /* extension flags */ 244 + __u8 tcpm_prefixlen; /* address prefix */ 242 245 __u16 tcpm_keylen; /* key length */ 243 - __u32 __tcpm_pad2; /* zero */ 246 + __u32 __tcpm_pad; /* zero */ 244 247 __u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */ 245 248 }; 246 249
+2 -1
net/ipv4/tcp.c
··· 2714 2714 2715 2715 #ifdef CONFIG_TCP_MD5SIG 2716 2716 case TCP_MD5SIG: 2717 + case TCP_MD5SIG_EXT: 2717 2718 /* Read the IP->Key mappings from userspace */ 2718 - err = tp->af_specific->md5_parse(sk, optval, optlen); 2719 + err = tp->af_specific->md5_parse(sk, optname, optval, optlen); 2719 2720 break; 2720 2721 #endif 2721 2722 case TCP_USER_TIMEOUT:
+12 -4
net/ipv4/tcp_ipv4.c
··· 1066 1066 } 1067 1067 } 1068 1068 1069 - static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, 1070 - int optlen) 1069 + static int tcp_v4_parse_md5_keys(struct sock *sk, int optname, 1070 + char __user *optval, int optlen) 1071 1071 { 1072 1072 struct tcp_md5sig cmd; 1073 1073 struct sockaddr_in *sin = (struct sockaddr_in *)&cmd.tcpm_addr; 1074 + u8 prefixlen = 32; 1074 1075 1075 1076 if (optlen < sizeof(cmd)) 1076 1077 return -EINVAL; ··· 1082 1081 if (sin->sin_family != AF_INET) 1083 1082 return -EINVAL; 1084 1083 1084 + if (optname == TCP_MD5SIG_EXT && 1085 + cmd.tcpm_flags & TCP_MD5SIG_FLAG_PREFIX) { 1086 + prefixlen = cmd.tcpm_prefixlen; 1087 + if (prefixlen > 32) 1088 + return -EINVAL; 1089 + } 1090 + 1085 1091 if (!cmd.tcpm_keylen) 1086 1092 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr, 1087 - AF_INET, 32); 1093 + AF_INET, prefixlen); 1088 1094 1089 1095 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) 1090 1096 return -EINVAL; 1091 1097 1092 1098 return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr, 1093 - AF_INET, 32, cmd.tcpm_key, cmd.tcpm_keylen, 1099 + AF_INET, prefixlen, cmd.tcpm_key, cmd.tcpm_keylen, 1094 1100 GFP_KERNEL); 1095 1101 } 1096 1102
+18 -7
net/ipv6/tcp_ipv6.c
··· 515 515 return tcp_v6_md5_do_lookup(sk, &addr_sk->sk_v6_daddr); 516 516 } 517 517 518 - static int tcp_v6_parse_md5_keys(struct sock *sk, char __user *optval, 519 - int optlen) 518 + static int tcp_v6_parse_md5_keys(struct sock *sk, int optname, 519 + char __user *optval, int optlen) 520 520 { 521 521 struct tcp_md5sig cmd; 522 522 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr; 523 + u8 prefixlen; 523 524 524 525 if (optlen < sizeof(cmd)) 525 526 return -EINVAL; ··· 531 530 if (sin6->sin6_family != AF_INET6) 532 531 return -EINVAL; 533 532 533 + if (optname == TCP_MD5SIG_EXT && 534 + cmd.tcpm_flags & TCP_MD5SIG_FLAG_PREFIX) { 535 + prefixlen = cmd.tcpm_prefixlen; 536 + if (prefixlen > 128 || (ipv6_addr_v4mapped(&sin6->sin6_addr) && 537 + prefixlen > 32)) 538 + return -EINVAL; 539 + } else { 540 + prefixlen = ipv6_addr_v4mapped(&sin6->sin6_addr) ? 32 : 128; 541 + } 542 + 534 543 if (!cmd.tcpm_keylen) { 535 544 if (ipv6_addr_v4mapped(&sin6->sin6_addr)) 536 545 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3], 537 - AF_INET, 32); 546 + AF_INET, prefixlen); 538 547 return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr, 539 - AF_INET6, 128); 548 + AF_INET6, prefixlen); 540 549 } 541 550 542 551 if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) ··· 554 543 555 544 if (ipv6_addr_v4mapped(&sin6->sin6_addr)) 556 545 return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3], 557 - AF_INET, 32, cmd.tcpm_key, 546 + AF_INET, prefixlen, cmd.tcpm_key, 558 547 cmd.tcpm_keylen, GFP_KERNEL); 559 548 560 549 return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr, 561 - AF_INET6, 128, cmd.tcpm_key, cmd.tcpm_keylen, 562 - GFP_KERNEL); 550 + AF_INET6, prefixlen, cmd.tcpm_key, 551 + cmd.tcpm_keylen, GFP_KERNEL); 563 552 } 564 553 565 554 static int tcp_v6_md5_hash_headers(struct tcp_md5sig_pool *hp,