netfilter: nf_tables: implement Passive OS fingerprint module in nft_osf
[linux-block.git] / net / netfilter / nft_osf.c
CommitLineData
b96af92d
FFM
1#include <net/ip.h>
2#include <net/tcp.h>
3
4#include <net/netfilter/nf_tables.h>
5#include <linux/netfilter/nf_osf.h>
6
7#define OSF_GENRE_SIZE 32
8
9struct nft_osf {
10 enum nft_registers dreg:8;
11};
12
13static const struct nla_policy nft_osf_policy[NFTA_OSF_MAX + 1] = {
14 [NFTA_OSF_DREG] = { .type = NLA_U32 },
15};
16
17static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs,
18 const struct nft_pktinfo *pkt)
19{
20 struct nft_osf *priv = nft_expr_priv(expr);
21 u32 *dest = &regs->data[priv->dreg];
22 struct sk_buff *skb = pkt->skb;
23 const struct tcphdr *tcp;
24 struct tcphdr _tcph;
25 const char *os_name;
26
27 tcp = skb_header_pointer(skb, ip_hdrlen(skb),
28 sizeof(struct tcphdr), &_tcph);
29 if (!tcp) {
30 regs->verdict.code = NFT_BREAK;
31 return;
32 }
33 if (!tcp->syn) {
34 regs->verdict.code = NFT_BREAK;
35 return;
36 }
37
38 os_name = nf_osf_find(skb, nf_osf_fingers);
39 if (!os_name)
40 strncpy((char *)dest, "unknown", IFNAMSIZ);
41 else
42 strncpy((char *)dest, os_name, IFNAMSIZ);
43}
44
45static int nft_osf_init(const struct nft_ctx *ctx,
46 const struct nft_expr *expr,
47 const struct nlattr * const tb[])
48{
49 struct nft_osf *priv = nft_expr_priv(expr);
50 int err;
51
52 priv->dreg = nft_parse_register(tb[NFTA_OSF_DREG]);
53 err = nft_validate_register_store(ctx, priv->dreg, NULL,
54 NFTA_DATA_VALUE, OSF_GENRE_SIZE);
55 if (err < 0)
56 return err;
57
58 return 0;
59}
60
61static int nft_osf_dump(struct sk_buff *skb, const struct nft_expr *expr)
62{
63 const struct nft_osf *priv = nft_expr_priv(expr);
64
65 if (nft_dump_register(skb, NFTA_OSF_DREG, priv->dreg))
66 goto nla_put_failure;
67
68 return 0;
69
70nla_put_failure:
71 return -1;
72}
73
74static struct nft_expr_type nft_osf_type;
75static const struct nft_expr_ops nft_osf_op = {
76 .eval = nft_osf_eval,
77 .size = NFT_EXPR_SIZE(sizeof(struct nft_osf)),
78 .init = nft_osf_init,
79 .dump = nft_osf_dump,
80 .type = &nft_osf_type,
81};
82
83static struct nft_expr_type nft_osf_type __read_mostly = {
84 .ops = &nft_osf_op,
85 .name = "osf",
86 .owner = THIS_MODULE,
87 .policy = nft_osf_policy,
88 .maxattr = NFTA_OSF_MAX,
89};
90
91static int __init nft_osf_module_init(void)
92{
93 return nft_register_expr(&nft_osf_type);
94}
95
96static void __exit nft_osf_module_exit(void)
97{
98 return nft_unregister_expr(&nft_osf_type);
99}
100
101module_init(nft_osf_module_init);
102module_exit(nft_osf_module_exit);
103
104MODULE_LICENSE("GPL");
105MODULE_AUTHOR("Fernando Fernandez <ffmancera@riseup.net>");
106MODULE_ALIAS_NFT_EXPR("osf");