0001
0002 #include <linux/module.h>
0003 #include <linux/netfilter/nf_tables.h>
0004 #include <net/netfilter/nf_tables.h>
0005 #include <net/netfilter/nf_tables_core.h>
0006 #include <net/netfilter/nf_tproxy.h>
0007 #include <net/inet_sock.h>
0008 #include <net/tcp.h>
0009 #include <linux/if_ether.h>
0010 #include <net/netfilter/ipv4/nf_defrag_ipv4.h>
0011 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
0012 #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
0013 #endif
0014
0015 struct nft_tproxy {
0016 u8 sreg_addr;
0017 u8 sreg_port;
0018 u8 family;
0019 };
0020
0021 static void nft_tproxy_eval_v4(const struct nft_expr *expr,
0022 struct nft_regs *regs,
0023 const struct nft_pktinfo *pkt)
0024 {
0025 const struct nft_tproxy *priv = nft_expr_priv(expr);
0026 struct sk_buff *skb = pkt->skb;
0027 const struct iphdr *iph = ip_hdr(skb);
0028 struct udphdr _hdr, *hp;
0029 __be32 taddr = 0;
0030 __be16 tport = 0;
0031 struct sock *sk;
0032
0033 if (pkt->tprot != IPPROTO_TCP &&
0034 pkt->tprot != IPPROTO_UDP) {
0035 regs->verdict.code = NFT_BREAK;
0036 return;
0037 }
0038
0039 hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr);
0040 if (!hp) {
0041 regs->verdict.code = NFT_BREAK;
0042 return;
0043 }
0044
0045
0046
0047
0048
0049 sk = nf_tproxy_get_sock_v4(nft_net(pkt), skb, iph->protocol,
0050 iph->saddr, iph->daddr,
0051 hp->source, hp->dest,
0052 skb->dev, NF_TPROXY_LOOKUP_ESTABLISHED);
0053
0054 if (priv->sreg_addr)
0055 taddr = nft_reg_load_be32(®s->data[priv->sreg_addr]);
0056 taddr = nf_tproxy_laddr4(skb, taddr, iph->daddr);
0057
0058 if (priv->sreg_port)
0059 tport = nft_reg_load_be16(®s->data[priv->sreg_port]);
0060 if (!tport)
0061 tport = hp->dest;
0062
0063
0064 if (sk && sk->sk_state == TCP_TIME_WAIT) {
0065
0066 sk = nf_tproxy_handle_time_wait4(nft_net(pkt), skb, taddr, tport, sk);
0067 } else if (!sk) {
0068
0069
0070
0071 sk = nf_tproxy_get_sock_v4(nft_net(pkt), skb, iph->protocol,
0072 iph->saddr, taddr,
0073 hp->source, tport,
0074 skb->dev, NF_TPROXY_LOOKUP_LISTENER);
0075 }
0076
0077 if (sk && nf_tproxy_sk_is_transparent(sk))
0078 nf_tproxy_assign_sock(skb, sk);
0079 else
0080 regs->verdict.code = NFT_BREAK;
0081 }
0082
0083 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
0084 static void nft_tproxy_eval_v6(const struct nft_expr *expr,
0085 struct nft_regs *regs,
0086 const struct nft_pktinfo *pkt)
0087 {
0088 const struct nft_tproxy *priv = nft_expr_priv(expr);
0089 struct sk_buff *skb = pkt->skb;
0090 const struct ipv6hdr *iph = ipv6_hdr(skb);
0091 int thoff = nft_thoff(pkt);
0092 struct udphdr _hdr, *hp;
0093 struct in6_addr taddr;
0094 __be16 tport = 0;
0095 struct sock *sk;
0096 int l4proto;
0097
0098 memset(&taddr, 0, sizeof(taddr));
0099
0100 if (pkt->tprot != IPPROTO_TCP &&
0101 pkt->tprot != IPPROTO_UDP) {
0102 regs->verdict.code = NFT_BREAK;
0103 return;
0104 }
0105 l4proto = pkt->tprot;
0106
0107 hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
0108 if (hp == NULL) {
0109 regs->verdict.code = NFT_BREAK;
0110 return;
0111 }
0112
0113
0114
0115
0116
0117 sk = nf_tproxy_get_sock_v6(nft_net(pkt), skb, thoff, l4proto,
0118 &iph->saddr, &iph->daddr,
0119 hp->source, hp->dest,
0120 nft_in(pkt), NF_TPROXY_LOOKUP_ESTABLISHED);
0121
0122 if (priv->sreg_addr)
0123 memcpy(&taddr, ®s->data[priv->sreg_addr], sizeof(taddr));
0124 taddr = *nf_tproxy_laddr6(skb, &taddr, &iph->daddr);
0125
0126 if (priv->sreg_port)
0127 tport = nft_reg_load_be16(®s->data[priv->sreg_port]);
0128 if (!tport)
0129 tport = hp->dest;
0130
0131
0132 if (sk && sk->sk_state == TCP_TIME_WAIT) {
0133
0134 sk = nf_tproxy_handle_time_wait6(skb, l4proto, thoff,
0135 nft_net(pkt),
0136 &taddr,
0137 tport,
0138 sk);
0139 } else if (!sk) {
0140
0141
0142
0143 sk = nf_tproxy_get_sock_v6(nft_net(pkt), skb, thoff,
0144 l4proto, &iph->saddr, &taddr,
0145 hp->source, tport,
0146 nft_in(pkt), NF_TPROXY_LOOKUP_LISTENER);
0147 }
0148
0149
0150 if (sk && nf_tproxy_sk_is_transparent(sk))
0151 nf_tproxy_assign_sock(skb, sk);
0152 else
0153 regs->verdict.code = NFT_BREAK;
0154 }
0155 #endif
0156
0157 static void nft_tproxy_eval(const struct nft_expr *expr,
0158 struct nft_regs *regs,
0159 const struct nft_pktinfo *pkt)
0160 {
0161 const struct nft_tproxy *priv = nft_expr_priv(expr);
0162
0163 switch (nft_pf(pkt)) {
0164 case NFPROTO_IPV4:
0165 switch (priv->family) {
0166 case NFPROTO_IPV4:
0167 case NFPROTO_UNSPEC:
0168 nft_tproxy_eval_v4(expr, regs, pkt);
0169 return;
0170 }
0171 break;
0172 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
0173 case NFPROTO_IPV6:
0174 switch (priv->family) {
0175 case NFPROTO_IPV6:
0176 case NFPROTO_UNSPEC:
0177 nft_tproxy_eval_v6(expr, regs, pkt);
0178 return;
0179 }
0180 #endif
0181 }
0182 regs->verdict.code = NFT_BREAK;
0183 }
0184
0185 static const struct nla_policy nft_tproxy_policy[NFTA_TPROXY_MAX + 1] = {
0186 [NFTA_TPROXY_FAMILY] = { .type = NLA_U32 },
0187 [NFTA_TPROXY_REG_ADDR] = { .type = NLA_U32 },
0188 [NFTA_TPROXY_REG_PORT] = { .type = NLA_U32 },
0189 };
0190
0191 static int nft_tproxy_init(const struct nft_ctx *ctx,
0192 const struct nft_expr *expr,
0193 const struct nlattr * const tb[])
0194 {
0195 struct nft_tproxy *priv = nft_expr_priv(expr);
0196 unsigned int alen = 0;
0197 int err;
0198
0199 if (!tb[NFTA_TPROXY_FAMILY] ||
0200 (!tb[NFTA_TPROXY_REG_ADDR] && !tb[NFTA_TPROXY_REG_PORT]))
0201 return -EINVAL;
0202
0203 priv->family = ntohl(nla_get_be32(tb[NFTA_TPROXY_FAMILY]));
0204
0205 switch (ctx->family) {
0206 case NFPROTO_IPV4:
0207 if (priv->family != NFPROTO_IPV4)
0208 return -EINVAL;
0209 break;
0210 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
0211 case NFPROTO_IPV6:
0212 if (priv->family != NFPROTO_IPV6)
0213 return -EINVAL;
0214 break;
0215 #endif
0216 case NFPROTO_INET:
0217 break;
0218 default:
0219 return -EOPNOTSUPP;
0220 }
0221
0222
0223 if (priv->family == NFPROTO_UNSPEC && tb[NFTA_TPROXY_REG_ADDR])
0224 return -EINVAL;
0225
0226 switch (priv->family) {
0227 case NFPROTO_IPV4:
0228 alen = sizeof_field(union nf_inet_addr, in);
0229 err = nf_defrag_ipv4_enable(ctx->net);
0230 if (err)
0231 return err;
0232 break;
0233 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
0234 case NFPROTO_IPV6:
0235 alen = sizeof_field(union nf_inet_addr, in6);
0236 err = nf_defrag_ipv6_enable(ctx->net);
0237 if (err)
0238 return err;
0239 break;
0240 #endif
0241 case NFPROTO_UNSPEC:
0242
0243 err = nf_defrag_ipv4_enable(ctx->net);
0244 if (err)
0245 return err;
0246 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
0247 err = nf_defrag_ipv6_enable(ctx->net);
0248 if (err)
0249 return err;
0250 #endif
0251 break;
0252 default:
0253 return -EOPNOTSUPP;
0254 }
0255
0256 if (tb[NFTA_TPROXY_REG_ADDR]) {
0257 err = nft_parse_register_load(tb[NFTA_TPROXY_REG_ADDR],
0258 &priv->sreg_addr, alen);
0259 if (err < 0)
0260 return err;
0261 }
0262
0263 if (tb[NFTA_TPROXY_REG_PORT]) {
0264 err = nft_parse_register_load(tb[NFTA_TPROXY_REG_PORT],
0265 &priv->sreg_port, sizeof(u16));
0266 if (err < 0)
0267 return err;
0268 }
0269
0270 return 0;
0271 }
0272
0273 static void nft_tproxy_destroy(const struct nft_ctx *ctx,
0274 const struct nft_expr *expr)
0275 {
0276 const struct nft_tproxy *priv = nft_expr_priv(expr);
0277
0278 switch (priv->family) {
0279 case NFPROTO_IPV4:
0280 nf_defrag_ipv4_disable(ctx->net);
0281 break;
0282 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
0283 case NFPROTO_IPV6:
0284 nf_defrag_ipv6_disable(ctx->net);
0285 break;
0286 #endif
0287 case NFPROTO_UNSPEC:
0288 nf_defrag_ipv4_disable(ctx->net);
0289 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
0290 nf_defrag_ipv6_disable(ctx->net);
0291 #endif
0292 break;
0293 }
0294 }
0295
0296 static int nft_tproxy_dump(struct sk_buff *skb,
0297 const struct nft_expr *expr)
0298 {
0299 const struct nft_tproxy *priv = nft_expr_priv(expr);
0300
0301 if (nla_put_be32(skb, NFTA_TPROXY_FAMILY, htonl(priv->family)))
0302 return -1;
0303
0304 if (priv->sreg_addr &&
0305 nft_dump_register(skb, NFTA_TPROXY_REG_ADDR, priv->sreg_addr))
0306 return -1;
0307
0308 if (priv->sreg_port &&
0309 nft_dump_register(skb, NFTA_TPROXY_REG_PORT, priv->sreg_port))
0310 return -1;
0311
0312 return 0;
0313 }
0314
0315 static int nft_tproxy_validate(const struct nft_ctx *ctx,
0316 const struct nft_expr *expr,
0317 const struct nft_data **data)
0318 {
0319 return nft_chain_validate_hooks(ctx->chain, 1 << NF_INET_PRE_ROUTING);
0320 }
0321
0322 static struct nft_expr_type nft_tproxy_type;
0323 static const struct nft_expr_ops nft_tproxy_ops = {
0324 .type = &nft_tproxy_type,
0325 .size = NFT_EXPR_SIZE(sizeof(struct nft_tproxy)),
0326 .eval = nft_tproxy_eval,
0327 .init = nft_tproxy_init,
0328 .destroy = nft_tproxy_destroy,
0329 .dump = nft_tproxy_dump,
0330 .reduce = NFT_REDUCE_READONLY,
0331 .validate = nft_tproxy_validate,
0332 };
0333
0334 static struct nft_expr_type nft_tproxy_type __read_mostly = {
0335 .name = "tproxy",
0336 .ops = &nft_tproxy_ops,
0337 .policy = nft_tproxy_policy,
0338 .maxattr = NFTA_TPROXY_MAX,
0339 .owner = THIS_MODULE,
0340 };
0341
0342 static int __init nft_tproxy_module_init(void)
0343 {
0344 return nft_register_expr(&nft_tproxy_type);
0345 }
0346
0347 static void __exit nft_tproxy_module_exit(void)
0348 {
0349 nft_unregister_expr(&nft_tproxy_type);
0350 }
0351
0352 module_init(nft_tproxy_module_init);
0353 module_exit(nft_tproxy_module_exit);
0354
0355 MODULE_LICENSE("GPL");
0356 MODULE_AUTHOR("Máté Eckl");
0357 MODULE_DESCRIPTION("nf_tables tproxy support module");
0358 MODULE_ALIAS_NFT_EXPR("tproxy");