File Index
Files and directories
Sign in
FILE

nft_reject_bridge.c

File preview with syntax highlighting.

linux-6.19.14/net/bridge/netfilter/nft_reject_bridge.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2014 Pablo Neira Ayuso <pablo@netfilter.org>
  4 */
  5
  6#include <linux/kernel.h>
  7#include <linux/init.h>
  8#include <linux/module.h>
  9#include <linux/netlink.h>
 10#include <linux/netfilter.h>
 11#include <linux/netfilter/nf_tables.h>
 12#include <net/netfilter/nf_tables.h>
 13#include <net/netfilter/nft_reject.h>
 14#include <net/netfilter/ipv4/nf_reject.h>
 15#include <net/netfilter/ipv6/nf_reject.h>
 16#include <linux/ip.h>
 17#include <net/ip.h>
 18#include <net/ip6_checksum.h>
 19#include <linux/netfilter_bridge.h>
 20#include <linux/netfilter_ipv6.h>
 21#include "../br_private.h"
 22
 23static void nft_reject_br_push_etherhdr(struct sk_buff *oldskb,
 24					struct sk_buff *nskb)
 25{
 26	struct ethhdr *eth;
 27
 28	eth = skb_push(nskb, ETH_HLEN);
 29	skb_reset_mac_header(nskb);
 30	ether_addr_copy(eth->h_source, eth_hdr(oldskb)->h_dest);
 31	ether_addr_copy(eth->h_dest, eth_hdr(oldskb)->h_source);
 32	eth->h_proto = eth_hdr(oldskb)->h_proto;
 33	skb_pull(nskb, ETH_HLEN);
 34
 35	if (skb_vlan_tag_present(oldskb)) {
 36		u16 vid = skb_vlan_tag_get(oldskb);
 37
 38		__vlan_hwaccel_put_tag(nskb, oldskb->vlan_proto, vid);
 39	}
 40}
 41
 42/* We cannot use oldskb->dev, it can be either bridge device (NF_BRIDGE INPUT)
 43 * or the bridge port (NF_BRIDGE PREROUTING).
 44 */
 45static void nft_reject_br_send_v4_tcp_reset(struct net *net,
 46					    struct sk_buff *oldskb,
 47					    const struct net_device *dev,
 48					    int hook)
 49{
 50	struct sk_buff *nskb;
 51
 52	nskb = nf_reject_skb_v4_tcp_reset(net, oldskb, NULL, hook);
 53	if (!nskb)
 54		return;
 55
 56	nft_reject_br_push_etherhdr(oldskb, nskb);
 57
 58	br_forward(br_port_get_rcu(dev), nskb, false, true);
 59}
 60
 61static void nft_reject_br_send_v4_unreach(struct net *net,
 62					  struct sk_buff *oldskb,
 63					  const struct net_device *dev,
 64					  int hook, u8 code)
 65{
 66	struct sk_buff *nskb;
 67
 68	nskb = nf_reject_skb_v4_unreach(net, oldskb, NULL, hook, code);
 69	if (!nskb)
 70		return;
 71
 72	nft_reject_br_push_etherhdr(oldskb, nskb);
 73
 74	br_forward(br_port_get_rcu(dev), nskb, false, true);
 75}
 76
 77static void nft_reject_br_send_v6_tcp_reset(struct net *net,
 78					    struct sk_buff *oldskb,
 79					    const struct net_device *dev,
 80					    int hook)
 81{
 82	struct sk_buff *nskb;
 83
 84	nskb = nf_reject_skb_v6_tcp_reset(net, oldskb, NULL, hook);
 85	if (!nskb)
 86		return;
 87
 88	nft_reject_br_push_etherhdr(oldskb, nskb);
 89
 90	br_forward(br_port_get_rcu(dev), nskb, false, true);
 91}
 92
 93
 94static void nft_reject_br_send_v6_unreach(struct net *net,
 95					  struct sk_buff *oldskb,
 96					  const struct net_device *dev,
 97					  int hook, u8 code)
 98{
 99	struct sk_buff *nskb;
100
101	nskb = nf_reject_skb_v6_unreach(net, oldskb, NULL, hook, code);
102	if (!nskb)
103		return;
104
105	nft_reject_br_push_etherhdr(oldskb, nskb);
106
107	br_forward(br_port_get_rcu(dev), nskb, false, true);
108}
109
110static void nft_reject_bridge_eval(const struct nft_expr *expr,
111				   struct nft_regs *regs,
112				   const struct nft_pktinfo *pkt)
113{
114	struct nft_reject *priv = nft_expr_priv(expr);
115	const unsigned char *dest = eth_hdr(pkt->skb)->h_dest;
116
117	if (is_broadcast_ether_addr(dest) ||
118	    is_multicast_ether_addr(dest))
119		goto out;
120
121	switch (eth_hdr(pkt->skb)->h_proto) {
122	case htons(ETH_P_IP):
123		switch (priv->type) {
124		case NFT_REJECT_ICMP_UNREACH:
125			nft_reject_br_send_v4_unreach(nft_net(pkt), pkt->skb,
126						      nft_in(pkt),
127						      nft_hook(pkt),
128						      priv->icmp_code);
129			break;
130		case NFT_REJECT_TCP_RST:
131			nft_reject_br_send_v4_tcp_reset(nft_net(pkt), pkt->skb,
132							nft_in(pkt),
133							nft_hook(pkt));
134			break;
135		case NFT_REJECT_ICMPX_UNREACH:
136			nft_reject_br_send_v4_unreach(nft_net(pkt), pkt->skb,
137						      nft_in(pkt),
138						      nft_hook(pkt),
139						      nft_reject_icmp_code(priv->icmp_code));
140			break;
141		}
142		break;
143	case htons(ETH_P_IPV6):
144		switch (priv->type) {
145		case NFT_REJECT_ICMP_UNREACH:
146			nft_reject_br_send_v6_unreach(nft_net(pkt), pkt->skb,
147						      nft_in(pkt),
148						      nft_hook(pkt),
149						      priv->icmp_code);
150			break;
151		case NFT_REJECT_TCP_RST:
152			nft_reject_br_send_v6_tcp_reset(nft_net(pkt), pkt->skb,
153							nft_in(pkt),
154							nft_hook(pkt));
155			break;
156		case NFT_REJECT_ICMPX_UNREACH:
157			nft_reject_br_send_v6_unreach(nft_net(pkt), pkt->skb,
158						      nft_in(pkt),
159						      nft_hook(pkt),
160						      nft_reject_icmpv6_code(priv->icmp_code));
161			break;
162		}
163		break;
164	default:
165		/* No explicit way to reject this protocol, drop it. */
166		break;
167	}
168out:
169	regs->verdict.code = NF_DROP;
170}
171
172static int nft_reject_bridge_validate(const struct nft_ctx *ctx,
173				      const struct nft_expr *expr)
174{
175	return nft_chain_validate_hooks(ctx->chain, (1 << NF_BR_PRE_ROUTING) |
176						    (1 << NF_BR_LOCAL_IN));
177}
178
179static struct nft_expr_type nft_reject_bridge_type;
180static const struct nft_expr_ops nft_reject_bridge_ops = {
181	.type		= &nft_reject_bridge_type,
182	.size		= NFT_EXPR_SIZE(sizeof(struct nft_reject)),
183	.eval		= nft_reject_bridge_eval,
184	.init		= nft_reject_init,
185	.dump		= nft_reject_dump,
186	.validate	= nft_reject_bridge_validate,
187	.reduce		= NFT_REDUCE_READONLY,
188};
189
190static struct nft_expr_type nft_reject_bridge_type __read_mostly = {
191	.family		= NFPROTO_BRIDGE,
192	.name		= "reject",
193	.ops		= &nft_reject_bridge_ops,
194	.policy		= nft_reject_policy,
195	.maxattr	= NFTA_REJECT_MAX,
196	.owner		= THIS_MODULE,
197};
198
199static int __init nft_reject_bridge_module_init(void)
200{
201	return nft_register_expr(&nft_reject_bridge_type);
202}
203
204static void __exit nft_reject_bridge_module_exit(void)
205{
206	nft_unregister_expr(&nft_reject_bridge_type);
207}
208
209module_init(nft_reject_bridge_module_init);
210module_exit(nft_reject_bridge_module_exit);
211
212MODULE_LICENSE("GPL");
213MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
214MODULE_ALIAS_NFT_AF_EXPR(AF_BRIDGE, "reject");
215MODULE_DESCRIPTION("Reject packets from bridge via nftables");
~/ Read-only file preview.