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 && !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 96 static bool 97 socket_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 106 static bool 107 socket_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) 113 static bool 114 socket_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 158 static 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 172 static 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 189 static 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 206 static 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 223 static 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 307 static int __init socket_mt_init(void) 308 { 309 return xt_register_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg)); 310 } 311 312 static void __exit socket_mt_exit(void) 313 { 314 xt_unregister_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg)); 315 } 316 317 module_init(socket_mt_init); 318 module_exit(socket_mt_exit); 319 320 MODULE_LICENSE("GPL"); 321 MODULE_AUTHOR("Krisztian Kovacs, Balazs Scheidler"); 322 MODULE_DESCRIPTION("x_tables socket match module"); 323 MODULE_ALIAS("ipt_socket"); 324 MODULE_ALIAS("ip6t_socket"); 325