Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Socket inactivity/leak detector
-- Chisel description
description = "Detects inactivity/leak on sockets"
short_description = "Socket inactivity/leak detector"
category = "Net"
-- Chisel argument list
args =
{
{
name = "inactivity_period",
description = "minimum number of milliseconds before detecting socket as staled",
argtype = "int"
},
{
name = "debug",
description = "Show diagnostic messages",
argtype = "string"
},
}
require "common"
-- Argument notification callback
function on_set_arg(name, val)
setters = {
["inactivity_period"] = function (val) inactivity_period = val * 1e6 end,
["debug"] = function (val) debug = val end,
}
setters[name](val)
return true
end
-- Initialization callback
function on_init()
-- Request the fileds that we need
ftime = chisel.request_field("evt.rawtime")
ftype = chisel.request_field("evt.type")
fdir = chisel.request_field("evt.dir")
fip = chisel.request_field("fd.ip")
fname = chisel.request_field("fd.name")
fisio = chisel.request_field("evt.is_io")
fproto = chisel.request_field("fd.l4proto")
fserver = chisel.request_field("fd.is_server")
fnum = chisel.request_field("fd.num")
fprocid = chisel.request_field("proc.pid")
chisel.set_interval_ns(inactivity_period / 10)
condition_tcp_in = {[fdir] = "<", [fproto] = "tcp"}
condition_tcp_out = {[fdir] = ">", [fproto] = "tcp"}
return true
end
function fd_id(evt)
return "proc:" .. (evt.field(fprocid) or "-").. ",fd:" .. (evt.field(fnum) or "-")
end
function print_if_debug(evt, ...)
if (debug == "true") then
print("[proc " .. evt.field(fprocid) .. "] " .. string.format(...))
end
end
function precond_all(evt, fields)
met = true
for field, value in pairs(fields) do
if (evt.field(field) ~= value) then
met = false
end
end
return met
end
tracked_cons = {}
-- Event parsing callback
function on_event()
conn_id = fd_id(evt)
-- socket was opened
if ((evt.field(ftype) == 'accept' or evt.field(ftype) == 'connect') and precond_all(evt, condition_tcp_in)) then
print_if_debug(evt, "Opened TCP/IP connection with %-8s: %s", evt.field(ftype), evt.field(fname))
tracked_cons[conn_id] = {
["opened"] = evt.field(ftime),
["accessed"] = evt.field(ftime),
["tuple"] = evt.field(fname),
["process"] = evt.field(fprocid),
["reported"] = false
}
end
-- socket was closed
if ((evt.field(ftype) == 'close' or evt.field(ftype) == 'shutdown') and precond_all(evt, condition_tcp_out)) then
print_if_debug(evt, "Closed TCP/IP connection with %-8s: %s", evt.field(ftype), evt.field(fname))
tracked_cons[conn_id] = nil
end
-- untrack on process exit
if (evt.field(ftype) == 'procexit') then
for pid, info in pairs(tracked_cons) do
if (string.match(pid, "proc:" .. evt.field(fprocid))) then
print_if_debug(evt, "Closed TCP/IP connection on shutdown : %s", info["tuple"])
tracked_cons[pid] = null;
end
end
end
-- socket was used - update access time
if (evt.field(fisio)) and precond_all(evt, condition_tcp_out) then
if (tracked_cons[conn_id]) then
tracked_cons[conn_id].accessed = evt.field(ftime)
tracked_cons[conn_id].reported = false
end
end
return true
end
-- End of capture callback
function on_capture_end(ts_s, ts_ns, delta)
count = table.getn(tracked_cons)
print("\nStill opened sockets (" .. count .. "):\n--------")
for id, values in pairs(tracked_cons) do
-- delta can be used to compare relative times
access_delta = (ts_s * 1e9 + ts_ns) - values.accessed
if (access_delta > inactivity_period) then
print(string.format("[proc %s] Inactivity of %s on socket %s (threshold: %s)", values.process, format_time_interval(access_delta), values.tuple, format_time_interval(inactivity_period)))
end
end
if (count == 0) then
print("Zero? Try adjusting threshold")
end
print("--------")
return true
end
function on_interval(ts_s, ts_ns, delta)
for id, values in pairs(tracked_cons) do
-- delta can be used to compare relative times
access_delta = (ts_s * 1e9 + ts_ns) - values.accessed
if (values.reported == false and access_delta > inactivity_period) then
print(string.format("[proc %s] Inactivity of %s on socket %s (threshold: %s)", values.process, format_time_interval(access_delta), values.tuple, format_time_interval(inactivity_period)))
values.reported = true
end
end
return true
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment