Skip to content

Commit

Permalink
Import pcap file reader and writer from snabbswitch.
Browse files Browse the repository at this point in the history
savefile.lua was originally snabbswitch/src/lib/pcap/pcap.lua in
snabbswitch, and was written by Luke Gorrie.  It is under the Apache 2.0
license, like pflua.
  • Loading branch information
wingo committed Jun 24, 2014
1 parent 86d4f60 commit 89b0047
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 2 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
Andy Wingo <[email protected]>
Javier Muñoz <[email protected]>
Luke Gorrie <[email protected]>
4 changes: 2 additions & 2 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Copyright (C) 2014 Igalia, S.L.
Copyright (C) 2014 Igalia, S.L. and others

Pflua (the "Software") is licensed under the Apache License, Version 2.0
pflua (the "Software") is licensed under the Apache License, Version 2.0
(the "License"); you may not use the Software except in compliance with
the License. You may obtain a copy of the License in the COPYING file
located in this same directory, or at
Expand Down
94 changes: 94 additions & 0 deletions src/pf/savefile.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
module(...,package.seeall)

local ffi = require("ffi")

-- PCAP file format: http://wiki.wireshark.org/Development/LibpcapFileFormat/
ffi.cdef[[
struct pcap_file {
/* file header */
uint32_t magic_number; /* magic number */
uint16_t version_major; /* major version number */
uint16_t version_minor; /* minor version number */
int32_t thiszone; /* GMT to local correction */
uint32_t sigfigs; /* accuracy of timestamps */
uint32_t snaplen; /* max length of captured packets, in octets */
uint32_t network; /* data link type */
};

struct pcap_record {
/* record header */
uint32_t ts_sec; /* timestamp seconds */
uint32_t ts_usec; /* timestamp microseconds */
uint32_t incl_len; /* number of octets of packet saved in file */
uint32_t orig_len; /* actual length of packet */
};

struct pcap_record_extra {
/* Extra metadata that we append to the pcap record, after the payload. */
uint32_t port_id; /* port the packet is captured on */
uint32_t flags; /* bit 0 set means input, bit 0 clear means output */
uint64_t reserved0, reserved1, reserved2, reserved3;
};
]]

function write_file_header(file)
local pcap_file = ffi.new("struct pcap_file")
pcap_file.magic_number = 0xa1b2c3d4
pcap_file.version_major = 2
pcap_file.version_minor = 4
pcap_file.snaplen = 65535
pcap_file.network = 1
file:write(ffi.string(pcap_file, ffi.sizeof(pcap_file)))
file:flush()
end

local pcap_extra = ffi.new("struct pcap_record_extra")
ffi.fill(pcap_extra, ffi.sizeof(pcap_extra), 0)

function write_record (file, ffi_buffer, length)
write_record_header(file, length)
file:write(ffi.string(ffi_buffer, length))
file:flush()
end

function write_record_header (file, length)
local pcap_record = ffi.new("struct pcap_record")
pcap_record.incl_len = length
pcap_record.orig_len = length
file:write(ffi.string(pcap_record, ffi.sizeof(pcap_record)))
end

-- Return an iterator for pcap records in FILENAME.
function records (filename)
local file = io.open(filename, "r")
if file == nil then error("Unable to open file: " .. filename) end
local pcap_file = readc(file, "struct pcap_file")
if pcap_file.magic_number == 0xD4C3B2A1 then
error("Endian mismatch in " .. filename)
elseif pcap_file.magic_number ~= 0xA1B2C3D4 then
error("Bad PCAP magic number in " .. filename)
end
local function pcap_records_it (t, i)
local record = readc(file, "struct pcap_record")
if record == nil then return nil end
local datalen = math.min(record.orig_len, record.incl_len)
local packet = file:read(datalen)
local extra = nil
if record.incl_len == #packet + ffi.sizeof("struct pcap_record_extra") then
extra = readc(file, "struct pcap_record_extra")
end
return packet, record, extra
end
return pcap_records_it, true, true
end

-- Read a C object of TYPE from FILE. Return a pointer to the result.
function readc(file, type)
local string = file:read(ffi.sizeof(type))
if string == nil then return nil end
if #string ~= ffi.sizeof(type) then
error("short read of " .. type .. " from " .. tostring(file))
end
return ffi.cast(type.."*", string)
end

0 comments on commit 89b0047

Please sign in to comment.