diff --git a/scripts/base/frameworks/notice/actions/email_admin.zeek b/scripts/base/frameworks/notice/actions/email_admin.zeek index 2d8c4ba432..16083760e8 100644 --- a/scripts/base/frameworks/notice/actions/email_admin.zeek +++ b/scripts/base/frameworks/notice/actions/email_admin.zeek @@ -18,19 +18,28 @@ export { }; } -# Run before ACTION_PAGE -hook notice(n: Notice::Info) &priority=5 +hook notice(n: Notice::Info) { if ( |Site::local_admins| > 0 && ACTION_EMAIL_ADMIN in n$actions ) { local email = ""; if ( n?$src && |Site::get_emails(n$src)| > 0 ) - email = fmt("%s, %s", email, Site::get_emails(n$src)); + email = Site::get_emails(n$src); if ( n?$dst && |Site::get_emails(n$dst)| > 0 ) - email = fmt("%s, %s", email, Site::get_emails(n$dst)); + { + if ( email != "" ) + email = fmt("%s, %s", email, Site::get_emails(n$dst)); + else + email = Site::get_emails(n$dst); + } if ( email != "" ) - n$email_dest = email; + { + if ( ! n?$email_dest ) + n$email_dest = set(); + + add n$email_dest[email]; + } } } diff --git a/scripts/base/frameworks/notice/actions/page.zeek b/scripts/base/frameworks/notice/actions/page.zeek index 01c43f53f1..34019b9e45 100644 --- a/scripts/base/frameworks/notice/actions/page.zeek +++ b/scripts/base/frameworks/notice/actions/page.zeek @@ -17,9 +17,13 @@ export { option mail_page_dest = ""; } -# Runs after EMAIL_ADMIN (assume page supercedes), but before hostnames are added. -hook notice(n: Notice::Info) &priority=4 +hook notice(n: Notice::Info) { if ( ACTION_PAGE in n$actions ) - n$email_dest = mail_page_dest; + { + if ( ! n?$email_dest ) + n$email_dest = set(); + + add n$email_dest[mail_page_dest]; + } } diff --git a/scripts/base/frameworks/notice/main.zeek b/scripts/base/frameworks/notice/main.zeek index 6dd953cb9e..202967cf7b 100644 --- a/scripts/base/frameworks/notice/main.zeek +++ b/scripts/base/frameworks/notice/main.zeek @@ -5,6 +5,7 @@ ##! the notice framework can be found in :doc:`/frameworks/notice`. @load base/frameworks/cluster +@load base/utils/strings module Notice; @@ -136,8 +137,8 @@ export { ## The actions which have been applied to this notice. actions: ActionSet &log &default=ActionSet(); - ## The email address where to send this notice - email_dest: string &log &optional; + ## The email address(es) where to send this notice + email_dest: set[string] &log &optional; ## By adding chunks of text into this element, other scripts ## can expand on notices that are being emailed. The normal @@ -513,14 +514,22 @@ hook Notice::policy(n: Notice::Info) &priority=10 add n$actions[ACTION_LOG]; } +hook Notice::notice(n: Notice::Info) + { + if ( ACTION_EMAIL in n$actions ) + { + if ( ! n?$email_dest ) + n$email_dest = set(); + + add n$email_dest[mail_dest]; + } + } + hook Notice::notice(n: Notice::Info) &priority=-5 { - # Send to requested address if set if ( n?$email_dest ) - email_notice_to(n, n$email_dest, T); - # Otherwise Send to default address - else if ( ACTION_EMAIL in n$actions ) - email_notice_to(n, mail_dest, T); + for ( dest in n$email_dest ) + email_notice_to(n, dest, T); if ( ACTION_LOG in n$actions ) Log::write(Notice::LOG, n); diff --git a/scripts/policy/frameworks/notice/extend-email/hostnames.zeek b/scripts/policy/frameworks/notice/extend-email/hostnames.zeek index ad1662b26b..f6ed1a58be 100644 --- a/scripts/policy/frameworks/notice/extend-email/hostnames.zeek +++ b/scripts/policy/frameworks/notice/extend-email/hostnames.zeek @@ -14,7 +14,7 @@ module Notice; global tmp_notice_storage: table[string] of Notice::Info &create_expire=max_email_delay+10secs; # Run after e-mail address is set, but before e-mail is sent. -hook notice(n: Notice::Info) &priority=0 +hook notice(n: Notice::Info) &priority=-1 { if ( ! n?$src && ! n?$dst ) return; diff --git a/testing/btest/Baseline/scripts.base.frameworks.notice.action-email-admin/sendmail.out b/testing/btest/Baseline/scripts.base.frameworks.notice.action-email-admin/sendmail.out new file mode 100644 index 0000000000..95b718e67c --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.notice.action-email-admin/sendmail.out @@ -0,0 +1,20 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +------- cmdline args ----------- +-t -oi +----------- stdin -------------- +From: Zeek +Subject: [Zeek] Test_Notice +To: postmaster@the.cloud, cloudflare@example.net +User-Agent: Zeek/$zeek_version() + +Message: test + +Address: 1.1.1.1 + +Email Extensions +---------------- + + +-- +[Automatically generated] + diff --git a/testing/btest/Baseline/scripts.base.frameworks.notice.action-email-custom-address/sendmail.out b/testing/btest/Baseline/scripts.base.frameworks.notice.action-email-custom-address/sendmail.out new file mode 100644 index 0000000000..4af3d1e4d2 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.notice.action-email-custom-address/sendmail.out @@ -0,0 +1,37 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +------- cmdline args ----------- +-t -oi +----------- stdin -------------- +From: Zeek +Subject: [Zeek] Test_Notice +To: user@example.net +User-Agent: Zeek/$zeek_version() + +Message: test + + +Email Extensions +---------------- + + +-- +[Automatically generated] + +------- cmdline args ----------- +-t -oi +----------- stdin -------------- +From: Zeek +Subject: [Zeek] Test_Notice +To: admin@example.net +User-Agent: Zeek/$zeek_version() + +Message: test + + +Email Extensions +---------------- + + +-- +[Automatically generated] + diff --git a/testing/btest/Baseline/scripts.base.frameworks.notice.action-email-multiple/sendmail.out b/testing/btest/Baseline/scripts.base.frameworks.notice.action-email-multiple/sendmail.out new file mode 100644 index 0000000000..17fe9b1af2 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.notice.action-email-multiple/sendmail.out @@ -0,0 +1,37 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +------- cmdline args ----------- +-t -oi +----------- stdin -------------- +From: Zeek +Subject: [Zeek] Test_Notice +To: page@example.net +User-Agent: Zeek/$zeek_version() + +Message: test + + +Email Extensions +---------------- + + +-- +[Automatically generated] + +------- cmdline args ----------- +-t -oi +----------- stdin -------------- +From: Zeek +Subject: [Zeek] Test_Notice +To: user@example.net +User-Agent: Zeek/$zeek_version() + +Message: test + + +Email Extensions +---------------- + + +-- +[Automatically generated] + diff --git a/testing/btest/Baseline/scripts.base.frameworks.notice.action-email/sendmail.out b/testing/btest/Baseline/scripts.base.frameworks.notice.action-email/sendmail.out new file mode 100644 index 0000000000..496d895fa4 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.notice.action-email/sendmail.out @@ -0,0 +1,19 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +------- cmdline args ----------- +-t -oi +----------- stdin -------------- +From: Zeek +Subject: [Zeek] Test_Notice +To: user@example.net +User-Agent: Zeek/$zeek_version() + +Message: test + + +Email Extensions +---------------- + + +-- +[Automatically generated] + diff --git a/testing/btest/Baseline/scripts.base.frameworks.notice.action-page-with-hostnames/sendmail.out b/testing/btest/Baseline/scripts.base.frameworks.notice.action-page-with-hostnames/sendmail.out new file mode 100644 index 0000000000..1c4933b43a --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.notice.action-page-with-hostnames/sendmail.out @@ -0,0 +1,24 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +------- cmdline args ----------- +-t -oi +----------- stdin -------------- +From: Zeek +Subject: [Zeek] Test_Notice +To: page@example.net +User-Agent: Zeek/$zeek_version() + +Message: test + +Address: 1.1.1.1 + +Email Extensions +---------------- +orig/src hostname: fake_addr_lookup_result_1.1.1.1 + +resp/dst hostname: fake_addr_lookup_result_::1 + + + +-- +[Automatically generated] + diff --git a/testing/btest/Baseline/scripts.base.frameworks.notice.action-page/sendmail.out b/testing/btest/Baseline/scripts.base.frameworks.notice.action-page/sendmail.out new file mode 100644 index 0000000000..fe5c593721 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.frameworks.notice.action-page/sendmail.out @@ -0,0 +1,19 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +------- cmdline args ----------- +-t -oi +----------- stdin -------------- +From: Zeek +Subject: [Zeek] Test_Notice +To: page@example.net +User-Agent: Zeek/$zeek_version() + +Message: test + + +Email Extensions +---------------- + + +-- +[Automatically generated] + diff --git a/testing/btest/scripts/base/frameworks/notice/action-email-admin.zeek b/testing/btest/scripts/base/frameworks/notice/action-email-admin.zeek new file mode 100644 index 0000000000..28cd849f48 --- /dev/null +++ b/testing/btest/scripts/base/frameworks/notice/action-email-admin.zeek @@ -0,0 +1,24 @@ +# @TEST-EXEC: zeek -b %INPUT +# @TEST-EXEC: btest-diff sendmail.out + +@load base/frameworks/notice +@load base/utils/site + +redef Notice::mail_dest = "user@example.net"; +redef Notice::sendmail = "fake-sendmail"; + +redef Site::local_admins += { [1.0.0.0/8] = set("cloudflare@example.net", "postmaster@the.cloud") }; + +redef enum Notice::Type += { + Test_Notice, +}; + +event zeek_init() + { + NOTICE([$note=Test_Notice, $msg="test", $identifier="static", $src=1.1.1.1, $dst=[::1]]); + } + +hook Notice::policy(n: Notice::Info) &priority=1 + { + add n$actions[Notice::ACTION_EMAIL_ADMIN]; + } diff --git a/testing/btest/scripts/base/frameworks/notice/action-email-custom-address.zeek b/testing/btest/scripts/base/frameworks/notice/action-email-custom-address.zeek new file mode 100644 index 0000000000..dc233f77a7 --- /dev/null +++ b/testing/btest/scripts/base/frameworks/notice/action-email-custom-address.zeek @@ -0,0 +1,29 @@ +# @TEST-EXEC: zeek -b %INPUT +# @TEST-EXEC: btest-diff sendmail.out + +# Tests overriding the e-mail destination for a specific notice + + +@load base/frameworks/notice + +hook Notice::policy(n: Notice::Info) &priority=1 + { + add n$actions[Notice::ACTION_EMAIL]; + } + +redef Notice::mail_dest = "user@example.net"; +redef Notice::sendmail = "fake-sendmail"; + +redef enum Notice::Type += { + Test_Notice, +}; + +event zeek_init() + { + NOTICE([$note=Test_Notice, $msg="test", $identifier="static"]); + } + +hook Notice::policy(n: Notice::Info) + { + n$email_dest = set("admin@example.net"); + } diff --git a/testing/btest/scripts/base/frameworks/notice/action-email-multiple.zeek b/testing/btest/scripts/base/frameworks/notice/action-email-multiple.zeek new file mode 100644 index 0000000000..e57e9e723a --- /dev/null +++ b/testing/btest/scripts/base/frameworks/notice/action-email-multiple.zeek @@ -0,0 +1,25 @@ +# @TEST-EXEC: zeek -b %INPUT +# @TEST-EXEC: btest-diff sendmail.out + +# Test what happens with PAGE and EMAIL + +@load base/frameworks/notice + +redef Notice::mail_dest = "user@example.net"; +redef Notice::mail_page_dest = "page@example.net"; +redef Notice::sendmail = "fake-sendmail"; + +redef enum Notice::Type += { + Test_Notice, +}; + +event zeek_init() + { + NOTICE([$note=Test_Notice, $msg="test", $identifier="static"]); + } + +hook Notice::policy(n: Notice::Info) &priority=1 + { + add n$actions[Notice::ACTION_PAGE]; + add n$actions[Notice::ACTION_EMAIL]; + } diff --git a/testing/btest/scripts/base/frameworks/notice/action-email.zeek b/testing/btest/scripts/base/frameworks/notice/action-email.zeek new file mode 100644 index 0000000000..0bdc3f51be --- /dev/null +++ b/testing/btest/scripts/base/frameworks/notice/action-email.zeek @@ -0,0 +1,21 @@ +# @TEST-EXEC: zeek -b %INPUT +# @TEST-EXEC: btest-diff sendmail.out + +@load base/frameworks/notice + +redef Notice::mail_dest = "user@example.net"; +redef Notice::sendmail = "fake-sendmail"; + +redef enum Notice::Type += { + Test_Notice, +}; + +event zeek_init() + { + NOTICE([$note=Test_Notice, $msg="test", $identifier="static"]); + } + +hook Notice::policy(n: Notice::Info) &priority=1 + { + add n$actions[Notice::ACTION_EMAIL]; + } diff --git a/testing/btest/scripts/base/frameworks/notice/action-page-with-hostnames.zeek b/testing/btest/scripts/base/frameworks/notice/action-page-with-hostnames.zeek new file mode 100644 index 0000000000..d5486e808a --- /dev/null +++ b/testing/btest/scripts/base/frameworks/notice/action-page-with-hostnames.zeek @@ -0,0 +1,23 @@ +# @TEST-EXEC: zeek -b %INPUT +# @TEST-EXEC: btest-diff sendmail.out + +@load base/frameworks/notice +@load frameworks/notice/extend-email/hostnames + +redef Notice::mail_dest = "user@example.net"; +redef Notice::mail_page_dest = "page@example.net"; +redef Notice::sendmail = "fake-sendmail"; + +redef enum Notice::Type += { + Test_Notice, +}; + +event zeek_init() + { + NOTICE([$note=Test_Notice, $msg="test", $identifier="static", $src=1.1.1.1, $dst=[::1]]); + } + +hook Notice::policy(n: Notice::Info) &priority=1 + { + add n$actions[Notice::ACTION_PAGE]; + } diff --git a/testing/btest/scripts/base/frameworks/notice/action-page.zeek b/testing/btest/scripts/base/frameworks/notice/action-page.zeek new file mode 100644 index 0000000000..539c3d00b4 --- /dev/null +++ b/testing/btest/scripts/base/frameworks/notice/action-page.zeek @@ -0,0 +1,22 @@ +# @TEST-EXEC: zeek -b %INPUT +# @TEST-EXEC: btest-diff sendmail.out + +@load base/frameworks/notice + +redef Notice::mail_dest = "user@example.net"; +redef Notice::mail_page_dest = "page@example.net"; +redef Notice::sendmail = "fake-sendmail"; + +redef enum Notice::Type += { + Test_Notice, +}; + +event zeek_init() + { + NOTICE([$note=Test_Notice, $msg="test", $identifier="static"]); + } + +hook Notice::policy(n: Notice::Info) &priority=1 + { + add n$actions[Notice::ACTION_PAGE]; + } diff --git a/testing/scripts/fake-sendmail b/testing/scripts/fake-sendmail new file mode 100755 index 0000000000..4483460261 --- /dev/null +++ b/testing/scripts/fake-sendmail @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# +# Just writes the arguments and stdin to a file, to compare with diff + +echo "------- cmdline args -----------" >> sendmail.out +echo "$*" >> sendmail.out +echo "----------- stdin --------------" >> sendmail.out +while IFS= read -r line; do + # Strip out the user agent, which is version dependent + if [[ $line == "User-Agent: Zeek/"* ]]; then + printf 'User-Agent: Zeek/$zeek_version()\n' >> sendmail.out + else + printf '%s\n' "$line" >> sendmail.out + fi +done