Huge thanks to our Platinum Members Endace and LiveAction,
and our Silver Member Veeam, for supporting the Wireshark Foundation and project.

Wireshark-dev: Re: [Wireshark-dev] [RFC] Vendor-specific dissector extension for EtherNet/IP

From: Michael Mann <mmann78@xxxxxxxxxxxx>
Date: Wed, 30 Aug 2017 10:49:51 -0400
My mail client decided to butcher the formatting of your email, so I manually tried to reformat it so that my inline replies make sense.
Hopefully the mail client doesn't butcher it on the way out too.  Sorry for the inconvience.

Le 29/08/2017 à 21:34, Michael Mann via Wireshark-dev a écrit :
>> The answer depends on exactly what you are trying to do, some things
>> will be easier than others.
>> 1. If you want to add vendor specific objects, that can easily be done
>> in Lua because there is a dissector table that you can just register
>> your vendor specific class with ("cip.class.iface").  There should be
>> numerous examples of Lua using a dissector table (just not specifically
>> for CIP).
 
> I have to admit the way dissector tables work is not clear for me.
 
There are 2 types of dissector tables, one for heuristics, one for fixed values.
For the "fixed" values one, you associate a value with a dissection function.
Using "cip.class.iface" as an example, you are associating the numeric value
of your object class with the dissector table, so the CIP dissector can use
that table to decide how/what to dissect next.
With a heuristic dissection table, you just register a "heuristic" function with
the dissector table.  Within that function could can decide if the "packet" should
be handled by your dissector.

I mention both because I forgot that there is a heuristic dissector for service codes
("cip.sc").  It looks like you need a combination of a dissector function for your
vendor-specific class as well as a heuristic function to handle the common services
within your vendor specific class.
 
You can mimic the behavior of the Connection Configuration Object dissection for your
vendor-specific objects.  It first registers a "(CIP) object dissection function" with:
 
cip_class_cco_handle = create_dissector_handle( dissect_cip_class_cco, proto_cip_class_cco );
dissector_add_uint( "cip.class.iface", CI_CLS_CCO, cip_class_cco_handle );
 
But it also adds a huerisitic function:
heur_dissector_add("cip.sc", dissect_class_cco_heur, "CIP Connection Configuration Object", "cco_cip", proto_cip_class_cco, HEURISTIC_ENABLE);
 
The dissect_class_cco_heur() basically checks the EPATH for the Connection Configuration
Object class value and then calls the main object dissection function, dissect_cip_class_cco.
 
> I registered my dissector for a vendor-specific class, and I observed the following
> behaviour: - When the service is common (Get_Attribute_List for example), the dissector
> is not called.
> - when the service is vendor-specific, the dissector is then called.
> So I can implement the vendor-specific services for vendor-specific classes at least,
> with a new dissector.
> But I don't understand why discriminate dissector in the class dissector table based
> on the service being known or not, any idea why it was implemented this way? Since the
> service is parsed and interpreted before the path (so the class), > wouldn't it make more sense to actually make a dissector table based on the service?
 
Hopefully the explanation above satisfies your questions.

>> 2. There is no support currently for "classless" service codes (like
>> those used in Rockwell Automation PLCs), which is what
>> _https://www.wireshark.org/lists/ethereal-dev/200601/msg00174.html_ appears
>> to be talking about.
 
> As I understand it the service codes mentioned in that thread are class specific.
> I have never encountered "classless" service codes until now, I didn't even know that
> existed (as CIP doesn't implement this behaviour, or at least I couldn't find it in the documentation).
 
To me, in layman's terms, the format of a CIP message is <service code><identifier>
In the CIP specs, they focus on <identifier> being an object class and instance, but
for some Rockwell PLCs, the <identifier> is just a string (and there is no class in the message).
That's what I mean when I refer to "classless" requests.

>> 2. If you want to add vendor specific services to already supported
>> objects, that would be more difficult to do in Lua because there isn't a
>> dissector table hook for them.  I'm not sure there would be a way to
>> handle the "general" case of registering service + class into a
>> dissector table, but you could add dissector tables (patching
>> packet-cip.c) for specific objects (Identity, ConnectionManager, etc)
>> and submit just that part as a patch for inclusion in base Wireshark code.
 
This is where I started to steer you incorrectly.  The heuristic functionality should
be able to handle this case without issue.

>> 3. Vendor specific attributes of an object would have the same
>> difficulty in Lua and would need dissector tables.
 
> Well, there is the cip.data_segment.iface dissector table, but then one would need to
> check (in every dissector register in this table) the class code, and also the
> instance id (to determine if it is a class attribute or an instance attribute).
> I'm not sure how this dissector table is used though: is it only for attribute data or also service data?
 
I think the intent of the cip.data_segment.iface dissector table was to handle the "string"
identifiers I mentioned with the Rockwell PLCs.  It's probably something that should actually
be removed from the dissector.
 
>> 4. I believe Lua will "override" any value registered to a dissector
>> table, so you could write the "vendor specific" portion, for say the
>> Identity object, but then you'd have to duplicate all of the dissection
>> currently being done for it in your Lua script.
 
> I did test with setting a lua dissector for Identity in the cip.class.iface, and on packets
> with common services it wasn't triggered (I didn't have packets with vendor-specific
> services call for Identity).  So apparently it does not override the default dissector
> with the lua one (at least with a common service).
 
Again, this issue can be handled with the heuristic dissection mentioned above.
 
>> 5. Also note that not all "open" objects are supported in
>> packet-cip.c.  It would be appreciated that if you added dissection for
>> any of those, that you provide a patch for integration here:
>> https://code.wireshark.org/review (see
>> https://wiki.wireshark.org/Development/SubmittingPatches for more
>> details).  If you're more familiar with Lua than C, you can put the Lua
>> script here: https://wiki.wireshark.org/Contrib, but I'd probably end up
>> taking it and converting it to C.
 
> If I encounter those I can implement it (in C or lua, both are fine for me), but it is not my
> priority for now. The problem I see here is that the system of dissector table does
> not fit our needs in this context. Ideally I would see one custom dissector just for the
> service and path (so service, classes and instances), and one for the payload (attributes
> and services data). All the structure would be made in C, and just small portions of lua
> would need to be used to (dynamically) provide names for classes, services and attributes.
> Then, a bigger lua script would provide a full dissector for the payload (attributes or services
> data), based on the previously parsed informations. How I have no idea if this is possible in wireshark, any thoughts?

Hopefully my correction with how the heuristic table works can solve your needs.  And it sounds
like you are familiar enough with C that you could follow the code for the Connection
Configuration Object in the CIP dissector.