1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2020 Laura Garcia Liebana <nevola@gmail.com>
4 * Copyright (c) 2020 Jose M. Guisado <guigom@riseup.net>
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>
19 static void nft_reject_queue_xmit(struct sk_buff
*nskb
, struct sk_buff
*oldskb
)
21 dev_hard_header(nskb
, nskb
->dev
, ntohs(oldskb
->protocol
),
22 eth_hdr(oldskb
)->h_source
, eth_hdr(oldskb
)->h_dest
,
27 static void nft_reject_netdev_send_v4_tcp_reset(struct net
*net
,
28 struct sk_buff
*oldskb
,
29 const struct net_device
*dev
,
34 nskb
= nf_reject_skb_v4_tcp_reset(net
, oldskb
, dev
, hook
);
38 nft_reject_queue_xmit(nskb
, oldskb
);
41 static void nft_reject_netdev_send_v4_unreach(struct net
*net
,
42 struct sk_buff
*oldskb
,
43 const struct net_device
*dev
,
48 nskb
= nf_reject_skb_v4_unreach(net
, oldskb
, dev
, hook
, code
);
52 nft_reject_queue_xmit(nskb
, oldskb
);
55 static void nft_reject_netdev_send_v6_tcp_reset(struct net
*net
,
56 struct sk_buff
*oldskb
,
57 const struct net_device
*dev
,
62 nskb
= nf_reject_skb_v6_tcp_reset(net
, oldskb
, dev
, hook
);
66 nft_reject_queue_xmit(nskb
, oldskb
);
70 static void nft_reject_netdev_send_v6_unreach(struct net
*net
,
71 struct sk_buff
*oldskb
,
72 const struct net_device
*dev
,
77 nskb
= nf_reject_skb_v6_unreach(net
, oldskb
, dev
, hook
, code
);
81 nft_reject_queue_xmit(nskb
, oldskb
);
84 static void nft_reject_netdev_eval(const struct nft_expr
*expr
,
85 struct nft_regs
*regs
,
86 const struct nft_pktinfo
*pkt
)
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
;
92 if (is_broadcast_ether_addr(dest
) ||
93 is_multicast_ether_addr(dest
))
96 switch (eth
->h_proto
) {
99 case NFT_REJECT_ICMP_UNREACH
:
100 nft_reject_netdev_send_v4_unreach(nft_net(pkt
), pkt
->skb
,
105 case NFT_REJECT_TCP_RST
:
106 nft_reject_netdev_send_v4_tcp_reset(nft_net(pkt
), pkt
->skb
,
110 case NFT_REJECT_ICMPX_UNREACH
:
111 nft_reject_netdev_send_v4_unreach(nft_net(pkt
), pkt
->skb
,
114 nft_reject_icmp_code(priv
->icmp_code
));
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
,
126 case NFT_REJECT_TCP_RST
:
127 nft_reject_netdev_send_v6_tcp_reset(nft_net(pkt
), pkt
->skb
,
131 case NFT_REJECT_ICMPX_UNREACH
:
132 nft_reject_netdev_send_v6_unreach(nft_net(pkt
), pkt
->skb
,
135 nft_reject_icmpv6_code(priv
->icmp_code
));
140 /* No explicit way to reject this protocol, drop it. */
144 regs
->verdict
.code
= NF_DROP
;
147 static int nft_reject_netdev_validate(const struct nft_ctx
*ctx
,
148 const struct nft_expr
*expr
)
150 return nft_chain_validate_hooks(ctx
->chain
, (1 << NF_NETDEV_INGRESS
));
153 static struct nft_expr_type nft_reject_netdev_type
;
154 static 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
,
164 static struct nft_expr_type nft_reject_netdev_type __read_mostly
= {
165 .family
= NFPROTO_NETDEV
,
167 .ops
= &nft_reject_netdev_ops
,
168 .policy
= nft_reject_policy
,
169 .maxattr
= NFTA_REJECT_MAX
,
170 .owner
= THIS_MODULE
,
173 static int __init
nft_reject_netdev_module_init(void)
175 return nft_register_expr(&nft_reject_netdev_type
);
178 static void __exit
nft_reject_netdev_module_exit(void)
180 nft_unregister_expr(&nft_reject_netdev_type
);
183 module_init(nft_reject_netdev_module_init
);
184 module_exit(nft_reject_netdev_module_exit
);
186 MODULE_LICENSE("GPL");
187 MODULE_AUTHOR("Laura Garcia Liebana <nevola@gmail.com>");
188 MODULE_AUTHOR("Jose M. Guisado <guigom@riseup.net>");
189 MODULE_DESCRIPTION("Reject packets from netdev via nftables");
190 MODULE_ALIAS_NFT_AF_EXPR(5, "reject");