Files
nebula/dist/wireshark/nebula.lua
T
zorvios 02471b4121
smoke-extra / Run windows smoke test (push) Waiting to run
Build and test / Test macos (push) Waiting to run
Build and test / Test windows (push) Waiting to run
Build and test / CI status (push) Blocked by required conditions
smoke-extra / freebsd-amd64 (push) Failing after 16s
smoke-extra / linux-amd64-ipv6disable (push) Failing after 16s
smoke-extra / netbsd-amd64 (push) Failing after 14s
smoke-extra / openbsd-amd64 (push) Failing after 14s
smoke-extra / linux-386 (push) Failing after 14s
smoke / Run multi node smoke test (push) Failing after 1m27s
Build and test / Static checks (push) Successful in 1m46s
Build and test / Test linux (push) Failing after 1m41s
Build and test / Test linux-boringcrypto (push) Failing after 2m49s
Build and test / Test linux-pkcs11 (push) Failing after 2m49s
Build and test / Cross-build linux-arm (push) Successful in 3m1s
Build and test / Cross-build linux-mips (push) Successful in 3m41s
Build and test / Cross-build linux-other (push) Successful in 3m4s
Build and test / Cross-build windows (push) Successful in 1m1s
Build and test / Cross-build freebsd (push) Successful in 1m32s
Build and test / Cross-build netbsd (push) Successful in 1m33s
Build and test / Cross-build openbsd (push) Successful in 1m31s
Build and test / Cross-build mobile (push) Successful in 3m12s
wireshark: fix Lua 5.4 bitwise operation (#1776)
The Nebula Wireshark dissector uses bit32.band() when parsing the
Nebula packet type. On Wireshark builds using Lua 5.4, bit32 is not
available, which causes dissection to fail with:

Lua Error: nebula.lua:65: attempt to index a nil value (global 'bit32')

Wireshark bundles Lua BitOp and exposes it globally as bit for Lua
dissectors. This is the documented API for maximum backwards
compatibility across supported Lua versions.

Use bit.band() instead of bit32.band().
2026-07-01 16:12:14 -05:00

108 lines
4.3 KiB
Lua

local nebula = Proto("nebula", "nebula")
local default_settings = {
port = 4242,
all_ports = false,
}
nebula.prefs.port = Pref.uint("Port number", default_settings.port, "The UDP port number for Nebula")
nebula.prefs.all_ports = Pref.bool("All ports", default_settings.all_ports, "Assume nebula packets on any port, useful when dealing with hole punching")
local pf_version = ProtoField.new("version", "nebula.version", ftypes.UINT8, nil, base.DEC, 0xF0)
local pf_type = ProtoField.new("type", "nebula.type", ftypes.UINT8, {
[0] = "handshake",
[1] = "message",
[2] = "recvError",
[3] = "lightHouse",
[4] = "test",
[5] = "closeTunnel",
}, base.DEC, 0x0F)
local pf_subtype = ProtoField.new("subtype", "nebula.subtype", ftypes.UINT8, nil, base.DEC)
local pf_subtype_test = ProtoField.new("subtype", "nebula.subtype", ftypes.UINT8, {
[0] = "request",
[1] = "reply",
}, base.DEC)
local pf_subtype_handshake = ProtoField.new("subtype", "nebula.subtype", ftypes.UINT8, {
[0] = "ix_psk0",
}, base.DEC)
local pf_reserved = ProtoField.new("reserved", "nebula.reserved", ftypes.UINT16, nil, base.HEX)
local pf_remote_index = ProtoField.new("remote index", "nebula.remote_index", ftypes.UINT32, nil, base.DEC)
local pf_message_counter = ProtoField.new("counter", "nebula.counter", ftypes.UINT64, nil, base.DEC)
local pf_payload = ProtoField.new("payload", "nebula.payload", ftypes.BYTES, nil, base.NONE)
nebula.fields = { pf_version, pf_type, pf_subtype, pf_subtype_handshake, pf_subtype_test, pf_reserved, pf_remote_index, pf_message_counter, pf_payload }
local ef_holepunch = ProtoExpert.new("nebula.holepunch.expert", "Nebula hole punch packet", expert.group.PROTOCOL, expert.severity.NOTE)
local ef_punchy = ProtoExpert.new("nebula.punchy.expert", "Nebula punchy keepalive packet", expert.group.PROTOCOL, expert.severity.NOTE)
nebula.experts = { ef_holepunch, ef_punchy }
local type_field = Field.new("nebula.type")
local subtype_field = Field.new("nebula.subtype")
function nebula.dissector(tvbuf, pktinfo, root)
-- set the protocol column to show our protocol name
pktinfo.cols.protocol:set("NEBULA")
local pktlen = tvbuf:reported_length_remaining()
local tree = root:add(nebula, tvbuf:range(0,pktlen))
if pktlen == 0 then
tree:add_proto_expert_info(ef_holepunch)
pktinfo.cols.info:append(" (holepunch)")
return
elseif pktlen == 1 then
tree:add_proto_expert_info(ef_punchy)
pktinfo.cols.info:append(" (punchy)")
return
end
tree:add(pf_version, tvbuf:range(0,1))
local type = tree:add(pf_type, tvbuf:range(0,1))
local nebula_type = bit.band(tvbuf:range(0,1):uint(), 0x0F)
if nebula_type == 0 then
local stage = tvbuf(8,8):uint64()
tree:add(pf_subtype_handshake, tvbuf:range(1,1))
type:append_text(" stage " .. stage)
pktinfo.cols.info:append(" (" .. type_field().display .. ", stage " .. stage .. ", " .. subtype_field().display .. ")")
elseif nebula_type == 4 then
tree:add(pf_subtype_test, tvbuf:range(1,1))
pktinfo.cols.info:append(" (" .. type_field().display .. ", " .. subtype_field().display .. ")")
else
tree:add(pf_subtype, tvbuf:range(1,1))
pktinfo.cols.info:append(" (" .. type_field().display .. ")")
end
tree:add(pf_reserved, tvbuf:range(2,2))
tree:add(pf_remote_index, tvbuf:range(4,4))
tree:add(pf_message_counter, tvbuf:range(8,8))
tree:add(pf_payload, tvbuf:range(16,tvbuf:len() - 16))
end
function nebula.prefs_changed()
if default_settings.all_ports == nebula.prefs.all_ports and default_settings.port == nebula.prefs.port then
return
end
-- Remove all existing registrations
DissectorTable.get("udp.port"):remove_all(nebula)
if nebula.prefs.all_ports then
-- Register on every port for hole punch capture
for i=0, 65535 do
DissectorTable.get("udp.port"):add(i, nebula)
end
else
-- Register on the configured port only
DissectorTable.get("udp.port"):add(nebula.prefs.port, nebula)
end
default_settings.all_ports = nebula.prefs.all_ports
default_settings.port = nebula.prefs.port
end
DissectorTable.get("udp.port"):add(default_settings.port, nebula)