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