Skip to content

parsing of captured KMP traffic#12

Open
jktjkt wants to merge 2 commits intogertvdijk:developfrom
jktjkt:wip/command-parsing
Open

parsing of captured KMP traffic#12
jktjkt wants to merge 2 commits intogertvdijk:developfrom
jktjkt:wip/command-parsing

Conversation

@jktjkt
Copy link
Copy Markdown
Contributor

@jktjkt jktjkt commented Apr 22, 2026

The first patch adds support for "context-free" decoding of KMP commands and responses, that is, without actually sending the command first. The second command then adds a very simple sniffer which can work with the output of socat. I used this to analyze traffic captured from the vendor's LogView application which was running in a libvirt/KVM VM. Here's a simple log:

> 2026/01/24 23:37:36.000562669  length=9 from=29553 to=29561
80 3f 10 01 03 e9 7c d4 0d
< 2026/01/24 23:37:36.000658765  length=1 from=127635 to=127635
40
< 2026/01/24 23:37:36.000667759  length=1 from=127636 to=127636
3f
< 2026/01/24 23:37:36.000676940  length=1 from=127637 to=127637
10
< 2026/01/24 23:37:36.000686033  length=1 from=127638 to=127638
03
< 2026/01/24 23:37:36.000695251  length=1 from=127639 to=127639
e9
< 2026/01/24 23:37:36.000704439  length=1 from=127640 to=127640
33
< 2026/01/24 23:37:36.000713505  length=1 from=127641 to=127641
04
< 2026/01/24 23:37:36.000722680  length=1 from=127642 to=127642
00
< 2026/01/24 23:37:36.000732096  length=1 from=127643 to=127643
04
< 2026/01/24 23:37:36.000741146  length=1 from=127644 to=127644
cf
< 2026/01/24 23:37:36.000750320  length=1 from=127645 to=127645
95
< 2026/01/24 23:37:36.000759528  length=1 from=127646 to=127646
76
< 2026/01/24 23:37:36.000768603  length=1 from=127647 to=127647
5a
< 2026/01/24 23:37:36.000777851  length=1 from=127648 to=127648
1b
< 2026/01/24 23:37:36.000787020  length=1 from=127649 to=127649
bf
< 2026/01/24 23:37:36.000796300  length=1 from=127650 to=127650
0d

And the corresponding output:

>>> GetRegisterRequest(data_raw=b'\x01\x03\xe9', registers=[1001])
<<< GetRegisterResponse(data_raw=b'\x03\xe93\x04\x00\x04\xcf\x95v', registers={1001: RegisterData(id_=1001, unit=51, value=b'\x04\x00\x04\xcf\x95v')})
| 1001 → Fabrication No               = 80713078 no unit (number)

I think that you might not take the CLI script as-is, please feel free to convert it to a click interface and a proper entrypoint and what not. I won't be doing that because this one suits my needs well enough.

If you decided to not want the sniffer at all, please consider merging the first commit which implements the actual decoding, I'm OK with carrying the sniffer as an out-of tree patch locally.

