gltail 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,50 @@
1
+ # gl_tail.rb - OpenGL visualization of your server traffic
2
+ # Copyright 2007 Erlend Simonsen <mr@fudgie.org>
3
+ #
4
+ # Licensed under the GNU General Public License v2 (see LICENSE)
5
+ #
6
+
7
+ # Parser which handles logs from Cisco PIX or FWSM firewalls
8
+ # should also handle ASA logs, with minimal change...
9
+ # Leif Sawyer (leif@denali.net)
10
+ #
11
+
12
+ class PixParser < Parser
13
+ def parse( line )
14
+ if line.include?(': Built')
15
+ _, firewall, type, direction, srcif, src, srcport, dstif, dst, dstport =
16
+ /^.* \d+ \d+:\d+:\d+ \[?([a-zA-Z0-9\-]+)\/?\]?.* %(FWSM|PIX)-\d+-\d+: Built (\w+)bound \w+ connection \d+ for (\w+):([a-zA-Z0-9.]+)\/([a-zA-Z0-9.]+) \(.*\) to (\w+):([a-zA-Z0-9.]+)\/([a-zA-Z0-9.]+)/.match(line).to_a
17
+
18
+ if firewall
19
+ add_activity(:block => 'firewall', :name => firewall)
20
+ if direction == 'out'
21
+ add_activity(:block => 'hosts', :name => src)
22
+ add_activity(:block => 'sites', :name => dst)
23
+ else
24
+ add_activity(:block => 'hosts', :name => dst)
25
+ add_activity(:block => 'sites', :name => src)
26
+ end
27
+ printf("%sbound from %s firewall '%s', srcif=%s, src=%s, srcport=%s, dstif=%s, dst=%s, dstport=%s...\n", direction, type, firewall, srcif, src, srcport, dstif, dst, dstport ) if $VRB > 0
28
+ end
29
+
30
+ elsif line.include?('Accessed URL')
31
+ _, firewall, type, client, server, url = /^.* \d+ \d+:\d+:\d+ \[?([a-zA-Z0-9\-]+)\/?\]?.* %(FWSM|PIX)-\d+-\d+: ([a-zA-Z0-9.]+) Accessed URL ([a-zA-Z0-9.]+):(.*)[\?]?/.match(line).to_a
32
+ if firewall
33
+ add_activity(:block => 'firewall', :name => firewall)
34
+ add_activity(:block => 'hosts', :name => client)
35
+ add_activity(:block => 'sites', :name => server)
36
+ add_activity(:block => 'urls', :name => url)
37
+ printf("%s firewall '%s': client %s accessed url %s on host %s\n", type, firewall, client, url, server) if $VRB > 0
38
+ end
39
+
40
+ # elsif line.include?(': Deny')
41
+ # Deny udp src outside:_SRC_IP_/_SRC_PORT_ dst inside:_DST_IP_/_DST_PORT_ by access-group "_ACL_NAME"
42
+ # printf("ACL denied access ...\n") if $VRB > 0
43
+
44
+ # elsif line.include?('static translation')
45
+ # Teardown static translation from inside:_SRC_IP_ to dmz-anc-csa:_DST_IP_ duration 0:01:00
46
+ # printf("static translation ...\n") if $VRB > 0
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,119 @@
1
+ # gl_tail.rb - OpenGL visualization of your server traffic
2
+ # Copyright 2007 Erlend Simonsen <mr@fudgie.org>
3
+ #
4
+ # Licensed under the GNU General Public License v2 (see LICENSE)
5
+
6
+ # Parser which handles Postfix logs
7
+ class PostfixParser < Parser
8
+ def parse( line )
9
+ if line.include?(': connect from')
10
+ _, host, ip = /: connect from ([^\[]+)\[(\d+.\d+.\d+.\d+)\]/.match(line).to_a
11
+ if host
12
+ host = ip if host == 'unknown'
13
+ add_activity(:block => 'smtp', :name => host, :size => 0.03)
14
+ end
15
+ elsif line.include?(' sasl_username=')
16
+ _, username = /, sasl_username=(.*)/.match(line).to_a
17
+ add_activity(:block => 'logins', :name => "#{username}/sasl", :size => 0.1)
18
+ elsif line.include?('NOQUEUE: reject:')
19
+ #
20
+ # Parse rejection messages, including RBL rejections.
21
+ # The rejection status could be displayed with the actual error codes if desired.
22
+ # Change :name => 'rejected'
23
+ # To :name => status
24
+ # Or :name => extstatus
25
+ #
26
+ _, host, ip, status, extstatus, rejectreason, from, to, proto, helo = /: reject: RCPT from ([^\[]+)\[(\d+.\d+.\d+.\d+)\]: (\d+) (\d.\d.\d) (.*) from=<([^>]+)> to=<([^>]+)> proto=(.*) helo=<([^>]+)>/.match(line).to_a
27
+ add_activity(:block => 'status', :name => 'rejected', :size => 0.03)
28
+ host = ip if host == 'unknown'
29
+ if not rejectreason.nil?
30
+ if rejectreason.include?(' blocked using ')
31
+ rbltype = 'rbl'
32
+ if rejectreason.include?('Sender address')
33
+ # RHSBL-stle rejection message
34
+ _, ip, rbl, rbltext = /Sender address \[([^>]+)\] blocked using (.*)\; (.*)\;/.match(rejectreason).to_a
35
+ rbltype = 'rhsbl'
36
+ else
37
+ # Plain RBL rejection message
38
+ _, ip, rbl, rbltext = /Client host \[(\d+.\d+.\d+.\d+)\] blocked using (.*)\; (.*)\;/.match(rejectreason).to_a
39
+ end
40
+ if not rbl.nil?
41
+ # add_activity(:block => 'rejections', :name => host, :size => 0.03)
42
+ add_activity(:block => 'rejections', :name => rbltype + ' ' + rbl, :size => 0.03)
43
+ end
44
+ else
45
+ # Generic rejection message, print the whole thing.
46
+ _, address, reason = /<([^>]+)>\: (.*);/.match(rejectreason).to_a
47
+ # add_activity(:block => 'rejections', :name => host, :size => 0.03)
48
+ add_activity(:block => 'rejections', :name => reason, :size => 0.03)
49
+ end
50
+ end
51
+ elsif line.include?(' from=<')
52
+ _, from, size = /: from=<([^>]+)>, size=(\d+)/.match(line).to_a
53
+ if from
54
+ add_activity(:block => 'mail from', :name => from, :size => size.to_f/100000.0)
55
+ end
56
+ elsif line.include?(' to=<')
57
+ if line.include?('relay=local')
58
+ # Incoming
59
+ _, to, delay, status = /: to=<([^>]+)>, .*delay=([\d.]+).*status=([^ ]+)/.match(line).to_a
60
+ add_activity(:block => 'mail to', :name => to, :size => delay.to_f/10.0, :type => 5, :color => [1.0, 0.0, 1.0, 1.0])
61
+ add_activity(:block => 'status', :name => 'received', :size => delay.to_f/10.0, :type => 3)
62
+ else
63
+ # Outgoing
64
+ _, to, relay_host, delay, status = /: to=<([^>]+)>.*relay=([^\[,]+).*delay=([\d.]+).*status=([^ ]+)/.match(line).to_a
65
+ add_activity(:block => 'mail from', :name => to, :size => delay.to_f/10.0)
66
+ add_activity(:block => 'smtp', :name => relay_host, :size => delay.to_f/10.0)
67
+ add_activity(:block => 'status', :name => status, :size => delay.to_f/10.0, :type => 3)
68
+ end
69
+ elsif line.include?('spamd:') and (line.include?('clean message') or line.include?('identified spam'))
70
+ #
71
+ # Parse spamd log entries for the result summary, and add the clean/spam status to the status block.
72
+ #
73
+ # NOTE/TODO: Much more could be done with this block, including averaging scores and processing times
74
+ #
75
+ _, status, score, mailaddr, proctime, size = /: spamd: (\w+ \w+) \((\d+\.\d+)\/.*\) for (.*):.* in (\d+\.\d+) seconds, (\d+) bytes/.match(line).to_a
76
+ if not status.nil?
77
+ status = status.include?('clean') ? 'clean' : 'spam'
78
+ add_activity(:block => 'status', :name => status, :size => proctime.to_f/10.0)
79
+ end
80
+ elsif line.include?('clamd[')
81
+ #
82
+ # Parse clamd log entries. Print the name of the detected virus.
83
+ #
84
+ _, virusname = /clamd\[\d+\]: .*: (.*) FOUND/.match(line).to_a
85
+ add_activity(:block => 'status', :name => 'virus', :size => 0.03)
86
+ add_activity(:block => 'viruses', :name => virusname, :size => 0.03)
87
+ elsif line.include?(': warning:')
88
+ #
89
+ # Parse warning messages. If it is a known warning, shorten the message, otherwise print the full text
90
+ #
91
+ _, warningtext = /: warning: (.*)/.match(line).to_a
92
+ if warningtext.include?('malformed domain name')
93
+ warningtext = 'Malformed Domain Name'
94
+ elsif warningtext.include?('non-SMTP command')
95
+ warningtext = 'Non-SMTP Command'
96
+ elsif warningtext.include?('Non-recoverable failure in name resolution')
97
+ warningtext = 'DNS Failure'
98
+ elsif warningtext.include?('hostname nor servname provided')
99
+ warningtext = 'Host Verification Failure'
100
+ elsif warningtext.include?('address not listed for hostname')
101
+ warningtext = 'Hostname Without Address'
102
+ elsif warningtext.include?('Connection rate limit exceeded')
103
+ warningtext = 'Per-Host Connection Rate Exceeded'
104
+ elsif warningtext.include?('Connection concurrency limit exceeded')
105
+ warningtext = 'Per-Host Connection concurrency Exceeded'
106
+ elsif warningtext.include?('numeric domain name in resource data')
107
+ warningtext = 'Numeric Domain Name'
108
+ elsif warningtext.include?('numeric hostname')
109
+ warningtext = 'Numeric Host Name'
110
+ elsif warningtext.include?('valid_hostname: empty hostname')
111
+ warningtext = 'Empty Hostname'
112
+ elsif warningtext.include?('Illegal address syntax')
113
+ warningtext = 'Illegal Address Syntax'
114
+ end
115
+ add_activity(:block => 'status', :name => 'warning', :size => 0.03)
116
+ add_activity(:block => 'warnings', :name => warningtext, :size => 0.03)
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,42 @@
1
+ # gl_tail.rb - OpenGL visualization of your server traffic
2
+ # Copyright 2007 Erlend Simonsen <mr@fudgie.org>
3
+ #
4
+ # Licensed under the GNU General Public License v2 (see LICENSE)
5
+ #
6
+
7
+ # Parser which handles PostgreSQL logs
8
+ class PostgreSQLParser < Parser
9
+ def parse( line )
10
+ # here's an example parser for postgres log files; adjust accordingly for different logfile setups.
11
+ #
12
+ # postgresql.conf:
13
+ # log_line_prefix = '[%d, %t] '
14
+ # log_connections = on
15
+ # log_disconnections = on
16
+ # log_duration = on
17
+ # log_statement = 'all'
18
+
19
+ _, database, datetime, activity, description = /^\[(.*), (.* .* .*)\] LOG: ([a-zA-Z0-9\s]*): (.*)/.match(line).to_a
20
+
21
+ if database
22
+ add_activity(:block => 'database', :name => database, :size => 0.2)
23
+ else
24
+ _, datetime, activity, description = /^(.* .* .*) LOG: ([a-zA-Z0-9\s]*): (.*)/.match(line).to_a
25
+ end
26
+
27
+ if activity
28
+ activity = 'vacuum' if(description.include?('vacuum') || activity == 'autovacuum')
29
+ case activity
30
+ when 'duration'
31
+ add_activity(:block => 'database', :name => 'duration', :size => description.to_f / 100.0)
32
+ when 'statement'
33
+ add_activity(:block => 'database', :name => 'activity', :size => 0.2)
34
+ when 'connection authorized', 'disconnection'
35
+ add_activity(:block => 'database', :name => 'login/logout', :size => 0.2)
36
+ when 'vacuum'
37
+ add_event(:block => 'database', :name => 'vacuum', :message => description, :update_stats => true, :color => [1.0, 1.0, 0.0, 1.0])
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,30 @@
1
+ # gl_tail.rb - OpenGL visualization of your server traffic
2
+ # Copyright 2007 Erlend Simonsen <mr@fudgie.org>
3
+ #
4
+ # Licensed under the GNU General Public License v2 (see LICENSE)
5
+ #
6
+
7
+ # Parser which handles logs from PureFTPD
8
+ class PureftpdParser < Parser
9
+ def parse( line )
10
+ _, host, domain, user, date, url, status, size = /^([\d\S.]+) (\S+) (\S+) \[([^\]]+)\] \"(.+?)\" (\d+) ([\S]+)/.match(line).to_a
11
+
12
+ if host
13
+ user = host if user == 'ftp'
14
+
15
+ method, url = url.split(" ")
16
+ url = method if url.nil?
17
+
18
+ if method == "PUT"
19
+ add_activity(:block => 'urls', :name => url, :size => size.to_i, :type => 5)
20
+ else
21
+ add_activity(:block => 'urls', :name => url, :size => size.to_i)
22
+ end
23
+ add_activity(:block => 'sites', :name => server.name, :size => size.to_i) # Size of activity based on size of request
24
+ add_activity(:block => 'users', :name => user, :size => size.to_i)
25
+
26
+ add_activity(:block => 'content', :name => 'file')
27
+ add_activity(:block => 'status', :name => status, :type => 3) # don't show a blob
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ # gl_tail.rb - OpenGL visualization of your server traffic
2
+ # Copyright 2007 Erlend Simonsen <mr@fudgie.org>
3
+ #
4
+ # Licensed under the GNU General Public License v2 (see LICENSE)
5
+ #
6
+
7
+ # Parser which handles qmail logs
8
+ class QmailParser < Parser
9
+ def parse( line )
10
+ if line.include?(' logged in from ')
11
+ _, user, host, ip = /: User \'([^']+)\' of \'([^']+)\' logged in from (\d+.\d+.\d+.\d+)/.match(line).to_a
12
+ if host
13
+ add_activity(:block => 'logins', :name => user+'@'+host, :size => 0.05)
14
+ add_activity(:block => 'sites', :name => server.name, :size => 0.05)
15
+ end
16
+ elsif line.include?(' to local ')
17
+ _, prefix, host = / to local ([^@]+)@(.*)/.match(line).to_a
18
+ if host
19
+ add_activity(:block => 'mail to', :name => host, :size => 0.05)
20
+ add_activity(:block => 'sites', :name => server.name, :size => 0.05)
21
+ end
22
+ elsif line.include?(' to remote ')
23
+ _, prefix, host = / to remote ([^@]+)@(.*)/.match(line).to_a
24
+ if host
25
+ add_activity(:block => 'mail from', :name => host, :size => 0.05)
26
+ add_activity(:block => 'sites', :name => server.name, :size => 0.05)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,41 @@
1
+ # gl_tail.rb - OpenGL visualization of your server traffic
2
+ # Copyright 2007 Erlend Simonsen <mr@fudgie.org>
3
+ #
4
+ # Licensed under the GNU General Public License v2 (see LICENSE)
5
+ #
6
+
7
+ # Parser which handles Rails access logs
8
+ class RailsParser < Parser
9
+ def parse( line )
10
+ #Completed in 0.02100 (47 reqs/sec) | Rendering: 0.01374 (65%) | DB: 0.00570 (27%) | 200 OK [http://example.com/whatever/whatever]
11
+ _, ms, url = /^Completed in ([\d.]+) .* \[([^\]]+)\]/.match(line).to_a
12
+
13
+ if url
14
+ _, host, url = /^http[s]?:\/\/([^\/]+)(.*)/.match(url).to_a
15
+
16
+ add_activity(:block => 'sites', :name => host, :size => ms.to_f) # Size of activity based on request time.
17
+ add_activity(:block => 'urls', :name => HttpHelper.generalize_url(url), :size => ms.to_f)
18
+ add_activity(:block => 'slow requests', :name => url, :size => ms.to_f)
19
+ add_activity(:block => 'content', :name => 'page')
20
+
21
+ # Events to pop up
22
+ add_event(:block => 'info', :name => "Logins", :message => "Login...", :update_stats => true, :color => [0.5, 1.0, 0.5, 1.0]) if url.include?('/login')
23
+ add_event(:block => 'info', :name => "Sales", :message => "$", :update_stats => true, :color => [1.5, 0.0, 0.0, 1.0]) if url.include?('/checkout')
24
+ add_event(:block => 'info', :name => "Signups", :message => "New User...", :update_stats => true, :color => [1.0, 1.0, 1.0, 1.0]) if(url.include?('/signup') || url.include?('/users/create'))
25
+ elsif line.include?('Processing ')
26
+ #Processing TasksController#update_sheet_info (for 123.123.123.123 at 2007-10-05 22:34:33) [POST]
27
+ _, host = /^Processing .* \(for (\d+.\d+.\d+.\d+) at .*\).*$/.match(line).to_a
28
+ if host
29
+ add_activity(:block => 'users', :name => host)
30
+ end
31
+ elsif line.include?('Error (')
32
+ _, error, msg = /^([^ ]+Error) \((.*)\):/.match(line).to_a
33
+ if error
34
+ add_event(:block => 'info', :name => "Exceptions", :message => error, :update_stats => true, :color => [1.0, 0.0, 0.0, 1.0])
35
+ add_event(:block => 'info', :name => "Exceptions", :message => msg, :update_stats => false, :color => [1.0, 0.0, 0.0, 1.0])
36
+ add_activity(:block => 'warnings', :name => msg)
37
+
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,25 @@
1
+ # gl_tail.rb - OpenGL visualization of your server traffic
2
+ # Copyright 2007 Erlend Simonsen <mr@fudgie.org>
3
+ #
4
+ # Licensed under the GNU General Public License v2 (see LICENSE)
5
+ #
6
+
7
+ # Parser which handles squid logs
8
+ class SquidParser < Parser
9
+ def parse( line )
10
+ _, delay, host, size, method, uri, user = /\d+.\d+ +(\d+) +(\d+.\d+.\d+.\d+.\d+).+ (\d+) (.+) (.+) (.+) .+ .+/.match(line).to_a
11
+ if host
12
+ if method != 'ICP_QUERY'
13
+ size = size.to_f / 100000.0
14
+ #Uncomment if you authenticate to use the proxy
15
+ #add_activity(:block => 'users', :name => user, :size => size)
16
+ add_activity(:block => 'hosts', :name => host, :size => size)
17
+ add_activity(:block => 'types', :name => method, :size => size) if method
18
+ _, site = /http:\/\/(.+?)\/.+/.match(uri).to_a
19
+ if site:
20
+ add_activity(:block => 'sites', :name => site, :size => size)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # gl_tail.rb - OpenGL visualization of your server traffic
2
+ # Copyright 2007 Erlend Simonsen <mr@fudgie.org>
3
+ #
4
+ # Licensed under the GNU General Public License v2 (see LICENSE)
5
+ #
6
+
7
+ # Parser which handles tshark logs
8
+ class TSharkParser < Parser
9
+
10
+ def parse( line )
11
+ if(line.include?('->'))
12
+ time, srcip, arrow, destip, type, = line.split(" ")
13
+ add_activity(:block => 'users', :name => srcip)
14
+ add_activity(:block => 'types', :name => type)
15
+ end
16
+
17
+ if(line.include?('DNS Standard query A'))
18
+ foo, name = line.split(" A ")
19
+ if(name != nil)
20
+ add_event(:block => 'status', :name => "DNS Queries", :message => "DNS Request: " + name, :update_stats => true, :color => [1.5, 1.0, 0.5, 1.0])
21
+ end
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,69 @@
1
+ require 'resolv-replace'
2
+
3
+ class Resolver
4
+ include GlTail::Configurable
5
+
6
+ config_attribute :reverse_ip_lookups, "Lookup Hostnames"
7
+ config_attribute :reverse_timeout, "Wait how long for DNS reply [s]"
8
+
9
+ def self.instance
10
+ @@instance ||= Resolver.new
11
+ end
12
+
13
+ def initialize
14
+ @cache = { }
15
+ @thread = nil
16
+ @reverse_ip_lookups = true
17
+ @reverse_timeout = 1.5
18
+ @queue = Queue.new
19
+ end
20
+
21
+ attr_reader :queue, :cache
22
+
23
+ def start
24
+ @thread = Thread.new {
25
+ while @reverse_ip_lookups
26
+ ip, element = @queue.pop
27
+ if @cache.include? ip
28
+ element.name = @cache[ip]
29
+ else
30
+ begin
31
+ timeout(@reverse_timeout.to_f) {
32
+ puts "[Resolver] Looking for #{ip}" if $DBG > 0
33
+ hostname = Resolv.getname(ip)
34
+ puts "[Resolver] Got #{hostname}[#{ip}]" if $DBG > 0
35
+ @cache[ip] = hostname
36
+ element.name = hostname
37
+ }
38
+ rescue Timeout::Error
39
+ puts "[Resolver] Timeout!" if $DBG > 0
40
+ rescue Resolv::ResolvError
41
+ # No result, don't bother retrying
42
+ @cache[ip] = ip
43
+ end
44
+ end
45
+ end
46
+ }
47
+ end
48
+
49
+ def lookup(ip, element)
50
+ return ip if not @reverse_ip_lookups
51
+
52
+ if name = cache[ip]
53
+ return name
54
+ else
55
+ puts "[Resolver] Pushing #{ip} for lookup" if $DBG > 0
56
+ queue.push([ip, element])
57
+ end
58
+
59
+ return ip
60
+
61
+ end
62
+
63
+ def self.resolv(ip, element)
64
+ instance.lookup(ip, element)
65
+ end
66
+
67
+ end
68
+
69
+ Resolver.instance.start
@@ -0,0 +1,46 @@
1
+ # gl_tail.rb - OpenGL visualization of your server traffic
2
+ # Copyright 2007 Erlend Simonsen <mr@fudgie.org>
3
+ #
4
+ # Licensed under the GNU General Public License v2 (see LICENSE)
5
+ #
6
+
7
+ class Server
8
+ attr_reader :name, :host, :color, :parser
9
+
10
+
11
+ def initialize(options)
12
+ @name = options[:name] || options[:host]
13
+ @host = options[:host]
14
+ @color = options[:color] || [1.0, 1.0, 1.0, 1.0]
15
+ @parser = Parser.registry[ options[:parser] ] || Parser.registry[ :apache ]
16
+ @blocks = options[:blocks]
17
+ @max_size = 1.0
18
+
19
+ # instantiate the parser
20
+ @parser = @parser.new( self )
21
+
22
+ end
23
+
24
+ #block, message, size
25
+ def add_activity(options = { })
26
+ size = $CONFIG.min_blob_size
27
+ if options[:size]
28
+ size = options[:size].to_f
29
+ @max_size = size if size > @max_size
30
+ size = $CONFIG.min_blob_size + ((size / @max_size) * ($CONFIG.max_blob_size - $CONFIG.min_blob_size))
31
+ options[:size] = size
32
+ end
33
+
34
+ block = @blocks[options[:block]].add_activity( { :name => @name, :color => @color, :size => $CONFIG.min_blob_size }.update(options) ) if (options[:block] && @blocks[options[:block]])
35
+ end
36
+
37
+ #block, message
38
+ def add_event(options = { })
39
+ block = @blocks[options[:block]].add_event( { :name => @name, :color => @color, :size => $CONFIG.min_blob_size}.update(options) ) if (options[:block] && @blocks[options[:block]])
40
+ end
41
+
42
+ def update
43
+ @max_size = @max_size * 0.99 if(@max_size * 0.99 > 1.0)
44
+ end
45
+
46
+ end