14
14
#include <linux/skbuff.h>
15
15
#include <linux/netfilter/x_tables.h>
16
16
#include <linux/netfilter_ipv4/ip_tables.h>
17
+ #include <linux/netfilter_ipv6/ip6_tables.h>
17
18
#include <net/tcp.h>
18
19
#include <net/udp.h>
19
20
#include <net/icmp.h>
20
21
#include <net/sock.h>
21
22
#include <net/inet_sock.h>
22
23
#include <net/netfilter/nf_tproxy_core.h>
23
24
#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
25
+ #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
24
26
25
27
#include <linux/netfilter/xt_socket.h>
26
28
30
32
#endif
31
33
32
34
static int
33
- extract_icmp_fields (const struct sk_buff * skb ,
35
+ extract_icmp4_fields (const struct sk_buff * skb ,
34
36
u8 * protocol ,
35
37
__be32 * raddr ,
36
38
__be32 * laddr ,
@@ -86,7 +88,6 @@ extract_icmp_fields(const struct sk_buff *skb,
86
88
return 0 ;
87
89
}
88
90
89
-
90
91
static bool
91
92
socket_match (const struct sk_buff * skb , struct xt_action_param * par ,
92
93
const struct xt_socket_mtinfo1 * info )
@@ -115,7 +116,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
115
116
dport = hp -> dest ;
116
117
117
118
} else if (iph -> protocol == IPPROTO_ICMP ) {
118
- if (extract_icmp_fields (skb , & protocol , & saddr , & daddr ,
119
+ if (extract_icmp4_fields (skb , & protocol , & saddr , & daddr ,
119
120
& sport , & dport ))
120
121
return false;
121
122
} else {
@@ -165,32 +166,157 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
165
166
sk = NULL ;
166
167
}
167
168
168
- pr_debug ("proto %u %08x:%u -> %08x:%u (orig %08x:%u ) sock %p\n" ,
169
- protocol , ntohl ( saddr ) , ntohs (sport ),
170
- ntohl ( daddr ) , ntohs (dport ),
171
- ntohl ( iph -> daddr ) , hp ? ntohs (hp -> dest ) : 0 , sk );
169
+ pr_debug ("proto %hhu %pI4:%hu -> %pI4:%hu (orig %pI4:%hu ) sock %p\n" ,
170
+ protocol , & saddr , ntohs (sport ),
171
+ & daddr , ntohs (dport ),
172
+ & iph -> daddr , hp ? ntohs (hp -> dest ) : 0 , sk );
172
173
173
174
return (sk != NULL );
174
175
}
175
176
176
177
static bool
177
- socket_mt_v0 (const struct sk_buff * skb , struct xt_action_param * par )
178
+ socket_mt4_v0 (const struct sk_buff * skb , struct xt_action_param * par )
178
179
{
179
180
return socket_match (skb , par , NULL );
180
181
}
181
182
182
183
static bool
183
- socket_mt_v1 (const struct sk_buff * skb , struct xt_action_param * par )
184
+ socket_mt4_v1 (const struct sk_buff * skb , struct xt_action_param * par )
184
185
{
185
186
return socket_match (skb , par , par -> matchinfo );
186
187
}
187
188
189
+ #if defined(CONFIG_IPV6 ) || defined(CONFIG_IPV6_MODULE )
190
+
191
+ static int
192
+ extract_icmp6_fields (const struct sk_buff * skb ,
193
+ unsigned int outside_hdrlen ,
194
+ u8 * protocol ,
195
+ struct in6_addr * * raddr ,
196
+ struct in6_addr * * laddr ,
197
+ __be16 * rport ,
198
+ __be16 * lport )
199
+ {
200
+ struct ipv6hdr * inside_iph , _inside_iph ;
201
+ struct icmp6hdr * icmph , _icmph ;
202
+ __be16 * ports , _ports [2 ];
203
+ u8 inside_nexthdr ;
204
+ int inside_hdrlen ;
205
+
206
+ icmph = skb_header_pointer (skb , outside_hdrlen ,
207
+ sizeof (_icmph ), & _icmph );
208
+ if (icmph == NULL )
209
+ return 1 ;
210
+
211
+ if (icmph -> icmp6_type & ICMPV6_INFOMSG_MASK )
212
+ return 1 ;
213
+
214
+ inside_iph = skb_header_pointer (skb , outside_hdrlen + sizeof (_icmph ), sizeof (_inside_iph ), & _inside_iph );
215
+ if (inside_iph == NULL )
216
+ return 1 ;
217
+ inside_nexthdr = inside_iph -> nexthdr ;
218
+
219
+ inside_hdrlen = ipv6_skip_exthdr (skb , outside_hdrlen + sizeof (_icmph ) + sizeof (_inside_iph ), & inside_nexthdr );
220
+ if (inside_hdrlen < 0 )
221
+ return 1 ; /* hjm: Packet has no/incomplete transport layer headers. */
222
+
223
+ if (inside_nexthdr != IPPROTO_TCP &&
224
+ inside_nexthdr != IPPROTO_UDP )
225
+ return 1 ;
226
+
227
+ ports = skb_header_pointer (skb , inside_hdrlen ,
228
+ sizeof (_ports ), & _ports );
229
+ if (ports == NULL )
230
+ return 1 ;
231
+
232
+ /* the inside IP packet is the one quoted from our side, thus
233
+ * its saddr is the local address */
234
+ * protocol = inside_nexthdr ;
235
+ * laddr = & inside_iph -> saddr ;
236
+ * lport = ports [0 ];
237
+ * raddr = & inside_iph -> daddr ;
238
+ * rport = ports [1 ];
239
+
240
+ return 0 ;
241
+ }
242
+
243
+ static bool
244
+ socket_mt6_v1 (const struct sk_buff * skb , struct xt_action_param * par )
245
+ {
246
+ struct ipv6hdr * iph = ipv6_hdr (skb );
247
+ struct udphdr _hdr , * hp = NULL ;
248
+ struct sock * sk ;
249
+ struct in6_addr * daddr , * saddr ;
250
+ __be16 dport , sport ;
251
+ int thoff ;
252
+ u8 tproto ;
253
+ const struct xt_socket_mtinfo1 * info = (struct xt_socket_mtinfo1 * ) par -> matchinfo ;
254
+
255
+ tproto = ipv6_find_hdr (skb , & thoff , -1 , NULL );
256
+ if (tproto < 0 ) {
257
+ pr_debug ("unable to find transport header in IPv6 packet, dropping\n" );
258
+ return NF_DROP ;
259
+ }
260
+
261
+ if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP ) {
262
+ hp = skb_header_pointer (skb , thoff ,
263
+ sizeof (_hdr ), & _hdr );
264
+ if (hp == NULL )
265
+ return false;
266
+
267
+ saddr = & iph -> saddr ;
268
+ sport = hp -> source ;
269
+ daddr = & iph -> daddr ;
270
+ dport = hp -> dest ;
271
+
272
+ } else if (tproto == IPPROTO_ICMPV6 ) {
273
+ if (extract_icmp6_fields (skb , thoff , & tproto , & saddr , & daddr ,
274
+ & sport , & dport ))
275
+ return false;
276
+ } else {
277
+ return false;
278
+ }
279
+
280
+ sk = nf_tproxy_get_sock_v6 (dev_net (skb -> dev ), tproto ,
281
+ saddr , daddr , sport , dport , par -> in , NFT_LOOKUP_ANY );
282
+ if (sk != NULL ) {
283
+ bool wildcard ;
284
+ bool transparent = true;
285
+
286
+ /* Ignore sockets listening on INADDR_ANY */
287
+ wildcard = (sk -> sk_state != TCP_TIME_WAIT &&
288
+ ipv6_addr_any (& inet6_sk (sk )-> rcv_saddr ));
289
+
290
+ /* Ignore non-transparent sockets,
291
+ if XT_SOCKET_TRANSPARENT is used */
292
+ if (info && info -> flags & XT_SOCKET_TRANSPARENT )
293
+ transparent = ((sk -> sk_state != TCP_TIME_WAIT &&
294
+ inet_sk (sk )-> transparent ) ||
295
+ (sk -> sk_state == TCP_TIME_WAIT &&
296
+ inet_twsk (sk )-> tw_transparent ));
297
+
298
+ nf_tproxy_put_sock (sk );
299
+
300
+ if (wildcard || !transparent )
301
+ sk = NULL ;
302
+ }
303
+
304
+ pr_debug ("proto %hhu %pI6:%hu -> %pI6:%hu "
305
+ "(orig %pI6:%hu) sock %p\n" ,
306
+ tproto , saddr , ntohs (sport ),
307
+ daddr , ntohs (dport ),
308
+ & iph -> daddr , hp ? ntohs (hp -> dest ) : 0 , sk );
309
+
310
+ return (sk != NULL );
311
+ }
312
+ #endif
313
+
188
314
static struct xt_match socket_mt_reg [] __read_mostly = {
189
315
{
190
316
.name = "socket" ,
191
317
.revision = 0 ,
192
318
.family = NFPROTO_IPV4 ,
193
- .match = socket_mt_v0 ,
319
+ .match = socket_mt4_v0 ,
194
320
.hooks = (1 << NF_INET_PRE_ROUTING ) |
195
321
(1 << NF_INET_LOCAL_IN ),
196
322
.me = THIS_MODULE ,
@@ -199,17 +325,33 @@ static struct xt_match socket_mt_reg[] __read_mostly = {
199
325
.name = "socket" ,
200
326
.revision = 1 ,
201
327
.family = NFPROTO_IPV4 ,
202
- .match = socket_mt_v1 ,
328
+ .match = socket_mt4_v1 ,
203
329
.matchsize = sizeof (struct xt_socket_mtinfo1 ),
204
330
.hooks = (1 << NF_INET_PRE_ROUTING ) |
205
331
(1 << NF_INET_LOCAL_IN ),
206
332
.me = THIS_MODULE ,
207
333
},
334
+ #if defined(CONFIG_IPV6 ) || defined (CONFIG_IPV6_MODULE )
335
+ {
336
+ .name = "socket" ,
337
+ .revision = 1 ,
338
+ .family = NFPROTO_IPV6 ,
339
+ .match = socket_mt6_v1 ,
340
+ .matchsize = sizeof (struct xt_socket_mtinfo1 ),
341
+ .hooks = (1 << NF_INET_PRE_ROUTING ) |
342
+ (1 << NF_INET_LOCAL_IN ),
343
+ .me = THIS_MODULE ,
344
+ },
345
+ #endif
208
346
};
209
347
210
348
static int __init socket_mt_init (void )
211
349
{
212
350
nf_defrag_ipv4_enable ();
351
+ #if defined(CONFIG_IPV6 ) || defined(CONFIG_IPV6_MODULE )
352
+ nf_defrag_ipv6_enable ();
353
+ #endif
354
+
213
355
return xt_register_matches (socket_mt_reg , ARRAY_SIZE (socket_mt_reg ));
214
356
}
215
357
@@ -225,3 +367,4 @@ MODULE_LICENSE("GPL");
225
367
MODULE_AUTHOR ("Krisztian Kovacs, Balazs Scheidler" );
226
368
MODULE_DESCRIPTION ("x_tables socket match module" );
227
369
MODULE_ALIAS ("ipt_socket" );
370
+ MODULE_ALIAS ("ip6t_socket" );
0 commit comments