]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s4:torture/smb2: refactor block.c to block the OUTPUT path
authorStefan Metzmacher <metze@samba.org>
Fri, 29 May 2020 16:18:12 +0000 (09:18 -0700)
committerStefan Metzmacher <metze@samba.org>
Wed, 8 Jul 2020 15:54:39 +0000 (15:54 +0000)
In order to create useful tests, we should block the outgoing
tcp packets only. That means we're able to see incoming
break notifications, but prevent outgoing TCP ACKs to be delivered
to the server.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11897

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Günther Deschner <gd@samba.org>
source4/torture/smb2/block.c
source4/torture/smb2/block.h
source4/torture/smb2/multichannel.c

index fa39ae1df9165494708c467b6399765d60b550e6..d0cb934adf98e56cb4c3fcfe7dfe8688a8e3c3c8 100644 (file)
 #include "libcli/smb/smbXcli_base.h"
 
 /*
- * INPUT
+ * OUTPUT
  *  |
- *  -----> SAMBA_INPUT
+ *  -----> SMBTORTURE_OUTPUT
  *             |
- *             -----> SAMBA_INPUT_transportname1
- *             -----> SAMBA_INPUT_transportname2
+ *             -----> SMBTORTURE_transportname1
+ *             -----> SMBTORTURE_transportname2
  */
 
 
@@ -54,38 +54,6 @@ static bool run_cmd(const char *cmd)
        return true;
 }
 
