Wireshark mailing list archives

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


From: Michael Mann via Wireshark-dev <wireshark-dev () wireshark org>
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.


___________________________________________________________________________
Sent via:    Wireshark-dev mailing list <wireshark-dev () wireshark org>
Archives:    https://www.wireshark.org/lists/wireshark-dev
Unsubscribe: https://www.wireshark.org/mailman/options/wireshark-dev
             mailto:wireshark-dev-request () wireshark org?subject=unsubscribe

Current thread: