[53014] | 1 | /* $Id: VUSBSniffer.cpp 99739 2023-05-11 01:01:08Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * Virtual USB - Sniffer facility.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2014-2023 Oracle and/or its affiliates.
|
---|
[53014] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[53014] | 26 | */
|
---|
| 27 |
|
---|
[57358] | 28 |
|
---|
| 29 | /*********************************************************************************************************************************
|
---|
| 30 | * Header Files *
|
---|
| 31 | *********************************************************************************************************************************/
|
---|
[53014] | 32 | #define LOG_GROUP LOG_GROUP_DRV_VUSB
|
---|
| 33 | #include <VBox/log.h>
|
---|
| 34 | #include <iprt/file.h>
|
---|
[76474] | 35 | #include <iprt/errcore.h>
|
---|
[59615] | 36 | #include <iprt/path.h>
|
---|
[53014] | 37 | #include <iprt/mem.h>
|
---|
| 38 | #include <iprt/string.h>
|
---|
[53071] | 39 | #include <iprt/semaphore.h>
|
---|
[53072] | 40 | #include <iprt/time.h>
|
---|
[53014] | 41 |
|
---|
[59615] | 42 | #include "VUSBSnifferInternal.h"
|
---|
[53014] | 43 |
|
---|
| 44 |
|
---|
[57358] | 45 | /*********************************************************************************************************************************
|
---|
| 46 | * Structures and Typedefs *
|
---|
| 47 | *********************************************************************************************************************************/
|
---|
| 48 |
|
---|
[53014] | 49 | /**
|
---|
| 50 | * The internal VUSB sniffer state.
|
---|
| 51 | */
|
---|
| 52 | typedef struct VUSBSNIFFERINT
|
---|
| 53 | {
|
---|
| 54 | /** The file handle to dump to. */
|
---|
| 55 | RTFILE hFile;
|
---|
[53071] | 56 | /** Fast Mutex protecting the state against concurrent access. */
|
---|
| 57 | RTSEMFASTMUTEX hMtx;
|
---|
[59615] | 58 | /** File stream. */
|
---|
| 59 | VUSBSNIFFERSTRM Strm;
|
---|
| 60 | /** Pointer to the used format. */
|
---|
| 61 | PCVUSBSNIFFERFMT pFmt;
|
---|
| 62 | /** Format specific state - variable in size. */
|
---|
| 63 | uint8_t abFmt[1];
|
---|
[53014] | 64 | } VUSBSNIFFERINT;
|
---|
| 65 | /** Pointer to the internal VUSB sniffer state. */
|
---|
| 66 | typedef VUSBSNIFFERINT *PVUSBSNIFFERINT;
|
---|
| 67 |
|
---|
| 68 |
|
---|
[59615] | 69 | /*********************************************************************************************************************************
|
---|
| 70 | * Static Variables *
|
---|
| 71 | *********************************************************************************************************************************/
|
---|
[53014] | 72 |
|
---|
[59615] | 73 | static PCVUSBSNIFFERFMT s_aVUsbSnifferFmts[] =
|
---|
[53060] | 74 | {
|
---|
[59633] | 75 | &g_VUsbSnifferFmtPcapNg,
|
---|
| 76 | &g_VUsbSnifferFmtUsbMon,
|
---|
| 77 | &g_VUsbSnifferFmtVmx,
|
---|
[59615] | 78 | };
|
---|
[53060] | 79 |
|
---|
| 80 |
|
---|
[59615] | 81 | /*********************************************************************************************************************************
|
---|
| 82 | * Internal Functions *
|
---|
| 83 | *********************************************************************************************************************************/
|
---|
[53060] | 84 |
|
---|
[64294] | 85 | /** @interface_method_impl{VUSBSNIFFERSTRM,pfnWrite} */
|
---|
[59615] | 86 | static DECLCALLBACK(int) vusbSnifferStrmWrite(PVUSBSNIFFERSTRM pStrm, const void *pvBuf, size_t cbBuf)
|
---|
[53014] | 87 | {
|
---|
[59615] | 88 | PVUSBSNIFFERINT pThis = RT_FROM_MEMBER(pStrm, VUSBSNIFFERINT, Strm);
|
---|
[53014] | 89 |
|
---|
[59615] | 90 | return RTFileWrite(pThis->hFile, pvBuf, cbBuf, NULL);
|
---|
[53072] | 91 | }
|
---|
| 92 |
|
---|
| 93 | /**
|
---|
[59615] | 94 | * Returns a supporting format writer taken from the given format name.
|
---|
[53072] | 95 | *
|
---|
[59615] | 96 | * @returns Pointer to the format structure or NULL if none was found.
|
---|
| 97 | * @param pszFmt The format to use.
|
---|
[53072] | 98 | */
|
---|
[59615] | 99 | static PCVUSBSNIFFERFMT vusbSnifferGetFmtFromString(const char *pszFmt)
|
---|
[53072] | 100 | {
|
---|
[59615] | 101 | for (unsigned i = 0; i < RT_ELEMENTS(s_aVUsbSnifferFmts); i++)
|
---|
[53014] | 102 | {
|
---|
[59615] | 103 | if (!RTStrICmp(pszFmt, s_aVUsbSnifferFmts[i]->szName))
|
---|
| 104 | return s_aVUsbSnifferFmts[i];
|
---|
[53014] | 105 | }
|
---|
| 106 |
|
---|
[59615] | 107 | return NULL;
|
---|
[53014] | 108 | }
|
---|
| 109 |
|
---|
| 110 | /**
|
---|
[59615] | 111 | * Returns a supporting format writer taken from the file suffix.
|
---|
[53014] | 112 | *
|
---|
[59615] | 113 | * @returns Pointer to the format structure or NULL if none was found.
|
---|
[64294] | 114 | * @param pszFilename The file name to take the suffix from.
|
---|
[53014] | 115 | */
|
---|
[59615] | 116 | static PCVUSBSNIFFERFMT vusbSnifferGetFmtFromFilename(const char *pszFilename)
|
---|
[53014] | 117 | {
|
---|
[59615] | 118 | const char *pszFileExt = RTPathSuffix(pszFilename);
|
---|
| 119 | if (!pszFileExt)
|
---|
| 120 | return NULL;
|
---|
[53014] | 121 |
|
---|
[59615] | 122 | pszFileExt++; /* Skip the dot. */
|
---|
[53014] | 123 |
|
---|
[59615] | 124 | for (unsigned i = 0; i < RT_ELEMENTS(s_aVUsbSnifferFmts); i++)
|
---|
| 125 | {
|
---|
| 126 | unsigned idxFileExt = 0;
|
---|
[53014] | 127 |
|
---|
[59615] | 128 | while (s_aVUsbSnifferFmts[i]->papszFileExts[idxFileExt])
|
---|
| 129 | {
|
---|
| 130 | if (!RTStrICmp(pszFileExt, s_aVUsbSnifferFmts[i]->papszFileExts[idxFileExt]))
|
---|
| 131 | return s_aVUsbSnifferFmts[i];
|
---|
[53014] | 132 |
|
---|
[59615] | 133 | idxFileExt++;
|
---|
| 134 | }
|
---|
[53014] | 135 | }
|
---|
| 136 |
|
---|
[59615] | 137 | return NULL;
|
---|
[53014] | 138 | }
|
---|
| 139 |
|
---|
[59615] | 140 |
|
---|
[53014] | 141 | DECLHIDDEN(int) VUSBSnifferCreate(PVUSBSNIFFER phSniffer, uint32_t fFlags,
|
---|
[59615] | 142 | const char *pszCaptureFilename, const char *pszFmt,
|
---|
| 143 | const char *pszDesc)
|
---|
[53014] | 144 | {
|
---|
[62959] | 145 | RT_NOREF(pszDesc);
|
---|
[53014] | 146 | int rc = VINF_SUCCESS;
|
---|
| 147 | PVUSBSNIFFERINT pThis = NULL;
|
---|
[59615] | 148 | PCVUSBSNIFFERFMT pFmt = NULL;
|
---|
[53014] | 149 |
|
---|
[59615] | 150 | if (pszFmt)
|
---|
| 151 | pFmt = vusbSnifferGetFmtFromString(pszFmt);
|
---|
| 152 | else
|
---|
| 153 | pFmt = vusbSnifferGetFmtFromFilename(pszCaptureFilename);
|
---|
| 154 |
|
---|
| 155 | if (!pFmt)
|
---|
| 156 | return VERR_NOT_FOUND;
|
---|
| 157 |
|
---|
[73097] | 158 | pThis = (PVUSBSNIFFERINT)RTMemAllocZ(RT_UOFFSETOF_DYN(VUSBSNIFFERINT, abFmt[pFmt->cbFmt]));
|
---|
[53014] | 159 | if (pThis)
|
---|
| 160 | {
|
---|
[59615] | 161 | pThis->hFile = NIL_RTFILE;
|
---|
| 162 | pThis->hMtx = NIL_RTSEMFASTMUTEX;
|
---|
| 163 | pThis->pFmt = pFmt;
|
---|
| 164 | pThis->Strm.pfnWrite = vusbSnifferStrmWrite;
|
---|
[53014] | 165 |
|
---|
[53071] | 166 | rc = RTSemFastMutexCreate(&pThis->hMtx);
|
---|
[53014] | 167 | if (RT_SUCCESS(rc))
|
---|
| 168 | {
|
---|
[59686] | 169 | uint32_t fFileFlags = RTFILE_O_DENY_NONE | RTFILE_O_WRITE | RTFILE_O_READ;
|
---|
| 170 | if (fFlags & VUSBSNIFFER_F_NO_REPLACE)
|
---|
| 171 | fFileFlags |= RTFILE_O_CREATE;
|
---|
| 172 | else
|
---|
| 173 | fFileFlags |= RTFILE_O_CREATE_REPLACE;
|
---|
| 174 |
|
---|
| 175 | rc = RTFileOpen(&pThis->hFile, pszCaptureFilename, fFileFlags);
|
---|
[53014] | 176 | if (RT_SUCCESS(rc))
|
---|
| 177 | {
|
---|
[59615] | 178 | rc = pThis->pFmt->pfnInit((PVUSBSNIFFERFMTINT)&pThis->abFmt[0], &pThis->Strm);
|
---|
[53071] | 179 | if (RT_SUCCESS(rc))
|
---|
| 180 | {
|
---|
| 181 | *phSniffer = pThis;
|
---|
| 182 | return VINF_SUCCESS;
|
---|
[53014] | 183 | }
|
---|
| 184 |
|
---|
[53071] | 185 | RTFileClose(pThis->hFile);
|
---|
| 186 | pThis->hFile = NIL_RTFILE;
|
---|
| 187 | RTFileDelete(pszCaptureFilename);
|
---|
[53014] | 188 | }
|
---|
[53071] | 189 | RTSemFastMutexDestroy(pThis->hMtx);
|
---|
[53072] | 190 | pThis->hMtx = NIL_RTSEMFASTMUTEX;
|
---|
[53014] | 191 | }
|
---|
[59615] | 192 |
|
---|
[53146] | 193 | RTMemFree(pThis);
|
---|
[53014] | 194 | }
|
---|
| 195 | else
|
---|
| 196 | rc = VERR_NO_MEMORY;
|
---|
| 197 |
|
---|
| 198 | return rc;
|
---|
| 199 | }
|
---|
| 200 |
|
---|
| 201 | /**
|
---|
| 202 | * Destroys the given VUSB sniffer instance.
|
---|
| 203 | *
|
---|
| 204 | * @param hSniffer The sniffer instance to destroy.
|
---|
| 205 | */
|
---|
| 206 | DECLHIDDEN(void) VUSBSnifferDestroy(VUSBSNIFFER hSniffer)
|
---|
| 207 | {
|
---|
| 208 | PVUSBSNIFFERINT pThis = hSniffer;
|
---|
| 209 |
|
---|
[53071] | 210 | int rc = RTSemFastMutexRequest(pThis->hMtx);
|
---|
| 211 | AssertRC(rc);
|
---|
| 212 |
|
---|
[59615] | 213 | pThis->pFmt->pfnDestroy((PVUSBSNIFFERFMTINT)&pThis->abFmt[0]);
|
---|
| 214 |
|
---|
[53014] | 215 | if (pThis->hFile != NIL_RTFILE)
|
---|
| 216 | RTFileClose(pThis->hFile);
|
---|
[53071] | 217 |
|
---|
| 218 | RTSemFastMutexRelease(pThis->hMtx);
|
---|
| 219 | RTSemFastMutexDestroy(pThis->hMtx);
|
---|
[53014] | 220 | RTMemFree(pThis);
|
---|
| 221 | }
|
---|
| 222 |
|
---|
| 223 | /**
|
---|
| 224 | * Records an VUSB event.
|
---|
| 225 | *
|
---|
| 226 | * @returns VBox status code.
|
---|
| 227 | * @param hSniffer The sniffer instance.
|
---|
| 228 | * @param pUrb The URB triggering the event.
|
---|
| 229 | * @param enmEvent The type of event to record.
|
---|
| 230 | */
|
---|
| 231 | DECLHIDDEN(int) VUSBSnifferRecordEvent(VUSBSNIFFER hSniffer, PVUSBURB pUrb, VUSBSNIFFEREVENT enmEvent)
|
---|
| 232 | {
|
---|
| 233 | int rc = VINF_SUCCESS;
|
---|
| 234 | PVUSBSNIFFERINT pThis = hSniffer;
|
---|
| 235 |
|
---|
[53071] | 236 | /* Write the packet to the capture file. */
|
---|
| 237 | rc = RTSemFastMutexRequest(pThis->hMtx);
|
---|
[53014] | 238 | if (RT_SUCCESS(rc))
|
---|
[53071] | 239 | {
|
---|
[59615] | 240 | rc = pThis->pFmt->pfnRecordEvent((PVUSBSNIFFERFMTINT)&pThis->abFmt[0], pUrb, enmEvent);
|
---|
[53071] | 241 | RTSemFastMutexRelease(pThis->hMtx);
|
---|
| 242 | }
|
---|
| 243 |
|
---|
[53014] | 244 | return rc;
|
---|
| 245 | }
|
---|
| 246 |
|
---|