• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
10 enum {
11 	O_TRANSPARENT = 0,
12 	O_NOWILDCARD = 1,
13 	O_RESTORESKMARK = 2,
14 };
15 
16 static const struct xt_option_entry socket_mt_opts[] = {
17 	{.name = "transparent", .id = O_TRANSPARENT, .type = XTTYPE_NONE},
18 	XTOPT_TABLEEND,
19 };
20 
21 static 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 
27 static 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 
socket_mt_help(void)34 static void socket_mt_help(void)
35 {
36 	printf(
37 		"socket match options:\n"
38 		"  --transparent    Ignore non-transparent sockets\n\n");
39 }
40 
socket_mt_help_v2(void)41 static 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 
socket_mt_help_v3(void)49 static 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 
socket_mt_parse(struct xt_option_call * cb)60 static 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 
socket_mt_parse_v2(struct xt_option_call * cb)72 static 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 
socket_mt_parse_v3(struct xt_option_call * cb)87 static 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 
105 static void
socket_mt_save(const void * ip,const struct xt_entry_match * match)106 socket_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 
114 static void
socket_mt_print(const void * ip,const struct xt_entry_match * match,int numeric)115 socket_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 
122 static void
socket_mt_save_v2(const void * ip,const struct xt_entry_match * match)123 socket_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 
133 static void
socket_mt_print_v2(const void * ip,const struct xt_entry_match * match,int numeric)134 socket_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 
141 static void
socket_mt_save_v3(const void * ip,const struct xt_entry_match * match)142 socket_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 
154 static void
socket_mt_print_v3(const void * ip,const struct xt_entry_match * match,int numeric)155 socket_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 
socket_mt_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)162 static int socket_mt_xlate(struct xt_xlate *xl, const struct xt_xlate_mt_params *params)
163 {
164 	const struct xt_socket_mtinfo3 *info = (const void *)params->match->data;
165 
166 	/* ONLY --nowildcard: match if socket exists. It does not matter
167 	 * to which address it is bound.
168 	 */
169 	if (info->flags == XT_SOCKET_NOWILDCARD) {
170 		xt_xlate_add(xl, "socket wildcard le 1");
171 		return 1;
172 	}
173 
174 	/* Without --nowildcard, restrict to sockets NOT bound to
175 	 * the any address.
176 	 */
177 	if ((info->flags & XT_SOCKET_NOWILDCARD) == 0)
178 		xt_xlate_add(xl, "socket wildcard 0");
179 
180 	if (info->flags & XT_SOCKET_TRANSPARENT)
181 		xt_xlate_add(xl, "socket transparent 1");
182 
183 	/* If --nowildcard was given, -m socket should not test
184 	 * the bound address.  We can simply ignore this; its
185 	 * equal to "wildcard <= 1".
186 	 */
187 	if (info->flags & XT_SOCKET_RESTORESKMARK)
188 		xt_xlate_add(xl, "meta mark set socket mark");
189 
190 	return 1;
191 }
192 
193 static struct xtables_match socket_mt_reg[] = {
194 	{
195 		.name          = "socket",
196 		.revision      = 0,
197 		.family        = NFPROTO_IPV4,
198 		.version       = XTABLES_VERSION,
199 		.size          = XT_ALIGN(0),
200 		.userspacesize = XT_ALIGN(0),
201 	},
202 	{
203 		.name          = "socket",
204 		.revision      = 1,
205 		.family        = NFPROTO_UNSPEC,
206 		.version       = XTABLES_VERSION,
207 		.size          = XT_ALIGN(sizeof(struct xt_socket_mtinfo1)),
208 		.userspacesize = XT_ALIGN(sizeof(struct xt_socket_mtinfo1)),
209 		.help          = socket_mt_help,
210 		.print         = socket_mt_print,
211 		.save          = socket_mt_save,
212 		.x6_parse      = socket_mt_parse,
213 		.x6_options    = socket_mt_opts,
214 		.xlate	       = socket_mt_xlate,
215 	},
216 	{
217 		.name          = "socket",
218 		.revision      = 2,
219 		.family        = NFPROTO_UNSPEC,
220 		.version       = XTABLES_VERSION,
221 		.size          = XT_ALIGN(sizeof(struct xt_socket_mtinfo2)),
222 		.userspacesize = XT_ALIGN(sizeof(struct xt_socket_mtinfo2)),
223 		.help          = socket_mt_help_v2,
224 		.print         = socket_mt_print_v2,
225 		.save          = socket_mt_save_v2,
226 		.x6_parse      = socket_mt_parse_v2,
227 		.x6_options    = socket_mt_opts_v2,
228 		.xlate	       = socket_mt_xlate,
229 	},
230 	{
231 		.name          = "socket",
232 		.revision      = 3,
233 		.family        = NFPROTO_UNSPEC,
234 		.version       = XTABLES_VERSION,
235 		.size          = XT_ALIGN(sizeof(struct xt_socket_mtinfo2)),
236 		.userspacesize = XT_ALIGN(sizeof(struct xt_socket_mtinfo2)),
237 		.help          = socket_mt_help_v3,
238 		.print         = socket_mt_print_v3,
239 		.save          = socket_mt_save_v3,
240 		.x6_parse      = socket_mt_parse_v3,
241 		.x6_options    = socket_mt_opts_v3,
242 		.xlate	       = socket_mt_xlate,
243 	},
244 };
245 
_init(void)246 void _init(void)
247 {
248 	xtables_register_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg));
249 }
250