-int smbrun(const char *cmd, int *outfd, char * const *env);
-
-static bool run_cmd_return_buf(TALLOC_CTX *mem_ctx,
-                              const char *cmd,
-                              int *num_lines, char ***buf)
-{
-       int ret;
-       int fd = -1;
-
-       DEBUG(10, ("%s will call '%s'\n", __location__, cmd));
-
-       ret = smbrun(cmd, &fd, NULL);
-       if (ret) {
-               DEBUG(1, ("%s failed to execute system call: %s: %d\n",
-                       __location__, cmd, ret));
-               if (fd != -1) {
-                       close(fd);
-               }
-               return false;
-       }
-
-       *buf = fd_lines_load(fd, num_lines, 0, mem_ctx);
-       if (fd != -1) {
-               close(fd);
-       }
-       if (*buf == NULL) {
-               return false;
-       }
-
-       return true;
-}
-
 static const char *iptables_command(struct torture_context *tctx)
 {
        return torture_setting_string(tctx, "iptables_command",
@@ -95,7 +63,7 @@ static const char *iptables_command(struct torture_context *tctx)
 char *escape_shell_string(const char *src);
 
 /*
- * iptables v1.6.1: chain name `SAMBA_INPUT_tree1->session->transport'
+ * iptables v1.6.1: chain name `SMBTORTURE_INPUT_tree1->session->transport'
  * too long (must be under 29 chars)
  *
  * maybe truncate chainname ?
@@ -123,170 +91,49 @@ static const char *samba_chain_name(struct torture_context *tctx,
        return s;
 }
 
-static bool filter_tcp_setup(struct torture_context *tctx,
-                            bool unblock)
+static bool iptables_setup_chain(struct torture_context *tctx,
+                                const char *parent_chain,
+                                const char *chain,
+                                bool unblock)
 {
-       const char *cmd_in, *cmd_out;
        const char *ipt = iptables_command(tctx);
+       const char *cmd;
 
        if (unblock) {
-               cmd_in = talloc_asprintf(tctx,
-                               "%s -L SAMBA_INPUT > /dev/null 2>&1 && "
-                               "("
-                               "%s -F SAMBA_INPUT; "
-                               "%s -D INPUT -j SAMBA_INPUT; "
-                               "%s -X SAMBA_INPUT;"
-                               ")",
-                               ipt, ipt, ipt, ipt);
-               cmd_out = talloc_asprintf(tctx,
-                               "%s -L SAMBA_OUTPUT > /dev/null 2>&1 && "
+               cmd = talloc_asprintf(tctx,
+                               "%s -L %s > /dev/null 2>&1 && "
                                "("
-                               "%s -F SAMBA_OUTPUT;"
-                               "%s -D OUTPUT -j SAMBA_OUTPUT;"
-                               "%s -X SAMBA_OUTPUT;"
-                               ")",
-                               ipt, ipt, ipt, ipt);
+                               "%s -F %s;"
+                               "%s -D %s -j %s > /dev/null 2>&1 || true;"
+                               "%s -X %s;"
+                               ");"
+                               "%s -L %s > /dev/null 2>&1 || true;",
+                               ipt, chain,
+                               ipt, chain,
+                               ipt, parent_chain, chain,
+                               ipt, chain,
+                               ipt, chain);
        } else {
-               cmd_in = talloc_asprintf(tctx,
-                               "%s -L SAMBA_INPUT > /dev/null 2>&1 || "
+               cmd = talloc_asprintf(tctx,
+                               "%s -L %s > /dev/null 2>&1 || "
                                "("
-                               "%s -N SAMBA_INPUT && "
-                               "%s -I INPUT -j SAMBA_INPUT "
-                               ")",
-                               ipt, ipt, ipt);
-               cmd_out = talloc_asprintf(tctx,
-                               "%s -L SAMBA_OUTPUT > /dev/null 2>&1 || "
-                               "("
-                               "%s -N SAMBA_OUTPUT && "
-                               "%s -I OUTPUT -j SAMBA_OUTPUT;"
-                               ")",
-                               ipt, ipt, ipt);
+                               "%s -N %s && "
+                               "%s -I %s -j %s;"
+                               ");"
+                               "%s -F %s;",
+                               ipt, chain,
+                               ipt, chain,
+                               ipt, parent_chain, chain,
+                               ipt, chain);
        }
 
-       if (cmd_in == NULL || cmd_out == NULL) {
-               return false;
-       }
-
-       if (!run_cmd(cmd_in)) {
-               return false;
-       }
-       /* if (!run_cmd(cmd_out)) { return false; } */
-
-       return true;
-}
-
-static bool filter_tcp_setup_name(struct torture_context *tctx,
-                                 const char *name, bool unblock)
-{
-       const char *cmd_in, *cmd_out;
-       const char *chain_in, *chain_out;
-       const char *ipt = iptables_command(tctx);
-
-       chain_in = samba_chain_name(tctx, name, "SAMBA_INPUT");
-       chain_out = samba_chain_name(tctx, name, "SAMBA_OUTPUT");
-       if (chain_in == NULL || chain_out == NULL) {
-               return false;
-       }
-
-       if (unblock) {
-               cmd_in  = talloc_asprintf(tctx, "%s -F %s; "
-                                               "%s -D SAMBA_INPUT -j %s; "
-                                               "%s -X %s",
-                                               ipt, chain_in,
-                                               ipt, chain_in,
-                                               ipt, chain_in);
-               cmd_out = talloc_asprintf(tctx, "%s -F %s; "
-                                               "%s -D SAMBA_OUTPUT -j %s; "
-                                               "%s -X %s",
-                                               ipt, chain_out,
-                                               ipt, chain_out,
-                                               ipt, chain_out);
-       } else {
-               cmd_in  = talloc_asprintf(tctx, "%s -L %s > /dev/null 2>&1 || "
-                                               "%s -N %s && "
-                                               "%s -I SAMBA_INPUT -j %s",
-                                               ipt, chain_in,
-                                               ipt, chain_in,
-                                               ipt, chain_in);
-               cmd_out = talloc_asprintf(tctx, "%s -L %s > /dev/null 2>&1 || "
-                                               "%s -N %s && "
-                                               "%s -I SAMBA_OUTPUT -j %s",
-                                               ipt, chain_out,
-                                               ipt, chain_out,
-                                               ipt, chain_out);
-       }
-
-       if (cmd_in == NULL || cmd_out == NULL) {
-               return false;
-       }
-
-       if (!run_cmd(cmd_in)) {
-               return false;
-       }
-       /* if (!run_cmd(cmd_out)) return false; */
-
-       return true;
-}
-
-/* '11   452 DROP tcp -- * *  0.0.0.0/0  0.0.0.0/0  tcp dpt:43062' */
-static bool get_packet_count(const char *s, uint32_t *count)
-{
-       int i = 0;
-       char *p;
-
-       if (s == NULL) {
-               return false;
-       }
-
-       while (s[i] == ' ') {
-               s++;
-       }
-
-       p = strchr(s, ' ');
-       if (p == NULL) {
-               return false;
-       }
-       *p = '\0';
-
-       *count = atoi(s);
-
-       return true;
-}
-
-bool torture_list_tcp_transport_name(struct torture_context *tctx,
-                                   const char *name,
-                                   uint32_t *_packets)
-{
-       const char *chain_in, *cmd;
-       int num_lines;
-       char **buf;
-       uint32_t packets = 0;
-       const char *ipt = iptables_command(tctx);
-
-       chain_in = samba_chain_name(tctx, name, "SAMBA_INPUT");
-       if (chain_in == NULL) {
-               return false;
-       }
-
-       cmd = talloc_asprintf(tctx, "%s -L %s -v -n", ipt, chain_in);
        if (cmd == NULL) {
                return false;
        }
 
-       if (!run_cmd_return_buf(tctx, cmd, &num_lines, &buf)) {
+       if (!run_cmd(cmd)) {
                return false;
        }
-       SMB_ASSERT(num_lines >= 3);
-
-       if (!get_packet_count(buf[2], &packets)) {
-               return false;
-       }
-
-       torture_comment(tctx, "chain: '%s', packets: %d\n", name, (int)packets);
-
-       if (_packets != NULL) {
-               *_packets = packets;
-       }
 
        return true;
 }
@@ -300,71 +147,86 @@ uint16_t torture_get_local_port_from_transport(struct smb2_transport *t)
        return get_sockaddr_port(local_ss);
 }
 
-static bool torture_block_tcp_transport_name_internal(
+static bool torture_block_tcp_output_port_internal(
                                                struct torture_context *tctx,
-                                               struct smb2_transport *t,
                                                const char *name,
+                                               uint16_t port,
                                                bool unblock)
 {
-       char *cmd_in;
-       char *cmd_out;
-       const char *chain_in, *chain_out;
-       uint16_t port = torture_get_local_port_from_transport(t);
        const char *ipt = iptables_command(tctx);
+       const char *chain_out = NULL;
+       char *cmd_out = NULL;
 
-       chain_in = samba_chain_name(tctx, name, "SAMBA_INPUT");
-       chain_out = samba_chain_name(tctx, name, "SAMBA_OUTPUT");
-       if (chain_in == NULL || chain_out == NULL) {
+       chain_out = samba_chain_name(tctx, name, "SMBTORTURE");
+       if (chain_out == NULL) {
                return false;
        }
 
-       if (!unblock) {
-               filter_tcp_setup(tctx, false);
-               filter_tcp_setup_name(tctx, name, false);
-       }
-
        torture_comment(tctx, "%sblocking %s dport %d\n",
                        unblock ? "un" : "", name, port);
 
-       cmd_in = talloc_asprintf(tctx,
-                                "%s %s %s -p tcp --dport %d -j DROP",
-                                ipt, unblock ? "-D" : "-I", chain_in, port);
+       if (!unblock) {
+               bool ok;
+
+               iptables_setup_chain(tctx,
+                                    "SMBTORTURE_OUTPUT",
+                                    chain_out,
+                                    true);
+               ok = iptables_setup_chain(tctx,
+                                         "SMBTORTURE_OUTPUT",
+                                         chain_out,
+                                         false);
+               if (!ok) {
+                       return false;
+               }
+       }
+
        cmd_out = talloc_asprintf(tctx,
                                  "%s %s %s -p tcp --sport %d -j DROP",
                                  ipt, unblock ? "-D" : "-I", chain_out, port);
-       if (cmd_in == NULL || cmd_out == NULL) {
+       if (cmd_out == NULL) {
                return false;
        }
 
-       if (!run_cmd(cmd_in)) {
+       if (!run_cmd(cmd_out)) {
                return false;
        }
-       /* if (!run_cmd(cmd_out)) return false; */
 
        if (unblock) {
-               filter_tcp_setup_name(tctx, name, true);
-               /* better don't cleanup here */
-               /* filter_tcp_setup(tctx, true); */
+               bool ok;
+
+               ok = iptables_setup_chain(tctx,
+                                         "SMBTORTURE_OUTPUT",
+                                         chain_out,
+                                         true);
+               if (!ok) {
+                       return false;
+               }
        }
 
        return true;
 }
 
-bool torture_block_tcp_transport_name(struct torture_context *tctx,
-                                     struct smb2_transport *t,
-                                     const char *name)
+bool torture_block_tcp_output_port(struct torture_context *tctx,
+                                  const char *name,
+                                  uint16_t port)
+{
+       return torture_block_tcp_output_port_internal(tctx, name, port, false);
+}
+
+bool torture_unblock_tcp_output_port(struct torture_context *tctx,
+                                    const char *name,
+                                    uint16_t port)
 {
-       return torture_block_tcp_transport_name_internal(tctx, t, name, false);
+       return torture_block_tcp_output_port_internal(tctx, name, port, true);
 }
 
-bool torture_unblock_tcp_transport_name(struct torture_context *tctx,
-                                       struct smb2_transport *t,
-                                       const char *name)
+bool torture_block_tcp_output_setup(struct torture_context *tctx)
 {
-       return torture_block_tcp_transport_name_internal(tctx, t, name, true);
+       return iptables_setup_chain(tctx, "OUTPUT", "SMBTORTURE_OUTPUT", false);
 }
 
-void torture_unblock_cleanup(struct torture_context *tctx)
+bool torture_unblock_tcp_output_cleanup(struct torture_context *tctx)
 {
-       filter_tcp_setup(tctx, true);
+       return iptables_setup_chain(tctx, "OUTPUT", "SMBTORTURE_OUTPUT", true);
 }
index 9278caaa2b704a3435f592b145b5cadef1ac6c84..7f36b89a6935d499e0dae960fad3adf822ebd00d 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-bool torture_list_tcp_transport_name(struct torture_context *tctx,
-                                   const char *name,
-                                   uint32_t *packets);
-
-bool torture_block_tcp_transport_name(struct torture_context *tctx,
-                                     struct smb2_transport *t,
-                                     const char *name);
-
-bool torture_unblock_tcp_transport_name(struct torture_context *tctx,
-                                       struct smb2_transport *t,
-                                       const char *name);
-
-void torture_unblock_cleanup(struct torture_context *tctx);
-
 uint16_t torture_get_local_port_from_transport(struct smb2_transport *t);
 
-#define torture_block_tcp_transport(_tctx, _t) \
-       torture_block_tcp_transport_name(_tctx, _t, #_t)
-
-#define torture_unblock_tcp_transport(_tctx, _t) \
-       torture_unblock_tcp_transport_name(_tctx, _t, #_t)
+bool torture_block_tcp_output_port(struct torture_context *tctx,
+                                  const char *name,
+                                  uint16_t port);
+bool torture_unblock_tcp_output_port(struct torture_context *tctx,
+                                    const char *name,
+                                    uint16_t port);
+bool torture_block_tcp_output_setup(struct torture_context *tctx);
+bool torture_unblock_tcp_output_cleanup(struct torture_context *tctx);
 
-#define torture_list_tcp_transport(_tctx, _t, _packets) \
-       torture_list_tcp_transport_name(_tctx, #_t, _packets)
index e2dea58372ce400b20c415455a545f0da088a219..7cf39dadbe32b1289c6b2dae1a85f854b92a8ef7 100644 (file)
@@ -399,8 +399,8 @@ static bool test_iptables_block_channel(struct torture_context *tctx,
        bool ret;
 
        local_port = torture_get_local_port_from_transport(transport);
-       torture_comment(tctx, "transport uses tcp port: %d\n", local_port);
-       ret = torture_block_tcp_transport_name(tctx, transport, name);
+       torture_comment(tctx, "transport[%s] uses tcp port: %d\n", name, local_port);
+       ret = torture_block_tcp_output_port(tctx, name, local_port);
        torture_assert(tctx, ret, "we could not block tcp transport");
 
        return ret;
@@ -414,8 +414,8 @@ static bool test_iptables_unblock_channel(struct torture_context *tctx,
        bool ret;
 
        local_port = torture_get_local_port_from_transport(transport);
-       torture_comment(tctx, "transport uses tcp port: %d\n", local_port);
-       ret = torture_unblock_tcp_transport_name(tctx, transport, name);
+       torture_comment(tctx, "transport[%s] uses tcp port: %d\n", name, local_port);
+       ret = torture_unblock_tcp_output_port(tctx, name, local_port);
        torture_assert(tctx, ret, "we could not block tcp transport");
 
        return ret;
@@ -451,13 +451,25 @@ static bool _test_unblock_channel(struct torture_context *tctx,
        }
 }
 
+static bool test_setup_blocked_channels(struct torture_context *tctx)
+{
+       bool use_iptables = torture_setting_bool(tctx,
+                                       "use_iptables", false);
+
+       if (use_iptables) {
+               return torture_block_tcp_output_setup(tctx);
+       }
+
+       return true;
+}
+
 static void test_cleanup_blocked_channels(struct torture_context *tctx)
 {
        bool use_iptables = torture_setting_bool(tctx,
                                        "use_iptables", false);
 
        if (use_iptables) {
-               torture_unblock_cleanup(tctx);
+               torture_unblock_tcp_output_cleanup(tctx);
        }
 }
 
@@ -695,6 +707,7 @@ static bool test_multichannel_oplock_break_test2(struct torture_context *tctx,
        struct smb2_session *session1 = tree1->session;
        uint16_t local_port = 0;
        DATA_BLOB blob;
+       bool block_setup = false;
        bool block_ok = false;
        bool unblock_ok = false;
 
@@ -779,6 +792,9 @@ static bool test_multichannel_oplock_break_test2(struct torture_context *tctx,
        transport2 = break_info.received_transport;
        torture_reset_break_info(tctx, &break_info);
 
+       block_setup = test_setup_blocked_channels(tctx);
+       torture_assert(tctx, block_setup, "test_setup_blocked_channels");
+
        /* block channel */
        block_ok = test_block_channel(tctx, transport2);
 
@@ -1156,6 +1172,7 @@ static bool test_multichannel_lease_break_test2(struct torture_context *tctx,
        struct smb2_lease ls1;
        struct smb2_lease ls2;
        struct smb2_lease ls3;
+       bool block_setup = false;
        bool block_ok = false;
        bool unblock_ok = false;
 
@@ -1231,6 +1248,8 @@ static bool test_multichannel_lease_break_test2(struct torture_context *tctx,
        CHECK_VAL(io2.out.durable_open, false);
        CHECK_VAL(lease_break_info.count, 0);
 
+       block_setup = test_setup_blocked_channels(tctx);
+       torture_assert(tctx, block_setup, "test_setup_blocked_channels");
 
        torture_comment(tctx, "Blocking 2A\n");
        /* Block 2A */
@@ -1384,7 +1403,9 @@ done:
        if (block_ok && !unblock_ok) {
                test_unblock_channel(tctx, transport2A);
        }
-       test_cleanup_blocked_channels(tctx);
+       if (block_setup) {
+               test_cleanup_blocked_channels(tctx);
+       }
 
        tree1->session = session1;