I am parsing a log of a large number of Modbus/TCP transactions and want to grab the raw data that is returned for function code 4 (Read Input Registers). I can grab all the relevant fields for the Modbus/TCP packet except for the register value. For example, here is the Modbus/TCP portion of a packet which requests a single register read on input register 401 (hex
And the corresponding slave response:
The actual value returned for register 401 is the final two bytes of the response: However, running tshark on the packet doesn't output 268, but instead it outputs 0.
If I run a similar command on more than one register, the output is a sequential list of numbers starting with 0. For example, running it on a capture with a read request for 8 sequential registers starting at 401 whose contents are various 16-bit integer values:
It is clear that Update 02/11/2016 I've uploaded a section of the capture here. The first three requests/responses only request a single register, while the last one requests 8 sequential input registers. Here's the (abbreviated) output of
I have found a workaround using the pyshark library in Python (which itself issues calls to tshark on the backend). I believe that it just uses raw tshark calls to parse the packet data and store it in various data structures; in this case, it does appear to store the registers as a list of individual key/value pairs. Some example code in the interactive Python 3.5.1 shell:
This suits my needs, but it is definitely a workaround. Given sindy’s explanation, it is strange albeit understandable that this is not currently a feature of the dissector. That said, what I’m trying to do could be far enough outside the typical usage of Wireshark that a workaround in the form of an external script or library may be necessary. If it turns out that there truly is no way to do this with tshark, then I may submit an enhancement request at the provided bugzilla link. asked 10 Feb ‘16, 10:18 evan edited 11 Feb ‘16, 08:29 |
One Answer:
Looking at that on a sample capture as you haven't provided the real one (the one with several registers requested in a single query would be the best), I'm afraid it is a bug of the dissector. But it is even more complex, which version of Wireshark do you use? Because in your case, the dissector provides the index of the value rather than the value itself, while in Wireshark 2.0.1, it still does not provide the value but it provides the reference number of the register, i.e. you can use a display filter like I understand the current (2.0.1) behaviour of the dissector in such a way that it does its best to display the reference number of the register and make it available for use in a display filter in the response packet where it does not exist as a protocol field. To do so, the dissector has to maintain state information and render this information taken from the query packet when dissecting the response. If the assumption is correct, you would have to file an "enhancement" severity level bug at wireshark bugzilla, asking for another field like edit: changed the register "addresses" and values in the example below to match the modbus reality. However, it may still not be all that simple to use even if such enhancement would be implemented, as the display filter only chooses the whole packet, not a particular field in it, and it does not link together the individual expressions. So if the query would ask for registers 5, 6 and 7, and the values of these registers in the response would be 50, 600 and 7000 respectively, use of answered 10 Feb '16, 16:46 sindy edited 11 Feb '16, 08:39 |
The commit that modified that area of the dissector noted:
I also think it would be useful to get the register data value. It might also be useful to have fields that show the value in any of the usual Modbus formats, e.g. signed\unsigned, 16 bit, 32 bit, float etc.
I am afraid that while for display filtering, it is indeed in most cases more useful to get access to the register “address”, for the actual display at tshark output, the register “value” (or “contents”) is required more often.
As the (pseudo)field identifier (
modbus.reg16
in this case) is common for both cases, so is the value to be used for filtering and for display.But the fact that if “register address” and “register value” cannot be linked together using a display filter leads me to an idea that display of the registers as address:value pairs, such as
100:0,101:4100,102:225,103:225,104:0,105:0,106:65535,107:65535
, could be useful.As backward compatibility seems not to be really important here (as the meaning of
modbus.reg16
has changed between dissector releases), if you are going to file the “enhancement” bug, I’d saymodbus.reg16.address
,modbus.reg16.value
, andmodbus.reg16.address_value_pair
would remove confusion and even allow filtering by specific value of a specific register, like-Y modbus.reg16.address_value_pair = 101:4100
. The value format as suggested by @grahamb could be added as another suffix to .value and .address_value_pair.Looking at that more generically, I’m missing the possibility to use constructions like
modbus[2:2]
, which can be used in the display filter, also as values of the-e
parameter to tshark. Correct me if I’m wrong but I believe this would not require modification of the individual dissectors and could be added to tshark as a whole.@evan, if you happen to know it without googling, can a single query indicate several reference numbers of registers, or only contiguous sets of registers may be read out using a single query? I.e. does my example in the answer with a query for registers with reference numbers 5,9, and 16 make sense?
Also, I’m still puzzled by the fact that your 2.0.1 shows the index of the values (0..7) while both Cloudshark (which I don’t suspect to run on Windows) as well as my Windows version of 2.0.1 properly show 100,101,…, i.e. the address (or reference number if you please), although no protocol preference of either Modbus/TCP or Modbus are related to this.
@grahamb Good find on that commit. From the perspective of sorting and displaying, it does make sense to sort that way (as per @sindy’s response).
@sindy Registers can only be polled sequentially given the structure of a modbus request (i.e., you tell it which register to start at and tell it how many to query). It is possible to make custom function codes (which not all devices/implementations support) but I think that trying to do something like what you suggest in your answer would just comprise several individual register reads combined into a single command and thus still fit within spec (and would likely only appear to read separated registers to the software/driver layer and not actually appear as a single modbus request on the packet level.)
As to your last point, I believe I made a mistake somewhere in transcribing the command and will edit my post to reflect this. It is indeed showing the reference number/address when I enter the command as shown above. Sorry for the confusion.
Given all of the comments/responses, does it make sense at this point for me to accept and file a request at the Bugzilla?
I’m afraid it does.
Sounds good, thanks for the help!