libxt_TPROXY.c revision 9e152fa9f1283ce4f4274cf251b2b2e69bbdfee6
1/*
2 * Shared library add-on to iptables to add TPROXY target support.
3 *
4 * Copyright (C) 2002-2008 BalaBit IT Ltd.
5 */
6#include <getopt.h>
7#include <stdbool.h>
8#include <stdint.h>
9#include <stdio.h>
10#include <string.h>
11#include <stdlib.h>
12#include <limits.h>
13
14#include <xtables.h>
15#include <linux/netfilter/x_tables.h>
16#include <linux/netfilter/xt_TPROXY.h>
17
18static const struct option tproxy_tg_opts[] = {
19	{.name = "on-port",     .has_arg = true, .val = '1'},
20	{.name = "on-ip",       .has_arg = true, .val = '2'},
21	{.name = "tproxy-mark", .has_arg = true, .val = '3'},
22	XT_GETOPT_TABLEEND,
23};
24
25enum {
26	PARAM_ONPORT = 1 << 0,
27	PARAM_ONIP = 1 << 1,
28	PARAM_MARK = 1 << 2,
29};
30
31static void tproxy_tg_help(void)
32{
33	printf(
34"TPROXY target options:\n"
35"  --on-port port		    Redirect connection to port, or the original port if 0\n"
36"  --on-ip ip			    Optionally redirect to the given IP\n"
37"  --tproxy-mark value[/mask]	    Mark packets with the given value/mask\n\n");
38}
39
40static void parse_tproxy_lport(const char *s, uint16_t *portp)
41{
42	unsigned int lport;
43
44	if (xtables_strtoui(s, NULL, &lport, 0, UINT16_MAX))
45		*portp = htons(lport);
46	else
47		xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--on-port", s);
48}
49
50static void parse_tproxy_laddr(const char *s, union nf_inet_addr *addrp,
51			       unsigned int nfproto)
52{
53	struct in6_addr *laddr6 = NULL;
54	struct in_addr *laddr4 = NULL;
55
56	if (nfproto == NFPROTO_IPV6) {
57		laddr6 = xtables_numeric_to_ip6addr(s);
58		if (laddr6 == NULL)
59			goto out;
60		addrp->in6 = *laddr6;
61	} else if (nfproto == NFPROTO_IPV4) {
62		laddr4 = xtables_numeric_to_ipaddr(s);
63		if (laddr4 == NULL)
64			goto out;
65		addrp->in = *laddr4;
66	}
67	return;
68 out:
69	xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--on-ip", s);
70}
71
72static void parse_tproxy_mark(char *s, uint32_t *markp, uint32_t *maskp)
73{
74	unsigned int value, mask = UINT32_MAX;
75	char *end;
76
77	if (!xtables_strtoui(s, &end, &value, 0, UINT32_MAX))
78		xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--tproxy-mark", s);
79	if (*end == '/')
80		if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX))
81			xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--tproxy-mark", s);
82	if (*end != '\0')
83		xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--tproxy-mark", s);
84
85	*markp = value;
86	*maskp = mask;
87}
88
89static int tproxy_tg_parse(int c, char **argv, int invert, unsigned int *flags,
90			const void *entry, struct xt_entry_target **target)
91{
92	struct xt_tproxy_target_info *info = (void *)(*target)->data;
93
94	switch (c) {
95	case '1':
96		xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--on-port", *flags & PARAM_ONPORT);
97		xtables_param_act(XTF_NO_INVERT, "TPROXY", "--on-port", invert);
98		parse_tproxy_lport(optarg, &info->lport);
99		*flags |= PARAM_ONPORT;
100		return 1;
101	case '2':
102		xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--on-ip", *flags & PARAM_ONIP);
103		xtables_param_act(XTF_NO_INVERT, "TPROXY", "--on-ip", invert);
104		parse_tproxy_laddr(optarg, (void *)&info->laddr, NFPROTO_IPV4);
105		*flags |= PARAM_ONIP;
106		return 1;
107	case '3':
108		xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--tproxy-mark", *flags & PARAM_MARK);
109		xtables_param_act(XTF_NO_INVERT, "TPROXY", "--tproxy-mark", invert);
110		parse_tproxy_mark(optarg, &info->mark_value, &info->mark_mask);
111		*flags |= PARAM_MARK;
112		return 1;
113	}
114
115	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