Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tproxy: add lookup type checks for UDP in nf_tproxy_get_sock_v4()

Also, inline this function as the lookup_type is always a literal
and inlining removes branches performed at runtime.

Signed-off-by: Balazs Scheidler <bazsi@balabit.hu>
Signed-off-by: KOVACS Krisztian <hidden@balabit.hu>
Signed-off-by: Patrick McHardy <kaber@trash.net>

authored by

Balazs Scheidler and committed by
Patrick McHardy
6006db84 106e4c26

+114 -50
+114 -2
include/net/netfilter/nf_tproxy_core.h
··· 13 13 #define NFT_LOOKUP_ESTABLISHED 2 14 14 15 15 /* look up and get a reference to a matching socket */ 16 - extern struct sock * 16 + 17 + 18 + /* This function is used by the 'TPROXY' target and the 'socket' 19 + * match. The following lookups are supported: 20 + * 21 + * Explicit TProxy target rule 22 + * =========================== 23 + * 24 + * This is used when the user wants to intercept a connection matching 25 + * an explicit iptables rule. In this case the sockets are assumed 26 + * matching in preference order: 27 + * 28 + * - match: if there's a fully established connection matching the 29 + * _packet_ tuple, it is returned, assuming the redirection 30 + * already took place and we process a packet belonging to an 31 + * established connection 32 + * 33 + * - match: if there's a listening socket matching the redirection 34 + * (e.g. on-port & on-ip of the connection), it is returned, 35 + * regardless if it was bound to 0.0.0.0 or an explicit 36 + * address. The reasoning is that if there's an explicit rule, it 37 + * does not really matter if the listener is bound to an interface 38 + * or to 0. The user already stated that he wants redirection 39 + * (since he added the rule). 40 + * 41 + * "socket" match based redirection (no specific rule) 42 + * =================================================== 43 + * 44 + * There are connections with dynamic endpoints (e.g. FTP data 45 + * connection) that the user is unable to add explicit rules 46 + * for. These are taken care of by a generic "socket" rule. It is 47 + * assumed that the proxy application is trusted to open such 48 + * connections without explicit iptables rule (except of course the 49 + * generic 'socket' rule). In this case the following sockets are 50 + * matched in preference order: 51 + * 52 + * - match: if there's a fully established connection matching the 53 + * _packet_ tuple 54 + * 55 + * - match: if there's a non-zero bound listener (possibly with a 56 + * non-local address) We don't accept zero-bound listeners, since 57 + * then local services could intercept traffic going through the 58 + * box. 59 + * 60 + * Please note that there's an overlap between what a TPROXY target 61 + * and a socket match will match. Normally if you have both rules the 62 + * "socket" match will be the first one, effectively all packets 63 + * belonging to established connections going through that one. 64 + */ 65 + static inline struct sock * 17 66 nf_tproxy_get_sock_v4(struct net *net, const u8 protocol, 18 67 const __be32 saddr, const __be32 daddr, 19 68 const __be16 sport, const __be16 dport, 20 - const struct net_device *in, int lookup_type); 69 + const struct net_device *in, int lookup_type) 70 + { 71 + struct sock *sk; 72 + 73 + /* look up socket */ 74 + switch (protocol) { 75 + case IPPROTO_TCP: 76 + switch (lookup_type) { 77 + case NFT_LOOKUP_ANY: 78 + sk = __inet_lookup(net, &tcp_hashinfo, 79 + saddr, sport, daddr, dport, 80 + in->ifindex); 81 + break; 82 + case NFT_LOOKUP_LISTENER: 83 + sk = inet_lookup_listener(net, &tcp_hashinfo, 84 + daddr, dport, 85 + in->ifindex); 86 + 87 + /* NOTE: we return listeners even if bound to 88 + * 0.0.0.0, those are filtered out in 89 + * xt_socket, since xt_TPROXY needs 0 bound 90 + * listeners too */ 91 + 92 + break; 93 + case NFT_LOOKUP_ESTABLISHED: 94 + sk = inet_lookup_established(net, &tcp_hashinfo, 95 + saddr, sport, daddr, dport, 96 + in->ifindex); 97 + break; 98 + default: 99 + WARN_ON(1); 100 + sk = NULL; 101 + break; 102 + } 103 + break; 104 + case IPPROTO_UDP: 105 + sk = udp4_lib_lookup(net, saddr, sport, daddr, dport, 106 + in->ifindex); 107 + if (sk && lookup_type != NFT_LOOKUP_ANY) { 108 + int connected = (sk->sk_state == TCP_ESTABLISHED); 109 + int wildcard = (inet_sk(sk)->inet_rcv_saddr == 0); 110 + 111 + /* NOTE: we return listeners even if bound to 112 + * 0.0.0.0, those are filtered out in 113 + * xt_socket, since xt_TPROXY needs 0 bound 114 + * listeners too */ 115 + if ((lookup_type == NFT_LOOKUP_ESTABLISHED && (!connected || wildcard)) || 116 + (lookup_type == NFT_LOOKUP_LISTENER && connected)) { 117 + sock_put(sk); 118 + sk = NULL; 119 + } 120 + } 121 + break; 122 + default: 123 + WARN_ON(1); 124 + sk = NULL; 125 + } 126 + 127 + pr_debug("tproxy socket lookup: proto %u %08x:%u -> %08x:%u, lookup type: %d, sock %p\n", 128 + protocol, ntohl(saddr), ntohs(sport), ntohl(daddr), ntohs(dport), lookup_type, sk); 129 + 130 + return sk; 131 + } 132 + 21 133 22 134 static inline void 23 135 nf_tproxy_put_sock(struct sock *sk)
-48
net/netfilter/nf_tproxy_core.c
··· 18 18 #include <net/udp.h> 19 19 #include <net/netfilter/nf_tproxy_core.h> 20 20 21 - struct sock * 22 - nf_tproxy_get_sock_v4(struct net *net, const u8 protocol, 23 - const __be32 saddr, const __be32 daddr, 24 - const __be16 sport, const __be16 dport, 25 - const struct net_device *in, int lookup_type) 26 - { 27 - struct sock *sk; 28 - 29 - /* look up socket */ 30 - switch (protocol) { 31 - case IPPROTO_TCP: 32 - switch (lookup_type) { 33 - case NFT_LOOKUP_ANY: 34 - sk = __inet_lookup(net, &tcp_hashinfo, 35 - saddr, sport, daddr, dport, 36 - in->ifindex); 37 - break; 38 - case NFT_LOOKUP_LISTENER: 39 - sk = inet_lookup_listener(net, &tcp_hashinfo, 40 - daddr, dport, 41 - in->ifindex); 42 - break; 43 - case NFT_LOOKUP_ESTABLISHED: 44 - sk = inet_lookup_established(net, &tcp_hashinfo, 45 - saddr, sport, daddr, dport, 46 - in->ifindex); 47 - break; 48 - default: 49 - WARN_ON(1); 50 - sk = NULL; 51 - break; 52 - } 53 - break; 54 - case IPPROTO_UDP: 55 - sk = udp4_lib_lookup(net, saddr, sport, daddr, dport, 56 - in->ifindex); 57 - break; 58 - default: 59 - WARN_ON(1); 60 - sk = NULL; 61 - } 62 - 63 - pr_debug("tproxy socket lookup: proto %u %08x:%u -> %08x:%u, lookup type: %d, sock %p\n", 64 - protocol, ntohl(saddr), ntohs(sport), ntohl(daddr), ntohs(dport), lookup_type, sk); 65 - 66 - return sk; 67 - } 68 - EXPORT_SYMBOL_GPL(nf_tproxy_get_sock_v4); 69 21 70 22 static void 71 23 nf_tproxy_destructor(struct sk_buff *skb)