jktjkt added 2 commits April 22, 2026 12:54
I'm writing a KMP protocol sniffer, and for that I need a function which
looks at the captured communication log, and returns parsed
commands/responses.
The input format is the same as what `socat` produces, e.g.:

 > 2026/01/24 23:37:36.000562669  length=9 from=29553 to=29561
 80 3f 10 01 03 e9 7c d4 0d
 < 2026/01/24 23:37:36.000658765  length=1 from=127635 to=127635
 40
 < 2026/01/24 23:37:36.000667759  length=1 from=127636 to=127636
 3f
 < 2026/01/24 23:37:36.000676940  length=1 from=127637 to=127637
 10
 < 2026/01/24 23:37:36.000686033  length=1 from=127638 to=127638
 03
 < 2026/01/24 23:37:36.000695251  length=1 from=127639 to=127639
 e9
 < 2026/01/24 23:37:36.000704439  length=1 from=127640 to=127640
 33
 < 2026/01/24 23:37:36.000713505  length=1 from=127641 to=127641
 04
 < 2026/01/24 23:37:36.000722680  length=1 from=127642 to=127642
 00
 < 2026/01/24 23:37:36.000732096  length=1 from=127643 to=127643
 04
 < 2026/01/24 23:37:36.000741146  length=1 from=127644 to=127644
 cf
 < 2026/01/24 23:37:36.000750320  length=1 from=127645 to=127645
 95
 < 2026/01/24 23:37:36.000759528  length=1 from=127646 to=127646
 76
 < 2026/01/24 23:37:36.000768603  length=1 from=127647 to=127647
 5a
 < 2026/01/24 23:37:36.000777851  length=1 from=127648 to=127648
 1b
 < 2026/01/24 23:37:36.000787020  length=1 from=127649 to=127649
 bf
 < 2026/01/24 23:37:36.000796300  length=1 from=127650 to=127650
 0d

The log can be produced by, e.g.:

 socat -d -d -x UNIX-CONNECT:path/to/libvirt-serial-pty GOPEN:/dev/real-serial-tty,b1200,rawer,cs8,cstopb=2

The output of that looks like:

 >>> GetRegisterRequest(data_raw=b'\x01\x03\xe9', registers=[1001])
 <<< GetRegisterResponse(data_raw=b'\x03\xe93\x04\x00\x04\xcf\x95v', registers={1001: RegisterData(id_=1001, unit=51, value=b'\x04\x00\x04\xcf\x95v')})
 | 1001 → Fabrication No               = 80713078 no unit (number)
@gertvdijk
Copy link
Copy Markdown
Owner

Thanks for sharing! I really like the idea of a sniffer tool and it makes sense on what you need here. Having that together with the hardware and vendor toolkit can be very powerful!

I don't really like the style/layout as-is, but I've got some ideas. What first comes to mind that I would like to see/try:

  • Not sure if this should be part of the ClientCodec. Perhaps it makes more sense to create a new more generic Codec class to do more opportunistic/heuristic things -- for the purpose of throwing bytes at it and returning as a typed object as much as it can do. After all it's not a client but a passive sniffer.
  • parts of the logic in your script could be part of a Communicator class that may be able to read the style of socat output or other styles and doing the reassembly/slicing.
  • another part of the tool could then do the display/presentation. for later, but I already have ideas on a bit more fancy yet functional output using color coding or tables using rich for example.
  • create a registry of all of the request & response classes via __init_subclass__() so that the lookup of that by its command ID will be trivial.

Let me think about it the coming days and I can rework this if you want.

@jktjkt
Copy link
Copy Markdown
Contributor Author

jktjkt commented Apr 23, 2026

Yup, feel free to adjust it as you see fit. The class/registry lookup was, I think, inspired by some other projects like (iirc) openswitcher or python-dali, but if you have a more idiomatic alternative, that’s ok with me.

I also have some pending patches for the actual log readout which depend on this one. Would you like me to push them as-is, or should I wait?

@gertvdijk
Copy link
Copy Markdown
Owner

I also have some pending patches for the actual log readout which depend on this one. Would you like me to push them as-is, or should I wait?

Push as-is, I would say. No need to wait.

I can imagine there are quite a few iterations while reverse-engineering this, so please don’t spend too much effort upfront on polishing of the structure of commits if that slows you down.

I’m happy to do that lifting on my side: picking things apart into bite-sized changes, cleaning up commit history, polishing commit messages, and adding or adjusting documentation where needed.

So feel free to push the work in whatever shape is easiest for you.

@jktjkt
Copy link
Copy Markdown
Contributor Author

jktjkt commented Apr 28, 2026

The full work is pushed at https://github.com/jktjkt/PyKMP/commits/83d85ace2f586049897650a7813a34c095c4a02c, please feel free to slice & dice it as you see fit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants