All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pablo Neira Ayuso <pablo@netfilter.org>
To: netfilter-devel@vger.kernel.org
Cc: davem@davemloft.net, netdev@vger.kernel.org
Subject: [PATCH 26/26] netfilter: nf_tables: add support for matching IPv4 options
Date: Tue, 25 Jun 2019 02:12:33 +0200	[thread overview]
Message-ID: <20190625001233.22057-27-pablo@netfilter.org> (raw)
In-Reply-To: <20190625001233.22057-1-pablo@netfilter.org>

From: Stephen Suryaputra <ssuryaextr@gmail.com>

This is the kernel change for the overall changes with this description:
Add capability to have rules matching IPv4 options. This is developed
mainly to support dropping of IP packets with loose and/or strict source
route route options.

Signed-off-by: Stephen Suryaputra <ssuryaextr@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/uapi/linux/netfilter/nf_tables.h |   2 +
 net/ipv4/ip_options.c                    |   1 +
 net/netfilter/nft_exthdr.c               | 133 +++++++++++++++++++++++++++++++
 3 files changed, 136 insertions(+)

diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index 31a6b8f7ff73..c6c8ec5c7c00 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -730,10 +730,12 @@ enum nft_exthdr_flags {
  *
  * @NFT_EXTHDR_OP_IPV6: match against ipv6 extension headers
  * @NFT_EXTHDR_OP_TCP: match against tcp options
+ * @NFT_EXTHDR_OP_IPV4: match against ipv4 options
  */
 enum nft_exthdr_op {
 	NFT_EXTHDR_OP_IPV6,
 	NFT_EXTHDR_OP_TCPOPT,
+	NFT_EXTHDR_OP_IPV4,
 	__NFT_EXTHDR_OP_MAX
 };
 #define NFT_EXTHDR_OP_MAX	(__NFT_EXTHDR_OP_MAX - 1)
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index 3db31bb9df50..ddaa01ec2bce 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -473,6 +473,7 @@ int __ip_options_compile(struct net *net,
 		*info = htonl((pp_ptr-iph)<<24);
 	return -EINVAL;
 }
+EXPORT_SYMBOL(__ip_options_compile);
 
 int ip_options_compile(struct net *net,
 		       struct ip_options *opt, struct sk_buff *skb)
diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c
index 45c8a6c07783..8032b2937c7f 100644
--- a/net/netfilter/nft_exthdr.c
+++ b/net/netfilter/nft_exthdr.c
@@ -62,6 +62,103 @@ static void nft_exthdr_ipv6_eval(const struct nft_expr *expr,
 	regs->verdict.code = NFT_BREAK;
 }
 
+/* find the offset to specified option.
+ *
+ * If target header is found, its offset is set in *offset and return option
+ * number. Otherwise, return negative error.
+ *
+ * If the first fragment doesn't contain the End of Options it is considered
+ * invalid.
+ */
+static int ipv4_find_option(struct net *net, struct sk_buff *skb,
+			    unsigned int *offset, int target)
+{
+	unsigned char optbuf[sizeof(struct ip_options) + 40];
+	struct ip_options *opt = (struct ip_options *)optbuf;
+	struct iphdr *iph, _iph;
+	unsigned int start;
+	bool found = false;
+	__be32 info;
+	int optlen;
+
+	iph = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+	if (!iph)
+		return -EBADMSG;
+	start = sizeof(struct iphdr);
+
+	optlen = iph->ihl * 4 - (int)sizeof(struct iphdr);
+	if (optlen <= 0)
+		return -ENOENT;
+
+	memset(opt, 0, sizeof(struct ip_options));
+	/* Copy the options since __ip_options_compile() modifies
+	 * the options.
+	 */
+	if (skb_copy_bits(skb, start, opt->__data, optlen))
+		return -EBADMSG;
+	opt->optlen = optlen;
+
+	if (__ip_options_compile(net, opt, NULL, &info))
+		return -EBADMSG;
+
+	switch (target) {
+	case IPOPT_SSRR:
+	case IPOPT_LSRR:
+		if (!opt->srr)
+			break;
+		found = target == IPOPT_SSRR ? opt->is_strictroute :
+					       !opt->is_strictroute;
+		if (found)
+			*offset = opt->srr + start;
+		break;
+	case IPOPT_RR:
+		if (!opt->rr)
+			break;
+		*offset = opt->rr + start;
+		found = true;
+		break;
+	case IPOPT_RA:
+		if (!opt->router_alert)
+			break;
+		*offset = opt->router_alert + start;
+		found = true;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+	return found ? target : -ENOENT;
+}
+
+static void nft_exthdr_ipv4_eval(const struct nft_expr *expr,
+				 struct nft_regs *regs,
+				 const struct nft_pktinfo *pkt)
+{
+	struct nft_exthdr *priv = nft_expr_priv(expr);
+	u32 *dest = &regs->data[priv->dreg];
+	struct sk_buff *skb = pkt->skb;
+	unsigned int offset;
+	int err;
+
+	if (skb->protocol != htons(ETH_P_IP))
+		goto err;
+
+	err = ipv4_find_option(nft_net(pkt), skb, &offset, priv->type);
+	if (priv->flags & NFT_EXTHDR_F_PRESENT) {
+		*dest = (err >= 0);
+		return;
+	} else if (err < 0) {
+		goto err;
+	}
+	offset += priv->offset;
+
+	dest[priv->len / NFT_REG32_SIZE] = 0;
+	if (skb_copy_bits(pkt->skb, offset, dest, priv->len) < 0)
+		goto err;
+	return;
+err:
+	regs->verdict.code = NFT_BREAK;
+}
+
 static void *
 nft_tcp_header_pointer(const struct nft_pktinfo *pkt,
 		       unsigned int len, void *buffer, unsigned int *tcphdr_len)
@@ -315,6 +412,28 @@ static int nft_exthdr_tcp_set_init(const struct nft_ctx *ctx,
 	return nft_validate_register_load(priv->sreg, priv->len);
 }
 
+static int nft_exthdr_ipv4_init(const struct nft_ctx *ctx,
+				const struct nft_expr *expr,
+				const struct nlattr * const tb[])
+{
+	struct nft_exthdr *priv = nft_expr_priv(expr);
+	int err = nft_exthdr_init(ctx, expr, tb);
+
+	if (err < 0)
+		return err;
+
+	switch (priv->type) {
+	case IPOPT_SSRR:
+	case IPOPT_LSRR:
+	case IPOPT_RR:
+	case IPOPT_RA:
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
 static int nft_exthdr_dump_common(struct sk_buff *skb, const struct nft_exthdr *priv)
 {
 	if (nla_put_u8(skb, NFTA_EXTHDR_TYPE, priv->type))
@@ -361,6 +480,14 @@ static const struct nft_expr_ops nft_exthdr_ipv6_ops = {
 	.dump		= nft_exthdr_dump,
 };
 
+static const struct nft_expr_ops nft_exthdr_ipv4_ops = {
+	.type		= &nft_exthdr_type,
+	.size		= NFT_EXPR_SIZE(sizeof(struct nft_exthdr)),
+	.eval		= nft_exthdr_ipv4_eval,
+	.init		= nft_exthdr_ipv4_init,
+	.dump		= nft_exthdr_dump,
+};
+
 static const struct nft_expr_ops nft_exthdr_tcp_ops = {
 	.type		= &nft_exthdr_type,
 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_exthdr)),
@@ -401,6 +528,12 @@ nft_exthdr_select_ops(const struct nft_ctx *ctx,
 		if (tb[NFTA_EXTHDR_DREG])
 			return &nft_exthdr_ipv6_ops;
 		break;
+	case NFT_EXTHDR_OP_IPV4:
+		if (ctx->family != NFPROTO_IPV6) {
+			if (tb[NFTA_EXTHDR_DREG])
+				return &nft_exthdr_ipv4_ops;
+		}
+		break;
 	}
 
 	return ERR_PTR(-EOPNOTSUPP);
-- 
2.11.0


  parent reply	other threads:[~2019-06-25  0:14 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-06-25  0:12 [PATCH 00/26] Netfilter updates for net-next Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 01/26] netfilter: ipv6: Fix undefined symbol nf_ct_frag6_gather Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 02/26] netfilter: ipset: remove useless memset() calls Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 03/26] netfilter: ipset: merge uadd and udel functions Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 04/26] netfilter: ipset: fix a missing check of nla_parse Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 05/26] netfilter: ipset: Fix the last missing check of nla_parse_deprecated() Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 06/26] netfilter: ipset: Fix error path in set_target_v3_checkentry() Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 07/26] ipset: Fix memory accounting for hash types on resize Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 08/26] Update my email address Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 09/26] netfilter: nft_ct: add ct expectations support Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 10/26] netfilter: conntrack: small conntrack lookup optimization Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 11/26] netfilter: xt_owner: bail out with EINVAL in case of unsupported flags Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 12/26] netfilter: bridge: port sysctls to use brnf_net Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 13/26] netfilter: bridge: namespace bridge netfilter sysctls Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 14/26] netfilter: synproxy: add common uapi for SYNPROXY infrastructure Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 15/26] netfilter: synproxy: remove module dependency on IPv6 SYNPROXY Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 16/26] netfilter: synproxy: extract SYNPROXY infrastructure from {ipt, ip6t}_SYNPROXY Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 17/26] netfilter: synproxy: ensure zero is returned on non-error return path Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 18/26] netfilter: nft_ct: fix null pointer in ct expectations support Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 19/26] netfilter: nf_tables: enable set expiration time for set elements Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 20/26] netfilter: synproxy: fix building syncookie calls Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 21/26] netfilter: synproxy: use nf_cookie_v6_check() from core Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 22/26] netfilter: bridge: prevent UAF in brnf_exit_net() Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 23/26] netfilter: fix nf_conntrack_bridge/ipv6 link error Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 24/26] netfilter: bridge: Fix non-untagged fragment packet Pablo Neira Ayuso
2019-06-25  0:12 ` [PATCH 25/26] netfilter: synproxy: fix manual bump of the reference counter Pablo Neira Ayuso
2019-06-25  0:12 ` Pablo Neira Ayuso [this message]
2019-06-25 19:46 ` [PATCH 00/26] Netfilter updates for net-next David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190625001233.22057-27-pablo@netfilter.org \
    --to=pablo@netfilter.org \
    --cc=davem@davemloft.net \
    --cc=netdev@vger.kernel.org \
    --cc=netfilter-devel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.