-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for USB Linux packets (usbmon) #4417
base: master
Are you sure you want to change the base?
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #4417 +/- ##
==========================================
- Coverage 81.56% 81.43% -0.14%
==========================================
Files 352 352
Lines 84032 84052 +20
==========================================
- Hits 68544 68451 -93
- Misses 15488 15601 +113
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking of adding request and response packets, but I got stuck. As far as I can tell, there is nothing in a response packet that says what type of response it is. It seems that you need to keep track of the last request to figure out the type of the response you're dissecting. What's a good way to do something like this in scapy?
LESignedIntField("urb_status", 0), | ||
LEIntField("urb_len", 0), | ||
LEIntField("urb_data_len", 0), | ||
_Setup] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This field is actually a union, for ISO packets it should be:
struct iso_rec { /* Only for ISO */
int error_count;
int numdesc;
} iso;
But I don't know how to deal with unions here. I tried MultiTypeField
and the packets went back to being parsed as Raw
.
StrFixedLenField("data_flag", b"\x00", length=1), | ||
LELongField("urb_ts_sec", 0), | ||
LESignedIntField("urb_ts_usec", 0), | ||
LESignedIntField("urb_status", 0), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
urb_status
is a standard Linux error code. I was hoping I could use the standard Python errno
library, but unfortunately that only gives you error codes for the system you're running on. So if you try to use scapy on macOS for example, all the error codes are wrong.
For now I left it as is, we can add in a dictionary or error codes in the future unless there's a better solution.
class _USBLinuxExt(Packet): | ||
name = "USBLinux URB" | ||
fields_desc = [LESignedIntField("interval", 0), | ||
LESignedIntField("start_frame", 0), | ||
LEIntField("xfer_flags", 0), | ||
LEIntField("numdesc", 0)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't sure about how to handle these extra fields. For example, if I wanted to create a SetFeatureRequest
Packet
subclass, I would need two versions of it: one for the 48 byte header and one for the 64 byte header. So I broke this out into _USBLinuxExt
so we can reuse it for making these different variants of packets.
I was hoping there was a cleaner way to do it, but I couldn't figure anything out. Let me know if there's a better way to do this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could just add those fields at the end of the extended header (instead of putting them in a separate packet), and keep the first field of the extended packet as the non-extended packet. (in which case its fields are copied)
You could implement a |
Thanks @gpotter2. I looked into this, but it seems like sessions are mainly for sniffing. How can I use a session with |
This PR adds support for packets captured with usbmon on Linux. The usbmon docs are here, although they're inaccurate in a few cases: https://docs.kernel.org/usb/usbmon.html. I mainly relied on the Wireshark implementation here: https://github.com/wireshark/wireshark/blob/master/epan/dissectors/packet-usb.c
DLT_USB_LINUX
is the 48 byte header of usbmon, whileDLT_USB_LINUX_MMAPPED
is the 64 byte header. AFAIK, all captures on modern systems use the 64 byte header, but I'm not sure if this is correct. In any case, I can only really test with the 64 byte header on real PCAPs, and I only added theDLT_USB_LINUX
support because it seemed easy enough to do.