1/*
2 * Shared library add-on to iptables to add early socket matching support.
3 *
4 * Copyright (C) 2007 BalaBit IT Ltd.
5 */
6#include <stdio.h>
7#include <xtables.h>
8#include <linux/netfilter/xt_socket.h>
9
10enum {
11	O_TRANSPARENT = 0,
12	O_NOWILDCARD = 1,
13	O_RESTORESKMARK = 2,
14};
15
16static const struct xt_option_entry socket_mt_opts[] = {
17	{.name = "transparent", .id = O_TRANSPARENT, .type = XTTYPE_NONE},
18	XTOPT_TABLEEND,
19};
20
21static const struct xt_option_entry socket_mt_opts_v2[] = {
22	{.name = "transparent", .id = O_TRANSPARENT, .type = XTTYPE_NONE},
23	{.name = "nowildcard", .id = O_NOWILDCARD, .type = XTTYPE_NONE},
24	XTOPT_TABLEEND,
25};
26
27static const struct xt_option_entry socket_mt_opts_v3[] = {
28	{.name = "transparent", .id = O_TRANSPARENT, .type = XTTYPE_NONE},
29	{.name = "nowildcard", .id = O_NOWILDCARD, .type = XTTYPE_NONE},
30	{.name = "restore-skmark", .id = O_RESTORESKMARK, .type = XTTYPE_NONE},
31	XTOPT_TABLEEND,
32};
33
34static void socket_mt_help(void)
35{
36	printf(
37		"socket match options:\n"
38		"  --transparent    Ignore non-transparent sockets\n\n");
39}
40
41static void socket_mt_help_v2(void)
42{
43	printf(
44		"socket match options:\n"
45		"  --nowildcard     Do not ignore LISTEN sockets bound on INADDR_ANY\n"
46		"  --transparent    Ignore non-transparent sockets\n\n");
47}
48
49static void socket_mt_help_v3(void)
50{
51	printf(
52		"socket match options:\n"
53		"  --nowildcard     Do not ignore LISTEN sockets bound on INADDR_ANY\n"
54		"  --transparent    Ignore non-transparent sockets\n"
55		"  --restore-skmark Set the packet mark to the socket mark if\n"
56		"                   the socket matches and transparent / \n"
57		"                   nowildcard conditions are satisfied\n\n");
58}
59
60static void socket_mt_parse(struct xt_option_call *cb)
61{
62	struct xt_socket_mtinfo1 *info = cb->data;
63
64	xtables_option_parse(cb);
65	switch (cb->entry->id) {
66	case O_TRANSPARENT:
67		info->flags |= XT_SOCKET_TRANSPARENT;
68		break;
69	}
70}
71
72static void socket_mt_parse_v2(struct xt_option_call *cb)
73{
74	struct xt_socket_mtinfo2 *info = cb->data;
75
76	xtables_option_parse(cb);
77	switch (cb->entry->id) {
78	case O_TRANSPARENT:
79		info->flags |= XT_SOCKET_TRANSPARENT;
80		break;
81	case O_NOWILDCARD:
82		info->flags |= XT_SOCKET_NOWILDCARD;
83		break;
84	}
85}
86
87static void socket_mt_parse_v3(struct xt_option_call *cb)
88{
89	struct xt_socket_mtinfo2 *info = cb->data;
90
91	xtables_option_parse(cb);
92	switch (cb->entry->id) {
93	case O_TRANSPARENT:
94		info->flags |= XT_SOCKET_TRANSPARENT;
95		break;
96	case O_NOWILDCARD:
97		info->flags |= XT_SOCKET_NOWILDCARD;
98		break;
99	case O_RESTORESKMARK:
100		info->flags |= XT_SOCKET_RESTORESKMARK;
101		break;
102	}
103}
104
105static void
106socket_mt_save(const void *ip, const struct xt_entry_match *match)
107{
108	const struct xt_socket_mtinfo1 *info = (const void *)match->data;
109
110	if (info->flags & XT_SOCKET_TRANSPARENT)
111		printf(" --transparent");
112}
113
114static void
115socket_mt_print(const void *ip, const struct xt_entry_match *match,
116		int numeric)
117{
118	printf(" socket");
119	socket_mt_save(ip, match);
120}
121
122static void
123socket_mt_save_v2(const void *ip, const struct xt_entry_match *match)
124{
125	const struct xt_socket_mtinfo2 *info = (const void *)match->data;
126
127	if (info->flags & XT_SOCKET_TRANSPARENT)
128		printf(" --transparent");
129	if (info->flags & XT_SOCKET_NOWILDCARD)
130		printf(" --nowildcard");
131}
132
133static void
134socket_mt_print_v2(const void *ip, const struct xt_entry_match *match,
135		   int numeric)
136{
137	printf(" socket");
138	socket_mt_save_v2(ip, match);
139}
140
141static void
142socket_mt_save_v3(const void *ip, const struct xt_entry_match *match)
143{
144	const struct xt_socket_mtinfo3 *info = (const void *)match->data;
145
146	if (info->flags & XT_SOCKET_TRANSPARENT)
147		printf(" --transparent");
148	if (info->flags & XT_SOCKET_NOWILDCARD)
149		printf(" --nowildcard");
150	if (info->flags & XT_SOCKET_RESTORESKMARK)
151		printf(" --restore-skmark");
152}
153
154static void
155socket_mt_print_v3(const void *ip, const struct xt_entry_match *match,
156		   int numeric)
157{
158	printf(" socket");
159	socket_mt_save_v3(ip, match);
160}
161
162static struct xtables_match socket_mt_reg[] = {
163	{
164		.name          = "socket",
165		.revision      = 0,
166		.family        = NFPROTO_IPV4,
167		.version       = XTABLES_VERSION,
168		.size          = XT_ALIGN(0),
169		.userspacesize = XT_ALIGN(0),
170	},
171	{
172		.name          = "socket",
173		.revision      = 1,
174		.family        = NFPROTO_UNSPEC,
175		.version       = XTABLES_VERSION,
176		.size          = XT_ALIGN(sizeof(struct xt_socket_mtinfo1)),
177		.userspacesize = XT_ALIGN(sizeof(struct xt_socket_mtinfo1)),
178		.help          = socket_mt_help,
179		.print         = socket_mt_print,
180		.save          = socket_mt_save,
181		.x6_parse      = socket_mt_parse,
182		.x6_options    = socket_mt_opts,
183	},
184	{
185		.name          = "socket",
186		.revision      = 2,
187		.family        = NFPROTO_UNSPEC,
188		.version       = XTABLES_VERSION,
189		.size          = XT_ALIGN(sizeof(struct xt_socket_mtinfo2)),
190		.userspacesize = XT_ALIGN(sizeof(struct xt_socket_mtinfo2)),
191		.help          = socket_mt_help_v2,
192		.print         = socket_mt_print_v2,
193		.save          = socket_mt_save_v2,
194		.x6_parse      = socket_mt_parse_v2,
195		.x6_options    = socket_mt_opts_v2,
196	},
197	{
198		.name          = "socket",
199		.revision      = 3,
200		.family        = NFPROTO_UNSPEC,
201		.version       = XTABLES_VERSION,
202		.size          = XT_ALIGN(sizeof(struct xt_socket_mtinfo2)),
203		.userspacesize = XT_ALIGN(sizeof(struct xt_socket_mtinfo2)),
204		.help          = socket_mt_help_v3,
205		.print         = socket_mt_print_v3,
206		.save          = socket_mt_save_v3,
207		.x6_parse      = socket_mt_parse_v3,
208		.x6_options    = socket_mt_opts_v3,
209	},
210};
211
212void _init(void)
213{
214	xtables_register_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg));
215}
216