Blame view
net/netfilter/xt_TPROXY.c
17.1 KB
e84392707
|
1 2 3 |
/* * Transparent proxy support for Linux/iptables * |
6ad788932
|
4 |
* Copyright (c) 2006-2010 BalaBit IT Ltd. |
e84392707
|
5 6 7 8 9 10 11 |
* Author: Balazs Scheidler, Krisztian Kovacs * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */ |
ff67e4e42
|
12 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
e84392707
|
13 14 15 16 17 |
#include <linux/module.h> #include <linux/skbuff.h> #include <linux/ip.h> #include <net/checksum.h> #include <net/udp.h> |
93742cf8a
|
18 |
#include <net/tcp.h> |
e84392707
|
19 |
#include <net/inet_sock.h> |
93742cf8a
|
20 |
#include <net/inet_hashtables.h> |
cc6eb4338
|
21 |
#include <linux/inetdevice.h> |
e84392707
|
22 23 |
#include <linux/netfilter/x_tables.h> #include <linux/netfilter_ipv4/ip_tables.h> |
e84392707
|
24 25 |
#include <net/netfilter/ipv4/nf_defrag_ipv4.h> |
f6318e558
|
26 |
|
c0cd11566
|
27 |
#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) |
f6318e558
|
28 |
#define XT_TPROXY_HAVE_IPV6 1 |
cc6eb4338
|
29 30 |
#include <net/if_inet6.h> #include <net/addrconf.h> |
93742cf8a
|
31 |
#include <net/inet6_hashtables.h> |
cc6eb4338
|
32 |
#include <linux/netfilter_ipv6/ip6_tables.h> |
6ad788932
|
33 |
#include <net/netfilter/ipv6/nf_defrag_ipv6.h> |
cc6eb4338
|
34 |
#endif |
cc6eb4338
|
35 |
#include <linux/netfilter/xt_TPROXY.h> |
93742cf8a
|
36 37 38 39 |
enum nf_tproxy_lookup_t { NFT_LOOKUP_LISTENER, NFT_LOOKUP_ESTABLISHED, }; |
d503b30bd
|
40 41 |
static bool tproxy_sk_is_transparent(struct sock *sk) { |
8b5801477
|
42 43 |
switch (sk->sk_state) { case TCP_TIME_WAIT: |
d503b30bd
|
44 45 |
if (inet_twsk(sk)->tw_transparent) return true; |
8b5801477
|
46 47 48 49 50 51 52 53 |
break; case TCP_NEW_SYN_RECV: if (inet_rsk(inet_reqsk(sk))->no_srccheck) return true; break; default: if (inet_sk(sk)->transparent) return true; |
d503b30bd
|
54 |
} |
8b5801477
|
55 56 |
sock_gen_put(sk); |
d503b30bd
|
57 58 |
return false; } |
cc6eb4338
|
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
static inline __be32 tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr) { struct in_device *indev; __be32 laddr; if (user_laddr) return user_laddr; laddr = 0; rcu_read_lock(); indev = __in_dev_get_rcu(skb->dev); for_primary_ifa(indev) { laddr = ifa->ifa_local; break; } endfor_ifa(indev); rcu_read_unlock(); return laddr ? laddr : daddr; } |
e84392707
|
79 |
|
93742cf8a
|
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
/* * This is used when the user wants to intercept a connection matching * an explicit iptables rule. In this case the sockets are assumed * matching in preference order: * * - match: if there's a fully established connection matching the * _packet_ tuple, it is returned, assuming the redirection * already took place and we process a packet belonging to an * established connection * * - match: if there's a listening socket matching the redirection * (e.g. on-port & on-ip of the connection), it is returned, * regardless if it was bound to 0.0.0.0 or an explicit * address. The reasoning is that if there's an explicit rule, it * does not really matter if the listener is bound to an interface * or to 0. The user already stated that he wants redirection * (since he added the rule). * * Please note that there's an overlap between what a TPROXY target * and a socket match will match. Normally if you have both rules the * "socket" match will be the first one, effectively all packets * belonging to established connections going through that one. */ static inline struct sock * |
a583636a8
|
104 105 |
nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp, const u8 protocol, |
93742cf8a
|
106 107 108 109 110 111 |
const __be32 saddr, const __be32 daddr, const __be16 sport, const __be16 dport, const struct net_device *in, const enum nf_tproxy_lookup_t lookup_type) { struct sock *sk; |
a583636a8
|
112 |
struct tcphdr *tcph; |
93742cf8a
|
113 114 115 116 117 |
switch (protocol) { case IPPROTO_TCP: switch (lookup_type) { case NFT_LOOKUP_LISTENER: |
a583636a8
|
118 119 120 121 |
tcph = hp; sk = inet_lookup_listener(net, &tcp_hashinfo, skb, ip_hdrlen(skb) + __tcp_hdrlen(tcph), |
93742cf8a
|
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
saddr, sport, daddr, dport, in->ifindex); /* NOTE: we return listeners even if bound to * 0.0.0.0, those are filtered out in * xt_socket, since xt_TPROXY needs 0 bound * listeners too */ break; case NFT_LOOKUP_ESTABLISHED: sk = inet_lookup_established(net, &tcp_hashinfo, saddr, sport, daddr, dport, in->ifindex); break; default: BUG(); } break; case IPPROTO_UDP: sk = udp4_lib_lookup(net, saddr, sport, daddr, dport, in->ifindex); if (sk) { int connected = (sk->sk_state == TCP_ESTABLISHED); int wildcard = (inet_sk(sk)->inet_rcv_saddr == 0); /* NOTE: we return listeners even if bound to * 0.0.0.0, those are filtered out in * xt_socket, since xt_TPROXY needs 0 bound * listeners too */ if ((lookup_type == NFT_LOOKUP_ESTABLISHED && (!connected || wildcard)) || (lookup_type == NFT_LOOKUP_LISTENER && connected)) { sock_put(sk); sk = NULL; } } break; default: WARN_ON(1); sk = NULL; } pr_debug("tproxy socket lookup: proto %u %08x:%u -> %08x:%u, lookup type: %d, sock %p ", protocol, ntohl(saddr), ntohs(sport), ntohl(daddr), ntohs(dport), lookup_type, sk); return sk; } |
d8b3bfc25
|
171 |
#ifdef XT_TPROXY_HAVE_IPV6 |
93742cf8a
|
172 |
static inline struct sock * |
a583636a8
|
173 174 |
nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp, const u8 protocol, |
93742cf8a
|
175 176 177 178 179 180 |
const struct in6_addr *saddr, const struct in6_addr *daddr, const __be16 sport, const __be16 dport, const struct net_device *in, const enum nf_tproxy_lookup_t lookup_type) { struct sock *sk; |
a583636a8
|
181 |
struct tcphdr *tcph; |
93742cf8a
|
182 183 184 185 186 |
switch (protocol) { case IPPROTO_TCP: switch (lookup_type) { case NFT_LOOKUP_LISTENER: |
a583636a8
|
187 188 189 |
tcph = hp; sk = inet6_lookup_listener(net, &tcp_hashinfo, skb, thoff + __tcp_hdrlen(tcph), |
93742cf8a
|
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
saddr, sport, daddr, ntohs(dport), in->ifindex); /* NOTE: we return listeners even if bound to * 0.0.0.0, those are filtered out in * xt_socket, since xt_TPROXY needs 0 bound * listeners too */ break; case NFT_LOOKUP_ESTABLISHED: sk = __inet6_lookup_established(net, &tcp_hashinfo, saddr, sport, daddr, ntohs(dport), in->ifindex); break; default: BUG(); } break; case IPPROTO_UDP: sk = udp6_lib_lookup(net, saddr, sport, daddr, dport, in->ifindex); if (sk) { int connected = (sk->sk_state == TCP_ESTABLISHED); |
efe4208f4
|
214 |
int wildcard = ipv6_addr_any(&sk->sk_v6_rcv_saddr); |
93742cf8a
|
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
/* NOTE: we return listeners even if bound to * 0.0.0.0, those are filtered out in * xt_socket, since xt_TPROXY needs 0 bound * listeners too */ if ((lookup_type == NFT_LOOKUP_ESTABLISHED && (!connected || wildcard)) || (lookup_type == NFT_LOOKUP_LISTENER && connected)) { sock_put(sk); sk = NULL; } } break; default: WARN_ON(1); sk = NULL; } pr_debug("tproxy socket lookup: proto %u %pI6:%u -> %pI6:%u, lookup type: %d, sock %p ", protocol, saddr, ntohs(sport), daddr, ntohs(dport), lookup_type, sk); return sk; } #endif |
106e4c26b
|
240 |
/** |
2c53040f0
|
241 |
* tproxy_handle_time_wait4 - handle IPv4 TCP TIME_WAIT reopen redirections |
106e4c26b
|
242 |
* @skb: The skb being processed. |
6ad788932
|
243 244 |
* @laddr: IPv4 address to redirect to or zero. * @lport: TCP port to redirect to or zero. |
106e4c26b
|
245 246 247 248 249 250 251 |
* @sk: The TIME_WAIT TCP socket found by the lookup. * * We have to handle SYN packets arriving to TIME_WAIT sockets * differently: instead of reopening the connection we should rather * redirect the new connection to the proxy if there's a listener * socket present. * |
6ad788932
|
252 |
* tproxy_handle_time_wait4() consumes the socket reference passed in. |
106e4c26b
|
253 254 255 256 257 |
* * Returns the listener socket if there's one, the TIME_WAIT socket if * no such listener is found, or NULL if the TCP header is incomplete. */ static struct sock * |
686c9b508
|
258 259 |
tproxy_handle_time_wait4(struct net *net, struct sk_buff *skb, __be32 laddr, __be16 lport, struct sock *sk) |
106e4c26b
|
260 261 |
{ const struct iphdr *iph = ip_hdr(skb); |
106e4c26b
|
262 263 264 265 266 267 268 269 270 271 272 273 |
struct tcphdr _hdr, *hp; hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr); if (hp == NULL) { inet_twsk_put(inet_twsk(sk)); return NULL; } if (hp->syn && !hp->rst && !hp->ack && !hp->fin) { /* SYN to a TIME_WAIT socket, we'd rather redirect it * to a listener socket if there's one */ struct sock *sk2; |
a583636a8
|
274 |
sk2 = nf_tproxy_get_sock_v4(net, skb, hp, iph->protocol, |
6ad788932
|
275 276 277 278 |
iph->saddr, laddr ? laddr : iph->daddr, hp->source, lport ? lport : hp->dest, skb->dev, NFT_LOOKUP_LISTENER); if (sk2) { |
dbe7faa40
|
279 |
inet_twsk_deschedule_put(inet_twsk(sk)); |
6ad788932
|
280 281 282 283 284 285 |
sk = sk2; } } return sk; } |
fd158d79d
|
286 287 288 289 290 291 292 293 |
/* assign a socket to the skb -- consumes sk */ static void nf_tproxy_assign_sock(struct sk_buff *skb, struct sock *sk) { skb_orphan(skb); skb->sk = sk; skb->destructor = sock_edemux; } |
e84392707
|
294 |
static unsigned int |
686c9b508
|
295 |
tproxy_tg4(struct net *net, struct sk_buff *skb, __be32 laddr, __be16 lport, |
6ad788932
|
296 |
u_int32_t mark_mask, u_int32_t mark_value) |
e84392707
|
297 298 |
{ const struct iphdr *iph = ip_hdr(skb); |
e84392707
|
299 300 301 302 303 304 |
struct udphdr _hdr, *hp; struct sock *sk; hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr); if (hp == NULL) return NF_DROP; |
6ad788932
|
305 306 307 308 |
/* check if there's an ongoing connection on the packet * addresses, this happens if the redirect already happened * and the current packet belongs to an already established * connection */ |
a583636a8
|
309 |
sk = nf_tproxy_get_sock_v4(net, skb, hp, iph->protocol, |
106e4c26b
|
310 311 |
iph->saddr, iph->daddr, hp->source, hp->dest, |
6ad788932
|
312 |
skb->dev, NFT_LOOKUP_ESTABLISHED); |
106e4c26b
|
313 |
|
cc6eb4338
|
314 315 316 |
laddr = tproxy_laddr4(skb, laddr, iph->daddr); if (!lport) lport = hp->dest; |
106e4c26b
|
317 318 |
/* UDP has no TCP_TIME_WAIT state, so we never enter here */ if (sk && sk->sk_state == TCP_TIME_WAIT) |
6ad788932
|
319 |
/* reopening a TIME_WAIT connection needs special handling */ |
686c9b508
|
320 |
sk = tproxy_handle_time_wait4(net, skb, laddr, lport, sk); |
106e4c26b
|
321 |
else if (!sk) |
6ad788932
|
322 323 |
/* no, there's no established connection, check if * there's a listener on the redirected addr/port */ |
a583636a8
|
324 |
sk = nf_tproxy_get_sock_v4(net, skb, hp, iph->protocol, |
cc6eb4338
|
325 326 |
iph->saddr, laddr, hp->source, lport, |
6ad788932
|
327 328 329 |
skb->dev, NFT_LOOKUP_LISTENER); /* NOTE: assign_sock consumes our sk reference */ |
d503b30bd
|
330 |
if (sk && tproxy_sk_is_transparent(sk)) { |
6ad788932
|
331 332 333 334 335 336 337 338 |
/* This should be in a separate target, but we don't do multiple targets on the same rule yet */ skb->mark = (skb->mark & ~mark_mask) ^ mark_value; pr_debug("redirecting: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x ", iph->protocol, &iph->daddr, ntohs(hp->dest), &laddr, ntohs(lport), skb->mark); |
d503b30bd
|
339 340 |
nf_tproxy_assign_sock(skb, sk); |
6ad788932
|
341 342 |
return NF_ACCEPT; } |
cc6eb4338
|
343 344 345 346 |
pr_debug("no socket, dropping: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x ", iph->protocol, &iph->saddr, ntohs(hp->source), &iph->daddr, ntohs(hp->dest), skb->mark); |
6ad788932
|
347 348 349 350 351 352 353 |
return NF_DROP; } static unsigned int tproxy_tg4_v0(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_tproxy_target_info *tgi = par->targinfo; |
686c9b508
|
354 |
return tproxy_tg4(par->net, skb, tgi->laddr, tgi->lport, tgi->mark_mask, tgi->mark_value); |
6ad788932
|
355 356 357 358 359 360 |
} static unsigned int tproxy_tg4_v1(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_tproxy_target_info_v1 *tgi = par->targinfo; |
686c9b508
|
361 |
return tproxy_tg4(par->net, skb, tgi->laddr.ip, tgi->lport, tgi->mark_mask, tgi->mark_value); |
6ad788932
|
362 |
} |
f6318e558
|
363 |
#ifdef XT_TPROXY_HAVE_IPV6 |
cc6eb4338
|
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 |
static inline const struct in6_addr * tproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr, const struct in6_addr *daddr) { struct inet6_dev *indev; struct inet6_ifaddr *ifa; struct in6_addr *laddr; if (!ipv6_addr_any(user_laddr)) return user_laddr; laddr = NULL; rcu_read_lock(); indev = __in6_dev_get(skb->dev); if (indev) list_for_each_entry(ifa, &indev->addr_list, if_list) { if (ifa->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED)) continue; laddr = &ifa->addr; break; } rcu_read_unlock(); return laddr ? laddr : daddr; } /** |
2c53040f0
|
393 |
* tproxy_handle_time_wait6 - handle IPv6 TCP TIME_WAIT reopen redirections |
cc6eb4338
|
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 |
* @skb: The skb being processed. * @tproto: Transport protocol. * @thoff: Transport protocol header offset. * @par: Iptables target parameters. * @sk: The TIME_WAIT TCP socket found by the lookup. * * We have to handle SYN packets arriving to TIME_WAIT sockets * differently: instead of reopening the connection we should rather * redirect the new connection to the proxy if there's a listener * socket present. * * tproxy_handle_time_wait6() consumes the socket reference passed in. * * Returns the listener socket if there's one, the TIME_WAIT socket if * no such listener is found, or NULL if the TCP header is incomplete. */ static struct sock * tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff, const struct xt_action_param *par, struct sock *sk) { const struct ipv6hdr *iph = ipv6_hdr(skb); struct tcphdr _hdr, *hp; const struct xt_tproxy_target_info_v1 *tgi = par->targinfo; hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr); if (hp == NULL) { inet_twsk_put(inet_twsk(sk)); return NULL; } if (hp->syn && !hp->rst && !hp->ack && !hp->fin) { /* SYN to a TIME_WAIT socket, we'd rather redirect it * to a listener socket if there's one */ struct sock *sk2; |
a583636a8
|
429 |
sk2 = nf_tproxy_get_sock_v6(par->net, skb, thoff, hp, tproto, |
cc6eb4338
|
430 431 432 433 434 435 |
&iph->saddr, tproxy_laddr6(skb, &tgi->laddr.in6, &iph->daddr), hp->source, tgi->lport ? tgi->lport : hp->dest, skb->dev, NFT_LOOKUP_LISTENER); if (sk2) { |
dbe7faa40
|
436 |
inet_twsk_deschedule_put(inet_twsk(sk)); |
cc6eb4338
|
437 438 439 440 441 442 |
sk = sk2; } } return sk; } |
6ad788932
|
443 444 445 446 447 448 449 |
static unsigned int tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par) { const struct ipv6hdr *iph = ipv6_hdr(skb); const struct xt_tproxy_target_info_v1 *tgi = par->targinfo; struct udphdr _hdr, *hp; struct sock *sk; |
cc6eb4338
|
450 451 |
const struct in6_addr *laddr; __be16 lport; |
84018f55a
|
452 |
int thoff = 0; |
6ad788932
|
453 |
int tproto; |
84018f55a
|
454 |
tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL); |
6ad788932
|
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
if (tproto < 0) { pr_debug("unable to find transport header in IPv6 packet, dropping "); return NF_DROP; } hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr); if (hp == NULL) { pr_debug("unable to grab transport header contents in IPv6 packet, dropping "); return NF_DROP; } /* check if there's an ongoing connection on the packet * addresses, this happens if the redirect already happened * and the current packet belongs to an already established * connection */ |
a583636a8
|
472 |
sk = nf_tproxy_get_sock_v6(par->net, skb, thoff, hp, tproto, |
6ad788932
|
473 474 475 |
&iph->saddr, &iph->daddr, hp->source, hp->dest, par->in, NFT_LOOKUP_ESTABLISHED); |
cc6eb4338
|
476 477 |
laddr = tproxy_laddr6(skb, &tgi->laddr.in6, &iph->daddr); lport = tgi->lport ? tgi->lport : hp->dest; |
6ad788932
|
478 479 480 481 482 483 484 |
/* UDP has no TCP_TIME_WAIT state, so we never enter here */ if (sk && sk->sk_state == TCP_TIME_WAIT) /* reopening a TIME_WAIT connection needs special handling */ sk = tproxy_handle_time_wait6(skb, tproto, thoff, par, sk); else if (!sk) /* no there's no established connection, check if * there's a listener on the redirected addr/port */ |
a583636a8
|
485 486 |
sk = nf_tproxy_get_sock_v6(par->net, skb, thoff, hp, tproto, &iph->saddr, laddr, |
cc6eb4338
|
487 |
hp->source, lport, |
106e4c26b
|
488 |
par->in, NFT_LOOKUP_LISTENER); |
e84392707
|
489 490 |
/* NOTE: assign_sock consumes our sk reference */ |
d503b30bd
|
491 |
if (sk && tproxy_sk_is_transparent(sk)) { |
e84392707
|
492 493 494 |
/* This should be in a separate target, but we don't do multiple targets on the same rule yet */ skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value; |
6ad788932
|
495 496 |
pr_debug("redirecting: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x ", |
cc6eb4338
|
497 498 |
tproto, &iph->saddr, ntohs(hp->source), laddr, ntohs(lport), skb->mark); |
d503b30bd
|
499 500 |
nf_tproxy_assign_sock(skb, sk); |
e84392707
|
501 502 |
return NF_ACCEPT; } |
6ad788932
|
503 504 |
pr_debug("no socket, dropping: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x ", |
cc6eb4338
|
505 506 |
tproto, &iph->saddr, ntohs(hp->source), &iph->daddr, ntohs(hp->dest), skb->mark); |
e84392707
|
507 508 |
return NF_DROP; } |
6ad788932
|
509 510 511 |
static int tproxy_tg6_check(const struct xt_tgchk_param *par) { const struct ip6t_ip6 *i = par->entryinfo; |
3d8c6dce5
|
512 513 |
if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP) && !(i->invflags & IP6T_INV_PROTO)) |
6ad788932
|
514 515 516 517 518 519 520 521 522 523 |
return 0; pr_info("Can be used only in combination with " "either -p tcp or -p udp "); return -EINVAL; } #endif static int tproxy_tg4_check(const struct xt_tgchk_param *par) |
e84392707
|
524 |
{ |
af5d6dc20
|
525 |
const struct ipt_ip *i = par->entryinfo; |
e84392707
|
526 527 528 |
if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP) && !(i->invflags & IPT_INV_PROTO)) |
d6b00a534
|
529 |
return 0; |
e84392707
|
530 |
|
ff67e4e42
|
531 |
pr_info("Can be used only in combination with " |
e84392707
|
532 533 |
"either -p tcp or -p udp "); |
d6b00a534
|
534 |
return -EINVAL; |
e84392707
|
535 |
} |
6ad788932
|
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 |
static struct xt_target tproxy_tg_reg[] __read_mostly = { { .name = "TPROXY", .family = NFPROTO_IPV4, .table = "mangle", .target = tproxy_tg4_v0, .revision = 0, .targetsize = sizeof(struct xt_tproxy_target_info), .checkentry = tproxy_tg4_check, .hooks = 1 << NF_INET_PRE_ROUTING, .me = THIS_MODULE, }, { .name = "TPROXY", .family = NFPROTO_IPV4, .table = "mangle", .target = tproxy_tg4_v1, .revision = 1, .targetsize = sizeof(struct xt_tproxy_target_info_v1), .checkentry = tproxy_tg4_check, .hooks = 1 << NF_INET_PRE_ROUTING, .me = THIS_MODULE, }, |
f6318e558
|
559 |
#ifdef XT_TPROXY_HAVE_IPV6 |
6ad788932
|
560 561 562 563 564 565 566 567 568 569 570 571 |
{ .name = "TPROXY", .family = NFPROTO_IPV6, .table = "mangle", .target = tproxy_tg6_v1, .revision = 1, .targetsize = sizeof(struct xt_tproxy_target_info_v1), .checkentry = tproxy_tg6_check, .hooks = 1 << NF_INET_PRE_ROUTING, .me = THIS_MODULE, }, #endif |
e84392707
|
572 573 574 575 576 |
}; static int __init tproxy_tg_init(void) { nf_defrag_ipv4_enable(); |
f6318e558
|
577 |
#ifdef XT_TPROXY_HAVE_IPV6 |
6ad788932
|
578 579 580 581 |
nf_defrag_ipv6_enable(); #endif return xt_register_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg)); |
e84392707
|
582 583 584 585 |
} static void __exit tproxy_tg_exit(void) { |
6ad788932
|
586 |
xt_unregister_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg)); |
e84392707
|
587 588 589 590 591 |
} module_init(tproxy_tg_init); module_exit(tproxy_tg_exit); MODULE_LICENSE("GPL"); |
6ad788932
|
592 |
MODULE_AUTHOR("Balazs Scheidler, Krisztian Kovacs"); |
e84392707
|
593 594 |
MODULE_DESCRIPTION("Netfilter transparent proxy (TPROXY) target module."); MODULE_ALIAS("ipt_TPROXY"); |
6ad788932
|
595 |
MODULE_ALIAS("ip6t_TPROXY"); |