linux/net/netfilter/xt_socket.c
<<
>>
Prefs
   1/*
   2 * Transparent proxy support for Linux/iptables
   3 *
   4 * Copyright (C) 2007-2008 BalaBit IT Ltd.
   5 * Author: 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/netfilter/x_tables.h>
  16#include <linux/netfilter_ipv4/ip_tables.h>
  17#include <net/tcp.h>
  18#include <net/udp.h>
  19#include <net/icmp.h>
  20#include <net/sock.h>
  21#include <net/inet_sock.h>
  22#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
  23
  24#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
  25#include <linux/netfilter_ipv6/ip6_tables.h>
  26#include <net/inet6_hashtables.h>
  27#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
  28#endif
  29
  30#include <net/netfilter/nf_socket.h>
  31#include <linux/netfilter/xt_socket.h>
  32
  33/* "socket" match based redirection (no specific rule)
  34 * ===================================================
  35 *
  36 * There are connections with dynamic endpoints (e.g. FTP data
  37 * connection) that the user is unable to add explicit rules
  38 * for. These are taken care of by a generic "socket" rule. It is
  39 * assumed that the proxy application is trusted to open such
  40 * connections without explicit iptables rule (except of course the
  41 * generic 'socket' rule). In this case the following sockets are
  42 * matched in preference order:
  43 *
  44 *   - match: if there's a fully established connection matching the
  45 *     _packet_ tuple
  46 *
  47 *   - match: if there's a non-zero bound listener (possibly with a
  48 *     non-local address) We don't accept zero-bound listeners, since
  49 *     then local services could intercept traffic going through the
  50 *     box.
  51 */
  52static bool
  53socket_match(const struct sk_buff *skb, struct xt_action_param *par,
  54             const struct xt_socket_mtinfo1 *info)
  55{
  56        struct sk_buff *pskb = (struct sk_buff *)skb;
  57        struct sock *sk = skb->sk;
  58
  59        if (sk && !net_eq(xt_net(par), sock_net(sk)))
  60                sk = NULL;
  61
  62        if (!sk)
  63                sk = nf_sk_lookup_slow_v4(xt_net(par), skb, xt_in(par));
  64
  65        if (sk) {
  66                bool wildcard;
  67                bool transparent = true;
  68
  69                /* Ignore sockets listening on INADDR_ANY,
  70                 * unless XT_SOCKET_NOWILDCARD is set
  71                 */
  72                wildcard = (!(info->flags & XT_SOCKET_NOWILDCARD) &&
  73                            sk_fullsock(sk) &&
  74                            inet_sk(sk)->inet_rcv_saddr == 0);
  75
  76                /* Ignore non-transparent sockets,
  77                 * if XT_SOCKET_TRANSPARENT is used
  78                 */
  79                if (info->flags & XT_SOCKET_TRANSPARENT)
  80                        transparent = inet_sk_transparent(sk);
  81
  82                if (info->flags & XT_SOCKET_RESTORESKMARK && !wildcard &&
  83                    transparent && sk_fullsock(sk))
  84                        pskb->mark = sk->sk_mark;
  85
  86                if (sk != skb->sk)
  87                        sock_gen_put(sk);
  88
  89                if (wildcard || !transparent)
  90                        sk = NULL;
  91        }
  92
  93        return sk != NULL;
  94}
  95
  96static bool
  97socket_mt4_v0(const struct sk_buff *skb, struct xt_action_param *par)
  98{
  99        static struct xt_socket_mtinfo1 xt_info_v0 = {
 100                .flags = 0,
 101        };
 102
 103        return socket_match(skb, par, &xt_info_v0);
 104}
 105
 106static bool
 107socket_mt4_v1_v2_v3(const struct sk_buff *skb, struct xt_action_param *par)
 108{
 109        return socket_match(skb, par, par->matchinfo);
 110}
 111
 112#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 113static bool
 114socket_mt6_v1_v2_v3(const struct sk_buff *skb, struct xt_action_param *par)
 115{
 116        const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
 117        struct sk_buff *pskb = (struct sk_buff *)skb;
 118        struct sock *sk = skb->sk;
 119
 120        if (sk && !net_eq(xt_net(par), sock_net(sk)))
 121                sk = NULL;
 122
 123        if (!sk)
 124                sk = nf_sk_lookup_slow_v6(xt_net(par), skb, xt_in(par));
 125
 126        if (sk) {
 127                bool wildcard;
 128                bool transparent = true;
 129
 130                /* Ignore sockets listening on INADDR_ANY
 131                 * unless XT_SOCKET_NOWILDCARD is set
 132                 */
 133                wildcard = (!(info->flags & XT_SOCKET_NOWILDCARD) &&
 134                            sk_fullsock(sk) &&
 135                            ipv6_addr_any(&sk->sk_v6_rcv_saddr));
 136
 137                /* Ignore non-transparent sockets,
 138                 * if XT_SOCKET_TRANSPARENT is used
 139                 */
 140                if (info->flags & XT_SOCKET_TRANSPARENT)
 141                        transparent = inet_sk_transparent(sk);
 142
 143                if (info->flags & XT_SOCKET_RESTORESKMARK && !wildcard &&
 144                    transparent && sk_fullsock(sk))
 145                        pskb->mark = sk->sk_mark;
 146
 147                if (sk != skb->sk)
 148                        sock_gen_put(sk);
 149
 150                if (wildcard || !transparent)
 151                        sk = NULL;
 152        }
 153
 154        return sk != NULL;
 155}
 156#endif
 157
 158static int socket_mt_enable_defrag(struct net *net, int family)
 159{
 160        switch (family) {
 161        case NFPROTO_IPV4:
 162                return nf_defrag_ipv4_enable(net);
 163#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 164        case NFPROTO_IPV6:
 165                return nf_defrag_ipv6_enable(net);
 166#endif
 167        }
 168        WARN_ONCE(1, "Unknown family %d\n", family);
 169        return 0;
 170}
 171
 172static int socket_mt_v1_check(const struct xt_mtchk_param *par)
 173{
 174        const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
 175        int err;
 176
 177        err = socket_mt_enable_defrag(par->net, par->family);
 178        if (err)
 179                return err;
 180
 181        if (info->flags & ~XT_SOCKET_FLAGS_V1) {
 182                pr_info_ratelimited("unknown flags 0x%x\n",
 183                                    info->flags & ~XT_SOCKET_FLAGS_V1);
 184                return -EINVAL;
 185        }
 186        return 0;
 187}
 188
 189static int socket_mt_v2_check(const struct xt_mtchk_param *par)
 190{
 191        const struct xt_socket_mtinfo2 *info = (struct xt_socket_mtinfo2 *) par->matchinfo;
 192        int err;
 193
 194        err = socket_mt_enable_defrag(par->net, par->family);
 195        if (err)
 196                return err;
 197
 198        if (info->flags & ~XT_SOCKET_FLAGS_V2) {
 199                pr_info_ratelimited("unknown flags 0x%x\n",
 200                                    info->flags & ~XT_SOCKET_FLAGS_V2);
 201                return -EINVAL;
 202        }
 203        return 0;
 204}
 205
 206static int socket_mt_v3_check(const struct xt_mtchk_param *par)
 207{
 208        const struct xt_socket_mtinfo3 *info =
 209                                    (struct xt_socket_mtinfo3 *)par->matchinfo;
 210        int err;
 211
 212        err = socket_mt_enable_defrag(par->net, par->family);
 213        if (err)
 214                return err;
 215        if (info->flags & ~XT_SOCKET_FLAGS_V3) {
 216                pr_info_ratelimited("unknown flags 0x%x\n",
 217                                    info->flags & ~XT_SOCKET_FLAGS_V3);
 218                return -EINVAL;
 219        }
 220        return 0;
 221}
 222
 223static struct xt_match socket_mt_reg[] __read_mostly = {
 224        {
 225                .name           = "socket",
 226                .revision       = 0,
 227                .family         = NFPROTO_IPV4,
 228                .match          = socket_mt4_v0,
 229                .hooks          = (1 << NF_INET_PRE_ROUTING) |
 230                                  (1 << NF_INET_LOCAL_IN),
 231                .me             = THIS_MODULE,
 232        },
 233        {
 234                .name           = "socket",
 235                .revision       = 1,
 236                .family         = NFPROTO_IPV4,
 237                .match          = socket_mt4_v1_v2_v3,
 238                .checkentry     = socket_mt_v1_check,
 239                .matchsize      = sizeof(struct xt_socket_mtinfo1),
 240                .hooks          = (1 << NF_INET_PRE_ROUTING) |
 241                                  (1 << NF_INET_LOCAL_IN),
 242                .me             = THIS_MODULE,
 243        },
 244#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 245        {
 246                .name           = "socket",
 247                .revision       = 1,
 248                .family         = NFPROTO_IPV6,
 249                .match          = socket_mt6_v1_v2_v3,
 250                .checkentry     = socket_mt_v1_check,
 251                .matchsize      = sizeof(struct xt_socket_mtinfo1),
 252                .hooks          = (1 << NF_INET_PRE_ROUTING) |
 253                                  (1 << NF_INET_LOCAL_IN),
 254                .me             = THIS_MODULE,
 255        },
 256#endif
 257        {
 258                .name           = "socket",
 259                .revision       = 2,
 260                .family         = NFPROTO_IPV4,
 261                .match          = socket_mt4_v1_v2_v3,
 262                .checkentry     = socket_mt_v2_check,
 263                .matchsize      = sizeof(struct xt_socket_mtinfo1),
 264                .hooks          = (1 << NF_INET_PRE_ROUTING) |
 265                                  (1 << NF_INET_LOCAL_IN),
 266                .me             = THIS_MODULE,
 267        },
 268#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 269        {
 270                .name           = "socket",
 271                .revision       = 2,
 272                .family         = NFPROTO_IPV6,
 273                .match          = socket_mt6_v1_v2_v3,
 274                .checkentry     = socket_mt_v2_check,
 275                .matchsize      = sizeof(struct xt_socket_mtinfo1),
 276                .hooks          = (1 << NF_INET_PRE_ROUTING) |
 277                                  (1 << NF_INET_LOCAL_IN),
 278                .me             = THIS_MODULE,
 279        },
 280#endif
 281        {
 282                .name           = "socket",
 283                .revision       = 3,
 284                .family         = NFPROTO_IPV4,
 285                .match          = socket_mt4_v1_v2_v3,
 286                .checkentry     = socket_mt_v3_check,
 287                .matchsize      = sizeof(struct xt_socket_mtinfo1),
 288                .hooks          = (1 << NF_INET_PRE_ROUTING) |
 289                                  (1 << NF_INET_LOCAL_IN),
 290                .me             = THIS_MODULE,
 291        },
 292#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 293        {
 294                .name           = "socket",
 295                .revision       = 3,
 296                .family         = NFPROTO_IPV6,
 297                .match          = socket_mt6_v1_v2_v3,
 298                .checkentry     = socket_mt_v3_check,
 299                .matchsize      = sizeof(struct xt_socket_mtinfo1),
 300                .hooks          = (1 << NF_INET_PRE_ROUTING) |
 301                                  (1 << NF_INET_LOCAL_IN),
 302                .me             = THIS_MODULE,
 303        },
 304#endif
 305};
 306
 307static int __init socket_mt_init(void)
 308{
 309        return xt_register_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg));
 310}
 311
 312static void __exit socket_mt_exit(void)
 313{
 314        xt_unregister_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg));
 315}
 316
 317module_init(socket_mt_init);
 318module_exit(socket_mt_exit);
 319
 320MODULE_LICENSE("GPL");
 321MODULE_AUTHOR("Krisztian Kovacs, Balazs Scheidler");
 322MODULE_DESCRIPTION("x_tables socket match module");
 323MODULE_ALIAS("ipt_socket");
 324MODULE_ALIAS("ip6t_socket");
 325