-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Add support for USB Linux packets (usbmon) #4417
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,20 +7,15 @@ | |
Default USB frames & Basic implementation | ||
""" | ||
|
||
# TODO: support USB headers for Linux and Darwin (usbmon/netmon) | ||
# https://github.com/wireshark/wireshark/blob/master/epan/dissectors/packet-usb.c # noqa: E501 | ||
|
||
from scapy.config import conf | ||
from scapy.compat import chb | ||
from scapy.data import DLT_USBPCAP | ||
from scapy.data import DLT_USBPCAP, DLT_USB_LINUX, DLT_USB_LINUX_MMAPPED | ||
from scapy.fields import ByteField, XByteField, ByteEnumField, LEShortField, \ | ||
LEShortEnumField, LEIntField, LEIntEnumField, XLELongField, \ | ||
LenField | ||
LEShortEnumField, LEIntField, LEIntEnumField, LELongField, LESignedIntField, \ | ||
XLELongField, LenField, StrFixedLenField, BitField, BitEnumField | ||
from scapy.packet import Packet, bind_top_down | ||
|
||
|
||
# USBpcap | ||
|
||
_usbd_status_codes = { | ||
0x00000000: "Success", | ||
0x40000000: "Pending", | ||
|
@@ -77,6 +72,94 @@ | |
} | ||
|
||
|
||
_requests = { | ||
0x00: "GET_STATUS", | ||
0x01: "CLEAR_FEATURE", | ||
0x03: "SET_FEATURE", | ||
0x05: "SET_ADDRESS", | ||
0x06: "GET_DESCRIPTOR", | ||
0x07: "SET_DESCRIPTOR", | ||
0x08: "GET_CONFIGURATION", | ||
0x09: "SET_CONFIGURATION", | ||
0x0A: "GET_INTERFACE", | ||
0x0B: "SET_INTERFACE", | ||
0x0C: "SYNCH_FRAME", | ||
} | ||
|
||
_request_recipients = { | ||
0x00: "Device", | ||
0x01: "Interface", | ||
0x02: "Endpoint", | ||
0x03: "Other", | ||
} | ||
|
||
_request_types = { | ||
0x00: "Standard", | ||
0x01: "Class", | ||
0x02: "Vendor", | ||
0x03: "Reserved", | ||
} | ||
|
||
_request_directions = { | ||
0: "Device-to-host", | ||
1: "Host-to-device", | ||
} | ||
|
||
_directions = { | ||
0: "OUT", | ||
1: "IN", | ||
} | ||
|
||
_urb_types = { | ||
ord("S"): "SUBMIT", | ||
ord("C"): "COMPLETE", | ||
ord("E"): "ERROR", | ||
} | ||
|
||
|
||
class _Setup(Packet): | ||
fields_desc = [BitEnumField("bmRequestType_direction", 0, 1, _request_directions), | ||
BitEnumField("bmRequestType_type", 0, 2, _request_types), | ||
BitEnumField("bmRequestType_recipient", 0, 5, _request_recipients), | ||
ByteEnumField("bRequest", 0, _requests), | ||
LEShortField("wValue", 0), | ||
LEShortField("wIndex", 0), | ||
LEShortField("wLength", 0)] | ||
|
||
|
||
class USBLinux(Packet): | ||
name = "USBLinux URB" | ||
fields_desc = [XLELongField("urb_id", 0), | ||
ByteEnumField("urb_type", 0, _urb_types), | ||
ByteEnumField("transfer_type", 0, _transfer_types), | ||
BitEnumField("direction", 0, 1, _directions), | ||
BitField("endpoint", 0, 7), | ||
ByteField("device_address", 0), | ||
LEShortField("bus_id", 0), | ||
StrFixedLenField("setup_flag", b"\x00", length=1), | ||
StrFixedLenField("data_flag", b"\x00", length=1), | ||
LELongField("urb_ts_sec", 0), | ||
LESignedIntField("urb_ts_usec", 0), | ||
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 commentThe reason will be displayed to describe this comment to others. Learn more. This field is actually a union, for ISO packets it should be:
But I don't know how to deal with unions here. I tried |
||
|
||
|
||
class _USBLinuxExt(Packet): | ||
name = "USBLinux URB" | ||
fields_desc = [LESignedIntField("interval", 0), | ||
LESignedIntField("start_frame", 0), | ||
LEIntField("xfer_flags", 0), | ||
LEIntField("numdesc", 0)] | ||
Comment on lines
+149
to
+154
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 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 commentThe 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) |
||
|
||
|
||
class USBLinuxMmapped(Packet): | ||
name = "USBLinux URB" | ||
fields_desc = [USBLinux, | ||
_USBLinuxExt] | ||
|
||
|
||
class USBpcap(Packet): | ||
name = "USBpcap URB" | ||
fields_desc = [ByteField("headerLen", None), | ||
|
@@ -144,3 +227,5 @@ class USBpcapTransferControl(Packet): | |
bind_top_down(USBpcap, USBpcapTransferControl, transfer=2) | ||
|
||
conf.l2types.register(DLT_USBPCAP, USBpcap) | ||
conf.l2types.register(DLT_USB_LINUX_MMAPPED, USBLinuxMmapped) | ||
conf.l2types.register(DLT_USB_LINUX, USBLinux) |
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 Pythonerrno
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.