diff options
| -rw-r--r-- | include/linux/netfilter/xt_TPROXY.h | 13 | ||||
| -rw-r--r-- | net/netfilter/xt_TPROXY.c | 262 |
2 files changed, 235 insertions, 40 deletions
diff --git a/include/linux/netfilter/xt_TPROXY.h b/include/linux/netfilter/xt_TPROXY.h index 152e8f97132b..3f3d69361289 100644 --- a/include/linux/netfilter/xt_TPROXY.h +++ b/include/linux/netfilter/xt_TPROXY.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #ifndef _XT_TPROXY_H_target | 1 | #ifndef _XT_TPROXY_H |
| 2 | #define _XT_TPROXY_H_target | 2 | #define _XT_TPROXY_H |
| 3 | 3 | ||
| 4 | /* TPROXY target is capable of marking the packet to perform | 4 | /* TPROXY target is capable of marking the packet to perform |
| 5 | * redirection. We can get rid of that whenever we get support for | 5 | * redirection. We can get rid of that whenever we get support for |
| @@ -11,4 +11,11 @@ struct xt_tproxy_target_info { | |||
| 11 | __be16 lport; | 11 | __be16 lport; |
| 12 | }; | 12 | }; |
| 13 | 13 | ||
| 14 | #endif /* _XT_TPROXY_H_target */ | 14 | struct xt_tproxy_target_info_v1 { |
| 15 | u_int32_t mark_mask; | ||
| 16 | u_int32_t mark_value; | ||
| 17 | union nf_inet_addr laddr; | ||
| 18 | __be16 lport; | ||
| 19 | }; | ||
| 20 | |||
| 21 | #endif /* _XT_TPROXY_H */ | ||
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c index e0b6900a92c1..d5f97e2302b8 100644 --- a/net/netfilter/xt_TPROXY.c +++ b/net/netfilter/xt_TPROXY.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Transparent proxy support for Linux/iptables | 2 | * Transparent proxy support for Linux/iptables |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2006-2007 BalaBit IT Ltd. | 4 | * Copyright (c) 2006-2010 BalaBit IT Ltd. |
| 5 | * Author: Balazs Scheidler, Krisztian Kovacs | 5 | * Author: Balazs Scheidler, Krisztian Kovacs |
| 6 | * | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
| @@ -19,15 +19,18 @@ | |||
| 19 | 19 | ||
| 20 | #include <linux/netfilter/x_tables.h> | 20 | #include <linux/netfilter/x_tables.h> |
| 21 | #include <linux/netfilter_ipv4/ip_tables.h> | 21 | #include <linux/netfilter_ipv4/ip_tables.h> |
| 22 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
| 22 | #include <linux/netfilter/xt_TPROXY.h> | 23 | #include <linux/netfilter/xt_TPROXY.h> |
| 23 | 24 | ||
| 24 | #include <net/netfilter/ipv4/nf_defrag_ipv4.h> | 25 | #include <net/netfilter/ipv4/nf_defrag_ipv4.h> |
| 26 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> | ||
| 25 | #include <net/netfilter/nf_tproxy_core.h> | 27 | #include <net/netfilter/nf_tproxy_core.h> |
| 26 | 28 | ||
| 27 | /** | 29 | /** |
| 28 | * tproxy_handle_time_wait() - handle TCP TIME_WAIT reopen redirections | 30 | * tproxy_handle_time_wait4() - handle IPv4 TCP TIME_WAIT reopen redirections |
| 29 | * @skb: The skb being processed. | 31 | * @skb: The skb being processed. |
| 30 | * @par: Iptables target parameters. | 32 | * @laddr: IPv4 address to redirect to or zero. |
| 33 | * @lport: TCP port to redirect to or zero. | ||
| 31 | * @sk: The TIME_WAIT TCP socket found by the lookup. | 34 | * @sk: The TIME_WAIT TCP socket found by the lookup. |
| 32 | * | 35 | * |
| 33 | * We have to handle SYN packets arriving to TIME_WAIT sockets | 36 | * We have to handle SYN packets arriving to TIME_WAIT sockets |
| @@ -35,16 +38,16 @@ | |||
| 35 | * redirect the new connection to the proxy if there's a listener | 38 | * redirect the new connection to the proxy if there's a listener |
| 36 | * socket present. | 39 | * socket present. |
| 37 | * | 40 | * |
| 38 | * tproxy_handle_time_wait() consumes the socket reference passed in. | 41 | * tproxy_handle_time_wait4() consumes the socket reference passed in. |
| 39 | * | 42 | * |
| 40 | * Returns the listener socket if there's one, the TIME_WAIT socket if | 43 | * Returns the listener socket if there's one, the TIME_WAIT socket if |
| 41 | * no such listener is found, or NULL if the TCP header is incomplete. | 44 | * no such listener is found, or NULL if the TCP header is incomplete. |
| 42 | */ | 45 | */ |
| 43 | static struct sock * | 46 | static struct sock * |
| 44 | tproxy_handle_time_wait(struct sk_buff *skb, const struct xt_action_param *par, struct sock *sk) | 47 | tproxy_handle_time_wait4(struct sk_buff *skb, __be32 laddr, __be16 lport, |
| 48 | struct sock *sk) | ||
| 45 | { | 49 | { |
| 46 | const struct iphdr *iph = ip_hdr(skb); | 50 | const struct iphdr *iph = ip_hdr(skb); |
| 47 | const struct xt_tproxy_target_info *tgi = par->targinfo; | ||
| 48 | struct tcphdr _hdr, *hp; | 51 | struct tcphdr _hdr, *hp; |
| 49 | 52 | ||
| 50 | hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr); | 53 | hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr); |
| @@ -59,13 +62,64 @@ tproxy_handle_time_wait(struct sk_buff *skb, const struct xt_action_param *par, | |||
| 59 | struct sock *sk2; | 62 | struct sock *sk2; |
| 60 | 63 | ||
| 61 | sk2 = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol, | 64 | sk2 = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol, |
| 62 | iph->saddr, tgi->laddr ? tgi->laddr : iph->daddr, | 65 | iph->saddr, laddr ? laddr : iph->daddr, |
| 63 | hp->source, tgi->lport ? tgi->lport : hp->dest, | 66 | hp->source, lport ? lport : hp->dest, |
| 64 | par->in, NFT_LOOKUP_LISTENER); | 67 | skb->dev, NFT_LOOKUP_LISTENER); |
| 68 | if (sk2) { | ||
| 69 | inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row); | ||
| 70 | inet_twsk_put(inet_twsk(sk)); | ||
| 71 | sk = sk2; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | return sk; | ||
| 76 | } | ||
| 77 | |||
| 78 | /** | ||
| 79 | * tproxy_handle_time_wait6() - handle IPv6 TCP TIME_WAIT reopen redirections | ||
| 80 | * @skb: The skb being processed. | ||
| 81 | * @tproto: Transport protocol. | ||
| 82 | * @thoff: Transport protocol header offset. | ||
| 83 | * @par: Iptables target parameters. | ||
| 84 | * @sk: The TIME_WAIT TCP socket found by the lookup. | ||
| 85 | * | ||
| 86 | * We have to handle SYN packets arriving to TIME_WAIT sockets | ||
| 87 | * differently: instead of reopening the connection we should rather | ||
| 88 | * redirect the new connection to the proxy if there's a listener | ||
| 89 | * socket present. | ||
| 90 | * | ||
| 91 | * tproxy_handle_time_wait6() consumes the socket reference passed in. | ||
| 92 | * | ||
| 93 | * Returns the listener socket if there's one, the TIME_WAIT socket if | ||
| 94 | * no such listener is found, or NULL if the TCP header is incomplete. | ||
| 95 | */ | ||
| 96 | static struct sock * | ||
| 97 | tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff, | ||
| 98 | const struct xt_action_param *par, | ||
| 99 | struct sock *sk) | ||
| 100 | { | ||
| 101 | const struct ipv6hdr *iph = ipv6_hdr(skb); | ||
| 102 | struct tcphdr _hdr, *hp; | ||
| 103 | const struct xt_tproxy_target_info_v1 *tgi = par->targinfo; | ||
| 104 | |||
| 105 | hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr); | ||
| 106 | if (hp == NULL) { | ||
| 107 | inet_twsk_put(inet_twsk(sk)); | ||
| 108 | return NULL; | ||
| 109 | } | ||
| 110 | |||
| 111 | if (hp->syn && !hp->rst && !hp->ack && !hp->fin) { | ||
| 112 | /* SYN to a TIME_WAIT socket, we'd rather redirect it | ||
| 113 | * to a listener socket if there's one */ | ||
| 114 | struct sock *sk2; | ||
| 115 | |||
| 116 | sk2 = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto, | ||
| 117 | &iph->saddr, | ||
| 118 | !ipv6_addr_any(&tgi->laddr.in6) ? &tgi->laddr.in6 : &iph->daddr, | ||
| 119 | hp->source, | ||
| 120 | tgi->lport ? tgi->lport : hp->dest, | ||
| 121 | skb->dev, NFT_LOOKUP_LISTENER); | ||
| 65 | if (sk2) { | 122 | if (sk2) { |
| 66 | /* yeah, there's one, let's kill the TIME_WAIT | ||
| 67 | * socket and redirect to the listener | ||
| 68 | */ | ||
| 69 | inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row); | 123 | inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row); |
| 70 | inet_twsk_put(inet_twsk(sk)); | 124 | inet_twsk_put(inet_twsk(sk)); |
| 71 | sk = sk2; | 125 | sk = sk2; |
| @@ -76,10 +130,10 @@ tproxy_handle_time_wait(struct sk_buff *skb, const struct xt_action_param *par, | |||
| 76 | } | 130 | } |
| 77 | 131 | ||
| 78 | static unsigned int | 132 | static unsigned int |
| 79 | tproxy_tg(struct sk_buff *skb, const struct xt_action_param *par) | 133 | tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport, |
| 134 | u_int32_t mark_mask, u_int32_t mark_value) | ||
| 80 | { | 135 | { |
| 81 | const struct iphdr *iph = ip_hdr(skb); | 136 | const struct iphdr *iph = ip_hdr(skb); |
| 82 | const struct xt_tproxy_target_info *tgi = par->targinfo; | ||
| 83 | struct udphdr _hdr, *hp; | 137 | struct udphdr _hdr, *hp; |
| 84 | struct sock *sk; | 138 | struct sock *sk; |
| 85 | 139 | ||
| @@ -87,18 +141,105 @@ tproxy_tg(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 87 | if (hp == NULL) | 141 | if (hp == NULL) |
| 88 | return NF_DROP; | 142 | return NF_DROP; |
| 89 | 143 | ||
| 144 | /* check if there's an ongoing connection on the packet | ||
| 145 | * addresses, this happens if the redirect already happened | ||
| 146 | * and the current packet belongs to an already established | ||
| 147 | * connection */ | ||
| 90 | sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol, | 148 | sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol, |
| 91 | iph->saddr, iph->daddr, | 149 | iph->saddr, iph->daddr, |
| 92 | hp->source, hp->dest, | 150 | hp->source, hp->dest, |
| 93 | par->in, NFT_LOOKUP_ESTABLISHED); | 151 | skb->dev, NFT_LOOKUP_ESTABLISHED); |
| 94 | 152 | ||
| 95 | /* UDP has no TCP_TIME_WAIT state, so we never enter here */ | 153 | /* UDP has no TCP_TIME_WAIT state, so we never enter here */ |
| 96 | if (sk && sk->sk_state == TCP_TIME_WAIT) | 154 | if (sk && sk->sk_state == TCP_TIME_WAIT) |
| 97 | sk = tproxy_handle_time_wait(skb, par, sk); | 155 | /* reopening a TIME_WAIT connection needs special handling */ |
| 156 | sk = tproxy_handle_time_wait4(skb, laddr, lport, sk); | ||
| 98 | else if (!sk) | 157 | else if (!sk) |
| 158 | /* no, there's no established connection, check if | ||
| 159 | * there's a listener on the redirected addr/port */ | ||
| 99 | sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol, | 160 | sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol, |
| 100 | iph->saddr, tgi->laddr ? tgi->laddr : iph->daddr, | 161 | iph->saddr, laddr ? laddr : iph->daddr, |
| 101 | hp->source, tgi->lport ? tgi->lport : hp->dest, | 162 | hp->source, lport ? lport : hp->dest, |
| 163 | skb->dev, NFT_LOOKUP_LISTENER); | ||
| 164 | |||
| 165 | /* NOTE: assign_sock consumes our sk reference */ | ||
| 166 | if (sk && nf_tproxy_assign_sock(skb, sk)) { | ||
| 167 | /* This should be in a separate target, but we don't do multiple | ||
| 168 | targets on the same rule yet */ | ||
| 169 | skb->mark = (skb->mark & ~mark_mask) ^ mark_value; | ||
| 170 | |||
| 171 | pr_debug("redirecting: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n", | ||
| 172 | iph->protocol, &iph->daddr, ntohs(hp->dest), | ||
| 173 | &laddr, ntohs(lport), skb->mark); | ||
| 174 | return NF_ACCEPT; | ||
| 175 | } | ||
| 176 | |||
| 177 | pr_debug("no socket, dropping: proto %hhu %08x:%hu -> %08x:%hu, mark: %x\n", | ||
| 178 | iph->protocol, ntohl(iph->daddr), ntohs(hp->dest), | ||
| 179 | ntohl(laddr), ntohs(lport), skb->mark); | ||
| 180 | return NF_DROP; | ||
| 181 | } | ||
| 182 | |||
| 183 | static unsigned int | ||
| 184 | tproxy_tg4_v0(struct sk_buff *skb, const struct xt_action_param *par) | ||
| 185 | { | ||
| 186 | const struct xt_tproxy_target_info *tgi = par->targinfo; | ||
| 187 | |||
| 188 | return tproxy_tg4(skb, tgi->laddr, tgi->lport, tgi->mark_mask, tgi->mark_value); | ||
| 189 | } | ||
| 190 | |||
| 191 | static unsigned int | ||
| 192 | tproxy_tg4_v1(struct sk_buff *skb, const struct xt_action_param *par) | ||
| 193 | { | ||
| 194 | const struct xt_tproxy_target_info_v1 *tgi = par->targinfo; | ||
| 195 | |||
| 196 | return tproxy_tg4(skb, tgi->laddr.ip, tgi->lport, tgi->mark_mask, tgi->mark_value); | ||
| 197 | } | ||
| 198 | |||
| 199 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
| 200 | static unsigned int | ||
| 201 | tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par) | ||
| 202 | { | ||
| 203 | const struct ipv6hdr *iph = ipv6_hdr(skb); | ||
| 204 | const struct xt_tproxy_target_info_v1 *tgi = par->targinfo; | ||
| 205 | struct udphdr _hdr, *hp; | ||
| 206 | struct sock *sk; | ||
| 207 | int thoff; | ||
| 208 | int tproto; | ||
| 209 | |||
| 210 | tproto = ipv6_find_hdr(skb, &thoff, -1, NULL); | ||
| 211 | if (tproto < 0) { | ||
| 212 | pr_debug("unable to find transport header in IPv6 packet, dropping\n"); | ||
| 213 | return NF_DROP; | ||
| 214 | } | ||
| 215 | |||
| 216 | hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr); | ||
| 217 | if (hp == NULL) { | ||
| 218 | pr_debug("unable to grab transport header contents in IPv6 packet, dropping\n"); | ||
| 219 | return NF_DROP; | ||
| 220 | } | ||
| 221 | |||
| 222 | /* check if there's an ongoing connection on the packet | ||
| 223 | * addresses, this happens if the redirect already happened | ||
| 224 | * and the current packet belongs to an already established | ||
| 225 | * connection */ | ||
| 226 | sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto, | ||
| 227 | &iph->saddr, &iph->daddr, | ||
| 228 | hp->source, hp->dest, | ||
| 229 | par->in, NFT_LOOKUP_ESTABLISHED); | ||
| 230 | |||
| 231 | /* UDP has no TCP_TIME_WAIT state, so we never enter here */ | ||
| 232 | if (sk && sk->sk_state == TCP_TIME_WAIT) | ||
| 233 | /* reopening a TIME_WAIT connection needs special handling */ | ||
| 234 | sk = tproxy_handle_time_wait6(skb, tproto, thoff, par, sk); | ||
| 235 | else if (!sk) | ||
| 236 | /* no there's no established connection, check if | ||
| 237 | * there's a listener on the redirected addr/port */ | ||
| 238 | sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto, | ||
| 239 | &iph->saddr, | ||
| 240 | !ipv6_addr_any(&tgi->laddr.in6) ? &tgi->laddr.in6 : &iph->daddr, | ||
| 241 | hp->source, | ||
| 242 | tgi->lport ? tgi->lport : hp->dest, | ||
| 102 | par->in, NFT_LOOKUP_LISTENER); | 243 | par->in, NFT_LOOKUP_LISTENER); |
| 103 | 244 | ||
| 104 | /* NOTE: assign_sock consumes our sk reference */ | 245 | /* NOTE: assign_sock consumes our sk reference */ |
| @@ -107,19 +248,33 @@ tproxy_tg(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 107 | targets on the same rule yet */ | 248 | targets on the same rule yet */ |
| 108 | skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value; | 249 | skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value; |
| 109 | 250 | ||
| 110 | pr_debug("redirecting: proto %u %08x:%u -> %08x:%u, mark: %x\n", | 251 | pr_debug("redirecting: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n", |
| 111 | iph->protocol, ntohl(iph->daddr), ntohs(hp->dest), | 252 | tproto, &iph->saddr, ntohs(hp->dest), |
| 112 | ntohl(tgi->laddr), ntohs(tgi->lport), skb->mark); | 253 | &tgi->laddr.in6, ntohs(tgi->lport), skb->mark); |
| 113 | return NF_ACCEPT; | 254 | return NF_ACCEPT; |
| 114 | } | 255 | } |
| 115 | 256 | ||
| 116 | pr_debug("no socket, dropping: proto %u %08x:%u -> %08x:%u, mark: %x\n", | 257 | pr_debug("no socket, dropping: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n", |
| 117 | iph->protocol, ntohl(iph->daddr), ntohs(hp->dest), | 258 | tproto, &iph->saddr, ntohs(hp->dest), |
| 118 | ntohl(tgi->laddr), ntohs(tgi->lport), skb->mark); | 259 | &tgi->laddr.in6, ntohs(tgi->lport), skb->mark); |
| 119 | return NF_DROP; | 260 | return NF_DROP; |
| 120 | } | 261 | } |
| 121 | 262 | ||
| 122 | static int tproxy_tg_check(const struct xt_tgchk_param *par) | 263 | static int tproxy_tg6_check(const struct xt_tgchk_param *par) |
| 264 | { | ||
| 265 | const struct ip6t_ip6 *i = par->entryinfo; | ||
| 266 | |||
| 267 | if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP) | ||
| 268 | && !(i->flags & IP6T_INV_PROTO)) | ||
| 269 | return 0; | ||
| 270 | |||
| 271 | pr_info("Can be used only in combination with " | ||
| 272 | "either -p tcp or -p udp\n"); | ||
| 273 | return -EINVAL; | ||
| 274 | } | ||
| 275 | #endif | ||
| 276 | |||
| 277 | static int tproxy_tg4_check(const struct xt_tgchk_param *par) | ||
| 123 | { | 278 | { |
| 124 | const struct ipt_ip *i = par->entryinfo; | 279 | const struct ipt_ip *i = par->entryinfo; |
| 125 | 280 | ||
| @@ -132,31 +287,64 @@ static int tproxy_tg_check(const struct xt_tgchk_param *par) | |||
| 132 | return -EINVAL; | 287 | return -EINVAL; |
| 133 | } | 288 | } |
| 134 | 289 | ||
| 135 | static struct xt_target tproxy_tg_reg __read_mostly = { | 290 | static struct xt_target tproxy_tg_reg[] __read_mostly = { |
| 136 | .name = "TPROXY", | 291 | { |
| 137 | .family = NFPROTO_IPV4, | 292 | .name = "TPROXY", |
| 138 | .table = "mangle", | 293 | .family = NFPROTO_IPV4, |
| 139 | .target = tproxy_tg, | 294 | .table = "mangle", |
| 140 | .targetsize = sizeof(struct xt_tproxy_target_info), | 295 | .target = tproxy_tg4_v0, |
| 141 | .checkentry = tproxy_tg_check, | 296 | .revision = 0, |
| 142 | .hooks = 1 << NF_INET_PRE_ROUTING, | 297 | .targetsize = sizeof(struct xt_tproxy_target_info), |
| 143 | .me = THIS_MODULE, | 298 | .checkentry = tproxy_tg4_check, |
| 299 | .hooks = 1 << NF_INET_PRE_ROUTING, | ||
| 300 | .me = THIS_MODULE, | ||
| 301 | }, | ||
| 302 | { | ||
| 303 | .name = "TPROXY", | ||
| 304 | .family = NFPROTO_IPV4, | ||
| 305 | .table = "mangle", | ||
| 306 | .target = tproxy_tg4_v1, | ||
| 307 | .revision = 1, | ||
| 308 | .targetsize = sizeof(struct xt_tproxy_target_info_v1), | ||
| 309 | .checkentry = tproxy_tg4_check, | ||
| 310 | .hooks = 1 << NF_INET_PRE_ROUTING, | ||
| 311 | .me = THIS_MODULE, | ||
| 312 | }, | ||
| 313 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
| 314 | { | ||
| 315 | .name = "TPROXY", | ||
| 316 | .family = NFPROTO_IPV6, | ||
| 317 | .table = "mangle", | ||
| 318 | .target = tproxy_tg6_v1, | ||
| 319 | .revision = 1, | ||
| 320 | .targetsize = sizeof(struct xt_tproxy_target_info_v1), | ||
| 321 | .checkentry = tproxy_tg6_check, | ||
| 322 | .hooks = 1 << NF_INET_PRE_ROUTING, | ||
| 323 | .me = THIS_MODULE, | ||
| 324 | }, | ||
| 325 | #endif | ||
| 326 | |||
| 144 | }; | 327 | }; |
| 145 | 328 | ||
| 146 | static int __init tproxy_tg_init(void) | 329 | static int __init tproxy_tg_init(void) |
| 147 | { | 330 | { |
| 148 | nf_defrag_ipv4_enable(); | 331 | nf_defrag_ipv4_enable(); |
| 149 | return xt_register_target(&tproxy_tg_reg); | 332 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
| 333 | nf_defrag_ipv6_enable(); | ||
| 334 | #endif | ||
| 335 | |||
| 336 | return xt_register_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg)); | ||
| 150 | } | 337 | } |
| 151 | 338 | ||
| 152 | static void __exit tproxy_tg_exit(void) | 339 | static void __exit tproxy_tg_exit(void) |
| 153 | { | 340 | { |
| 154 | xt_unregister_target(&tproxy_tg_reg); | 341 | xt_unregister_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg)); |
| 155 | } | 342 | } |
| 156 | 343 | ||
| 157 | module_init(tproxy_tg_init); | 344 | module_init(tproxy_tg_init); |
| 158 | module_exit(tproxy_tg_exit); | 345 | module_exit(tproxy_tg_exit); |
| 159 | MODULE_LICENSE("GPL"); | 346 | MODULE_LICENSE("GPL"); |
| 160 | MODULE_AUTHOR("Krisztian Kovacs"); | 347 | MODULE_AUTHOR("Balazs Scheidler, Krisztian Kovacs"); |
| 161 | MODULE_DESCRIPTION("Netfilter transparent proxy (TPROXY) target module."); | 348 | MODULE_DESCRIPTION("Netfilter transparent proxy (TPROXY) target module."); |
| 162 | MODULE_ALIAS("ipt_TPROXY"); | 349 | MODULE_ALIAS("ipt_TPROXY"); |
| 350 | MODULE_ALIAS("ip6t_TPROXY"); | ||
