1 /* 2 * Transparent proxy support for Linux/iptables 3 * 4 * Copyright (c) 2006-2010 BalaBit IT Ltd. 5 * Author: Balazs Scheidler, Krisztian Kovacs 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 */ 12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 13 #include <linux/module.h> 14 #include <linux/skbuff.h> 15 #include <linux/ip.h> 16 #include <net/checksum.h> 17 #include <net/udp.h> 18 #include <net/tcp.h> 19 #include <net/inet_sock.h> 20 #include <net/inet_hashtables.h> 21 #include <linux/inetdevice.h> 22 #include <linux/netfilter/x_tables.h> 23 #include <linux/netfilter_ipv4/ip_tables.h> 24 25 #include <net/netfilter/ipv4/nf_defrag_ipv4.h> 26 27 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 28 #define XT_TPROXY_HAVE_IPV6 1 29 #include <net/if_inet6.h> 30 #include <net/addrconf.h> 31 #include <net/inet6_hashtables.h> 32 #include <linux/netfilter_ipv6/ip6_tables.h> 33 #include <net/netfilter/ipv6/nf_defrag_ipv6.h> 34 #endif 35 36 #include <net/netfilter/nf_tproxy.h> 37 #include <linux/netfilter/xt_TPROXY.h> 38 39 /* assign a socket to the skb -- consumes sk */ 40 static void 41 nf_tproxy_assign_sock(struct sk_buff *skb, struct sock *sk) 42 { 43 skb_orphan(skb); 44 skb->sk = sk; 45 skb->destructor = sock_edemux; 46 } 47 48 static unsigned int 49 tproxy_tg4(struct net *net, struct sk_buff *skb, __be32 laddr, __be16 lport, 50 u_int32_t mark_mask, u_int32_t mark_value) 51 { 52 const struct iphdr *iph = ip_hdr(skb); 53 struct udphdr _hdr, *hp; 54 struct sock *sk; 55 56 hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr); 57 if (hp == NULL) 58 return NF_DROP; 59 60 /* check if there's an ongoing connection on the packet 61 * addresses, this happens if the redirect already happened 62 * and the current packet belongs to an already established 63 * connection */ 64 sk = nf_tproxy_get_sock_v4(net, skb, hp, iph->protocol, 65 iph->saddr, iph->daddr, 66 hp->source, hp->dest, 67 skb->dev, NF_TPROXY_LOOKUP_ESTABLISHED); 68 69 laddr = nf_tproxy_laddr4(skb, laddr, iph->daddr); 70 if (!lport) 71 lport = hp->dest; 72 73 /* UDP has no TCP_TIME_WAIT state, so we never enter here */ 74 if (sk && sk->sk_state == TCP_TIME_WAIT) 75 /* reopening a TIME_WAIT connection needs special handling */ 76 sk = nf_tproxy_handle_time_wait4(net, skb, laddr, lport, sk); 77 else if (!sk) 78 /* no, there's no established connection, check if 79 * there's a listener on the redirected addr/port */ 80 sk = nf_tproxy_get_sock_v4(net, skb, hp, iph->protocol, 81 iph->saddr, laddr, 82 hp->source, lport, 83 skb->dev, NF_TPROXY_LOOKUP_LISTENER); 84 85 /* NOTE: assign_sock consumes our sk reference */ 86 if (sk && nf_tproxy_sk_is_transparent(sk)) { 87 /* This should be in a separate target, but we don't do multiple 88 targets on the same rule yet */ 89 skb->mark = (skb->mark & ~mark_mask) ^ mark_value; 90 91 pr_debug("redirecting: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n", 92 iph->protocol, &iph->daddr, ntohs(hp->dest), 93 &laddr, ntohs(lport), skb->mark); 94 95 nf_tproxy_assign_sock(skb, sk); 96 return NF_ACCEPT; 97 } 98 99 pr_debug("no socket, dropping: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n", 100 iph->protocol, &iph->saddr, ntohs(hp->source), 101 &iph->daddr, ntohs(hp->dest), skb->mark); 102 return NF_DROP; 103 } 104 105 static unsigned int 106 tproxy_tg4_v0(struct sk_buff *skb, const struct xt_action_param *par) 107 { 108 const struct xt_tproxy_target_info *tgi = par->targinfo; 109 110 return tproxy_tg4(xt_net(par), skb, tgi->laddr, tgi->lport, 111 tgi->mark_mask, tgi->mark_value); 112 } 113 114 static unsigned int 115 tproxy_tg4_v1(struct sk_buff *skb, const struct xt_action_param *par) 116 { 117 const struct xt_tproxy_target_info_v1 *tgi = par->targinfo; 118 119 return tproxy_tg4(xt_net(par), skb, tgi->laddr.ip, tgi->lport, 120 tgi->mark_mask, tgi->mark_value); 121 } 122 123 #ifdef XT_TPROXY_HAVE_IPV6 124 125 static unsigned int 126 tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par) 127 { 128 const struct ipv6hdr *iph = ipv6_hdr(skb); 129 const struct xt_tproxy_target_info_v1 *tgi = par->targinfo; 130 struct udphdr _hdr, *hp; 131 struct sock *sk; 132 const struct in6_addr *laddr; 133 __be16 lport; 134 int thoff = 0; 135 int tproto; 136 137 tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL); 138 if (tproto < 0) { 139 pr_debug("unable to find transport header in IPv6 packet, dropping\n"); 140 return NF_DROP; 141 } 142 143 hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr); 144 if (hp == NULL) { 145 pr_debug("unable to grab transport header contents in IPv6 packet, dropping\n"); 146 return NF_DROP; 147 } 148 149 /* check if there's an ongoing connection on the packet 150 * addresses, this happens if the redirect already happened 151 * and the current packet belongs to an already established 152 * connection */ 153 sk = nf_tproxy_get_sock_v6(xt_net(par), skb, thoff, hp, tproto, 154 &iph->saddr, &iph->daddr, 155 hp->source, hp->dest, 156 xt_in(par), NF_TPROXY_LOOKUP_ESTABLISHED); 157 158 laddr = nf_tproxy_laddr6(skb, &tgi->laddr.in6, &iph->daddr); 159 lport = tgi->lport ? tgi->lport : hp->dest; 160 161 /* UDP has no TCP_TIME_WAIT state, so we never enter here */ 162 if (sk && sk->sk_state == TCP_TIME_WAIT) { 163 const struct xt_tproxy_target_info_v1 *tgi = par->targinfo; 164 /* reopening a TIME_WAIT connection needs special handling */ 165 sk = nf_tproxy_handle_time_wait6(skb, tproto, thoff, 166 xt_net(par), 167 &tgi->laddr.in6, 168 tgi->lport, 169 sk); 170 } 171 else if (!sk) 172 /* no there's no established connection, check if 173 * there's a listener on the redirected addr/port */ 174 sk = nf_tproxy_get_sock_v6(xt_net(par), skb, thoff, hp, 175 tproto, &iph->saddr, laddr, 176 hp->source, lport, 177 xt_in(par), NF_TPROXY_LOOKUP_LISTENER); 178 179 /* NOTE: assign_sock consumes our sk reference */ 180 if (sk && nf_tproxy_sk_is_transparent(sk)) { 181 /* This should be in a separate target, but we don't do multiple 182 targets on the same rule yet */ 183 skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value; 184 185 pr_debug("redirecting: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n", 186 tproto, &iph->saddr, ntohs(hp->source), 187 laddr, ntohs(lport), skb->mark); 188 189 nf_tproxy_assign_sock(skb, sk); 190 return NF_ACCEPT; 191 } 192 193 pr_debug("no socket, dropping: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n", 194 tproto, &iph->saddr, ntohs(hp->source), 195 &iph->daddr, ntohs(hp->dest), skb->mark); 196 197 return NF_DROP; 198 } 199 200 static int tproxy_tg6_check(const struct xt_tgchk_param *par) 201 { 202 const struct ip6t_ip6 *i = par->entryinfo; 203 int err; 204 205 err = nf_defrag_ipv6_enable(par->net); 206 if (err) 207 return err; 208 209 if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP) && 210 !(i->invflags & IP6T_INV_PROTO)) 211 return 0; 212 213 pr_info_ratelimited("Can be used only with -p tcp or -p udp\n"); 214 return -EINVAL; 215 } 216 #endif 217 218 static int tproxy_tg4_check(const struct xt_tgchk_param *par) 219 { 220 const struct ipt_ip *i = par->entryinfo; 221 int err; 222 223 err = nf_defrag_ipv4_enable(par->net); 224 if (err) 225 return err; 226 227 if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP) 228 && !(i->invflags & IPT_INV_PROTO)) 229 return 0; 230 231 pr_info_ratelimited("Can be used only with -p tcp or -p udp\n"); 232 return -EINVAL; 233 } 234 235 static struct xt_target tproxy_tg_reg[] __read_mostly = { 236 { 237 .name = "TPROXY", 238 .family = NFPROTO_IPV4, 239 .table = "mangle", 240 .target = tproxy_tg4_v0, 241 .revision = 0, 242 .targetsize = sizeof(struct xt_tproxy_target_info), 243 .checkentry = tproxy_tg4_check, 244 .hooks = 1 << NF_INET_PRE_ROUTING, 245 .me = THIS_MODULE, 246 }, 247 { 248 .name = "TPROXY", 249 .family = NFPROTO_IPV4, 250 .table = "mangle", 251 .target = tproxy_tg4_v1, 252 .revision = 1, 253 .targetsize = sizeof(struct xt_tproxy_target_info_v1), 254 .checkentry = tproxy_tg4_check, 255 .hooks = 1 << NF_INET_PRE_ROUTING, 256 .me = THIS_MODULE, 257 }, 258 #ifdef XT_TPROXY_HAVE_IPV6 259 { 260 .name = "TPROXY", 261 .family = NFPROTO_IPV6, 262 .table = "mangle", 263 .target = tproxy_tg6_v1, 264 .revision = 1, 265 .targetsize = sizeof(struct xt_tproxy_target_info_v1), 266 .checkentry = tproxy_tg6_check, 267 .hooks = 1 << NF_INET_PRE_ROUTING, 268 .me = THIS_MODULE, 269 }, 270 #endif 271 272 }; 273 274 static int __init tproxy_tg_init(void) 275 { 276 return xt_register_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg)); 277 } 278 279 static void __exit tproxy_tg_exit(void) 280 { 281 xt_unregister_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg)); 282 } 283 284 module_init(tproxy_tg_init); 285 module_exit(tproxy_tg_exit); 286 MODULE_LICENSE("GPL"); 287 MODULE_AUTHOR("Balazs Scheidler, Krisztian Kovacs"); 288 MODULE_DESCRIPTION("Netfilter transparent proxy (TPROXY) target module."); 289 MODULE_ALIAS("ipt_TPROXY"); 290 MODULE_ALIAS("ip6t_TPROXY"); 291