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 */ 52 static bool 53 socket_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) 60 sk = nf_sk_lookup_slow_v4(xt_net(par), skb, xt_in(par)); 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 = nf_sk_is_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 92 static bool 93 socket_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 102 static bool 103 socket_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) 109 static bool 110 socket_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) 117 sk = nf_sk_lookup_slow_v6(xt_net(par), skb, xt_in(par)); 118 if (sk) { 119 bool wildcard; 120 bool transparent = true; 121 122 /* Ignore sockets listening on INADDR_ANY 123 * unless XT_SOCKET_NOWILDCARD is set 124 */ 125 wildcard = (!(info->flags & XT_SOCKET_NOWILDCARD) && 126 sk_fullsock(sk) && 127 ipv6_addr_any(&sk->sk_v6_rcv_saddr)); 128 129 /* Ignore non-transparent sockets, 130 * if XT_SOCKET_TRANSPARENT is used 131 */ 132 if (info->flags & XT_SOCKET_TRANSPARENT) 133 transparent = nf_sk_is_transparent(sk); 134 135 if (info->flags & XT_SOCKET_RESTORESKMARK && !wildcard && 136 transparent && sk_fullsock(sk)) 137 pskb->mark = sk->sk_mark; 138 139 if (sk != skb->sk) 140 sock_gen_put(sk); 141 142 if (wildcard || !transparent) 143 sk = NULL; 144 } 145 146 return sk != NULL; 147 } 148 #endif 149 150 static int socket_mt_enable_defrag(struct net *net, int family) 151 { 152 switch (family) { 153 case NFPROTO_IPV4: 154 return nf_defrag_ipv4_enable(net); 155 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 156 case NFPROTO_IPV6: 157 return nf_defrag_ipv6_enable(net); 158 #endif 159 } 160 WARN_ONCE(1, "Unknown family %d\n", family); 161 return 0; 162 } 163 164 static int socket_mt_v1_check(const struct xt_mtchk_param *par) 165 { 166 const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo; 167 int err; 168 169 err = socket_mt_enable_defrag(par->net, par->family); 170 if (err) 171 return err; 172 173 if (info->flags & ~XT_SOCKET_FLAGS_V1) { 174 pr_info_ratelimited("unknown flags 0x%x\n", 175 info->flags & ~XT_SOCKET_FLAGS_V1); 176 return -EINVAL; 177 } 178 return 0; 179 } 180 181 static int socket_mt_v2_check(const struct xt_mtchk_param *par) 182 { 183 const struct xt_socket_mtinfo2 *info = (struct xt_socket_mtinfo2 *) par->matchinfo; 184 int err; 185 186 err = socket_mt_enable_defrag(par->net, par->family); 187 if (err) 188 return err; 189 190 if (info->flags & ~XT_SOCKET_FLAGS_V2) { 191 pr_info_ratelimited("unknown flags 0x%x\n", 192 info->flags & ~XT_SOCKET_FLAGS_V2); 193 return -EINVAL; 194 } 195 return 0; 196 } 197 198 static int socket_mt_v3_check(const struct xt_mtchk_param *par) 199 { 200 const struct xt_socket_mtinfo3 *info = 201 (struct xt_socket_mtinfo3 *)par->matchinfo; 202 int err; 203 204 err = socket_mt_enable_defrag(par->net, par->family); 205 if (err) 206 return err; 207 if (info->flags & ~XT_SOCKET_FLAGS_V3) { 208 pr_info_ratelimited("unknown flags 0x%x\n", 209 info->flags & ~XT_SOCKET_FLAGS_V3); 210 return -EINVAL; 211 } 212 return 0; 213 } 214 215 static struct xt_match socket_mt_reg[] __read_mostly = { 216 { 217 .name = "socket", 218 .revision = 0, 219 .family = NFPROTO_IPV4, 220 .match = socket_mt4_v0, 221 .hooks = (1 << NF_INET_PRE_ROUTING) | 222 (1 << NF_INET_LOCAL_IN), 223 .me = THIS_MODULE, 224 }, 225 { 226 .name = "socket", 227 .revision = 1, 228 .family = NFPROTO_IPV4, 229 .match = socket_mt4_v1_v2_v3, 230 .checkentry = socket_mt_v1_check, 231 .matchsize = sizeof(struct xt_socket_mtinfo1), 232 .hooks = (1 << NF_INET_PRE_ROUTING) | 233 (1 << NF_INET_LOCAL_IN), 234 .me = THIS_MODULE, 235 }, 236 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 237 { 238 .name = "socket", 239 .revision = 1, 240 .family = NFPROTO_IPV6, 241 .match = socket_mt6_v1_v2_v3, 242 .checkentry = socket_mt_v1_check, 243 .matchsize = sizeof(struct xt_socket_mtinfo1), 244 .hooks = (1 << NF_INET_PRE_ROUTING) | 245 (1 << NF_INET_LOCAL_IN), 246 .me = THIS_MODULE, 247 }, 248 #endif 249 { 250 .name = "socket", 251 .revision = 2, 252 .family = NFPROTO_IPV4, 253 .match = socket_mt4_v1_v2_v3, 254 .checkentry = socket_mt_v2_check, 255 .matchsize = sizeof(struct xt_socket_mtinfo1), 256 .hooks = (1 << NF_INET_PRE_ROUTING) | 257 (1 << NF_INET_LOCAL_IN), 258 .me = THIS_MODULE, 259 }, 260 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 261 { 262 .name = "socket", 263 .revision = 2, 264 .family = NFPROTO_IPV6, 265 .match = socket_mt6_v1_v2_v3, 266 .checkentry = socket_mt_v2_check, 267 .matchsize = sizeof(struct xt_socket_mtinfo1), 268 .hooks = (1 << NF_INET_PRE_ROUTING) | 269 (1 << NF_INET_LOCAL_IN), 270 .me = THIS_MODULE, 271 }, 272 #endif 273 { 274 .name = "socket", 275 .revision = 3, 276 .family = NFPROTO_IPV4, 277 .match = socket_mt4_v1_v2_v3, 278 .checkentry = socket_mt_v3_check, 279 .matchsize = sizeof(struct xt_socket_mtinfo1), 280 .hooks = (1 << NF_INET_PRE_ROUTING) | 281 (1 << NF_INET_LOCAL_IN), 282 .me = THIS_MODULE, 283 }, 284 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 285 { 286 .name = "socket", 287 .revision = 3, 288 .family = NFPROTO_IPV6, 289 .match = socket_mt6_v1_v2_v3, 290 .checkentry = socket_mt_v3_check, 291 .matchsize = sizeof(struct xt_socket_mtinfo1), 292 .hooks = (1 << NF_INET_PRE_ROUTING) | 293 (1 << NF_INET_LOCAL_IN), 294 .me = THIS_MODULE, 295 }, 296 #endif 297 }; 298 299 static int __init socket_mt_init(void) 300 { 301 return xt_register_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg)); 302 } 303 304 static void __exit socket_mt_exit(void) 305 { 306 xt_unregister_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg)); 307 } 308 309 module_init(socket_mt_init); 310 module_exit(socket_mt_exit); 311 312 MODULE_LICENSE("GPL"); 313 MODULE_AUTHOR("Krisztian Kovacs, Balazs Scheidler"); 314 MODULE_DESCRIPTION("x_tables socket match module"); 315 MODULE_ALIAS("ipt_socket"); 316 MODULE_ALIAS("ip6t_socket"); 317