# binpac
###### tags: `summary`, `binpac`
[TOC]
---
## Введение
***binpac*** — декларативный язык описания формата сообщений с самостоятельным синтаксисом (не YAML/XML/etc.). Ориентирован на анализ сетевого трафика. Внедряется в виде плагинов для [IDS Zeek (Bro)](https://www.zeek.org/). Развитая инфраструктура языка открытая ([GitHub](https://github.com/zeek/binpac)).
Обзорная статья [binpac: A yacc for Writing Application Protocol Parsers](https://www.icsi.berkeley.edu/pubs/networking/binpacIMC06.pdf)
| Достоинства | Недостатки |
| -------- | -------- |
| возможность описывать stateful протоколы | несамостоятельность инфраструктуры |
| нацеленность на бинарные форматы | сложный синтаксис |
## Описание языка
Описание формата в *binpac* состоит не только из непосредственного описания структуры бинарного файла, но и из вспомогательных секций, отвечающих за механизмы организации потока байт и соединений. Это позволяет моделировать ситуации чтения пакетов протокола, идущих в двух направлениях (например, если анализатор развернут на промежуточном узле) или добавлять различные пользовательские обработчики разобранных данных.
Все эти определения записываются в один `.pac` файл, подающийся на вход компилятору.
### Секции `analyzer`, `connection` и `flow`
В этих секциях описывается глобальный контекст парсера. Примеры:
```
analyzer HTTP withcontext {
connection : HTTP_analyzer;
flow : HTTP_flow;
};
```
```
connection HTTP_analyzer {
upflow = HTTP_flow (true);
downflow = HTTP_flow (false);
};
```
```
flow HTTP_flow(is_orig) {
flowunit = HTTP_PDU(is_orig) withcontext (analyzer, this);
};
```
### Секция `type`
Основная секция, отвечающая непосредственно за описание формата. Типы в *binpac* могут быть составными из любых других ранее определенных типов.
Список встроенных (*примитивных*) типов: `int8`, `int16`, `int32`, `uint8`, `uint16`, `uint32`, `bytestring`, регулярное выражение (`RE/[[:alnum:][:punct:]]+/`)
При описании пользовательского типа задается:
* имя типа
* параметры (опционально, для параметрических типов)
* класс типа (составной, условны и т.д.)
* список членов типа (подтипы, из которых он составлен)
* дополнительные атрибуты типа (порядок байт и т.п.)
Синтаксис определения одного типа:
```
type <Name>{(<optional type parameter(s)>)} = <compositor or primitive class> {
... cases or members declaration.
} <optional attribute(s)>;
```
Классов типов в *binpac* четыре:
* примитивный (`primitive`)
* составной (`record`)
* условным (`case`)
* массив (`array`)
Примитивные типы можно только использовать (переопределять нельзя).
Пример `.pac` файла:
```
analyzer HelloWorld withcontext {
connection : HelloWorld_analyzer;
flow : Myflow;
};
connection HelloWorld_analyzer {
upflow = Myflow (true);
downflow = Myflow (false);
};
flow Myflow(side: bool) {
datagram = myType withcontext (HelloWorld_analyzer, this);
};
type myType = record {
data: uint8;
}&byteorder = bigendian;
```
### Возможности языка
Ниже приводятся примеры, описывающие возможности языка.
#### Порядок байт
```
type myType = record {
data: uint8;
}&byteorder = bigendian;
```
#### Выравнивание байт
```
type RPC_Opaque = record {
length: uint32;
data: uint8[length];
pad: padding align 4; # выровнять до 4-х байт
};
```
#### Расширение атрибутов типов
Имея некоторый заданный тип, есть возможность расширять его атрибуты с помощью ключевой секции `refine`:
```
refine typeattr HTTP_RequestLine += &let {
process_request: bool = process_func(method, uri, version);
};
```
Здесь мы добавили типу `HTTP_RequestLine` атрибут `&let` (о нем ниже).
Также можно расширять условия в условных типах и условные функции:
```
refine casetype RPC_Params += {
RPC_SERVICE_PORTMAP -> portmap: PortmapParams(call);
};
refine casefunc RPC_BuildCallVal += {
RPC_SERVICE_PORTMAP -> PortmapBuildCallVal(call, call.params.portmap);
};
```
#### Определение функций
#### Встраивание кода C++