nebula.lua 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. local nebula = Proto("nebula", "nebula")
  2. local default_settings = {
  3. port = 4242,
  4. all_ports = false,
  5. }
  6. nebula.prefs.port = Pref.uint("Port number", default_settings.port, "The UDP port number for Nebula")
  7. nebula.prefs.all_ports = Pref.bool("All ports", default_settings.all_ports, "Assume nebula packets on any port, useful when dealing with hole punching")
  8. local pf_version = ProtoField.new("version", "nebula.version", ftypes.UINT8, nil, base.DEC, 0xF0)
  9. local pf_type = ProtoField.new("type", "nebula.type", ftypes.UINT8, {
  10. [0] = "handshake",
  11. [1] = "message",
  12. [2] = "recvError",
  13. [3] = "lightHouse",
  14. [4] = "test",
  15. [5] = "closeTunnel",
  16. }, base.DEC, 0x0F)
  17. local pf_subtype = ProtoField.new("subtype", "nebula.subtype", ftypes.UINT8, nil, base.DEC)
  18. local pf_subtype_test = ProtoField.new("subtype", "nebula.subtype", ftypes.UINT8, {
  19. [0] = "request",
  20. [1] = "reply",
  21. }, base.DEC)
  22. local pf_subtype_handshake = ProtoField.new("subtype", "nebula.subtype", ftypes.UINT8, {
  23. [0] = "ix_psk0",
  24. }, base.DEC)
  25. local pf_reserved = ProtoField.new("reserved", "nebula.reserved", ftypes.UINT16, nil, base.HEX)
  26. local pf_remote_index = ProtoField.new("remote index", "nebula.remote_index", ftypes.UINT32, nil, base.DEC)
  27. local pf_message_counter = ProtoField.new("counter", "nebula.counter", ftypes.UINT64, nil, base.DEC)
  28. local pf_payload = ProtoField.new("payload", "nebula.payload", ftypes.BYTES, nil, base.NONE)
  29. nebula.fields = { pf_version, pf_type, pf_subtype, pf_subtype_handshake, pf_subtype_test, pf_reserved, pf_remote_index, pf_message_counter, pf_payload }
  30. local ef_holepunch = ProtoExpert.new("nebula.holepunch.expert", "Nebula hole punch packet", expert.group.PROTOCOL, expert.severity.NOTE)
  31. local ef_punchy = ProtoExpert.new("nebula.punchy.expert", "Nebula punchy keepalive packet", expert.group.PROTOCOL, expert.severity.NOTE)
  32. nebula.experts = { ef_holepunch, ef_punchy }
  33. local type_field = Field.new("nebula.type")
  34. local subtype_field = Field.new("nebula.subtype")
  35. function nebula.dissector(tvbuf, pktinfo, root)
  36. -- set the protocol column to show our protocol name
  37. pktinfo.cols.protocol:set("NEBULA")
  38. local pktlen = tvbuf:reported_length_remaining()
  39. local tree = root:add(nebula, tvbuf:range(0,pktlen))
  40. if pktlen == 0 then
  41. tree:add_proto_expert_info(ef_holepunch)
  42. pktinfo.cols.info:append(" (holepunch)")
  43. return
  44. elseif pktlen == 1 then
  45. tree:add_proto_expert_info(ef_punchy)
  46. pktinfo.cols.info:append(" (punchy)")
  47. return
  48. end
  49. tree:add(pf_version, tvbuf:range(0,1))
  50. local type = tree:add(pf_type, tvbuf:range(0,1))
  51. local nebula_type = bit32.band(tvbuf:range(0,1):uint(), 0x0F)
  52. if nebula_type == 0 then
  53. local stage = tvbuf(8,8):uint64()
  54. tree:add(pf_subtype_handshake, tvbuf:range(1,1))
  55. type:append_text(" stage " .. stage)
  56. pktinfo.cols.info:append(" (" .. type_field().display .. ", stage " .. stage .. ", " .. subtype_field().display .. ")")
  57. elseif nebula_type == 4 then
  58. tree:add(pf_subtype_test, tvbuf:range(1,1))
  59. pktinfo.cols.info:append(" (" .. type_field().display .. ", " .. subtype_field().display .. ")")
  60. else
  61. tree:add(pf_subtype, tvbuf:range(1,1))
  62. pktinfo.cols.info:append(" (" .. type_field().display .. ")")
  63. end
  64. tree:add(pf_reserved, tvbuf:range(2,2))
  65. tree:add(pf_remote_index, tvbuf:range(4,4))
  66. tree:add(pf_message_counter, tvbuf:range(8,8))
  67. tree:add(pf_payload, tvbuf:range(16,tvbuf:len() - 16))
  68. end
  69. function nebula.prefs_changed()
  70. if default_settings.all_ports == nebula.prefs.all_ports and default_settings.port == nebula.prefs.port then
  71. -- Nothing changed, bail
  72. return
  73. end
  74. -- Remove our old dissector
  75. DissectorTable.get("udp.port"):remove_all(nebula)
  76. if nebula.prefs.all_ports and default_settings.all_ports ~= nebula.prefs.all_ports then
  77. default_settings.all_port = nebula.prefs.all_ports
  78. for i=0, 65535 do
  79. DissectorTable.get("udp.port"):add(i, nebula)
  80. end
  81. -- no need to establish again on specific ports
  82. return
  83. end
  84. if default_settings.all_ports ~= nebula.prefs.all_ports then
  85. -- Add our new port dissector
  86. default_settings.port = nebula.prefs.port
  87. DissectorTable.get("udp.port"):add(default_settings.port, nebula)
  88. end
  89. end
  90. DissectorTable.get("udp.port"):add(default_settings.port, nebula)