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

netfilter: ctnetlink: add kernel side filtering for dump

Conntrack dump does not support kernel side filtering (only get exists,
but it returns only one entry. And user has to give a full valid tuple)

It means that userspace has to implement filtering after receiving many
irrelevant entries, consuming resources (conntrack table is sometimes
very huge, much more than a routing table for example).

This patch adds filtering in kernel side. To achieve this goal, we:

* Add a new CTA_FILTER netlink attributes, actually a flag list to
parametize filtering
* Convert some *nlattr_to_tuple() functions, to allow a partial parsing
of CTA_TUPLE_ORIG and CTA_TUPLE_REPLY (so nf_conntrack_tuple it not
fully set)

Filtering is now possible on:
* IP SRC/DST values
* Ports for TCP and UDP flows
* IMCP(v6) codes types and IDs

Filtering is done as an "AND" operator. For example, when flags
PROTO_SRC_PORT, PROTO_NUM and IP_SRC are sets, only entries matching all
values are dumped.

Changes since v1:
Set NLM_F_DUMP_FILTERED in nlm flags if entries are filtered

Changes since v2:
Move several constants to nf_internals.h
Move a fix on netlink values check in a separate patch
Add a check on not-supported flags
Return EOPNOTSUPP if CDA_FILTER is set in ctnetlink_flush_conntrack
(not yet implemented)
Code style issues

Changes since v3:
Fix compilation warning reported by kbuild test robot

Changes since v4:
Fix a regression introduced in v3 (returned EINVAL for valid netlink
messages without CTA_MARK)

Changes since v5:
Change definition of CTA_FILTER_F_ALL
Fix a regression when CTA_TUPLE_ZONE is not set

Signed-off-by: Romain Bellan <romain.bellan@wifirst.fr>
Signed-off-by: Florent Fourcot <florent.fourcot@wifirst.fr>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Romain Bellan and committed by
Pablo Neira Ayuso
cb8aa9a3 626a8323

+390 -69
+4 -2
include/net/netfilter/nf_conntrack_l4proto.h
··· 42 42 /* Calculate tuple nlattr size */ 43 43 unsigned int (*nlattr_tuple_size)(void); 44 44 int (*nlattr_to_tuple)(struct nlattr *tb[], 45 - struct nf_conntrack_tuple *t); 45 + struct nf_conntrack_tuple *t, 46 + u_int32_t flags); 46 47 const struct nla_policy *nla_policy; 47 48 48 49 struct { ··· 153 152 int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb, 154 153 const struct nf_conntrack_tuple *tuple); 155 154 int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[], 156 - struct nf_conntrack_tuple *t); 155 + struct nf_conntrack_tuple *t, 156 + u_int32_t flags); 157 157 unsigned int nf_ct_port_nlattr_tuple_size(void); 158 158 extern const struct nla_policy nf_ct_port_nla_policy[]; 159 159
+14 -5
net/netfilter/nf_conntrack_core.c
··· 1974 1974 EXPORT_SYMBOL_GPL(nf_ct_port_nla_policy); 1975 1975 1976 1976 int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[], 1977 - struct nf_conntrack_tuple *t) 1977 + struct nf_conntrack_tuple *t, 1978 + u_int32_t flags) 1978 1979 { 1979 - if (!tb[CTA_PROTO_SRC_PORT] || !tb[CTA_PROTO_DST_PORT]) 1980 - return -EINVAL; 1980 + if (flags & CTA_FILTER_FLAG(CTA_PROTO_SRC_PORT)) { 1981 + if (!tb[CTA_PROTO_SRC_PORT]) 1982 + return -EINVAL; 1981 1983 1982 - t->src.u.tcp.port = nla_get_be16(tb[CTA_PROTO_SRC_PORT]); 1983 - t->dst.u.tcp.port = nla_get_be16(tb[CTA_PROTO_DST_PORT]); 1984 + t->src.u.tcp.port = nla_get_be16(tb[CTA_PROTO_SRC_PORT]); 1985 + } 1986 + 1987 + if (flags & CTA_FILTER_FLAG(CTA_PROTO_DST_PORT)) { 1988 + if (!tb[CTA_PROTO_DST_PORT]) 1989 + return -EINVAL; 1990 + 1991 + t->dst.u.tcp.port = nla_get_be16(tb[CTA_PROTO_DST_PORT]); 1992 + } 1984 1993 1985 1994 return 0; 1986 1995 }
+295 -39
net/netfilter/nf_conntrack_netlink.c
··· 54 54 #include <linux/netfilter/nfnetlink.h> 55 55 #include <linux/netfilter/nfnetlink_conntrack.h> 56 56 57 + #include "nf_internals.h" 58 + 57 59 MODULE_LICENSE("GPL"); 58 60 59 61 static int ctnetlink_dump_tuples_proto(struct sk_buff *skb, ··· 546 544 547 545 static int 548 546 ctnetlink_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, 549 - struct nf_conn *ct, bool extinfo) 547 + struct nf_conn *ct, bool extinfo, unsigned int flags) 550 548 { 551 549 const struct nf_conntrack_zone *zone; 552 550 struct nlmsghdr *nlh; 553 551 struct nfgenmsg *nfmsg; 554 552 struct nlattr *nest_parms; 555 - unsigned int flags = portid ? NLM_F_MULTI : 0, event; 553 + unsigned int event; 556 554 555 + if (portid) 556 + flags |= NLM_F_MULTI; 557 557 event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_NEW); 558 558 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags); 559 559 if (nlh == NULL) ··· 851 847 } 852 848 853 849 struct ctnetlink_filter { 850 + u_int32_t cta_flags; 854 851 u8 family; 852 + 853 + u_int32_t orig_flags; 854 + u_int32_t reply_flags; 855 + 856 + struct nf_conntrack_tuple orig; 857 + struct nf_conntrack_tuple reply; 858 + struct nf_conntrack_zone zone; 859 + 855 860 struct { 856 861 u_int32_t val; 857 862 u_int32_t mask; 858 863 } mark; 859 864 }; 860 865 866 + static const struct nla_policy cta_filter_nla_policy[CTA_FILTER_MAX + 1] = { 867 + [CTA_FILTER_ORIG_FLAGS] = { .type = NLA_U32 }, 868 + [CTA_FILTER_REPLY_FLAGS] = { .type = NLA_U32 }, 869 + }; 870 + 871 + static int ctnetlink_parse_filter(const struct nlattr *attr, 872 + struct ctnetlink_filter *filter) 873 + { 874 + struct nlattr *tb[CTA_FILTER_MAX + 1]; 875 + int ret = 0; 876 + 877 + ret = nla_parse_nested(tb, CTA_FILTER_MAX, attr, cta_filter_nla_policy, 878 + NULL); 879 + if (ret) 880 + return ret; 881 + 882 + if (tb[CTA_FILTER_ORIG_FLAGS]) { 883 + filter->orig_flags = nla_get_u32(tb[CTA_FILTER_ORIG_FLAGS]); 884 + if (filter->orig_flags & ~CTA_FILTER_F_ALL) 885 + return -EOPNOTSUPP; 886 + } 887 + 888 + if (tb[CTA_FILTER_REPLY_FLAGS]) { 889 + filter->reply_flags = nla_get_u32(tb[CTA_FILTER_REPLY_FLAGS]); 890 + if (filter->reply_flags & ~CTA_FILTER_F_ALL) 891 + return -EOPNOTSUPP; 892 + } 893 + 894 + return 0; 895 + } 896 + 897 + static int ctnetlink_parse_zone(const struct nlattr *attr, 898 + struct nf_conntrack_zone *zone); 899 + static int ctnetlink_parse_tuple_filter(const struct nlattr * const cda[], 900 + struct nf_conntrack_tuple *tuple, 901 + u32 type, u_int8_t l3num, 902 + struct nf_conntrack_zone *zone, 903 + u_int32_t flags); 904 + 905 + /* applied on filters */ 906 + #define CTA_FILTER_F_CTA_MARK (1 << 0) 907 + #define CTA_FILTER_F_CTA_MARK_MASK (1 << 1) 908 + 861 909 static struct ctnetlink_filter * 862 910 ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family) 863 911 { 864 912 struct ctnetlink_filter *filter; 913 + int err; 865 914 866 915 #ifndef CONFIG_NF_CONNTRACK_MARK 867 916 if (cda[CTA_MARK] || cda[CTA_MARK_MASK]) ··· 928 871 filter->family = family; 929 872 930 873 #ifdef CONFIG_NF_CONNTRACK_MARK 931 - if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) { 874 + if (cda[CTA_MARK]) { 932 875 filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK])); 933 - filter->mark.mask = ntohl(nla_get_be32(cda[CTA_MARK_MASK])); 876 + filter->cta_flags |= CTA_FILTER_FLAG(CTA_MARK); 877 + 878 + if (cda[CTA_MARK_MASK]) { 879 + filter->mark.mask = ntohl(nla_get_be32(cda[CTA_MARK_MASK])); 880 + filter->cta_flags |= CTA_FILTER_FLAG(CTA_MARK_MASK); 881 + } else { 882 + filter->mark.mask = 0xffffffff; 883 + } 884 + } else if (cda[CTA_MARK_MASK]) { 885 + return ERR_PTR(-EINVAL); 934 886 } 935 887 #endif 888 + if (!cda[CTA_FILTER]) 889 + return filter; 890 + 891 + err = ctnetlink_parse_zone(cda[CTA_ZONE], &filter->zone); 892 + if (err < 0) 893 + return ERR_PTR(err); 894 + 895 + err = ctnetlink_parse_filter(cda[CTA_FILTER], filter); 896 + if (err < 0) 897 + return ERR_PTR(err); 898 + 899 + if (filter->orig_flags) { 900 + if (!cda[CTA_TUPLE_ORIG]) 901 + return ERR_PTR(-EINVAL); 902 + 903 + err = ctnetlink_parse_tuple_filter(cda, &filter->orig, 904 + CTA_TUPLE_ORIG, 905 + filter->family, 906 + &filter->zone, 907 + filter->orig_flags); 908 + if (err < 0) 909 + return ERR_PTR(err); 910 + } 911 + 912 + if (filter->reply_flags) { 913 + if (!cda[CTA_TUPLE_REPLY]) 914 + return ERR_PTR(-EINVAL); 915 + 916 + err = ctnetlink_parse_tuple_filter(cda, &filter->reply, 917 + CTA_TUPLE_REPLY, 918 + filter->family, 919 + &filter->zone, 920 + filter->orig_flags); 921 + if (err < 0) 922 + return ERR_PTR(err); 923 + } 924 + 936 925 return filter; 926 + } 927 + 928 + static bool ctnetlink_needs_filter(u8 family, const struct nlattr * const *cda) 929 + { 930 + return family || cda[CTA_MARK] || cda[CTA_FILTER]; 937 931 } 938 932 939 933 static int ctnetlink_start(struct netlink_callback *cb) ··· 994 886 struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); 995 887 u8 family = nfmsg->nfgen_family; 996 888 997 - if (family || (cda[CTA_MARK] && cda[CTA_MARK_MASK])) { 889 + if (ctnetlink_needs_filter(family, cda)) { 998 890 filter = ctnetlink_alloc_filter(cda, family); 999 891 if (IS_ERR(filter)) 1000 892 return PTR_ERR(filter); ··· 1004 896 return 0; 1005 897 } 1006 898 899 + static int ctnetlink_filter_match_tuple(struct nf_conntrack_tuple *filter_tuple, 900 + struct nf_conntrack_tuple *ct_tuple, 901 + u_int32_t flags, int family) 902 + { 903 + switch (family) { 904 + case NFPROTO_IPV4: 905 + if ((flags & CTA_FILTER_FLAG(CTA_IP_SRC)) && 906 + filter_tuple->src.u3.ip != ct_tuple->src.u3.ip) 907 + return 0; 908 + 909 + if ((flags & CTA_FILTER_FLAG(CTA_IP_DST)) && 910 + filter_tuple->dst.u3.ip != ct_tuple->dst.u3.ip) 911 + return 0; 912 + break; 913 + case NFPROTO_IPV6: 914 + if ((flags & CTA_FILTER_FLAG(CTA_IP_SRC)) && 915 + !ipv6_addr_cmp(&filter_tuple->src.u3.in6, 916 + &ct_tuple->src.u3.in6)) 917 + return 0; 918 + 919 + if ((flags & CTA_FILTER_FLAG(CTA_IP_DST)) && 920 + !ipv6_addr_cmp(&filter_tuple->dst.u3.in6, 921 + &ct_tuple->dst.u3.in6)) 922 + return 0; 923 + break; 924 + } 925 + 926 + if ((flags & CTA_FILTER_FLAG(CTA_PROTO_NUM)) && 927 + filter_tuple->dst.protonum != ct_tuple->dst.protonum) 928 + return 0; 929 + 930 + switch (ct_tuple->dst.protonum) { 931 + case IPPROTO_TCP: 932 + case IPPROTO_UDP: 933 + if ((flags & CTA_FILTER_FLAG(CTA_PROTO_SRC_PORT)) && 934 + filter_tuple->src.u.tcp.port != ct_tuple->src.u.tcp.port) 935 + return 0; 936 + 937 + if ((flags & CTA_FILTER_FLAG(CTA_PROTO_DST_PORT)) && 938 + filter_tuple->dst.u.tcp.port != ct_tuple->dst.u.tcp.port) 939 + return 0; 940 + break; 941 + case IPPROTO_ICMP: 942 + if ((flags & CTA_FILTER_FLAG(CTA_PROTO_ICMP_TYPE)) && 943 + filter_tuple->dst.u.icmp.type != ct_tuple->dst.u.icmp.type) 944 + return 0; 945 + if ((flags & CTA_FILTER_FLAG(CTA_PROTO_ICMP_CODE)) && 946 + filter_tuple->dst.u.icmp.code != ct_tuple->dst.u.icmp.code) 947 + return 0; 948 + if ((flags & CTA_FILTER_FLAG(CTA_PROTO_ICMP_ID)) && 949 + filter_tuple->src.u.icmp.id != ct_tuple->src.u.icmp.id) 950 + return 0; 951 + break; 952 + case IPPROTO_ICMPV6: 953 + if ((flags & CTA_FILTER_FLAG(CTA_PROTO_ICMPV6_TYPE)) && 954 + filter_tuple->dst.u.icmp.type != ct_tuple->dst.u.icmp.type) 955 + return 0; 956 + if ((flags & CTA_FILTER_FLAG(CTA_PROTO_ICMPV6_CODE)) && 957 + filter_tuple->dst.u.icmp.code != ct_tuple->dst.u.icmp.code) 958 + return 0; 959 + if ((flags & CTA_FILTER_FLAG(CTA_PROTO_ICMPV6_ID)) && 960 + filter_tuple->src.u.icmp.id != ct_tuple->src.u.icmp.id) 961 + return 0; 962 + break; 963 + } 964 + 965 + return 1; 966 + } 967 + 1007 968 static int ctnetlink_filter_match(struct nf_conn *ct, void *data) 1008 969 { 1009 970 struct ctnetlink_filter *filter = data; 971 + struct nf_conntrack_tuple *tuple; 1010 972 1011 973 if (filter == NULL) 1012 974 goto out; ··· 1088 910 if (filter->family && nf_ct_l3num(ct) != filter->family) 1089 911 goto ignore_entry; 1090 912 913 + if (filter->orig_flags) { 914 + tuple = nf_ct_tuple(ct, IP_CT_DIR_ORIGINAL); 915 + if (!ctnetlink_filter_match_tuple(&filter->orig, tuple, 916 + filter->orig_flags, 917 + filter->family)) 918 + goto ignore_entry; 919 + } 920 + 921 + if (filter->reply_flags) { 922 + tuple = nf_ct_tuple(ct, IP_CT_DIR_REPLY); 923 + if (!ctnetlink_filter_match_tuple(&filter->reply, tuple, 924 + filter->reply_flags, 925 + filter->family)) 926 + goto ignore_entry; 927 + } 928 + 1091 929 #ifdef CONFIG_NF_CONNTRACK_MARK 1092 - if ((ct->mark & filter->mark.mask) != filter->mark.val) 930 + if ((filter->cta_flags & CTA_FILTER_FLAG(CTA_MARK_MASK)) && 931 + (ct->mark & filter->mark.mask) != filter->mark.val) 932 + goto ignore_entry; 933 + else if ((filter->cta_flags & CTA_FILTER_FLAG(CTA_MARK)) && 934 + ct->mark != filter->mark.val) 1093 935 goto ignore_entry; 1094 936 #endif 1095 937 ··· 1123 925 static int 1124 926 ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) 1125 927 { 928 + unsigned int flags = cb->data ? NLM_F_DUMP_FILTERED : 0; 1126 929 struct net *net = sock_net(skb->sk); 1127 930 struct nf_conn *ct, *last; 1128 931 struct nf_conntrack_tuple_hash *h; ··· 1178 979 ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).portid, 1179 980 cb->nlh->nlmsg_seq, 1180 981 NFNL_MSG_TYPE(cb->nlh->nlmsg_type), 1181 - ct, true); 982 + ct, true, flags); 1182 983 if (res < 0) { 1183 984 nf_conntrack_get(&ct->ct_general); 1184 985 cb->args[1] = (unsigned long)ct; ··· 1213 1014 } 1214 1015 1215 1016 static int ipv4_nlattr_to_tuple(struct nlattr *tb[], 1216 - struct nf_conntrack_tuple *t) 1017 + struct nf_conntrack_tuple *t, 1018 + u_int32_t flags) 1217 1019 { 1218 - if (!tb[CTA_IP_V4_SRC] || !tb[CTA_IP_V4_DST]) 1219 - return -EINVAL; 1020 + if (flags & CTA_FILTER_FLAG(CTA_IP_SRC)) { 1021 + if (!tb[CTA_IP_V4_SRC]) 1022 + return -EINVAL; 1220 1023 1221 - t->src.u3.ip = nla_get_in_addr(tb[CTA_IP_V4_SRC]); 1222 - t->dst.u3.ip = nla_get_in_addr(tb[CTA_IP_V4_DST]); 1024 + t->src.u3.ip = nla_get_in_addr(tb[CTA_IP_V4_SRC]); 1025 + } 1026 + 1027 + if (flags & CTA_FILTER_FLAG(CTA_IP_DST)) { 1028 + if (!tb[CTA_IP_V4_DST]) 1029 + return -EINVAL; 1030 + 1031 + t->dst.u3.ip = nla_get_in_addr(tb[CTA_IP_V4_DST]); 1032 + } 1223 1033 1224 1034 return 0; 1225 1035 } 1226 1036 1227 1037 static int ipv6_nlattr_to_tuple(struct nlattr *tb[], 1228 - struct nf_conntrack_tuple *t) 1038 + struct nf_conntrack_tuple *t, 1039 + u_int32_t flags) 1229 1040 { 1230 - if (!tb[CTA_IP_V6_SRC] || !tb[CTA_IP_V6_DST]) 1231 - return -EINVAL; 1041 + if (flags & CTA_FILTER_FLAG(CTA_IP_SRC)) { 1042 + if (!tb[CTA_IP_V6_SRC]) 1043 + return -EINVAL; 1232 1044 1233 - t->src.u3.in6 = nla_get_in6_addr(tb[CTA_IP_V6_SRC]); 1234 - t->dst.u3.in6 = nla_get_in6_addr(tb[CTA_IP_V6_DST]); 1045 + t->src.u3.in6 = nla_get_in6_addr(tb[CTA_IP_V6_SRC]); 1046 + } 1047 + 1048 + if (flags & CTA_FILTER_FLAG(CTA_IP_DST)) { 1049 + if (!tb[CTA_IP_V6_DST]) 1050 + return -EINVAL; 1051 + 1052 + t->dst.u3.in6 = nla_get_in6_addr(tb[CTA_IP_V6_DST]); 1053 + } 1235 1054 1236 1055 return 0; 1237 1056 } 1238 1057 1239 1058 static int ctnetlink_parse_tuple_ip(struct nlattr *attr, 1240 - struct nf_conntrack_tuple *tuple) 1059 + struct nf_conntrack_tuple *tuple, 1060 + u_int32_t flags) 1241 1061 { 1242 1062 struct nlattr *tb[CTA_IP_MAX+1]; 1243 1063 int ret = 0; ··· 1272 1054 1273 1055 switch (tuple->src.l3num) { 1274 1056 case NFPROTO_IPV4: 1275 - ret = ipv4_nlattr_to_tuple(tb, tuple); 1057 + ret = ipv4_nlattr_to_tuple(tb, tuple, flags); 1276 1058 break; 1277 1059 case NFPROTO_IPV6: 1278 - ret = ipv6_nlattr_to_tuple(tb, tuple); 1060 + ret = ipv6_nlattr_to_tuple(tb, tuple, flags); 1279 1061 break; 1280 1062 } 1281 1063 ··· 1287 1069 }; 1288 1070 1289 1071 static int ctnetlink_parse_tuple_proto(struct nlattr *attr, 1290 - struct nf_conntrack_tuple *tuple) 1072 + struct nf_conntrack_tuple *tuple, 1073 + u_int32_t flags) 1291 1074 { 1292 1075 const struct nf_conntrack_l4proto *l4proto; 1293 1076 struct nlattr *tb[CTA_PROTO_MAX+1]; ··· 1299 1080 if (ret < 0) 1300 1081 return ret; 1301 1082 1083 + if (!(flags & CTA_FILTER_FLAG(CTA_PROTO_NUM))) 1084 + return 0; 1085 + 1302 1086 if (!tb[CTA_PROTO_NUM]) 1303 1087 return -EINVAL; 1088 + 1304 1089 tuple->dst.protonum = nla_get_u8(tb[CTA_PROTO_NUM]); 1305 1090 1306 1091 rcu_read_lock(); ··· 1315 1092 l4proto->nla_policy, 1316 1093 NULL); 1317 1094 if (ret == 0) 1318 - ret = l4proto->nlattr_to_tuple(tb, tuple); 1095 + ret = l4proto->nlattr_to_tuple(tb, tuple, flags); 1319 1096 } 1320 1097 1321 1098 rcu_read_unlock(); ··· 1366 1143 [CTA_TUPLE_ZONE] = { .type = NLA_U16 }, 1367 1144 }; 1368 1145 1146 + #define CTA_FILTER_F_ALL_CTA_PROTO \ 1147 + (CTA_FILTER_F_CTA_PROTO_SRC_PORT | \ 1148 + CTA_FILTER_F_CTA_PROTO_DST_PORT | \ 1149 + CTA_FILTER_F_CTA_PROTO_ICMP_TYPE | \ 1150 + CTA_FILTER_F_CTA_PROTO_ICMP_CODE | \ 1151 + CTA_FILTER_F_CTA_PROTO_ICMP_ID | \ 1152 + CTA_FILTER_F_CTA_PROTO_ICMPV6_TYPE | \ 1153 + CTA_FILTER_F_CTA_PROTO_ICMPV6_CODE | \ 1154 + CTA_FILTER_F_CTA_PROTO_ICMPV6_ID) 1155 + 1369 1156 static int 1370 - ctnetlink_parse_tuple(const struct nlattr * const cda[], 1371 - struct nf_conntrack_tuple *tuple, u32 type, 1372 - u_int8_t l3num, struct nf_conntrack_zone *zone) 1157 + ctnetlink_parse_tuple_filter(const struct nlattr * const cda[], 1158 + struct nf_conntrack_tuple *tuple, u32 type, 1159 + u_int8_t l3num, struct nf_conntrack_zone *zone, 1160 + u_int32_t flags) 1373 1161 { 1374 1162 struct nlattr *tb[CTA_TUPLE_MAX+1]; 1375 1163 int err; ··· 1392 1158 if (err < 0) 1393 1159 return err; 1394 1160 1395 - if (!tb[CTA_TUPLE_IP]) 1396 - return -EINVAL; 1397 1161 1398 1162 tuple->src.l3num = l3num; 1399 1163 1400 - err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP], tuple); 1401 - if (err < 0) 1402 - return err; 1164 + if (flags & CTA_FILTER_FLAG(CTA_IP_DST) || 1165 + flags & CTA_FILTER_FLAG(CTA_IP_SRC)) { 1166 + if (!tb[CTA_TUPLE_IP]) 1167 + return -EINVAL; 1403 1168 1404 - if (!tb[CTA_TUPLE_PROTO]) 1169 + err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP], tuple, flags); 1170 + if (err < 0) 1171 + return err; 1172 + } 1173 + 1174 + if (flags & CTA_FILTER_FLAG(CTA_PROTO_NUM)) { 1175 + if (!tb[CTA_TUPLE_PROTO]) 1176 + return -EINVAL; 1177 + 1178 + err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO], tuple, flags); 1179 + if (err < 0) 1180 + return err; 1181 + } else if (flags & CTA_FILTER_FLAG(ALL_CTA_PROTO)) { 1182 + /* Can't manage proto flags without a protonum */ 1405 1183 return -EINVAL; 1184 + } 1406 1185 1407 - err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO], tuple); 1408 - if (err < 0) 1409 - return err; 1410 - 1411 - if (tb[CTA_TUPLE_ZONE]) { 1186 + if ((flags & CTA_FILTER_FLAG(CTA_TUPLE_ZONE)) && tb[CTA_TUPLE_ZONE]) { 1412 1187 if (!zone) 1413 1188 return -EINVAL; 1414 1189 ··· 1434 1191 tuple->dst.dir = IP_CT_DIR_ORIGINAL; 1435 1192 1436 1193 return 0; 1194 + } 1195 + 1196 + static int 1197 + ctnetlink_parse_tuple(const struct nlattr * const cda[], 1198 + struct nf_conntrack_tuple *tuple, u32 type, 1199 + u_int8_t l3num, struct nf_conntrack_zone *zone) 1200 + { 1201 + return ctnetlink_parse_tuple_filter(cda, tuple, type, l3num, zone, 1202 + CTA_FILTER_FLAG(ALL)); 1437 1203 } 1438 1204 1439 1205 static const struct nla_policy help_nla_policy[CTA_HELP_MAX+1] = { ··· 1492 1240 .len = NF_CT_LABELS_MAX_SIZE }, 1493 1241 [CTA_LABELS_MASK] = { .type = NLA_BINARY, 1494 1242 .len = NF_CT_LABELS_MAX_SIZE }, 1243 + [CTA_FILTER] = { .type = NLA_NESTED }, 1495 1244 }; 1496 1245 1497 1246 static int ctnetlink_flush_iterate(struct nf_conn *ct, void *data) ··· 1509 1256 { 1510 1257 struct ctnetlink_filter *filter = NULL; 1511 1258 1512 - if (family || (cda[CTA_MARK] && cda[CTA_MARK_MASK])) { 1259 + if (ctnetlink_needs_filter(family, cda)) { 1260 + if (cda[CTA_FILTER]) 1261 + return -EOPNOTSUPP; 1262 + 1513 1263 filter = ctnetlink_alloc_filter(cda, family); 1514 1264 if (IS_ERR(filter)) 1515 1265 return PTR_ERR(filter); ··· 1641 1385 } 1642 1386 1643 1387 err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 1644 - NFNL_MSG_TYPE(nlh->nlmsg_type), ct, true); 1388 + NFNL_MSG_TYPE(nlh->nlmsg_type), ct, true, 0); 1645 1389 nf_ct_put(ct); 1646 1390 if (err <= 0) 1647 1391 goto free; ··· 1714 1458 res = ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).portid, 1715 1459 cb->nlh->nlmsg_seq, 1716 1460 NFNL_MSG_TYPE(cb->nlh->nlmsg_type), 1717 - ct, dying ? true : false); 1461 + ct, dying ? true : false, 0); 1718 1462 if (res < 0) { 1719 1463 if (!atomic_inc_not_zero(&ct->ct_general.use)) 1720 1464 continue;
+25 -11
net/netfilter/nf_conntrack_proto_icmp.c
··· 20 20 #include <net/netfilter/nf_conntrack_zones.h> 21 21 #include <net/netfilter/nf_log.h> 22 22 23 + #include "nf_internals.h" 24 + 23 25 static const unsigned int nf_ct_icmp_timeout = 30*HZ; 24 26 25 27 bool icmp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, ··· 273 271 }; 274 272 275 273 static int icmp_nlattr_to_tuple(struct nlattr *tb[], 276 - struct nf_conntrack_tuple *tuple) 274 + struct nf_conntrack_tuple *tuple, 275 + u_int32_t flags) 277 276 { 278 - if (!tb[CTA_PROTO_ICMP_TYPE] || 279 - !tb[CTA_PROTO_ICMP_CODE] || 280 - !tb[CTA_PROTO_ICMP_ID]) 281 - return -EINVAL; 277 + if (flags & CTA_FILTER_FLAG(CTA_PROTO_ICMP_TYPE)) { 278 + if (!tb[CTA_PROTO_ICMP_TYPE]) 279 + return -EINVAL; 282 280 283 - tuple->dst.u.icmp.type = nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]); 284 - tuple->dst.u.icmp.code = nla_get_u8(tb[CTA_PROTO_ICMP_CODE]); 285 - tuple->src.u.icmp.id = nla_get_be16(tb[CTA_PROTO_ICMP_ID]); 281 + tuple->dst.u.icmp.type = nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]); 282 + if (tuple->dst.u.icmp.type >= sizeof(invmap) || 283 + !invmap[tuple->dst.u.icmp.type]) 284 + return -EINVAL; 285 + } 286 286 287 - if (tuple->dst.u.icmp.type >= sizeof(invmap) || 288 - !invmap[tuple->dst.u.icmp.type]) 289 - return -EINVAL; 287 + if (flags & CTA_FILTER_FLAG(CTA_PROTO_ICMP_CODE)) { 288 + if (!tb[CTA_PROTO_ICMP_CODE]) 289 + return -EINVAL; 290 + 291 + tuple->dst.u.icmp.code = nla_get_u8(tb[CTA_PROTO_ICMP_CODE]); 292 + } 293 + 294 + if (flags & CTA_FILTER_FLAG(CTA_PROTO_ICMP_ID)) { 295 + if (!tb[CTA_PROTO_ICMP_ID]) 296 + return -EINVAL; 297 + 298 + tuple->src.u.icmp.id = nla_get_be16(tb[CTA_PROTO_ICMP_ID]); 299 + } 290 300 291 301 return 0; 292 302 }
+26 -12
net/netfilter/nf_conntrack_proto_icmpv6.c
··· 24 24 #include <net/netfilter/nf_conntrack_zones.h> 25 25 #include <net/netfilter/nf_log.h> 26 26 27 + #include "nf_internals.h" 28 + 27 29 static const unsigned int nf_ct_icmpv6_timeout = 30*HZ; 28 30 29 31 bool icmpv6_pkt_to_tuple(const struct sk_buff *skb, ··· 195 193 }; 196 194 197 195 static int icmpv6_nlattr_to_tuple(struct nlattr *tb[], 198 - struct nf_conntrack_tuple *tuple) 196 + struct nf_conntrack_tuple *tuple, 197 + u_int32_t flags) 199 198 { 200 - if (!tb[CTA_PROTO_ICMPV6_TYPE] || 201 - !tb[CTA_PROTO_ICMPV6_CODE] || 202 - !tb[CTA_PROTO_ICMPV6_ID]) 203 - return -EINVAL; 199 + if (flags & CTA_FILTER_FLAG(CTA_PROTO_ICMPV6_TYPE)) { 200 + if (!tb[CTA_PROTO_ICMPV6_TYPE]) 201 + return -EINVAL; 204 202 205 - tuple->dst.u.icmp.type = nla_get_u8(tb[CTA_PROTO_ICMPV6_TYPE]); 206 - tuple->dst.u.icmp.code = nla_get_u8(tb[CTA_PROTO_ICMPV6_CODE]); 207 - tuple->src.u.icmp.id = nla_get_be16(tb[CTA_PROTO_ICMPV6_ID]); 203 + tuple->dst.u.icmp.type = nla_get_u8(tb[CTA_PROTO_ICMPV6_TYPE]); 204 + if (tuple->dst.u.icmp.type < 128 || 205 + tuple->dst.u.icmp.type - 128 >= sizeof(invmap) || 206 + !invmap[tuple->dst.u.icmp.type - 128]) 207 + return -EINVAL; 208 + } 208 209 209 - if (tuple->dst.u.icmp.type < 128 || 210 - tuple->dst.u.icmp.type - 128 >= sizeof(invmap) || 211 - !invmap[tuple->dst.u.icmp.type - 128]) 212 - return -EINVAL; 210 + if (flags & CTA_FILTER_FLAG(CTA_PROTO_ICMPV6_CODE)) { 211 + if (!tb[CTA_PROTO_ICMPV6_CODE]) 212 + return -EINVAL; 213 + 214 + tuple->dst.u.icmp.code = nla_get_u8(tb[CTA_PROTO_ICMPV6_CODE]); 215 + } 216 + 217 + if (flags & CTA_FILTER_FLAG(CTA_PROTO_ICMPV6_ID)) { 218 + if (!tb[CTA_PROTO_ICMPV6_ID]) 219 + return -EINVAL; 220 + 221 + tuple->src.u.icmp.id = nla_get_be16(tb[CTA_PROTO_ICMPV6_ID]); 222 + } 213 223 214 224 return 0; 215 225 }
+17
net/netfilter/nf_internals.h
··· 6 6 #include <linux/skbuff.h> 7 7 #include <linux/netdevice.h> 8 8 9 + /* nf_conntrack_netlink.c: applied on tuple filters */ 10 + #define CTA_FILTER_F_CTA_IP_SRC (1 << 0) 11 + #define CTA_FILTER_F_CTA_IP_DST (1 << 1) 12 + #define CTA_FILTER_F_CTA_TUPLE_ZONE (1 << 2) 13 + #define CTA_FILTER_F_CTA_PROTO_NUM (1 << 3) 14 + #define CTA_FILTER_F_CTA_PROTO_SRC_PORT (1 << 4) 15 + #define CTA_FILTER_F_CTA_PROTO_DST_PORT (1 << 5) 16 + #define CTA_FILTER_F_CTA_PROTO_ICMP_TYPE (1 << 6) 17 + #define CTA_FILTER_F_CTA_PROTO_ICMP_CODE (1 << 7) 18 + #define CTA_FILTER_F_CTA_PROTO_ICMP_ID (1 << 8) 19 + #define CTA_FILTER_F_CTA_PROTO_ICMPV6_TYPE (1 << 9) 20 + #define CTA_FILTER_F_CTA_PROTO_ICMPV6_CODE (1 << 10) 21 + #define CTA_FILTER_F_CTA_PROTO_ICMPV6_ID (1 << 11) 22 + #define CTA_FILTER_F_MAX (1 << 12) 23 + #define CTA_FILTER_F_ALL (CTA_FILTER_F_MAX-1) 24 + #define CTA_FILTER_FLAG(ctattr) CTA_FILTER_F_ ## ctattr 25 + 9 26 /* nf_queue.c */ 10 27 void nf_queue_nf_hook_drop(struct net *net); 11 28