Приборкуємо USB/IP

Регулярно виникає завдання підключення USB-пристрою до віддаленого ПК через локальну мережу. Під катом викладено історію моїх пошуків у цьому напрямі, і шлях до готового рішення на базі open-source проекту USB/IP з описом дбайливо встановлених різними людьми цьому шляху перешкод, і навіть способів їх обходу.

Частина перша, історична

Якщо машина віртуальна – все це нескладно. Функціонал прокидання USB від хоста у віртуалку з'явився ще VMWare 4.1. Але в моєму випадку ключик захисту, що пізнається як WIBU-KEY, потрібно було в різні часи підключати до різних машин, і не тільки віртуальних.
Перший виток пошуку в далекому 2009 році привів мене до залізниці під назвою TrendNet TU2-NU4
Плюси:

  • іноді навіть працює

Мінуси:

  • працює не завжди. Допустимо, ключ захисту Guardant Stealth II через неї не заводиться, лаючись помилкою «пристрій не може бути запущений».
  • ПЗ для управління (читай - монтування та розмонтування USB-пристроїв) убого до крайності. Ключі командного рядка, автоматизація – ні, не чули. Все лише руками. Жах.
  • Керуюче програмне забезпечення шукає саму залізницю в мережі широкомовленням, тому працює це тільки в межах одного broadcast-сегменту мережі. Вказати IP-адресу залізця руками не можна. Залізниця в іншій підмережі? Тоді у вас є проблема.
  • розробники забили на пристрій, слати баг-репорти марно.

Другий виток стався в часи вже не такі віддалені, і привів мене до теми статті. USB/IP проект. Приваблює відкритістю, тим більше, що хлопці з ReactOS підписали їм драйвер для Windows, так що тепер навіть на x64 все працює без будь-яких милиць на зразок тестового режиму. За що команді ReactOS велике спасибі! Звучить все красиво, спробуємо помацати, чи так воно насправді? На жаль, сам проект теж підкинутий, і на підтримку розраховувати не доводиться - але де наша не пропадала, вихідник є, розберемося!

Частина друга, серверно-лінуксова

Сервер USB/IP, що розшарує USB-девайси по мережі, може бути піднятий тільки в Linux-based OS. Ну що ж, лінукс так лінукс, встановлюємо на віртуалку Debian 8 у мінімальній конфігурації, стандартний рух руками:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install usbip

Встановились. Далі інтернет підказує, що потрібно завантажити модуль usbip, але — привіт, перші граблі. Нема такого модуля. А все тому, що більшість посібників у мережі відносяться до старішої гілки 0.1.x, а в крайній 0.2.0 модулі usbip мають інші назви.

Тому:

sudo modprobe usbip-core
sudo modprobe usbip-host
sudo lsmod | grep usbip

Ну і додамо до /etc/modules такі рядки, щоб завантажувати їх автоматично при старті системи:

usbip-core
usbip-host
vhci-hcd

Запустимо сервер usbip:

sudo usbipd -D

Далі всесвітній розум нам підказує, що в комплекті з usbip йдуть скрипти, що дозволяють нам керувати сервером - показати, який пристрій він розшаруватиме по мережі, подивитися статус і так далі. Тут на нас чекає ще один садовий інструмент - ці скрипти у гілці 0.2.x, знову ж таки, перейменовані. Отримати список команд можна за допомогою

sudo usbip

Почитавши опис команд, стає зрозуміло, що для того, щоб розшарити необхідний USB-девайс, usbip хоче дізнатися про його Bus ID. Шановні глядачі, на арені граблі номер три: Bus ID, який видасть нам lsusb (здавалося б, найочевидніший шлях) - їй не підходить! Справа в тому, що залізниці на кшталт USB-хабів usbip ігнорує. Тому скористаємося вбудованою командою:

user@usb-server:~$ sudo usbip list -l
 - busid 1-1 (064f:0bd7)
   WIBU-Systems AG : BOX/U (064f:0bd7)

Примітка: тут і далі в лістингах я все описуватиму на прикладі мого конкретного USB-ключа. Ваша назва залізниці та пара VID:PID можуть і відрізнятимуться. Моя називається Wibu-Systems AG: BOX/U, VID 064F, PID 0BD7.

