Skip to content

Conversation

@sneaky-potato
Copy link
Contributor

@sneaky-potato sneaky-potato commented Jan 3, 2026

We need separate call signatures for

  • receiving socket (protocol is required, passed in the form of packed string)
  • transmitting socket (only numeric interface index is passed to bind)

Related PR
#360

@sneaky-potato
Copy link
Contributor Author

If we want to do this in a single new method, we can pass whatever arguments we get to the bind call
something like this

-- Arguments are forwarded verbatim to socket:bind().
--
-- Examples:
--   raw.new(string.pack(">H", ETH_P_ALL), ifindex) RX-style bind
--   raw.new(ifindex) TX-style bind
--   raw.new() unbound socket
--
function raw.new(...)
    local s = socket.new(af.PACKET, sock.RAW)

    local argc = select("#", ...)
    if argc > 0 then
        s:bind(...)
    end

    return s
end

return raw

s:bind(string.pack(">H", proto), ifindex)
return s
local s = socket.new(af.PACKET, sock.RAW, proto)
s:bind(string.pack(">H", proto), ifindex)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this work for sending as well? Are you sure?

Copy link
Contributor Author

@sneaky-potato sneaky-potato Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to use this form to send frames over raw socket

local function worker()
	local tx <close> = socket.new(socket.af.PACKET, socket.sock.RAW, ETH_P_LLDP)
	tx:bind(string.pack(">H", ETH_P_LLDP), ifindex)

	while (not shouldstop()) do
		tx:send(lldp_frame)
		print(string.format("[lldpd] frame sent on ifindex=%d (%d bytes)", ifindex, #lldp_frame))
		linux.schedule(config.tx_interval_ms)
	end

	print("[lldpd] worker stopped")
end

return worker

got this error
[ 495.463722] luathread: [000000004887f053] ENXIO

The socket starts working when called with bind(ifindex)

Copy link
Contributor Author

@sneaky-potato sneaky-potato Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this branch executes when bind is called with string parameter.
So it blindly copies 2 bytes (ETH_P_LLDP) into sockaddr_storage.__data
Everything else is uninitialized garbage. (This explains ENXIO no such device error)

Summary

  • bind(ifindex) binds on a specific interface (this cannot be used to capture traffic because protocol is never set in this case)
  • bind(string.pack(">H", proto)) binds on all interfaces (0) (should be used when receiving frames)
  • anything else does not make sense

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were using ">I2" instead ">H" on tap.. why did you change it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I read this line in the documentation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's correct as short might vary depending on arch.. I would fix both the code and the doc

-- @see socket.new
-- @see socket.bind
function raw.tx(proto, ifindex)
local s = socket.new(af.PACKET, sock.RAW, proto)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would create a "new" function just to avoid repeat this line.. not fond of tx/Rx but couldn't figure better names.. it's up to you.. I can merge it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about bind and connect as the names for the methods?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better from the API client's perspective.. though it sounds a bit misleading to bind() on connect(), I will leave this decision to you ;-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a single bind call will suffice, we can call bind(ifindex) if ifindex is given else the usual listening socket bind(string.pack(">I2", proto))

Copy link
Contributor

@lneto lneto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah.. you need to add this to config.ld right?

@sneaky-potato sneaky-potato force-pushed the raw-socket-pattern-fix branch 2 times, most recently from 66c7e1e to 9bf99e5 Compare January 4, 2026 10:08
@sneaky-potato
Copy link
Contributor Author

@lneto from the luasocket_bind and more specifically luasocket_checkaddr, it seems that binding a listening AF_PACKET socket to a specific interface is not currently supported.

For AF_PACKET

  • when the argument is a number, it is always interpreted as sll_ifindex, and no path sets sll_protocol.
  • string-based path copies raw bytes into sockaddr_storage but does not populate struct sockaddr_ll fields in a structured way.

For a listening raw socket bound to an interface, we would need something equivalent to:

sll_protocol = htons(ETH_P_ALL);
sll_ifindex  = ifindex;

Currently there’s no way to express this combination from Lua. Is this by design? If not, would it make sense to open an issue to track proper AF_PACKET bind support for listening sockets?

Copy link
Contributor

@lneto lneto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's looking good to me, just a small comment.. btw, can you take the opportunity and bump the copyright year of those files as well? thanks

@sneaky-potato sneaky-potato force-pushed the raw-socket-pattern-fix branch from 9bf99e5 to 106d8dd Compare January 4, 2026 13:18
@@ -1,5 +1,5 @@
--
-- SPDX-FileCopyrightText: (c) 2025 Ashwani Kumar Kamal <[email protected]>
-- SPDX-FileCopyrightText: (c) 2026 Ashwani Kumar Kamal <[email protected]>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
-- SPDX-FileCopyrightText: (c) 2026 Ashwani Kumar Kamal <[email protected]>
-- SPDX-FileCopyrightText: (c) 2025-2026 Ashwani Kumar Kamal <[email protected]>

right?

Separate call signatures for raw socket bind call
- rx socket (protocol is required)
- tx socket (interface index is required)

Signed-off-by: Ashwani Kumar Kamal <[email protected]>
@sneaky-potato sneaky-potato force-pushed the raw-socket-pattern-fix branch from 106d8dd to f4a6a25 Compare January 4, 2026 13:47
@lneto lneto merged commit 4c7cc53 into luainkernel:master Jan 4, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants