Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 168 lines 3.9 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2#include <net/ip.h> 3#include <net/tcp.h> 4 5#include <net/netfilter/nf_tables.h> 6#include <linux/netfilter/nfnetlink_osf.h> 7 8struct nft_osf { 9 u8 dreg; 10 u8 ttl; 11 u32 flags; 12}; 13 14static const struct nla_policy nft_osf_policy[NFTA_OSF_MAX + 1] = { 15 [NFTA_OSF_DREG] = NLA_POLICY_MAX(NLA_BE32, NFT_REG32_MAX), 16 [NFTA_OSF_TTL] = { .type = NLA_U8 }, 17 [NFTA_OSF_FLAGS] = NLA_POLICY_MASK(NLA_BE32, NFT_OSF_F_VERSION), 18}; 19 20static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs, 21 const struct nft_pktinfo *pkt) 22{ 23 struct nft_osf *priv = nft_expr_priv(expr); 24 u32 *dest = &regs->data[priv->dreg]; 25 struct sk_buff *skb = pkt->skb; 26 char os_match[NFT_OSF_MAXGENRELEN]; 27 const struct tcphdr *tcp; 28 struct nf_osf_data data; 29 struct tcphdr _tcph; 30 31 if (nft_pf(pkt) != NFPROTO_IPV4) { 32 regs->verdict.code = NFT_BREAK; 33 return; 34 } 35 36 if (pkt->tprot != IPPROTO_TCP) { 37 regs->verdict.code = NFT_BREAK; 38 return; 39 } 40 41 tcp = skb_header_pointer(skb, ip_hdrlen(skb), 42 sizeof(struct tcphdr), &_tcph); 43 if (!tcp) { 44 regs->verdict.code = NFT_BREAK; 45 return; 46 } 47 if (!tcp->syn) { 48 regs->verdict.code = NFT_BREAK; 49 return; 50 } 51 52 if (!nf_osf_find(skb, nf_osf_fingers, priv->ttl, &data)) { 53 strscpy_pad((char *)dest, "unknown", NFT_OSF_MAXGENRELEN); 54 } else { 55 if (priv->flags & NFT_OSF_F_VERSION) 56 snprintf(os_match, NFT_OSF_MAXGENRELEN, "%s:%s", 57 data.genre, data.version); 58 else 59 strscpy(os_match, data.genre, NFT_OSF_MAXGENRELEN); 60 61 strscpy_pad((char *)dest, os_match, NFT_OSF_MAXGENRELEN); 62 } 63} 64 65static int nft_osf_init(const struct nft_ctx *ctx, 66 const struct nft_expr *expr, 67 const struct nlattr * const tb[]) 68{ 69 struct nft_osf *priv = nft_expr_priv(expr); 70 u32 flags; 71 u8 ttl; 72 73 if (!tb[NFTA_OSF_DREG]) 74 return -EINVAL; 75 76 if (tb[NFTA_OSF_TTL]) { 77 ttl = nla_get_u8(tb[NFTA_OSF_TTL]); 78 if (ttl > 2) 79 return -EINVAL; 80 priv->ttl = ttl; 81 } 82 83 if (tb[NFTA_OSF_FLAGS]) { 84 flags = ntohl(nla_get_be32(tb[NFTA_OSF_FLAGS])); 85 if (flags != NFT_OSF_F_VERSION) 86 return -EINVAL; 87 priv->flags = flags; 88 } 89 90 return nft_parse_register_store(ctx, tb[NFTA_OSF_DREG], &priv->dreg, 91 NULL, NFT_DATA_VALUE, 92 NFT_OSF_MAXGENRELEN); 93} 94 95static int nft_osf_dump(struct sk_buff *skb, 96 const struct nft_expr *expr, bool reset) 97{ 98 const struct nft_osf *priv = nft_expr_priv(expr); 99 100 if (nla_put_u8(skb, NFTA_OSF_TTL, priv->ttl)) 101 goto nla_put_failure; 102 103 if (nla_put_u32(skb, NFTA_OSF_FLAGS, ntohl((__force __be32)priv->flags))) 104 goto nla_put_failure; 105 106 if (nft_dump_register(skb, NFTA_OSF_DREG, priv->dreg)) 107 goto nla_put_failure; 108 109 return 0; 110 111nla_put_failure: 112 return -1; 113} 114 115static int nft_osf_validate(const struct nft_ctx *ctx, 116 const struct nft_expr *expr) 117{ 118 unsigned int hooks; 119 120 switch (ctx->family) { 121 case NFPROTO_IPV4: 122 case NFPROTO_INET: 123 hooks = (1 << NF_INET_LOCAL_IN) | 124 (1 << NF_INET_PRE_ROUTING) | 125 (1 << NF_INET_FORWARD); 126 break; 127 default: 128 return -EOPNOTSUPP; 129 } 130 131 return nft_chain_validate_hooks(ctx->chain, hooks); 132} 133 134static struct nft_expr_type nft_osf_type; 135static const struct nft_expr_ops nft_osf_op = { 136 .eval = nft_osf_eval, 137 .size = NFT_EXPR_SIZE(sizeof(struct nft_osf)), 138 .init = nft_osf_init, 139 .dump = nft_osf_dump, 140 .type = &nft_osf_type, 141 .validate = nft_osf_validate, 142}; 143 144static struct nft_expr_type nft_osf_type __read_mostly = { 145 .ops = &nft_osf_op, 146 .name = "osf", 147 .owner = THIS_MODULE, 148 .policy = nft_osf_policy, 149 .maxattr = NFTA_OSF_MAX, 150}; 151 152static int __init nft_osf_module_init(void) 153{ 154 return nft_register_expr(&nft_osf_type); 155} 156 157static void __exit nft_osf_module_exit(void) 158{ 159 return nft_unregister_expr(&nft_osf_type); 160} 161 162module_init(nft_osf_module_init); 163module_exit(nft_osf_module_exit); 164 165MODULE_LICENSE("GPL"); 166MODULE_AUTHOR("Fernando Fernandez <ffmancera@riseup.net>"); 167MODULE_ALIAS_NFT_EXPR("osf"); 168MODULE_DESCRIPTION("nftables passive OS fingerprint support");