diff options
author | Harsha Sharma <harshasharmaiitr@gmail.com> | 2018-08-07 11:14:23 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2018-08-07 11:14:23 -0400 |
commit | 7e0b2b57f01d183e1c84114f1f2287737358d748 (patch) | |
tree | fbcb423c2a0ee428ff74bd18cc040eab7b809b07 | |
parent | ad83f2a9ce37a264202f48f4fd8889ee9056b703 (diff) |
netfilter: nft_ct: add ct timeout support
This patch allows to add, list and delete connection tracking timeout
policies via nft objref infrastructure and assigning these timeout
via nft rule.
%./libnftnl/examples/nft-ct-timeout-add ip raw cttime tcp
Ruleset:
table ip raw {
ct timeout cttime {
protocol tcp;
policy = {established: 111, close: 13 }
}
chain output {
type filter hook output priority -300; policy accept;
ct timeout set "cttime"
}
}
%./libnftnl/examples/nft-rule-ct-timeout-add ip raw output cttime
%conntrack -E
[NEW] tcp 6 111 ESTABLISHED src=172.16.19.128 dst=172.16.19.1
sport=22 dport=41360 [UNREPLIED] src=172.16.19.1 dst=172.16.19.128
sport=41360 dport=22
%nft delete rule ip raw output handle <handle>
%./libnftnl/examples/nft-ct-timeout-del ip raw cttime
Joint work with Pablo Neira.
Signed-off-by: Harsha Sharma <harshasharmaiitr@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | include/uapi/linux/netfilter/nf_tables.h | 14 | ||||
-rw-r--r-- | net/netfilter/nft_ct.c | 204 |
2 files changed, 216 insertions, 2 deletions
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index 94657c701f22..e23290ffdc77 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h | |||
@@ -958,6 +958,7 @@ enum nft_socket_keys { | |||
958 | * @NFT_CT_DST_IP: conntrack layer 3 protocol destination (IPv4 address) | 958 | * @NFT_CT_DST_IP: conntrack layer 3 protocol destination (IPv4 address) |
959 | * @NFT_CT_SRC_IP6: conntrack layer 3 protocol source (IPv6 address) | 959 | * @NFT_CT_SRC_IP6: conntrack layer 3 protocol source (IPv6 address) |
960 | * @NFT_CT_DST_IP6: conntrack layer 3 protocol destination (IPv6 address) | 960 | * @NFT_CT_DST_IP6: conntrack layer 3 protocol destination (IPv6 address) |
961 | * @NFT_CT_TIMEOUT: connection tracking timeout policy assigned to conntrack | ||
961 | */ | 962 | */ |
962 | enum nft_ct_keys { | 963 | enum nft_ct_keys { |
963 | NFT_CT_STATE, | 964 | NFT_CT_STATE, |
@@ -983,6 +984,7 @@ enum nft_ct_keys { | |||
983 | NFT_CT_DST_IP, | 984 | NFT_CT_DST_IP, |
984 | NFT_CT_SRC_IP6, | 985 | NFT_CT_SRC_IP6, |
985 | NFT_CT_DST_IP6, | 986 | NFT_CT_DST_IP6, |
987 | NFT_CT_TIMEOUT, | ||
986 | __NFT_CT_MAX | 988 | __NFT_CT_MAX |
987 | }; | 989 | }; |
988 | #define NFT_CT_MAX (__NFT_CT_MAX - 1) | 990 | #define NFT_CT_MAX (__NFT_CT_MAX - 1) |
@@ -1411,6 +1413,15 @@ enum nft_ct_helper_attributes { | |||
1411 | }; | 1413 | }; |
1412 | #define NFTA_CT_HELPER_MAX (__NFTA_CT_HELPER_MAX - 1) | 1414 | #define NFTA_CT_HELPER_MAX (__NFTA_CT_HELPER_MAX - 1) |
1413 | 1415 | ||
1416 | enum nft_ct_timeout_timeout_attributes { | ||
1417 | NFTA_CT_TIMEOUT_UNSPEC, | ||
1418 | NFTA_CT_TIMEOUT_L3PROTO, | ||
1419 | NFTA_CT_TIMEOUT_L4PROTO, | ||
1420 | NFTA_CT_TIMEOUT_DATA, | ||
1421 | __NFTA_CT_TIMEOUT_MAX, | ||
1422 | }; | ||
1423 | #define NFTA_CT_TIMEOUT_MAX (__NFTA_CT_TIMEOUT_MAX - 1) | ||
1424 | |||
1414 | #define NFT_OBJECT_UNSPEC 0 | 1425 | #define NFT_OBJECT_UNSPEC 0 |
1415 | #define NFT_OBJECT_COUNTER 1 | 1426 | #define NFT_OBJECT_COUNTER 1 |
1416 | #define NFT_OBJECT_QUOTA 2 | 1427 | #define NFT_OBJECT_QUOTA 2 |
@@ -1418,7 +1429,8 @@ enum nft_ct_helper_attributes { | |||
1418 | #define NFT_OBJECT_LIMIT 4 | 1429 | #define NFT_OBJECT_LIMIT 4 |
1419 | #define NFT_OBJECT_CONNLIMIT 5 | 1430 | #define NFT_OBJECT_CONNLIMIT 5 |
1420 | #define NFT_OBJECT_TUNNEL 6 | 1431 | #define NFT_OBJECT_TUNNEL 6 |
1421 | #define __NFT_OBJECT_MAX 7 | 1432 | #define NFT_OBJECT_CT_TIMEOUT 7 |
1433 | #define __NFT_OBJECT_MAX 8 | ||
1422 | #define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1) | 1434 | #define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1) |
1423 | 1435 | ||
1424 | /** | 1436 | /** |
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c index 3bc82ee5464d..4788458a0931 100644 --- a/net/netfilter/nft_ct.c +++ b/net/netfilter/nft_ct.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <net/netfilter/nf_conntrack_helper.h> | 22 | #include <net/netfilter/nf_conntrack_helper.h> |
23 | #include <net/netfilter/nf_conntrack_ecache.h> | 23 | #include <net/netfilter/nf_conntrack_ecache.h> |
24 | #include <net/netfilter/nf_conntrack_labels.h> | 24 | #include <net/netfilter/nf_conntrack_labels.h> |
25 | #include <net/netfilter/nf_conntrack_timeout.h> | ||
26 | #include <net/netfilter/nf_conntrack_l4proto.h> | ||
25 | 27 | ||
26 | struct nft_ct { | 28 | struct nft_ct { |
27 | enum nft_ct_keys key:8; | 29 | enum nft_ct_keys key:8; |
@@ -765,6 +767,194 @@ static struct nft_expr_type nft_notrack_type __read_mostly = { | |||
765 | .owner = THIS_MODULE, | 767 | .owner = THIS_MODULE, |
766 | }; | 768 | }; |
767 | 769 | ||
770 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | ||
771 | static int | ||
772 | nft_ct_timeout_parse_policy(void *timeouts, | ||
773 | const struct nf_conntrack_l4proto *l4proto, | ||
774 | struct net *net, const struct nlattr *attr) | ||
775 | { | ||
776 | struct nlattr **tb; | ||
777 | int ret = 0; | ||
778 | |||
779 | if (!l4proto->ctnl_timeout.nlattr_to_obj) | ||
780 | return 0; | ||
781 | |||
782 | tb = kcalloc(l4proto->ctnl_timeout.nlattr_max + 1, sizeof(*tb), | ||
783 | GFP_KERNEL); | ||
784 | |||
785 | if (!tb) | ||
786 | return -ENOMEM; | ||
787 | |||
788 | ret = nla_parse_nested(tb, l4proto->ctnl_timeout.nlattr_max, | ||
789 | attr, l4proto->ctnl_timeout.nla_policy, | ||
790 | NULL); | ||
791 | if (ret < 0) | ||
792 | goto err; | ||
793 | |||
794 | ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net, timeouts); | ||
795 | |||
796 | err: | ||
797 | kfree(tb); | ||
798 | return ret; | ||
799 | } | ||
800 | |||
801 | struct nft_ct_timeout_obj { | ||
802 | struct nf_conn *tmpl; | ||
803 | u8 l4proto; | ||
804 | }; | ||
805 | |||
806 | static void nft_ct_timeout_obj_eval(struct nft_object *obj, | ||
807 | struct nft_regs *regs, | ||
808 | const struct nft_pktinfo *pkt) | ||
809 | { | ||
810 | const struct nft_ct_timeout_obj *priv = nft_obj_data(obj); | ||
811 | struct nf_conn *ct = (struct nf_conn *)skb_nfct(pkt->skb); | ||
812 | struct sk_buff *skb = pkt->skb; | ||
813 | |||
814 | if (ct || | ||
815 | priv->l4proto != pkt->tprot) | ||
816 | return; | ||
817 | |||
818 | nf_ct_set(skb, priv->tmpl, IP_CT_NEW); | ||
819 | } | ||
820 | |||
821 | static int nft_ct_timeout_obj_init(const struct nft_ctx *ctx, | ||
822 | const struct nlattr * const tb[], | ||
823 | struct nft_object *obj) | ||
824 | { | ||
825 | const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt; | ||
826 | struct nft_ct_timeout_obj *priv = nft_obj_data(obj); | ||
827 | const struct nf_conntrack_l4proto *l4proto; | ||
828 | struct nf_conn_timeout *timeout_ext; | ||
829 | struct nf_ct_timeout *timeout; | ||
830 | int l3num = ctx->family; | ||
831 | struct nf_conn *tmpl; | ||
832 | __u8 l4num; | ||
833 | int ret; | ||
834 | |||
835 | if (!tb[NFTA_CT_TIMEOUT_L3PROTO] || | ||
836 | !tb[NFTA_CT_TIMEOUT_L4PROTO] || | ||
837 | !tb[NFTA_CT_TIMEOUT_DATA]) | ||
838 | return -EINVAL; | ||
839 | |||
840 | l3num = ntohs(nla_get_be16(tb[NFTA_CT_TIMEOUT_L3PROTO])); | ||
841 | l4num = nla_get_u8(tb[NFTA_CT_TIMEOUT_L4PROTO]); | ||
842 | priv->l4proto = l4num; | ||
843 | |||
844 | l4proto = nf_ct_l4proto_find_get(l3num, l4num); | ||
845 | |||
846 | if (l4proto->l4proto != l4num) { | ||
847 | ret = -EOPNOTSUPP; | ||
848 | goto err_proto_put; | ||
849 | } | ||
850 | |||
851 | timeout = kzalloc(sizeof(struct nf_ct_timeout) + | ||
852 | l4proto->ctnl_timeout.obj_size, GFP_KERNEL); | ||
853 | if (timeout == NULL) { | ||
854 | ret = -ENOMEM; | ||
855 | goto err_proto_put; | ||
856 | } | ||
857 | |||
858 | ret = nft_ct_timeout_parse_policy(&timeout->data, l4proto, ctx->net, | ||
859 | tb[NFTA_CT_TIMEOUT_DATA]); | ||
860 | if (ret < 0) | ||
861 | goto err_free_timeout; | ||
862 | |||
863 | timeout->l3num = l3num; | ||
864 | timeout->l4proto = l4proto; | ||
865 | tmpl = nf_ct_tmpl_alloc(ctx->net, zone, GFP_ATOMIC); | ||
866 | if (!tmpl) { | ||
867 | ret = -ENOMEM; | ||
868 | goto err_free_timeout; | ||
869 | } | ||
870 | |||
871 | timeout_ext = nf_ct_timeout_ext_add(tmpl, timeout, GFP_ATOMIC); | ||
872 | if (!timeout_ext) { | ||
873 | ret = -ENOMEM; | ||
874 | goto err_free_tmpl; | ||
875 | } | ||
876 | |||
877 | ret = nf_ct_netns_get(ctx->net, ctx->family); | ||
878 | if (ret < 0) | ||
879 | goto err_free_tmpl; | ||
880 | |||
881 | priv->tmpl = tmpl; | ||
882 | |||
883 | return 0; | ||
884 | |||
885 | err_free_tmpl: | ||
886 | nf_ct_tmpl_free(tmpl); | ||
887 | err_free_timeout: | ||
888 | kfree(timeout); | ||
889 | err_proto_put: | ||
890 | nf_ct_l4proto_put(l4proto); | ||
891 | return ret; | ||
892 | } | ||
893 | |||
894 | static void nft_ct_timeout_obj_destroy(const struct nft_ctx *ctx, | ||
895 | struct nft_object *obj) | ||
896 | { | ||
897 | struct nft_ct_timeout_obj *priv = nft_obj_data(obj); | ||
898 | struct nf_conn_timeout *t = nf_ct_timeout_find(priv->tmpl); | ||
899 | struct nf_ct_timeout *timeout; | ||
900 | |||
901 | timeout = rcu_dereference_raw(t->timeout); | ||
902 | nf_ct_untimeout(ctx->net, timeout); | ||
903 | nf_ct_l4proto_put(timeout->l4proto); | ||
904 | nf_ct_netns_put(ctx->net, ctx->family); | ||
905 | nf_ct_tmpl_free(priv->tmpl); | ||
906 | } | ||
907 | |||
908 | static int nft_ct_timeout_obj_dump(struct sk_buff *skb, | ||
909 | struct nft_object *obj, bool reset) | ||
910 | { | ||
911 | const struct nft_ct_timeout_obj *priv = nft_obj_data(obj); | ||
912 | const struct nf_conn_timeout *t = nf_ct_timeout_find(priv->tmpl); | ||
913 | const struct nf_ct_timeout *timeout = rcu_dereference_raw(t->timeout); | ||
914 | struct nlattr *nest_params; | ||
915 | int ret; | ||
916 | |||
917 | if (nla_put_u8(skb, NFTA_CT_TIMEOUT_L4PROTO, timeout->l4proto->l4proto) || | ||
918 | nla_put_be16(skb, NFTA_CT_TIMEOUT_L3PROTO, htons(timeout->l3num))) | ||
919 | return -1; | ||
920 | |||
921 | nest_params = nla_nest_start(skb, NFTA_CT_TIMEOUT_DATA | NLA_F_NESTED); | ||
922 | if (!nest_params) | ||
923 | return -1; | ||
924 | |||
925 | ret = timeout->l4proto->ctnl_timeout.obj_to_nlattr(skb, &timeout->data); | ||
926 | if (ret < 0) | ||
927 | return -1; | ||
928 | nla_nest_end(skb, nest_params); | ||
929 | return 0; | ||
930 | } | ||
931 | |||
932 | static const struct nla_policy nft_ct_timeout_policy[NFTA_CT_TIMEOUT_MAX + 1] = { | ||
933 | [NFTA_CT_TIMEOUT_L3PROTO] = {.type = NLA_U16 }, | ||
934 | [NFTA_CT_TIMEOUT_L4PROTO] = {.type = NLA_U8 }, | ||
935 | [NFTA_CT_TIMEOUT_DATA] = {.type = NLA_NESTED }, | ||
936 | }; | ||
937 | |||
938 | static struct nft_object_type nft_ct_timeout_obj_type; | ||
939 | |||
940 | static const struct nft_object_ops nft_ct_timeout_obj_ops = { | ||
941 | .type = &nft_ct_timeout_obj_type, | ||
942 | .size = sizeof(struct nft_ct_timeout_obj), | ||
943 | .eval = nft_ct_timeout_obj_eval, | ||
944 | .init = nft_ct_timeout_obj_init, | ||
945 | .destroy = nft_ct_timeout_obj_destroy, | ||
946 | .dump = nft_ct_timeout_obj_dump, | ||
947 | }; | ||
948 | |||
949 | static struct nft_object_type nft_ct_timeout_obj_type __read_mostly = { | ||
950 | .type = NFT_OBJECT_CT_TIMEOUT, | ||
951 | .ops = &nft_ct_timeout_obj_ops, | ||
952 | .maxattr = NFTA_CT_TIMEOUT_MAX, | ||
953 | .policy = nft_ct_timeout_policy, | ||
954 | .owner = THIS_MODULE, | ||
955 | }; | ||
956 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | ||
957 | |||
768 | static int nft_ct_helper_obj_init(const struct nft_ctx *ctx, | 958 | static int nft_ct_helper_obj_init(const struct nft_ctx *ctx, |
769 | const struct nlattr * const tb[], | 959 | const struct nlattr * const tb[], |
770 | struct nft_object *obj) | 960 | struct nft_object *obj) |
@@ -949,9 +1139,17 @@ static int __init nft_ct_module_init(void) | |||
949 | err = nft_register_obj(&nft_ct_helper_obj_type); | 1139 | err = nft_register_obj(&nft_ct_helper_obj_type); |
950 | if (err < 0) | 1140 | if (err < 0) |
951 | goto err2; | 1141 | goto err2; |
952 | 1142 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | |
1143 | err = nft_register_obj(&nft_ct_timeout_obj_type); | ||
1144 | if (err < 0) | ||
1145 | goto err3; | ||
1146 | #endif | ||
953 | return 0; | 1147 | return 0; |
954 | 1148 | ||
1149 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | ||
1150 | err3: | ||
1151 | nft_unregister_obj(&nft_ct_helper_obj_type); | ||
1152 | #endif | ||
955 | err2: | 1153 | err2: |
956 | nft_unregister_expr(&nft_notrack_type); | 1154 | nft_unregister_expr(&nft_notrack_type); |
957 | err1: | 1155 | err1: |
@@ -961,6 +1159,9 @@ err1: | |||
961 | 1159 | ||
962 | static void __exit nft_ct_module_exit(void) | 1160 | static void __exit nft_ct_module_exit(void) |
963 | { | 1161 | { |
1162 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | ||
1163 | nft_unregister_obj(&nft_ct_timeout_obj_type); | ||
1164 | #endif | ||
964 | nft_unregister_obj(&nft_ct_helper_obj_type); | 1165 | nft_unregister_obj(&nft_ct_helper_obj_type); |
965 | nft_unregister_expr(&nft_notrack_type); | 1166 | nft_unregister_expr(&nft_notrack_type); |
966 | nft_unregister_expr(&nft_ct_type); | 1167 | nft_unregister_expr(&nft_ct_type); |
@@ -974,3 +1175,4 @@ MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | |||
974 | MODULE_ALIAS_NFT_EXPR("ct"); | 1175 | MODULE_ALIAS_NFT_EXPR("ct"); |
975 | MODULE_ALIAS_NFT_EXPR("notrack"); | 1176 | MODULE_ALIAS_NFT_EXPR("notrack"); |
976 | MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_HELPER); | 1177 | MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_HELPER); |
1178 | MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CT_TIMEOUT); | ||