root/net/netfilter/xt_TPROXY.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tproxy_tg4
  2. tproxy_tg4_v0
  3. tproxy_tg4_v1
  4. tproxy_tg6_v1
  5. tproxy_tg6_check
  6. tproxy_tg4_check
  7. tproxy_tg_init
  8. tproxy_tg_exit

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

/* [<][>][^][v][top][bottom][index][help] */