Тепер ми можемо розшарити наш пристрій:

user@usb-server:~$ sudo usbip bind --busid=1-1
usbip: info: bind device on busid 1-1: complete

УРА товариші!

user@usb-server:~$ sudo usbip list -r localhost
Exportable USB devices
======================
 - localhost
        1-1: WIBU-Systems AG : BOX/U (064f:0bd7)
           : /sys/devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb1/1-1
           : Vendor Specific Class / unknown subclass / unknown protocol (ff/00/ff)

Триразове ура, товариші! Сервер розшарив залізну мережу, і ми можемо її підключати! Залишилося тільки дописати автозапуск демона usbip /etc/rc.local

usbipd -D

Частина третя, клієнтська та заплутана

Підключити розшарований пристрій по мережі до машини під керуванням Debian я спробував відразу ж на тому ж сервері, і все чудово підключилося:

sudo usbip attach --remote=localhost --busid=1-1

Переходимо до Windows. Це був Windows Server 2008R2 Standard Edition. Офіційний посібник просить спочатку встановити драйвер. Процедура чудово описана в readme, що додається до windows-клієнту, робимо все як написано, все виходить. На XP теж працює без жодних труднощів.

Розпакувавши клієнт, пробуємо примонтувати наш ключик:

C:Program FilesUSB-IP>usbip -a %server-ip% 1-1
usbip err: usbip_network.c: 121 (usbip_recv_op_common) recv op_common, -1
usbip err: usbip_windows.c: 756 (query_interface0) recv op_common
usbip err: usbip_windows.c: 829 (attach_device) cannot find device

Ой ой. Щось пішло не так. Використовуємо навичку гугла. Зустрічаються уривчасті згадки, що щось там не так з константами, в серверній частині розробники при переході на версію 0.2.0 змінили версію протоколу, а ось у клієнті під Win це забули. Запропоноване рішення - поміняйте константу у вихіднику і перезберіть клієнт.

Ось тільки мені не хочеться качати Visual Studio заради цієї процедури. Зате у мене є старий-добрий Hiew. У вихіднику константа оголошено як подвійне слово. Шукаємо у файлі 0х00000106, замінюючи на 0х00000111. Не забуваємо, порядок байт зворотний. Підсумок - два збіги, патчим:

[usbip.exe]
00000CBC: 06 11
00000E0A: 06 11

ІІІІ… так!

C:Program FilesUSB-IP>usbip -a %server-ip% 1-1
new usb device attached to usbvbus port 1

На цьому можна було закінчити виклад, але музика грала недовго. Перезавантаживши сервер, я виявив, що пристрій на клієнті не вмонтовується!

C:Program FilesUSB-IP>usbip -a %server-ip% 1-1
usbip err: usbip_windows.c: 829 (attach_device) cannot find device

І все. На це мені не зміг відповісти навіть всезнаючий гугл. А при цьому команда відобразити доступні на сервері пристрої цілком коректно показує - він, ключ, можете монтувати. Пробую примонтувати з-під Linux – працює! А якщо тепер спробувати з-під Windows? Про жах - це працює!

Граблі останні: щось там у коді сервера не дописано. При розшаруванні пристрою він не зчитує кількість USB-дескрипторів. А при монтуванні пристрою з-під Linux це поле заповнюється. На жаль, з розробкою під Linux я знайомий на рівні «make & make install». Тому проблему вирішено за допомогою досить брудного хаку — додаванням до /etc/rc.local

usbip attach --remote=localhost --busid=1-1
usbip port
usbip detach --port=00

Частина заключна

Після деяких поневірянь, це працює. Бажане отримано, тепер ключ можна примонтувати до будь-якого ПК (і розмонтувати, звичайно, теж), у тому числі — за межами широкомовного сегменту мережі. Якщо хочеться, можна це зробити за допомогою скрипта командної оболонки. Що приємно – задоволення абсолютно безкоштовне.
Сподіваюся, що мій досвід допоможе хабражителям обійти ті граблі, які на мене відбити на лобі. Дякую за увагу!

Джерело: habr.com

Додати коментар або відгук