linux/net/netfilter/xt_TPROXY.c
<<
>>
Prefs
   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 <linux/netfilter/xt_TPROXY.h>
  37
  38enum nf_tproxy_lookup_t {
  39         NFT_LOOKUP_LISTENER,
  40         NFT_LOOKUP_ESTABLISHED,
  41};
  42
  43static bool tproxy_sk_is_transparent(struct sock *sk)
  44{
  45        if (sk->sk_state != TCP_TIME_WAIT) {
  46                if (inet_sk(sk)->transparent)
  47                        return true;
  48                sock_put(sk);
  49        } else {
  50                if (inet_twsk(sk)->tw_transparent)
  51                        return true;
  52                inet_twsk_put(inet_twsk(sk));
  53        }
  54        return false;
  55}
  56
  57static inline __be32
  58tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr)
  59{
  60        struct in_device *indev;
  61        __be32 laddr;
  62
  63        if (user_laddr)
  64                return user_laddr;
  65
  66        laddr = 0;
  67        rcu_read_lock();
  68        indev = __in_dev_get_rcu(skb->dev);
  69        for_primary_ifa(indev) {
  70                laddr = ifa->ifa_local;
  71                break;
  72        } endfor_ifa(indev);
  73        rcu_read_unlock();
  74
  75        return laddr ? laddr : daddr;
  76}
  77
  78/*
  79 * This is used when the user wants to intercept a connection matching
  80 * an explicit iptables rule. In this case the sockets are assumed
  81 * matching in preference order:
  82 *
  83 *   - match: if there's a fully established connection matching the
  84 *     _packet_ tuple, it is returned, assuming the redirection
  85 *     already took place and we process a packet belonging to an
  86 *     established connection
  87 *
  88 *   - match: if there's a listening socket matching the redirection
  89 *     (e.g. on-port & on-ip of the connection), it is returned,
  90 *     regardless if it was bound to 0.0.0.0 or an explicit
  91 *     address. The reasoning is that if there's an explicit rule, it
  92 *     does not really matter if the listener is bound to an interface
  93 *     or to 0. The user already stated that he wants redirection
  94 *     (since he added the rule).
  95 *
  96 * Please note that there's an overlap between what a TPROXY target
  97 * and a socket match will match. Normally if you have both rules the
  98 * "socket" match will be the first one, effectively all packets
  99 * belonging to established connections going through that one.
 100 */
 101static inline struct sock *
 102nf_tproxy_get_sock_v4(struct net *net, const u8 protocol,
 103                      const __be32 saddr, const __be32 daddr,
 104                      const __be16 sport, const __be16 dport,
 105                      const struct net_device *in,
 106                      const enum nf_tproxy_lookup_t lookup_type)
 107{
 108        struct sock *sk;
 109
 110        switch (protocol) {
 111        case IPPROTO_TCP:
 112                switch (lookup_type) {
 113                case NFT_LOOKUP_LISTENER:
 114                        sk = inet_lookup_listener(net, &tcp_hashinfo,
 115                                                    saddr, sport,
 116                                                    daddr, dport,
 117                                                    in->ifindex);
 118
 119                        /* NOTE: we return listeners even if bound to
 120                         * 0.0.0.0, those are filtered out in
 121                         * xt_socket, since xt_TPROXY needs 0 bound
 122                         * listeners too
 123                         */
 124                        break;
 125                case NFT_LOOKUP_ESTABLISHED:
 126                        sk = inet_lookup_established(net, &tcp_hashinfo,
 127                                                    saddr, sport, daddr, dport,
 128                                                    in->ifindex);
 129                        break;
 130                default:
 131                        BUG();
 132                }
 133                break;
 134        case IPPROTO_UDP:
 135                sk = udp4_lib_lookup(net, saddr, sport, daddr, dport,
 136                                     in->ifindex);
 137                if (sk) {
 138                        int connected = (sk->sk_state == TCP_ESTABLISHED);
 139                        int wildcard = (inet_sk(sk)->inet_rcv_saddr == 0);
 140
 141                        /* NOTE: we return listeners even if bound to
 142                         * 0.0.0.0, those are filtered out in
 143                         * xt_socket, since xt_TPROXY needs 0 bound
 144                         * listeners too
 145                         */
 146                        if ((lookup_type == NFT_LOOKUP_ESTABLISHED && (!connected || wildcard)) ||
 147                            (lookup_type == NFT_LOOKUP_LISTENER && connected)) {
 148                                sock_put(sk);
 149                                sk = NULL;
 150                        }
 151                }
 152                break;
 153        default:
 154                WARN_ON(1);
 155                sk = NULL;
 156        }
 157
 158        pr_debug("tproxy socket lookup: proto %u %08x:%u -> %08x:%u, lookup type: %d, sock %p\n",
 159                 protocol, ntohl(saddr), ntohs(sport), ntohl(daddr), ntohs(dport), lookup_type, sk);
 160
 161        return sk;
 162}
 163
 164#ifdef XT_TPROXY_HAVE_IPV6
 165static inline struct sock *
 166nf_tproxy_get_sock_v6(struct net *net, const u8 protocol,
 167                      const struct in6_addr *saddr, const struct in6_addr *daddr,
 168                      const __be16 sport, const __be16 dport,
 169                      const struct net_device *in,
 170                      const enum nf_tproxy_lookup_t lookup_type)
 171{
 172        struct sock *sk;
 173
 174        switch (protocol) {
 175        case IPPROTO_TCP:
 176                switch (lookup_type) {
 177                case NFT_LOOKUP_LISTENER:
 178                        sk = inet6_lookup_listener(net, &tcp_hashinfo,
 179                                                   saddr, sport,
 180                                                   daddr, ntohs(dport),
 181                                                   in->ifindex);
 182
 183                        /* NOTE: we return listeners even if bound to
 184                         * 0.0.0.0, those are filtered out in
 185                         * xt_socket, since xt_TPROXY needs 0 bound
 186                         * listeners too
 187                         */
 188                        break;
 189                case NFT_LOOKUP_ESTABLISHED:
 190                        sk = __inet6_lookup_established(net, &tcp_hashinfo,
 191                                                        saddr, sport, daddr, ntohs(dport),
 192                                                        in->ifindex);
 193                        break;
 194                default:
 195                        BUG();
 196                }
 197                break;
 198        case IPPROTO_UDP:
 199                sk = udp6_lib_lookup(net, saddr, sport, daddr, dport,
 200                                     in->ifindex);
 201                if (sk) {
 202                        int connected = (sk->sk_state == TCP_ESTABLISHED);
 203                        int wildcard = ipv6_addr_any(&inet6_sk(sk)->rcv_saddr);
 204
 205                        /* NOTE: we return listeners even if bound to
 206                         * 0.0.0.0, those are filtered out in
 207                         * xt_socket, since xt_TPROXY needs 0 bound
 208                         * listeners too
 209                         */
 210                        if ((lookup_type == NFT_LOOKUP_ESTABLISHED && (!connected || wildcard)) ||
 211                            (lookup_type == NFT_LOOKUP_LISTENER && connected)) {
 212                                sock_put(sk);
 213                                sk = NULL;
 214                        }
 215                }
 216                break;
 217        default:
 218                WARN_ON(1);
 219                sk = NULL;
 220        }
 221
 222        pr_debug("tproxy socket lookup: proto %u %pI6:%u -> %pI6:%u, lookup type: %d, sock %p\n",
 223                 protocol, saddr, ntohs(sport), daddr, ntohs(dport), lookup_type, sk);
 224
 225        return sk;
 226}
 227#endif
 228
 229/**
 230 * tproxy_handle_time_wait4 - handle IPv4 TCP TIME_WAIT reopen redirections
 231 * @skb:        The skb being processed.
 232 * @laddr:      IPv4 address to redirect to or zero.
 233 * @lport:      TCP port to redirect to or zero.
 234 * @sk:         The TIME_WAIT TCP socket found by the lookup.
 235 *
 236 * We have to handle SYN packets arriving to TIME_WAIT sockets
 237 * differently: instead of reopening the connection we should rather
 238 * redirect the new connection to the proxy if there's a listener
 239 * socket present.
 240 *
 241 * tproxy_handle_time_wait4() consumes the socket reference passed in.
 242 *
 243 * Returns the listener socket if there's one, the TIME_WAIT socket if
 244 * no such listener is found, or NULL if the TCP header is incomplete.
 245 */
 246static struct sock *
 247tproxy_handle_time_wait4(struct sk_buff *skb, __be32 laddr, __be16 lport,
 248                        struct sock *sk)
 249{
 250        const struct iphdr *iph = ip_hdr(skb);
 251        struct tcphdr _hdr, *hp;
 252
 253        hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr);
 254        if (hp == NULL) {
 255                inet_twsk_put(inet_twsk(sk));
 256                return NULL;
 257        }
 258
 259        if (hp->syn && !hp->rst && !hp->ack && !hp->fin) {
 260                /* SYN to a TIME_WAIT socket, we'd rather redirect it
 261                 * to a listener socket if there's one */
 262                struct sock *sk2;
 263
 264                sk2 = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
 265                                            iph->saddr, laddr ? laddr : iph->daddr,
 266                                            hp->source, lport ? lport : hp->dest,
 267                                            skb->dev, NFT_LOOKUP_LISTENER);
 268                if (sk2) {
 269                        inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row);
 270                        inet_twsk_put(inet_twsk(sk));
 271                        sk = sk2;
 272                }
 273        }
 274
 275        return sk;
 276}
 277
 278/* assign a socket to the skb -- consumes sk */
 279static void
 280nf_tproxy_assign_sock(struct sk_buff *skb, struct sock *sk)
 281{
 282        skb_orphan(skb);
 283        skb->sk = sk;
 284        skb->destructor = sock_edemux;
 285}
 286
 287static unsigned int
 288tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
 289           u_int32_t mark_mask, u_int32_t mark_value)
 290{
 291        const struct iphdr *iph = ip_hdr(skb);
 292        struct udphdr _hdr, *hp;
 293        struct sock *sk;
 294
 295        hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr);
 296        if (hp == NULL)
 297                return NF_DROP;
 298
 299        /* check if there's an ongoing connection on the packet
 300         * addresses, this happens if the redirect already happened
 301         * and the current packet belongs to an already established
 302         * connection */
 303        sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
 304                                   iph->saddr, iph->daddr,
 305                                   hp->source, hp->dest,
 306                                   skb->dev, NFT_LOOKUP_ESTABLISHED);
 307
 308        laddr = tproxy_laddr4(skb, laddr, iph->daddr);
 309        if (!lport)
 310                lport = hp->dest;
 311
 312        /* UDP has no TCP_TIME_WAIT state, so we never enter here */
 313        if (sk && sk->sk_state == TCP_TIME_WAIT)
 314                /* reopening a TIME_WAIT connection needs special handling */
 315                sk = tproxy_handle_time_wait4(skb, laddr, lport, sk);
 316        else if (!sk)
 317                /* no, there's no established connection, check if
 318                 * there's a listener on the redirected addr/port */
 319                sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
 320                                           iph->saddr, laddr,
 321                                           hp->source, lport,
 322                                           skb->dev, NFT_LOOKUP_LISTENER);
 323
 324        /* NOTE: assign_sock consumes our sk reference */
 325        if (sk && tproxy_sk_is_transparent(sk)) {
 326                /* This should be in a separate target, but we don't do multiple
 327                   targets on the same rule yet */
 328                skb->mark = (skb->mark & ~mark_mask) ^ mark_value;
 329
 330                pr_debug("redirecting: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n",
 331                         iph->protocol, &iph->daddr, ntohs(hp->dest),
 332                         &laddr, ntohs(lport), skb->mark);
 333
 334                nf_tproxy_assign_sock(skb, sk);
 335                return NF_ACCEPT;
 336        }
 337
 338        pr_debug("no socket, dropping: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n",
 339                 iph->protocol, &iph->saddr, ntohs(hp->source),
 340                 &iph->daddr, ntohs(hp->dest), skb->mark);
 341        return NF_DROP;
 342}
 343
 344static unsigned int
 345tproxy_tg4_v0(struct sk_buff *skb, const struct xt_action_param *par)
 346{
 347        const struct xt_tproxy_target_info *tgi = par->targinfo;
 348
 349        return tproxy_tg4(skb, tgi->laddr, tgi->lport, tgi->mark_mask, tgi->mark_value);
 350}
 351
 352static unsigned int
 353tproxy_tg4_v1(struct sk_buff *skb, const struct xt_action_param *par)
 354{
 355        const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
 356
 357        return tproxy_tg4(skb, tgi->laddr.ip, tgi->lport, tgi->mark_mask, tgi->mark_value);
 358}
 359
 360#ifdef XT_TPROXY_HAVE_IPV6
 361
 362static inline const struct in6_addr *
 363tproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr,
 364              const struct in6_addr *daddr)
 365{
 366        struct inet6_dev *indev;
 367        struct inet6_ifaddr *ifa;
 368        struct in6_addr *laddr;
 369
 370        if (!ipv6_addr_any(user_laddr))
 371                return user_laddr;
 372        laddr = NULL;
 373
 374        rcu_read_lock();
 375        indev = __in6_dev_get(skb->dev);
 376        if (indev)
 377                list_for_each_entry(ifa, &indev->addr_list, if_list) {
 378                        if (ifa->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED))
 379                                continue;
 380
 381                        laddr = &ifa->addr;
 382                        break;
 383                }
 384        rcu_read_unlock();
 385
 386        return laddr ? laddr : daddr;
 387}
 388
 389/**
 390 * tproxy_handle_time_wait6 - handle IPv6 TCP TIME_WAIT reopen redirections
 391 * @skb:        The skb being processed.
 392 * @tproto:     Transport protocol.
 393 * @thoff:      Transport protocol header offset.
 394 * @par:        Iptables target parameters.
 395 * @sk:         The TIME_WAIT TCP socket found by the lookup.
 396 *
 397 * We have to handle SYN packets arriving to TIME_WAIT sockets
 398 * differently: instead of reopening the connection we should rather
 399 * redirect the new connection to the proxy if there's a listener
 400 * socket present.
 401 *
 402 * tproxy_handle_time_wait6() consumes the socket reference passed in.
 403 *
 404 * Returns the listener socket if there's one, the TIME_WAIT socket if
 405 * no such listener is found, or NULL if the TCP header is incomplete.
 406 */
 407static struct sock *
 408tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff,
 409                         const struct xt_action_param *par,
 410                         struct sock *sk)
 411{
 412        const struct ipv6hdr *iph = ipv6_hdr(skb);
 413        struct tcphdr _hdr, *hp;
 414        const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
 415
 416        hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
 417        if (hp == NULL) {
 418                inet_twsk_put(inet_twsk(sk));
 419                return NULL;
 420        }
 421
 422        if (hp->syn && !hp->rst && !hp->ack && !hp->fin) {
 423                /* SYN to a TIME_WAIT socket, we'd rather redirect it
 424                 * to a listener socket if there's one */
 425                struct sock *sk2;
 426
 427                sk2 = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
 428                                            &iph->saddr,
 429                                            tproxy_laddr6(skb, &tgi->laddr.in6, &iph->daddr),
 430                                            hp->source,
 431                                            tgi->lport ? tgi->lport : hp->dest,
 432                                            skb->dev, NFT_LOOKUP_LISTENER);
 433                if (sk2) {
 434                        inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row);
 435                        inet_twsk_put(inet_twsk(sk));
 436                        sk = sk2;
 437                }
 438        }
 439
 440        return sk;
 441}
 442
 443static unsigned int
 444tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
 445{
 446        const struct ipv6hdr *iph = ipv6_hdr(skb);
 447        const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
 448        struct udphdr _hdr, *hp;
 449        struct sock *sk;
 450        const struct in6_addr *laddr;
 451        __be16 lport;
 452        int thoff = 0;
 453        int tproto;
 454
 455        tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
 456        if (tproto < 0) {
 457                pr_debug("unable to find transport header in IPv6 packet, dropping\n");
 458                return NF_DROP;
 459        }
 460
 461        hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
 462        if (hp == NULL) {
 463                pr_debug("unable to grab transport header contents in IPv6 packet, dropping\n");
 464                return NF_DROP;
 465        }
 466
 467        /* check if there's an ongoing connection on the packet
 468         * addresses, this happens if the redirect already happened
 469         * and the current packet belongs to an already established
 470         * connection */
 471        sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
 472                                   &iph->saddr, &iph->daddr,
 473                                   hp->source, hp->dest,
 474                                   par->in, NFT_LOOKUP_ESTABLISHED);
 475
 476        laddr = tproxy_laddr6(skb, &tgi->laddr.in6, &iph->daddr);
 477        lport = tgi->lport ? tgi->lport : hp->dest;
 478
 479        /* UDP has no TCP_TIME_WAIT state, so we never enter here */
 480        if (sk && sk->sk_state == TCP_TIME_WAIT)
 481                /* reopening a TIME_WAIT connection needs special handling */
 482                sk = tproxy_handle_time_wait6(skb, tproto, thoff, par, sk);
 483        else if (!sk)
 484                /* no there's no established connection, check if
 485                 * there's a listener on the redirected addr/port */
 486                sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
 487                                           &iph->saddr, laddr,
 488                                           hp->source, lport,
 489                                           par->in, NFT_LOOKUP_LISTENER);
 490
 491        /* NOTE: assign_sock consumes our sk reference */
 492        if (sk && tproxy_sk_is_transparent(sk)) {
 493                /* This should be in a separate target, but we don't do multiple
 494                   targets on the same rule yet */
 495                skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value;
 496
 497                pr_debug("redirecting: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n",
 498                         tproto, &iph->saddr, ntohs(hp->source),
 499                         laddr, ntohs(lport), skb->mark);
 500
 501                nf_tproxy_assign_sock(skb, sk);
 502                return NF_ACCEPT;
 503        }
 504
 505        pr_debug("no socket, dropping: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n",
 506                 tproto, &iph->saddr, ntohs(hp->source),
 507                 &iph->daddr, ntohs(hp->dest), skb->mark);
 508
 509        return NF_DROP;
 510}
 511
 512static int tproxy_tg6_check(const struct xt_tgchk_param *par)
 513{
 514        const struct ip6t_ip6 *i = par->entryinfo;
 515
 516        if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
 517            && !(i->flags & IP6T_INV_PROTO))
 518                return 0;
 519
 520        pr_info("Can be used only in combination with "
 521                "either -p tcp or -p udp\n");
 522        return -EINVAL;
 523}
 524#endif
 525
 526static int tproxy_tg4_check(const struct xt_tgchk_param *par)
 527{
 528        const struct ipt_ip *i = par->entryinfo;
 529
 530        if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
 531            && !(i->invflags & IPT_INV_PROTO))
 532                return 0;
 533
 534        pr_info("Can be used only in combination with "
 535                "either -p tcp or -p udp\n");
 536        return -EINVAL;
 537}
 538
 539static struct xt_target tproxy_tg_reg[] __read_mostly = {
 540        {
 541                .name           = "TPROXY",
 542                .family         = NFPROTO_IPV4,
 543                .table          = "mangle",
 544                .target         = tproxy_tg4_v0,
 545                .revision       = 0,
 546                .targetsize     = sizeof(struct xt_tproxy_target_info),
 547                .checkentry     = tproxy_tg4_check,
 548                .hooks          = 1 << NF_INET_PRE_ROUTING,
 549                .me             = THIS_MODULE,
 550        },
 551        {
 552                .name           = "TPROXY",
 553                .family         = NFPROTO_IPV4,
 554                .table          = "mangle",
 555                .target         = tproxy_tg4_v1,
 556                .revision       = 1,
 557                .targetsize     = sizeof(struct xt_tproxy_target_info_v1),
 558                .checkentry     = tproxy_tg4_check,
 559                .hooks          = 1 << NF_INET_PRE_ROUTING,
 560                .me             = THIS_MODULE,
 561        },
 562#ifdef XT_TPROXY_HAVE_IPV6
 563        {
 564                .name           = "TPROXY",
 565                .family         = NFPROTO_IPV6,
 566                .table          = "mangle",
 567                .target         = tproxy_tg6_v1,
 568                .revision       = 1,
 569                .targetsize     = sizeof(struct xt_tproxy_target_info_v1),
 570                .checkentry     = tproxy_tg6_check,
 571                .hooks          = 1 << NF_INET_PRE_ROUTING,
 572                .me             = THIS_MODULE,
 573        },
 574#endif
 575
 576};
 577
 578static int __init tproxy_tg_init(void)
 579{
 580        nf_defrag_ipv4_enable();
 581#ifdef XT_TPROXY_HAVE_IPV6
 582        nf_defrag_ipv6_enable();
 583#endif
 584
 585        return xt_register_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg));
 586}
 587
 588static void __exit tproxy_tg_exit(void)
 589{
 590        xt_unregister_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg));
 591}
 592
 593module_init(tproxy_tg_init);
 594module_exit(tproxy_tg_exit);
 595MODULE_LICENSE("GPL");
 596MODULE_AUTHOR("Balazs Scheidler, Krisztian Kovacs");
 597MODULE_DESCRIPTION("Netfilter transparent proxy (TPROXY) target module.");
 598MODULE_ALIAS("ipt_TPROXY");
 599MODULE_ALIAS("ip6t_TPROXY");
 600