Skip to content

Commit

Permalink
Merge #1350 branch 'snabbco/max-next' into next
Browse files Browse the repository at this point in the history
  • Loading branch information
lukego committed Jun 19, 2018
2 parents 636a6cb + ffc5ddc commit 7c36e3a
Show file tree
Hide file tree
Showing 8 changed files with 1,252 additions and 4 deletions.
46 changes: 44 additions & 2 deletions src/apps/pcap/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# PcapReader and PcapWriter Apps (apps.pcap.pcap)
# Pcap Savefile Apps

## PcapReader and PcapWriter Apps (apps.pcap.pcap)

The `PcapReader` and `PcapWriter` apps can be used to inject and log raw
packet data into and out of the app network using the
Expand All @@ -14,10 +16,50 @@ port to a PCAP file.
| | | |
+------------+ +------------+

## Configuration
### Configuration

Both `PcapReader` and `PcapWriter` expect a filename string as their
configuration arguments to read from and write to respectively. `PcapWriter`
will alternatively accept an array as its configuration argument, with the
first element being the filename and the second element being a *mode* argument
to `io.open`.

## Tap (apps.pcap.tap)

The `Tap` app is a simple in-band packet tap that writes packets that it
sees to a pcap savefile. It can optionally only write packets that pass
a pcap filter, and optionally subsample so it can write only every /n/th
packet.

DIAGRAM: pcaptap
+-------------------+
input | | output
---->* apps.pcap.tap.Tap *---->
| |
+-------------------+

### Configuration

The `Tap` app accepts a table as its configuration argument. The
following keys are defined:

— Key **filename**

*Required*. The name of the file to which to write the packets.

— Key **mode**

*Optional*. Either `"truncate"` or `"append"`, indicating whether the
savefile will be truncated (the default) or appended to.

— Key **filter**

*Optional*. A pflang filter expression to select packets for tapping.
Only packets that pass this filter will be sampled for the packet tap.

— Key **sample**

*Optional*. A sampling period. Defaults to 1, indicating that every
packet seen by the tap and passing the optional filter string will be
written. Setting this value to 2 will capture every second packet, and
so on.
87 changes: 87 additions & 0 deletions src/apps/pcap/tap.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
-- Use of this source code is governed by the Apache 2.0 license; see COPYING.

module(...,package.seeall)

local ffi = require("ffi")

local app = require("core.app")
local lib = require("core.lib")
local link = require("core.link")
local pcap = require("lib.pcap.pcap")
local pf = require("pf")

Tap = {}

local tap_config_params = {
-- Name of file to which to write packets.
filename = { required=true },
-- "truncate" to truncate the file, or "append" to add to the file.
mode = { default = "truncate" },
-- Only packets that match this pflang filter will be captured.
filter = { },
-- Only write every Nth packet that matches the filter.
sample = { default=1 },
}

function Tap:new(conf)
local o = lib.parse(conf, tap_config_params)
local mode = assert(({truncate='w+b', append='a+b'})[o.mode])
o.file = assert(io.open(o.filename, mode))
if o.file:seek() == 0 then pcap.write_file_header(o.file) end
if o.filter then o.filter = pf.compile_filter(o.filter) end
o.n = o.sample - 1
return setmetatable(o, {__index = Tap})
end

function Tap:push ()
local n = self.n
while not link.empty(self.input.input) do
local p = link.receive(self.input.input)
if not self.filter or self.filter(p.data, p.length) then
n = n + 1
if n == self.sample then
n = 0
pcap.write_record(self.file, p.data, p.length)
end
end
link.transmit(self.output.output, p)
end
self.n = n
end

function selftest ()
print('selftest: apps.pcap.tap')

local config = require("core.config")
local Sink = require("apps.basic.basic_apps").Sink
local PcapReader = require("apps.pcap.pcap").PcapReader

local function run(filter, sample)
local tmp = os.tmpname()
local c = config.new()
-- Re-use example from packet filter test.
config.app(c, "source", PcapReader, "apps/packet_filter/samples/v6.pcap")
config.app(c, "tap", Tap, {filename=tmp, filter=filter, sample=sample})
config.app(c, "sink", Sink )

config.link(c, "source.output -> tap.input")
config.link(c, "tap.output -> sink.input")
app.configure(c)
while not app.app_table.source.done do app.breathe() end

local n = 0
for packet, record in pcap.records(tmp) do n = n + 1 end
os.remove(tmp)

app.configure(config.new())

return n
end

assert(run() == 161)
assert(run("icmp6") == 49)
assert(run(nil, 2) == 81)
assert(run("icmp6", 2) == 25)

print('selftest: ok')
end
Loading

0 comments on commit 7c36e3a

Please sign in to comment.