Rename project to SIMtrace Analyser (v2.0.0)

- move the analysis server out of simtrace2_pysniff into simtrace_analyser;
  simtrace2_pysniff stays as the simtrace2-sniff replacement capture utility
- new server CLI: simtrace-analyser-server; python -m simtrace_analyser
  (simtrace2-pysniff-server and python -m simtrace2_pysniff.server dropped)
- simtrace2_pysniff lazy-imports hardware symbols, so the server no longer
  pulls PyUSB at startup; the GSMTAP/PCAP codecs work without libusb
- version 2.0.0 everywhere (was 1.22.21); PWA SW cache simtrace-analyser-v54
- frontend: server name, clone URL and i18n strings updated; vendored-parser
  reference otaman -> SIMple
- README/README_RUS reworked product-first (analyser first, utility second)
- DB dir ~/.simtrace-analyser, /api status payload and hosted PWA unchanged
This commit is contained in:
catarrh committed 2026-09-19 12:34:16 +03:00
1 parent 8441b56e99
commit 38650b4797
20 files changed
+390 -321

No files matched your search

+69 -51
View File
@@ -1,15 +1,29 @@
# simtrace2-pysniff
# SIMtrace Analyser
English | [Русский](README_RUS.md)
Python-based replacement for `simtrace2-sniff` — SIM card communication sniffer
for Osmocom SIMtrace2 hardware (firmware in **trace** mode). It bundles the
**simtrace-analyser** PWA (in [`frontend/`](frontend/)) and an analysis server
that both captures APDU traffic and serves that PWA.
APDU trace analyser for the GSMTAP-SIM format — captures SIM/UICC
communication from a UDP GSMTAP stream (or imports PCAP/PCAPNG files),
decodes it, and serves an installable web app for browsing. The repository
also bundles **simtrace2-pysniff**, a Python replacement for
`simtrace2-sniff` that captures from Osmocom SIMtrace2 hardware and can feed
GSMTAP into this analyser.
**Single dependency**: PyUSB (libusb wrapper). No libosmocore, no libosmosim.
![SIMtrace Analyser PWA](frontend.png)
![simtrace-analyser PWA](frontend.png)
## Components
- **Analysis server + PWA** (`simtrace-analyser-server`) — stores captured
traffic in SQLite, decodes it, and serves the PWA ([`frontend/`](frontend/))
plus the HTTP API on a single origin. Three capture modes: a GSMTAP
listener, direct SIMtrace2 hardware capture, or disabled (browse existing
captures only).
- **Capture utility** (`simtrace2-pysniff`) — captures SIMtrace2 hardware
traffic and writes it to stdout, GSMTAP (Wireshark), or PCAP files. It is
one GSMTAP source of several that the analyser accepts (see also
[sigrok_iso7816_stream](https://github.com/anttro/sigrok_iso7816_stream)).
- **PWA** ([`frontend/`](frontend/)) — trace browser with decoded APDU,
SIM Toolkit, SMS and SCP80 OTA detail; sessions, PCAP import, EN/RU UI.
## Features
@@ -38,7 +52,7 @@ that both captures APDU traffic and serves that PWA.
decryption for ciphered packets
- ATR parse (clock-rate conversion, Fi/Di, T-bitmask) and FCP/FCI TLV
**simtrace-analyser PWA** ([`frontend/`](frontend/)):
**SIMtrace Analyser PWA** ([`frontend/`](frontend/)):
- Trace view with Map/List modes — proactive, TERMINAL RESPONSE, ENVELOPE
and AUTH commands get distinctive styling in map view
@@ -49,20 +63,22 @@ that both captures APDU traffic and serves that PWA.
## Prerequisites
- **Python 3.9+**
- **PyUSB** — `pip install pyusb`
- **PyUSB** — `pip install pyusb` (needed only for capture from SIMtrace2
hardware; GSMTAP/UDP capture and PCAP import work without it)
- **libusb** — system library, present by default on Linux; on Windows the
SIMtrace2 driver must be swapped (see [USB Device Access](#usb-device-access))
- **SIMtrace2 hardware** running firmware in *trace* mode
(VID `1d50`, PID `60e3`, USB class `ff`, subclass `01`). For building and
flashing trace firmware, see the [upstream SIMtrace2 project](https://gitea.osmocom.org/sim-card/simtrace2).
- **SIMtrace2 hardware** running firmware in *trace* mode (only for direct
capture; VID `1d50`, PID `60e3`, USB class `ff`, subclass `01`). For
building and flashing trace firmware, see the
[upstream SIMtrace2 project](https://gitea.osmocom.org/sim-card/simtrace2).
No other dependencies. PCAP, GSMTAP, and hex dump output use only Python stdlib.
## Install
```sh
git clone https://github.com/anttro/simtrace2-pysniff.git
cd simtrace2-pysniff
git clone https://github.com/anttro/simtrace-analyser.git
cd simtrace-analyser
pip install pyusb
```
@@ -70,52 +86,27 @@ Or install the package into your environment:
```sh
pip install -e .
# then run: simtrace2-pysniff [opts]
# then run: simtrace-analyser-server [opts]
# or: simtrace2-pysniff [opts]
```
## Running
Two tools are provided:
### Sniffer CLI (`simtrace2-pysniff`)
Captures SIMtrace2 traffic and writes it to stdout, GSMTAP (Wireshark), or PCAP files.
### Startup script
`./sniff-start.sh` performs a pre-flight USB permission check (prints udev
install instructions if the SIMtrace2 device is not writable) and then
launches the Python module. On Windows, use `sniff-start.bat` with the same
options (no permission check needed).
```sh
./sniff-start.sh
./sniff-start.sh --format timestamp
./sniff-start.sh --gsmtap 127.0.0.1:4729
./sniff-start.sh --pcap trace.pcap --format atr-time
```
OPTIONS can also be set via environment variables:
```sh
FORMAT=timestamp GSMTAP=127.0.0.1 ./sniff-start.sh
```
### Analysis server + PWA (`simtrace2-pysniff-server`)
### Analysis server + PWA (`simtrace-analyser-server`)
Stores captured APDU traffic in SQLite and serves it over HTTP, together with
the bundled **simtrace-analyser** PWA (`frontend/`) on the same origin. Three
the bundled **SIMtrace Analyser** PWA (`frontend/`) on the same origin. Three
capture modes:
```sh
# Listen for GSMTAP from simtrace2-pysniff (or original simtrace2-sniff):
simtrace2-pysniff-server --capture gsmtap
simtrace-analyser-server --capture gsmtap
# Capture directly from SIMtrace2 hardware (no external tool needed):
simtrace2-pysniff-server --capture direct
simtrace-analyser-server --capture direct
# Browse/analyse existing captures without a capture backend:
simtrace2-pysniff-server --capture disabled
simtrace-analyser-server --capture disabled
```
The server logs its capture liveness to stderr (each line timestamped
@@ -166,7 +157,7 @@ setup is involved. Use `--web-dir PATH` to serve a different PWA directory
A standalone copy of the PWA is hosted at **https://simtrace.atroshin.ru**.
It is a pure frontend: point it (Settings → Server URL) at a locally running
`simtrace2-pysniff-server`.
`simtrace-analyser-server`.
> **Browser restriction:** when the PWA is served from a public HTTPS host,
> reaching a local server (`http://127.0.0.1:8081`) requires two things: the
@@ -176,7 +167,31 @@ It is a pure frontend: point it (Settings → Server URL) at a locally running
> (or accept the permission prompt). Without the browser permission, the
> request to `127.0.0.1` is blocked before any preflight is sent.
### Python module (cross-platform)
### Capture utility (`simtrace2-pysniff`)
Captures SIMtrace2 hardware traffic and writes it to stdout, GSMTAP
(Wireshark), or PCAP files. It is the bundled replacement for the original
Osmocom `simtrace2-sniff`.
The `./sniff-start.sh` startup script performs a pre-flight USB permission
check (prints udev install instructions if the SIMtrace2 device is not
writable) and then launches the Python module. On Windows, use
`sniff-start.bat` with the same options (no permission check needed).
```sh
./sniff-start.sh
./sniff-start.sh --format timestamp
./sniff-start.sh --gsmtap 127.0.0.1:4729
./sniff-start.sh --pcap trace.pcap --format atr-time
```
OPTIONS can also be set via environment variables:
```sh
FORMAT=timestamp GSMTAP=127.0.0.1 ./sniff-start.sh
```
Cross-platform module invocation:
```sh
python -m simtrace2_pysniff
@@ -192,6 +207,9 @@ simtrace2-pysniff --format atr-time
## USB Device Access
Required for capture from SIMtrace2 hardware (the utility and the server's
`--capture direct` mode); not needed for GSMTAP or PCAP sources.
### Linux
A udev rule is required for non-root USB access to the SIMtrace2 device.
@@ -218,7 +236,7 @@ Windows does not ship a libusb-compatible driver for SIMtrace2. Use
After that, `python -m simtrace2_pysniff` works identically to Linux.
## CLI Options
## Utility CLI Options
```
python -m simtrace2_pysniff [OPTIONS]
@@ -279,14 +297,14 @@ for msg in session.iter_messages():
## Recovery
The tool survives hardware resets, cable disconnects, and firmware hangs
The utility survives hardware resets, cable disconnects, and firmware hangs
by default — it reconnects with exponential backoff (1s → 30s cap).
Use `--inactivity-timeout` to also trigger reconnect on silent firmware hangs.
## Related
- **[simtrace2](https://gitea.osmocom.org/sim-card/simtrace2)** — the upstream
SIMtrace2 hardware/firmware project that this tool sniffs from.
SIMtrace2 hardware/firmware project that the capture utility sniffs from.
- **[sigrok_iso7816_stream](https://github.com/anttro/sigrok_iso7816_stream)** —
FX2LP-based passive ISO 7816 sniffer that emits the same GSMTAP-SIM stream
on UDP 4729 (accepted by this project's GSMTAP listener).
+70 -54
View File
@@ -1,16 +1,30 @@
# simtrace2-pysniff
# SIMtrace Analyser
[English](README.md) | Русский
Замена `simtrace2-sniff` на Python — сниффер обмена с SIM-картой для
оборудования Osmocom SIMtrace2 (прошивка в режиме **trace**). Включает PWA
**simtrace-analyser** (в [`frontend/`](frontend/)) и анализирующий сервер,
который и захватывает APDU-трафик, и отдаёт эту PWA.
Анализатор APDU-трассировок в формате GSMTAP-SIM — захватывает обмен с
SIM/UICC из UDP-потока GSMTAP (или импортирует файлы PCAP/PCAPNG),
декодирует его и отдаёт устанавливаемое веб-приложение для просмотра.
В репозиторий также включён **simtrace2-pysniff** — замена `simtrace2-sniff`
на Python, которая захватывает трафик с оборудования Osmocom SIMtrace2
и может передавать GSMTAP этому анализатору.
**Единственная зависимость**: PyUSB (обёртка над libusb). Без libosmocore,
без libosmosim.
![PWA SIMtrace Analyser](frontend.png)
![simtrace-analyser PWA](frontend.png)
## Компоненты
- **Анализирующий сервер + PWA** (`simtrace-analyser-server`) — сохраняет
захваченный трафик в SQLite, декодирует его и отдаёт PWA
([`frontend/`](frontend/)) вместе с HTTP API на одном origin. Три режима
захвата: GSMTAP-листенер, захват напрямую с оборудования SIMtrace2 или
отключённый захват (только просмотр существующих записей).
- **Утилита захвата** (`simtrace2-pysniff`) — захватывает трафик
оборудования SIMtrace2 и выводит его в stdout, GSMTAP (Wireshark) или
PCAP-файлы. Это один из нескольких источников GSMTAP, которые принимает
анализатор (см. также
[sigrok_iso7816_stream](https://github.com/anttro/sigrok_iso7816_stream)).
- **PWA** ([`frontend/`](frontend/)) — окно трассировки с декодированными
APDU, SIM Toolkit, SMS и SCP80 OTA; сессии, импорт PCAP, интерфейс EN/RU.
## Возможности
@@ -41,7 +55,7 @@
- Разбор ATR (пересчёт тактовой частоты, Fi/Di, битовая маска T)
и FCP/FCI TLV
**PWA simtrace-analyser** ([`frontend/`](frontend/)):
**PWA SIMtrace Analyser** ([`frontend/`](frontend/)):
- Окно трассировки с режимами «Карта»/«Список» — proactive,
TERMINAL RESPONSE, ENVELOPE и AUTH-команды выделяются в режиме карты
@@ -52,13 +66,14 @@
## Требования
- **Python 3.9+**
- **PyUSB** — `pip install pyusb`
- **PyUSB** — `pip install pyusb` (нужен только для захвата с оборудования
SIMtrace2; захват GSMTAP/UDP и импорт PCAP работают без него)
- **libusb** — системная библиотека, обычно уже есть в Linux; в Windows
нужно заменить драйвер SIMtrace2
(см. [Доступ к USB-устройству](#доступ-к-usb-устройству))
- **Оборудование SIMtrace2** с прошивкой в режиме *trace*
(VID `1d50`, PID `60e3`, USB class `ff`, subclass `01`). О сборке
и прошивке trace-прошивки см.
- **Оборудование SIMtrace2** с прошивкой в режиме *trace* (только для
прямого захвата; VID `1d50`, PID `60e3`, USB class `ff`, subclass `01`).
О сборке и прошивке trace-прошивки см.
[проект SIMtrace2](https://gitea.osmocom.org/sim-card/simtrace2).
Других зависимостей нет. Вывод PCAP, GSMTAP и hex dump использует только
@@ -67,8 +82,8 @@
## Установка
```sh
git clone https://github.com/anttro/simtrace2-pysniff.git
cd simtrace2-pysniff
git clone https://github.com/anttro/simtrace-analyser.git
cd simtrace-analyser
pip install pyusb
```
@@ -76,53 +91,27 @@ pip install pyusb
```sh
pip install -e .
# затем запуск: simtrace2-pysniff [opts]
# затем запуск: simtrace-analyser-server [opts]
# или: simtrace2-pysniff [opts]
```
## Запуск
Предоставляются два инструмента:
### CLI сниффера (`simtrace2-pysniff`)
Захватывает трафик SIMtrace2 и выводит его в stdout, GSMTAP (Wireshark)
или файлы PCAP.
### Скрипт запуска
`./sniff-start.sh` выполняет предварительную проверку прав доступа к USB
(при неудаче печатает инструкцию по установке udev-правила) и затем
запускает модуль Python. В Windows используйте `sniff-start.bat` с теми же
параметрами (проверка прав не требуется).
```sh
./sniff-start.sh
./sniff-start.sh --format timestamp
./sniff-start.sh --gsmtap 127.0.0.1:4729
./sniff-start.sh --pcap trace.pcap --format atr-time
```
Параметры также можно задавать через переменные окружения:
```sh
FORMAT=timestamp GSMTAP=127.0.0.1 ./sniff-start.sh
```
### Анализирующий сервер + PWA (`simtrace2-pysniff-server`)
### Анализирующий сервер + PWA (`simtrace-analyser-server`)
Сохраняет захваченный APDU-трафик в SQLite и отдаёт его по HTTP вместе
со встроенной PWA **simtrace-analyser** (`frontend/`) на том же origin.
со встроенной PWA **SIMtrace Analyser** (`frontend/`) на том же origin.
Три режима захвата:
```sh
# Слушать GSMTAP от simtrace2-pysniff (или оригинального simtrace2-sniff):
simtrace2-pysniff-server --capture gsmtap
simtrace-analyser-server --capture gsmtap
# Захват напрямую с оборудования SIMtrace2 (внешний инструмент не нужен):
simtrace2-pysniff-server --capture direct
simtrace-analyser-server --capture direct
# Просмотр/анализ существующих записей без бэкенда захвата:
simtrace2-pysniff-server --capture disabled
simtrace-analyser-server --capture disabled
```
Сервер пишет в stderr информацию о жизненном цикле захвата (каждая строка
@@ -174,7 +163,7 @@ CORS/Private-Network-Access не требуется. Используйте `--w
Автономная копия PWA размещена на **https://simtrace.atroshin.ru**.
Это чистый фронтенд: укажите в нём (Settings → Server URL) адрес
локально запущенного `simtrace2-pysniff-server`.
локально запущенного `simtrace-analyser-server`.
> **Ограничение браузера:** когда PWA отдаётся с публичного HTTPS-хоста,
> доступ к локальному серверу (`http://127.0.0.1:8081`) требует двух
@@ -185,7 +174,31 @@ CORS/Private-Network-Access не требуется. Используйте `--w
> разрешить сайту (или принять запрос разрешения). Без разрешения
> браузера запрос к `127.0.0.1` блокируется ещё до отправки preflight.
### Модуль Python (кроссплатформенный)
### Утилита захвата (`simtrace2-pysniff`)
Захватывает трафик оборудования SIMtrace2 и выводит его в stdout, GSMTAP
(Wireshark) или PCAP-файлы. Это встроенная замена оригинального
инструмента Osmocom `simtrace2-sniff`.
Скрипт запуска `./sniff-start.sh` выполняет предварительную проверку прав
доступа к USB (при неудаче печатает инструкцию по установке udev-правила)
и затем запускает модуль Python. В Windows используйте `sniff-start.bat`
с теми же параметрами (проверка прав не требуется).
```sh
./sniff-start.sh
./sniff-start.sh --format timestamp
./sniff-start.sh --gsmtap 127.0.0.1:4729
./sniff-start.sh --pcap trace.pcap --format atr-time
```
Параметры также можно задавать через переменные окружения:
```sh
FORMAT=timestamp GSMTAP=127.0.0.1 ./sniff-start.sh
```
Кроссплатформенный запуск модуля:
```sh
python -m simtrace2_pysniff
@@ -202,6 +215,9 @@ simtrace2-pysniff --format atr-time
## Доступ к USB-устройству
Нужен для захвата с оборудования SIMtrace2 (утилита и режим
`--capture direct` сервера); для источников GSMTAP и PCAP не требуется.
### Linux
Для доступа к устройству SIMtrace2 без root нужно udev-правило.
@@ -229,7 +245,7 @@ sudo udevadm trigger
После этого `python -m simtrace2_pysniff` работает так же, как в Linux.
## Параметры CLI
## Параметры CLI утилиты
```
python -m simtrace2_pysniff [OPTIONS]
@@ -295,15 +311,15 @@ for msg in session.iter_messages():
## Восстановление
Инструмент по умолчанию переживает сбросы оборудования, отключения кабеля
и зависания прошивки — он переподключается с экспоненциальной задержкой
Утилита по умолчанию переживает сбросы оборудования, отключения кабеля
и зависания прошивки — она переподключается с экспоненциальной задержкой
(1с → 30с). Используйте `--inactivity-timeout`, чтобы также переподключаться
при «тихих» зависаниях прошивки.
## Связанные проекты
- **[simtrace2](https://gitea.osmocom.org/sim-card/simtrace2)** — вышестоящий
проект оборудования/прошивки SIMtrace2, с которого этот инструмент
проект оборудования/прошивки SIMtrace2, с которого утилита захвата
снимает трафик.
- **[sigrok_iso7816_stream](https://github.com/anttro/sigrok_iso7816_stream)** —
пассивный ISO 7816 сниффер на базе FX2LP, выдающий такой же поток
+17 -17
View File
@@ -297,7 +297,7 @@ body { font: 14px/1.5 system-ui, sans-serif; background: var(--bg); color: var(-
<div class="header-right">
<span class="capture-chip" id="capture-chip" style="display:none"></span>
<button id="install-btn" data-l10n="Install PWA">Install PWA</button>
<a href="https://github.com/anttro/simtrace2-pysniff" target="_blank" rel="noopener">GitHub</a>
<a href="https://github.com/anttro/simtrace-analyser" target="_blank" rel="noopener">GitHub</a>
<button id="lang-btn" onclick="toggleLang()" title="Language / Язык">EN</button>
<button id="theme-btn" onclick="toggleTheme()">☀️</button>
</div>
@@ -676,7 +676,7 @@ function desCbcDecrypt(keyBytes, ivBytes, ctBytes) {
return out;
}
// ──────────────────── C-APDU parsing (vendored from otaman) ────────────────────
// ──────────────────── C-APDU parsing (vendored from SIMple) ────────────────────
// Parses C-APDU hex streams (e.g. SCP80 secured-packet application messages)
// into {label, hex, desc, children} trees.
const PARSE_INS = {
@@ -2504,16 +2504,16 @@ function updateVersionWarn(serverVersion) {
const elv = el('version-warn');
const sv = parseVersion(serverVersion);
if (sv === null) {
elv.textContent = t('Server version unknown — update simtrace2-pysniff-server.');
elv.textContent = t('Server version unknown — update simtrace-analyser-server.');
return;
}
const cmpMin = compareVersions(serverVersion, MIN_SERVER_VERSION);
if (cmpMin !== null && cmpMin < 0) {
elv.textContent = t('Server version {v} is outdated. Please update simtrace2-pysniff-server.').replace('{v}', serverVersion);
elv.textContent = t('Server version {v} is outdated. Please update simtrace-analyser-server.').replace('{v}', serverVersion);
return;
}
if (sv[0] > parseVersion(PWA_VERSION)[0]) {
elv.textContent = t('Server version {v} is newer than expected. Update simtrace2-pysniff for full compatibility.').replace('{v}', serverVersion);
elv.textContent = t('Server version {v} is newer than expected. Update SIMtrace Analyser for full compatibility.').replace('{v}', serverVersion);
return;
}
elv.textContent = '';
@@ -2635,9 +2635,9 @@ async function checkConnection() {
el('conn-instructions').innerHTML = `
<h3>${t('Setup')}</h3>
<ol>
<li>${t('Clone and install simtrace2-pysniff:')}<br>
<code>git clone https://github.com/anttro/simtrace2-pysniff.git</code><br>
<code>cd simtrace2-pysniff && pip install -e .</code></li>
<li>${t('Clone and install SIMtrace Analyser:')}<br>
<code>git clone https://github.com/anttro/simtrace-analyser.git</code><br>
<code>cd simtrace-analyser && pip install -e .</code></li>
<li>${t('Start the server in direct mode (recommended):')}<br>
<code>./start.sh --capture direct</code><br>
<span style="color:var(--text-muted);">${t('Requires SIMtrace2 hardware connected via USB; captures directly from the device.')}</span></li>
@@ -2681,7 +2681,7 @@ function onFilterChange() {
}
// ──────────────────── Versioning ────────────────────
const PWA_VERSION = '1.22.21';
const PWA_VERSION = '2.0.0';
const MIN_SERVER_VERSION = '1.0.0';
function parseVersion(v) {
@@ -2705,8 +2705,8 @@ function compareVersions(a, b) {
// ──────────────────── i18n ────────────────────
let currentLang = 'en';
const HINT_BLOCKED = 'The browser likely blocked access to the local server. Allow local network access for this site (Chrome/Edge/Vivaldi: Site settings → Local network access → Allow) and confirm simtrace2-pysniff-server is running at {url}.';
const HINT_UNREACHABLE = 'Couldn\'t reach the server. Check that simtrace2-pysniff-server is running and the URL is correct ({url}). If this page is served over HTTPS, also allow local network access in the browser (Site settings → Local network access → Allow).';
const HINT_BLOCKED = 'The browser likely blocked access to the local server. Allow local network access for this site (Chrome/Edge/Vivaldi: Site settings → Local network access → Allow) and confirm simtrace-analyser-server is running at {url}.';
const HINT_UNREACHABLE = 'Couldn\'t reach the server. Check that simtrace-analyser-server is running and the URL is correct ({url}). If this page is served over HTTPS, also allow local network access in the browser (Site settings → Local network access → Allow).';
const LANG_RU = {
'Trace': 'Трассировка',
@@ -2785,10 +2785,10 @@ const LANG_RU = {
'Empty file': 'Пустой файл',
'Install from the address bar:\nclick the install icon (⊕ / monitor icon) at the right\nend of Chrome\'s address bar, then "Install SIMtrace Analyser".':
'Установка из адресной строки:\nнажмите значок установки (⊕ / значок монитора) в правом\nконце адресной строки Chrome, затем «Установить SIMtrace Analyser».',
[HINT_BLOCKED]: 'Браузер, вероятно, заблокировал доступ к локальному серверу. Разрешите доступ к локальной сети для этого сайта (Chrome/Edge/Vivaldi: Настройки сайта → Доступ к локальной сети → Разрешить) и убедитесь, что simtrace2-pysniff-server запущен по адресу {url}.',
[HINT_UNREACHABLE]: 'Не удалось связаться с сервером. Проверьте, что simtrace2-pysniff-server запущен и URL указан верно ({url}). Если эта страница открыта по HTTPS, также разрешите доступ к локальной сети в браузере (Настройки сайта → Доступ к локальной сети → Разрешить).',
[HINT_BLOCKED]: 'Браузер, вероятно, заблокировал доступ к локальному серверу. Разрешите доступ к локальной сети для этого сайта (Chrome/Edge/Vivaldi: Настройки сайта → Доступ к локальной сети → Разрешить) и убедитесь, что simtrace-analyser-server запущен по адресу {url}.',
[HINT_UNREACHABLE]: 'Не удалось связаться с сервером. Проверьте, что simtrace-analyser-server запущен и URL указан верно ({url}). Если эта страница открыта по HTTPS, также разрешите доступ к локальной сети в браузере (Настройки сайта → Доступ к локальной сети → Разрешить).',
'Setup': 'Настройка',
'Clone and install simtrace2-pysniff:': 'Клонируйте и установите simtrace2-pysniff:',
'Clone and install SIMtrace Analyser:': 'Клонируйте и установите SIMtrace Analyser:',
'Start the server in direct mode (recommended):': 'Запустите сервер в режиме direct (рекомендуется):',
'Requires SIMtrace2 hardware connected via USB; captures directly from the device.': 'Требуется оборудование SIMtrace2, подключённое по USB; захват выполняется напрямую с устройства.',
'Then set the URL above to http://127.0.0.1:8081 and return to the Trace tab.': 'Затем укажите URL выше (http://127.0.0.1:8081) и вернитесь на вкладку «Трассировка».',
@@ -2797,9 +2797,9 @@ const LANG_RU = {
'Start the server:': 'Запустите сервер:',
'Start a GSMTAP source in another terminal — either:': 'Запустите источник GSMTAP в другом терминале — либо:',
'(original Osmocom tool)': '(оригинальный инструмент Osmocom)',
'Server version unknown — update simtrace2-pysniff-server.': 'Версия сервера неизвестна — обновите simtrace2-pysniff-server.',
'Server version {v} is outdated. Please update simtrace2-pysniff-server.': 'Версия сервера {v} устарела. Обновите simtrace2-pysniff-server.',
'Server version {v} is newer than expected. Update simtrace2-pysniff for full compatibility.': 'Версия сервера {v} новее ожидаемой. Обновите simtrace2-pysniff для полной совместимости.',
'Server version unknown — update simtrace-analyser-server.': 'Версия сервера неизвестна — обновите simtrace-analyser-server.',
'Server version {v} is outdated. Please update simtrace-analyser-server.': 'Версия сервера {v} устарела. Обновите simtrace-analyser-server.',
'Server version {v} is newer than expected. Update SIMtrace Analyser for full compatibility.': 'Версия сервера {v} новее ожидаемой. Обновите SIMtrace Analyser для полной совместимости.',
'Capture mode: GSMTAP — the server is listening for incoming UDP/GSMTAP traffic. Ensure a GSMTAP source (e.g. simtrace2-pysniff or simtrace2-sniff) is feeding the server.': 'Режим захвата: GSMTAP — сервер ожидает входящий UDP/GSMTAP-трафик. Убедитесь, что источник GSMTAP (например, simtrace2-pysniff или simtrace2-sniff) передаёт данные серверу.',
'Capture mode: direct — the server captures from SIMtrace2 hardware. Keep the device connected.': 'Режим захвата: direct — сервер захватывает данные с устройства SIMtrace2. Не отключайте устройство.',
'Capture is disabled — only pre-captured traces (saved sessions / PCAP import) are available.': 'Захват отключён — доступны только ранее записанные трассировки (сохранённые сессии / импорт PCAP).',
+1 -1
View File
@@ -1,4 +1,4 @@
const CACHE = 'simtrace-analyser-v53';
const CACHE = 'simtrace-analyser-v54';
const PRECACHE = [
'index.html',
+5 -5
View File
@@ -3,9 +3,9 @@ requires = ["setuptools>=64"]
build-backend = "setuptools.backends._legacy:_Backend"
[project]
name = "simtrace2-pysniff"
version = "1.22.21"
description = "Python-based sniffing tool for SIMtrace2 hardware (SIM card communication sniffer)"
name = "simtrace-analyser"
version = "2.0.0"
description = "SIMtrace Analyser — APDU trace analyser for GSMTAP/PCAP captures (bundles the simtrace2-pysniff utility)"
readme = {file = "README.md", content-type = "text/markdown"}
license = {text = "GPL-2.0-or-later"}
requires-python = ">=3.9"
@@ -14,8 +14,8 @@ dependencies = [
]
[project.scripts]
simtrace-analyser-server = "simtrace_analyser.__main__:main"
simtrace2-pysniff = "simtrace2_pysniff.__main__:main"
simtrace2-pysniff-server = "simtrace2_pysniff.server.__main__:main"
[tool.setuptools.packages.find]
include = ["simtrace2_pysniff*"]
include = ["simtrace_analyser*", "simtrace2_pysniff*"]
+31 -7
View File
@@ -1,12 +1,11 @@
"""simtrace2-pysniff — Python replacement for simtrace2-sniff."""
"""simtrace2-pysniff — Python replacement for simtrace2-sniff.
from .device import SniffSession, DeviceDisconnected, find_sniffer_device
from .protocol import parse_message, SniffMessage
from .gsmtap import GsmtapSender, GsmtapReceiver
from .pcap import PcapWriter
from .dump import FileDumper, format_message
Capture utility bundled with SIMtrace Analyser. Hardware access (PyUSB) is
imported lazily, so the GSMTAP/PCAP codec modules can be used without libusb.
"""
from simtrace_analyser.version import __version__
__version__ = '1.22.21'
__all__ = [
'SniffSession',
'DeviceDisconnected',
@@ -20,3 +19,28 @@ __all__ = [
'format_message',
'__version__',
]
_LAZY_IMPORTS = {
'SniffSession': ('.device', 'SniffSession'),
'DeviceDisconnected': ('.device', 'DeviceDisconnected'),
'find_sniffer_device': ('.device', 'find_sniffer_device'),
'parse_message': ('.protocol', 'parse_message'),
'SniffMessage': ('.protocol', 'SniffMessage'),
'GsmtapSender': ('.gsmtap', 'GsmtapSender'),
'GsmtapReceiver': ('.gsmtap', 'GsmtapReceiver'),
'PcapWriter': ('.pcap', 'PcapWriter'),
'FileDumper': ('.dump', 'FileDumper'),
'format_message': ('.dump', 'format_message'),
}
def __getattr__(name):
"""Import utility symbols on first use (PEP 562)."""
try:
module_name, attr = _LAZY_IMPORTS[name]
except KeyError:
raise AttributeError(f'module {__name__!r} has no attribute {name!r}') from None
from importlib import import_module
value = getattr(import_module(module_name, __name__), attr)
globals()[name] = value
return value
-1
View File
@@ -1 +0,0 @@
"""simtrace2-pysniff server sub-package."""
+9
View File
@@ -0,0 +1,9 @@
"""simtrace_analyser — server side of SIMtrace Analyser.
Stores captured GSMTAP/PCAP APDU traffic in SQLite, decodes it, and serves
the PWA (``frontend/``) plus the HTTP API on a single origin.
"""
from .version import __version__
__all__ = ['__version__']
@@ -1,8 +1,8 @@
"""simtrace2-pysniff-server — CLI entry point.
"""simtrace-analyser-server — CLI entry point.
Usage:
simtrace2-pysniff-server --capture gsmtap [--gsmtap-port 4729] [--port 8081]
simtrace2-pysniff-server --capture direct [--port 8081]
simtrace-analyser-server --capture gsmtap [--gsmtap-port 4729] [--port 8081]
simtrace-analyser-server --capture direct [--port 8081]
"""
import argparse
@@ -13,19 +13,19 @@ from http.server import HTTPServer
from .server import RequestHandler
from .database import Database, DEFAULT_DB_PATH
from .capture import CaptureManager, GsmtapListener, DirectSniffer
from .. import __version__
from .version import __version__
def _default_web_dir():
# <repo>/frontend, whether run from source or an editable install.
# __file__ is <repo>/simtrace2_pysniff/server/__main__.py → up three levels.
return os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), 'frontend')
# __file__ is <repo>/simtrace_analyser/__main__.py → up two levels.
return os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'frontend')
def main():
p = argparse.ArgumentParser(
prog='simtrace2-pysniff-server',
description='HTTP API + PWA server for SIMtrace2 APDU capture and analysis')
prog='simtrace-analyser-server',
description='HTTP API + PWA server for APDU trace capture and analysis')
p.add_argument('--host', default='127.0.0.1',
help='HTTP bind address (default: 127.0.0.1)')
p.add_argument('--port', type=int, default=8081,
@@ -63,7 +63,7 @@ def main():
server = HTTPServer((args.host, args.port), RequestHandler)
server.web_dir = args.web_dir
print(f'simtrace2-pysniff-server v{__version__} — http://{args.host}:{args.port}', file=sys.stderr)
print(f'simtrace-analyser-server v{__version__} — http://{args.host}:{args.port}', file=sys.stderr)
print(f' capture mode: {args.capture}', file=sys.stderr)
if args.capture == 'gsmtap':
print(f' GSMTAP port: {args.gsmtap_port}', file=sys.stderr)
@@ -6,7 +6,7 @@ import threading
import time
import traceback
from ..gsmtap import (GsmtapReceiver, GSMTAP_SIM_ATR,
from simtrace2_pysniff.gsmtap import (GsmtapReceiver, GSMTAP_SIM_ATR,
GSMTAP_SIM_PPS_REQ, GSMTAP_SIM_PPS_RSP,
GSMTAP_SIM_RST_EVENT, GSMTAP_SIM_VCC_EVENT)
@@ -76,7 +76,7 @@ class GsmtapListener:
class DirectSniffer:
def __init__(self):
from ..device import SniffSession
from simtrace2_pysniff.device import SniffSession
self._session = SniffSession(
reconnect=True,
reconnect_delay_min=1.0,
@@ -98,7 +98,7 @@ class DirectSniffer:
self._session.close()
def iter_messages(self):
from ..device import DeviceDisconnected
from simtrace2_pysniff.device import DeviceDisconnected
try:
for msg in self._session.iter_messages():
if not self._running:
@@ -398,7 +398,7 @@ class Database:
# Only card-level changes invalidate the selection. A
# waiting-time timeout interrupts a single TPDU but leaves the
# card selected, so the phone usually just retries.
from ..protocol import (
from simtrace2_pysniff.protocol import (
CHANGE_FLAG_CARD_INSERT, CHANGE_FLAG_CARD_EJECT,
CHANGE_FLAG_RESET_ASSERT, CHANGE_FLAG_RESET_DEASSERT,
)
@@ -4,7 +4,7 @@ Pure Python, no dependencies. Decodes raw TPDU bytes captured by
the SIMtrace2 sniffer into structured dicts for the PWA to display.
"""
from ..gsmtap import GSMTAP_FLAG_BAD_FCS
from simtrace2_pysniff.gsmtap import GSMTAP_FLAG_BAD_FCS
# ──────────────────── Status Word names ────────────────────
@@ -1,4 +1,4 @@
"""HTTP API + static PWA server for simtrace2-pysniff."""
"""HTTP API + static PWA server for SIMtrace Analyser."""
import json
import os
@@ -11,9 +11,9 @@ from urllib.parse import urlparse, parse_qs, quote
from .database import Database
from .capture import CaptureManager, GsmtapListener, DirectSniffer, _log
from ..gsmtap import build_gsmtap_packet, GSMTAP_SIM_ATR, GSMTAP_SIM_APDU
from ..pcap import build_pcap, parse_pcap, parse_pcapng
from .. import __version__
from simtrace2_pysniff.gsmtap import build_gsmtap_packet, GSMTAP_SIM_ATR, GSMTAP_SIM_APDU
from simtrace2_pysniff.pcap import build_pcap, parse_pcap, parse_pcapng
from .version import __version__
# Static file serving (the PWA lives in <repo>/frontend, served by this server
+3
View File
@@ -0,0 +1,3 @@
"""Single source of truth for the SIMtrace Analyser version."""
__version__ = '2.0.0'
+3 -3
View File
@@ -1,7 +1,7 @@
@echo off
setlocal enabledelayedexpansion
:: simtrace2-pysniff-server startup script for Windows
:: simtrace-analyser-server startup script for Windows
::
:: Usage: start.bat [--capture gsmtap|direct] [--port PORT] [--db PATH] [--gsmtap-port PORT]
::
@@ -47,8 +47,8 @@ shift
goto :parse_args
:run
echo Starting simtrace2-pysniff-server...
echo Starting simtrace-analyser-server...
echo PWA (simtrace-analyser) will be served at http://127.0.0.1:%PORT%/
set "PYTHONPATH=%~dp0"
python -m simtrace2_pysniff.server --capture %CAPTURE% --port %PORT% --gsmtap-port %GSMTAP_PORT% %EXTRA_ARGS%
python -m simtrace_analyser --capture %CAPTURE% --port %PORT% --gsmtap-port %GSMTAP_PORT% %EXTRA_ARGS%
+3 -3
View File
@@ -1,5 +1,5 @@
#!/bin/bash
# simtrace2-pysniff-server startup script
# simtrace-analyser-server startup script
#
# Usage: ./start.sh [--capture gsmtap|direct] [--port PORT] [--db PATH] [--gsmtap-port PORT]
#
@@ -71,6 +71,6 @@ ARGS+=(--port "$PORT")
[[ "$CAPTURE" == "gsmtap" ]] && ARGS+=(--gsmtap-port "$GSMTAP_PORT")
ARGS+=("${EXTRA_ARGS[@]}")
echo "Starting simtrace2-pysniff-server..." >&2
echo "Starting simtrace-analyser-server..." >&2
echo "PWA (simtrace-analyser) will be served at http://127.0.0.1:$PORT/" >&2
exec env PYTHONPATH="$PROJECT_DIR" python3 -m simtrace2_pysniff.server "${ARGS[@]}"
exec env PYTHONPATH="$PROJECT_DIR" python3 -m simtrace_analyser "${ARGS[@]}"
+7 -7
View File
@@ -7,8 +7,8 @@ import tempfile
import time
import unittest
from simtrace2_pysniff.server.capture import CaptureManager, gsmtap_msg_type
from simtrace2_pysniff.server.database import Database
from simtrace_analyser.capture import CaptureManager, gsmtap_msg_type
from simtrace_analyser.database import Database
class TestGsmtapSubtypeMapping(unittest.TestCase):
@@ -67,7 +67,7 @@ class TestCaptureManager(unittest.TestCase):
self.assertEqual(db.count_messages(sid), 1)
def test_direct_sniffer_device_disconnect(self):
from simtrace2_pysniff.server.capture import DirectSniffer
from simtrace_analyser.capture import DirectSniffer
sn = DirectSniffer()
sn._session = _DisconnectingSession()
self.assertEqual(list(sn.iter_messages()), [])
@@ -84,7 +84,7 @@ class TestCaptureManager(unittest.TestCase):
self.assertEqual([m['type'] for m in msgs], ['gap', 'tpdu'])
def test_direct_sniffer_connected(self):
from simtrace2_pysniff.server.capture import DirectSniffer
from simtrace_analyser.capture import DirectSniffer
class _FakeSession:
connected = True
@@ -96,7 +96,7 @@ class TestCaptureManager(unittest.TestCase):
self.assertFalse(sn.connected)
def test_device_connected_gsmtap_none(self):
from simtrace2_pysniff.server.capture import GsmtapListener
from simtrace_analyser.capture import GsmtapListener
listener = GsmtapListener(bind_port=0)
self.addCleanup(listener.stop)
mgr, _ = self._manager(listener)
@@ -170,7 +170,7 @@ class _RaisingBackend:
class TestGsmtapListenerRobustness(unittest.TestCase):
def test_listener_survives_bad_packet(self):
from simtrace2_pysniff.server.capture import GsmtapListener
from simtrace_analyser.capture import GsmtapListener
listener = GsmtapListener(bind_port=0)
listener._receiver.close() # drop the real socket before swapping
listener._receiver = _FlakyReceiver(listener, ['raise_non_sim', 'good'])
@@ -181,7 +181,7 @@ class TestGsmtapListenerRobustness(unittest.TestCase):
self.assertEqual(listener.dropped, 1)
def test_listener_survives_short_packet(self):
from simtrace2_pysniff.server.capture import GsmtapListener
from simtrace_analyser.capture import GsmtapListener
listener = GsmtapListener(bind_port=0)
listener._receiver.close() # drop the real socket before swapping
listener._receiver = _FlakyReceiver(listener, ['raise_short', 'good'])
+146 -146
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -4,7 +4,7 @@ import struct
import unittest
from simtrace2_pysniff.pcap import build_pcap, PCAP_MAGIC, LINKTYPE_ETHERNET
from simtrace2_pysniff.server.server import _content_disposition
from simtrace_analyser.server import _content_disposition
FRAMING = 14 + 20 + 8 # Ethernet + IPv4 + UDP
+7 -7
View File
@@ -147,8 +147,8 @@ class TestTsresol(unittest.TestCase):
class TestImportEndpoint(unittest.TestCase):
def _handler(self, body):
from simtrace2_pysniff.server.server import RequestHandler
from simtrace2_pysniff.server.database import Database
from simtrace_analyser.server import RequestHandler
from simtrace_analyser.database import Database
class Fake(RequestHandler):
def __init__(self, body, db):
@@ -224,12 +224,12 @@ class TestImportEndpoint(unittest.TestCase):
class TestVersion(unittest.TestCase):
def test_package_version(self):
from simtrace2_pysniff import __version__
self.assertEqual(__version__, '1.22.21')
self.assertEqual(__version__, '2.0.0')
def test_status_includes_version(self):
import os
from simtrace2_pysniff.server.server import RequestHandler
from simtrace2_pysniff.server.database import Database
from simtrace_analyser.server import RequestHandler
from simtrace_analyser.database import Database
from simtrace2_pysniff import __version__
class FakeCapture:
@@ -259,8 +259,8 @@ class TestVersion(unittest.TestCase):
class TestCaptureDisabled(unittest.TestCase):
def _handler(self, capture_mode):
import os
from simtrace2_pysniff.server.server import RequestHandler
from simtrace2_pysniff.server.database import Database
from simtrace_analyser.server import RequestHandler
from simtrace_analyser.database import Database
class Fake(RequestHandler):
def __init__(self, db, capture_mode):