| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2015 Nicira, Inc. |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or |
|---|
| 5 | | - * modify it under the terms of version 2 of the GNU General Public |
|---|
| 6 | | - * License as published by the Free Software Foundation. |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is distributed in the hope that it will be useful, but |
|---|
| 9 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 10 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 11 | | - * General Public License for more details. |
|---|
| 12 | 4 | */ |
|---|
| 13 | 5 | |
|---|
| 14 | 6 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 24 | 16 | #include <net/netfilter/nf_conntrack_helper.h> |
|---|
| 25 | 17 | #include <net/netfilter/nf_conntrack_labels.h> |
|---|
| 26 | 18 | #include <net/netfilter/nf_conntrack_seqadj.h> |
|---|
| 19 | +#include <net/netfilter/nf_conntrack_timeout.h> |
|---|
| 27 | 20 | #include <net/netfilter/nf_conntrack_zones.h> |
|---|
| 28 | 21 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> |
|---|
| 29 | 22 | #include <net/ipv6_frag.h> |
|---|
| 30 | 23 | |
|---|
| 31 | | -#ifdef CONFIG_NF_NAT_NEEDED |
|---|
| 32 | | -#include <linux/netfilter/nf_nat.h> |
|---|
| 33 | | -#include <net/netfilter/nf_nat_core.h> |
|---|
| 34 | | -#include <net/netfilter/nf_nat_l3proto.h> |
|---|
| 24 | +#if IS_ENABLED(CONFIG_NF_NAT) |
|---|
| 25 | +#include <net/netfilter/nf_nat.h> |
|---|
| 35 | 26 | #endif |
|---|
| 36 | 27 | |
|---|
| 37 | 28 | #include "datapath.h" |
|---|
| .. | .. |
|---|
| 75 | 66 | u32 eventmask; /* Mask of 1 << IPCT_*. */ |
|---|
| 76 | 67 | struct md_mark mark; |
|---|
| 77 | 68 | struct md_labels labels; |
|---|
| 78 | | -#ifdef CONFIG_NF_NAT_NEEDED |
|---|
| 69 | + char timeout[CTNL_TIMEOUT_NAME_MAX]; |
|---|
| 70 | + struct nf_ct_timeout *nf_ct_timeout; |
|---|
| 71 | +#if IS_ENABLED(CONFIG_NF_NAT) |
|---|
| 79 | 72 | struct nf_nat_range2 range; /* Only present for SRC NAT and DST NAT. */ |
|---|
| 80 | 73 | #endif |
|---|
| 81 | 74 | }; |
|---|
| .. | .. |
|---|
| 157 | 150 | static u32 ovs_ct_get_mark(const struct nf_conn *ct) |
|---|
| 158 | 151 | { |
|---|
| 159 | 152 | #if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) |
|---|
| 160 | | - return ct ? ct->mark : 0; |
|---|
| 153 | + return ct ? READ_ONCE(ct->mark) : 0; |
|---|
| 161 | 154 | #else |
|---|
| 162 | 155 | return 0; |
|---|
| 163 | 156 | #endif |
|---|
| .. | .. |
|---|
| 343 | 336 | #if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) |
|---|
| 344 | 337 | u32 new_mark; |
|---|
| 345 | 338 | |
|---|
| 346 | | - new_mark = ct_mark | (ct->mark & ~(mask)); |
|---|
| 347 | | - if (ct->mark != new_mark) { |
|---|
| 348 | | - ct->mark = new_mark; |
|---|
| 339 | + new_mark = ct_mark | (READ_ONCE(ct->mark) & ~(mask)); |
|---|
| 340 | + if (READ_ONCE(ct->mark) != new_mark) { |
|---|
| 341 | + WRITE_ONCE(ct->mark, new_mark); |
|---|
| 349 | 342 | if (nf_ct_is_confirmed(ct)) |
|---|
| 350 | 343 | nf_conntrack_event_cache(IPCT_MARK, ct); |
|---|
| 351 | 344 | key->ct.mark = new_mark; |
|---|
| .. | .. |
|---|
| 534 | 527 | return -EPFNOSUPPORT; |
|---|
| 535 | 528 | } |
|---|
| 536 | 529 | |
|---|
| 530 | + /* The key extracted from the fragment that completed this datagram |
|---|
| 531 | + * likely didn't have an L4 header, so regenerate it. |
|---|
| 532 | + */ |
|---|
| 533 | + ovs_flow_key_update_l3l4(skb, key); |
|---|
| 534 | + |
|---|
| 537 | 535 | key->ip.frag = OVS_FRAG_TYPE_NONE; |
|---|
| 538 | 536 | skb_clear_hash(skb); |
|---|
| 539 | 537 | skb->ignore_df = 1; |
|---|
| .. | .. |
|---|
| 624 | 622 | if (natted) { |
|---|
| 625 | 623 | struct nf_conntrack_tuple inverse; |
|---|
| 626 | 624 | |
|---|
| 627 | | - if (!nf_ct_invert_tuplepr(&inverse, &tuple)) { |
|---|
| 625 | + if (!nf_ct_invert_tuple(&inverse, &tuple)) { |
|---|
| 628 | 626 | pr_debug("ovs_ct_find_existing: Inversion failed!\n"); |
|---|
| 629 | 627 | return NULL; |
|---|
| 630 | 628 | } |
|---|
| .. | .. |
|---|
| 707 | 705 | if (help && rcu_access_pointer(help->helper) != info->helper) |
|---|
| 708 | 706 | return false; |
|---|
| 709 | 707 | } |
|---|
| 708 | + if (info->nf_ct_timeout) { |
|---|
| 709 | + struct nf_conn_timeout *timeout_ext; |
|---|
| 710 | + |
|---|
| 711 | + timeout_ext = nf_ct_timeout_find(ct); |
|---|
| 712 | + if (!timeout_ext || info->nf_ct_timeout != |
|---|
| 713 | + rcu_dereference(timeout_ext->timeout)) |
|---|
| 714 | + return false; |
|---|
| 715 | + } |
|---|
| 710 | 716 | /* Force conntrack entry direction to the current packet? */ |
|---|
| 711 | 717 | if (info->force && CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) { |
|---|
| 712 | 718 | /* Delete the conntrack entry if confirmed, else just release |
|---|
| .. | .. |
|---|
| 723 | 729 | return ct_executed; |
|---|
| 724 | 730 | } |
|---|
| 725 | 731 | |
|---|
| 726 | | -#ifdef CONFIG_NF_NAT_NEEDED |
|---|
| 727 | | -/* Modelled after nf_nat_ipv[46]_fn(). |
|---|
| 728 | | - * range is only used for new, uninitialized NAT state. |
|---|
| 729 | | - * Returns either NF_ACCEPT or NF_DROP. |
|---|
| 730 | | - */ |
|---|
| 731 | | -static int ovs_ct_nat_execute(struct sk_buff *skb, struct nf_conn *ct, |
|---|
| 732 | | - enum ip_conntrack_info ctinfo, |
|---|
| 733 | | - const struct nf_nat_range2 *range, |
|---|
| 734 | | - enum nf_nat_manip_type maniptype) |
|---|
| 735 | | -{ |
|---|
| 736 | | - int hooknum, nh_off, err = NF_ACCEPT; |
|---|
| 737 | | - |
|---|
| 738 | | - nh_off = skb_network_offset(skb); |
|---|
| 739 | | - skb_pull_rcsum(skb, nh_off); |
|---|
| 740 | | - |
|---|
| 741 | | - /* See HOOK2MANIP(). */ |
|---|
| 742 | | - if (maniptype == NF_NAT_MANIP_SRC) |
|---|
| 743 | | - hooknum = NF_INET_LOCAL_IN; /* Source NAT */ |
|---|
| 744 | | - else |
|---|
| 745 | | - hooknum = NF_INET_LOCAL_OUT; /* Destination NAT */ |
|---|
| 746 | | - |
|---|
| 747 | | - switch (ctinfo) { |
|---|
| 748 | | - case IP_CT_RELATED: |
|---|
| 749 | | - case IP_CT_RELATED_REPLY: |
|---|
| 750 | | - if (IS_ENABLED(CONFIG_NF_NAT_IPV4) && |
|---|
| 751 | | - skb->protocol == htons(ETH_P_IP) && |
|---|
| 752 | | - ip_hdr(skb)->protocol == IPPROTO_ICMP) { |
|---|
| 753 | | - if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo, |
|---|
| 754 | | - hooknum)) |
|---|
| 755 | | - err = NF_DROP; |
|---|
| 756 | | - goto push; |
|---|
| 757 | | - } else if (IS_ENABLED(CONFIG_NF_NAT_IPV6) && |
|---|
| 758 | | - skb->protocol == htons(ETH_P_IPV6)) { |
|---|
| 759 | | - __be16 frag_off; |
|---|
| 760 | | - u8 nexthdr = ipv6_hdr(skb)->nexthdr; |
|---|
| 761 | | - int hdrlen = ipv6_skip_exthdr(skb, |
|---|
| 762 | | - sizeof(struct ipv6hdr), |
|---|
| 763 | | - &nexthdr, &frag_off); |
|---|
| 764 | | - |
|---|
| 765 | | - if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { |
|---|
| 766 | | - if (!nf_nat_icmpv6_reply_translation(skb, ct, |
|---|
| 767 | | - ctinfo, |
|---|
| 768 | | - hooknum, |
|---|
| 769 | | - hdrlen)) |
|---|
| 770 | | - err = NF_DROP; |
|---|
| 771 | | - goto push; |
|---|
| 772 | | - } |
|---|
| 773 | | - } |
|---|
| 774 | | - /* Non-ICMP, fall thru to initialize if needed. */ |
|---|
| 775 | | - /* fall through */ |
|---|
| 776 | | - case IP_CT_NEW: |
|---|
| 777 | | - /* Seen it before? This can happen for loopback, retrans, |
|---|
| 778 | | - * or local packets. |
|---|
| 779 | | - */ |
|---|
| 780 | | - if (!nf_nat_initialized(ct, maniptype)) { |
|---|
| 781 | | - /* Initialize according to the NAT action. */ |
|---|
| 782 | | - err = (range && range->flags & NF_NAT_RANGE_MAP_IPS) |
|---|
| 783 | | - /* Action is set up to establish a new |
|---|
| 784 | | - * mapping. |
|---|
| 785 | | - */ |
|---|
| 786 | | - ? nf_nat_setup_info(ct, range, maniptype) |
|---|
| 787 | | - : nf_nat_alloc_null_binding(ct, hooknum); |
|---|
| 788 | | - if (err != NF_ACCEPT) |
|---|
| 789 | | - goto push; |
|---|
| 790 | | - } |
|---|
| 791 | | - break; |
|---|
| 792 | | - |
|---|
| 793 | | - case IP_CT_ESTABLISHED: |
|---|
| 794 | | - case IP_CT_ESTABLISHED_REPLY: |
|---|
| 795 | | - break; |
|---|
| 796 | | - |
|---|
| 797 | | - default: |
|---|
| 798 | | - err = NF_DROP; |
|---|
| 799 | | - goto push; |
|---|
| 800 | | - } |
|---|
| 801 | | - |
|---|
| 802 | | - err = nf_nat_packet(ct, ctinfo, hooknum, skb); |
|---|
| 803 | | -push: |
|---|
| 804 | | - skb_push(skb, nh_off); |
|---|
| 805 | | - skb_postpush_rcsum(skb, skb->data, nh_off); |
|---|
| 806 | | - |
|---|
| 807 | | - return err; |
|---|
| 808 | | -} |
|---|
| 809 | | - |
|---|
| 732 | +#if IS_ENABLED(CONFIG_NF_NAT) |
|---|
| 810 | 733 | static void ovs_nat_update_key(struct sw_flow_key *key, |
|---|
| 811 | 734 | const struct sk_buff *skb, |
|---|
| 812 | 735 | enum nf_nat_manip_type maniptype) |
|---|
| .. | .. |
|---|
| 858 | 781 | } |
|---|
| 859 | 782 | } |
|---|
| 860 | 783 | |
|---|
| 784 | +/* Modelled after nf_nat_ipv[46]_fn(). |
|---|
| 785 | + * range is only used for new, uninitialized NAT state. |
|---|
| 786 | + * Returns either NF_ACCEPT or NF_DROP. |
|---|
| 787 | + */ |
|---|
| 788 | +static int ovs_ct_nat_execute(struct sk_buff *skb, struct nf_conn *ct, |
|---|
| 789 | + enum ip_conntrack_info ctinfo, |
|---|
| 790 | + const struct nf_nat_range2 *range, |
|---|
| 791 | + enum nf_nat_manip_type maniptype, struct sw_flow_key *key) |
|---|
| 792 | +{ |
|---|
| 793 | + int hooknum, nh_off, err = NF_ACCEPT; |
|---|
| 794 | + |
|---|
| 795 | + nh_off = skb_network_offset(skb); |
|---|
| 796 | + skb_pull_rcsum(skb, nh_off); |
|---|
| 797 | + |
|---|
| 798 | + /* See HOOK2MANIP(). */ |
|---|
| 799 | + if (maniptype == NF_NAT_MANIP_SRC) |
|---|
| 800 | + hooknum = NF_INET_LOCAL_IN; /* Source NAT */ |
|---|
| 801 | + else |
|---|
| 802 | + hooknum = NF_INET_LOCAL_OUT; /* Destination NAT */ |
|---|
| 803 | + |
|---|
| 804 | + switch (ctinfo) { |
|---|
| 805 | + case IP_CT_RELATED: |
|---|
| 806 | + case IP_CT_RELATED_REPLY: |
|---|
| 807 | + if (IS_ENABLED(CONFIG_NF_NAT) && |
|---|
| 808 | + skb->protocol == htons(ETH_P_IP) && |
|---|
| 809 | + ip_hdr(skb)->protocol == IPPROTO_ICMP) { |
|---|
| 810 | + if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo, |
|---|
| 811 | + hooknum)) |
|---|
| 812 | + err = NF_DROP; |
|---|
| 813 | + goto push; |
|---|
| 814 | + } else if (IS_ENABLED(CONFIG_IPV6) && |
|---|
| 815 | + skb->protocol == htons(ETH_P_IPV6)) { |
|---|
| 816 | + __be16 frag_off; |
|---|
| 817 | + u8 nexthdr = ipv6_hdr(skb)->nexthdr; |
|---|
| 818 | + int hdrlen = ipv6_skip_exthdr(skb, |
|---|
| 819 | + sizeof(struct ipv6hdr), |
|---|
| 820 | + &nexthdr, &frag_off); |
|---|
| 821 | + |
|---|
| 822 | + if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { |
|---|
| 823 | + if (!nf_nat_icmpv6_reply_translation(skb, ct, |
|---|
| 824 | + ctinfo, |
|---|
| 825 | + hooknum, |
|---|
| 826 | + hdrlen)) |
|---|
| 827 | + err = NF_DROP; |
|---|
| 828 | + goto push; |
|---|
| 829 | + } |
|---|
| 830 | + } |
|---|
| 831 | + /* Non-ICMP, fall thru to initialize if needed. */ |
|---|
| 832 | + fallthrough; |
|---|
| 833 | + case IP_CT_NEW: |
|---|
| 834 | + /* Seen it before? This can happen for loopback, retrans, |
|---|
| 835 | + * or local packets. |
|---|
| 836 | + */ |
|---|
| 837 | + if (!nf_nat_initialized(ct, maniptype)) { |
|---|
| 838 | + /* Initialize according to the NAT action. */ |
|---|
| 839 | + err = (range && range->flags & NF_NAT_RANGE_MAP_IPS) |
|---|
| 840 | + /* Action is set up to establish a new |
|---|
| 841 | + * mapping. |
|---|
| 842 | + */ |
|---|
| 843 | + ? nf_nat_setup_info(ct, range, maniptype) |
|---|
| 844 | + : nf_nat_alloc_null_binding(ct, hooknum); |
|---|
| 845 | + if (err != NF_ACCEPT) |
|---|
| 846 | + goto push; |
|---|
| 847 | + } |
|---|
| 848 | + break; |
|---|
| 849 | + |
|---|
| 850 | + case IP_CT_ESTABLISHED: |
|---|
| 851 | + case IP_CT_ESTABLISHED_REPLY: |
|---|
| 852 | + break; |
|---|
| 853 | + |
|---|
| 854 | + default: |
|---|
| 855 | + err = NF_DROP; |
|---|
| 856 | + goto push; |
|---|
| 857 | + } |
|---|
| 858 | + |
|---|
| 859 | + err = nf_nat_packet(ct, ctinfo, hooknum, skb); |
|---|
| 860 | +push: |
|---|
| 861 | + skb_push(skb, nh_off); |
|---|
| 862 | + skb_postpush_rcsum(skb, skb->data, nh_off); |
|---|
| 863 | + |
|---|
| 864 | + /* Update the flow key if NAT successful. */ |
|---|
| 865 | + if (err == NF_ACCEPT) |
|---|
| 866 | + ovs_nat_update_key(key, skb, maniptype); |
|---|
| 867 | + |
|---|
| 868 | + return err; |
|---|
| 869 | +} |
|---|
| 870 | + |
|---|
| 861 | 871 | /* Returns NF_DROP if the packet should be dropped, NF_ACCEPT otherwise. */ |
|---|
| 862 | 872 | static int ovs_ct_nat(struct net *net, struct sw_flow_key *key, |
|---|
| 863 | 873 | const struct ovs_conntrack_info *info, |
|---|
| .. | .. |
|---|
| 897 | 907 | } else { |
|---|
| 898 | 908 | return NF_ACCEPT; /* Connection is not NATed. */ |
|---|
| 899 | 909 | } |
|---|
| 900 | | - err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype); |
|---|
| 910 | + err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype, key); |
|---|
| 901 | 911 | |
|---|
| 902 | 912 | if (err == NF_ACCEPT && ct->status & IPS_DST_NAT) { |
|---|
| 903 | 913 | if (ct->status & IPS_SRC_NAT) { |
|---|
| .. | .. |
|---|
| 907 | 917 | maniptype = NF_NAT_MANIP_SRC; |
|---|
| 908 | 918 | |
|---|
| 909 | 919 | err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, |
|---|
| 910 | | - maniptype); |
|---|
| 920 | + maniptype, key); |
|---|
| 911 | 921 | } else if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) { |
|---|
| 912 | 922 | err = ovs_ct_nat_execute(skb, ct, ctinfo, NULL, |
|---|
| 913 | | - NF_NAT_MANIP_SRC); |
|---|
| 923 | + NF_NAT_MANIP_SRC, key); |
|---|
| 914 | 924 | } |
|---|
| 915 | 925 | } |
|---|
| 916 | 926 | |
|---|
| 917 | | - /* Mark NAT done if successful and update the flow key. */ |
|---|
| 918 | | - if (err == NF_ACCEPT) |
|---|
| 919 | | - ovs_nat_update_key(key, skb, maniptype); |
|---|
| 920 | | - |
|---|
| 921 | 927 | return err; |
|---|
| 922 | 928 | } |
|---|
| 923 | | -#else /* !CONFIG_NF_NAT_NEEDED */ |
|---|
| 929 | +#else /* !CONFIG_NF_NAT */ |
|---|
| 924 | 930 | static int ovs_ct_nat(struct net *net, struct sw_flow_key *key, |
|---|
| 925 | 931 | const struct ovs_conntrack_info *info, |
|---|
| 926 | 932 | struct sk_buff *skb, struct nf_conn *ct, |
|---|
| .. | .. |
|---|
| 950 | 956 | struct nf_conn *ct; |
|---|
| 951 | 957 | |
|---|
| 952 | 958 | if (!cached) { |
|---|
| 959 | + struct nf_hook_state state = { |
|---|
| 960 | + .hook = NF_INET_PRE_ROUTING, |
|---|
| 961 | + .pf = info->family, |
|---|
| 962 | + .net = net, |
|---|
| 963 | + }; |
|---|
| 953 | 964 | struct nf_conn *tmpl = info->ct; |
|---|
| 954 | 965 | int err; |
|---|
| 955 | 966 | |
|---|
| .. | .. |
|---|
| 961 | 972 | nf_ct_set(skb, tmpl, IP_CT_NEW); |
|---|
| 962 | 973 | } |
|---|
| 963 | 974 | |
|---|
| 964 | | - err = nf_conntrack_in(net, info->family, |
|---|
| 965 | | - NF_INET_PRE_ROUTING, skb); |
|---|
| 975 | + err = nf_conntrack_in(skb, &state); |
|---|
| 966 | 976 | if (err != NF_ACCEPT) |
|---|
| 967 | 977 | return -ENOENT; |
|---|
| 968 | 978 | |
|---|
| .. | .. |
|---|
| 978 | 988 | |
|---|
| 979 | 989 | ct = nf_ct_get(skb, &ctinfo); |
|---|
| 980 | 990 | if (ct) { |
|---|
| 991 | + bool add_helper = false; |
|---|
| 992 | + |
|---|
| 981 | 993 | /* Packets starting a new connection must be NATted before the |
|---|
| 982 | 994 | * helper, so that the helper knows about the NAT. We enforce |
|---|
| 983 | 995 | * this by delaying both NAT and helper calls for unconfirmed |
|---|
| .. | .. |
|---|
| 995 | 1007 | } |
|---|
| 996 | 1008 | |
|---|
| 997 | 1009 | /* Userspace may decide to perform a ct lookup without a helper |
|---|
| 998 | | - * specified followed by a (recirculate and) commit with one. |
|---|
| 999 | | - * Therefore, for unconfirmed connections which we will commit, |
|---|
| 1000 | | - * we need to attach the helper here. |
|---|
| 1010 | + * specified followed by a (recirculate and) commit with one, |
|---|
| 1011 | + * or attach a helper in a later commit. Therefore, for |
|---|
| 1012 | + * connections which we will commit, we may need to attach |
|---|
| 1013 | + * the helper here. |
|---|
| 1001 | 1014 | */ |
|---|
| 1002 | | - if (!nf_ct_is_confirmed(ct) && info->commit && |
|---|
| 1003 | | - info->helper && !nfct_help(ct)) { |
|---|
| 1015 | + if (info->commit && info->helper && !nfct_help(ct)) { |
|---|
| 1004 | 1016 | int err = __nf_ct_try_assign_helper(ct, info->ct, |
|---|
| 1005 | 1017 | GFP_ATOMIC); |
|---|
| 1006 | 1018 | if (err) |
|---|
| 1007 | 1019 | return err; |
|---|
| 1020 | + add_helper = true; |
|---|
| 1021 | + |
|---|
| 1022 | + /* helper installed, add seqadj if NAT is required */ |
|---|
| 1023 | + if (info->nat && !nfct_seqadj(ct)) { |
|---|
| 1024 | + if (!nfct_seqadj_ext_add(ct)) |
|---|
| 1025 | + return -EINVAL; |
|---|
| 1026 | + } |
|---|
| 1008 | 1027 | } |
|---|
| 1009 | 1028 | |
|---|
| 1010 | 1029 | /* Call the helper only if: |
|---|
| 1011 | | - * - nf_conntrack_in() was executed above ("!cached") for a |
|---|
| 1012 | | - * confirmed connection, or |
|---|
| 1030 | + * - nf_conntrack_in() was executed above ("!cached") or a |
|---|
| 1031 | + * helper was just attached ("add_helper") for a confirmed |
|---|
| 1032 | + * connection, or |
|---|
| 1013 | 1033 | * - When committing an unconfirmed connection. |
|---|
| 1014 | 1034 | */ |
|---|
| 1015 | | - if ((nf_ct_is_confirmed(ct) ? !cached : info->commit) && |
|---|
| 1035 | + if ((nf_ct_is_confirmed(ct) ? !cached || add_helper : |
|---|
| 1036 | + info->commit) && |
|---|
| 1016 | 1037 | ovs_ct_helper(skb, info->family) != NF_ACCEPT) { |
|---|
| 1017 | 1038 | return -EINVAL; |
|---|
| 1018 | 1039 | } |
|---|
| .. | .. |
|---|
| 1179 | 1200 | &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); |
|---|
| 1180 | 1201 | if (err) { |
|---|
| 1181 | 1202 | net_warn_ratelimited("openvswitch: zone: %u " |
|---|
| 1182 | | - "execeeds conntrack limit\n", |
|---|
| 1203 | + "exceeds conntrack limit\n", |
|---|
| 1183 | 1204 | info->zone.id); |
|---|
| 1184 | 1205 | return err; |
|---|
| 1185 | 1206 | } |
|---|
| .. | .. |
|---|
| 1303 | 1324 | if (skb_nfct(skb)) { |
|---|
| 1304 | 1325 | nf_conntrack_put(skb_nfct(skb)); |
|---|
| 1305 | 1326 | nf_ct_set(skb, NULL, IP_CT_UNTRACKED); |
|---|
| 1306 | | - ovs_ct_fill_key(skb, key); |
|---|
| 1327 | + if (key) |
|---|
| 1328 | + ovs_ct_fill_key(skb, key); |
|---|
| 1307 | 1329 | } |
|---|
| 1308 | 1330 | |
|---|
| 1309 | 1331 | return 0; |
|---|
| .. | .. |
|---|
| 1314 | 1336 | { |
|---|
| 1315 | 1337 | struct nf_conntrack_helper *helper; |
|---|
| 1316 | 1338 | struct nf_conn_help *help; |
|---|
| 1339 | + int ret = 0; |
|---|
| 1317 | 1340 | |
|---|
| 1318 | 1341 | helper = nf_conntrack_helper_try_module_get(name, info->family, |
|---|
| 1319 | 1342 | key->ip.proto); |
|---|
| .. | .. |
|---|
| 1328 | 1351 | return -ENOMEM; |
|---|
| 1329 | 1352 | } |
|---|
| 1330 | 1353 | |
|---|
| 1354 | +#if IS_ENABLED(CONFIG_NF_NAT) |
|---|
| 1355 | + if (info->nat) { |
|---|
| 1356 | + ret = nf_nat_helper_try_module_get(name, info->family, |
|---|
| 1357 | + key->ip.proto); |
|---|
| 1358 | + if (ret) { |
|---|
| 1359 | + nf_conntrack_helper_put(helper); |
|---|
| 1360 | + OVS_NLERR(log, "Failed to load \"%s\" NAT helper, error: %d", |
|---|
| 1361 | + name, ret); |
|---|
| 1362 | + return ret; |
|---|
| 1363 | + } |
|---|
| 1364 | + } |
|---|
| 1365 | +#endif |
|---|
| 1331 | 1366 | rcu_assign_pointer(help->helper, helper); |
|---|
| 1332 | 1367 | info->helper = helper; |
|---|
| 1333 | | - |
|---|
| 1334 | | - if (info->nat) |
|---|
| 1335 | | - request_module("ip_nat_%s", name); |
|---|
| 1336 | | - |
|---|
| 1337 | | - return 0; |
|---|
| 1368 | + return ret; |
|---|
| 1338 | 1369 | } |
|---|
| 1339 | 1370 | |
|---|
| 1340 | | -#ifdef CONFIG_NF_NAT_NEEDED |
|---|
| 1371 | +#if IS_ENABLED(CONFIG_NF_NAT) |
|---|
| 1341 | 1372 | static int parse_nat(const struct nlattr *attr, |
|---|
| 1342 | 1373 | struct ovs_conntrack_info *info, bool log) |
|---|
| 1343 | 1374 | { |
|---|
| .. | .. |
|---|
| 1474 | 1505 | .maxlen = sizeof(struct md_labels) }, |
|---|
| 1475 | 1506 | [OVS_CT_ATTR_HELPER] = { .minlen = 1, |
|---|
| 1476 | 1507 | .maxlen = NF_CT_HELPER_NAME_LEN }, |
|---|
| 1477 | | -#ifdef CONFIG_NF_NAT_NEEDED |
|---|
| 1508 | +#if IS_ENABLED(CONFIG_NF_NAT) |
|---|
| 1478 | 1509 | /* NAT length is checked when parsing the nested attributes. */ |
|---|
| 1479 | 1510 | [OVS_CT_ATTR_NAT] = { .minlen = 0, .maxlen = INT_MAX }, |
|---|
| 1480 | 1511 | #endif |
|---|
| 1481 | 1512 | [OVS_CT_ATTR_EVENTMASK] = { .minlen = sizeof(u32), |
|---|
| 1482 | 1513 | .maxlen = sizeof(u32) }, |
|---|
| 1514 | + [OVS_CT_ATTR_TIMEOUT] = { .minlen = 1, |
|---|
| 1515 | + .maxlen = CTNL_TIMEOUT_NAME_MAX }, |
|---|
| 1483 | 1516 | }; |
|---|
| 1484 | 1517 | |
|---|
| 1485 | 1518 | static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, |
|---|
| .. | .. |
|---|
| 1512 | 1545 | switch (type) { |
|---|
| 1513 | 1546 | case OVS_CT_ATTR_FORCE_COMMIT: |
|---|
| 1514 | 1547 | info->force = true; |
|---|
| 1515 | | - /* fall through. */ |
|---|
| 1548 | + fallthrough; |
|---|
| 1516 | 1549 | case OVS_CT_ATTR_COMMIT: |
|---|
| 1517 | 1550 | info->commit = true; |
|---|
| 1518 | 1551 | break; |
|---|
| .. | .. |
|---|
| 1552 | 1585 | return -EINVAL; |
|---|
| 1553 | 1586 | } |
|---|
| 1554 | 1587 | break; |
|---|
| 1555 | | -#ifdef CONFIG_NF_NAT_NEEDED |
|---|
| 1588 | +#if IS_ENABLED(CONFIG_NF_NAT) |
|---|
| 1556 | 1589 | case OVS_CT_ATTR_NAT: { |
|---|
| 1557 | 1590 | int err = parse_nat(a, info, log); |
|---|
| 1558 | 1591 | |
|---|
| .. | .. |
|---|
| 1565 | 1598 | info->have_eventmask = true; |
|---|
| 1566 | 1599 | info->eventmask = nla_get_u32(a); |
|---|
| 1567 | 1600 | break; |
|---|
| 1601 | +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
|---|
| 1602 | + case OVS_CT_ATTR_TIMEOUT: |
|---|
| 1603 | + memcpy(info->timeout, nla_data(a), nla_len(a)); |
|---|
| 1604 | + if (!memchr(info->timeout, '\0', nla_len(a))) { |
|---|
| 1605 | + OVS_NLERR(log, "Invalid conntrack timeout"); |
|---|
| 1606 | + return -EINVAL; |
|---|
| 1607 | + } |
|---|
| 1608 | + break; |
|---|
| 1609 | +#endif |
|---|
| 1568 | 1610 | |
|---|
| 1569 | 1611 | default: |
|---|
| 1570 | 1612 | OVS_NLERR(log, "Unknown conntrack attr (%d)", |
|---|
| .. | .. |
|---|
| 1646 | 1688 | OVS_NLERR(log, "Failed to allocate conntrack template"); |
|---|
| 1647 | 1689 | return -ENOMEM; |
|---|
| 1648 | 1690 | } |
|---|
| 1691 | + |
|---|
| 1692 | + if (ct_info.timeout[0]) { |
|---|
| 1693 | + if (nf_ct_set_timeout(net, ct_info.ct, family, key->ip.proto, |
|---|
| 1694 | + ct_info.timeout)) |
|---|
| 1695 | + pr_info_ratelimited("Failed to associated timeout " |
|---|
| 1696 | + "policy `%s'\n", ct_info.timeout); |
|---|
| 1697 | + else |
|---|
| 1698 | + ct_info.nf_ct_timeout = rcu_dereference( |
|---|
| 1699 | + nf_ct_timeout_find(ct_info.ct)->timeout); |
|---|
| 1700 | + |
|---|
| 1701 | + } |
|---|
| 1702 | + |
|---|
| 1649 | 1703 | if (helper) { |
|---|
| 1650 | 1704 | err = ovs_ct_add_helper(&ct_info, helper, key, log); |
|---|
| 1651 | 1705 | if (err) |
|---|
| .. | .. |
|---|
| 1665 | 1719 | return err; |
|---|
| 1666 | 1720 | } |
|---|
| 1667 | 1721 | |
|---|
| 1668 | | -#ifdef CONFIG_NF_NAT_NEEDED |
|---|
| 1722 | +#if IS_ENABLED(CONFIG_NF_NAT) |
|---|
| 1669 | 1723 | static bool ovs_ct_nat_to_attr(const struct ovs_conntrack_info *info, |
|---|
| 1670 | 1724 | struct sk_buff *skb) |
|---|
| 1671 | 1725 | { |
|---|
| 1672 | 1726 | struct nlattr *start; |
|---|
| 1673 | 1727 | |
|---|
| 1674 | | - start = nla_nest_start(skb, OVS_CT_ATTR_NAT); |
|---|
| 1728 | + start = nla_nest_start_noflag(skb, OVS_CT_ATTR_NAT); |
|---|
| 1675 | 1729 | if (!start) |
|---|
| 1676 | 1730 | return false; |
|---|
| 1677 | 1731 | |
|---|
| .. | .. |
|---|
| 1686 | 1740 | } |
|---|
| 1687 | 1741 | |
|---|
| 1688 | 1742 | if (info->range.flags & NF_NAT_RANGE_MAP_IPS) { |
|---|
| 1689 | | - if (IS_ENABLED(CONFIG_NF_NAT_IPV4) && |
|---|
| 1743 | + if (IS_ENABLED(CONFIG_NF_NAT) && |
|---|
| 1690 | 1744 | info->family == NFPROTO_IPV4) { |
|---|
| 1691 | 1745 | if (nla_put_in_addr(skb, OVS_NAT_ATTR_IP_MIN, |
|---|
| 1692 | 1746 | info->range.min_addr.ip) || |
|---|
| .. | .. |
|---|
| 1695 | 1749 | (nla_put_in_addr(skb, OVS_NAT_ATTR_IP_MAX, |
|---|
| 1696 | 1750 | info->range.max_addr.ip)))) |
|---|
| 1697 | 1751 | return false; |
|---|
| 1698 | | - } else if (IS_ENABLED(CONFIG_NF_NAT_IPV6) && |
|---|
| 1752 | + } else if (IS_ENABLED(CONFIG_IPV6) && |
|---|
| 1699 | 1753 | info->family == NFPROTO_IPV6) { |
|---|
| 1700 | 1754 | if (nla_put_in6_addr(skb, OVS_NAT_ATTR_IP_MIN, |
|---|
| 1701 | 1755 | &info->range.min_addr.in6) || |
|---|
| .. | .. |
|---|
| 1738 | 1792 | { |
|---|
| 1739 | 1793 | struct nlattr *start; |
|---|
| 1740 | 1794 | |
|---|
| 1741 | | - start = nla_nest_start(skb, OVS_ACTION_ATTR_CT); |
|---|
| 1795 | + start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_CT); |
|---|
| 1742 | 1796 | if (!start) |
|---|
| 1743 | 1797 | return -EMSGSIZE; |
|---|
| 1744 | 1798 | |
|---|
| .. | .. |
|---|
| 1766 | 1820 | if (ct_info->have_eventmask && |
|---|
| 1767 | 1821 | nla_put_u32(skb, OVS_CT_ATTR_EVENTMASK, ct_info->eventmask)) |
|---|
| 1768 | 1822 | return -EMSGSIZE; |
|---|
| 1823 | + if (ct_info->timeout[0]) { |
|---|
| 1824 | + if (nla_put_string(skb, OVS_CT_ATTR_TIMEOUT, ct_info->timeout)) |
|---|
| 1825 | + return -EMSGSIZE; |
|---|
| 1826 | + } |
|---|
| 1769 | 1827 | |
|---|
| 1770 | | -#ifdef CONFIG_NF_NAT_NEEDED |
|---|
| 1828 | +#if IS_ENABLED(CONFIG_NF_NAT) |
|---|
| 1771 | 1829 | if (ct_info->nat && !ovs_ct_nat_to_attr(ct_info, skb)) |
|---|
| 1772 | 1830 | return -EMSGSIZE; |
|---|
| 1773 | 1831 | #endif |
|---|
| .. | .. |
|---|
| 1785 | 1843 | |
|---|
| 1786 | 1844 | static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info) |
|---|
| 1787 | 1845 | { |
|---|
| 1788 | | - if (ct_info->helper) |
|---|
| 1846 | + if (ct_info->helper) { |
|---|
| 1847 | +#if IS_ENABLED(CONFIG_NF_NAT) |
|---|
| 1848 | + if (ct_info->nat) |
|---|
| 1849 | + nf_nat_helper_put(ct_info->helper); |
|---|
| 1850 | +#endif |
|---|
| 1789 | 1851 | nf_conntrack_helper_put(ct_info->helper); |
|---|
| 1790 | | - if (ct_info->ct) |
|---|
| 1852 | + } |
|---|
| 1853 | + if (ct_info->ct) { |
|---|
| 1854 | + if (ct_info->timeout[0]) |
|---|
| 1855 | + nf_ct_destroy_timeout(ct_info->ct); |
|---|
| 1791 | 1856 | nf_ct_tmpl_free(ct_info->ct); |
|---|
| 1857 | + } |
|---|
| 1792 | 1858 | } |
|---|
| 1793 | 1859 | |
|---|
| 1794 | 1860 | #if IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT) |
|---|
| .. | .. |
|---|
| 1836 | 1902 | struct hlist_head *head = &info->limits[i]; |
|---|
| 1837 | 1903 | struct ovs_ct_limit *ct_limit; |
|---|
| 1838 | 1904 | |
|---|
| 1839 | | - hlist_for_each_entry_rcu(ct_limit, head, hlist_node) |
|---|
| 1905 | + hlist_for_each_entry_rcu(ct_limit, head, hlist_node, |
|---|
| 1906 | + lockdep_ovsl_is_held()) |
|---|
| 1840 | 1907 | kfree_rcu(ct_limit, rcu); |
|---|
| 1841 | 1908 | } |
|---|
| 1842 | | - kfree(ovs_net->ct_limit_info->limits); |
|---|
| 1843 | | - kfree(ovs_net->ct_limit_info); |
|---|
| 1909 | + kfree(info->limits); |
|---|
| 1910 | + kfree(info); |
|---|
| 1844 | 1911 | } |
|---|
| 1845 | 1912 | |
|---|
| 1846 | 1913 | static struct sk_buff * |
|---|
| .. | .. |
|---|
| 1958 | 2025 | static int ovs_ct_limit_get_default_limit(struct ovs_ct_limit_info *info, |
|---|
| 1959 | 2026 | struct sk_buff *reply) |
|---|
| 1960 | 2027 | { |
|---|
| 1961 | | - struct ovs_zone_limit zone_limit; |
|---|
| 1962 | | - int err; |
|---|
| 2028 | + struct ovs_zone_limit zone_limit = { |
|---|
| 2029 | + .zone_id = OVS_ZONE_LIMIT_DEFAULT_ZONE, |
|---|
| 2030 | + .limit = info->default_limit, |
|---|
| 2031 | + }; |
|---|
| 1963 | 2032 | |
|---|
| 1964 | | - zone_limit.zone_id = OVS_ZONE_LIMIT_DEFAULT_ZONE; |
|---|
| 1965 | | - zone_limit.limit = info->default_limit; |
|---|
| 1966 | | - err = nla_put_nohdr(reply, sizeof(zone_limit), &zone_limit); |
|---|
| 1967 | | - if (err) |
|---|
| 1968 | | - return err; |
|---|
| 1969 | | - |
|---|
| 1970 | | - return 0; |
|---|
| 2033 | + return nla_put_nohdr(reply, sizeof(zone_limit), &zone_limit); |
|---|
| 1971 | 2034 | } |
|---|
| 1972 | 2035 | |
|---|
| 1973 | 2036 | static int __ovs_ct_limit_get_zone_limit(struct net *net, |
|---|
| .. | .. |
|---|
| 2141 | 2204 | if (IS_ERR(reply)) |
|---|
| 2142 | 2205 | return PTR_ERR(reply); |
|---|
| 2143 | 2206 | |
|---|
| 2144 | | - nla_reply = nla_nest_start(reply, OVS_CT_LIMIT_ATTR_ZONE_LIMIT); |
|---|
| 2207 | + nla_reply = nla_nest_start_noflag(reply, OVS_CT_LIMIT_ATTR_ZONE_LIMIT); |
|---|
| 2208 | + if (!nla_reply) { |
|---|
| 2209 | + err = -EMSGSIZE; |
|---|
| 2210 | + goto exit_err; |
|---|
| 2211 | + } |
|---|
| 2145 | 2212 | |
|---|
| 2146 | 2213 | if (a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT]) { |
|---|
| 2147 | 2214 | err = ovs_ct_limit_get_zone_limit( |
|---|
| .. | .. |
|---|
| 2165 | 2232 | return err; |
|---|
| 2166 | 2233 | } |
|---|
| 2167 | 2234 | |
|---|
| 2168 | | -static struct genl_ops ct_limit_genl_ops[] = { |
|---|
| 2235 | +static const struct genl_small_ops ct_limit_genl_ops[] = { |
|---|
| 2169 | 2236 | { .cmd = OVS_CT_LIMIT_CMD_SET, |
|---|
| 2237 | + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, |
|---|
| 2170 | 2238 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN |
|---|
| 2171 | 2239 | * privilege. */ |
|---|
| 2172 | | - .policy = ct_limit_policy, |
|---|
| 2173 | 2240 | .doit = ovs_ct_limit_cmd_set, |
|---|
| 2174 | 2241 | }, |
|---|
| 2175 | 2242 | { .cmd = OVS_CT_LIMIT_CMD_DEL, |
|---|
| 2243 | + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, |
|---|
| 2176 | 2244 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN |
|---|
| 2177 | 2245 | * privilege. */ |
|---|
| 2178 | | - .policy = ct_limit_policy, |
|---|
| 2179 | 2246 | .doit = ovs_ct_limit_cmd_del, |
|---|
| 2180 | 2247 | }, |
|---|
| 2181 | 2248 | { .cmd = OVS_CT_LIMIT_CMD_GET, |
|---|
| 2249 | + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, |
|---|
| 2182 | 2250 | .flags = 0, /* OK for unprivileged users. */ |
|---|
| 2183 | | - .policy = ct_limit_policy, |
|---|
| 2184 | 2251 | .doit = ovs_ct_limit_cmd_get, |
|---|
| 2185 | 2252 | }, |
|---|
| 2186 | 2253 | }; |
|---|
| .. | .. |
|---|
| 2194 | 2261 | .name = OVS_CT_LIMIT_FAMILY, |
|---|
| 2195 | 2262 | .version = OVS_CT_LIMIT_VERSION, |
|---|
| 2196 | 2263 | .maxattr = OVS_CT_LIMIT_ATTR_MAX, |
|---|
| 2264 | + .policy = ct_limit_policy, |
|---|
| 2197 | 2265 | .netnsok = true, |
|---|
| 2198 | 2266 | .parallel_ops = true, |
|---|
| 2199 | | - .ops = ct_limit_genl_ops, |
|---|
| 2200 | | - .n_ops = ARRAY_SIZE(ct_limit_genl_ops), |
|---|
| 2267 | + .small_ops = ct_limit_genl_ops, |
|---|
| 2268 | + .n_small_ops = ARRAY_SIZE(ct_limit_genl_ops), |
|---|
| 2201 | 2269 | .mcgrps = &ovs_ct_limit_multicast_group, |
|---|
| 2202 | 2270 | .n_mcgrps = 1, |
|---|
| 2203 | 2271 | .module = THIS_MODULE, |
|---|