1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #include <linux/module.h> 3 #include <linux/netfilter/nf_tables.h> 4 #include <net/netfilter/nf_tables.h> 5 #include <net/netfilter/nf_tables_core.h> 6 #include <net/netfilter/nf_tproxy.h> 7 #include <net/inet_sock.h> 8 #include <net/tcp.h> 9 #include <linux/if_ether.h> 10 #include <net/netfilter/ipv4/nf_defrag_ipv4.h> 11 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) 12 #include <net/netfilter/ipv6/nf_defrag_ipv6.h> 13 #endif 14 15 struct nft_tproxy { 16 enum nft_registers sreg_addr:8; 17 enum nft_registers sreg_port:8; 18 u8 family; 19 }; 20 21 static void nft_tproxy_eval_v4(const struct nft_expr *expr, 22 struct nft_regs *regs, 23 const struct nft_pktinfo *pkt) 24 { 25 const struct nft_tproxy *priv = nft_expr_priv(expr); 26 struct sk_buff *skb = pkt->skb; 27 const struct iphdr *iph = ip_hdr(skb); 28 struct udphdr _hdr, *hp; 29 __be32 taddr = 0; 30 __be16 tport = 0; 31 struct sock *sk; 32 33 hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr); 34 if (!hp) { 35 regs->verdict.code = NFT_BREAK; 36 return; 37 } 38 39 /* check if there's an ongoing connection on the packet addresses, this 40 * happens if the redirect already happened and the current packet 41 * belongs to an already established connection 42 */ 43 sk = nf_tproxy_get_sock_v4(nft_net(pkt), skb, iph->protocol, 44 iph->saddr, iph->daddr, 45 hp->source, hp->dest, 46 skb->dev, NF_TPROXY_LOOKUP_ESTABLISHED); 47 48 if (priv->sreg_addr) 49 taddr = regs->data[priv->sreg_addr]; 50 taddr = nf_tproxy_laddr4(skb, taddr, iph->daddr); 51 52 if (priv->sreg_port) 53 tport = regs->data[priv->sreg_port]; 54 if (!tport) 55 tport = hp->dest; 56 57 /* UDP has no TCP_TIME_WAIT state, so we never enter here */ 58 if (sk && sk->sk_state == TCP_TIME_WAIT) { 59 /* reopening a TIME_WAIT connection needs special handling */ 60 sk = nf_tproxy_handle_time_wait4(nft_net(pkt), skb, taddr, tport, sk); 61 } else if (!sk) { 62 /* no, there's no established connection, check if 63 * there's a listener on the redirected addr/port 64 */ 65 sk = nf_tproxy_get_sock_v4(nft_net(pkt), skb, iph->protocol, 66 iph->saddr, taddr, 67 hp->source, tport, 68 skb->dev, NF_TPROXY_LOOKUP_LISTENER); 69 } 70 71 if (sk && nf_tproxy_sk_is_transparent(sk)) 72 nf_tproxy_assign_sock(skb, sk); 73 else 74 regs->verdict.code = NFT_BREAK; 75 } 76 77 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) 78 static void nft_tproxy_eval_v6(const struct nft_expr *expr, 79 struct nft_regs *regs, 80 const struct nft_pktinfo *pkt) 81 { 82 const struct nft_tproxy *priv = nft_expr_priv(expr); 83 struct sk_buff *skb = pkt->skb; 84 const struct ipv6hdr *iph = ipv6_hdr(skb); 85 struct in6_addr taddr; 86 int thoff = pkt->xt.thoff; 87 struct udphdr _hdr, *hp; 88 __be16 tport = 0; 89 struct sock *sk; 90 int l4proto; 91 92 memset(&taddr, 0, sizeof(taddr)); 93 94 if (!pkt->tprot_set) { 95 regs->verdict.code = NFT_BREAK; 96 return; 97 } 98 l4proto = pkt->tprot; 99 100 hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr); 101 if (hp == NULL) { 102 regs->verdict.code = NFT_BREAK; 103 return; 104 } 105 106 /* check if there's an ongoing connection on the packet addresses, this 107 * happens if the redirect already happened and the current packet 108 * belongs to an already established connection 109 */ 110 sk = nf_tproxy_get_sock_v6(nft_net(pkt), skb, thoff, l4proto, 111 &iph->saddr, &iph->daddr, 112 hp->source, hp->dest, 113 nft_in(pkt), NF_TPROXY_LOOKUP_ESTABLISHED); 114 115 if (priv->sreg_addr) 116 memcpy(&taddr, ®s->data[priv->sreg_addr], sizeof(taddr)); 117 taddr = *nf_tproxy_laddr6(skb, &taddr, &iph->daddr); 118 119 if (priv->sreg_port) 120 tport = regs->data[priv->sreg_port]; 121 if (!tport) 122 tport = hp->dest; 123 124 /* UDP has no TCP_TIME_WAIT state, so we never enter here */ 125 if (sk && sk->sk_state == TCP_TIME_WAIT) { 126 /* reopening a TIME_WAIT connection needs special handling */ 127 sk = nf_tproxy_handle_time_wait6(skb, l4proto, thoff, 128 nft_net(pkt), 129 &taddr, 130 tport, 131 sk); 132 } else if (!sk) { 133 /* no there's no established connection, check if 134 * there's a listener on the redirected addr/port 135 */ 136 sk = nf_tproxy_get_sock_v6(nft_net(pkt), skb, thoff, 137 l4proto, &iph->saddr, &taddr, 138 hp->source, tport, 139 nft_in(pkt), NF_TPROXY_LOOKUP_LISTENER); 140 } 141 142 /* NOTE: assign_sock consumes our sk reference */ 143 if (sk && nf_tproxy_sk_is_transparent(sk)) 144 nf_tproxy_assign_sock(skb, sk); 145 else 146 regs->verdict.code = NFT_BREAK; 147 } 148 #endif 149 150 static void nft_tproxy_eval(const struct nft_expr *expr, 151 struct nft_regs *regs, 152 const struct nft_pktinfo *pkt) 153 { 154 const struct nft_tproxy *priv = nft_expr_priv(expr); 155 156 switch (nft_pf(pkt)) { 157 case NFPROTO_IPV4: 158 switch (priv->family) { 159 case NFPROTO_IPV4: 160 case NFPROTO_UNSPEC: 161 nft_tproxy_eval_v4(expr, regs, pkt); 162 return; 163 } 164 break; 165 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) 166 case NFPROTO_IPV6: 167 switch (priv->family) { 168 case NFPROTO_IPV6: 169 case NFPROTO_UNSPEC: 170 nft_tproxy_eval_v6(expr, regs, pkt); 171 return; 172 } 173 #endif 174 } 175 regs->verdict.code = NFT_BREAK; 176 } 177 178 static const struct nla_policy nft_tproxy_policy[NFTA_TPROXY_MAX + 1] = { 179 [NFTA_TPROXY_FAMILY] = { .type = NLA_U32 }, 180 [NFTA_TPROXY_REG_ADDR] = { .type = NLA_U32 }, 181 [NFTA_TPROXY_REG_PORT] = { .type = NLA_U32 }, 182 }; 183 184 static int nft_tproxy_init(const struct nft_ctx *ctx, 185 const struct nft_expr *expr, 186 const struct nlattr * const tb[]) 187 { 188 struct nft_tproxy *priv = nft_expr_priv(expr); 189 unsigned int alen = 0; 190 int err; 191 192 if (!tb[NFTA_TPROXY_FAMILY] || 193 (!tb[NFTA_TPROXY_REG_ADDR] && !tb[NFTA_TPROXY_REG_PORT])) 194 return -EINVAL; 195 196 priv->family = ntohl(nla_get_be32(tb[NFTA_TPROXY_FAMILY])); 197 198 switch (ctx->family) { 199 case NFPROTO_IPV4: 200 if (priv->family != NFPROTO_IPV4) 201 return -EINVAL; 202 break; 203 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) 204 case NFPROTO_IPV6: 205 if (priv->family != NFPROTO_IPV6) 206 return -EINVAL; 207 break; 208 #endif 209 case NFPROTO_INET: 210 break; 211 default: 212 return -EOPNOTSUPP; 213 } 214 215 /* Address is specified but the rule family is not set accordingly */ 216 if (priv->family == NFPROTO_UNSPEC && tb[NFTA_TPROXY_REG_ADDR]) 217 return -EINVAL; 218 219 switch (priv->family) { 220 case NFPROTO_IPV4: 221 alen = FIELD_SIZEOF(union nf_inet_addr, in); 222 err = nf_defrag_ipv4_enable(ctx->net); 223 if (err) 224 return err; 225 break; 226 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) 227 case NFPROTO_IPV6: 228 alen = FIELD_SIZEOF(union nf_inet_addr, in6); 229 err = nf_defrag_ipv6_enable(ctx->net); 230 if (err) 231 return err; 232 break; 233 #endif 234 case NFPROTO_UNSPEC: 235 /* No address is specified here */ 236 err = nf_defrag_ipv4_enable(ctx->net); 237 if (err) 238 return err; 239 #if IS_ENABLED(CONFIG_NF_TABLES_IPV6) 240 err = nf_defrag_ipv6_enable(ctx->net); 241 if (err) 242 return err; 243 #endif 244 break; 245 default: 246 return -EOPNOTSUPP; 247 } 248 249 if (tb[NFTA_TPROXY_REG_ADDR]) { 250 priv->sreg_addr = nft_parse_register(tb[NFTA_TPROXY_REG_ADDR]); 251 err = nft_validate_register_load(priv->sreg_addr, alen); 252 if (err < 0) 253 return err; 254 } 255 256 if (tb[NFTA_TPROXY_REG_PORT]) { 257 priv->sreg_port = nft_parse_register(tb[NFTA_TPROXY_REG_PORT]); 258 err = nft_validate_register_load(priv->sreg_port, sizeof(u16)); 259 if (err < 0) 260 return err; 261 } 262 263 return 0; 264 } 265 266 static int nft_tproxy_dump(struct sk_buff *skb, 267 const struct nft_expr *expr) 268 { 269 const struct nft_tproxy *priv = nft_expr_priv(expr); 270 271 if (nla_put_be32(skb, NFTA_TPROXY_FAMILY, htonl(priv->family))) 272 return -1; 273 274 if (priv->sreg_addr && 275 nft_dump_register(skb, NFTA_TPROXY_REG_ADDR, priv->sreg_addr)) 276 return -1; 277 278 if (priv->sreg_port && 279 nft_dump_register(skb, NFTA_TPROXY_REG_PORT, priv->sreg_port)) 280 return -1; 281 282 return 0; 283 } 284 285 static struct nft_expr_type nft_tproxy_type; 286 static const struct nft_expr_ops nft_tproxy_ops = { 287 .type = &nft_tproxy_type, 288 .size = NFT_EXPR_SIZE(sizeof(struct nft_tproxy)), 289 .eval = nft_tproxy_eval, 290 .init = nft_tproxy_init, 291 .dump = nft_tproxy_dump, 292 }; 293 294 static struct nft_expr_type nft_tproxy_type __read_mostly = { 295 .name = "tproxy", 296 .ops = &nft_tproxy_ops, 297 .policy = nft_tproxy_policy, 298 .maxattr = NFTA_TPROXY_MAX, 299 .owner = THIS_MODULE, 300 }; 301 302 static int __init nft_tproxy_module_init(void) 303 { 304 return nft_register_expr(&nft_tproxy_type); 305 } 306 307 static void __exit nft_tproxy_module_exit(void) 308 { 309 nft_unregister_expr(&nft_tproxy_type); 310 } 311 312 module_init(nft_tproxy_module_init); 313 module_exit(nft_tproxy_module_exit); 314 315 MODULE_LICENSE("GPL"); 316 MODULE_AUTHOR("Máté Eckl"); 317 MODULE_DESCRIPTION("nf_tables tproxy support module"); 318 MODULE_ALIAS_NFT_EXPR("tproxy"); 319