См. README
│
├── cbpf/
│ ├── filter/
│ │ └── `*.c`
│ │
│ ├── tests/
│ │ └── `*.c`
│ │
│ ├── Makefile
│ │
│ └── README.md
│
├── cmd/
│ └── controller/
│ └── `main.go`
│ # Точка входа
│ # - читает конфиг
│ # - настраивает контекст сигналов
│ # - вызывает bootstrap.New(cfg) и затем application.Run(ctx)
│
├── internal/
│ ├── application/
│ │ ├── filter/
│ │ │ ├── `port.go` # Контракт backend для сценария allow/stats
│ │ │ ├── `service.go` # UseCase для /allow
│ │ │ └── `stats.go` # Модель расширенной статистики
│ │ └── management/
│ │ ├── `types.go` # Настройки trust-контура + runtime status
│ │ ├── `port.go` # Контракты usecase/repository/verifier/runtime applier
│ │ └── `service.go` # Bootstrap + валидация settings + авторизация JWT
│ │
│ ├── bootstrap/
│ │ └── `bootstrap.go` # Composition root + применение сохраненных settings при старте
│ │
│ ├── config/
│ │ ├── `config.go` # Чтение yaml и runtime-валидация общих параметров
│ │ └── `config_test.go`
│ │
│ ├── contracts/
│ │ ├── rest/v1/
│ │ │ └── `types.go` # DTO REST API v1 (включая runtime_attached/runtime_iface)
│ │ └── grpc/v1/
│ │ ├── `leshy_controller_v1.pb.go`
│ │ └── `leshy_controller_v1_grpc.pb.go` # Сгенерированные контракты из docs/api/grpc/*.proto
│ │
│ ├── infrastructure/
│ │ ├── jwtauth/
│ │ │ └── `verifier.go` # EdDSA JWT verifier + JWKS fetch/cache
│ │ ├── leshybpf/
│ │ │ ├── `attach_manager.go` # Attach lifecycle
│ │ │ ├── `attach_tc.go` # Загрузка/attach tc+bpf
│ │ │ ├── `filter_backend.go` # Backend adapter для application/filter
│ │ │ ├── `runtime_settings_applier.go` # Динамическое применение iface/ports/handshake/inactive-timer
│ │ │ ├── `diagnostics_linux.go` # Linux debug diagnostics
│ │ │ └── `*.go` # guarded ports, pending, stats, utils
│ │ └── sqlite/
│ │ ├── `db.go` # Open/prepare sqlite file
│ │ ├── `settings_repository.go` # Raw SQL репозиторий management settings
│ │ └── migrations/
│ │ ├── `embed.go` # embed SQL миграций
│ │ ├── `runner.go` # применение миграций на старте
│ │ └── `sql/`
│ │ └── `0001_create_management_settings.sql`
│ │
│ ├── interfaces/
│ │ ├── grpc/
│ │ │ ├── server/
│ │ │ │ └── `server.go` # gRPC transport (runtime.Server)
│ │ │ └── v1/
│ │ │ └── `api.go` # gRPC handlers v1 + auth/validation/error mapping -> usecases
│ │ │
│ │ ├── rest/
│ │ │ ├── httpserver/
│ │ │ │ ├── `server.go` # HTTP transport (runtime.Server)
│ │ │ │ └── `handlers.go`
│ │ │ ├── router/
│ │ │ │ └── `router.go` # Root router (/api/v1, /api/healthz)
│ │ │ └── v1/
│ │ │ └── `api.go` # HTTP handlers v1, auth middleware + mapping -> usecases
│ │ │
│ └── runtime/
│ ├── `app.go` # Оркестратор жизненного цикла приложения
│ ├── `close_server.go` # Adapter для graceful close ресурсов
│ └── `server.go` # Контракт транспорта Start/Stop/Name
│
├── devops/
│ └── ... (скрипты сборки)
│
├── docs/
│ ├── examples/
│ │ └── `basic.md`
│ │
│ ├── cbpf/
│ │ └── `cbpf-schema.drawio`
│ │
│ ├── plantuml/
│ │ ├── `c4-component.puml`
│ │ ├── `c4-containter.puml`
│ │ └── `c4-context.puml`
│ │
│ ├── api/
│ │ ├── grpc/
│ │ │ └── `leshy_controller_v1.proto` # gRPC-контракт, зеркалирующий HTTP API
│ │ └── swagger/
│ │
│ ├── badges/
│ │ └── `coverage.svg`
│ │
│ ├── `architecture.md`
│ │
│ └── `c4.md`
│
├── .pre-commit-config.yaml # Pre-commit хуки
├── .clang-format # Форматирование C
├── .golangci.yaml # Go линтер
├── Makefile # Основной Makefile
├── go.mod # Go модули
├── go.sum
├── LICENSE
└── README.mdinfrastructure/leshybpf — это конкретный secondary adapter (инфраструктурный драйвер) для Linux/eBPF/TC. Usecase-слой (
internal/application/filter) не знает про*ebpf.Map,tc,bpftoolи syscalls: он общается с инфраструктурой только через портfilter.Backend. Внутриleshybpfсобрана вся “железная” логика: attach/pin, работа с картами, byte order, и опциональная диагностика (только в debug). API транспорт переключается черезapi_server_mode:http(REST) илиgrpc(protobuf контракт изdocs/api/grpc).
Используется в режиме отладки. Если отсутствует в системе - будет залогировано предупреждение. Необходима для расширенного анализа вывода bpf-программ.
Используется для расширенной аналитики планировщика пакетов ядра.
Все тестирование и адаптация исключительно выполнялось для x64. На x86 с большой долей вероятности будут ошибки конвертации.
Отладка, во многом, опирается на bpftool. Пример сборки из исходных текстов - https://gist.github.com/devalv/0d4af62eca14b1ea91b8f7c2c6f3f163
Текущая схема:
POST /api/v1/management/settingsдоступен только в bootstrap-режиме (заголовокX-Bootstrap-Token).PATCH /api/v1/management/settingsдоступен только после первичной конфигурации и авторизуется тем жеBeareraccess token, что и/allow.- В
settingsпередаются runtime-параметры фильтра:iface,guarded_ports_range,handshake_window_sec,inactive_timer_sec. POST /api/v1/management/blockочищает разрешающие правила (pendingиactive_flows), созданные через/allow.- После успешного
POSTилиPATCHприложение динамически поднимает/обновляет eBPF runtime. JWTдля/allow,PATCH /management/settingsиPOST /management/blockпроверяется поJWKSвнешней системы (EdDSA / Ed25519).
Примечание: insecure-режим с отключением TLS-проверки в leshy-controller не предусмотрен.
Дополнительные примеры openAPI gRPC proto
Генерация Go-контрактов из protobuf:
make grpc
api_server_mode: http:- запускается REST API на
api_listen_addr; - доступны
/api/healthzи/api/v1/*.
- запускается REST API на
api_server_mode: grpc:- запускается gRPC сервер на
api_listen_addr; - доступны сервисы
HealthService,FilterService,ManagementServiceизdocs/api/grpc/leshy_controller_v1.proto.
- запускается gRPC сервер на
- Остановите leshy-controller
- Удалите локальную БД (файл)
- Запустите leshy-controller
- После первого успешного
POST /api/v1/management/settingsbootstrap-endpoint блокируется (409 management settings are locked), включая сценарий после перезапуска приложения. - Для последующих изменений используется
PATCH /api/v1/management/settings(Bearer JWT). - После перезапуска приложение читает сохранённые settings из SQLite и повторно применяет их в runtime (attach выполняется автоматически при наличии сохраненных настроек).
- Для ротации ключей публикуйте новый ключ в JWKS с новым
kid, затем выпускайте новые JWT с этимkid. - Если
management_bootstrap_tokenне задан в конфиге,POST /api/v1/management/settingsвернёт503. - Если settings еще не заданы, runtime не подключен:
POST /api/v1/allowвернет503 filter is not configuredGET /api/v1/statsвернет503 filter is not configuredGET /api/healthzвернет JSON сruntime_attached: false
- Runtime-статус дублируется в:
GET /api/healthz(runtime_attached)GET /api/v1/management/settingsPOST /api/v1/management/settingsPATCH /api/v1/management/settingsPOST /api/v1/management/block
- Типовые ответы для
PATCH /api/v1/management/settings:200при успешном обновлении;400при ошибках валидации тела запроса;401при невалидном или отсутствующемAuthorization: Bearer ...;409если настройки еще не были заданы;503если авторизация временно недоступна (authorization unavailable).
- Типовые ответы для
POST /api/v1/management/block:200при успешной очистке разрешающих правил;401при невалидном или отсутствующемAuthorization: Bearer ...;409если настройки еще не были заданы;503если авторизация или filter-runtime недоступны;500при внутренней ошибке очистки.
- После первого успешного
ManagementService/CreateSettingsbootstrap-вызов блокируется и повторный вызов вернетFailedPrecondition(management settings are locked), включая сценарий после перезапуска приложения. - Для последующих изменений используется
ManagementService/UpdateSettings(Bearer JWT в metadataauthorization). - После перезапуска приложение читает сохранённые settings из SQLite и повторно применяет их в runtime (attach выполняется автоматически при наличии сохраненных настроек).
- Для ротации ключей публикуйте новый ключ в JWKS с новым
kid, затем выпускайте новые JWT с этимkid. - Если
management_bootstrap_tokenне задан в конфиге,ManagementService/CreateSettingsвернётUnavailable. - Если settings еще не заданы, runtime не подключен:
FilterService/AllowвернетUnavailable(Authorization is unavailable);FilterService/StatsвернетUnavailable(Authorization is unavailable);HealthService/Healthвернетruntime_attached: false.
- Runtime-статус дублируется в:
HealthService/Health(runtime_attached);ManagementService/GetSettings;ManagementService/CreateSettings;ManagementService/UpdateSettings;ManagementService/Block.
- Типовые ответы для
ManagementService/UpdateSettings:OKпри успешном обновлении;InvalidArgumentпри ошибках валидации запроса;Unauthenticatedпри невалидном или отсутствующемauthorization: Bearer ...;FailedPreconditionесли настройки еще не были заданы;Unavailableесли авторизация временно недоступна (authorization unavailable).
- Типовые ответы для
ManagementService/Block:OKпри успешной очистке разрешающих правил;Unauthenticatedпри невалидном или отсутствующемauthorization: Bearer ...;FailedPreconditionесли настройки еще не были заданы;Unavailableесли авторизация или filter-runtime недоступны;Internalпри внутренней ошибке очистки.