Skip to content

Commit

Permalink
Merge pull request #312 from splunk/feature/cisco-uc
Browse files Browse the repository at this point in the history
Support cisco UCM
  • Loading branch information
Ryan Faircloth authored and GitHub committed Feb 10, 2020
2 parents db78f52 + ae6aea5 commit 651db37
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 0 deletions.
47 changes: 47 additions & 0 deletions docs/sources/Cisco/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,3 +331,50 @@ index=<asconfigured> sourcetype=merkai

Verify timestamp, and host values match as expected

## Product - UCM

| Ref | Link |
|----------------|---------------------------------------------------------------------------------------------------------|
| Splunk Add-on | na |
| Product Manual | multiple |


### Sourcetypes

| sourcetype | notes |
|----------------|---------------------------------------------------------------------------------------------------------|
| cisco:ucm | None |

### Sourcetype and Index Configuration

| key | sourcetype | index | notes |
|----------------|----------------|----------------|----------------|
| cisco_ucm | cisco:ucm | ucm | None |


### Filter type

PATTERN MATCH

### Setup and Configuration

* Refer to Cisco support web site

### Options

| Variable | default | description |
|----------------|----------------|----------------|
| SC4S_LISTEN_CISCO_UCM_TCP_PORT | empty string | Enable a TCP port for this specific vendor product using the number defined |
| SC4S_LISTEN_CISCO_UCM_UDP_PORT | empty string | Enable a UDP port for this specific vendor product using the number defined |
| SC4S_ARCHIVE_CISCO_UCM | no | Enable archive to disk for this specific source |
| SC4S_DEST_CISCO_UCM_HEC | no | When Splunk HEC is disabled globally set to yes to enable this specific source |

### Verification

Use the following search to validate events are present

```
index=<asconfigured> sourcetype=cisco:ucm
```

Verify timestamp, and host values match as expected
32 changes: 32 additions & 0 deletions package/etc/conf.d/filters/cisco/ucm.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

filter f_cisco_ucm {
message("^%UC\_")
or
message("^%CCM\_")
};

filter f_cisco_ucm_message {
message(
'^(<\d{1,3}>)\d*: (?:([^:]+): )?(.*) : (%.*)'
flags(store-matches)
);
};

parser p_cisco_ucm_date {
#Oct 14 2015 05:50:19 AM.484 UTC
#Apr 21 19:01:35.638 UTC
date-parser(format(
'%b %d %Y %I:%M:%S %p.%f %Z',
'%b %d %H:%M:%S.%f %Z'
)
template("$3")
);
};

rewrite r_cisco_ucm_message {
set("cisco_ucm" value("fields.sc4s_syslog_format"));
set("cisco_ucm" value("fields.sc4s_vendor_product"));
set("$HOST_FROM" value("HOST") );
set("$2" value("HOST") condition(match("^..." template("${2}"))) );
set("$4" value("MESSAGE"));
};
62 changes: 62 additions & 0 deletions package/etc/conf.d/log_paths/lp-cisco_ucm.conf.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Cisco UCM
{{- /* The following provides a unique port source configuration if env var(s) are set */}}
{{- $context := dict "port_id" "CISCO_UCM" "parser" "cisco_ucm" }}
{{- tmpl.Exec "t/source_network.t" $context }}

