diff options
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 312 |
1 files changed, 157 insertions, 155 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index fd54c5f8a255..3a25cf743f8b 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | * a single port at the same time. | 50 | * a single port at the same time. |
| 51 | */ | 51 | */ |
| 52 | 52 | ||
| 53 | #define pr_fmt(fmt) "TCP: " fmt | ||
| 53 | 54 | ||
| 54 | #include <linux/bottom_half.h> | 55 | #include <linux/bottom_half.h> |
| 55 | #include <linux/types.h> | 56 | #include <linux/types.h> |
| @@ -90,16 +91,8 @@ EXPORT_SYMBOL(sysctl_tcp_low_latency); | |||
| 90 | 91 | ||
| 91 | 92 | ||
| 92 | #ifdef CONFIG_TCP_MD5SIG | 93 | #ifdef CONFIG_TCP_MD5SIG |
| 93 | static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, | 94 | static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, |
| 94 | __be32 addr); | ||
| 95 | static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key, | ||
| 96 | __be32 daddr, __be32 saddr, const struct tcphdr *th); | 95 | __be32 daddr, __be32 saddr, const struct tcphdr *th); |
| 97 | #else | ||
| 98 | static inline | ||
| 99 | struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) | ||
| 100 | { | ||
| 101 | return NULL; | ||
| 102 | } | ||
| 103 | #endif | 96 | #endif |
| 104 | 97 | ||
| 105 | struct inet_hashinfo tcp_hashinfo; | 98 | struct inet_hashinfo tcp_hashinfo; |
| @@ -601,6 +594,10 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) | |||
| 601 | struct ip_reply_arg arg; | 594 | struct ip_reply_arg arg; |
| 602 | #ifdef CONFIG_TCP_MD5SIG | 595 | #ifdef CONFIG_TCP_MD5SIG |
| 603 | struct tcp_md5sig_key *key; | 596 | struct tcp_md5sig_key *key; |
| 597 | const __u8 *hash_location = NULL; | ||
| 598 | unsigned char newhash[16]; | ||
| 599 | int genhash; | ||
| 600 | struct sock *sk1 = NULL; | ||
| 604 | #endif | 601 | #endif |
| 605 | struct net *net; | 602 | struct net *net; |
| 606 | 603 | ||
| @@ -631,7 +628,36 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) | |||
| 631 | arg.iov[0].iov_len = sizeof(rep.th); | 628 | arg.iov[0].iov_len = sizeof(rep.th); |
| 632 | 629 | ||
| 633 | #ifdef CONFIG_TCP_MD5SIG | 630 | #ifdef CONFIG_TCP_MD5SIG |
| 634 | key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr) : NULL; | 631 | hash_location = tcp_parse_md5sig_option(th); |
| 632 | if (!sk && hash_location) { | ||
| 633 | /* | ||
| 634 | * active side is lost. Try to find listening socket through | ||
| 635 | * source port, and then find md5 key through listening socket. | ||
| 636 | * we are not loose security here: | ||
| 637 | * Incoming packet is checked with md5 hash with finding key, | ||
| 638 | * no RST generated if md5 hash doesn't match. | ||
| 639 | */ | ||
| 640 | sk1 = __inet_lookup_listener(dev_net(skb_dst(skb)->dev), | ||
| 641 | &tcp_hashinfo, ip_hdr(skb)->daddr, | ||
| 642 | ntohs(th->source), inet_iif(skb)); | ||
| 643 | /* don't send rst if it can't find key */ | ||
| 644 | if (!sk1) | ||
| 645 | return; | ||
| 646 | rcu_read_lock(); | ||
| 647 | key = tcp_md5_do_lookup(sk1, (union tcp_md5_addr *) | ||
| 648 | &ip_hdr(skb)->saddr, AF_INET); | ||
| 649 | if (!key) | ||
| 650 | goto release_sk1; | ||
| 651 | |||
| 652 | genhash = tcp_v4_md5_hash_skb(newhash, key, NULL, NULL, skb); | ||
| 653 | if (genhash || memcmp(hash_location, newhash, 16) != 0) | ||
| 654 | goto release_sk1; | ||
| 655 | } else { | ||
| 656 | key = sk ? tcp_md5_do_lookup(sk, (union tcp_md5_addr *) | ||
| 657 | &ip_hdr(skb)->saddr, | ||
| 658 | AF_INET) : NULL; | ||
| 659 | } | ||
| 660 | |||
| 635 | if (key) { | 661 | if (key) { |
| 636 | rep.opt[0] = htonl((TCPOPT_NOP << 24) | | 662 | rep.opt[0] = htonl((TCPOPT_NOP << 24) | |
| 637 | (TCPOPT_NOP << 16) | | 663 | (TCPOPT_NOP << 16) | |
| @@ -664,6 +690,14 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) | |||
| 664 | 690 | ||
| 665 | TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); | 691 | TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); |
| 666 | TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); | 692 | TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); |
| 693 | |||
| 694 | #ifdef CONFIG_TCP_MD5SIG | ||
| 695 | release_sk1: | ||
| 696 | if (sk1) { | ||
| 697 | rcu_read_unlock(); | ||
| 698 | sock_put(sk1); | ||
| 699 | } | ||
| 700 | #endif | ||
| 667 | } | 701 | } |
| 668 | 702 | ||
| 669 | /* The code following below sending ACKs in SYN-RECV and TIME-WAIT states | 703 | /* The code following below sending ACKs in SYN-RECV and TIME-WAIT states |
| @@ -764,7 +798,8 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, | |||
| 764 | tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, | 798 | tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, |
| 765 | req->ts_recent, | 799 | req->ts_recent, |
| 766 | 0, | 800 | 0, |
| 767 | tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->daddr), | 801 | tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->daddr, |
| 802 | AF_INET), | ||
| 768 | inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0, | 803 | inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0, |
| 769 | ip_hdr(skb)->tos); | 804 | ip_hdr(skb)->tos); |
| 770 | } | 805 | } |
| @@ -842,8 +877,7 @@ int tcp_syn_flood_action(struct sock *sk, | |||
| 842 | lopt = inet_csk(sk)->icsk_accept_queue.listen_opt; | 877 | lopt = inet_csk(sk)->icsk_accept_queue.listen_opt; |
| 843 | if (!lopt->synflood_warned) { | 878 | if (!lopt->synflood_warned) { |
| 844 | lopt->synflood_warned = 1; | 879 | lopt->synflood_warned = 1; |
| 845 | pr_info("%s: Possible SYN flooding on port %d. %s. " | 880 | pr_info("%s: Possible SYN flooding on port %d. %s. Check SNMP counters.\n", |
| 846 | " Check SNMP counters.\n", | ||
| 847 | proto, ntohs(tcp_hdr(skb)->dest), msg); | 881 | proto, ntohs(tcp_hdr(skb)->dest), msg); |
| 848 | } | 882 | } |
| 849 | return want_cookie; | 883 | return want_cookie; |
| @@ -881,153 +915,138 @@ static struct ip_options_rcu *tcp_v4_save_options(struct sock *sk, | |||
| 881 | */ | 915 | */ |
| 882 | 916 | ||
| 883 | /* Find the Key structure for an address. */ | 917 | /* Find the Key structure for an address. */ |
| 884 | static struct tcp_md5sig_key * | 918 | struct tcp_md5sig_key *tcp_md5_do_lookup(struct sock *sk, |
| 885 | tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) | 919 | const union tcp_md5_addr *addr, |
| 920 | int family) | ||
| 886 | { | 921 | { |
| 887 | struct tcp_sock *tp = tcp_sk(sk); | 922 | struct tcp_sock *tp = tcp_sk(sk); |
| 888 | int i; | 923 | struct tcp_md5sig_key *key; |
| 889 | 924 | struct hlist_node *pos; | |
| 890 | if (!tp->md5sig_info || !tp->md5sig_info->entries4) | 925 | unsigned int size = sizeof(struct in_addr); |
| 926 | struct tcp_md5sig_info *md5sig; | ||
| 927 | |||
| 928 | /* caller either holds rcu_read_lock() or socket lock */ | ||
| 929 | md5sig = rcu_dereference_check(tp->md5sig_info, | ||
| 930 | sock_owned_by_user(sk) || | ||
| 931 | lockdep_is_held(&sk->sk_lock.slock)); | ||
| 932 | if (!md5sig) | ||
| 891 | return NULL; | 933 | return NULL; |
| 892 | for (i = 0; i < tp->md5sig_info->entries4; i++) { | 934 | #if IS_ENABLED(CONFIG_IPV6) |
| 893 | if (tp->md5sig_info->keys4[i].addr == addr) | 935 | if (family == AF_INET6) |
| 894 | return &tp->md5sig_info->keys4[i].base; | 936 | size = sizeof(struct in6_addr); |
| 937 | #endif | ||
| 938 | hlist_for_each_entry_rcu(key, pos, &md5sig->head, node) { | ||
| 939 | if (key->family != family) | ||
| 940 | continue; | ||
| 941 | if (!memcmp(&key->addr, addr, size)) | ||
| 942 | return key; | ||
| 895 | } | 943 | } |
| 896 | return NULL; | 944 | return NULL; |
| 897 | } | 945 | } |
| 946 | EXPORT_SYMBOL(tcp_md5_do_lookup); | ||
| 898 | 947 | ||
| 899 | struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, | 948 | struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, |
| 900 | struct sock *addr_sk) | 949 | struct sock *addr_sk) |
| 901 | { | 950 | { |
| 902 | return tcp_v4_md5_do_lookup(sk, inet_sk(addr_sk)->inet_daddr); | 951 | union tcp_md5_addr *addr; |
| 952 | |||
| 953 | addr = (union tcp_md5_addr *)&inet_sk(addr_sk)->inet_daddr; | ||
| 954 | return tcp_md5_do_lookup(sk, addr, AF_INET); | ||
| 903 | } | 955 | } |
| 904 | EXPORT_SYMBOL(tcp_v4_md5_lookup); | 956 | EXPORT_SYMBOL(tcp_v4_md5_lookup); |
| 905 | 957 | ||
| 906 | static struct tcp_md5sig_key *tcp_v4_reqsk_md5_lookup(struct sock *sk, | 958 | static struct tcp_md5sig_key *tcp_v4_reqsk_md5_lookup(struct sock *sk, |
| 907 | struct request_sock *req) | 959 | struct request_sock *req) |
| 908 | { | 960 | { |
| 909 | return tcp_v4_md5_do_lookup(sk, inet_rsk(req)->rmt_addr); | 961 | union tcp_md5_addr *addr; |
| 962 | |||
| 963 | addr = (union tcp_md5_addr *)&inet_rsk(req)->rmt_addr; | ||
| 964 | return tcp_md5_do_lookup(sk, addr, AF_INET); | ||
| 910 | } | 965 | } |
| 911 | 966 | ||
| 912 | /* This can be called on a newly created socket, from other files */ | 967 | /* This can be called on a newly created socket, from other files */ |
| 913 | int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, | 968 | int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, |
| 914 | u8 *newkey, u8 newkeylen) | 969 | int family, const u8 *newkey, u8 newkeylen, gfp_t gfp) |
| 915 | { | 970 | { |
| 916 | /* Add Key to the list */ | 971 | /* Add Key to the list */ |
| 917 | struct tcp_md5sig_key *key; | 972 | struct tcp_md5sig_key *key; |
| 918 | struct tcp_sock *tp = tcp_sk(sk); | 973 | struct tcp_sock *tp = tcp_sk(sk); |
| 919 | struct tcp4_md5sig_key *keys; | 974 | struct tcp_md5sig_info *md5sig; |
| 920 | 975 | ||
| 921 | key = tcp_v4_md5_do_lookup(sk, addr); | 976 | key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&addr, AF_INET); |
| 922 | if (key) { | 977 | if (key) { |
| 923 | /* Pre-existing entry - just update that one. */ | 978 | /* Pre-existing entry - just update that one. */ |
| 924 | kfree(key->key); | 979 | memcpy(key->key, newkey, newkeylen); |
| 925 | key->key = newkey; | ||
| 926 | key->keylen = newkeylen; | 980 | key->keylen = newkeylen; |
| 927 | } else { | 981 | return 0; |
| 928 | struct tcp_md5sig_info *md5sig; | 982 | } |
| 929 | |||
| 930 | if (!tp->md5sig_info) { | ||
| 931 | tp->md5sig_info = kzalloc(sizeof(*tp->md5sig_info), | ||
| 932 | GFP_ATOMIC); | ||
| 933 | if (!tp->md5sig_info) { | ||
| 934 | kfree(newkey); | ||
| 935 | return -ENOMEM; | ||
| 936 | } | ||
| 937 | sk_nocaps_add(sk, NETIF_F_GSO_MASK); | ||
| 938 | } | ||
| 939 | 983 | ||
| 940 | md5sig = tp->md5sig_info; | 984 | md5sig = rcu_dereference_protected(tp->md5sig_info, |
| 941 | if (md5sig->entries4 == 0 && | 985 | sock_owned_by_user(sk)); |
| 942 | tcp_alloc_md5sig_pool(sk) == NULL) { | 986 | if (!md5sig) { |
| 943 | kfree(newkey); | 987 | md5sig = kmalloc(sizeof(*md5sig), gfp); |
| 988 | if (!md5sig) | ||
| 944 | return -ENOMEM; | 989 | return -ENOMEM; |
| 945 | } | ||
| 946 | |||
| 947 | if (md5sig->alloced4 == md5sig->entries4) { | ||
| 948 | keys = kmalloc((sizeof(*keys) * | ||
| 949 | (md5sig->entries4 + 1)), GFP_ATOMIC); | ||
| 950 | if (!keys) { | ||
| 951 | kfree(newkey); | ||
| 952 | if (md5sig->entries4 == 0) | ||
| 953 | tcp_free_md5sig_pool(); | ||
| 954 | return -ENOMEM; | ||
| 955 | } | ||
| 956 | 990 | ||
| 957 | if (md5sig->entries4) | 991 | sk_nocaps_add(sk, NETIF_F_GSO_MASK); |
| 958 | memcpy(keys, md5sig->keys4, | 992 | INIT_HLIST_HEAD(&md5sig->head); |
| 959 | sizeof(*keys) * md5sig->entries4); | 993 | rcu_assign_pointer(tp->md5sig_info, md5sig); |
| 994 | } | ||
| 960 | 995 | ||
| 961 | /* Free old key list, and reference new one */ | 996 | key = sock_kmalloc(sk, sizeof(*key), gfp); |
| 962 | kfree(md5sig->keys4); | 997 | if (!key) |
| 963 | md5sig->keys4 = keys; | 998 | return -ENOMEM; |
| 964 | md5sig->alloced4++; | 999 | if (hlist_empty(&md5sig->head) && !tcp_alloc_md5sig_pool(sk)) { |
| 965 | } | 1000 | sock_kfree_s(sk, key, sizeof(*key)); |
| 966 | md5sig->entries4++; | 1001 | return -ENOMEM; |
| 967 | md5sig->keys4[md5sig->entries4 - 1].addr = addr; | ||
| 968 | md5sig->keys4[md5sig->entries4 - 1].base.key = newkey; | ||
| 969 | md5sig->keys4[md5sig->entries4 - 1].base.keylen = newkeylen; | ||
| 970 | } | 1002 | } |
| 971 | return 0; | ||
| 972 | } | ||
| 973 | EXPORT_SYMBOL(tcp_v4_md5_do_add); | ||
| 974 | 1003 | ||
| 975 | static int tcp_v4_md5_add_func(struct sock *sk, struct sock *addr_sk, | 1004 | memcpy(key->key, newkey, newkeylen); |
| 976 | u8 *newkey, u8 newkeylen) | 1005 | key->keylen = newkeylen; |
| 977 | { | 1006 | key->family = family; |
| 978 | return tcp_v4_md5_do_add(sk, inet_sk(addr_sk)->inet_daddr, | 1007 | memcpy(&key->addr, addr, |
| 979 | newkey, newkeylen); | 1008 | (family == AF_INET6) ? sizeof(struct in6_addr) : |
| 1009 | sizeof(struct in_addr)); | ||
| 1010 | hlist_add_head_rcu(&key->node, &md5sig->head); | ||
| 1011 | return 0; | ||
| 980 | } | 1012 | } |
| 1013 | EXPORT_SYMBOL(tcp_md5_do_add); | ||
| 981 | 1014 | ||
| 982 | int tcp_v4_md5_do_del(struct sock *sk, __be32 addr) | 1015 | int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family) |
| 983 | { | 1016 | { |
| 984 | struct tcp_sock *tp = tcp_sk(sk); | 1017 | struct tcp_sock *tp = tcp_sk(sk); |
| 985 | int i; | 1018 | struct tcp_md5sig_key *key; |
| 986 | 1019 | struct tcp_md5sig_info *md5sig; | |
| 987 | for (i = 0; i < tp->md5sig_info->entries4; i++) { | 1020 | |
| 988 | if (tp->md5sig_info->keys4[i].addr == addr) { | 1021 | key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&addr, AF_INET); |
| 989 | /* Free the key */ | 1022 | if (!key) |
| 990 | kfree(tp->md5sig_info->keys4[i].base.key); | 1023 | return -ENOENT; |
| 991 | tp->md5sig_info->entries4--; | 1024 | hlist_del_rcu(&key->node); |
| 992 | 1025 | atomic_sub(sizeof(*key), &sk->sk_omem_alloc); | |
| 993 | if (tp->md5sig_info->entries4 == 0) { | 1026 | kfree_rcu(key, rcu); |
| 994 | kfree(tp->md5sig_info->keys4); | 1027 | md5sig = rcu_dereference_protected(tp->md5sig_info, |
| 995 | tp->md5sig_info->keys4 = NULL; | 1028 | sock_owned_by_user(sk)); |
| 996 | tp->md5sig_info->alloced4 = 0; | 1029 | if (hlist_empty(&md5sig->head)) |
| 997 | tcp_free_md5sig_pool(); | 1030 | tcp_free_md5sig_pool(); |
| 998 | } else if (tp->md5sig_info->entries4 != i) { | 1031 | return 0; |
| 999 | /* Need to do some manipulation */ | ||
| 1000 | memmove(&tp->md5sig_info->keys4[i], | ||
| 1001 | &tp->md5sig_info->keys4[i+1], | ||
| 1002 | (tp->md5sig_info->entries4 - i) * | ||
| 1003 | sizeof(struct tcp4_md5sig_key)); | ||
| 1004 | } | ||
| 1005 | return 0; | ||
| 1006 | } | ||
| 1007 | } | ||
| 1008 | return -ENOENT; | ||
| 1009 | } | 1032 | } |
| 1010 | EXPORT_SYMBOL(tcp_v4_md5_do_del); | 1033 | EXPORT_SYMBOL(tcp_md5_do_del); |
| 1011 | 1034 | ||
| 1012 | static void tcp_v4_clear_md5_list(struct sock *sk) | 1035 | void tcp_clear_md5_list(struct sock *sk) |
| 1013 | { | 1036 | { |
| 1014 | struct tcp_sock *tp = tcp_sk(sk); | 1037 | struct tcp_sock *tp = tcp_sk(sk); |
| 1038 | struct tcp_md5sig_key *key; | ||
| 1039 | struct hlist_node *pos, *n; | ||
| 1040 | struct tcp_md5sig_info *md5sig; | ||
| 1015 | 1041 | ||
| 1016 | /* Free each key, then the set of key keys, | 1042 | md5sig = rcu_dereference_protected(tp->md5sig_info, 1); |
| 1017 | * the crypto element, and then decrement our | 1043 | |
| 1018 | * hold on the last resort crypto. | 1044 | if (!hlist_empty(&md5sig->head)) |
| 1019 | */ | ||
| 1020 | if (tp->md5sig_info->entries4) { | ||
| 1021 | int i; | ||
| 1022 | for (i = 0; i < tp->md5sig_info->entries4; i++) | ||
| 1023 | kfree(tp->md5sig_info->keys4[i].base.key); | ||
| 1024 | tp->md5sig_info->entries4 = 0; | ||
| 1025 | tcp_free_md5sig_pool(); | 1045 | tcp_free_md5sig_pool(); |
| 1026 | } | 1046 | hlist_for_each_entry_safe(key, pos, n, &md5sig->head, node) { |
| 1027 | if (tp->md5sig_info->keys4) { | 1047 | hlist_del_rcu(&key->node); |
| 1028 | kfree(tp->md5sig_info->keys4); | 1048 | atomic_sub(sizeof(*key), &sk->sk_omem_alloc); |
| 1029 | tp->md5sig_info->keys4 = NULL; | 1049 | kfree_rcu(key, rcu); |
| 1030 | tp->md5sig_info->alloced4 = 0; | ||
| 1031 | } | 1050 | } |
| 1032 | } | 1051 | } |
| 1033 | 1052 | ||
| @@ -1036,7 +1055,6 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, | |||
| 1036 | { | 1055 | { |
| 1037 | struct tcp_md5sig cmd; | 1056 | struct tcp_md5sig cmd; |
| 1038 | struct sockaddr_in *sin = (struct sockaddr_in *)&cmd.tcpm_addr; | 1057 | struct sockaddr_in *sin = (struct sockaddr_in *)&cmd.tcpm_addr; |
| 1039 | u8 *newkey; | ||
| 1040 | 1058 | ||
| 1041 | if (optlen < sizeof(cmd)) | 1059 | if (optlen < sizeof(cmd)) |
| 1042 | return -EINVAL; | 1060 | return -EINVAL; |
| @@ -1047,32 +1065,16 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, | |||
| 1047 | if (sin->sin_family != AF_INET) | 1065 | if (sin->sin_family != AF_INET) |
| 1048 | return -EINVAL; | 1066 | return -EINVAL; |
| 1049 | 1067 | ||
| 1050 | if (!cmd.tcpm_key || !cmd.tcpm_keylen) { | 1068 | if (!cmd.tcpm_key || !cmd.tcpm_keylen) |
| 1051 | if (!tcp_sk(sk)->md5sig_info) | 1069 | return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr, |
| 1052 | return -ENOENT; | 1070 | AF_INET); |
| 1053 | return tcp_v4_md5_do_del(sk, sin->sin_addr.s_addr); | ||
| 1054 | } | ||
| 1055 | 1071 | ||
| 1056 | if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) | 1072 | if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) |
| 1057 | return -EINVAL; | 1073 | return -EINVAL; |
| 1058 | 1074 | ||
| 1059 | if (!tcp_sk(sk)->md5sig_info) { | 1075 | return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr, |
| 1060 | struct tcp_sock *tp = tcp_sk(sk); | 1076 | AF_INET, cmd.tcpm_key, cmd.tcpm_keylen, |
| 1061 | struct tcp_md5sig_info *p; | 1077 | GFP_KERNEL); |
| 1062 | |||
| 1063 | p = kzalloc(sizeof(*p), sk->sk_allocation); | ||
| 1064 | if (!p) | ||
| 1065 | return -EINVAL; | ||
| 1066 | |||
| 1067 | tp->md5sig_info = p; | ||
| 1068 | sk_nocaps_add(sk, NETIF_F_GSO_MASK); | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, sk->sk_allocation); | ||
| 1072 | if (!newkey) | ||
| 1073 | return -ENOMEM; | ||
| 1074 | return tcp_v4_md5_do_add(sk, sin->sin_addr.s_addr, | ||
| 1075 | newkey, cmd.tcpm_keylen); | ||
| 1076 | } | 1078 | } |
| 1077 | 1079 | ||
| 1078 | static int tcp_v4_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, | 1080 | static int tcp_v4_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, |
| @@ -1098,7 +1100,7 @@ static int tcp_v4_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp, | |||
| 1098 | return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp)); | 1100 | return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp)); |
| 1099 | } | 1101 | } |
| 1100 | 1102 | ||
| 1101 | static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key, | 1103 | static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, |
| 1102 | __be32 daddr, __be32 saddr, const struct tcphdr *th) | 1104 | __be32 daddr, __be32 saddr, const struct tcphdr *th) |
| 1103 | { | 1105 | { |
| 1104 | struct tcp_md5sig_pool *hp; | 1106 | struct tcp_md5sig_pool *hp; |
| @@ -1198,7 +1200,8 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb) | |||
| 1198 | int genhash; | 1200 | int genhash; |
| 1199 | unsigned char newhash[16]; | 1201 | unsigned char newhash[16]; |
| 1200 | 1202 | ||
| 1201 | hash_expected = tcp_v4_md5_do_lookup(sk, iph->saddr); | 1203 | hash_expected = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&iph->saddr, |
| 1204 | AF_INET); | ||
| 1202 | hash_location = tcp_parse_md5sig_option(th); | 1205 | hash_location = tcp_parse_md5sig_option(th); |
| 1203 | 1206 | ||
| 1204 | /* We've parsed the options - do we have a hash? */ | 1207 | /* We've parsed the options - do we have a hash? */ |
| @@ -1224,10 +1227,10 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, const struct sk_buff *skb) | |||
| 1224 | 1227 | ||
| 1225 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { | 1228 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { |
| 1226 | if (net_ratelimit()) { | 1229 | if (net_ratelimit()) { |
| 1227 | printk(KERN_INFO "MD5 Hash failed for (%pI4, %d)->(%pI4, %d)%s\n", | 1230 | pr_info("MD5 Hash failed for (%pI4, %d)->(%pI4, %d)%s\n", |
| 1228 | &iph->saddr, ntohs(th->source), | 1231 | &iph->saddr, ntohs(th->source), |
| 1229 | &iph->daddr, ntohs(th->dest), | 1232 | &iph->daddr, ntohs(th->dest), |
| 1230 | genhash ? " tcp_v4_calc_md5_hash failed" : ""); | 1233 | genhash ? " tcp_v4_calc_md5_hash failed" : ""); |
| 1231 | } | 1234 | } |
| 1232 | return 1; | 1235 | return 1; |
| 1233 | } | 1236 | } |
| @@ -1396,7 +1399,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 1396 | * to destinations, already remembered | 1399 | * to destinations, already remembered |
| 1397 | * to the moment of synflood. | 1400 | * to the moment of synflood. |
| 1398 | */ | 1401 | */ |
| 1399 | LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI4/%u\n", | 1402 | LIMIT_NETDEBUG(KERN_DEBUG pr_fmt("drop open request from %pI4/%u\n"), |
| 1400 | &saddr, ntohs(tcp_hdr(skb)->source)); | 1403 | &saddr, ntohs(tcp_hdr(skb)->source)); |
| 1401 | goto drop_and_release; | 1404 | goto drop_and_release; |
| 1402 | } | 1405 | } |
| @@ -1461,6 +1464,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1461 | ireq->opt = NULL; | 1464 | ireq->opt = NULL; |
| 1462 | newinet->mc_index = inet_iif(skb); | 1465 | newinet->mc_index = inet_iif(skb); |
| 1463 | newinet->mc_ttl = ip_hdr(skb)->ttl; | 1466 | newinet->mc_ttl = ip_hdr(skb)->ttl; |
| 1467 | newinet->rcv_tos = ip_hdr(skb)->tos; | ||
| 1464 | inet_csk(newsk)->icsk_ext_hdr_len = 0; | 1468 | inet_csk(newsk)->icsk_ext_hdr_len = 0; |
| 1465 | if (inet_opt) | 1469 | if (inet_opt) |
| 1466 | inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen; | 1470 | inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen; |
| @@ -1490,7 +1494,8 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1490 | 1494 | ||
| 1491 | #ifdef CONFIG_TCP_MD5SIG | 1495 | #ifdef CONFIG_TCP_MD5SIG |
| 1492 | /* Copy over the MD5 key from the original socket */ | 1496 | /* Copy over the MD5 key from the original socket */ |
| 1493 | key = tcp_v4_md5_do_lookup(sk, newinet->inet_daddr); | 1497 | key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&newinet->inet_daddr, |
| 1498 | AF_INET); | ||
| 1494 | if (key != NULL) { | 1499 | if (key != NULL) { |
| 1495 | /* | 1500 | /* |
| 1496 | * We're using one, so create a matching key | 1501 | * We're using one, so create a matching key |
| @@ -1498,10 +1503,8 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1498 | * memory, then we end up not copying the key | 1503 | * memory, then we end up not copying the key |
| 1499 | * across. Shucks. | 1504 | * across. Shucks. |
| 1500 | */ | 1505 | */ |
| 1501 | char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC); | 1506 | tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newinet->inet_daddr, |
| 1502 | if (newkey != NULL) | 1507 | AF_INET, key->key, key->keylen, GFP_ATOMIC); |
| 1503 | tcp_v4_md5_do_add(newsk, newinet->inet_daddr, | ||
| 1504 | newkey, key->keylen); | ||
| 1505 | sk_nocaps_add(newsk, NETIF_F_GSO_MASK); | 1508 | sk_nocaps_add(newsk, NETIF_F_GSO_MASK); |
| 1506 | } | 1509 | } |
| 1507 | #endif | 1510 | #endif |
| @@ -1862,7 +1865,6 @@ EXPORT_SYMBOL(ipv4_specific); | |||
| 1862 | static const struct tcp_sock_af_ops tcp_sock_ipv4_specific = { | 1865 | static const struct tcp_sock_af_ops tcp_sock_ipv4_specific = { |
| 1863 | .md5_lookup = tcp_v4_md5_lookup, | 1866 | .md5_lookup = tcp_v4_md5_lookup, |
| 1864 | .calc_md5_hash = tcp_v4_md5_hash_skb, | 1867 | .calc_md5_hash = tcp_v4_md5_hash_skb, |
| 1865 | .md5_add = tcp_v4_md5_add_func, | ||
| 1866 | .md5_parse = tcp_v4_parse_md5_keys, | 1868 | .md5_parse = tcp_v4_parse_md5_keys, |
| 1867 | }; | 1869 | }; |
| 1868 | #endif | 1870 | #endif |
| @@ -1951,8 +1953,8 @@ void tcp_v4_destroy_sock(struct sock *sk) | |||
| 1951 | #ifdef CONFIG_TCP_MD5SIG | 1953 | #ifdef CONFIG_TCP_MD5SIG |
| 1952 | /* Clean up the MD5 key list, if any */ | 1954 | /* Clean up the MD5 key list, if any */ |
| 1953 | if (tp->md5sig_info) { | 1955 | if (tp->md5sig_info) { |
| 1954 | tcp_v4_clear_md5_list(sk); | 1956 | tcp_clear_md5_list(sk); |
| 1955 | kfree(tp->md5sig_info); | 1957 | kfree_rcu(tp->md5sig_info, rcu); |
| 1956 | tp->md5sig_info = NULL; | 1958 | tp->md5sig_info = NULL; |
| 1957 | } | 1959 | } |
| 1958 | #endif | 1960 | #endif |
