libxt_TPROXY.c revision 73866357e4a7a0fdc1b293bf8863fee2bd56da9e
11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/*
21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Shared library add-on to iptables to add TPROXY target support.
31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *
41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Copyright (C) 2002-2008 BalaBit IT Ltd.
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */
61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <getopt.h>
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <stdbool.h>
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <stdint.h>
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <stdio.h>
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <string.h>
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <stdlib.h>
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <limits.h>
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <xtables.h>
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <linux/netfilter/x_tables.h>
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <linux/netfilter/xt_TPROXY.h>
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic const struct option tproxy_tg_opts[] = {
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	{.name = "on-port",     .has_arg = true, .val = '1'},
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	{.name = "on-ip",       .has_arg = true, .val = '2'},
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	{.name = "tproxy-mark", .has_arg = true, .val = '3'},
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	XT_GETOPT_TABLEEND,
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccienum {
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	PARAM_ONPORT = 1 << 0,
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	PARAM_ONIP = 1 << 1,
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	PARAM_MARK = 1 << 2,
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic void tproxy_tg_help(void)
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	printf(
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci"TPROXY target options:\n"
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci"  --on-port port		    Redirect connection to port, or the original port if 0\n"
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci"  --on-ip ip			    Optionally redirect to the given IP\n"
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci"  --tproxy-mark value[/mask]	    Mark packets with the given value/mask\n\n");
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic void parse_tproxy_lport(const char *s, uint16_t *portp)
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	unsigned int lport;
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	if (xtables_strtoui(s, NULL, &lport, 0, UINT16_MAX))
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		*portp = htons(lport);
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	else
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--on-port", s);
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic void parse_tproxy_laddr(const char *s, union nf_inet_addr *addrp,
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci			       unsigned int nfproto)
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	struct in6_addr *laddr6 = NULL;
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	struct in_addr *laddr4 = NULL;
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	if (nfproto == NFPROTO_IPV6) {
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		laddr6 = xtables_numeric_to_ip6addr(s);
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		if (laddr6 == NULL)
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci			goto out;
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		addrp->in6 = *laddr6;
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	} else if (nfproto == NFPROTO_IPV4) {
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		laddr4 = xtables_numeric_to_ipaddr(s);
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		if (laddr4 == NULL)
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci			goto out;
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		addrp->in = *laddr4;
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	}
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	return;
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci out:
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--on-ip", s);
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic void parse_tproxy_mark(char *s, uint32_t *markp, uint32_t *maskp)
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	unsigned int value, mask = UINT32_MAX;
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	char *end;
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	if (!xtables_strtoui(s, &end, &value, 0, UINT32_MAX))
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--tproxy-mark", s);
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	if (*end == '/')
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX))
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci			xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--tproxy-mark", s);
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	if (*end != '\0')
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--tproxy-mark", s);
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	*markp = value;
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	*maskp = mask;
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic int tproxy_tg_parse(int c, char **argv, int invert, unsigned int *flags,
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci			const void *entry, struct xt_entry_target **target)
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci{
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	struct xt_tproxy_target_info *info = (void *)(*target)->data;
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	switch (c) {
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	case '1':
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--on-port", *flags & PARAM_ONPORT);
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		xtables_param_act(XTF_NO_INVERT, "TPROXY", "--on-port", invert);
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		parse_tproxy_lport(optarg, &info->lport);
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		*flags |= PARAM_ONPORT;
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		return 1;
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	case '2':
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--on-ip", *flags & PARAM_ONIP);
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		xtables_param_act(XTF_NO_INVERT, "TPROXY", "--on-ip", invert);
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		parse_tproxy_laddr(optarg, (void *)&info->laddr, NFPROTO_IPV4);
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		*flags |= PARAM_ONIP;
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		return 1;
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	case '3':
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--tproxy-mark", *flags & PARAM_MARK);
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		xtables_param_act(XTF_NO_INVERT, "TPROXY", "--tproxy-mark", invert);
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		parse_tproxy_mark(optarg, &info->mark_value, &info->mark_mask);
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		*flags |= PARAM_MARK;
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		return 1;
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	}
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	return 0;
116}
117
118static int
119tproxy_tg_parse1(int c, char **argv, int invert, unsigned int *flags,
120		 struct xt_tproxy_target_info_v1 *info, unsigned int nfproto)
121{
122	switch (c) {
123	case '1':
124		xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--on-port", *flags & PARAM_ONPORT);
125		xtables_param_act(XTF_NO_INVERT, "TPROXY", "--on-port", invert);
126		parse_tproxy_lport(optarg, &info->lport);
127		*flags |= PARAM_ONPORT;
128		return true;
129	case '2':
130		xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--on-ip", *flags & PARAM_ONIP);
131		xtables_param_act(XTF_NO_INVERT, "TPROXY", "--on-ip", invert);
132		parse_tproxy_laddr(optarg, (void *)&info->laddr, nfproto);
133		*flags |= PARAM_ONIP;
134		return true;
135	case '3':
136		xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--tproxy-mark", *flags & PARAM_MARK);
137		xtables_param_act(XTF_NO_INVERT, "TPROXY", "--tproxy-mark", invert);
138		parse_tproxy_mark(optarg, &info->mark_value, &info->mark_mask);
139		*flags |= PARAM_MARK;
140		return true;
141	}
142	return false;
143}
144
145static int
146tproxy_tg_parse4(int c, char **argv, int invert, unsigned int *flags,
147		 const void *entry, struct xt_entry_target **target)
148{
149	struct xt_tproxy_target_info_v1 *info = (void *)(*target)->data;
150	return tproxy_tg_parse1(c, argv, invert, flags, info, NFPROTO_IPV4);
151}
152
153static int
154tproxy_tg_parse6(int c, char **argv, int invert, unsigned int *flags,
155		 const void *entry, struct xt_entry_target **target)
156{
157	struct xt_tproxy_target_info_v1 *info = (void *)(*target)->data;
158	return tproxy_tg_parse1(c, argv, invert, flags, info, NFPROTO_IPV6);
159}
160
161static void tproxy_tg_check(unsigned int flags)
162{
163	if (!(flags & PARAM_ONPORT))
164		xtables_error(PARAMETER_PROBLEM,
165			   "TPROXY target: Parameter --on-port is required");
166}
167
168static void tproxy_tg_print(const void *ip, const struct xt_entry_target *target,
169			 int numeric)
170{
171	const struct xt_tproxy_target_info *info = (const void *)target->data;
172	printf(" TPROXY redirect %s:%u mark 0x%x/0x%x",
173	       xtables_ipaddr_to_numeric((const struct in_addr *)&info->laddr),
174	       ntohs(info->lport), (unsigned int)info->mark_value,
175	       (unsigned int)info->mark_mask);
176}
177
178static void
179tproxy_tg_print4(const void *ip, const struct xt_entry_target *target,
180		 int numeric)
181{
182	const struct xt_tproxy_target_info_v1 *info =
183		(const void *)target->data;
184
185	printf(" TPROXY redirect %s:%u mark 0x%x/0x%x",
186	       xtables_ipaddr_to_numeric(&info->laddr.in),
187	       ntohs(info->lport), (unsigned int)info->mark_value,
188	       (unsigned int)info->mark_mask);
189}
190
191static void
192tproxy_tg_print6(const void *ip, const struct xt_entry_target *target,
193		 int numeric)
194{
195	const struct xt_tproxy_target_info_v1 *info =
196		(const void *)target->data;
197
198	printf(" TPROXY redirect %s:%u mark 0x%x/0x%x",
199	       xtables_ip6addr_to_numeric(&info->laddr.in6),
200	       ntohs(info->lport), (unsigned int)info->mark_value,
201	       (unsigned int)info->mark_mask);
202}
203
204static void tproxy_tg_save(const void *ip, const struct xt_entry_target *target)
205{
206	const struct xt_tproxy_target_info *info = (const void *)target->data;
207
208	printf(" --on-port %u", ntohs(info->lport));
209	printf(" --on-ip %s",
210	       xtables_ipaddr_to_numeric((const struct in_addr *)&info->laddr));
211	printf(" --tproxy-mark 0x%x/0x%x",
212	       (unsigned int)info->mark_value, (unsigned int)info->mark_mask);
213}
214
215static void
216tproxy_tg_save4(const void *ip, const struct xt_entry_target *target)
217{
218	const struct xt_tproxy_target_info_v1 *info;
219
220	info = (const void *)target->data;
221	printf(" --on-port %u", ntohs(info->lport));
222	printf(" --on-ip %s", xtables_ipaddr_to_numeric(&info->laddr.in));
223	printf(" --tproxy-mark 0x%x/0x%x",
224	       (unsigned int)info->mark_value, (unsigned int)info->mark_mask);
225}
226
227static void
228tproxy_tg_save6(const void *ip, const struct xt_entry_target *target)
229{
230	const struct xt_tproxy_target_info_v1 *info;
231
232	info = (const void *)target->data;
233	printf(" --on-port %u", ntohs(info->lport));
234	printf(" --on-ip %s", xtables_ip6addr_to_numeric(&info->laddr.in6));
235	printf(" --tproxy-mark 0x%x/0x%x",
236	       (unsigned int)info->mark_value, (unsigned int)info->mark_mask);
237}
238
239static struct xtables_target tproxy_tg_reg[] = {
240	{
241		.name          = "TPROXY",
242		.revision      = 0,
243		.family        = NFPROTO_IPV4,
244		.version       = XTABLES_VERSION,
245		.size          = XT_ALIGN(sizeof(struct xt_tproxy_target_info)),
246		.userspacesize = XT_ALIGN(sizeof(struct xt_tproxy_target_info)),
247		.help          = tproxy_tg_help,
248		.parse         = tproxy_tg_parse,
249		.final_check   = tproxy_tg_check,
250		.print         = tproxy_tg_print,
251		.save          = tproxy_tg_save,
252		.extra_opts    = tproxy_tg_opts,
253	},
254	{
255		.name          = "TPROXY",
256		.revision      = 1,
257		.family        = NFPROTO_IPV4,
258		.version       = XTABLES_VERSION,
259		.size          = XT_ALIGN(sizeof(struct xt_tproxy_target_info_v1)),
260		.userspacesize = XT_ALIGN(sizeof(struct xt_tproxy_target_info_v1)),
261		.help          = tproxy_tg_help,
262		.parse         = tproxy_tg_parse4,
263		.final_check   = tproxy_tg_check,
264		.print         = tproxy_tg_print4,
265		.save          = tproxy_tg_save4,
266		.extra_opts    = tproxy_tg_opts,
267	},
268	{
269		.name          = "TPROXY",
270		.revision      = 1,
271		.family        = NFPROTO_IPV6,
272		.version       = XTABLES_VERSION,
273		.size          = XT_ALIGN(sizeof(struct xt_tproxy_target_info_v1)),
274		.userspacesize = XT_ALIGN(sizeof(struct xt_tproxy_target_info_v1)),
275		.help          = tproxy_tg_help,
276		.parse         = tproxy_tg_parse6,
277		.final_check   = tproxy_tg_check,
278		.print         = tproxy_tg_print6,
279		.save          = tproxy_tg_save6,
280		.extra_opts    = tproxy_tg_opts,
281	},
282};
283
284void _init(void)
285{
286	xtables_register_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg));
287}
288