Using create_expire and expire_func

Dear Bro Team,

I have a global table that i populate at the time of initialization (bro_init). I want to empty it every x minutes to fill it up with fresh values. This means that i also need to be notified when the table is being emptied. It seems to me that the attributes &create_expire and &expire_func will be helpful for my requirements. I wrote a quick script to check if the behavior matches my expectation. However, it doesn’t seems to work as expected. Here is my script:

in try.bro:

    print s;

    sleep(15);

    #s should be empty
    print s;
}
----------------------------------------------------------------------------
in bro.bif
-----------------------------------------------------------------------------
function sleep%(time_secs: count%): any
    %{
    usleep(time_secs * 1000000);
    return 0;
    %}

...

Why isn't 's' empty on second print?

Bro drives its evaluation of timers based on the clock advancing between
events. The above code sequence doesn't include any subsequent event after
bro_init(), so the expiration timers don't have a chance to run.

    Vern

Hi Sheharbano,

I inlined some notes:

in try.bro:
-----------------------------------------------------------------------------
function inform_me(s: set[string], idx: any): interval
{
    print "expired";
    return 5secs;
}

The return value of an &expire_func indicates the amount of additional time to wait before expiring the element. So always returning "5secs" will never expire the element. Return "0secs" if you want the element removed automatically, or you could even "delete s[idx]" yourself.

global s: set[string] &create_expire=5secs &expire_func=inform_me;

event bro_init()
{

    add s["i"];
    add s["am"];
    add s["here"];

    #s should have i,am,here
    print s;

    sleep(15);

    #s should be empty
    print s;
}
----------------------------------------------------------------------------
in bro.bif
-----------------------------------------------------------------------------
function sleep%(time_secs: count%): any
    %{
    usleep(time_secs * 1000000);
    return 0;
    %}

The sleep BIF you added doesn't look like it's enough to trigger the internal timers that Bro would use for table expiration, or at least I couldn't find a way, but reading input from a pcap file that captured traffic for longer than your expiration interval could allow you to test it. You could handle the "new_connection" event and check the contents of your global table there.

I did find a bug for the case when reading input live from an interface that would prevent expiry of table values set in bro_init(), for which I committed a fix in the git fastpath branch. Also in fastpath, I made a test script you could refer to: testing/btest/language/expire_func.test.

+Jon