Commit | Line | Data |
---|---|---|
96518518 PM |
1 | /* |
2 | * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License version 2 as | |
6 | * published by the Free Software Foundation. | |
7 | * | |
8 | * Development of this code funded by Astaro AG (http://www.astaro.com/) | |
9 | */ | |
10 | ||
11 | #include <linux/kernel.h> | |
12 | #include <linux/init.h> | |
13 | #include <linux/module.h> | |
14 | #include <linux/netlink.h> | |
15 | #include <linux/netfilter.h> | |
16 | #include <linux/netfilter/nf_tables.h> | |
17 | #include <net/netfilter/nf_tables.h> | |
18 | #include <net/icmp.h> | |
19 | ||
20 | struct nft_reject { | |
21 | enum nft_reject_types type:8; | |
22 | u8 icmp_code; | |
23 | }; | |
24 | ||
25 | static void nft_reject_eval(const struct nft_expr *expr, | |
26 | struct nft_data data[NFT_REG_MAX + 1], | |
27 | const struct nft_pktinfo *pkt) | |
28 | { | |
29 | struct nft_reject *priv = nft_expr_priv(expr); | |
30 | ||
31 | switch (priv->type) { | |
32 | case NFT_REJECT_ICMP_UNREACH: | |
33 | icmp_send(pkt->skb, ICMP_DEST_UNREACH, priv->icmp_code, 0); | |
34 | break; | |
35 | case NFT_REJECT_TCP_RST: | |
36 | break; | |
37 | } | |
38 | ||
39 | data[NFT_REG_VERDICT].verdict = NF_DROP; | |
40 | } | |
41 | ||
42 | static const struct nla_policy nft_reject_policy[NFTA_REJECT_MAX + 1] = { | |
43 | [NFTA_REJECT_TYPE] = { .type = NLA_U32 }, | |
44 | [NFTA_REJECT_ICMP_CODE] = { .type = NLA_U8 }, | |
45 | }; | |
46 | ||
47 | static int nft_reject_init(const struct nft_ctx *ctx, | |
48 | const struct nft_expr *expr, | |
49 | const struct nlattr * const tb[]) | |
50 | { | |
51 | struct nft_reject *priv = nft_expr_priv(expr); | |
52 | ||
53 | if (tb[NFTA_REJECT_TYPE] == NULL) | |
54 | return -EINVAL; | |
55 | ||
56 | priv->type = ntohl(nla_get_be32(tb[NFTA_REJECT_TYPE])); | |
57 | switch (priv->type) { | |
58 | case NFT_REJECT_ICMP_UNREACH: | |
59 | if (tb[NFTA_REJECT_ICMP_CODE] == NULL) | |
60 | return -EINVAL; | |
61 | priv->icmp_code = nla_get_u8(tb[NFTA_REJECT_ICMP_CODE]); | |
62 | case NFT_REJECT_TCP_RST: | |
63 | break; | |
64 | default: | |
65 | return -EINVAL; | |
66 | } | |
67 | ||
68 | return 0; | |
69 | } | |
70 | ||
71 | static int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr) | |
72 | { | |
73 | const struct nft_reject *priv = nft_expr_priv(expr); | |
74 | ||
75 | if (nla_put_be32(skb, NFTA_REJECT_TYPE, priv->type)) | |
76 | goto nla_put_failure; | |
77 | ||
78 | switch (priv->type) { | |
79 | case NFT_REJECT_ICMP_UNREACH: | |
80 | if (nla_put_u8(skb, NFTA_REJECT_ICMP_CODE, priv->icmp_code)) | |
81 | goto nla_put_failure; | |
82 | break; | |
83 | } | |
84 | ||
85 | return 0; | |
86 | ||
87 | nla_put_failure: | |
88 | return -1; | |
89 | } | |
90 | ||
91 | static struct nft_expr_ops reject_ops __read_mostly = { | |
92 | .name = "reject", | |
93 | .size = NFT_EXPR_SIZE(sizeof(struct nft_reject)), | |
94 | .owner = THIS_MODULE, | |
95 | .eval = nft_reject_eval, | |
96 | .init = nft_reject_init, | |
97 | .dump = nft_reject_dump, | |
98 | .policy = nft_reject_policy, | |
99 | .maxattr = NFTA_REJECT_MAX, | |
100 | }; | |
101 | ||
102 | static int __init nft_reject_module_init(void) | |
103 | { | |
104 | return nft_register_expr(&reject_ops); | |
105 | } | |
106 | ||
107 | static void __exit nft_reject_module_exit(void) | |
108 | { | |
109 | nft_unregister_expr(&reject_ops); | |
110 | } | |
111 | ||
112 | module_init(nft_reject_module_init); | |
113 | module_exit(nft_reject_module_exit); | |
114 | ||
115 | MODULE_LICENSE("GPL"); | |
116 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | |
117 | MODULE_ALIAS_NFT_EXPR("reject"); |