File Index
Files and directories
Sign in
FILE

nft_reject_netdev.c

File preview with syntax highlighting.

linux-6.19.14/net/netfilter/nft_reject_netdev.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2020 Laura Garcia Liebana <nevola@gmail.com>
  4 * Copyright (c) 2020 Jose M. Guisado <guigom@riseup.net>
  5 */
  6
  7#include <linux/etherdevice.h>
  8#include <linux/kernel.h>
  9#include <linux/init.h>
 10#include <linux/module.h>
 11#include <linux/netlink.h>
 12#include <linux/netfilter.h>
 13#include <linux/netfilter/nf_tables.h>
 14#include <net/netfilter/nf_tables.h>
 15#include <net/netfilter/nft_reject.h>
 16#include <net/netfilter/ipv4/nf_reject.h>
 17#include <net/netfilter/ipv6/nf_reject.h>
 18
 19static void nft_reject_queue_xmit(struct sk_buff *nskb, struct sk_buff *oldskb)
 20{
 21	dev_hard_header(nskb, nskb->dev, ntohs(oldskb->protocol),
 22			eth_hdr(oldskb)->h_source, eth_hdr(oldskb)->h_dest,
 23			nskb->len);
 24	dev_queue_xmit(nskb);
 25}
 26
 27static void nft_reject_netdev_send_v4_tcp_reset(struct net *net,
 28						struct sk_buff *oldskb,
 29						const struct net_device *dev,
 30						int hook)
 31{
 32	struct sk_buff *nskb;
 33
 34	nskb = nf_reject_skb_v4_tcp_reset(net, oldskb, dev, hook);
 35	if (!nskb)
 36		return;
 37
 38	nft_reject_queue_xmit(nskb, oldskb);
 39}
 40
 41static void nft_reject_netdev_send_v4_unreach(struct net *net,
 42					      struct sk_buff *oldskb,
 43					      const struct net_device *dev,
 44					      int hook, u8 code)
 45{
 46	struct sk_buff *nskb;
 47
 48	nskb = nf_reject_skb_v4_unreach(net, oldskb, dev, hook, code);
 49	if (!nskb)
 50		return;
 51
 52	nft_reject_queue_xmit(nskb, oldskb);
 53}
 54
 55static void nft_reject_netdev_send_v6_tcp_reset(struct net *net,
 56						struct sk_buff *oldskb,
 57						const struct net_device *dev,
 58						int hook)
 59{
 60	struct sk_buff *nskb;
 61
 62	nskb = nf_reject_skb_v6_tcp_reset(net, oldskb, dev, hook);
 63	if (!nskb)
 64		return;
 65
 66	nft_reject_queue_xmit(nskb, oldskb);
 67}
 68
 69
 70static void nft_reject_netdev_send_v6_unreach(struct net *net,
 71					      struct sk_buff *oldskb,
 72					      const struct net_device *dev,
 73					      int hook, u8 code)
 74{
 75	struct sk_buff *nskb;
 76
 77	nskb = nf_reject_skb_v6_unreach(net, oldskb, dev, hook, code);
 78	if (!nskb)
 79		return;
 80
 81	nft_reject_queue_xmit(nskb, oldskb);
 82}
 83
 84static void nft_reject_netdev_eval(const struct nft_expr *expr,
 85				   struct nft_regs *regs,
 86				   const struct nft_pktinfo *pkt)
 87{
 88	struct ethhdr *eth = eth_hdr(pkt->skb);
 89	struct nft_reject *priv = nft_expr_priv(expr);
 90	const unsigned char *dest = eth->h_dest;
 91
 92	if (is_broadcast_ether_addr(dest) ||
 93	    is_multicast_ether_addr(dest))
 94		goto out;
 95
 96	switch (eth->h_proto) {
 97	case htons(ETH_P_IP):
 98		switch (priv->type) {
 99		case NFT_REJECT_ICMP_UNREACH:
100			nft_reject_netdev_send_v4_unreach(nft_net(pkt), pkt->skb,
101							  nft_in(pkt),
102							  nft_hook(pkt),
103							  priv->icmp_code);
104			break;
105		case NFT_REJECT_TCP_RST:
106			nft_reject_netdev_send_v4_tcp_reset(nft_net(pkt), pkt->skb,
107							    nft_in(pkt),
108							    nft_hook(pkt));
109			break;
110		case NFT_REJECT_ICMPX_UNREACH:
111			nft_reject_netdev_send_v4_unreach(nft_net(pkt), pkt->skb,
112							  nft_in(pkt),
113							  nft_hook(pkt),
114							  nft_reject_icmp_code(priv->icmp_code));
115			break;
116		}
117		break;
118	case htons(ETH_P_IPV6):
119		switch (priv->type) {
120		case NFT_REJECT_ICMP_UNREACH:
121			nft_reject_netdev_send_v6_unreach(nft_net(pkt), pkt->skb,
122							  nft_in(pkt),
123							  nft_hook(pkt),
124							  priv->icmp_code);
125			break;
126		case NFT_REJECT_TCP_RST:
127			nft_reject_netdev_send_v6_tcp_reset(nft_net(pkt), pkt->skb,
128							    nft_in(pkt),
129							    nft_hook(pkt));
130			break;
131		case NFT_REJECT_ICMPX_UNREACH:
132			nft_reject_netdev_send_v6_unreach(nft_net(pkt), pkt->skb,
133							  nft_in(pkt),
134							  nft_hook(pkt),
135							  nft_reject_icmpv6_code(priv->icmp_code));
136			break;
137		}
138		break;
139	default:
140		/* No explicit way to reject this protocol, drop it. */
141		break;
142	}
143out:
144	regs->verdict.code = NF_DROP;
145}
146
147static int nft_reject_netdev_validate(const struct nft_ctx *ctx,
148				      const struct nft_expr *expr)
149{
150	return nft_chain_validate_hooks(ctx->chain, (1 << NF_NETDEV_INGRESS));
151}
152
153static struct nft_expr_type nft_reject_netdev_type;
154static const struct nft_expr_ops nft_reject_netdev_ops = {
155	.type		= &nft_reject_netdev_type,
156	.size		= NFT_EXPR_SIZE(sizeof(struct nft_reject)),
157	.eval		= nft_reject_netdev_eval,
158	.init		= nft_reject_init,
159	.dump		= nft_reject_dump,
160	.validate	= nft_reject_netdev_validate,
161	.reduce		= NFT_REDUCE_READONLY,
162};
163
164static struct nft_expr_type nft_reject_netdev_type __read_mostly = {
165	.family		= NFPROTO_NETDEV,
166	.name		= "reject",
167	.ops		= &nft_reject_netdev_ops,
168	.policy		= nft_reject_policy,
169	.maxattr	= NFTA_REJECT_MAX,
170	.owner		= THIS_MODULE,
171};
172
173static int __init nft_reject_netdev_module_init(void)
174{
175	return nft_register_expr(&nft_reject_netdev_type);
176}
177
178static void __exit nft_reject_netdev_module_exit(void)
179{
180	nft_unregister_expr(&nft_reject_netdev_type);
181}
182
183module_init(nft_reject_netdev_module_init);
184module_exit(nft_reject_netdev_module_exit);
185
186MODULE_LICENSE("GPL");
187MODULE_AUTHOR("Laura Garcia Liebana <nevola@gmail.com>");
188MODULE_AUTHOR("Jose M. Guisado <guigom@riseup.net>");
189MODULE_DESCRIPTION("Reject packets from netdev via nftables");
190MODULE_ALIAS_NFT_AF_EXPR(5, "reject");
~/ Read-only file preview.