---
# System prepended metadata

title: binpac
tags: [summary, binpac]

---

# 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++
