This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Язык документации и комментариев — русский; коды, имена сообщений/полей, команды — в оригинале.
dcvp-server — отдельный git-репозиторий (github.com/uzmasterdev/dcvp-server), физически вложенный в монорепо voyah-courage. Работать строго в пределах этого репозитория — корень /Users/saidakbar.sadikov/code/voyah-courage/soft/dcvp-server.
- НЕ читать, НЕ править, НЕ создавать, НЕ искать файлы вне этой папки: ни в
../(soft/), ни в../../(voyah-courage/), ни в соседних../firmware/,../../docs/,../../experience/и т.д. Все пути, начинающиеся с../, — за границей и трогать их нельзя. grep/find/ls/Read/Edit/Writeзапускать только по путям внутриdcvp-server. Не подниматься выше корня репозитория.- Ссылки в коде и docs на
../firmware/tbox-power-and-redirect.md(§C.*) — это внешний первоисточник реверса, только для сведения. Не открывать его и не зависеть от него: всё нужное для работы уже перенесено в этот репозиторий (README.md, docstringserver/dcvp_server.py,docs/). - Родительские
CLAUDE.md(soft/и кореньvoyah-courage) и так подаются автоматически — читать их файлы вручную не нужно; при конфликте это правило о границе имеет приоритет.
Исключение — только по явной просьбе пользователя выйти за границу в конкретный файл; по своей инициативе — никогда.
Приёмный сервер телематического протокола DCVP (Dongfeng Cloud Vehicle Platform) для блока T-BOX нашей машины (T_BOX_H37A3630849BA). Цель — принимать штатную выгрузку T-BOX на свой сервер в бортовой сети, без китайского облака. Протокол восстановлен статическим реверсом прошивки tsp_manager — правок на живой машине нет. Полный контекст — в README.md, первоисточник реверса — ../firmware/tbox-power-and-redirect.md (§C), на которую ссылаются комментарии в коде (§C.3, §C.4, §C.5).
rsa_aes_tbox.key, боевой client.crt, tbox.pfx, ca.pem) и идентификаторы машины (VIN/ICCID/IMEI/MAC/GPS) сюда класть нельзя; значения в client/fake_tbox.py — синтетические заглушки.
make certs # свой лабораторный CA + server/client cert (локально, gitignored)
make build # docker-образ; protobuf-байндинги генерятся ВНУТРИ из .proto
make up # сервер на :6504/:6507 (сессия) + :6553 (HTTPS-логи), лог в консоль (== certs)
make client # синтетический клиент: полный цикл login→binding→loc→N×(heartbeat+veh)→logout
make logs # docker compose logs -f dcvp-server
make stats # сводка по базе принятого (logs/dcvp.sqlite3)
make export # JSONL-выгрузка → logs/export.jsonl (SINCE=… TABLE=… VIN=…)
make raw # hexdump сырого захвата соединений logs/raw/ (FILE=… LIMIT=…)
make down # остановить; make clean — down -v + снести сгенерённые cert'ы
make gen # сгенерить *_pb2.py локально (нужен protoc: python -m grpc_tools.protoc) — для правки вне докераТестового фреймворка нет — проверка сквозная: поднять сервер (make up) и прогнать против него клиент (make client), глядя на лог кадров/ACK и на базу (make stats / make export). Без docker: сгенерить байндинги в отдельный каталог (python -m grpc_tools.protoc -Iproto --python_out=<gen> proto/vcp_custom_message.proto) и запустить PYTHONPATH=<gen>:server DCVP_LOGDIR=<data> python server/dcvp_server.py --plaintext --ports 16504 --log-port 16553, клиент — PYTHONPATH=<gen> python client/fake_tbox.py --plaintext --port 16504. Отладка без TLS: добавить серверу флаг --plaintext или --no-client-cert (в docker-compose.yml, поле command), клиенту — --plaintext.
Байндинги vcp_custom_message_pb2.py не коммитятся — генерятся из .proto при docker build (в /app/gen) или через make gen. Код без них деградирует до hexdump (HAVE_PB=False).
Три части, обёртка кадра — китайский нацстандарт GB/T 32960, внутри едет protobuf. Чтобы понять систему, читать в связке proto/vcp_custom_message.proto ↔ server/dcvp_server.py ↔ client/fake_tbox.py (клиент и сервер должны строить/разбирать кадр одинаково).
-
proto/vcp_custom_message.proto— схема данных (пакетtboxev.vcp, proto2, 68 сообщений / 534 поля), извлечённая из встроенногоFileDescriptorProtoв.rodataбинаряtsp_manager(не protoc'ом, декодером wire-формата). Только имена — секретов нет. Ключевые сообщения:in_binding_info(хендшейк),in_veh_data(97 полей состояния),in_location_data,in_general_config(адрес платформы). -
server/dcvp_server.py(~450 строк, stdlib + protobuf, потоки на соединение) — приёмник:serve()слушает несколько портов; порты сессии (6504/6507) идут вhandle_session, порт логов (6553) — вhandle_log_upload(отдельный HTTPSPOST /log/logReceiveGateway, канал libcurl, не GB/T).gb_deframe()нарезает TCP-поток на кадры: ищет старт##(0x23 0x23), длина data-unit — big-endian по смещению 22, контроль — XOR-BCC (gb_bcc, не CRC). Пропускает мусор, придерживает недочитанный кадр — это ядро устойчивости, не упрощать.- Диспетч по
cmd(байт[2]);cmd=0xCB(заводской диапазон0x80..0xFE) — custom-кадр, data-unit распаковывается как protobuf (try_decodeперебирает типы, берёт полностью поглотившие payload и ранжирует: required на месте → меньше unknown-полей → больше распознанных → тип изTOP_CANDIDATES; альтернативы уходят в базу).enc=0x02(AES) помечается, не парсится (ключа нет). make_ack()строит GB-ACK (resp=0x01) — без него T-BOX ловитresponse_TimeOutи переоткрывает сессию. Отвечаем только на запросы (resp=0xFE) с верным BCC, не на чужие ACK и не на битые кадры. ACK минимальный (эхоtime+serialдля login/logout, header-only для heartbeat) — точная структура data-unit ACK статически не выведена.- Порядок в
handle_session:analyze_frame→store.add_frame→ ACK →mark_acked. Персист до ACK (FR-5) — не переставлять. Ошибка базы логируется какSTORE-ERRи сессию не роняет. - Консоль — не место для координат/ICCID/серийников (SEC-9):
mask_text()/MASK_FIELDSрежут их в дампе protobuf, login data-unit печатается только какtime+serial. Полные значения — только в базе.
-
server/store.py— хранилище (FR-15…17): SQLite (stdlib, WAL, одно соединение подLock) вDCVP_LOGDIR+uploads/для тел журналов. Таблицыsessions/frames(каждый кадр сырьёмraw+ разборpb_json+status) /log_uploads/meta. Схема версионируется:SCHEMA_VERSION+MIGRATIONS[n]— старые миграции не править, только добавлять следующую; база новее кода → отказ на старте. RetentionDCVP_RETENTION_DAYS(0 = хранить всё) —purge()на старте и раз в час. Экспорт/статистика/ручная чистка —server/dcvp_export.py. Сырьё хранится всегда: без него нечего будет сверять с живым перехватом. -
server/rawcap.py— сырой захват каждого соединения до кадрирования (DCVP_RAW_CAPTURE=1по умолчанию) вlogs/raw/<ts>_<port>_<peer>.raw: записи'DR'|ts|dir|len|payload, без буферизации. Это страховка на первый живой трафик: если раскладка кадра окажется не такой, как выведена статически, байты всё равно на диске.handle_sessionвызываетcap.rx()на каждыйrecvиcap.tx()на каждый ACK, на закрытии печатает недокадрованный хвост (TAIL). Читать —dcvp_export.py raw. Не убирать, пока формат не подтверждён живым блоком. -
postman/— коллекция для пробы канала логов6553из Postman (сырой TCP-сессии Postman не умеет). Секретов нет: VIN/tbox_id синтетические. -
client/fake_tbox.py— синтетический T-BOX: гоняетlogin(0x01) → in_binding_info → in_location_data → N×(heartbeat(0x07) + in_veh_data) → logout(0x04), печатает ACK. Позволяет отлаживать приёмник без живой машины и без qemu-стенда.
Формат кадра GB/T 32960 задокументирован в docstring server/dcvp_server.py и в README.md (таблица смещений). Правишь раскладку кадра/BCC — правь синхронно в сервере и клиенте.
-
harness/README.md— план (пока только план, без скриптов) qemu-стенда: запуск настоящегоtsp_managerподqemu-user(aarch64) с LD_PRELOAD-стабами железа, чтобы снять ground-truth формата сессии/ACK, оставшийся невыясненным при статическом реверсе. -
certs/gen-ca.sh— генератор нашего лабораторного CA + server/client cert. SAN серверного cert включает боевые хосты платформы (vdcvpapinx.dfmc.com.cnи т.п.) — под подменуca.pemв trust store T-BOX (§C.3). Вся папкаcerts/gitignored.
docs/REQUIREMENTS.md — индекс, подТЗ в docs/requirements/*.md, разбиты по областям. Сквозные идентификаторы (FR-*, NFR-*, SEC-*, NOT-*) уникальны по всему ТЗ; канон каждого — в его «домашнем» файле (см. карту в §3 индекса), из других файлов на него ссылаются, не дублируют. Реализованы пока только телематический приёмник и хранение принятого (telematics.md: FR-1…FR-8, FR-14…FR-17) — FR-9 (нормализованная модель телеметрии), backend-API, биллинг, PKI-провижининг, SMS-канал и т.д. в коде отсутствуют, есть только требования.