GNU Linux-libre 4.19.286-gnu1
[releases.git] / net / netfilter / nft_osf.c
1 #include <net/ip.h>
2 #include <net/tcp.h>
3
4 #include <net/netfilter/nf_tables.h>
5 #include <linux/netfilter/nfnetlink_osf.h>
6
7 struct nft_osf {
8         u8                      dreg;
9 };
10
11 static const struct nla_policy nft_osf_policy[NFTA_OSF_MAX + 1] = {
12         [NFTA_OSF_DREG]         = { .type = NLA_U32 },
13 };
14
15 static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs,
16                          const struct nft_pktinfo *pkt)
17 {
18         struct nft_osf *priv = nft_expr_priv(expr);
19         u32 *dest = &regs->data[priv->dreg];
20         struct sk_buff *skb = pkt->skb;
21         const struct tcphdr *tcp;
22         struct tcphdr _tcph;
23         const char *os_name;
24
25         if (pkt->tprot != IPPROTO_TCP) {
26                 regs->verdict.code = NFT_BREAK;
27                 return;
28         }
29
30         tcp = skb_header_pointer(skb, ip_hdrlen(skb),
31                                  sizeof(struct tcphdr), &_tcph);
32         if (!tcp) {
33                 regs->verdict.code = NFT_BREAK;
34                 return;
35         }
36         if (!tcp->syn) {
37                 regs->verdict.code = NFT_BREAK;
38                 return;
39         }
40
41         os_name = nf_osf_find(skb, nf_osf_fingers);
42         if (!os_name)
43                 strncpy((char *)dest, "unknown", NFT_OSF_MAXGENRELEN);
44         else
45                 strncpy((char *)dest, os_name, NFT_OSF_MAXGENRELEN);
46 }
47
48 static int nft_osf_init(const struct nft_ctx *ctx,
49                         const struct nft_expr *expr,
50                         const struct nlattr * const tb[])
51 {
52         struct nft_osf *priv = nft_expr_priv(expr);
53         int err;
54
55         if (!tb[NFTA_OSF_DREG])
56                 return -EINVAL;
57
58         err = nft_parse_register_store(ctx, tb[NFTA_OSF_DREG], &priv->dreg,
59                                        NULL, NFT_DATA_VALUE,
60                                        NFT_OSF_MAXGENRELEN);
61         if (err < 0)
62                 return err;
63
64         return 0;
65 }
66
67 static int nft_osf_dump(struct sk_buff *skb, const struct nft_expr *expr)
68 {
69         const struct nft_osf *priv = nft_expr_priv(expr);
70
71         if (nft_dump_register(skb, NFTA_OSF_DREG, priv->dreg))
72                 goto nla_put_failure;
73
74         return 0;
75
76 nla_put_failure:
77         return -1;
78 }
79
80 static int nft_osf_validate(const struct nft_ctx *ctx,
81                             const struct nft_expr *expr,
82                             const struct nft_data **data)
83 {
84         unsigned int hooks;
85
86         switch (ctx->family) {
87         case NFPROTO_IPV4:
88         case NFPROTO_IPV6:
89         case NFPROTO_INET:
90                 hooks = (1 << NF_INET_LOCAL_IN) |
91                         (1 << NF_INET_PRE_ROUTING) |
92                         (1 << NF_INET_FORWARD);
93                 break;
94         default:
95                 return -EOPNOTSUPP;
96         }
97
98         return nft_chain_validate_hooks(ctx->chain, hooks);
99 }
100
101 static struct nft_expr_type nft_osf_type;
102 static const struct nft_expr_ops nft_osf_op = {
103         .eval           = nft_osf_eval,
104         .size           = NFT_EXPR_SIZE(sizeof(struct nft_osf)),
105         .init           = nft_osf_init,
106         .dump           = nft_osf_dump,
107         .type           = &nft_osf_type,
108         .validate       = nft_osf_validate,
109 };
110
111 static struct nft_expr_type nft_osf_type __read_mostly = {
112         .ops            = &nft_osf_op,
113         .name           = "osf",
114         .owner          = THIS_MODULE,
115         .policy         = nft_osf_policy,
116         .maxattr        = NFTA_OSF_MAX,
117 };
118
119 static int __init nft_osf_module_init(void)
120 {
121         return nft_register_expr(&nft_osf_type);
122 }
123
124 static void __exit nft_osf_module_exit(void)
125 {
126         return nft_unregister_expr(&nft_osf_type);
127 }
128
129 module_init(nft_osf_module_init);
130 module_exit(nft_osf_module_exit);
131
132 MODULE_LICENSE("GPL");
133 MODULE_AUTHOR("Fernando Fernandez <ffmancera@riseup.net>");
134 MODULE_ALIAS_NFT_EXPR("osf");