File: syslog.lua

package info (click to toggle)
ntopng 5.2.1%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 121,832 kB
  • sloc: javascript: 143,431; cpp: 71,175; ansic: 11,108; sh: 4,687; makefile: 911; python: 587; sql: 512; pascal: 234; perl: 118; ruby: 52; exp: 4
file content (196 lines) | stat: -rw-r--r-- 6,131 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
--
-- (C) 2021 - ntop.org
--

require "lua_utils"
local json = require "dkjson"
local alert_utils = require "alert_utils"
local alert_consts = require "alert_consts"
local alert_severities = require "alert_severities"
local format_utils = require "format_utils"

local syslog = {
   name = "Syslog",
   conf_max_num = 1, -- At most 1 endpoint
   endpoint_params = {
      { param_name = "syslog_alert_format" },
      { param_name = "syslog_protocol", optional = true },
      { param_name = "syslog_host", optional = true },
      { param_name = "syslog_port", optional = true },
   },
   endpoint_template = {
      plugin_key = "syslog_alert_endpoint",
      template_name = "syslog_endpoint.template"
   },
   recipient_params = {
   },
   recipient_template = {
      plugin_key = "syslog_alert_endpoint",
      template_name = "syslog_recipient.template"
   },
}

-- syslog.DEFAULT_SEVERITY = "info"
syslog.EXPORT_FREQUENCY = 1 -- 1 second, i.e., as soon as possible
syslog.prio = 300

-- ##############################################

function syslog.isAvailable()
   return(ntop.syslog ~= nil)
end

-- ##############################################

local function readSettings(recipient)
   local settings = {
      -- Endpoint
      protocol = recipient.endpoint_conf.syslog_protocol, -- tcp or udp
      host = recipient.endpoint_conf.syslog_host,
      port = recipient.endpoint_conf.syslog_port,
      syslog_alert_format = recipient.endpoint_conf.syslog_alert_format
   }

   if isEmptyString(settings.host) then
      settings.host = nil
   else
      if settings.protocol == nil or settings.protocol ~= 'tcp' then
         settings.protocol = 'udp'
      end
      if settings.port == nil then
         settings.port = 514
      else
         settings.port = tonumber(settings.port)
      end
   end

   return settings
end

-- ##############################################

-- @brief Returns the desided formatted output for recipient params
function syslog.format_recipient_params(recipient_params)
   return string.format("(%s)", syslog.name)
end

-- ##############################################

function syslog.sendMessage(settings, notif, severity)
   local syslog_severity = alert_consts.alertLevelToSyslogLevel(severity)
   local syslog_format = settings.syslog_alert_format
   local msg

   if syslog_format and syslog_format == "json" then
      -- Send it plain, notif is already a json-encoded string
      -- so for efficiency, no decoding is done
      msg = notif
   elseif syslog_format and syslog_format == "ecs" then
     if ntop.isEnterpriseM() then
        package.path = dirs.installdir .. "/pro/scripts/lua/modules/?.lua;" .. package.path
        local ecs_format = require "ecs_format"
        msg = json.encode(ecs_format.format(json.decode(notif)))
     else
        return false
     end
   else -- syslog_format == "plaintext" or "plaintextrfc"
      -- prepare a plain text message
      msg = alert_utils.formatAlertNotification(json.decode(notif), {
         nohtml = true,
	 show_severity = true,
	 show_entity = true,
	 timezone = true --[[ Epochs adjusted to the server TZ using ISO 8601 date format --]]
      })
   end

   if settings.host == nil then
      ntop.syslog(msg, syslog_severity)
   else

      local facility = 14 -- log alert
      local level = syslog_severity
      local prio = (facility * 8) + level
      local host_info = ntop.getHostInformation()
      local host = host_info.ip
      local tag = "ntopng"
      local info = ntop.getInfo()
      local pid = info.pid

      if syslog_format and syslog_format == "plaintextrfc" then
         local iso_time = format_utils.formatEpochISO8601() -- "2020-11-19T18:31:21.003Z"

         -- RFC5424 Format:
         -- <PRIO>VERSION ISOTIMESTAMP HOSTNAME APPLICATION PID MESSAGEID MSG
         -- Example:
         -- <113>1 2020-11-19T18:31:21.003Z 192.168.1.1 ntopng 21365 ID1 -
         msg = "<"..prio..">1 "..iso_time.." "..host.." "..tag.." "..pid.." - - "..msg	 
      else
         -- local log_time = format_utils.formatEpoch() -- "2020-11-09 18:00:00"
         local log_time = os.date("!%b %d %X") -- "Feb 25 09:58:12"
	 
         -- Unix Format:
         -- <PRIO>DATE TIME DEVICE APPLICATION[PID]: MSG
         -- Example:
         -- <113>09/11/2020 18:31:21 192.168.1.1 ntopng[21365]: ...  
         msg = "<"..prio..">"..log_time.." "..host.." "..tag.."["..pid.."]: "..msg
      end

      if settings.protocol == 'tcp' then
         ntop.send_tcp_data(settings.host, settings.port, msg.."\n", 1 --[[ timeout (msec) --]] )
      else
         ntop.send_udp_data(settings.host, settings.port, msg)
      end
   end

   return true
end

-- ##############################################

-- Dequeue alerts from a recipient queue for sending notifications
function syslog.dequeueRecipientAlerts(recipient, budget, high_priority)   
   local settings = readSettings(recipient)
   local notifications = {}

   for i = 1, budget do
      local notification = ntop.recipient_dequeue(recipient.recipient_id, high_priority)
      if notification then 
         notifications[#notifications + 1] = notification
      else
         break
      end
   end

   if not notifications or #notifications == 0 then
      return {success = true, more_available = false}
   end

   -- Most recent notifications first
   for _, notification in ipairs(notifications) do
      syslog.sendMessage(settings, notification.alert, ntop.mapScoreToSeverity(notification.score))
   end

   return {success = true,  more_available = true}
end

-- ##############################################

function syslog.runTest(recipient)
   local settings = readSettings(recipient)

   local now = os.time()
   local notif = {
      tstamp = now,
      entity_id = alert_consts.alert_entities.test.entity_id,
      severity = alert_severities.info.severity_id
   }

   local success = syslog.sendMessage(settings, json.encode(notif), alert_severities.info.severity_id)

   local message_info = i18n("prefs.syslog_sent_successfully")
   return success, message_info
end

-- ##############################################

return syslog