]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1017 in SNORT/snort3 from binder_direction to master
authorMichael Altizer (mialtize) <mialtize@cisco.com>
Mon, 25 Sep 2017 16:03:16 +0000 (12:03 -0400)
committerMichael Altizer (mialtize) <mialtize@cisco.com>
Mon, 25 Sep 2017 16:03:16 +0000 (12:03 -0400)
Squashed commit of the following:

commit 4cd912df8cfa19769b83058243cd227bf24a693b
Author: Carter Waxman <cwaxman@cisco.com>
Date:   Tue Sep 19 10:35:10 2017 -0400

    Binder: allow src and dst specifications for ports and nets

src/network_inspectors/binder/bind_module.cc
src/network_inspectors/binder/bind_module.h
src/network_inspectors/binder/binder.cc
src/network_inspectors/binder/binding.h

index 1903b50a155e5872651c19723dc3c33f0cd0a8e8..f30c1433b348a8f420fb10dda1fa16f459caa53f 100644 (file)
@@ -69,12 +69,24 @@ static const Parameter binder_when_params[] =
     { "nets", Parameter::PT_ADDR_LIST, nullptr, nullptr,
       "list of networks" },
 
+    { "src_nets", Parameter::PT_ADDR_LIST, nullptr, nullptr,
+      "list of source networks" },
+
+    { "dst_nets", Parameter::PT_ADDR_LIST, nullptr, nullptr,
+      "list of destination networks" },
+
     { "proto", Parameter::PT_ENUM, "any | ip | icmp | tcp | udp | user | file", nullptr,
       "protocol" },
 
     { "ports", Parameter::PT_BIT_LIST, "65535", nullptr,
       "list of ports" },
 
+    { "src_ports", Parameter::PT_BIT_LIST, "65535", nullptr,
+      "list of source ports" },
+
+    { "dst_ports", Parameter::PT_BIT_LIST, "65535", nullptr,
+      "list of destination ports" },
+
     { "role", Parameter::PT_ENUM, "client | server | any", "any",
       "use the given configuration on one or any end of a session" },
 
@@ -133,8 +145,20 @@ BinderModule::~BinderModule()
 ProfileStats* BinderModule::get_profile() const
 { return &bindPerfStats; }
 
-static void file_name_type_error()
-{ ParseError("you can't set binder.use file, detection_policy, or inspection_policy with type or name"); }
+void BinderModule::add_file(const char* name, const char* type)
+{
+    work->use.name = name;
+    work->use.type = type;
+    use_name_count++;
+    use_type_count++;
+}
+
+static void set_ip_var(sfip_var_t*& var, const char* val)
+{
+    if ( var )
+        sfvar_free(var);
+    var = sfip_var_from_string(val);
+}
 
 bool BinderModule::set(const char* fqn, Value& v, SnortConfig*)
 {
@@ -153,8 +177,20 @@ bool BinderModule::set(const char* fqn, Value& v, SnortConfig*)
         v.get_bits(work->when.ifaces);
 
     else if ( v.is("nets") )
-        work->when.nets = sfip_var_from_string(v.get_string());
-
+    {
+        set_ip_var(work->when.src_nets, v.get_string());
+        unsplit_nets = true;
+    }
+    else if ( v.is("src_nets") )
+    {
+        set_ip_var(work->when.src_nets, v.get_string());
+        work->when.split_nets = true;
+    }
+    else if ( v.is("dst_nets") )
+    {
+        set_ip_var(work->when.dst_nets, v.get_string());
+        work->when.split_nets = true;
+    }
     else if ( v.is("ips_policy_id") )
         work->when.ips_id = v.get_long();
 
@@ -168,7 +204,20 @@ bool BinderModule::set(const char* fqn, Value& v, SnortConfig*)
         work->when.protos = (unsigned)mask[v.get_long()];
     }
     else if ( v.is("ports") )
-        v.get_bits(work->when.ports);
+    {
+        v.get_bits(work->when.src_ports);
+        unsplit_ports = true;
+    }
+    else if ( v.is("src_ports") )
+    {
+        v.get_bits(work->when.src_ports);
+        work->when.split_ports = true;
+    }
+    else if ( v.is("dst_ports") )
+    {
+        v.get_bits(work->when.dst_ports);
+        work->when.split_ports = true;
+    }
 
     else if ( v.is("role") )
         work->when.role = (BindWhen::Role)v.get_long();
@@ -181,42 +230,23 @@ bool BinderModule::set(const char* fqn, Value& v, SnortConfig*)
         work->use.action = (BindUse::Action)(v.get_long());
 
     else if ( v.is("file") )
-    {
-        if ( !work->use.name.empty() || !work->use.type.empty() )
-            file_name_type_error();
+        add_file(v.get_string(), FILE_KEY);
 
-        work->use.name = v.get_string();
-        work->use.type = FILE_KEY;
-    }
     else if ( v.is("inspection_policy") )
-    {
-        if ( !work->use.name.empty() || !work->use.type.empty() )
-            file_name_type_error();
+        add_file(v.get_string(), INSPECTION_KEY);
 
-        work->use.name = v.get_string();
-        work->use.type = INSPECTION_KEY;
-    }
     else if ( v.is("ips_policy") )
-    {
-        if ( !work->use.name.empty() || !work->use.type.empty() )
-            file_name_type_error();
+        add_file(v.get_string(), IPS_KEY);
 
-        work->use.name = v.get_string();
-        work->use.type = IPS_KEY;
-    }
     else if ( v.is("name") )
     {
-        if ( !work->use.name.empty() )
-            file_name_type_error();
-
         work->use.name = v.get_string();
+        use_name_count++;
     }
     else if ( v.is("type") )
     {
-        if ( !work->use.type.empty() )
-            file_name_type_error();
-
         work->use.type = v.get_string();
+        use_type_count++;
     }
     else
         return false;
@@ -227,11 +257,25 @@ bool BinderModule::set(const char* fqn, Value& v, SnortConfig*)
 bool BinderModule::begin(const char* fqn, int idx, SnortConfig*)
 {
     if ( idx && !strcmp(fqn, BIND_NAME) )
+    {
         work = new Binding;
+        unsplit_nets = false;
+        use_name_count = 0;
+        use_type_count = 0;
+    }
 
     return true;
 }
 
+static void file_name_type_error()
+{ ParseError("you can't set binder.use file, detection_policy, or inspection_policy with type or name"); }
+
+static void split_nets_warning()
+{ ParseWarning(WARN_CONF, "src_nets and dst_nets override nets"); }
+
+static void split_ports_warning()
+{ ParseWarning(WARN_CONF, "src_ports and dst_ports override ports"); }
+
 bool BinderModule::end(const char* fqn, int idx, SnortConfig* sc)
 {
     if ( idx && !strcmp(fqn, BIND_NAME) )
@@ -242,6 +286,15 @@ bool BinderModule::end(const char* fqn, int idx, SnortConfig* sc)
             return true;
         }
 
+        if ( unsplit_nets && work->when.split_nets )
+            split_nets_warning();
+
+        if ( unsplit_ports && work->when.split_ports )
+            split_ports_warning();
+
+        if ( use_type_count > 1 || use_name_count > 1 )
+            file_name_type_error();
+
         if ( work->use.type == FILE_KEY )
         {
             Shell* sh = new Shell(work->use.name.c_str());
index fd7014f97507be3992f7a7c73687ebb1146a0a13..7084862b0c009f24048673312be394d32943f1a0 100644 (file)
@@ -64,6 +64,12 @@ public:
 private:
     Binding* work;
     std::vector<Binding*> bindings;
+    bool unsplit_nets;
+    bool unsplit_ports;
+    unsigned use_name_count;
+    unsigned use_type_count;
+
+    void add_file(const char* name, const char* type);
 };
 
 #endif
index ad46996d81b37b67dbaaedd15ff38357c3cdb214..7b2f7d8a52c8899c763228ec548aa080ab264d12 100644 (file)
@@ -56,11 +56,16 @@ THREAD_LOCAL ProfileStats bindPerfStats;
 
 Binding::Binding()
 {
-    when.nets = nullptr;
-    when.protos = (unsigned)PktType::ANY;
+    when.split_nets = false;
+    when.src_nets = nullptr;
+    when.dst_nets = nullptr;
+
+    when.split_ports = false;
+    when.src_ports.set();
+    when.dst_ports.set();
 
+    when.protos = (unsigned)PktType::ANY;
     when.vlans.set();
-    when.ports.set();
     when.ifaces.set();
 
     when.ips_id = 0;
@@ -76,8 +81,11 @@ Binding::Binding()
 
 Binding::~Binding()
 {
-    if ( when.nets )
-        sfvar_free(when.nets);
+    if ( when.src_nets )
+        sfvar_free(when.src_nets);
+
+    if ( when.dst_nets )
+        sfvar_free(when.dst_nets);
 }
 
 bool Binding::check_ips_policy(const Flow* flow) const
@@ -93,30 +101,53 @@ bool Binding::check_ips_policy(const Flow* flow) const
 
 bool Binding::check_addr(const Flow* flow) const
 {
-    if ( !when.nets )
+    if ( when.split_nets )
+        return true;
+
+    if ( !when.src_nets )
         return true;
 
     switch ( when.role )
     {
         case BindWhen::BR_SERVER:
-            if ( sfvar_ip_in(when.nets, &flow->server_ip) )
+            if ( sfvar_ip_in(when.src_nets, &flow->server_ip) )
                 return true;
-            break;
+
         case BindWhen::BR_CLIENT:
-            if ( sfvar_ip_in(when.nets, &flow->client_ip) )
+            if ( sfvar_ip_in(when.src_nets, &flow->client_ip) )
                 return true;
-            break;
+
         case BindWhen::BR_EITHER:
-            if ( sfvar_ip_in(when.nets, &flow->client_ip) or
-                    sfvar_ip_in(when.nets, &flow->server_ip) )
+            if ( sfvar_ip_in(when.src_nets, &flow->client_ip) or
+                   sfvar_ip_in(when.src_nets, &flow->server_ip) )
                 return true;
-            break;
+
         default:
             break;
     }
+    return false;
+}
 
+Binding::DirResult Binding::check_split_addr(const Flow* flow) const
+{
+    if ( !when.split_nets )
+        return Binding::DR_ANY_MATCH;
 
-    return false;
+    if ( !when.src_nets && !when.dst_nets )
+        return Binding::DR_ANY_MATCH;
+
+    bool client_in_src = !when.src_nets or sfvar_ip_in(when.src_nets, &flow->client_ip);
+    bool client_in_dst = !when.dst_nets or sfvar_ip_in(when.dst_nets, &flow->client_ip);
+    bool server_in_src = !when.src_nets or sfvar_ip_in(when.src_nets, &flow->server_ip);
+    bool server_in_dst = !when.dst_nets or sfvar_ip_in(when.dst_nets, &flow->server_ip);
+
+    if ( client_in_src and server_in_dst )
+        return Binding::DR_CLIENT_SRC;
+    
+    if ( server_in_src and client_in_dst )
+        return Binding::DR_SERVER_SRC;
+
+    return Binding::DR_NO_MATCH;
 }
 
 bool Binding::check_proto(const Flow* flow) const
@@ -150,14 +181,52 @@ bool Binding::check_vlan(const Flow* flow) const
 
 bool Binding::check_port(const Flow* flow) const
 {
+    if ( when.split_ports )
+        return true;
+
     switch ( when.role )
     {
         case BindWhen::BR_SERVER:
-            return when.ports.test(flow->server_port);
+            return when.src_ports.test(flow->server_port);
         case BindWhen::BR_CLIENT:
-            return when.ports.test(flow->client_port);
+            return when.src_ports.test(flow->client_port);
         case BindWhen::BR_EITHER:
-            return (when.ports.test(flow->client_port) or when.ports.test(flow->server_port) );
+            return (when.src_ports.test(flow->client_port) or when.src_ports.test(flow->server_port) );
+        default:
+            break;
+    }
+    return false;
+}
+
+bool Binding::check_split_port(const Flow* flow, const DirResult dr) const
+{
+    if ( !when.split_ports )
+        return true;
+
+    bool client_in_src = false;
+    bool client_in_dst = false;
+    bool server_in_src = false;
+    bool server_in_dst = false;
+
+    switch ( dr )
+    {
+        case Binding::DR_ANY_MATCH:
+            client_in_src = when.src_ports.test(flow->client_port);
+            client_in_dst = when.dst_ports.test(flow->client_port);
+            server_in_src = when.src_ports.test(flow->server_port);
+            server_in_dst = when.dst_ports.test(flow->server_port);
+            return ( client_in_src and server_in_dst ) or ( server_in_src and client_in_dst );
+
+        case Binding::DR_CLIENT_SRC:
+            client_in_src = when.src_ports.test(flow->client_port);
+            server_in_dst = when.dst_ports.test(flow->server_port);
+            return client_in_src and server_in_dst;
+
+        case Binding::DR_SERVER_SRC:
+            server_in_src = when.src_ports.test(flow->server_port);
+            client_in_dst = when.dst_ports.test(flow->client_port);
+            return server_in_src and client_in_dst;
+
         default:
             break;
     }
@@ -190,12 +259,19 @@ bool Binding::check_all(const Flow* flow) const
     if ( !check_addr(flow) )
         return false;
 
+    auto dir = check_split_addr(flow);
+    if ( dir == Binding::DR_NO_MATCH )
+        return false;
+
     if ( !check_proto(flow) )
         return false;
 
     if ( !check_port(flow) )
         return false;
 
+    if ( !check_split_port(flow, dir) )
+        return false;
+
     if ( !check_service(flow) )
         return false;
 
index 294d81137ed1774b009db6da3a587e60acebf2a3..69e191038d05cb8a64c0ed2f571fa739d80ab1eb 100644 (file)
@@ -36,10 +36,17 @@ struct BindWhen
     unsigned protos;
     Role role;
     std::string svc;
-    sfip_var_t* nets;
+
+    bool split_nets;
+    sfip_var_t* src_nets;
+    sfip_var_t* dst_nets;
+
     ByteBitSet ifaces;
     VlanBitSet vlans;
-    PortBitSet ports;
+
+    bool split_ports;
+    PortBitSet src_ports;
+    PortBitSet dst_ports;
 };
 
 struct BindUse
@@ -64,6 +71,9 @@ struct BindUse
 
 struct Binding
 {
+    enum DirResult
+    { DR_NO_MATCH, DR_ANY_MATCH, DR_CLIENT_SRC, DR_SERVER_SRC };
+
     BindWhen when;
     BindUse use;
 
@@ -71,13 +81,14 @@ struct Binding
     ~Binding();
 
     bool check_all(const Flow*) const;
+    bool check_ips_policy(const Flow*) const;
     bool check_iface(const Flow*) const;
     bool check_vlan(const Flow*) const;
     bool check_addr(const Flow*) const;
+    DirResult check_split_addr(const Flow*) const;
     bool check_proto(const Flow*) const;
     bool check_port(const Flow*) const;
-    bool check_inspection_policy(const Flow*) const;
-    bool check_ips_policy(const Flow*) const;
+    bool check_split_port(const Flow*, const DirResult) const;
     bool check_service(const Flow*) const;
 };