1e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian/*
2e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian * Transparent proxy support for Linux/iptables
3e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian *
46ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler * Copyright (c) 2006-2010 BalaBit IT Ltd.
5e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian * Author: Balazs Scheidler, Krisztian Kovacs
6e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian *
7e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian * This program is free software; you can redistribute it and/or modify
8e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian * it under the terms of the GNU General Public License version 2 as
9e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian * published by the Free Software Foundation.
10e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian *
11e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian */
12ff67e4e42bd178b1179c4d8e5c1fde18758ce84fJan Engelhardt#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian#include <linux/module.h>
14e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian#include <linux/skbuff.h>
15e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian#include <linux/ip.h>
16e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian#include <net/checksum.h>
17e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian#include <net/udp.h>
18e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian#include <net/inet_sock.h>
19cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler#include <linux/inetdevice.h>
20e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian#include <linux/netfilter/x_tables.h>
21e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian#include <linux/netfilter_ipv4/ip_tables.h>
22e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian
23e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
24f6318e558806c925029dc101f14874be9f9fa78fKOVACS Krisztian
25c0cd115667bcd23c2a31fe2114beaab3608de68cIgor Maravić#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
26f6318e558806c925029dc101f14874be9f9fa78fKOVACS Krisztian#define XT_TPROXY_HAVE_IPV6 1
27cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler#include <net/if_inet6.h>
28cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler#include <net/addrconf.h>
29cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler#include <linux/netfilter_ipv6/ip6_tables.h>
306ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
31cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler#endif
32cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
33e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian#include <net/netfilter/nf_tproxy_core.h>
34cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler#include <linux/netfilter/xt_TPROXY.h>
35cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
36d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphalstatic bool tproxy_sk_is_transparent(struct sock *sk)
37d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal{
38d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal	if (sk->sk_state != TCP_TIME_WAIT) {
39d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal		if (inet_sk(sk)->transparent)
40d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal			return true;
41d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal		sock_put(sk);
42d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal	} else {
43d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal		if (inet_twsk(sk)->tw_transparent)
44d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal			return true;
45d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal		inet_twsk_put(inet_twsk(sk));
46d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal	}
47d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal	return false;
48d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal}
49d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal
50cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidlerstatic inline __be32
51cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidlertproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr)
52cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler{
53cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	struct in_device *indev;
54cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	__be32 laddr;
55cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
56cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	if (user_laddr)
57cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		return user_laddr;
58cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
59cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	laddr = 0;
60cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	rcu_read_lock();
61cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	indev = __in_dev_get_rcu(skb->dev);
62cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	for_primary_ifa(indev) {
63cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		laddr = ifa->ifa_local;
64cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		break;
65cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	} endfor_ifa(indev);
66cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	rcu_read_unlock();
67cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
68cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	return laddr ? laddr : daddr;
69cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler}
70e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian
71106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler/**
722c53040f018b6c36a46eec75b9b937aaa5f78e6dBen Hutchings * tproxy_handle_time_wait4 - handle IPv4 TCP TIME_WAIT reopen redirections
73106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler * @skb:	The skb being processed.
746ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler * @laddr:	IPv4 address to redirect to or zero.
756ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler * @lport:	TCP port to redirect to or zero.
76106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler * @sk:		The TIME_WAIT TCP socket found by the lookup.
77106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler *
78106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler * We have to handle SYN packets arriving to TIME_WAIT sockets
79106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler * differently: instead of reopening the connection we should rather
80106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler * redirect the new connection to the proxy if there's a listener
81106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler * socket present.
82106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler *
836ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler * tproxy_handle_time_wait4() consumes the socket reference passed in.
84106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler *
85106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler * Returns the listener socket if there's one, the TIME_WAIT socket if
86106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler * no such listener is found, or NULL if the TCP header is incomplete.
87106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler */
88106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidlerstatic struct sock *
896ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidlertproxy_handle_time_wait4(struct sk_buff *skb, __be32 laddr, __be16 lport,
906ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler			struct sock *sk)
91106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler{
92106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler	const struct iphdr *iph = ip_hdr(skb);
93106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler	struct tcphdr _hdr, *hp;
94106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler
95106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler	hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr);
96106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler	if (hp == NULL) {
97106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler		inet_twsk_put(inet_twsk(sk));
98106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler		return NULL;
99106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler	}
100106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler
101106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler	if (hp->syn && !hp->rst && !hp->ack && !hp->fin) {
102106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler		/* SYN to a TIME_WAIT socket, we'd rather redirect it
103106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler		 * to a listener socket if there's one */
104106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler		struct sock *sk2;
105106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler
106106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler		sk2 = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
1076ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler					    iph->saddr, laddr ? laddr : iph->daddr,
1086ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler					    hp->source, lport ? lport : hp->dest,
1096ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler					    skb->dev, NFT_LOOKUP_LISTENER);
1106ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		if (sk2) {
1116ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler			inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row);
1126ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler			inet_twsk_put(inet_twsk(sk));
1136ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler			sk = sk2;
1146ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		}
1156ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	}
1166ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
1176ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	return sk;
1186ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler}
1196ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
120e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztianstatic unsigned int
1216ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidlertproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
1226ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	   u_int32_t mark_mask, u_int32_t mark_value)
123e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian{
124e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian	const struct iphdr *iph = ip_hdr(skb);
125e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian	struct udphdr _hdr, *hp;
126e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian	struct sock *sk;
127e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian
128e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian	hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr);
129e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian	if (hp == NULL)
130e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian		return NF_DROP;
131e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian
1326ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	/* check if there's an ongoing connection on the packet
1336ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	 * addresses, this happens if the redirect already happened
1346ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	 * and the current packet belongs to an already established
1356ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	 * connection */
136e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian	sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
137106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler				   iph->saddr, iph->daddr,
138106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler				   hp->source, hp->dest,
1396ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler				   skb->dev, NFT_LOOKUP_ESTABLISHED);
140106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler
141cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	laddr = tproxy_laddr4(skb, laddr, iph->daddr);
142cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	if (!lport)
143cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		lport = hp->dest;
144cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
145106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler	/* UDP has no TCP_TIME_WAIT state, so we never enter here */
146106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler	if (sk && sk->sk_state == TCP_TIME_WAIT)
1476ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		/* reopening a TIME_WAIT connection needs special handling */
1486ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		sk = tproxy_handle_time_wait4(skb, laddr, lport, sk);
149106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler	else if (!sk)
1506ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		/* no, there's no established connection, check if
1516ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		 * there's a listener on the redirected addr/port */
152106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler		sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol,
153cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler					   iph->saddr, laddr,
154cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler					   hp->source, lport,
1556ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler					   skb->dev, NFT_LOOKUP_LISTENER);
1566ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
1576ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	/* NOTE: assign_sock consumes our sk reference */
158d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal	if (sk && tproxy_sk_is_transparent(sk)) {
1596ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		/* This should be in a separate target, but we don't do multiple
1606ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		   targets on the same rule yet */
1616ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		skb->mark = (skb->mark & ~mark_mask) ^ mark_value;
1626ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
1636ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		pr_debug("redirecting: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n",
1646ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler			 iph->protocol, &iph->daddr, ntohs(hp->dest),
1656ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler			 &laddr, ntohs(lport), skb->mark);
166d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal
167d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal		nf_tproxy_assign_sock(skb, sk);
1686ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		return NF_ACCEPT;
1696ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	}
1706ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
171cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	pr_debug("no socket, dropping: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n",
172cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		 iph->protocol, &iph->saddr, ntohs(hp->source),
173cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		 &iph->daddr, ntohs(hp->dest), skb->mark);
1746ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	return NF_DROP;
1756ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler}
1766ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
1776ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidlerstatic unsigned int
1786ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidlertproxy_tg4_v0(struct sk_buff *skb, const struct xt_action_param *par)
1796ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler{
1806ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	const struct xt_tproxy_target_info *tgi = par->targinfo;
1816ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
1826ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	return tproxy_tg4(skb, tgi->laddr, tgi->lport, tgi->mark_mask, tgi->mark_value);
1836ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler}
1846ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
1856ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidlerstatic unsigned int
1866ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidlertproxy_tg4_v1(struct sk_buff *skb, const struct xt_action_param *par)
1876ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler{
1886ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
1896ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
1906ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	return tproxy_tg4(skb, tgi->laddr.ip, tgi->lport, tgi->mark_mask, tgi->mark_value);
1916ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler}
1926ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
193f6318e558806c925029dc101f14874be9f9fa78fKOVACS Krisztian#ifdef XT_TPROXY_HAVE_IPV6
194cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
195cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidlerstatic inline const struct in6_addr *
196cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidlertproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr,
197cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	      const struct in6_addr *daddr)
198cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler{
199cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	struct inet6_dev *indev;
200cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	struct inet6_ifaddr *ifa;
201cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	struct in6_addr *laddr;
202cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
203cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	if (!ipv6_addr_any(user_laddr))
204cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		return user_laddr;
205cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	laddr = NULL;
206cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
207cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	rcu_read_lock();
208cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	indev = __in6_dev_get(skb->dev);
209cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	if (indev)
210cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		list_for_each_entry(ifa, &indev->addr_list, if_list) {
211cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler			if (ifa->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED))
212cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler				continue;
213cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
214cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler			laddr = &ifa->addr;
215cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler			break;
216cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		}
217cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	rcu_read_unlock();
218cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
219cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	return laddr ? laddr : daddr;
220cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler}
221cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
222cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler/**
2232c53040f018b6c36a46eec75b9b937aaa5f78e6dBen Hutchings * tproxy_handle_time_wait6 - handle IPv6 TCP TIME_WAIT reopen redirections
224cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler * @skb:	The skb being processed.
225cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler * @tproto:	Transport protocol.
226cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler * @thoff:	Transport protocol header offset.
227cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler * @par:	Iptables target parameters.
228cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler * @sk:		The TIME_WAIT TCP socket found by the lookup.
229cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler *
230cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler * We have to handle SYN packets arriving to TIME_WAIT sockets
231cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler * differently: instead of reopening the connection we should rather
232cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler * redirect the new connection to the proxy if there's a listener
233cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler * socket present.
234cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler *
235cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler * tproxy_handle_time_wait6() consumes the socket reference passed in.
236cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler *
237cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler * Returns the listener socket if there's one, the TIME_WAIT socket if
238cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler * no such listener is found, or NULL if the TCP header is incomplete.
239cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler */
240cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidlerstatic struct sock *
241cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidlertproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff,
242cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler			 const struct xt_action_param *par,
243cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler			 struct sock *sk)
244cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler{
245cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	const struct ipv6hdr *iph = ipv6_hdr(skb);
246cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	struct tcphdr _hdr, *hp;
247cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
248cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
249cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
250cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	if (hp == NULL) {
251cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		inet_twsk_put(inet_twsk(sk));
252cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		return NULL;
253cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	}
254cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
255cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	if (hp->syn && !hp->rst && !hp->ack && !hp->fin) {
256cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		/* SYN to a TIME_WAIT socket, we'd rather redirect it
257cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		 * to a listener socket if there's one */
258cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		struct sock *sk2;
259cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
260cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		sk2 = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
261cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler					    &iph->saddr,
262cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler					    tproxy_laddr6(skb, &tgi->laddr.in6, &iph->daddr),
263cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler					    hp->source,
264cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler					    tgi->lport ? tgi->lport : hp->dest,
265cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler					    skb->dev, NFT_LOOKUP_LISTENER);
266cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		if (sk2) {
267cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler			inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row);
268cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler			inet_twsk_put(inet_twsk(sk));
269cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler			sk = sk2;
270cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		}
271cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	}
272cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
273cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	return sk;
274cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler}
275cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
2766ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidlerstatic unsigned int
2776ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidlertproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
2786ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler{
2796ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	const struct ipv6hdr *iph = ipv6_hdr(skb);
2806ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
2816ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	struct udphdr _hdr, *hp;
2826ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	struct sock *sk;
283cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	const struct in6_addr *laddr;
284cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	__be16 lport;
28584018f55ab883f03d41ec3c9ac7f0cc80830b20fHans Schillstrom	int thoff = 0;
2866ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	int tproto;
2876ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
28884018f55ab883f03d41ec3c9ac7f0cc80830b20fHans Schillstrom	tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
2896ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	if (tproto < 0) {
2906ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		pr_debug("unable to find transport header in IPv6 packet, dropping\n");
2916ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		return NF_DROP;
2926ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	}
2936ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
2946ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
2956ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	if (hp == NULL) {
2966ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		pr_debug("unable to grab transport header contents in IPv6 packet, dropping\n");
2976ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		return NF_DROP;
2986ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	}
2996ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
3006ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	/* check if there's an ongoing connection on the packet
3016ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	 * addresses, this happens if the redirect already happened
3026ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	 * and the current packet belongs to an already established
3036ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	 * connection */
3046ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
3056ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler				   &iph->saddr, &iph->daddr,
3066ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler				   hp->source, hp->dest,
3076ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler				   par->in, NFT_LOOKUP_ESTABLISHED);
3086ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
309cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	laddr = tproxy_laddr6(skb, &tgi->laddr.in6, &iph->daddr);
310cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler	lport = tgi->lport ? tgi->lport : hp->dest;
311cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
3126ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	/* UDP has no TCP_TIME_WAIT state, so we never enter here */
3136ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	if (sk && sk->sk_state == TCP_TIME_WAIT)
3146ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		/* reopening a TIME_WAIT connection needs special handling */
3156ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		sk = tproxy_handle_time_wait6(skb, tproto, thoff, par, sk);
3166ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	else if (!sk)
3176ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		/* no there's no established connection, check if
3186ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		 * there's a listener on the redirected addr/port */
3196ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		sk = nf_tproxy_get_sock_v6(dev_net(skb->dev), tproto,
320cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler					   &iph->saddr, laddr,
321cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler					   hp->source, lport,
322106e4c26b1529e559d1aae777f11b4f8f7bafc26Balazs Scheidler					   par->in, NFT_LOOKUP_LISTENER);
323e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian
324e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian	/* NOTE: assign_sock consumes our sk reference */
325d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal	if (sk && tproxy_sk_is_transparent(sk)) {
326e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian		/* This should be in a separate target, but we don't do multiple
327e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian		   targets on the same rule yet */
328e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian		skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value;
329e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian
3306ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		pr_debug("redirecting: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n",
331cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler			 tproto, &iph->saddr, ntohs(hp->source),
332cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler			 laddr, ntohs(lport), skb->mark);
333d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal
334d503b30bd648b3cb4e5f50b65d27e389960cc6d9Florian Westphal		nf_tproxy_assign_sock(skb, sk);
335e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian		return NF_ACCEPT;
336e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian	}
337e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian
3386ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	pr_debug("no socket, dropping: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n",
339cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		 tproto, &iph->saddr, ntohs(hp->source),
340cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler		 &iph->daddr, ntohs(hp->dest), skb->mark);
341cc6eb433856983e91071469c4ce57accb6947ccbBalazs Scheidler
342e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian	return NF_DROP;
343e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian}
344e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian
3456ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidlerstatic int tproxy_tg6_check(const struct xt_tgchk_param *par)
3466ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler{
3476ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	const struct ip6t_ip6 *i = par->entryinfo;
3486ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
3496ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
3506ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	    && !(i->flags & IP6T_INV_PROTO))
3516ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		return 0;
3526ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
3536ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	pr_info("Can be used only in combination with "
3546ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		"either -p tcp or -p udp\n");
3556ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	return -EINVAL;
3566ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler}
3576ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler#endif
3586ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
3596ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidlerstatic int tproxy_tg4_check(const struct xt_tgchk_param *par)
360e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian{
361af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	const struct ipt_ip *i = par->entryinfo;
362e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian
363e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian	if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
364e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian	    && !(i->invflags & IPT_INV_PROTO))
365d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt		return 0;
366e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian
367ff67e4e42bd178b1179c4d8e5c1fde18758ce84fJan Engelhardt	pr_info("Can be used only in combination with "
368e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian		"either -p tcp or -p udp\n");
369d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt	return -EINVAL;
370e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian}
371e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian
3726ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidlerstatic struct xt_target tproxy_tg_reg[] __read_mostly = {
3736ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	{
3746ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.name		= "TPROXY",
3756ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.family		= NFPROTO_IPV4,
3766ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.table		= "mangle",
3776ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.target		= tproxy_tg4_v0,
3786ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.revision	= 0,
3796ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.targetsize	= sizeof(struct xt_tproxy_target_info),
3806ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.checkentry	= tproxy_tg4_check,
3816ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.hooks		= 1 << NF_INET_PRE_ROUTING,
3826ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.me		= THIS_MODULE,
3836ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	},
3846ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	{
3856ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.name		= "TPROXY",
3866ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.family		= NFPROTO_IPV4,
3876ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.table		= "mangle",
3886ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.target		= tproxy_tg4_v1,
3896ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.revision	= 1,
3906ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.targetsize	= sizeof(struct xt_tproxy_target_info_v1),
3916ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.checkentry	= tproxy_tg4_check,
3926ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.hooks		= 1 << NF_INET_PRE_ROUTING,
3936ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.me		= THIS_MODULE,
3946ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	},
395f6318e558806c925029dc101f14874be9f9fa78fKOVACS Krisztian#ifdef XT_TPROXY_HAVE_IPV6
3966ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	{
3976ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.name		= "TPROXY",
3986ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.family		= NFPROTO_IPV6,
3996ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.table		= "mangle",
4006ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.target		= tproxy_tg6_v1,
4016ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.revision	= 1,
4026ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.targetsize	= sizeof(struct xt_tproxy_target_info_v1),
4036ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.checkentry	= tproxy_tg6_check,
4046ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.hooks		= 1 << NF_INET_PRE_ROUTING,
4056ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler		.me		= THIS_MODULE,
4066ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	},
4076ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler#endif
4086ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
409e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian};
410e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian
411e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztianstatic int __init tproxy_tg_init(void)
412e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian{
413e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian	nf_defrag_ipv4_enable();
414f6318e558806c925029dc101f14874be9f9fa78fKOVACS Krisztian#ifdef XT_TPROXY_HAVE_IPV6
4156ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	nf_defrag_ipv6_enable();
4166ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler#endif
4176ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler
4186ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	return xt_register_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg));
419e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian}
420e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian
421e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztianstatic void __exit tproxy_tg_exit(void)
422e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian{
4236ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs Scheidler	xt_unregister_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg));
424e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian}
425e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztian
426e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztianmodule_init(tproxy_tg_init);
427e84392707e10301b93121e1b74e2823db50cdf9eKOVACS Krisztianmodule_exit(tproxy_tg_exit);
428e84392707e10301b93121e1b74e2823db50cdf9eKOVACS KrisztianMODULE_LICENSE("GPL");
4296ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs ScheidlerMODULE_AUTHOR("Balazs Scheidler, Krisztian Kovacs");
430e84392707e10301b93121e1b74e2823db50cdf9eKOVACS KrisztianMODULE_DESCRIPTION("Netfilter transparent proxy (TPROXY) target module.");
431e84392707e10301b93121e1b74e2823db50cdf9eKOVACS KrisztianMODULE_ALIAS("ipt_TPROXY");
4326ad7889327a5ee6ab4220bd34e4428c7d0de0f32Balazs ScheidlerMODULE_ALIAS("ip6t_TPROXY");
433