tproxy: add lookup type checks for UDP in nf_tproxy_get_sock_v4()
[pandora-kernel.git] / include / net / netfilter / nf_tproxy_core.h
1 #ifndef _NF_TPROXY_CORE_H
2 #define _NF_TPROXY_CORE_H
3
4 #include <linux/types.h>
5 #include <linux/in.h>
6 #include <linux/skbuff.h>
7 #include <net/sock.h>
8 #include <net/inet_sock.h>
9 #include <net/tcp.h>
10
11 #define NFT_LOOKUP_ANY         0
12 #define NFT_LOOKUP_LISTENER    1
13 #define NFT_LOOKUP_ESTABLISHED 2
14
15 /* look up and get a reference to a matching socket */
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 *
66 nf_tproxy_get_sock_v4(struct net *net, const u8 protocol,
67                       const __be32 saddr, const __be32 daddr,
68                       const __be16 sport, const __be16 dport,
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
133
134 static inline void
135 nf_tproxy_put_sock(struct sock *sk)
136 {
137         /* TIME_WAIT inet sockets have to be handled differently */
138         if ((sk->sk_protocol == IPPROTO_TCP) && (sk->sk_state == TCP_TIME_WAIT))
139                 inet_twsk_put(inet_twsk(sk));
140         else
141                 sock_put(sk);
142 }
143
144 /* assign a socket to the skb -- consumes sk */
145 int
146 nf_tproxy_assign_sock(struct sk_buff *skb, struct sock *sk);
147
148 #endif