From: Michael Altizer (mialtize) Date: Mon, 25 Sep 2017 16:03:16 +0000 (-0400) Subject: Merge pull request #1017 in SNORT/snort3 from binder_direction to master X-Git-Tag: 3.0.0-240~33 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6358e62535010f5cf67a4d3cc07d978018450147;p=thirdparty%2Fsnort3.git Merge pull request #1017 in SNORT/snort3 from binder_direction to master Squashed commit of the following: commit 4cd912df8cfa19769b83058243cd227bf24a693b Author: Carter Waxman Date: Tue Sep 19 10:35:10 2017 -0400 Binder: allow src and dst specifications for ports and nets --- diff --git a/src/network_inspectors/binder/bind_module.cc b/src/network_inspectors/binder/bind_module.cc index 1903b50a1..f30c1433b 100644 --- a/src/network_inspectors/binder/bind_module.cc +++ b/src/network_inspectors/binder/bind_module.cc @@ -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()); diff --git a/src/network_inspectors/binder/bind_module.h b/src/network_inspectors/binder/bind_module.h index fd7014f97..7084862b0 100644 --- a/src/network_inspectors/binder/bind_module.h +++ b/src/network_inspectors/binder/bind_module.h @@ -64,6 +64,12 @@ public: private: Binding* work; std::vector 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 diff --git a/src/network_inspectors/binder/binder.cc b/src/network_inspectors/binder/binder.cc index ad46996d8..7b2f7d8a5 100644 --- a/src/network_inspectors/binder/binder.cc +++ b/src/network_inspectors/binder/binder.cc @@ -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; diff --git a/src/network_inspectors/binder/binding.h b/src/network_inspectors/binder/binding.h index 294d81137..69e191038 100644 --- a/src/network_inspectors/binder/binding.h +++ b/src/network_inspectors/binder/binding.h @@ -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; };