* [PATCH v2 nf-next] netfilter: introduce support for reject at prerouting stage
@ 2020-05-29 11:03 Laura Garcia Liebana
2020-05-29 19:15 ` Pablo Neira Ayuso
0 siblings, 1 reply; 3+ messages in thread
From: Laura Garcia Liebana @ 2020-05-29 11:03 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo, devel
REJECT statement can be only used in INPUT, FORWARD and OUTPUT
chains. This patch adds support of REJECT, both icmp and tcp
reset, at PREROUTING stage.
The need for this patch comes from the requirement of some
forwarding devices to reject traffic before the natting and
routing decisions.
The main use case is to be able to send a graceful termination
to legitimate clients that, under any circumstances, the NATed
endpoints are not available. This option allows clients to
decide either to perform a reconnection or manage the error in
their side, instead of just dropping the connection and let
them die due to timeout.
It is supported ipv4, ipv6 and inet families for nft
infrastructure.
Signed-off-by: Laura Garcia Liebana <nevola@gmail.com>
---
v2:
- Add error handling in nf_route(), suggested by Florian Westphal.
- Add use case description, suggested by Reindl Harald.
net/ipv4/netfilter/nf_reject_ipv4.c | 22 ++++++++++++++++++++++
net/ipv6/netfilter/nf_reject_ipv6.c | 27 +++++++++++++++++++++++++++
net/netfilter/nft_reject.c | 3 ++-
3 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c b/net/ipv4/netfilter/nf_reject_ipv4.c
index 2361fdac2c43..b5b7633d9433 100644
--- a/net/ipv4/netfilter/nf_reject_ipv4.c
+++ b/net/ipv4/netfilter/nf_reject_ipv4.c
@@ -96,6 +96,22 @@ void nf_reject_ip_tcphdr_put(struct sk_buff *nskb, const struct sk_buff *oldskb,
}
EXPORT_SYMBOL_GPL(nf_reject_ip_tcphdr_put);
+static int nf_reject_fill_skb_dst(struct sk_buff *skb_in)
+{
+ struct dst_entry *dst = NULL;
+ struct flowi fl;
+ struct flowi4 *fl4 = &fl.u.ip4;
+
+ memset(fl4, 0, sizeof(*fl4));
+ fl4->daddr = ip_hdr(skb_in)->saddr;
+ nf_route(dev_net(skb_in->dev), &dst, &fl, false, AF_INET);
+ if (!dst)
+ return -1;
+
+ skb_dst_set(skb_in, dst);
+ return 0;
+}
+
/* Send RST reply */
void nf_send_reset(struct net *net, struct sk_buff *oldskb, int hook)
{
@@ -109,6 +125,9 @@ void nf_send_reset(struct net *net, struct sk_buff *oldskb, int hook)
if (!oth)
return;
+ if (hook == NF_INET_PRE_ROUTING && nf_reject_fill_skb_dst(oldskb))
+ return;
+
if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
return;
@@ -175,6 +194,9 @@ void nf_send_unreach(struct sk_buff *skb_in, int code, int hook)
if (iph->frag_off & htons(IP_OFFSET))
return;
+ if (hook == NF_INET_PRE_ROUTING && nf_reject_fill_skb_dst(skb_in))
+ return;
+
if (skb_csum_unnecessary(skb_in) || !nf_reject_verify_csum(proto)) {
icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0);
return;
diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c
index 5fae66f66671..df1ac768cadc 100644
--- a/net/ipv6/netfilter/nf_reject_ipv6.c
+++ b/net/ipv6/netfilter/nf_reject_ipv6.c
@@ -126,6 +126,22 @@ void nf_reject_ip6_tcphdr_put(struct sk_buff *nskb,
}
EXPORT_SYMBOL_GPL(nf_reject_ip6_tcphdr_put);
+static int nf_reject6_fill_skb_dst(struct sk_buff *skb_in)
+{
+ struct dst_entry *dst = NULL;
+ struct flowi fl;
+ struct flowi6 *fl6 = &fl.u.ip6;
+
+ memset(fl6, 0, sizeof(*fl6));
+ fl6->daddr = ipv6_hdr(skb_in)->saddr;
+ nf_route(dev_net(skb_in->dev), &dst, &fl, false, AF_INET6);
+ if (!dst)
+ return -1;
+
+ skb_dst_set(skb_in, dst);
+ return 0;
+}
+
void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
{
struct net_device *br_indev __maybe_unused;
@@ -154,6 +170,14 @@ void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
fl6.daddr = oip6h->saddr;
fl6.fl6_sport = otcph->dest;
fl6.fl6_dport = otcph->source;
+
+ if (hook == NF_INET_PRE_ROUTING) {
+ nf_route(dev_net(oldskb->dev), &dst, flowi6_to_flowi(&fl6), false, AF_INET6);
+ if (!dst)
+ return;
+ skb_dst_set(oldskb, dst);
+ }
+
fl6.flowi6_oif = l3mdev_master_ifindex(skb_dst(oldskb)->dev);
fl6.flowi6_mark = IP6_REPLY_MARK(net, oldskb->mark);
security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6));
@@ -245,6 +269,9 @@ void nf_send_unreach6(struct net *net, struct sk_buff *skb_in,
if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL)
skb_in->dev = net->loopback_dev;
+ if (hooknum == NF_INET_PRE_ROUTING && nf_reject6_fill_skb_dst(skb_in))
+ return;
+
icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0);
}
EXPORT_SYMBOL_GPL(nf_send_unreach6);
diff --git a/net/netfilter/nft_reject.c b/net/netfilter/nft_reject.c
index 00f865fb80ca..5eac28269bdb 100644
--- a/net/netfilter/nft_reject.c
+++ b/net/netfilter/nft_reject.c
@@ -30,7 +30,8 @@ int nft_reject_validate(const struct nft_ctx *ctx,
return nft_chain_validate_hooks(ctx->chain,
(1 << NF_INET_LOCAL_IN) |
(1 << NF_INET_FORWARD) |
- (1 << NF_INET_LOCAL_OUT));
+ (1 << NF_INET_LOCAL_OUT) |
+ (1 << NF_INET_PRE_ROUTING));
}
EXPORT_SYMBOL_GPL(nft_reject_validate);
--
2.20.1
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH v2 nf-next] netfilter: introduce support for reject at prerouting stage
2020-05-29 11:03 [PATCH v2 nf-next] netfilter: introduce support for reject at prerouting stage Laura Garcia Liebana
@ 2020-05-29 19:15 ` Pablo Neira Ayuso
2020-05-30 20:51 ` Laura García Liébana
0 siblings, 1 reply; 3+ messages in thread
From: Pablo Neira Ayuso @ 2020-05-29 19:15 UTC (permalink / raw)
To: Laura Garcia Liebana; +Cc: netfilter-devel, devel
On Fri, May 29, 2020 at 01:03:28PM +0200, Laura Garcia Liebana wrote:
[...]
> diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c b/net/ipv4/netfilter/nf_reject_ipv4.c
> index 2361fdac2c43..b5b7633d9433 100644
> --- a/net/ipv4/netfilter/nf_reject_ipv4.c
> +++ b/net/ipv4/netfilter/nf_reject_ipv4.c
> @@ -96,6 +96,22 @@ void nf_reject_ip_tcphdr_put(struct sk_buff *nskb, const struct sk_buff *oldskb,
> }
> EXPORT_SYMBOL_GPL(nf_reject_ip_tcphdr_put);
>
> +static int nf_reject_fill_skb_dst(struct sk_buff *skb_in)
> +{
> + struct dst_entry *dst = NULL;
> + struct flowi fl;
> + struct flowi4 *fl4 = &fl.u.ip4;
> +
> + memset(fl4, 0, sizeof(*fl4));
> + fl4->daddr = ip_hdr(skb_in)->saddr;
> + nf_route(dev_net(skb_in->dev), &dst, &fl, false, AF_INET);
> + if (!dst)
> + return -1;
> +
> + skb_dst_set(skb_in, dst);
> + return 0;
> +}
Probably slightly simplify this? I'd suggest:
* make calls to nf_ip_route() and nf_ip6_route() instead of the nf_route()
wrapper.
* use flowi structure, no need to add struct flowi4 ? Probably:
static int nf_reject_fill_skb_dst(struct sk_buff *skb_in)
{
struct dst_entry *dst = NULL;
struct flowi fl;
memset(fl, 0, sizeof(*fl));
fl.u.ip4 = ip_hdr(skb_in)->saddr;
nf_ip_route(dev_net(skb_in->dev), &dst, &fl, false);
if (!dst)
return -1;
skb_dst_set(skb_in, dst);
return 0;
}
Another possibility would be to use C99 structure initialization. But
I think the code above should be fine.
Thanks.
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH v2 nf-next] netfilter: introduce support for reject at prerouting stage
2020-05-29 19:15 ` Pablo Neira Ayuso
@ 2020-05-30 20:51 ` Laura García Liébana
0 siblings, 0 replies; 3+ messages in thread
From: Laura García Liébana @ 2020-05-30 20:51 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: Netfilter Development Mailing list, devel
On Fri, May 29, 2020 at 9:15 PM Pablo Neira Ayuso <pablo@netfilter.org> wrote:
>
> On Fri, May 29, 2020 at 01:03:28PM +0200, Laura Garcia Liebana wrote:
> [...]
> > diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c b/net/ipv4/netfilter/nf_reject_ipv4.c
> > index 2361fdac2c43..b5b7633d9433 100644
> > --- a/net/ipv4/netfilter/nf_reject_ipv4.c
> > +++ b/net/ipv4/netfilter/nf_reject_ipv4.c
> > @@ -96,6 +96,22 @@ void nf_reject_ip_tcphdr_put(struct sk_buff *nskb, const struct sk_buff *oldskb,
> > }
> > EXPORT_SYMBOL_GPL(nf_reject_ip_tcphdr_put);
> >
> > +static int nf_reject_fill_skb_dst(struct sk_buff *skb_in)
> > +{
> > + struct dst_entry *dst = NULL;
> > + struct flowi fl;
> > + struct flowi4 *fl4 = &fl.u.ip4;
> > +
> > + memset(fl4, 0, sizeof(*fl4));
> > + fl4->daddr = ip_hdr(skb_in)->saddr;
> > + nf_route(dev_net(skb_in->dev), &dst, &fl, false, AF_INET);
> > + if (!dst)
> > + return -1;
> > +
> > + skb_dst_set(skb_in, dst);
> > + return 0;
> > +}
>
> Probably slightly simplify this? I'd suggest:
>
> * make calls to nf_ip_route() and nf_ip6_route() instead of the nf_route()
> wrapper.
>
> * use flowi structure, no need to add struct flowi4 ? Probably:
>
> static int nf_reject_fill_skb_dst(struct sk_buff *skb_in)
> {
> struct dst_entry *dst = NULL;
> struct flowi fl;
>
> memset(fl, 0, sizeof(*fl));
> fl.u.ip4 = ip_hdr(skb_in)->saddr;
> nf_ip_route(dev_net(skb_in->dev), &dst, &fl, false);
> if (!dst)
> return -1;
>
> skb_dst_set(skb_in, dst);
> return 0;
> }
>
> Another possibility would be to use C99 structure initialization. But
> I think the code above should be fine.
>
> Thanks.
It looks better, I'll apply the changes.
Thanks.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2020-05-30 20:51 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-05-29 11:03 [PATCH v2 nf-next] netfilter: introduce support for reject at prerouting stage Laura Garcia Liebana
2020-05-29 19:15 ` Pablo Neira Ayuso
2020-05-30 20:51 ` Laura García Liébana
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.