Hi Risto

Thank you so much for such a comprehensive and informative reply!

I'm just getting started with SEC but can already imagine a number of very 
useful applications of it.

________________________________
From: Risto Vaarandi <risto.vaara...@gmail.com>
Sent: Friday, September 6, 2019 3:50 AM
To: David Thomas <dtho...@kwiktrip.com>
Cc: simple-evcorr-users@lists.sourceforge.net 
<simple-evcorr-users@lists.sourceforge.net>
Subject: Re: [Simple-evcorr-users] Help calling perl to get hostname


ATTENTION: This email originated from outside of Kwik Trip. Do not click links 
or open attachments unless you recognize the sender and know the content is 
safe.



hi David,

Kontakt David Thomas (<dtho...@kwiktrip.com<mailto:dtho...@kwiktrip.com>>) 
kirjutas kuupƤeval N, 5. september 2019 kell 21:37:
Hello Risto:

Last week you provided Clayton some advice on the rule below.  I am the 
customer he was asking about this for.  The rule is in place and working 
exactly as expected so thank you for your help.

I need to take another step  now.  When the value of %TT is greater than 14400 
and %+{tunnel} equal '241' I need to treat it differently.

Our original idea was to have a second rule that monitored the events written 
by action2 below and then run an additional tcpsock if the conditions above 
were true.  But as I'm learning how SEC works I'm wondering if it wouldn't be 
better to handle it all with just this one rule.  I could have pattern2 call a 
sub that would figure out if the conditions above held or not and write a 
different version of the tcpsock in that case.

Does that make sense, or would it be better to have the second separate rule.

You can actually use both approaches, and your choice would largely depend on 
wider context and future plans for expanding the ruleset. For example, if you 
plan to implement a number of additional rules in near future for processing 
"neighbor Up" events, I would recommend to create separate rules for all those 
cases (including the current one), in order to make your ruleset more readable 
and manageable. However, if the current special case will remain the only one, 
you can also address it within the Pair rule that you already have. Since 2.7.0 
version SEC supports the 'if' action which allows for conditional execution of 
action lists, and you can use it for addressing the special case for tunnel 241 
by modifying the 'action2' field of the current rule. For example, consider the 
following Pair rule which executes different actions for tunnel 241 with long 
downtime, and all other events:

type=Pair
ptype=PerlFunc
pattern=sub { my(%var); \
        if ($_[0] !~ /neighbor \*?(\d+\.\d+\.\d+\.\d+) Down/) { return 0; } \
        $var{"nip"} = $1; $var{"ts"} = time(); \
        $var{"hostname"} = scalar gethostbyaddr(Socket::inet_aton($var{"nip"}), 
Socket::AF_INET); \
        if (!defined($var{"hostname"})) { $var{"hostname"} = $var{"nip"} }; \
        $var{"storenumber"} = "NA"; $var{"tunnel"} = "NA"; \
        if ($var{"hostname"} =~ /(\d+)lo/) { $var{"storenumber"} = $1; } \
        if ($var{"hostname"} =~ /lo(\d+)/) { $var{"tunnel"} = $1; } \
        return \%var; }
desc=BGP Neighbor $+{nip} Down
action=tcpsock 10.3.0.85:514<http://10.3.0.85:514> LzEC BGP Neighbor 
status="Down" hostname="$+{hostname}" store="$+{storenumber}" 
tunnel="$+{tunnel}" ECRule="01-bgp-flap-detection" ECRulenum="1"%{.nl};
ptype2=RegExp
pattern2=neighbor \*?$+{nip} Up
desc2=BGP Neighbor %+{nip} Up
action2=lcall %TT %+{ts} -> ( sub { time() - $_[0] } ); \
        lcall %o %TT %+{tunnel} -> ( sub { $_[0] > 14400 && $_[1] eq "241" } ); 
\
        if %o ( write - Event for hostname %+{hostname} store %+{storenumber} 
tunnel 241 downtime %TT ) \
        else ( \
          tcpsock 10.3.0.85:514<http://10.3.0.85:514> LzEC BGP Neighbor 
status="Up" hostname="%+{hostname}" store="%+{storenumber}" tunnel="%+{tunnel}" 
downtime="%TT" ECRule="01-bgp-flap-detection" ECRulenum="2"%{.nl} \
        )

In this rule, the following 'lcall' action first verifies that we are dealing 
with tunnel 241 that has been down for more than 14400 seconds, and sets %o 
action list variable to either true or false:
lcall %o %TT %+{tunnel} -> ( sub { $_[0] > 14400 && $_[1] eq "241" } )

