This is a static archive of our old Q&A Site. Please post any new questions and answers at ask.wireshark.org.

LUA:How to dissect fields with a lot of conditions effectively (BGP) ?

0

I am making Lua script to dissect BGP protocol. It has many path attributes and within each other values...:

alt text

I can dissect all writing if conditions, but I think there is a easier and effectively way to dissect all values.

BGP reference: https://tools.ietf.org/html/rfc4271

asked 11 May '16, 03:53

javiguembe's gravatar image

javiguembe
21448
accept rate: 0%

Is there an issue with the existing c-based BGP dissector?

(11 May '16, 07:30) grahamb ♦

No, but I want to do it to practice.

(11 May '16, 09:01) javiguembe

One Answer:

1

You may want to read the part of Lua manual which deals with data types named Tables, and make use of the Wireshark's Lua API's ability to use Lua tables as number to string translation vocabularies. An example from one of my ad hoc Lua dissectors:

-- first, we define translation tables for individual items
prec_level_values = {}
prec_level_values[0] = "flashOverride"
prec_level_values[1] = "flash"
prec_level_values[2] = "immediate"
prec_level_values[3] = "priority"
prec_level_values[4] = "routine"

lfb_indictn_values = {} lfb_indictn_values[0] = "lfbAllowed" lfb_indictn_values[1] = "lfbNotAllowed" lfb_indictn_values[2] = "pathReserved"

– later, we define the Protocol fields' properties, referring to the conversion tables above – as a way to translate the individual numeric values to corresponding strings MLPP_Prec_level = ProtoField.uint8("mlpp.Prec_level","Prec_level",base.DEC,prec_level_values) MLPP_LFB_Indictn = ProtoField.uint8("mlpp.LFB_Indictn","LFB_Indictn",base.DEC,lfb_indictn_values)

– then, we tell Wireshark that these fields belong to this protocol MLPP_proto.fields = {MLPP_Prec_level, MLPP_LFB_Indictn, …}

– and in the body of the dissector, we just extract the portions of tvb which contain those numeric values and pass them as arguments to tree:add local prec = buffer:range(4,1) local lfb_ind = buffer:range(7,1) subtree:add(MLPP_Prec_level,prec) subtree:add(MLPP_LFB_Indictn,lfb_ind)

– instead, if you don't need the buffer ranges for any other purpose, you could just write subtree:add(MLPP_Prec_level,buffer:range(4,1)) subtree:add(MLPP_LFB_Indictn,buffer:range(7,1))

As for dealing with the higher 4 bits of the MSB, a forged example of what you could do for two bits, X and Y, where each value of each bit has to be translated to a string and the values of the bits do not affect each other, you can translate all four numeric combinations to concatenations of strings which you then split using a separator character:

my_values = {}
my_values[0] = "[email protected]_is_0"
my_values[1] = "[email protected]_is_1"
my_values[2] = "[email protected]_is_0"
my_values[3] = "[email protected]_is_1"

local aux_number = buffer:range(5,1):uint8 local aux_text = my_values[aux_number] local X_text_value,Y_text_value = aux_text:match("(.)@(.)")

– or you can do the same on a single line local X_text_value,Y_text_value = my_values[buffer:range(5,1):uint8]:match("(.)@(.)")

answered 11 May ‘16, 09:52

sindy's gravatar image

sindy
6.0k4851
accept rate: 24%

Thanks for answer !! Is a god answer, but I know that I can make tables to dissect a lot of posible values. In fact, I use it to dissect Attribute types using Attribute type codes (see picture above).

Althougth, my question is; How to dissect Attribute Values (the last column) effectively. I said that because Attribute Values depends on fields before it: Attribute type, class and attribute value code. So I have to make if conditionals like:

if(attribute_type_cod ==1 && flag_o ==0) then subtree:add (attr_values1_withtable,buf(x,x)) end

I need to do 10 conditionals like this, other there is another way to do?

(12 May ‘16, 02:00) javiguembe

It is a good answer, but…

Well, the quality of the question has a large impact on the quality of the answer :-) So rather than pasting the screenshot of a table (which seems inconsistent until you look into the RFC you’ve given a link to), it would have been better to write that you need to translate numeric values of protocol field A to text ones in several different ways, choosing the appropriate way up to the numeric value of protocol field B.

For Lua in general, there is a page suggesting several possible implementations of “case” (Pascal) or “switch” (C, Java) replacement of a bunch of “if” statements to choose a branch of algorithm to be executed.

But as we talk about Wireshark’s Lua API here, we’d like to have the possibility to use Lua tables to translate the numeric values of parameters to text names so that they could be used for filtering, printing using tshark etc.

I haven’t tested that yet, but as the “values” in a Lua table may be variables (of any type, even other tables), it should be possible to do the following (example simplified to illustrative minimum):

my_value_table_1 = {}
my_value_table_1[0] = "IGP"
my_value_table_1[1] = "EGP"
my_value_table_1[2] = "INCOMPLETE"

my_value_table_2 = {} my_value_table_2[1] = "AS_SET" my_value_table_2[2] = "AS_SEQUENCE"

my_type_names_table = {} my_type_names_table[1] = "ORIGIN" my_type_names_table[2] = "AS_PATH"

BGP_attr_type_code = ProtoField.uint8("bgp.attr_type_code","Attr_type_code",base.DEC,my_type_names_table)

BGP_origin_value = ProtoField.uint8("bgp.attr_type.origin","Attr_origin_value",base.DEC,my_value_table_1)

BGP_as_path_value = ProtoField.uint8("bgp.attr_type.as_path","Attr_as_path_value",base.DEC,my_value_table_2)

BGP_proto.fields = {BGP_attr_type_code, BGP_origin_value, BGP_as_path_value, …}

my_type_fields_table = {} my_type_fields_table[1] = BGP_origin_value my_type_fields_table[2] = BGP_as_path_value

local attr_type_code = buffer:range(4,1) local attr_len = buffer:range(5,1) subtree:add(BGP_attr_type_code,buffer:range(4,1)) subtree:add(my_type_fields_table[attr_type_code],buffer:range(6,attr_len))

(12 May ‘16, 12:31) sindy

…continuation:

As a Lua table may contain another table, you can also individually extract the values of bits O, T, P, E and use them as additional key values as shown below, provided that you create a corresponding hierarchy of tables.

subtree:add(my_type_fields_table[attr_type_code][O_value][T_value][P_value][E_value],buffer:range(6,attr_len))

While you can define tables (of tables) using a compact notation, like

topmost_table = {
{
{"x111","x112"}, {"x121","x122"}
}, {
{"x211","x212"}, {"x221","x222"}
}
}

, doing so will automatically generate the keys as monotonous sequences of numeric values starting from of 1, so you’ll get the following values:

topmost_table[1][1][1]: "x111"
topmost_table[1][1][2]: "x112"
…
topmost_table[2][2][2]: "x222"

Therefore, you have to construct the individual levels of the tables “manually”, which will allow you to specify the keys as necessary (O,T,P,E values chosen randomly):

attr_type_table[2][0][1][0][1] = BGP_as_path_value

While the Wireshark’s Lua API will handle translation of a key for which no value is given in the table referred to in the protocol field specification very simply, by displaying “Unknown” in the packet dissection pane, things won’t go that easy if you ask TreeItem:add to add a non-existent protocol field. Therefore, you’ll likely want to check first whether attr_type_table[TypeCode][O][T][P][E] returns a value (a variable holding a reference to a protocol field descriptor), and only execute the TreeItem:add if it does.

(12 May ‘16, 14:24) sindy