2 * Unix SMB/CIFS implementation.
4 * block SMB2 transports using iptables
6 * Copyright (C) Guenther Deschner, 2017
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "libcli/smb2/smb2.h"
24 #include "torture/torture.h"
25 #include "torture/smb2/proto.h"
26 #include "system/network.h"
27 #include "lib/util/util_net.h"
28 #include "torture/smb2/block.h"
29 #include "libcli/smb/smbXcli_base.h"
36 * -----> SAMBA_INPUT_transportname1
37 * -----> SAMBA_INPUT_transportname2
41 static bool run_cmd(const char *cmd
)
45 DEBUG(10, ("%s will call '%s'\n", __location__
, cmd
));
49 DEBUG(1, ("%s failed to execute system call: %s: %d\n",
50 __location__
, cmd
, ret
));
57 int smbrun(const char *cmd
, int *outfd
, char * const *env
);
59 static bool run_cmd_return_buf(TALLOC_CTX
*mem_ctx
,
61 int *num_lines
, char ***buf
)
66 DEBUG(10, ("%s will call '%s'\n", __location__
, cmd
));
68 ret
= smbrun(cmd
, &fd
, NULL
);
70 DEBUG(1, ("%s failed to execute system call: %s: %d\n",
71 __location__
, cmd
, ret
));
78 *buf
= fd_lines_load(fd
, num_lines
, 0, mem_ctx
);
89 static const char *iptables_command(struct torture_context
*tctx
)
91 return torture_setting_string(tctx
, "iptables_command",
92 "/usr/sbin/iptables");
95 char *escape_shell_string(const char *src
);
98 * iptables v1.6.1: chain name `SAMBA_INPUT_tree1->session->transport'
99 * too long (must be under 29 chars)
101 * maybe truncate chainname ?
103 static const char *samba_chain_name(struct torture_context
*tctx
,
110 s
= talloc_asprintf(tctx
, "%s_%s", prefix
, name
);
115 sm
= escape_shell_string(s
);
120 s
= talloc_strdup(tctx
, sm
);
126 static bool filter_tcp_setup(struct torture_context
*tctx
,
129 const char *cmd_in
, *cmd_out
;
130 const char *ipt
= iptables_command(tctx
);
133 cmd_in
= talloc_asprintf(tctx
,
134 "%s -L SAMBA_INPUT > /dev/null 2>&1 && "
136 "%s -F SAMBA_INPUT; "
137 "%s -D INPUT -j SAMBA_INPUT; "
141 cmd_out
= talloc_asprintf(tctx
,
142 "%s -L SAMBA_OUTPUT > /dev/null 2>&1 && "
144 "%s -F SAMBA_OUTPUT;"
145 "%s -D OUTPUT -j SAMBA_OUTPUT;"
146 "%s -X SAMBA_OUTPUT;"
150 cmd_in
= talloc_asprintf(tctx
,
151 "%s -L SAMBA_INPUT > /dev/null 2>&1 || "
153 "%s -N SAMBA_INPUT && "
154 "%s -I INPUT -j SAMBA_INPUT "
157 cmd_out
= talloc_asprintf(tctx
,
158 "%s -L SAMBA_OUTPUT > /dev/null 2>&1 || "
160 "%s -N SAMBA_OUTPUT && "
161 "%s -I OUTPUT -j SAMBA_OUTPUT;"
166 if (cmd_in
== NULL
|| cmd_out
== NULL
) {
170 if (!run_cmd(cmd_in
)) {
173 /* if (!run_cmd(cmd_out)) { return false; } */
178 static bool filter_tcp_setup_name(struct torture_context
*tctx
,
179 const char *name
, bool unblock
)
181 const char *cmd_in
, *cmd_out
;
182 const char *chain_in
, *chain_out
;
183 const char *ipt
= iptables_command(tctx
);
185 chain_in
= samba_chain_name(tctx
, name
, "SAMBA_INPUT");
186 chain_out
= samba_chain_name(tctx
, name
, "SAMBA_OUTPUT");
187 if (chain_in
== NULL
|| chain_out
== NULL
) {
192 cmd_in
= talloc_asprintf(tctx
, "%s -F %s; "
193 "%s -D SAMBA_INPUT -j %s; "
198 cmd_out
= talloc_asprintf(tctx
, "%s -F %s; "
199 "%s -D SAMBA_OUTPUT -j %s; "
205 cmd_in
= talloc_asprintf(tctx
, "%s -L %s > /dev/null 2>&1 || "
207 "%s -I SAMBA_INPUT -j %s",
211 cmd_out
= talloc_asprintf(tctx
, "%s -L %s > /dev/null 2>&1 || "
213 "%s -I SAMBA_OUTPUT -j %s",
219 if (cmd_in
== NULL
|| cmd_out
== NULL
) {
223 if (!run_cmd(cmd_in
)) {
226 /* if (!run_cmd(cmd_out)) return false; */
231 /* '11 452 DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:43062' */
232 static bool get_packet_count(const char *s
, uint32_t *count
)
241 while (s
[i
] == ' ') {
256 bool torture_list_tcp_transport_name(struct torture_context
*tctx
,
260 const char *chain_in
, *cmd
;
263 uint32_t packets
= 0;
264 const char *ipt
= iptables_command(tctx
);
266 chain_in
= samba_chain_name(tctx
, name
, "SAMBA_INPUT");
267 if (chain_in
== NULL
) {
271 cmd
= talloc_asprintf(tctx
, "%s -L %s -v -n", ipt
, chain_in
);
276 if (!run_cmd_return_buf(tctx
, cmd
, &num_lines
, &buf
)) {
279 SMB_ASSERT(num_lines
>= 3);
281 if (!get_packet_count(buf
[2], &packets
)) {
285 torture_comment(tctx
, "chain: '%s', packets: %d\n", name
, (int)packets
);
287 if (_packets
!= NULL
) {
294 uint16_t torture_get_local_port_from_transport(struct smb2_transport
*t
)
296 const struct sockaddr_storage
*local_ss
;
298 local_ss
= smbXcli_conn_local_sockaddr(t
->conn
);
300 return get_sockaddr_port(local_ss
);
303 static bool torture_block_tcp_transport_name_internal(
304 struct torture_context
*tctx
,
305 struct smb2_transport
*t
,
311 const char *chain_in
, *chain_out
;
312 uint16_t port
= torture_get_local_port_from_transport(t
);
313 const char *ipt
= iptables_command(tctx
);
315 chain_in
= samba_chain_name(tctx
, name
, "SAMBA_INPUT");
316 chain_out
= samba_chain_name(tctx
, name
, "SAMBA_OUTPUT");
317 if (chain_in
== NULL
|| chain_out
== NULL
) {
322 filter_tcp_setup(tctx
, false);
323 filter_tcp_setup_name(tctx
, name
, false);
326 torture_comment(tctx
, "%sblocking %s dport %d\n",
327 unblock
? "un" : "", name
, port
);
329 cmd_in
= talloc_asprintf(tctx
,
330 "%s %s %s -p tcp --dport %d -j DROP",
331 ipt
, unblock
? "-D" : "-I", chain_in
, port
);
332 cmd_out
= talloc_asprintf(tctx
,
333 "%s %s %s -p tcp --sport %d -j DROP",
334 ipt
, unblock
? "-D" : "-I", chain_out
, port
);
335 if (cmd_in
== NULL
|| cmd_out
== NULL
) {
339 if (!run_cmd(cmd_in
)) {
342 /* if (!run_cmd(cmd_out)) return false; */
345 filter_tcp_setup_name(tctx
, name
, true);
346 /* better don't cleanup here */
347 /* filter_tcp_setup(tctx, true); */
353 bool torture_block_tcp_transport_name(struct torture_context
*tctx
,
354 struct smb2_transport
*t
,
357 return torture_block_tcp_transport_name_internal(tctx
, t
, name
, false);
360 bool torture_unblock_tcp_transport_name(struct torture_context
*tctx
,
361 struct smb2_transport
*t
,
364 return torture_block_tcp_transport_name_internal(tctx
, t
, name
, true);
367 void torture_unblock_cleanup(struct torture_context
*tctx
)
369 filter_tcp_setup(tctx
, true);