Skip to content

Instantly share code, notes, and snippets.

@Xitsa
Last active September 7, 2020 11:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Xitsa/03a091bfc0ae480b00d424ba1d137abf to your computer and use it in GitHub Desktop.
Save Xitsa/03a091bfc0ae480b00d424ba1d137abf to your computer and use it in GitHub Desktop.
Плагин для Wireshark, который расшифровывает мандатные метки согласно ГОСТ Р 58256-2018 (а-ля астралинукс)
--[[
--Для установки надо открыть в wireshark’е меню Help/About
--Там найти вкладку Folders, скопировать путь к ‘Personal Lua Plugins’
--Создать этот каталог, если надо
--Скопировать туда этот файл и перезапустить wireshark
--]]
local function pack_byte(mask, byte, offset)
local limited_byte = bit32.band(byte, 0xFF)
local low_pos = 8 - math.floor(offset / 8)
local high_pos = low_pos - 1
local bit_offset = math.fmod(offset, 8)
local low_value = bit32.band(bit32.lshift(byte, bit_offset), 0xFF)
local high_value = bit32.rshift(bit32.band(bit32.lshift(byte, bit_offset), 0xFF00), 8)
if low_pos > 0 then
mask[low_pos] = bit32.bor(mask[low_pos], low_value)
end
if high_pos > 0 then
mask[high_pos] = bit32.bor(mask[high_pos], high_value)
end
end
local function decode_mandate_labels(option_bytes)
if not option_bytes then return nil end
if #option_bytes < 3 then return nil end
if option_bytes[1] ~= 130 then return nil end
if option_bytes[2] ~= #option_bytes then return nil end
if option_bytes[3] ~= 171 then return nil end
table.remove(option_bytes, 3)
table.remove(option_bytes, 2)
table.remove(option_bytes, 1)
local level = 0
local mask = {0, 0, 0, 0, 0, 0, 0, 0}
local offset = 0
if (#option_bytes == 0) then return { level = level, mask = mask } end
local state = "BUILD_LEVEL"
for f = 1, #option_bytes do
local byte = option_bytes[f]
if (bit32.band(byte, 1) == 1) and (f == #option_bytes) then
-- Последний байт имеет продолжение
return nil
end
if (bit32.band(byte, 1) == 0) and (f ~= #option_bytes) then
-- Не последний байт указал, что он последний
return nil
end
if state == "BUILD_LEVEL" then
level = bit32.rshift(byte, 1)
state = "BUILD_HIGH_LEVEL_AND_MASK"
elseif state == "BUILD_HIGH_LEVEL_AND_MASK" then
level = bit32.bor(level, bit32.lshift(bit32.band(byte, 2), 6))
pack_byte(mask, bit32.rshift(bit32.band(byte, 0xFC), 2), 0)
offset = 6
state = "BUILD_MASK"
elseif state == "BUILD_MASK" then
pack_byte(mask, bit32.rshift(bit32.band(byte, 0xFE), 1), offset)
offset = offset + 7
else
return nil
end
end
return { level = level, mask = mask }
end
function strip_leading_zeroes(str)
local without_all_leading_zeroes = str:gsub("^0*", "")
if without_all_leading_zeroes == "" then
return "0"
end
return without_all_leading_zeroes
end
local function array_to_bytes(array)
local hexes = {}
for k, v in ipairs(array) do
table.insert(hexes, string.format("%02x", v))
end
return table.concat(hexes, "")
end
local ip_sec = Proto("IP_OPT_SEC", "IP option SEC (GOST R 58256-2018)")
local ip_opt_f = Field.new("ip.options.security")
local level_F = ProtoField.uint8("ip_opt_sec.level", "Security level")
local mask_F = ProtoField.string("ip_opt_sec.mask", "Categories mask")
ip_sec.fields = {level_F, mask_F, debug_F}
-- create a function to "postdissect" each frame
function ip_sec.dissector(buffer,pinfo,tree)
-- obtain the current values the protocol fields
local ip_opt = ip_opt_f()
if ip_opt then
local subtree = tree:add(ip_sec,"IP option SEC (GOST R 58256-2018) data")
local options = tostring(ip_opt)
local tvb_range = ip_opt.range
local bytes_array, bytes_len = tvb_range:bytes()
local x = {}
for f = 1, bytes_len do
table.insert(x, bytes_array:get_index(f - 1))
end
local mandate_labels = decode_mandate_labels(x)
if mandate_labels then
subtree:add(level_F, mandate_labels.level)
subtree:add(mask_F, strip_leading_zeroes(array_to_bytes(mandate_labels.mask)))
end
end
end
-- register our protocol as a postdissector
register_postdissector(ip_sec)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment