History

netfilter: ctnetlink: allow to filter dump by status bits

If CTA_STATUS is present, but CTA_STATUS_MASK is not, then the mask is automatically set to 'status', so that kernel returns those entries that have all of the requested bits set. This makes more sense than using a all-one mask since we'd hardly ever find a match. There are no other checks for status bits, so if e.g. userspace sets impossible combinations it will get an empty dump. If kernel would reject unknown status bits, then a program that works on a future kernel that has IPS_FOO bit fails on old kernels. Same for 'impossible' combinations: Kernel never sets ASSURED without first having set SEEN_REPLY, but its possible that a future kernel could do so. Therefore no sanity tests other than a 0-mask.

Florian Westphal committed 5 years ago

Commit 93449881 parent ff1199d2 files · +34 −1Browse files

Unified · Split

2 files
  1. include/uapi/linux/netfilter/nfnetlink_conntrack.h +1 −0
  2. net/netfilter/nf_conntrack_netlink.c +33 −1
include/uapi/linux/netfilter/nfnetlink_conntrack.h+1−0
@@ -56,6 +56,7 @@ enum ctattr_type { · 55 unmodified lines
56 CTA_LABELS_MASK,56 CTA_LABELS_MASK,
57 CTA_SYNPROXY,57 CTA_SYNPROXY,
58 CTA_FILTER,58 CTA_FILTER,
59 CTA_STATUS_MASK,
59 __CTA_MAX60 __CTA_MAX
60};61};
61#define CTA_MAX (__CTA_MAX - 1)62#define CTA_MAX (__CTA_MAX - 1)
net/netfilter/nf_conntrack_netlink.c+33−1
@@ -868,6 +868,7 @@ struct ctnetlink_filter { · 867 unmodified lines
868 struct nf_conntrack_zone zone;868 struct nf_conntrack_zone zone;
869 869
870 struct ctnetlink_filter_u32 mark;870 struct ctnetlink_filter_u32 mark;
871 struct ctnetlink_filter_u32 status;
871};872};
872 873
873static const struct nla_policy cta_filter_nla_policy[CTA_FILTER_MAX + 1] = {874static const struct nla_policy cta_filter_nla_policy[CTA_FILTER_MAX + 1] = {
@@ -927,6 +928,28 @@ static int ctnetlink_filter_parse_mark(struct ctnetlink_filter_u32 *mark, · 53 unmodified lines
927 return 0;928 return 0;
928}929}
929 930
931static int ctnetlink_filter_parse_status(struct ctnetlink_filter_u32 *status,
932 const struct nlattr * const cda[])
933{
934 if (cda[CTA_STATUS]) {
935 status->val = ntohl(nla_get_be32(cda[CTA_STATUS]));
936 if (cda[CTA_STATUS_MASK])
937 status->mask = ntohl(nla_get_be32(cda[CTA_STATUS_MASK]));
938 else
939 status->mask = status->val;
940
941 /* status->val == 0? always true, else always false. */
942 if (status->mask == 0)
943 return -EINVAL;
944 } else if (cda[CTA_STATUS_MASK]) {
945 return -EINVAL;
946 }
947
948 /* CTA_STATUS is NLA_U32, if this fires UAPI needs to be extended */
949 BUILD_BUG_ON(__IPS_MAX_BIT >= 32);
950 return 0;
951}
952
930static struct ctnetlink_filter *953static struct ctnetlink_filter *
931ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)954ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
932{955{
@@ -948,6 +971,10 @@ ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family) · 15 unmodified lines
948 if (err)971 if (err)
949 goto err_filter;972 goto err_filter;
950 973
974 err = ctnetlink_filter_parse_status(&filter->status, cda);
975 if (err)
976 goto err_filter;
977
951 if (!cda[CTA_FILTER])978 if (!cda[CTA_FILTER])
952 return filter;979 return filter;
953 980
@@ -1001,7 +1028,7 @@ err_filter: · 47 unmodified lines
1001 1028
1002static bool ctnetlink_needs_filter(u8 family, const struct nlattr * const *cda)1029static bool ctnetlink_needs_filter(u8 family, const struct nlattr * const *cda)
1003{1030{
1004 return family || cda[CTA_MARK] || cda[CTA_FILTER];1031 return family || cda[CTA_MARK] || cda[CTA_FILTER] || cda[CTA_STATUS];
1005}1032}
1006 1033
1007static int ctnetlink_start(struct netlink_callback *cb)1034static int ctnetlink_start(struct netlink_callback *cb)
@@ -1094,6 +1121,7 @@ static int ctnetlink_filter_match(struct nf_conn *ct, void *data) · 86 unmodified lines
1094{1121{
1095 struct ctnetlink_filter *filter = data;1122 struct ctnetlink_filter *filter = data;
1096 struct nf_conntrack_tuple *tuple;1123 struct nf_conntrack_tuple *tuple;
1124 u32 status;
1097 1125
1098 if (filter == NULL)1126 if (filter == NULL)
1099 goto out;1127 goto out;
@@ -1125,6 +1153,9 @@ static int ctnetlink_filter_match(struct nf_conn *ct, void *data) · 25 unmodified lines
1125 if ((ct->mark & filter->mark.mask) != filter->mark.val)1153 if ((ct->mark & filter->mark.mask) != filter->mark.val)
1126 goto ignore_entry;1154 goto ignore_entry;
1127#endif1155#endif
1156 status = (u32)READ_ONCE(ct->status);
1157 if ((status & filter->status.mask) != filter->status.val)
1158 goto ignore_entry;
1128 1159
1129out:1160out:
1130 return 1;1161 return 1;
@@ -1507,6 +1538,7 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = { · 376 unmodified lines
1507 [CTA_LABELS_MASK] = { .type = NLA_BINARY,1538 [CTA_LABELS_MASK] = { .type = NLA_BINARY,
1508 .len = NF_CT_LABELS_MAX_SIZE },1539 .len = NF_CT_LABELS_MAX_SIZE },
1509 [CTA_FILTER] = { .type = NLA_NESTED },1540 [CTA_FILTER] = { .type = NLA_NESTED },
1541 [CTA_STATUS_MASK] = { .type = NLA_U32 },
1510};1542};
1511 1543
1512static int ctnetlink_flush_iterate(struct nf_conn *ct, void *data)1544static int ctnetlink_flush_iterate(struct nf_conn *ct, void *data)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t