how to get the oldest entry out of table

You can implement a FIFO of type "foo" using "table[count] of foo" and
explicitly tracking its first and last element in order to pull from the
front and push onto the back.

With this idiom, you can track connection failures like you sketch using
something like the appended. What I've implemented counts multiple failures
to the same host; I think you instead want multiple failures regardless
of whether they're to the same host or different, but I wasn't quite sure
since you traced destination IP in your failed_attempts variable. Hopefully
it's clear how to modify this for the different functionality - let me
know if not.

Also, while I implemented a FIFO that tracks <src, dst, time>, for
your example use all that's actually needed is a count. That would
be much simpler, just have a table[addr] of count indexed per source,
bump it up on each connection_attempt event and set a timer to decrement
it a minute later.


type pair: record { src: addr; dst: addr; };
type failure: record { p: pair; t: time; };

global conn_failures: table[count, pair] of failure;
global first_conn_failure: table[pair] of count;
global last_conn_failure: table[pair] of count;

global failure_thresh = 100 &redef;
global failure_interval = 1 min &redef;

event remove_conn_failure(p: pair)
  if ( pair !in first_conn_failure )
    # Shouldn't happen - could print an error and exit.

  # Pop from front.
  delete conn_failures[first_conn_failure[p], p];
  ++first_conn_failure[p]; # move past now vacated element

event connection_attempt(c: connection)
  local p = [$src = c$id$orig_h, $dst = c$id$resp_h];

  if ( p !in first_conn_failure )
    first_conn_failure[p] = 1;
    last_conn_failure[p] = 0; # about to increment

  local f = [$p = p, $t = c$start_time];
  # Append to end.
  conn_failures[++last_conn_failure[p], p] = f;

  if ( last_conn_failure[p] - first_conn_failure[p] > failure_thresh )
    alarm fmt("more than %d failed attempts of host %s in 1 minute",
      failure_thresh, f$p$src);

  schedule failure_interval { remove_conn_failure(p) };