# Маршрутизация по DID номеру

### Введение <a href="#vvedenie" id="vvedenie"></a>

При настройке входящей маршрутизации часто возникает ситуация, когда провайдер предоставляет учетную одну запись SIP для нескольких купленных номеров телефонов.

К примеру у МИКО есть номера телефонов:

* `+7(495)229-30-42`
* `+7(499)638-25-84`

В интерфейсе MikoPBX создана только одна учетная запись «[Провайдер телефонии](https://docs.mikopbx.com/mikopbx/manual/routing/providers)». Каждый номер телефона необходимо направить на свой маршрут, к примеру на различные IVR.

Тут к приходит на помощь [DID номер](https://ru.wikipedia.org/wiki/DID), который провайдер может передавать при входящих звонках. Зная DID номер, можно для провайдера описать несколько входящие маршрутов, с различными DID, что позволит решить описанную выше задачу.

### Как это работает <a href="#kak_ehto_rabotaet" id="kak_ehto_rabotaet"></a>

Для анализа звонков я обычно использую «[приложение Sngrep](https://wiki.mikopbx.ru/faq:sngrep)». Вот пример запроса от провайдера при входящем:

```php
INVITE sip:84996382584@93.188.XX.XX SIP/2.0
Via: SIP/2.0/UDP 81.88.86.65:5060;branch=z9hG4bK1cf7.16247c44.0;cid=2
Max-Forwards: 67
Contact: <sip:81.88.86.65>
To: <sip:84996382584@93.188.XX.XX>
From: "79260577653"<sip:79260577653@mangosip.ru>;tag=5e1a5a28
Call-ID: JUm-E_ISk4DPaL8Npv2Hlw..
CSeq: 1 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, UPDATE, UPDATE, INFO, REFER, MESSAGE
Content-Type: application/sdp
Supported: replaces
User-Agent: Softswitch3
Content-Length: 351
```

При получении такого пакета, MikoPBX проанализирует первую строку с ключевым словом «**`INVITE`**», значение «**`84996382584`**» и будет являться **DID** номером.

### Возможные особенности <a href="#vozmozhnye_problemy" id="vozmozhnye_problemy"></a>

#### DID в заголовке To <a href="#did_v_zagolovke_to" id="did_v_zagolovke_to"></a>

На практике, не всегда все так просто. К примеру я встречал провайдера, который присылает следующий `INVITE`:

```php
INVITE sip:mikoteam@93.188.XX.XX SIP/2.0
Via: SIP/2.0/UDP 81.88.86.65:5060;branch=z9hG4bK1cf7.16247c44.0;cid=2
Max-Forwards: 67
Contact: <sip:81.88.86.65>
To: <sip:84996382584@93.188.XX.XX>
From: "79260577653"<sip:79260577653@mangosip.ru>;tag=5e1a5a28
Call-ID: JUm-E_ISk4DPaL8Npv2Hlw..
CSeq: 1 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, UPDATE, UPDATE, INFO, REFER, MESSAGE
Content-Type: application/sdp
Supported: replaces
User-Agent: Softswitch3
Content-Length: 351
```

В этом случае в строке «`INVITE`» описывается логин учетной записи, в вот DID уже описывается в заголовке «To[^1]». Для корректной настройки достаточно в разделе [Кастомизация системных файлов](https://docs.mikopbx.com/mikopbx/manual/system/custom-files) добавить в конец файла «extensions.conf» следующие строки:

```php
[SIP-1622040384-incoming-custom]
exten => _[0-9*#+a-zA-Z][0-9*#+a-zA-Z]!,1,NoOp(------)
	same => n,Set(toNum=${PJSIP_PARSE_URI(${PJSIP_HEADER(read,To)},user)})
	same => n,ExecIf($["${toNum}" != "${EXTEN}"]?Goto(${CUT(CONTEXT,,1-3)},${toNum},1))
	same => n,return
```

* функция «**`PJSIP_HEADER`**» считывает значение заголовка «**`To`**»
* функция «**`PJSIP_PARSE_URI`**» получает из значения заголовка поле «**`user`**», которое соответствует значению DID
* `Goto` перемещает канал в начало, для повторной инициализации маршрута
* "`1-3`" - означает, что нужно взять первые три слова из "`SIP-1622040384-incoming-custom`", по сути, нужно из этой строки получить все до "`-custom`", в старых версиях АТС может потребоваться скорректировать это правило
* **`SIP-1622040384`** - это ID учетной записи провайдера MikoPBX, можно подсмотреть в адресной строке браузера при редактировании учетной записи

<figure><img src="https://3704471835-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MPK4TuzRBnP7rt8htho-887967055%2Fuploads%2FxZcjivKIv8XhkH6VjUHi%2FcodeForExtensions2.png?alt=media&#x26;token=888b3fba-1ec1-4ebb-8817-f2f2bdabbe78" alt=""><figcaption><p>Код для решения проблемы</p></figcaption></figure>

#### Замена DID на произвольный <a href="#zamena_did_na_proizvolnyj" id="zamena_did_na_proizvolnyj"></a>

Следующий пример удобно применять, когда провайдер не предоставляет информации по номеру, на который пришел вызов, поступает информация только о логине. При этом, важно, чтобы одному логину соответствовал один DID.

```php
[add-trim-prefix-clid-custom]
exten => user1,1,Goto(SIP-1622040384-incoming,74952293042,1)
exten => admin,1,Goto(SIP-1622040000-incoming,74952291111,1)

exten => _[0-9*#+a-zA-Z]!,2,return
```

* "`user1`" и "`admin`" - это примеры популярных логин

#### Установить CID на основании DID <a href="#ustanovit_cid_na_osnovanii_did" id="ustanovit_cid_na_osnovanii_did"></a>

```php
[add-trim-prefix-clid-custom]
exten => _[0-9*#+a-zA-Z][0-9*#+a-zA-Z]!,1,NoOp(...)
	same => n,GosubIf($["${DIALPLAN_EXISTS(did-from-cid-map,${EXTEN},1)}" == "1"]?cid-from-did-map,${EXTEN},1)
	same => n,return
```

```php
[cid-from-did-map]
exten => 74952293042,1,Set(CALLERID(name)=Sales)
exten => 74952291111,1,Set(CALLERID(name)=Support)

exten => _[0-9*#+a-zA-Z]!,2,return
```

* Если вызов поступен на номер **`74952293042`**, то `CID (name)` будет установлен в значение **`Sales`**
* Если вызов поступен на номер **`74952291111`**, то `CID (name)` будет установлен в значение **`Support`**

#### DID произвольном заголовке <a href="#did_proizvolnom_zagolovke" id="did_proizvolnom_zagolovke"></a>

Такое встречается при использовании сервиса **roistat**. Сервис при входящем может прислать следующий запрос:

```php
INVITE sip:mikoteam@93.188.XX.XX SIP/2.0
Via: SIP/2.0/UDP 81.88.86.65:5060;branch=z9hG4bK1cf7.16247c44.0;cid=2
Max-Forwards: 67
Contact: <sip:81.88.86.65>
To: <sip:mikoteam@93.188.XX.XX>
From: "79260577653"<sip:79260577653@mangosip.ru>;tag=5e1a5a28
Call-ID: JUm-E_ISk4DPaL8Npv2Hlw..
CSeq: 1 INVITE
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, UPDATE, UPDATE, INFO, REFER, MESSAGE
Content-Type: application/sdp
Supported: replaces
User-Agent: Softswitch3
x-roistat-phone: 84996382584
Content-Length: 351
```

Корректного DID нет ни в **`INVITE`**, ни в поле **To**, но при этом появился новый заголовок «x-roistat-phone».

Для корректной настройки достаточно в разделе [Кастомизация системных файлов](https://wiki.mikopbx.ru/custom-files) добавить в конец файла «extensions.conf» следующие строки:

```php
[SIP-1622040384-incoming-custom]
exten => _[0-9*#+a-zA-Z][0-9*#+a-zA-Z]!,1,NoOp(------)
	same => n,Set(toNum=${PJSIP_HEADER(read,x-roistat-phone)})
	same => n,ExecIf($["${toNum}x" != "x" && "${toNum}" != "${EXTEN}"]?Goto(${CUT(CONTEXT,,1-3)},${toNum},1))
	same => n,return
```

1. функция «**`PJSIP_HEADER`**» считывает значение заголовка «**`x-roistat-phone`**»
2. `Goto` перемещает канал в начало, для повторной инициализации маршрута

<figure><img src="https://3704471835-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MPK4TuzRBnP7rt8htho-887967055%2Fuploads%2Fqx9GvC66YpFo00GpXQGb%2FcodeForExtensions3.png?alt=media&#x26;token=b2c9c446-ccd0-4ec0-970e-aa06c0b6c36e" alt=""><figcaption></figcaption></figure>

#### Манго офис <a href="#mango_ofis" id="mango_ofis"></a>

Получение номера, на который позвонил клиент из поля «`Diversion`»:

```php
[SIP-1622040384-incoming-custom]
exten => _[0-9*#+a-zA-Z][0-9*#+a-zA-Z]!,1,NoOp(------)
	same => n,Set(tmpDiversion=${PJSIP_HEADER(read,Diversion)})
	same => n,ExecIf($["x${tmpDiversion}" != "x"]?Set(toNum=${CUT(CUT(tmpDiversion,>,1),:,2)}))
	same => n,ExecIf($["${toNum}x" != "x" && "${toNum}" != "${EXTEN}"]?Goto(${CUT(CONTEXT,,1-3)},${toNum},1))
	same => n,return
	
```

Более универсальный вариант:

```php
[add-trim-prefix-clid-custom]
exten => _[0-9*#+a-zA-Z][0-9*#+a-zA-Z]!,1,NoOp(------)
	same => n,Set(tmpDiversion=${PJSIP_HEADER(read,Diversion)})
	same => n,ExecIf($["x${tmpDiversion}" != "x"]?Set(toNum=${CUT(CUT(tmpDiversion,@,1),:,2)}))
	same => n,ExecIf($["${toNum}x" != "x" && "${toNum}" != "${EXTEN}"]?Goto(${contextID},${toNum},1))
	same => n,return
```

#### Novafon (zadarma) <a href="#novafon_zadarma" id="novafon_zadarma"></a>

Получение номера, на который позвонил клиент из заголовка «`CALLED_DID`»:

```php
[SIP-1622040384-incoming-custom]
exten => _[0-9*#+a-zA-Z][0-9*#+a-zA-Z]!,1,NoOp(------)
	same => n,Set(toNum=${PJSIP_HEADER(read,CALLED_DID)})
	same => n,ExecIf($["${toNum}x" != "x" && "${toNum}" != "${EXTEN}"]?Goto(${CUT(CONTEXT,,1-3)},${toNum},1))
	same => n,return
```

[^1]:
