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 
162 static 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 
_init(void)212 void _init(void)
213 {
214 	xtables_register_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg));
215 }
216