
लाइव, सिस्टम-व्यापी USB ट्रांसफर स्निफर eBPF में — दो यूनिवर्सल URB हुक से इनलाइन USB ट्रैफिक (कंट्रोल SETUP, SCSI, HID) को डिकोड करता है। कोई usbmon नहीं, कोई हार्डवेयर स्निफर नहीं। CO-RE पोर्टेबल।

एक वास्तविक समय, रंगीन फ़ीड USB ट्रैफ़िक का सिस्टम-व्यापी — दो सार्वभौमिक URB चोकपॉइंट्स पर निर्मित जिसके माध्यम से प्रत्येक होस्ट-नियंत्रक ड्राइवर गुज़रता है, इसलिए यह xHCI/EHCI/OHCI/dwc पर बिना प्रति-नियंत्रक ट्रेसपॉइंट और usbmon के काम करता है। पूर्णतः CO-RE पोर्टेबल।
| fentry हुक | यह हमें क्या बताता है |
|---|---|
usb_submit_urb | एक ट्रांसफर कतारबद्ध किया गया (डिवाइस, एंडपॉइंट, प्रकार, पेलोड) |
usb_hcd_giveback_urb | यह पूरा हुआ (स्थिति, स्थानांतरित बाइट्स, विलंबता, पेलोड) |
URB पॉइंटर द्वारा कुंजीबद्ध एक lru_hash दोनों को एक साथ जोड़ता है: सबमिट एक प्रारंभ समय स्टाम्प करता है, पूर्णता इसे submit→complete विलंबता के लिए वापस पढ़ती है, फिर इसे हटा देती है। यह httpbody की request/response जोड़ी को दर्पण करता है — SUBMIT "request" है (होस्ट क्या भेजता है), COMPLETE "response" है (डिवाइस क्या लौटाता है)।
कंट्रोल ट्रांसफर को उनके 8-बाइट SETUP पैकेट को मानक अनुरोध नाम (GET_DESCRIPTOR, SET_CONFIGURATION, …) में डिकोड किया जाता है; डेटा चरण टेक्स्ट के रूप में प्रस्तुत होते हैं जब वे टेक्स्टुअल दिखते हैं और अन्यथा हेक्सडंप के रूप में।
आउटपुट प्रति घटना एक पंक्ति (कॉम्पैक्ट) है। पहली बार जब कोई डिवाइस दिखाई देता है तो उसे एक ▸ लीजेंड पंक्ति मिलती है (bus-dev, vid:pid, उत्पाद, लिंक गति); उसके बाद प्रत्येक पंक्ति में केवल छोटा DEV टैग होता है, इसलिए बाएँ-हाथ के कॉलम भारी ट्रैफ़िक के तहत संरेखित और स्कैन करने योग्य रहते हैं। प्रत्येक पंक्ति में समय, प्रकार (SUBMIT/CMPLT), ट्रांसफर प्रकार, epNdir, दिशा तीर (← डिवाइस→होस्ट IN, → होस्ट→डिवाइस OUT), बाइट गणना, स्थिति, विलंबता, और स्वामी कर्नेल ड्राइवर, फिर एक · और सबसे उपयोगी विवरण (डिकोडेड SETUP, SCSI कमांड, या एक छोटा पेलोड पूर्वावलोकन) दिखाती है। पूर्ण बहु-पंक्ति हेक्सडंप के लिए --hex पास करें। TTY पर हेक्स बाइट मान वर्ग द्वारा रंगीन होते हैं (null नीला, प्रिंट करने योग्य ASCII सियान, व्हाइटस्पेस हरा, अन्य नियंत्रण मैजेंटा, उच्च/गैर-ASCII पीला); पाइप किया गया आउटपुट सादा होता है।
usbmon सेटअप के लाइव एनुमरेट और विक्रेता नियंत्रण अनुरोधों और HID रिपोर्टों का आदान-प्रदान करते हुए देखें। जैसे ही आप डिवाइस के साथ छेड़छाड़ करते हैं, SETUP पैकेट और पेलोड डिकोड हो जाते हैं।READ(10) lba=… blocks=…, WRITE(10), CSW PASS/FAIL) में डिकोड होते हैं।--errors-only एक साथ हर डिवाइस पर स्टॉल (EPIPE), टाइमआउट, बैबल और CRC त्रुटियाँ दिखाता है।INT रिपोर्ट या SET_REPORT नियंत्रण लिखने के रूप में सामने आता है जिसे आपने ट्रिगर नहीं किया।--json NDJSON उत्सर्जित करता है; पेलोड को चलाने के बीच अंतर करने के लिए jq या फ़ाइल में पाइप करें।curl -fsSL https://yeet.cx | sh
फिर इसे सीधे GitHub से चलाएँ — yeet उदाहरण लाता है और आपके लिए बनाता है, क्लोन की आवश्यकता नहीं:
yeet run github:yeet-src/usbsnoop
स्थानीय चेकआउट से बनाने के लिए:
make
कर्नेल के BTF को vmlinux.h में डंप करता है (struct urb, usb_device, और डिवाइस डिस्क्रिप्टर के लिए), फिर कंपाइल करता है। clang, bpftool, और BTF वाले कर्नेल की आवश्यकता है।
yeet run . # all devices, runs until Ctrl-C
yeet run . -- --secs 30 # stop after 30s (prints a summary)
yeet run . -- --vid 0x320f # one vendor
yeet run . -- --vendor-id 0x046d --product-id 0xc52b # one device by id
yeet run . -- --bus 3 --dev 4 # one device by bus address
yeet run . -- --type control,int # only these transfer types
yeet run . -- --no-data # metadata only, skip payload capture
yeet run . -- --max-data 64 # cap rendered payload at 64 bytes
yeet run . -- --errors-only # only failed completions (stalls, timeouts)
yeet run . -- --hex # full multi-line hexdump per transfer
yeet run . -- --json | jq . # NDJSON, one object per event
सभी फ़िल्टरिंग कर्नेल-साइड होती है, इसलिए फ़िल्टर किया गया ट्रैफ़िक कभी यूज़रस्पेस तक नहीं पहुँचता।
प्रत्येक घटना पंक्ति कोष्ठक में स्वामी कर्नेल ड्राइवर के साथ समाप्त होती है ([hid_irq_in], [usb_api_blocking_completion]) — urb->complete को कर्नेल में bpf_snprintf("%ps") के माध्यम से प्रतीकित किया जाता है, इसलिए कोई /proc/kallsyms लुकअप आवश्यक नहीं है। मास-स्टोरेज बल्क ट्रांसफर अपने Bulk-Only Transport रैपर को SCSI कमांड (CBW READ(10) lba=… blocks=… / CSW PASS) में डिकोड करते हैं। समयबद्ध निकास पर (--secs तक पहुँचने पर) एक प्रति-डिवाइस सारांश और एक log2 विलंबता हिस्टोग्राम प्रिंट होता है; Ctrl-C निकास इसे छोड़ देता है (कोई JS-दृश्य सिग्नल हुक नहीं है)।
बल्क ट्रैफ़िक (मास स्टोरेज और इसके जैसे) अक्सर स्टैक को एक struct scatterlist ऐरे (urb->sg) देता है, एक एकल रैखिक transfer_buffer के बजाय, इसलिए पेलोड पृष्ठों पर बिखरा रहता है। usbsnoop उस ऐरे को चलता है और प्रत्येक सेगमेंट के बाइट्स को कॉपी करता है, लेकिन उन तक पहुँचने का मतलब एक पृष्ठ को उसके कर्नेल वर्चुअल पते में अनुवाद करना है — x86-64 के page_to_virt का उल्टा, जिसे चल रहे कर्नेल के page_offset_base और vmemmap_base (दोनों KASLR-यादृच्छिक) की आवश्यकता है।
JS आइसोलेट /proc/kallsyms नहीं पढ़ सकता और लोडर में ksym समर्थन नहीं है, इसलिए आप दो प्रतीक पते अंदर पास करते हैं और BPF पक्ष उन्हें डीरेफरेंस करता है:
yeet run . -- \
--page-offset-base 0x$(sudo awk '$3=="page_offset_base"{print $1}' /proc/kallsyms) \
--vmemmap-base 0x$(sudo awk '$3=="vmemmap_base"{print $1}' /proc/kallsyms)
उन फ़्लैग के बिना, SG ट्रांसफर अभी भी पूर्ण मेटाडेटा दिखाते हैं, बस कोई पेलोड बाइट्स नहीं — पिछला व्यवहार। यह पथ केवल x86-64 है: अन्य आर्किटेक्चर पर फ़्लैग को छोड़ दें।
actual/requested लंबाई की रिपोर्ट करता है। प्रत्येक रिंग रिकॉर्ड में एक पूर्ण data[16384] होता है, इसलिए 8 MiB रिंग में ~512 इवेंट होते हैं।--page-offset-base / --vmemmap-base फ़्लैग और एक x86-64 होस्ट की आवश्यकता है; प्रत्येक सेगमेंट को एक पृष्ठ तक कैप्चर किया जाता है, और एक ट्रांसफर के केवल पहले 64 सेगमेंट को चला जाता है।| फ़्लैग | डिफ़ॉल्ट | अर्थ |
|---|
--secs | forever | कितनी देर चलना है; Ctrl-C तक चलाने के लिए छोड़ें (एक संख्या रुक जाती है और सारांश प्रिंट करती है) |
--vid, --vendor-id | any | विक्रेता आईडी द्वारा फ़िल्टर करें (हेक्स 0x1d6b या दशमलव) |
--pid, --product-id | any | उत्पाद आईडी द्वारा फ़िल्टर करें |
--bus | any | बस संख्या द्वारा फ़िल्टर करें |
--dev | any | डिवाइस पते द्वारा फ़िल्टर करें |
--type | all | iso, int, control, bulk की csv |
--no-data | off | ट्रांसफर बफ़र न पढ़ें (केवल मेटाडेटा) |
--max-data | 4096 | प्रति घटना प्रस्तुत पेलोड के अधिकतम बाइट्स |
--errors-only | off | केवल गैर-OK पूर्णताएँ दिखाएं (SUBMIT और OK छोड़ें) |
--hex | off | प्रति ट्रांसफर पूर्ण बहु-पंक्ति हेक्सडंप (अन्यथा कॉम्पैक्ट इनलाइन पूर्वावलोकन) |
--json | off | TTY दृश्य के बजाय NDJSON उत्सर्जित करें (प्रति घटना एक ऑब्जेक्ट) |
--page-offset-base | off | कर्नेल page_offset_base पता (हेक्स) — SG पेलोड कैप्चर सक्षम करता है (x86-64) |
--vmemmap-base | off | कर्नेल vmemmap_base पता (हेक्स) — --page-offset-base के साथ जोड़ा गया |