return host_port_cache.add(sc, ip, port, proto, type, appid);
}
- bool host_first_pkt_add(const snort::SnortConfig* sc, const snort::SfIp* ip, uint16_t port,
+ bool host_first_pkt_add(const snort::SnortConfig* sc, const snort::SfIp* ip, uint32_t* netmask, uint16_t port,
IpProtocol proto, AppId protocol_appid, AppId client_appid, AppId web_appid, unsigned reinspect)
{
- return first_pkt_cache.add_host(sc, ip, port, proto, protocol_appid, client_appid, web_appid, reinspect);
+ return first_pkt_cache.add_host(sc, ip, netmask, port, proto, protocol_appid, client_appid, web_appid, reinspect);
}
HostAppIdsVal* host_first_pkt_find(const snort::SfIp* ip, uint16_t port, IpProtocol proto)
using namespace snort;
+inline void apply_min_ip_range(SfIp& ip, const uint32_t* netmask)
+{
+ if (ip.get_family() == AF_INET)
+ {
+ uint32_t tmp_val = ip.get_ip4_value() & netmask[3];
+ ip.set(&tmp_val, AF_INET);
+ }
+ else if (ip.get_family() == AF_INET6)
+ {
+ uint32_t* tmp_val = const_cast<uint32_t*>(ip.get_ip6_ptr());
+ tmp_val[0] = tmp_val[0] & netmask[0];
+ tmp_val[1] = tmp_val[1] & netmask[1];
+ tmp_val[2] = tmp_val[2] & netmask[2];
+ tmp_val[3] = tmp_val[3] & netmask[3];
+ ip.set(tmp_val, AF_INET6);
+ }
+}
+
+inline void apply_max_ip_range(SfIp& ip, const uint32_t* netmask)
+{
+ if (ip.get_family() == AF_INET)
+ {
+ uint32_t tmp_val = ip.get_ip4_value() | ~netmask[3];
+ ip.set(&tmp_val, AF_INET);
+ }
+ else if (ip.get_family() == AF_INET6)
+ {
+ uint32_t* tmp_val = const_cast<uint32_t*>(ip.get_ip6_ptr());
+
+ tmp_val[0] = tmp_val[0] | ~netmask[0];
+ tmp_val[1] = tmp_val[1] | ~netmask[1];
+ tmp_val[2] = tmp_val[2] | ~netmask[2];
+ tmp_val[3] = tmp_val[3] | ~netmask[3];
+
+ ip.set(tmp_val, AF_INET6);
+ }
+}
+
+inline bool check_ip_range(const SfIp& max, const SfIp& min, const SfIp& ip, const uint32_t* netmask)
+{
+ if (max.get_family() != ip.get_family())
+ return false;
+
+ if (max.is_ip4())
+ {
+ SfIp tmp = ip;
+ apply_min_ip_range(tmp, netmask);
+ if (tmp.get_ip4_value() == min.get_ip4_value())
+ {
+ apply_max_ip_range(tmp, netmask);
+ return tmp.get_ip4_value() == max.get_ip4_value();
+ }
+ }
+ else if (max.is_ip6())
+ {
+ SfIp tmp = ip;
+ apply_min_ip_range(tmp, netmask);
+ if (memcmp(tmp.get_ip6_ptr(), min.get_ip6_ptr(), 16) == 0)
+ {
+ apply_max_ip_range(tmp, netmask);
+ return memcmp(tmp.get_ip6_ptr(), max.get_ip6_ptr(), 16) == 0;
+ }
+ }
+
+ return false;
+}
+
HostPortVal* HostPortCache::find(const SfIp* ip, uint16_t port, IpProtocol protocol,
const OdpContext& odp_ctxt)
{
return true;
}
-
HostAppIdsVal* HostPortCache::find_on_first_pkt(const SfIp* ip, uint16_t port, IpProtocol protocol,
const OdpContext& odp_ctxt)
{
- HostPortKey hk;
+ uint16_t lookup_port = (odp_ctxt.allow_port_wildcard_host_cache)? 0 : port;
- hk.ip = *ip;
- hk.port = (odp_ctxt.allow_port_wildcard_host_cache)? 0 : port;
- hk.proto = protocol;
+ if (!cache_first_ip.empty())
+ {
+ HostPortKey hk;
- std::map<HostPortKey, HostAppIdsVal>::iterator it;
- it = cache_first.find(hk);
- if (it != cache_first.end())
- return &it->second;
- else
- return nullptr;
+ hk.ip = *ip;
+ hk.port = lookup_port;
+ hk.proto = protocol;
+
+ std::map<HostPortKey, HostAppIdsVal>::iterator check_cache;
+ check_cache = cache_first_ip.find(hk);
+ if (check_cache != cache_first_ip.end())
+ return &check_cache->second;
+ }
+
+ for (std::map<FirstPktkey ,HostAppIdsVal>::iterator iter = cache_first_subnet.begin(); iter != cache_first_subnet.end(); ++iter)
+ {
+ if (iter->first.port == lookup_port and iter->first.proto == protocol and
+ check_ip_range(iter->first.max_network_range, iter->first.network_address, *ip, &iter->first.netmask[0]))
+ {
+ return &iter->second;
+ }
+ }
+
+ return nullptr;
}
-bool HostPortCache::add_host(const SnortConfig* sc, const SfIp* ip, uint16_t port, IpProtocol proto,
+bool HostPortCache::add_host(const SnortConfig* sc, const SfIp* ip, uint32_t* netmask, uint16_t port, IpProtocol proto,
AppId protocol_appId, AppId client_appId, AppId web_appId, unsigned reinspect)
{
- HostPortKey hk;
- HostAppIdsVal hv;
-
- hk.ip = *ip;
- AppIdInspector* inspector =
- (AppIdInspector*)InspectorManager::get_inspector(MOD_NAME, false, sc);
- assert(inspector);
- const AppIdContext& ctxt = inspector->get_ctxt();
- hk.port = (ctxt.get_odp_ctxt().allow_port_wildcard_host_cache)? 0 : port;
- hk.proto = proto;
-
- hv.protocol_appId = protocol_appId;
- hv.client_appId = client_appId;
- hv.web_appId = web_appId;
- hv.reinspect = reinspect;
-
- cache_first[ hk ] = hv;
-
+ if (!netmask)
+ {
+ HostPortKey hk;
+ HostAppIdsVal hv;
+
+ hk.ip = *ip;
+ AppIdInspector* inspector =
+ (AppIdInspector*)InspectorManager::get_inspector(MOD_NAME, false, sc);
+ assert(inspector);
+ const AppIdContext& ctxt = inspector->get_ctxt();
+ hk.port = (ctxt.get_odp_ctxt().allow_port_wildcard_host_cache)? 0 : port;
+ hk.proto = proto;
+
+ hv.protocol_appId = protocol_appId;
+ hv.client_appId = client_appId;
+ hv.web_appId = web_appId;
+ hv.reinspect = reinspect;
+
+ cache_first_ip[ hk ] = hv;
+ }
+ else
+ {
+ FirstPktkey hk;
+ HostAppIdsVal hv;
+
+ hk.network_address = *ip;
+ apply_min_ip_range(hk.network_address, netmask);
+ hk.max_network_range = hk.network_address;
+ apply_max_ip_range(hk.max_network_range, netmask);
+
+ memcpy(&hk.netmask[0], netmask, 16);
+
+ AppIdInspector* inspector =
+ (AppIdInspector*)InspectorManager::get_inspector(MOD_NAME, false, sc);
+ assert(inspector);
+ const AppIdContext& ctxt = inspector->get_ctxt();
+ hk.port = (ctxt.get_odp_ctxt().allow_port_wildcard_host_cache)? 0 : port;
+ hk.proto = proto;
+
+ hv.protocol_appId = protocol_appId;
+ hv.client_appId = client_appId;
+ hv.web_appId = web_appId;
+ hv.reinspect = reinspect;
+
+ cache_first_subnet.emplace(hk, hv);
+ }
return true;
}
};
PADDING_GUARD_END
+PADDING_GUARD_BEGIN
+struct FirstPktkey
+{
+ FirstPktkey()
+ {
+ max_network_range.clear();
+ network_address.clear();
+ port = 0;
+ proto = IpProtocol::PROTO_NOT_SET;
+ }
+
+ bool operator<(const FirstPktkey& right) const
+ {
+ if ((htonl(right.netmask[0]) < htonl(this->netmask[0])) or
+ (htonl(right.netmask[1]) < htonl(this->netmask[1])) or
+ (htonl(right.netmask[2]) < htonl(this->netmask[2])) or
+ (htonl(right.netmask[3]) < htonl(this->netmask[3])))
+ return true;
+ else
+ return false;
+ }
+
+ uint32_t netmask[4];
+ snort::SfIp max_network_range;
+ snort::SfIp network_address;
+ uint16_t port;
+ IpProtocol proto;
+ char padding;
+};
+PADDING_GUARD_END
+
struct HostPortVal
{
AppId appId;
unsigned type, AppId);
HostAppIdsVal* find_on_first_pkt(const snort::SfIp*, uint16_t port, IpProtocol, const OdpContext&);
- bool add_host(const snort::SnortConfig*, const snort::SfIp*, uint16_t port, IpProtocol,
+ bool add_host(const snort::SnortConfig*, const snort::SfIp*, uint32_t* netmask, uint16_t port, IpProtocol,
AppId, AppId, AppId, unsigned reinspect);
void dump();
~HostPortCache()
{
cache.clear();
- cache_first.clear();
+ cache_first_ip.clear();
+ cache_first_subnet.clear();
}
private:
+
std::map<HostPortKey, HostPortVal> cache;
- std::map<HostPortKey, HostAppIdsVal> cache_first;
+ std::map<HostPortKey, HostAppIdsVal> cache_first_ip;
+ std::multimap<FirstPktkey, HostAppIdsVal> cache_first_subnet;
};
#endif
uint32_t client_appid = lua_tointeger(L, ++index);
uint32_t web_appid = lua_tointeger(L, ++index);
unsigned reinspect = lua_tointeger(L, ++index);
-
- /* Extract IP, Port, protocol */
+
+ /* Extract Network IP and netmask */
size_t ipaddr_size = 0;
- const char* ip_str = lua_tolstring(L, ++index, &ipaddr_size);
- if (!ip_str or !ipaddr_size or !convert_string_to_address(ip_str, &ip_address))
+ uint32_t netmask32[4] = { 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu };
+ bool netmask_parsed = false;
+ const char* cidr_str = lua_tolstring(L, ++index, &ipaddr_size);
+ vector<string> tokens;
+
+ if (!cidr_str or !ipaddr_size)
{
- ErrorMessage("%s: Invalid IP address: %s\n",__func__, ip_str);
+ ErrorMessage("%s: No IP address provided\n", "First packet API");
return 0;
+ }
+
+ if (strchr(cidr_str, '/') == nullptr)
+ {
+ if (!convert_string_to_address(cidr_str, &ip_address))
+ {
+ ErrorMessage("%s: Invalid IP address: %s\n", "First packet API", cidr_str);
+ return 0;
+ }
+ }
+ else
+ {
+ stringstream ss(cidr_str);
+ string temp_str;
+
+ while (getline(ss, temp_str, '/'))
+ {
+ tokens.push_back(temp_str);
+ }
+
+ const char* netip_str = tokens[0].c_str();
+
+ if (!netip_str or !convert_string_to_address(netip_str, &ip_address))
+ {
+ ErrorMessage("%s: Invalid IP address: %s\n", "First packet API", netip_str);
+ return 0;
+ }
+
+ if (all_of(tokens[1].begin(), tokens[1].end(), ::isdigit))
+ {
+ int bits = stoi(tokens[1].c_str());
+ if (strchr(netip_str, '.'))
+ {
+ if (bits < 0 or bits > 32)
+ {
+ ErrorMessage("%s: Invalid IPv4 prefix range: %d\n","First packet API", bits);
+ return 0;
+ }
+ }
+ else if (strchr(netip_str, ':'))
+ {
+ if (bits < 0 or bits > 128) {
+ ErrorMessage("%s: Invalid IPv6 prefix range: %d\n","First packet API", bits);
+ return 0;
+ }
+ }
+
+ if (bits < 32 and !strchr(netip_str, ':'))
+ netmask32[3] = bits > 0 ? (0xFFFFFFFFu << (32 - bits)) : 0xFFFFFFFFu;
+ else
+ {
+ for (int i = 3; i >= 0; --i)
+ {
+ auto tmp_bits = 32 + (32 * i) - bits;
+
+ if (tmp_bits > 0)
+ netmask32[i] = tmp_bits >= 32 ? 0 : (0xFFFFFFFFu << tmp_bits);
+ }
+ }
+
+ for (int i = 0; i < 4; i++)
+ {
+ netmask32[i] = (uint32_t)htonl(netmask32[i]);
+ }
+
+ netmask_parsed = true;
+ }
+ else
+ {
+ ErrorMessage("%s: Invalid prefix bit: %s\n", "First packet API", tokens[1].c_str());
+ return 0;
+ }
}
unsigned port = lua_tointeger(L, ++index);
lua_pop(L, 1);
if (!ud->get_odp_ctxt().host_first_pkt_add(
- sc, &ip_address, (uint16_t)port, proto, protocol_appid, client_appid, web_appid, reinspect))
+ sc, &ip_address, netmask_parsed ? netmask32 : nullptr, (uint16_t)port, proto, protocol_appid, client_appid, web_appid, reinspect))
ErrorMessage("%s:Failed to backend call first pkt add\n",__func__);
return 0;