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
|
#!/usr/bin/env ruby
# IOS:
# logging discriminator CFG mnemonics includes CONFIG_I
# logging host SERVER discriminator CFG
# JunOS:
# set system syslog host SERVER interactive-commands notice
# set system syslog host SERVER match "^mgd\[[0-9]+\]: UI_COMMIT: .*"
# Ports < 1024 need extra privileges, use a port higher than this by passing the first argument a number
# To use the default port for syslog (514) you shouldnt pass an argument, but you will need to allow this with:
# sudo setcap 'cap_net_bind_service=+ep' /usr/bin/ruby
# exit if fork ## TODO: proper daemonize
require 'socket'
require 'resolv'
require_relative 'rest_client'
module Oxidized
class SyslogMonitor
NAME_MAP = {
/(.*)\.ip\.tdc\.net/ => '\1',
/(.*)\.ip\.fi/ => '\1',
}
PORT = 514
FILE = 'messages'
MSG = {
:ios => /%SYS-(SW[0-9]+-)?5-CONFIG_I:/,
:junos => 'UI_COMMIT:',
}
class << self
def udp port=PORT, listen=0
port ||= PORT
io = UDPSocket.new
io.bind listen, port
new io, :udp
end
def file syslog_file=FILE
io = open syslog_file, 'r'
io.seek 0, IO::SEEK_END
new io, :file
end
end
private
def initialize io, mode=:udp
@mode = mode
run io
end
def rest opt
Oxidized::RestClient.next opt
end
def ios ip, log, i
# TODO: we need to fetch 'ip/name' in mode == :file here
user = log[i+5]
from = log[-1][1..-2]
rest( :user => user, :from => from, :model => 'ios', :ip => ip,
:name => getname(ip) )
end
def jnpr ip, log, i
# TODO: we need to fetch 'ip/name' in mode == :file here
user = log[i+2][1..-2]
msg = log[(i+6)..-1].join(' ')[10..-2]
msg = nil if msg == 'none'
rest( :user => user, :msg => msg, :model => 'jnpr', :ip => ip,
:name => getname(ip) )
end
def handle_log log, ip
log = log.to_s.split ' '
if i = log.find_index { |e| e.match( MSG[:ios] ) }
ios ip, log, i
elsif i = log.index(MSG[:junos])
jnpr ip, log, i
end
end
def run io
while true
log = select [io]
log, ip = log.first.first, nil
if @mode == :udp
log, ip = log.recvfrom_nonblock 2000
ip = ip.last
else
begin
log = log.read_nonblock 2000
rescue EOFError
sleep 1
retry
end
end
handle_log log, ip
end
end
def getname ip
name = (Resolv.getname ip.to_s rescue ip)
NAME_MAP.each { |re, sub| name.sub! re, sub }
name
end
end
end
Oxidized::SyslogMonitor.udp ARGV[0]
#Oxidized::SyslogMonitor.file '/var/log/poop'
|