-
Notifications
You must be signed in to change notification settings - Fork 299
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implementation of RawSocket using ljsyscall #655
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
70c05c7
Remove apps/socket/io.{c,h}
dpino f975447
Remove lib/raw/raw.{c,h}
dpino d153be8
Implement RawSocket using ljsyscall
dpino bbff56a
Merge RawSocketDev into RawSocket
dpino e522ee7
Avoid memory leak on error in RawSocket:receive
dpino 8ebd725
Use packet API to access data and length
dpino b4d6f08
Raise exception on error
dpino File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,72 +1,122 @@ | ||
module(...,package.seeall) | ||
module(..., package.seeall) | ||
|
||
local app = require("core.app") | ||
local link = require("core.link") | ||
local S = require("syscall") | ||
local h = require("syscall.helpers") | ||
local bit = require("bit") | ||
local link = require("core.link") | ||
local packet = require("core.packet") | ||
local dev = require("apps.socket.dev").dev | ||
local ffi = require("ffi") | ||
local C = ffi.C | ||
|
||
local c, t = S.c, S.types.t | ||
|
||
RawSocket = {} | ||
|
||
function RawSocket:new (ifname) | ||
assert(ifname) | ||
self.__index = self | ||
return setmetatable({dev = dev:new(ifname)}, self) | ||
local tp = h.htons(c.ETH_P["ALL"]) | ||
local sock, err = S.socket(c.AF.PACKET, bit.bor(c.SOCK.RAW, c.SOCK.NONBLOCK), tp) | ||
if not sock then error(err) end | ||
local index, err = S.util.if_nametoindex(ifname, sock) | ||
if err then | ||
S.close(sock) | ||
error(err) | ||
end | ||
local addr = t.sockaddr_ll{sll_family = c.AF.PACKET, sll_ifindex = index, sll_protocol = tp} | ||
local ok, err = S.bind(sock, addr) | ||
if not ok then | ||
S.close(sock) | ||
error(err) | ||
end | ||
return setmetatable({sock = sock}, {__index = RawSocket}) | ||
end | ||
|
||
function RawSocket:pull () | ||
local l = self.output.tx | ||
if l == nil then return end | ||
while not link.full(l) and self.dev:can_receive() do | ||
link.transmit(l, self.dev:receive()) | ||
while not link.full(l) and self:can_receive() do | ||
link.transmit(l, self:receive()) | ||
end | ||
end | ||
|
||
function RawSocket:can_receive () | ||
local ok, err = S.select({readfds = {self.sock}}, 0) | ||
return not (err or ok.count == 0) | ||
end | ||
|
||
function RawSocket:receive () | ||
local buffer = ffi.new("uint8_t[?]", C.PACKET_PAYLOAD_SIZE) | ||
local sz, err = S.read(self.sock, buffer, C.PACKET_PAYLOAD_SIZE) | ||
if not sz then return err end | ||
return packet.from_pointer(buffer, sz) | ||
end | ||
|
||
function RawSocket:push () | ||
local l = self.input.rx | ||
if l == nil then return end | ||
while not link.empty(l) and self.dev:can_transmit() do | ||
while not link.empty(l) and self:can_transmit() do | ||
local p = link.receive(l) | ||
self.dev:transmit(p) | ||
self:transmit(p) | ||
packet.free(p) | ||
end | ||
end | ||
|
||
function RawSocket:can_transmit () | ||
local ok, err = S.select({writefds = {self.sock}}, 0) | ||
return not (err or ok.count == 0) | ||
end | ||
|
||
function RawSocket:transmit (p) | ||
local sz, err = S.write(self.sock, packet.data(p), packet.length(p)) | ||
if not sz then return err end | ||
return sz | ||
end | ||
|
||
function RawSocket:stop() | ||
S.close(self.sock) | ||
end | ||
|
||
function selftest () | ||
-- Send a packet over the loopback device and check | ||
-- that it is received correctly. | ||
-- XXX beware of a race condition with unrelated traffic over the | ||
-- loopback device | ||
-- XXX Beware of a race condition with unrelated traffic over the | ||
-- loopback device. | ||
local datagram = require("lib.protocol.datagram") | ||
local ethernet = require("lib.protocol.ethernet") | ||
local ipv6 = require("lib.protocol.ipv6") | ||
|
||
-- Initialize RawSocket. | ||
local lo = RawSocket:new("lo") | ||
lo.input, lo.output = {}, {} | ||
lo.input.rx, lo.output.tx = link.new("test1"), link.new("test2") | ||
-- Construct packet. | ||
local dg_tx = datagram:new() | ||
local src = ethernet:pton("02:00:00:00:00:01") | ||
local dst = ethernet:pton("02:00:00:00:00:02") | ||
local localhost = ipv6:pton("0:0:0:0:0:0:0:1") | ||
dg_tx:push(ipv6:new({src = localhost, | ||
dst = localhost, | ||
next_header = 59, -- no next header | ||
next_header = 59, -- No next header. | ||
hop_limit = 1})) | ||
dg_tx:push(ethernet:new({src = src, dst = dst, type = 0x86dd})) | ||
|
||
local link = require("core.link") | ||
local lo = RawSocket:new("lo") | ||
lo.input, lo.output = {}, {} | ||
lo.input.rx, lo.output.tx = link.new("test1"), link.new("test2") | ||
dg_tx:push(ethernet:new({src = src, | ||
dst = dst, | ||
type = 0x86dd})) | ||
-- Transmit packet. | ||
link.transmit(lo.input.rx, dg_tx:packet()) | ||
lo:push() | ||
-- Receive packet. | ||
lo:pull() | ||
local dg_rx = datagram:new(link.receive(lo.output.tx), ethernet) | ||
assert(dg_rx:parse({ { ethernet, function(eth) | ||
return(eth:src_eq(src) and eth:dst_eq(dst) | ||
and eth:type() == 0x86dd) | ||
end }, | ||
{ ipv6, function(ipv6) | ||
return(ipv6:src_eq(localhost) and | ||
ipv6:dst_eq(localhost)) | ||
end } }), "loopback test failed") | ||
-- Assert packet was received OK. | ||
assert(dg_rx:parse({{ethernet, function(eth) | ||
return(eth:src_eq(src) and eth:dst_eq(dst) and eth:type() == 0x86dd) | ||
end }, { ipv6, function(ipv6) | ||
return(ipv6:src_eq(localhost) and ipv6:dst_eq(localhost)) | ||
end } }), "loopback test failed") | ||
lo:stop() | ||
print("selftest passed") | ||
|
||
-- Another useful test would be to feed a pcap file with | ||
-- XXX Another useful test would be to feed a pcap file with | ||
-- pings to 127.0.0.1 and ::1 into lo and capture/compare | ||
-- the responses with a pre-recorded pcap. | ||
end |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that a
packet.free(p)
is needed here to avoid a resource leak.