XSEM XSEN XSHA1 XSHA256
]]
+ftp_default_data_chan_cmds =
+[[
+ PORT PASV LPRT LPSV EPRT EPSV
+]]
+
+ftp_default_data_xfer_cmds =
+[[
+ RETR STOR STOU APPE LIST NLST
+]]
+
+ftp_default_file_put_cmds =
+[[
+ STOR STOU
+]]
+
+ftp_default_file_get_cmds =
+[[
+ RETR
+]]
+
+ftp_default_login_cmds =
+[[
+ USER PASS
+]]
+
+ftp_default_encr_cmds =
+[[
+ AUTH
+]]
+
ftp_format_commands =
[[
ACCT ADAT ALLO APPE AUTH CEL CLNT CMD CONF CWD DELE ENC EPRT EPSV ESTP
ignore_data_chan = true,
ftp_cmds = ftp_default_commands,
+ data_chan_cmds = ftp_default_data_chan_cmds,
+ data_xfer_cmds = ftp_default_data_xfer_cmds,
+ file_put_cmds = ftp_default_file_put_cmds,
+ file_get_cmds = ftp_default_file_get_cmds,
+ login_cmds = ftp_default_login_cmds,
+ encr_cmds = ftp_default_encr_cmds,
chk_str_fmt = ftp_format_commands,
cmd_validity = ftp_command_specs
}
return;
}
+ total = 0;
for (i=0; i<num_objects; i++)
{
void* data = ((char*)datapool) + (i * obj_size);
#include <assert.h>
-#include "time/packet_time.h"
#include "hash/zhash.h"
+#include "packet_io/sfdaq.h"
#include "protocols/packet.h"
-#include "stream/stream.h"
+#include "protocols/vlan.h"
#include "sfip/sf_ip.h"
+#include "stream/stream.h" // FIXIT-M bad dependency
+#include "time/packet_time.h"
/* Reasonably small, and prime */
// FIXIT-L size based on max_tcp + max_udp?
void ExpectFlow::clear()
{
- while ( data )
+ while (data)
{
FlowData* fd = data;
data = data->next;
struct ExpectNode
{
time_t expires = 0;
- int reversed_key = 0;
+ bool reversed_key = false;
int direction = 0;
unsigned count = 0;
int16_t appId = 0;
void ExpectNode::clear(ExpectFlow*& list)
{
- while ( head )
+ while (head)
{
ExpectFlow* p = head;
head = head->next;
count = 0;
}
-struct ExpectKey
-{
- sfip_t ip1;
- sfip_t ip2;
- uint16_t port1;
- uint16_t port2;
- PktType protocol;
-
- bool set(
- const sfip_t *cliIP, uint16_t cliPort,
- const sfip_t *srvIP, uint16_t srvPort,
- PktType proto);
-};
-
-inline bool ExpectKey::set(
- const sfip_t *cliIP, uint16_t cliPort,
- const sfip_t *srvIP, uint16_t srvPort,
- PktType proto )
-{
- bool reverse;
- SFIP_RET rval = sfip_compare(cliIP, srvIP);
-
- if (rval == SFIP_LESSER || (rval == SFIP_EQUAL && cliPort < srvPort))
- {
- sfip_copy(ip1, cliIP);
- port1 = cliPort;
- sfip_copy(ip2, srvIP);
- port2 = srvPort;
- reverse = false;
- }
- else
- {
- sfip_copy(ip1, srvIP);
- port1 = srvPort;
- sfip_copy(ip2, cliIP);
- port2 = cliPort;
- reverse = true;
- }
- protocol = proto;
- return reverse;
-}
-
//-------------------------------------------------------------------------
// private ExpectCache methods
//-------------------------------------------------------------------------
}
}
-inline ExpectNode* ExpectCache::get_node(ExpectKey& key, bool& init)
+ExpectNode* ExpectCache::find_node_by_packet(Packet* p, FlowKey &key)
{
- ExpectNode* node;
-
- if ( !free_list )
- node = nullptr;
- else
- node = (ExpectNode*)hash_table->get(&key);
+ if (!hash_table->get_count())
+ return nullptr;
- if ( node )
- init = false;
+ const sfip_t* srcIP = p->ptrs.ip_api.get_src();
+ const sfip_t* dstIP = p->ptrs.ip_api.get_dst();
+ uint16_t vlanId = (p->proto_bits & PROTO_BIT__VLAN) ? layer::get_vlan_layer(p)->vid() : 0;
+ uint32_t mplsId = (p->proto_bits & PROTO_BIT__MPLS) ? p->ptrs.mplsHdr.label : 0;
+ uint16_t addressSpaceId = p->pkth->address_space_id;
+ PktType type = p->type();
+ IpProtocol ip_proto = p->get_ip_proto_next();
- else
- {
- prune();
+ bool reversed_key = key.init(type, ip_proto, dstIP, p->ptrs.dp, srcIP, p->ptrs.sp,
+ vlanId, mplsId, addressSpaceId);
- node = (ExpectNode*)hash_table->get(&key);
+ uint16_t port1;
+ uint16_t port2;
- if ( !node )
+ /*
+ Lookup order:
+ 1. Full match.
+ 2. Unknown (zeroed) source port.
+ 3. Unknown (zeroed) destination port.
+ If the client/server addresses were reversed during key creation, the
+ source port will be in port_l.
+ */
+ // FIXIT-P X This should be optimized to only do full matches when full keys
+ // are present, likewise for partial keys.
+ ExpectNode* node = (ExpectNode*) hash_table->find(&key);
+ if (!node)
+ {
+ // FIXIT-M X This logic could fail if IPs were equal because the original key
+ // would always have been created with a 0 for src or dst port and put the
+ // known port in port_h.
+ if (reversed_key)
{
- ++overflows;
- return nullptr;
+ port1 = key.port_l;
+ port2 = 0;
+ key.port_l = 0;
}
- else if ( !free_list )
+ else
{
- assert(false);
- ++overflows;
- return nullptr;
+ port1 = 0;
+ port2 = key.port_h;
+ key.port_h = 0;
+ }
+ node = (ExpectNode*) hash_table->find(&key);
+ if (!node)
+ {
+ key.port_l = port1;
+ key.port_h = port2;
+ node = (ExpectNode*) hash_table->find(&key);
+ if (!node)
+ return nullptr;
}
}
- return node;
-}
-
-inline ExpectFlow* ExpectCache::get_flow(ExpectNode* node, unsigned flow_id, int16_t appId)
-{
- if ( packet_time() > node->expires )
+ if (!node->head || (p->pkth->ts.tv_sec > node->expires))
{
- node->clear(free_list);
- node->appId = appId;
- ++prunes;
+ hash_table->remove(&key);
+ return nullptr;
}
- else if ( node->appId != appId )
+ /* Make sure the packet direction is correct */
+ switch (node->direction)
{
- if ( node->appId && appId )
- // reject changing known appId
- return nullptr;
+ case SSN_DIR_BOTH:
+ break;
- // allow changing unknown appId
- node->appId = appId;
+ case SSN_DIR_FROM_CLIENT:
+ case SSN_DIR_FROM_SERVER:
+ if (node->reversed_key != reversed_key)
+ return nullptr;
+ break;
}
- ExpectFlow* last = node->tail;
-
- if ( !last )
- return nullptr;
-
- FlowData* fd = last->data;
-
- while ( fd )
- {
- if ( fd->get_id() == flow_id )
- return nullptr;
- fd = fd->next;
- }
- return last;
+ return node;
}
-inline bool ExpectCache::set_data(ExpectNode* node, ExpectFlow*& last, FlowData* fd)
+bool ExpectCache::process_expected(ExpectNode* node, FlowKey& key, Packet* p, Flow* lws)
{
- if ( !last )
- {
- if ( node->count >= MAX_LIST )
- {
- // fail when maxed out
- ++overflows;
- return false;
- }
- last = free_list;
- free_list = free_list->next;
+ ExpectFlow* head;
+ FlowData* fd;
+ int ignoring = false;
- if ( !node->tail )
- node->head = last;
- else
- node->tail->next = last;
+ assert(node->count && node->head);
- node->tail = last;
- last->next = nullptr;
+ /* Pull the first set of expected flow data off of the Expect node and apply it
+ in its entirety to the target flow. Discard the set (and potentially the
+ entire node, it empty) after this is done. */
+ node->count--;
+ head = node->head;
+ node->head = head->next;
- node->count++;
- }
- if (last->data)
+ while ((fd = head->data))
{
- FlowData* prev_fd;
- for (prev_fd = last->data; prev_fd && prev_fd->next; prev_fd = prev_fd->next);
- prev_fd->next = fd;
+ head->data = fd->next;
+ lws->set_flow_data(fd);
+ ++realized;
+ fd->handle_expected(p);
}
- else
- last->data = fd;
+ head->next = free_list;
+ free_list = head;
+
+ /* If this is 0, we're ignoring, otherwise setting id of new session */
+ if (!node->appId)
+ ignoring = node->direction ? true : false;
+ else if (lws->ssn_state.application_protocol != node->appId)
+ lws->ssn_state.application_protocol = node->appId;
+
+ if (!node->count)
+ hash_table->remove(&key);
- return true;
+ return ignoring;
}
//-------------------------------------------------------------------------
// public ExpectCache methods
//-------------------------------------------------------------------------
-ExpectCache::ExpectCache (uint32_t max)
+ExpectCache::ExpectCache(uint32_t max)
{
// -size forces use of abs(size) ie w/o bumping up
- hash_table = new ZHash(-MAX_HASH, sizeof(ExpectKey));
+ hash_table = new ZHash(-MAX_HASH, sizeof(FlowKey));
+ hash_table->set_keyops(FlowKey::hash, FlowKey::compare);
nodes = new ExpectNode[max];
-
- for ( unsigned i = 0; i < max; ++i )
+ for (unsigned i = 0; i < max; ++i)
hash_table->push(nodes+i);
+ /* Preallocate a pool of ExpectFlows big enough to handle the worst case
+ requirement (max number of nodes * max flows per node) and add them all
+ to an initial free list. */
max *= MAX_LIST;
-
pool = new ExpectFlow[max];
free_list = nullptr;
-
- for ( unsigned i = 0; i < max; ++i )
+ for (unsigned i = 0; i < max; ++i)
{
ExpectFlow* p = pool + i;
p->data = nullptr;
p->next = free_list;
free_list = p;
}
- memset(&zeroed, 0, sizeof(zeroed));
expects = realized = 0;
prunes = overflows = 0;
}
-ExpectCache::~ExpectCache ()
+ExpectCache::~ExpectCache()
{
delete hash_table;
delete[] nodes;
* existing appId, new appId and associated data is not stored.
*
*/
-int ExpectCache::add_flow(
- const sfip_t *cliIP, uint16_t cliPort,
- const sfip_t *srvIP, uint16_t srvPort,
- PktType protocol, char direction,
- FlowData* fd, int16_t appId)
+int ExpectCache::add_flow(const Packet *ctrlPkt,
+ PktType type, IpProtocol ip_proto,
+ const sfip_t* cliIP, uint16_t cliPort,
+ const sfip_t* srvIP, uint16_t srvPort,
+ char direction, FlowData* fd, int16_t appId)
{
- // FIXIT-L sip inspector knows both ports
- //assert(!cliPort || !srvPort);
+ /* Just pull the VLAN ID, MPLS ID, and Address Space ID from the
+ control packet until we have a use case for not doing so. */
+ uint16_t vlanId = (ctrlPkt->proto_bits & PROTO_BIT__VLAN) ? layer::get_vlan_layer(ctrlPkt)->vid() : 0;
+ uint32_t mplsId = (ctrlPkt->proto_bits & PROTO_BIT__MPLS) ? ctrlPkt->ptrs.mplsHdr.label : 0;
+ uint16_t addressSpaceId = ctrlPkt->pkth->address_space_id;
- ExpectKey hashKey;
- int reversed_key = hashKey.set(cliIP, cliPort, srvIP, srvPort, protocol);
+ FlowKey key;
+ bool reversed_key = key.init(type, ip_proto, cliIP, cliPort, srvIP, srvPort,
+ vlanId, mplsId, addressSpaceId);
- bool init = true;
- ExpectNode* node = get_node(hashKey, init);
+ ExpectNode* node;
+ ExpectFlow* last;
+ bool new_node = false;
- if ( !node )
- return -1;
+ node = (ExpectNode*) hash_table->get(&key, &new_node);
+ if (!node)
+ {
+ prune();
+ node = (ExpectNode*) hash_table->get(&key, &new_node);
+ /* The flow free list should never be empty if there was a node
+ to be (re-)used unless we managed to leak some. Check just
+ in case. Maybe assert instead? */
+ if (!node || !free_list)
+ {
+ ++overflows;
+ return -1;
+ }
+ }
- ExpectFlow* last;
+ /* If the node is past its expiration date, whack it and reuse it. */
+ if (!new_node && packet_time() > node->expires)
+ {
+ node->clear(free_list);
+ new_node = true;
+ }
- if ( !init )
- last = get_flow(node, fd->get_id(), appId);
+ if (!new_node)
+ {
+ /* Requests will be rejected if the AppID doesn't match what has already been set. */
+ if (node->appId != appId)
+ {
+ if (node->appId && appId)
+ return -1;
+ node->appId = appId;
+ }
+ last = node->tail;
+ if (last)
+ {
+ FlowData* lfd = last->data;
+
+ while (lfd)
+ {
+ if (lfd->get_id() == fd->get_id())
+ {
+ last = nullptr;
+ break;
+ }
+ fd = fd->next;
+ }
+ }
+ }
else
{
node->appId = appId;
node->head = node->tail = nullptr;
node->count = 0;
last = nullptr;
+ /* Only add TCP and UDP expected flows for now via the DAQ module. */
+ if (ip_proto == IpProtocol::TCP || ip_proto == IpProtocol::UDP)
+ SFDAQ::get_local_instance()->add_expected(ctrlPkt, cliIP, cliPort, srvIP, srvPort,
+ ip_proto, 1000, 0);
}
- if ( !set_data(node, last, fd) )
- return -1;
-
- node->expires = packet_time() + MAX_WAIT;
- ++expects;
-
- return 0;
-}
-
-bool ExpectCache::is_expected(Packet* p)
-{
- if ( !hash_table->get_count() )
- return false;
- const sfip_t* srcIP = p->ptrs.ip_api.get_src();
- const sfip_t* dstIP = p->ptrs.ip_api.get_dst();
-
- ExpectKey key;
- bool reversed_key = key.set(dstIP, p->ptrs.dp, srcIP, p->ptrs.sp, p->type());
-
- uint16_t port1;
- uint16_t port2;
-
- if ( reversed_key )
- {
- key.port2 = 0;
- port1 = 0;
- port2 = p->ptrs.sp;
- }
- else
+ if (!last)
{
- key.port1 = 0;
- port1 = p->ptrs.sp;
- port2 = 0;
- }
-
- ExpectNode* node = (ExpectNode*)hash_table->find(&key);
+ if (node->count >= MAX_LIST)
+ {
+ // fail when maxed out
+ ++overflows;
+ return -1;
+ }
+ last = free_list;
+ free_list = free_list->next;
- if ( !node )
- {
- // can't find with dp, so try sp ...
- key.port1 = port1;
- key.port2 = port2;
+ if (!node->tail)
+ node->head = last;
+ else
+ node->tail->next = last;
- node = (ExpectNode*)hash_table->find(&key);
+ node->tail = last;
+ last->next = nullptr;
- if ( !node )
- return false;
- }
- // FIXIT-M X This should also include a lookup in the table for entries where both
- // src and dst ports are known.
- if ( !node->head || (p->pkth->ts.tv_sec > node->expires) )
- {
- hash_table->remove();
- return false;
+ node->count++;
}
- /* Make sure the packet direction is correct */
- switch (node->direction)
+ if (last->data)
{
- case SSN_DIR_BOTH:
- break;
-
- case SSN_DIR_FROM_CLIENT:
- case SSN_DIR_FROM_SERVER:
- if (node->reversed_key != reversed_key)
- return false;
- break;
+ FlowData* prev_fd;
+ for (prev_fd = last->data; prev_fd && prev_fd->next; prev_fd = prev_fd->next);
+ prev_fd->next = fd;
}
+ else
+ last->data = fd;
+
+ node->expires = packet_time() + MAX_WAIT;
+ ++expects;
- return true;
+ return 0;
}
-char ExpectCache::process_expected(Packet* p, Flow* lws)
+bool ExpectCache::is_expected(Packet* p)
{
- int retVal = SSN_DIR_NONE;
-
- ExpectNode* node = (ExpectNode*)hash_table->current();
-
- if ( !node )
- return retVal;
-
- assert(node->count && node->head);
-
- node->count--;
- ExpectFlow* head = node->head;
- node->head = head->next;
-
- FlowData* fd;
-
- while ((fd = head->data))
- {
- head->data = fd->next;
- lws->set_flow_data(fd);
- ++realized;
- fd->handle_expected(p);
- }
- head->next = free_list;
- free_list = head;
-
- /* If this is 0, we're ignoring, otherwise setting id of new session */
- if ( !node->appId )
- retVal = node->direction;
-
- else if ( lws->ssn_state.application_protocol != node->appId )
- {
- lws->ssn_state.application_protocol = node->appId;
- }
-
- if ( !node->count )
- hash_table->remove();
-
- return retVal;
+ FlowKey key;
+ return (find_node_by_packet(p, key) != nullptr);
}
-char ExpectCache::check(Packet* p, Flow* lws)
+bool ExpectCache::check(Packet* p, Flow* lws)
{
- if ( !is_expected(p) )
- return SSN_DIR_NONE;
+ FlowKey key;
+ ExpectNode* node = find_node_by_packet(p, key);
+
+ if (!node)
+ return false;
- return process_expected(p, lws);
+ return process_expected(node, key, p, lws);
}
#include "flow/flow.h"
struct Packet;
+struct ExpectFlow;
+struct ExpectNode;
class ExpectCache
{
ExpectCache(uint32_t max);
~ExpectCache();
- int add_flow(
- const sfip_t *cliIP, uint16_t cliPort,
- const sfip_t *srvIP, uint16_t srvPort,
- PktType, char direction, FlowData*, int16_t appId = 0);
+ int add_flow(const Packet *ctrlPkt, PktType, IpProtocol,
+ const sfip_t* cliIP, uint16_t cliPort,
+ const sfip_t* srvIP, uint16_t srvPort,
+ char direction, FlowData*, int16_t appId = 0);
bool is_expected(Packet*);
- char process_expected(Packet*, Flow*);
- char check(Packet*, Flow*);
+ bool check(Packet*, Flow*);
unsigned long get_expects() { return expects; }
unsigned long get_realized() { return realized; }
private:
void prune();
- struct ExpectNode* get_node(struct ExpectKey&, bool&);
- struct ExpectFlow* get_flow(ExpectNode*, uint32_t, int16_t);
+ ExpectNode* get_node(FlowKey&, bool&);
+ ExpectFlow* get_flow(ExpectNode*, uint32_t, int16_t);
bool set_data(ExpectNode*, ExpectFlow*&, FlowData*);
+ ExpectNode* find_node_by_packet(Packet*, FlowKey&);
+ bool process_expected(ExpectNode*, FlowKey&, Packet*, Flow*);
private:
class ZHash* hash_table;
- struct ExpectNode* nodes;
- struct ExpectFlow* pool, * free_list;
- sfip_t zeroed;
+ ExpectNode* nodes;
+ ExpectFlow* pool, * free_list;
unsigned long expects, realized;
unsigned long prunes, overflows;
exp_cache = new ExpectCache(max);
}
-char FlowControl::expected_flow(Flow* flow, Packet* p)
+bool FlowControl::expected_flow(Flow* flow, Packet* p)
{
- char ignore = exp_cache->check(p, flow);
+ bool ignore = exp_cache->check(p, flow);
if ( ignore )
{
}
int FlowControl::add_expected(
+ const Packet* ctrlPkt, PktType type, IpProtocol ip_proto,
const sfip_t *srcIP, uint16_t srcPort,
const sfip_t *dstIP, uint16_t dstPort,
- PktType type, char direction,
- FlowData* fd)
+ char direction, FlowData* fd)
{
return exp_cache->add_flow(
- srcIP, srcPort, dstIP, dstPort, type, direction, fd);
+ ctrlPkt, type, ip_proto, srcIP, srcPort, dstIP, dstPort,
+ direction, fd);
}
int FlowControl::add_expected(
+ const Packet* ctrlPkt, PktType type, IpProtocol ip_proto,
const sfip_t *srcIP, uint16_t srcPort,
const sfip_t *dstIP, uint16_t dstPort,
- PktType type, int16_t appId, FlowData* fd)
+ int16_t appId, FlowData* fd)
{
return exp_cache->add_flow(
- srcIP, srcPort, dstIP, dstPort, type, SSN_DIR_BOTH, fd, appId);
+ ctrlPkt, type, ip_proto, srcIP, srcPort, dstIP, dstPort,
+ SSN_DIR_BOTH, fd, appId);
}
bool FlowControl::is_expected(Packet* p)
void timeout_flows(time_t cur_time);
- char expected_flow(Flow*, Packet*);
+ bool expected_flow(Flow*, Packet*);
bool is_expected(Packet*);
int add_expected(
+ const Packet* ctrlPkt, PktType, IpProtocol,
const sfip_t *srcIP, uint16_t srcPort,
const sfip_t *dstIP, uint16_t dstPort,
- PktType, char direction, FlowData*);
+ char direction, FlowData*);
int add_expected(
+ const Packet* ctrlPkt, PktType, IpProtocol,
const sfip_t *srcIP, uint16_t srcPort,
const sfip_t *dstIP, uint16_t dstPort,
- PktType, int16_t appId, FlowData*);
+ int16_t appId, FlowData*);
PegCount get_flows(PktType);
PegCount get_total_prunes(PktType) const;
// init foo
//-------------------------------------------------------------------------
-inline void FlowKey::init4(
+inline bool FlowKey::init4(
IpProtocol ip_proto,
const sfip_t *srcIP, uint16_t srcPort,
const sfip_t *dstIP, uint16_t dstPort,
{
const uint32_t* src;
const uint32_t* dst;
+ bool reversed = false;
if ( ip_proto == IpProtocol::ICMPV4 )
{
{
port_l = dstPort;
port_h = srcPort;
+ reversed = true;
}
}
else
port_l = dstPort;
COPY4(ip_h, src);
port_h = srcPort;
+ reversed = true;
}
if (SnortConfig::mpls_overlapping_ip() &&
ip::isPrivateIP(*src) && ip::isPrivateIP(*dst))
mplsLabel = mplsId;
else
mplsLabel = 0;
+
+ return reversed;
}
-inline void FlowKey::init6(
+inline bool FlowKey::init6(
IpProtocol ip_proto,
const sfip_t *srcIP, uint16_t srcPort,
const sfip_t *dstIP, uint16_t dstPort,
{
const sfip_t* src;
const sfip_t* dst;
+ bool reversed = false;
if ( ip_proto == IpProtocol::ICMPV4 )
{
{
port_l = dstPort;
port_h = srcPort;
+ reversed = true;
}
}
else
port_l = dstPort;
COPY4(ip_h, src->ip32);
port_h = srcPort;
+ reversed = true;
}
if (SnortConfig::mpls_overlapping_ip())
mplsLabel = mplsId;
else
mplsLabel = 0;
+
+ return reversed;
}
void FlowKey::init_vlan(uint16_t vlanId)
mplsLabel = 0;
}
-void FlowKey::init(
+bool FlowKey::init(
PktType type, IpProtocol ip_proto,
const sfip_t *srcIP, uint16_t srcPort,
const sfip_t *dstIP, uint16_t dstPort,
uint16_t vlanId, uint32_t mplsId, uint16_t addrSpaceId)
{
+ bool reversed;
+
/* Because the key is going to be used for hash lookups,
- * the lower of the values of the IP address field is
- * stored in the ip_l and the port for that ip is
- * stored in port_l.
+ * the key fields will be normalized such that the lower
+ * of the IP addresses is stored in ip_l and the port for
+ * that IP is stored in port_l.
*/
if (srcIP->is_ip4())
{
version = 4;
- init4(ip_proto, srcIP, srcPort, dstIP, dstPort, mplsId);
+ reversed = init4(ip_proto, srcIP, srcPort, dstIP, dstPort, mplsId);
}
else
{
version = 6;
- init6(ip_proto, srcIP, srcPort, dstIP, dstPort, mplsId);
+ reversed = init6(ip_proto, srcIP, srcPort, dstIP, dstPort, mplsId);
}
pkt_type = type;
init_vlan(vlanId);
init_address_space(addrSpaceId);
+
+ return reversed;
}
-void FlowKey::init(
+bool FlowKey::init(
PktType type, IpProtocol ip_proto,
const sfip_t *srcIP, const sfip_t *dstIP,
uint32_t id, uint16_t vlanId,
init_vlan(vlanId);
init_address_space(addrSpaceId);
+
+ return false;
}
//-------------------------------------------------------------------------
uint16_t addressSpaceId;
uint16_t addressSpaceIdPad1;
- void init(
+ /* The init() functions return true if the key IP/port fields were actively
+ normalized, reversing the source and destination addresses internally.
+ The IP-only init() will always return false as we will not reorder its
+ addresses at this time. */
+ bool init(
PktType, IpProtocol,
const sfip_t *srcIP, uint16_t srcPort,
const sfip_t *dstIP, uint16_t dstPort,
uint16_t vlanId, uint32_t mplsId, uint16_t addrSpaceId);
- void init(
+ bool init(
PktType, IpProtocol,
const sfip_t *srcIP, const sfip_t *dstIP,
uint32_t id, uint16_t vlanId,
static int compare(const void* s1, const void* s2, size_t);
private:
- void init4(
+ bool init4(
IpProtocol,
const sfip_t *srcIP, uint16_t srcPort,
const sfip_t *dstIP, uint16_t dstPort,
uint32_t mplsId, bool order = true);
- void init6(
+ bool init6(
IpProtocol,
const sfip_t *srcIP, uint16_t srcPort,
const sfip_t *dstIP, uint16_t dstPort,
return pv;
}
-void* ZHash::get(const void* key)
+void* ZHash::get(const void* key, bool *new_node)
{
int index = 0;
ZHashNode* node = find_node_row(key, &index);
count++;
+ if (new_node)
+ *new_node = true;
+
return node->data;
}
bool touch();
void* find(const void* key);
- void* get(const void* key);
+ void* get(const void* key, bool *new_node = nullptr);
bool remove(const void* key);
bool remove();
delete_shared_data();
}
-AppIdSession* AppIdSession::create_future_session(const Packet* /*ctrlPkt*/, const sfip_t* cliIp, uint16_t cliPort,
+// FIXIT-L X Move this to somewhere more generally available/appropriate.
+static inline PktType get_pkt_type_from_ip_proto(IpProtocol proto)
+{
+ switch (proto)
+ {
+ case IpProtocol::TCP:
+ return PktType::TCP;
+ case IpProtocol::UDP:
+ return PktType::UDP;
+ case IpProtocol::ICMPV4:
+ return PktType::ICMP;
+ case IpProtocol::IP:
+ return PktType::IP;
+ default:
+ break;
+ }
+ return PktType::NONE;
+}
+
+AppIdSession* AppIdSession::create_future_session(const Packet* ctrlPkt, const sfip_t* cliIp, uint16_t cliPort,
const sfip_t* srvIp, uint16_t srvPort, IpProtocol proto, int16_t app_id, int /*flags*/)
{
char src_ip[INET6_ADDRSTRLEN];
char dst_ip[INET6_ADDRSTRLEN];
- // FIXIT - not needed until crtlPkt expectedSession is supported
+ // FIXIT - not needed until ctrlPkt expectedSession is supported
//struct _ExpectNode** node;
- enum PktType protocol = ( enum PktType ) proto;
+ enum PktType type = get_pkt_type_from_ip_proto(proto);
+
+ assert(type != PktType::NONE);
if (app_id_debug_session_flag)
{
// FIXIT - 2.9.x set_application_protocol_id_expected has several new parameters, need to look
// into what is required to support those here.
- if ( Stream::set_application_protocol_id_expected(
- /*crtlPkt,*/ cliIp, cliPort, srvIp, srvPort, protocol, app_id, session) )
+ if ( Stream::set_application_protocol_id_expected(ctrlPkt, type, proto, cliIp, cliPort, srvIp, srvPort,
+ app_id, session) )
{
if (app_id_debug_session_flag)
LogMessage("AppIdDbg %s failed to create a related flow for %s-%u -> %s-%u %u\n",
#include "sfdaq_config.h"
#include "main/snort_config.h"
#include "parser/parser.h"
+#include "protocols/vlan.h"
#include "utils/util.h"
using namespace std;
{
DAQ_ModFlow_t mod;
-#ifdef DAQ_MODFLOW_TYPE_OPAQUE
mod.type = DAQ_MODFLOW_TYPE_OPAQUE;
mod.length = sizeof(opaque);
mod.value = &opaque;
-#else
- mod.opaque = opaque;
-#endif
return daq_modify_flow(daq_mod, daq_hand, hdr, &mod);
}
+
+// FIXIT-L X Add Snort flag defitions for callers to use and translate/pass them through to the DAQ module
+int SFDAQInstance::add_expected(const Packet* ctrlPkt, const sfip_t* cliIP, uint16_t cliPort,
+ const sfip_t* srvIP, uint16_t srvPort, IpProtocol protocol, unsigned timeout_ms, unsigned /* flags */)
+{
+ DAQ_Data_Channel_Params_t daq_params;
+ DAQ_DP_key_t dp_key;
+
+ dp_key.src_af = cliIP->family;
+ if (cliIP->is_ip4())
+ dp_key.sa.src_ip4.s_addr = *cliIP->ip32;
+ else
+ memcpy(&dp_key.sa.src_ip6, cliIP->ip8, sizeof(dp_key.sa.src_ip6));
+ dp_key.src_port = cliPort;
+
+ dp_key.dst_af = srvIP->family;
+ if (srvIP->is_ip4())
+ dp_key.da.dst_ip4.s_addr = *srvIP->ip32;
+ else
+ memcpy(&dp_key.da.dst_ip6, srvIP->ip8, sizeof(dp_key.da.dst_ip6));
+ dp_key.dst_port = srvPort;
+
+ dp_key.protocol = (uint8_t) protocol;
+ dp_key.vlan_cnots = 1;
+ if (ctrlPkt->proto_bits & PROTO_BIT__VLAN)
+ dp_key.vlan_id = layer::get_vlan_layer(ctrlPkt)->vid();
+ else
+ dp_key.vlan_id = 0xFFFF;
+
+ if (ctrlPkt->proto_bits & PROTO_BIT__GTP)
+ dp_key.tunnel_type = DAQ_DP_TUNNEL_TYPE_GTP_TUNNEL;
+ else if (ctrlPkt->proto_bits & PROTO_BIT__MPLS)
+ dp_key.tunnel_type = DAQ_DP_TUNNEL_TYPE_MPLS_TUNNEL;
+/*
+ else if ( ctrlPkt->encapsulated )
+ dp_key.tunnel_type = DAQ_DP_TUNNEL_TYPE_OTHER_TUNNEL;
+*/
+ else
+ dp_key.tunnel_type = DAQ_DP_TUNNEL_TYPE_NON_TUNNEL;
+
+ memset(&daq_params, 0, sizeof(daq_params));
+ daq_params.timeout_ms = timeout_ms;
+/*
+ if (flags & DAQ_DC_FLOAT)
+ daq_params.flags |= DAQ_DATA_CHANNEL_FLOAT;
+ if (flags & DAQ_DC_ALLOW_MULTIPLE)
+ daq_params.flags |= DAQ_DATA_CHANNEL_ALLOW_MULTIPLE;
+ if (flags & DAQ_DC_PERSIST)
+ daq_params.flags |= DAQ_DATA_CHANNEL_PERSIST;
+*/
+
+ return daq_dp_add_dc(daq_mod, daq_hand, ctrlPkt->pkth, &dp_key, NULL, &daq_params);
+}
#include <string>
#include "main/snort_types.h"
+#include "protocols/protocol_ids.h"
+struct Packet;
struct SnortConfig;
+struct sfip_t;
class SFDAQInstance
{
bool break_loop(int error);
const DAQ_Stats_t* get_stats();
int modify_flow_opaque(const DAQ_PktHdr_t*, uint32_t opaque);
+ int add_expected(const Packet* ctrlPkt, const sfip_t* cliIP, uint16_t cliPort,
+ const sfip_t* srvIP, uint16_t srvPort, IpProtocol, unsigned timeout_ms,
+ unsigned /* flags */);
private:
bool set_filter(const char*);
std::string interface_spec;
FTPCmd->file_put_cmd = 1;
if ( fc->flags & CMD_GET )
- FTPCmd->data_xfer_cmd = 1;
+ FTPCmd->file_get_cmd = 1;
if ( fc->flags & CMD_CHECK )
{
#define s_help \
"FTP data channel handler"
+static const char* const fd_svc_name = "ftp-data";
+
static THREAD_LOCAL ProfileStats ftpdataPerfStats;
static THREAD_LOCAL SimpleStats fdstats;
return -1;
FtpDataFlowData* fd = (FtpDataFlowData*)
- p->flow->get_flow_data(FtpFlowData::flow_id);
+ p->flow->get_flow_data(FtpDataFlowData::flow_id);
FTP_DATA_SESSION* data_ssn = fd ? &fd->session : nullptr;
session.ft_ssn.proto = FTPP_SI_PROTO_FTP_DATA;
Stream::populate_flow_key(p, &session.ftp_key);
+ if (p->flow)
+ session.ftp_key.pkt_type = p->flow->pkt_type;
}
FtpDataFlowData::~FtpDataFlowData()
snort_free(session.filename);
}
+void FtpDataFlowData::handle_expected(Packet* p)
+{
+ // FIXIT-M X This is an ugly, ugly hack, but it's the way Wizard is doing it
+ if (!p->flow->service)
+ p->flow->service = fd_svc_name;
+}
+
void FtpDataFlowData::handle_eof(Packet* p)
{
FTP_DATA_SESSION* data_ssn = &session;
IT_SERVICE,
(uint16_t)PktType::PDU,
nullptr, // buffers
- "ftp-data",
+ fd_svc_name,
fd_init,
nullptr, // pterm
nullptr, // tinit
static void init()
{ flow_id = FlowData::get_flow_id(); }
+ void handle_expected(Packet*) override;
void handle_eof(Packet*) override;
public:
* Returns: int => return code indicating error or success
*
*/
+// FIXIT-M X Expected flow operations are using hardcoded TCP PktType/IpProtocol,
+// which could that bite us on the mythical FTP over UDP or SCTP?
static int do_stateful_checks(FTP_SESSION* session, Packet* p,
FTP_CLIENT_REQ* req, int rsp_code)
{
/* Call into Streams to mark data channel as ftp-data */
result = Stream::set_application_protocol_id_expected(
+ p, PktType::TCP, IpProtocol::TCP,
&session->clientIP, session->clientPort,
&session->serverIP, session->serverPort,
- p->type(), ftp_data_app_id, fd);
+ ftp_data_app_id, fd);
if (result < 0)
delete fd;
/* Call into Streams to mark data channel as something
* to ignore. */
Stream::ignore_flow(
+ p, PktType::TCP, IpProtocol::TCP,
&session->clientIP, session->clientPort,
&session->serverIP, session->serverPort,
- p->type(), SSN_DIR_BOTH,
- FtpDataFlowData::flow_id);
+ SSN_DIR_BOTH, FtpDataFlowData::flow_id);
}
}
}
/* Call into Streams to mark data channel as ftp-data */
result = Stream::set_application_protocol_id_expected(
+ p, PktType::TCP, IpProtocol::TCP,
&session->clientIP, session->clientPort,
&session->serverIP, session->serverPort,
- p->type(), ftp_data_app_id, fd);
+ ftp_data_app_id, fd);
if (result < 0)
delete fd;
/* Call into Streams to mark data channel as something
* to ignore. */
Stream::ignore_flow(
+ p, PktType::TCP, IpProtocol::TCP,
&session->clientIP, session->clientPort,
&session->serverIP, session->serverPort,
- p->type(), SSN_DIR_BOTH,
- FtpDataFlowData::flow_id);
+ SSN_DIR_BOTH, FtpDataFlowData::flow_id);
}
}
}
#include <assert.h>
#include "framework/data_bus.h"
-#include "main/snort_types.h"
-#include "main/snort_debug.h"
#include "main/snort_config.h"
-#include "stream/stream.h"
+#include "main/snort_debug.h"
+#include "main/snort_types.h"
+#include "protocols/vlan.h"
#include "sfip/sf_ip.h"
+#include "stream/stream.h"
#include "sip_module.h"
#include "sip.h"
sfip_to_str(&mdataB->maddress), mdataB->mport);
/* Call into Streams to mark data channel as something to ignore. */
- FlowData* fd = Stream::get_flow_data(
- PktType::UDP, IpProtocol::UDP, &mdataA->maddress,mdataA->mport,
- &mdataB->maddress, mdataB->mport, 0, 0, p->pkth->address_space_id,
- SipFlowData::flow_id);
- if ( fd )
+ Flow* ssn = Stream::get_flow(
+ PktType::UDP, IpProtocol::UDP, &mdataA->maddress,
+ mdataA->mport, &mdataB->maddress, mdataB->mport,
+ (p->proto_bits & PROTO_BIT__VLAN) ? layer::get_vlan_layer(p)->vid() : 0,
+ (p->proto_bits & PROTO_BIT__MPLS) ? p->ptrs.mplsHdr.label : 0,
+ p->pkth->address_space_id);
+ if (ssn)
{
- p->flow->set_ignore_direction(SSN_DIR_BOTH);
+ ssn->set_ignore_direction(SSN_DIR_BOTH);
}
else
{
- Stream::ignore_flow(&mdataA->maddress, mdataA->mport, &mdataB->maddress,
- mdataB->mport, p->type(), SSN_DIR_BOTH, SipFlowData::flow_id);
+ Stream::ignore_flow(p, p->flow->pkt_type, p->get_ip_proto_next(), &mdataA->maddress,
+ mdataA->mport, &mdataB->maddress, mdataB->mport, SSN_DIR_BOTH, SipFlowData::flow_id);
}
sip_stats.ignoreChannels++;
mdataA = mdataA->nextM;
const FlowKey* key, unsigned flow_id)
{
Flow* flow = get_flow(key);
+ if (!flow)
+ return nullptr;
return flow->get_flow_data(flow_id);
}
vlan, mplsId, addressSpaceID);
if (!flow)
- return NULL;
+ return nullptr;
return flow->get_flow_data(flow_id);
}
}
int Stream::ignore_flow(
+ const Packet* ctrlPkt, PktType type, IpProtocol ip_proto,
const sfip_t* srcIP, uint16_t srcPort,
const sfip_t* dstIP, uint16_t dstPort,
- PktType protocol, char direction,
- uint32_t flow_id)
+ char direction, uint32_t flow_id)
{
assert(flow_con);
FlowData* fd = new FlowData(flow_id);
- return flow_con->add_expected(srcIP, srcPort, dstIP, dstPort, protocol, direction, fd);
+
+ return flow_con->add_expected(
+ ctrlPkt, type, ip_proto, srcIP, srcPort, dstIP, dstPort, direction, fd);
}
void Stream::proxy_started(Flow* flow, unsigned dir)
//-------------------------------------------------------------------------
int Stream::set_application_protocol_id_expected(
+ const Packet* ctrlPkt, PktType type, IpProtocol ip_proto,
const sfip_t* srcIP, uint16_t srcPort,
- const sfip_t* dstIP, uint16_t dstPort,
- PktType protocol, int16_t appId, FlowData* fd)
+ const sfip_t* dstIP, uint16_t dstPort,
+ int16_t appId, FlowData* fd)
{
assert(flow_con);
return flow_con->add_expected(
- srcIP, srcPort, dstIP, dstPort, protocol, appId, fd);
+ ctrlPkt, type, ip_proto, srcIP, srcPort, dstIP, dstPort, appId, fd);
}
void Stream::set_application_protocol_id(
// n-tuple parameters specified. Inspection will be turned off for this expected session
// when it arrives.
static int ignore_flow(
- const sfip_t *addr1, uint16_t p1, const sfip_t *addr2, uint16_t p2,
- PktType, char dir, uint32_t ppId);
+ const Packet* ctrlPkt, PktType, IpProtocol, const sfip_t* srcIP, uint16_t srcPort,
+ const sfip_t* dstIP, uint16_t dstPort, char direction, uint32_t flow_id);
// Resume inspection for flow.
// FIXIT-L does resume work only for a flow that has been stopped by call to stop_inspection?
// Turn off inspection for potential session. Adds session identifiers to a hash table.
// TCP only.
static int set_application_protocol_id_expected(
- const sfip_t *a1, uint16_t p1, const sfip_t *a2, uint16_t p2, PktType,
- int16_t appId, FlowData*);
+ const Packet* ctrlPkt, PktType, IpProtocol, const sfip_t* srcIP, uint16_t srcPort,
+ const sfip_t* dstIP, uint16_t dstPort, int16_t appId, FlowData*);
// Get pointer to application data for a flow based on the lookup tuples for cases where
// Snort does not have an active packet that is relevant.
void TcpSession::check_for_session_hijack(TcpSegmentDescriptor& tsd)
{
-#ifdef DAQ_PKT_FLAG_PRE_ROUTING
if (!(tsd.get_pkt()->pkth->flags & DAQ_PKT_FLAG_PRE_ROUTING))
-#endif
{
uint32_t event_code = 0;
// FIXIT-L expected flow should be checked by Stream before we get here
// harmonize this with that and the checks above
-
if ( Stream::expected_flow(flow, p) )
{
server->flush_policy = STREAM_FLPOLICY_IGNORE;