This repository has been archived by the owner on May 25, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathapp.coffee
199 lines (161 loc) · 5.48 KB
/
app.coffee
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
197
198
###
✿ flower
2012 Yao Wei <mwei@lxde.org>
###
config = require './config'
express = require 'express'
dgram = require 'dgram'
NetflowPacket = require 'Netflow/lib/NetFlowPacket'
app = module.exports = express.createServer()
model = require './model'
cronJob = require('cron').CronJob
io = require('socket.io').listen(app)
# Configuration
app.configure ->
app.set 'views', __dirname + '/views'
app.set 'view engine', 'jade'
app.use express.bodyParser()
app.use express.methodOverride()
app.use app.router
app.use express.static(__dirname + '/public')
# add dummy data on development mode
app.configure 'development', ->
app.use express.errorHandler({ dumpExceptions: true, showStack: true })
dummy = model.daily.getIp "127.0.0.1"
dummy.upload = 123456789
dummy.download = 987654321
app.configure 'production', ->
app.use express.errorHandler()
# socket.io configuration in production
io.enable 'browser client minification' # send minified client
io.enable 'browser client etag' # apply etag caching logic based on version number
io.enable 'browser client gzip' # gzip the file
io.set 'log level', 1 # reduce logging
io.set 'transports', ['websocket', 'flashsocket', 'htmlfile', 'xhr-polling', 'jsonp-polling']
# socket.io events
pushingTargets = {}
io.sockets.on 'connection', (socket) ->
socket.emit 'ready'
socket.on 'set ip', (data) ->
if config.ipRule data.ip
socket.set 'ip', data.ip, ->
pushingTargets[socket.id] = {ip: data.ip, socket: socket}
socket.on 'update graph', ->
socket.get 'ip', (error, ip) ->
model.hourly.getHistoryPlot ip, (historyPlot) ->
socket.emit 'graph update', historyPlot
socket.on 'disconnect', ->
socket.get 'ip', (error, ip) ->
delete pushingTargets[socket.id] if socket.id in pushingTargets
# Packet receiving event
netflowClient = dgram.createSocket "udp4"
netflowClient.on "message", (mesg, rinfo) ->
try
packet = new NetflowPacket mesg
if packet.header.version == 5
updatedIps = {}
for flow in packet.v5Flows
srcIp = flow.srcaddr.join '.'
srcIpInbound = config.ipRule srcIp
dstIp = flow.dstaddr.join '.'
dstIpInbound = config.ipRule dstIp
if dstIpInbound and not srcIpInbound # this flow means download
ip = dstIp
status = "download"
bytes = flow.dOctets
else if srcIpInbound and not dstIpInbound # this flow means upload
ip = srcIp
status = "upload"
bytes = flow.dOctets
else
continue # not interested
continue if not config.ipRule ip
ipData = model.daily.getIp ip
hourlyIpData = model.hourly.getIp ip
switch status
when "upload"
ipData.addUpload bytes
hourlyIpData.addUpload bytes
when "download"
ipData.addDownload bytes
hourlyIpData.addDownload bytes
updatedIps[ip] = 1
# TODO: do banning in packet receiving event
for socketId, target of pushingTargets
if target.ip of updatedIps
target.socket.volatile.emit 'update', model.daily.getIp(target.ip)
catch err
console.error "* error receiving Netflow message: #{err}"
# Some global variables used for view
global.views = {
siteName: config.siteName
siteUri: config.siteUri
# TODO sidebar:
}
# Routes
app.get '/', (req, res) ->
remoteIp = req.connection.remoteAddress
if config.ipRule remoteIp
res.redirect '/'+req.connection.remoteAddress
else
res.redirect '/category'
app.get '/category', (req, res) ->
res.render 'categories'
app.get '/category/:category', (req, res) ->
res.render 'category'
app.get '/banned', (req, res) ->
res.render 'banned'
app.get '/:ip', (req, res, next) ->
ip = req.params.ip
if not config.ipRule ip
res.redirect '/category'
return
ipData = model.daily.getIp ip
model.hourly.getHistoryPlot ip, (historyPlot) ->
res.render 'ip', { ip: ip, ipData: ipData, historyPlot: historyPlot }
app.get '/:ip/log', (req, res) ->
ip = req.params.ip
if not config.ipRule ip
res.redirect '/category'
return
date = new Date()
res.redirect "/#{ip}/log/#{date.getYear}/#{date.getMonth+1}"
app.get '/:ip/log/:year/:month', (req, res) ->
ip = req.params.ip
if not config.ipRule ip
res.redirect '/category'
return
date = new Date(parseInt(req.params.year, 10), parseInt(req.params.month, 10)-1, 1)
model.daily.getHistory ip, date, (error, result) ->
res.render 'daily', {ip: ip, date: date, result: result.rows}
app.get '/:ip/log/:year/:month/:day', (req, res) ->
# get from a single day.
# Restore values from database, and launch the system.
loadDatabase = (callback)->
model.daily.restore ->
model.hourly.restore ->
callback()
setupCronJobs = ->
new cronJob '0 0 0 * * *', ->
model.daily.rotate()
, null, true
new cronJob '0 0 * * * *', ->
model.hourly.rotate()
, null, true
new cronJob '1 */10 * * * *', ->
model.daily.save()
model.hourly.save()
console.log "* data upserted at #{new Date()}"
, null, true
launch = ->
# start cron jobs
setupCronJobs()
# start listening
netflowClient.bind config.netflowPort
app.listen config.httpPort
console.log "✿ flower"
console.log "* running under #{app.settings.env} environment"
console.log "* listening on port #{app.address().port} for web server"
console.log "* listening on port #{netflowClient.address().port} for netflow client"
# ready, set, go!
loadDatabase launch