log {
junction {
{{- if or (or (getenv (print "SC4S_LISTEN_CISCO_UCM_TCP_PORT")) (getenv (print "SC4S_LISTEN_CISCO_UCM_UDP_PORT"))) (getenv (print "SC4S_LISTEN_CISCO_UCM_TLS_PORT")) }}
channel {
# Listen on the specified dedicated port(s) for CISCO_UCM traffic
source (s_CISCO_UCM);
flags (final);
};
{{- end}}
channel {
# Listen on the default port (typically 514) for CISCO_UCM traffic
source (s_DEFAULT);
filter(f_cisco_ucm);
flags(final);
};
};

if {
filter {
message(
'Node ?ID(?:\:|\=)([^ \]]+)'
flags(store-matches)
);
};
rewrite {
set("$1" value("HOST") );
};
} elif {
filter {
message(
' on node ([^ ]+\. |[^ ]+ )'
flags(store-matches)
);
};
rewrite {
set("$1" value("HOST") );
};
};

rewrite {
set("cisco_ucm", value("fields.sc4s_vendor_product"));
r_set_splunk_dest_default(sourcetype("cisco:ucm"), index("main"))
};
parser {p_add_context_splunk(key("cisco_ucm")); };
parser (compliance_meta_by_source);
rewrite { set("$(template ${.splunk.sc4s_template} $(template t_hdr_msg))" value("MSG")); };

{{- if or (conv.ToBool (getenv "SC4S_DEST_SPLUNK_HEC_GLOBAL" "yes")) (conv.ToBool (getenv "SC4S_DEST_CISCO_UCM_HEC" "no")) }}
destination(d_hec);
{{- end}}

{{- if or (conv.ToBool (getenv "SC4S_ARCHIVE_GLOBAL" "no")) (conv.ToBool (getenv "SC4S_ARCHIVE_CISCO_UCM" "no")) }}
destination(d_archive);
{{- end}}

flags(flow-control,final);
};
1 change: 1 addition & 0 deletions package/etc/context_templates/splunk_index.csv.example
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#cisco_ios,index,netops
#cisco_ise,index,netauth
#cisco_nx_os,index,netops
#cisco_ucm,index,main
#local_example,index,main
#forcepoint_webprotect,index,netproxy
#fortinet_fortios_event,index,netops
Expand Down
7 changes: 7 additions & 0 deletions package/etc/go_templates/source_network.t
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ source s_{{ .port_id }} {
{{ else if eq .parser "cisco_meraki_parser" }}
parser (p_cisco_meraki);
rewrite(set_rfc5424_epochtime);
{{ else if eq .parser "cisco_ucm" }}
parser (p_cisco_ucm_date);
rewrite (r_cisco_ucm_message);
{{ else if eq .parser "no_parse" }}
rewrite(set_no_parse);
{{ else }}
Expand All @@ -100,6 +103,10 @@ source s_{{ .port_id }} {
} elif {
parser (p_cisco_meraki);
rewrite(set_rfc5424_epochtime);
} elif {
filter(f_cisco_ucm_message);
parser (p_cisco_ucm_date);
rewrite (r_cisco_ucm_message);
} elif {
filter(f_rfc3164_version);
rewrite(set_rfc3164_no_version_string);
Expand Down
1 change: 1 addition & 0 deletions tests/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ services:
- SC4S_LISTEN_PALOALTO_PANOS_TCP_PORT=5005
- SC4S_LISTEN_PFSENSE_TCP_PORT=5006
- SC4S_ARCHIVE_GLOBAL=no
- SC4S_SOURCE_STORE_RAWMSG=yes
splunk:
build:
context: ../splunk
Expand Down
110 changes: 110 additions & 0 deletions tests/test_cisco_ucm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Copyright 2019 Splunk, Inc.
#
# Use of this source code is governed by a BSD-2-clause-style
# license that can be found in the LICENSE-BSD2 file or at
# https://opensource.org/licenses/BSD-2-Clause
import random

from jinja2 import Environment

from .sendmessage import *
from .splunkutils import *

env = Environment(extensions=['jinja2_time.TimeExtension'])

# https://www.ciscolive.com/c/dam/r/ciscolive/us/docs/2017/pdf/TECUCC-3000.pdf

# <189>8103: Oct 14 2015 05:50:19 AM.484 UTC : %UC_AUDITLOG-5-AdministrativeEvent: %[ UserID =administrator][ ClientAddress =10.110.1.2][ Severity =5][ EventType =GeneralConfigurationUpdate][ ResourceAccessed=CUCMAdmin][ EventStatus =Success][ CompulsoryEvent =No][ AuditCategory =AdministrativeEvent][ ComponentID =Cisco CUCM Administration][ AuditDetails =record in table device, with key field name = SEP0000311107A5 deleted][App ID=Cisco Tomcat][Cluster ID=][Node ID=CUCM11PUB]: Audit Event is generated by this application


def test_cisco_ucm_nohost_auditlog(record_property, setup_wordlist, setup_splunk, setup_sc4s):
host = "{}-{}".format(random.choice(setup_wordlist),
random.choice(setup_wordlist))

mt = env.from_string(
"{{ mark }}8103: {% now 'utc', '%b %d %Y %I:%M:%S %p' %}.100 UTC : %UC_AUDITLOG-5-AdministrativeEvent: %[ UserID =administrator][ ClientAddress =192.168.1.1][ Severity =5][ EventType =GeneralConfigurationUpdate][ ResourceAccessed=CUCMAdmin][ EventStatus =Success][ CompulsoryEvent =No][ AuditCategory =AdministrativeEvent][ ComponentID =Cisco CUCM Administration][ AuditDetails =record in table device, with key field name = SEP0000311107A5 deleted][App ID=Cisco Tomcat][Cluster ID=][Node ID={{ host }}]: Audit Event is generated by this application\n")
message = mt.render(mark="<189>", host=host)
sendsingle(message, setup_sc4s[0], setup_sc4s[1][514])

st = env.from_string(
"search index=main host=\"{{ host }}\" sourcetype=\"cisco:ucm\" | head 11")
search = st.render(host=host)

resultCount, eventCount = splunk_single(setup_splunk, search)

record_property("host", host)
record_property("resultCount", resultCount)
record_property("message", message)

assert resultCount == 1


# <189>17: Apr 21 19:01:35.638 UTC : %CCM_RTMT-RTMT-2-RTMT-ERROR-ALERT: RTMT Alert Name:SyslogSeverityMatchFound Detail: At Tue Apr 21 14:01:35 CDT 2009 on node ORD-PUB1, the following SyslogSeverityMatchFound events generated: SeverityMatch - Critical ntpRunningStatus.sh: NTP server 10.12.254.33 is inactive. Verify the network to this server, that it is a NTPv4 server and is operational. SeverityMatch - Alert sshd(pam_unix)[20038]: check pass; user unknown App ID:Cisco AMC Service Cluster ID: Node ID:ord-pub1
def test_cisco_ucm_nohost_rtmt(record_property, setup_wordlist, setup_splunk, setup_sc4s):
host = "{}-{}".format(random.choice(setup_wordlist),
random.choice(setup_wordlist))

mt = env.from_string(
"{{ mark }}17: {% now 'utc', '%b %d %H:%M:%S' %}.100 UTC : %UC_AUDITLOG-5-AdministrativeEvent: %[ UserID =administrator][ ClientAddress =10.1.1.1][ Severity =5][ EventType =GeneralConfigurationUpdate][ ResourceAccessed=CUCMAdmin][ EventStatus =Success][ CompulsoryEvent =No][ AuditCategory =AdministrativeEvent][ ComponentID =Cisco CUCM Administration][ AuditDetails =record in table device, with key field name = SEP0000311107A5 deleted][App ID=Cisco Tomcat][Cluster ID=][Node ID={{ host }}]: Audit Event is generated by this application\n")
message = mt.render(mark="<189>", host=host)
sendsingle(message, setup_sc4s[0], setup_sc4s[1][514])

st = env.from_string(
"search index=main host=\"{{ host }}\" sourcetype=\"cisco:ucm\" | head 11")
search = st.render(host=host)

resultCount, eventCount = splunk_single(setup_splunk, search)

record_property("host", host)
record_property("resultCount", resultCount)
record_property("message", message)

assert resultCount == 1

# <189>23813: cucm-pub: Jul 05 2016 04:03:01 PM.688 UTC : %UC_RTMT-2-RTMT_ALERT: %[AlertName=SyslogSeverityMatchFound][AlertDetail= At Tue Jul 05 12:03:01 EDT 2016 on node 1.2.3.4, the following SyslogSeverityMatchFound events generated: #012SeverityMatch : Critical#012MatchedEvent : Jul 5 12:02:29 cucm-sub1 local7 2 ccm: 6838: cucm-sub1: Jul 05 2016 16:02:29.795 UTC : %UC_CALLMANAGER-2-SignalCongestionEntry: %[Thread=SIP Handler Thread] [AverageDelay=22] [EntryLatency=20] [ExitLatency=8] [SampleSize=10] [TotalSignalCongestionEntry=6752][HighPriorityQueueDepth=0][NormalPriorityQueueDepth=1][LowPriorityQueueDepth=0][AppID=Cisco CallManager][ClusterID=UCMCluster1][NodeID=cucm-sub1]: Unified CM has detected signal congestion in an internal thread and has throttled activities for that thread#012AppID : Cisco Syslog Agent#012Cluster


def test_cisco_ucm_host_auditlog(record_property, setup_wordlist, setup_splunk, setup_sc4s):
host = "{}-{}".format(random.choice(setup_wordlist),
random.choice(setup_wordlist))

mt = env.from_string(
"{{ mark }}23813: {% now 'utc', '%b %d %Y %I:%M:%S %p' %}.100 UTC : %UC_AUDITLOG-5-AdministrativeEvent: %[ UserID =administrator][ ClientAddress =192.1.1.1][ Severity =5][ EventType =GeneralConfigurationUpdate][ ResourceAccessed=CUCMAdmin][ EventStatus =Success][ CompulsoryEvent =No][ AuditCategory =AdministrativeEvent][ ComponentID =Cisco CUCM Administration][ AuditDetails =record in table device, with key field name = SEP0000311107A5 deleted][App ID=Cisco Tomcat][Cluster ID=][Node ID={{ host }}]: Audit Event is generated by this application\n")
message = mt.render(mark="<189>", host=host)
sendsingle(message, setup_sc4s[0], setup_sc4s[1][514])

st = env.from_string(
"search index=main host=\"{{ host }}\" sourcetype=\"cisco:ucm\" | head 11")
search = st.render(host=host)

resultCount, eventCount = splunk_single(setup_splunk, search)

record_property("host", host)
record_property("resultCount", resultCount)
record_property("message", message)

assert resultCount == 1

#<121>17: Apr 21 19:01:35.638 UTC : %CCM_RTMT-RTMT-2-RTMT-ERROR-ALERT: RTMT Alert Name:SyslogSeverityMatchFound Detail: At Tue Apr 21 14:01:35 CDT 2009 on node ORD-PUB1, the following SyslogSeverityMatchFound events generated: SeverityMatch - Critical ntpRunningStatus.sh: NTP server 10.12.254.33 is inactive. Verify the network to this server, that it is a NTPv4 server and is operational. SeverityMatch - Alert sshd(pam_unix)[20038]: check pass; user unknown App ID:Cisco AMC Service Cluster ID: Node ID:ord-pub1


def test_cisco_ucm_nohost_alert(record_property, setup_wordlist, setup_splunk, setup_sc4s):
host = "{}-{}".format(random.choice(setup_wordlist),
random.choice(setup_wordlist))

mt = env.from_string(
"{{ mark }}17: {% now 'utc', '%b %d %H:%M:%S' %}.100 UTC : %CCM_RTMT-RTMT-2-RTMT-ERROR-ALERT: RTMT Alert Name:SyslogSeverityMatchFound Detail: At Tue Apr 21 14:01:35 CDT 2009 on node {{ host }}, the following SyslogSeverityMatchFound events generated: SeverityMatch - Critical ntpRunningStatus.sh: NTP server 10.12.254.33 is inactive. Verify the network to this server, that it is a NTPv4 server and is operational. SeverityMatch - Alert sshd(pam_unix)[20038]: check pass; user unknown App ID:Cisco AMC Service Cluster ID: Node ID:{{host}}\n")
message = mt.render(mark="<189>", host=host)
sendsingle(message, setup_sc4s[0], setup_sc4s[1][514])

st = env.from_string(
"search index=main host=\"{{ host }}\" sourcetype=\"cisco:ucm\" | head 11")
search = st.render(host=host)

resultCount, eventCount = splunk_single(setup_splunk, search)

record_property("host", host)
record_property("resultCount", resultCount)
record_property("message", message)

assert resultCount == 1

0 comments on commit 651db37

Please sign in to comment.