After that, the if-else action executes different actions depending on the 
truth value of %o variable -- if %o is true, an event is written to standard 
output, otherwise a message is sent to port 514/tcp of host 10.3.0.85.
If you want to execute tcpsock action for all events (be it tunnel 241 with 
long downtime or not), you can easily move 'tcpsock' action out from the 
else-block and drop the empty else-block of 'if' action altogether.

However, if you would like to have several rules in place, you could generate a 
synthetic event from the Pair rule, and process this event by additional Single 
rule which checks the tunnel name and downtime. For example, consider the 
following ruleset of two rules:

type=Pair
ptype=PerlFunc
pattern=sub { my(%var); \
        if ($_[0] !~ /neighbor \*?(\d+\.\d+\.\d+\.\d+) Down/) { return 0; } \
        $var{"nip"} = $1; $var{"ts"} = time(); \
        $var{"hostname"} = scalar gethostbyaddr(Socket::inet_aton($var{"nip"}), 
Socket::AF_INET); \
        if (!defined($var{"hostname"})) { $var{"hostname"} = $var{"nip"} }; \
        $var{"storenumber"} = "NA"; $var{"tunnel"} = "NA"; \
        if ($var{"hostname"} =~ /(\d+)lo/) { $var{"storenumber"} = $1; } \
        if ($var{"hostname"} =~ /lo(\d+)/) { $var{"tunnel"} = $1; } \
        return \%var; }
desc=BGP Neighbor $+{nip} Down
action=tcpsock 10.3.0.85:514<http://10.3.0.85:514> LzEC BGP Neighbor 
status="Down" hostname="$+{hostname}" store="$+{storenumber}" 
tunnel="$+{tunnel}" ECRule="01-bgp-flap-detection" ECRulenum="1"%{.nl};
ptype2=RegExp
pattern2=neighbor \*?$+{nip} Up
desc2=BGP Neighbor %+{nip} Up
action2=lcall %TT %+{ts} -> ( sub { time() - $_[0] } ); \
        tcpsock 10.3.0.85:514<http://10.3.0.85:514> LzEC BGP Neighbor 
status="Up" hostname="%+{hostname}" store="%+{storenumber}" tunnel="%+{tunnel}" 
downtime="%TT" ECRule="01-bgp-flap-detection" ECRulenum="2"%{.nl}; \
        event LzEC BGP Neighbor status="Up" hostname="%+{hostname}" 
store="%+{storenumber}" tunnel="%+{tunnel}" downtime="%TT" 
ECRule="01-bgp-flap-detection" ECRulenum="2"

type=Single
ptype=PerlFunc
pattern=sub { if ($_[0] !~ /LzEC BGP Neighbor status="Up" hostname="(\S+)" 
store="(\S+)" tunnel="241" downtime="(\d+)" ECRule="01-bgp-flap-detection" 
ECRulenum="2"/) { return 0; } \
        if ($3 <= 14400) { return 0; } \
        return ($1, $2, $3); }
desc=event for tunnel 241 with long downtime
action=write - Event for hostname $1 store $2 tunnel 241 downtime $3

The above ruleset use the approach you mentioned in your letter -- the tunnel 
name and downtime are checked within the PerlFunc pattern, and if tunnel 241 
with long downtime is detected, the pattern matches.

Finally, there is also another slightly less efficient way for writing the 
above Single rule which uses a RegExp pattern:

type=Single
ptype=RegExp
pattern=LzEC BGP Neighbor status="Up" hostname="(\S+)" store="(\S+)" 
tunnel="241" downtime="(\d+)" ECRule="01-bgp-flap-detection" ECRulenum="2"
context=$3 -> ( sub { $_[0] > 14400 } )
desc=event for tunnel 241 with long downtime
action=write - Event for hostname $1 store $2 tunnel 241 downtime $3

This rule first matches the synthetic event with a traditional regular 
expression, and then executes a context expression that checks whether downtime 
is greater than 14400. Although this rule is computationally slightly more 
expensive (in addition to pattern matching there is also context evaluation), 
the Perl code in this rule is simpler and perhaps easier to read.

Hopefully above examples provided some insights how you can potentially address 
the task that you have.

kind regards,
risto



_______________________________________________
Simple-evcorr-users mailing list
Simple-evcorr-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/simple-evcorr-users

Reply via email to