<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Unified Communications Expert</title>
	<atom:link href="https://ucexpert.ru/feed" rel="self" type="application/rss+xml" />
	<link>https://ucexpert.ru</link>
	<description>Унифицированные Коммуникации и IP-телефония</description>
	<lastBuildDate>Thu, 16 Jul 2026 21:35:42 +0000</lastBuildDate>
	<language>ru-RU</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.1</generator>
	<item>
		<title>После семилетней паузы: как я обновил UCExpert с ИИ</title>
		<link>https://ucexpert.ru/archives/7471</link>
		
		<dc:creator><![CDATA[Игнат Кудрявцев]]></dc:creator>
		<pubDate>Thu, 16 Jul 2026 21:19:47 +0000</pubDate>
				<category><![CDATA[Веб-сайты]]></category>
		<category><![CDATA[Главное]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[OpenAI Codex]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[веб-разработка]]></category>
		<category><![CDATA[искусственный интеллект]]></category>
		<guid isPermaLink="false">https://ucexpert.ru/?p=7471</guid>

					<description><![CDATA[<p>Последняя статья на UCExpert вышла в мае 2019 года. Спустя семь лет я решил не закрывать накопившийся архив, а обновить WordPress, оживить старую тему и привести сайт в порядок с помощью Codex. Рассказываю, что из этого получилось и зачем вообще сохранять технический блог в эпоху ИИ.</p>
<p>The post <a href="https://ucexpert.ru/archives/7471">После семилетней паузы: как я обновил UCExpert с ИИ</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></description>
										<content:encoded><![CDATA[<p align="justify">Последняя статья на UCExpert вышла в мае 2019 года. Спустя семь лет я решил не закрывать накопившийся архив, а обновить WordPress, оживить старую тему и привести сайт в порядок с помощью ИИ. Рассказываю, что из этого получилось и зачем вообще сохранять технический блог в эпоху ИИ.</p>
<p><span id="more-7471"></span></p>
<figure class="wp-block-image size-large is-resized"><img fetchpriority="high" decoding="async" width="1024" height="576" src="https://ucexpert.ru/wp-content/uploads/2026/07/ChatGPT-Image-16-июл.-2026-г.-22_02_54-1024x576.png" alt="" class="wp-image-7474" style="aspect-ratio:1.777802416594694;width:622px;height:auto" srcset="https://ucexpert.ru/wp-content/uploads/2026/07/ChatGPT-Image-16-июл.-2026-г.-22_02_54-1024x576.png 1024w, https://ucexpert.ru/wp-content/uploads/2026/07/ChatGPT-Image-16-июл.-2026-г.-22_02_54-300x169.png 300w, https://ucexpert.ru/wp-content/uploads/2026/07/ChatGPT-Image-16-июл.-2026-г.-22_02_54-768x432.png 768w, https://ucexpert.ru/wp-content/uploads/2026/07/ChatGPT-Image-16-июл.-2026-г.-22_02_54-1536x864.png 1536w, https://ucexpert.ru/wp-content/uploads/2026/07/ChatGPT-Image-16-июл.-2026-г.-22_02_54.png 1672w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>
<div class="wp-block-group">
<div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<p class="wp-block-paragraph">
<p align="justify">Последняя статья на UCExpert вышла 29 мая 2019 года. Получается, что пауза длилась не шесть лет, как мне сначала казалось, а чуть больше семи.</p>
</p>
<p class="wp-block-paragraph">
<p align="justify">У этой паузы не было одной большой причины. В 2019 году начались серьёзные изменения в компании, где я тогда работал, и стало уже не до блога. Весной 2020 года пришли пандемия, удалённая работа и совершенно другой ритм жизни. Потом была смена места работы, новые обязанности и заметно меньше свободного времени.</p>
</p>
<p class="wp-block-paragraph">
<p align="justify">Изменилась и сама работа. Раньше у меня регулярно появлялись новые устройства, системы и технологии, которые можно было испытать, настроить, а затем описать на основе собственного опыта. Со временем таких задач стало меньше, а писать пересказы чужих материалов мне не хотелось.</p>
</p>
<p class="wp-block-paragraph">
<p align="justify">Наконец, этот блог никогда не был коммерческим проектом и денег мне не приносил. Он существовал из интереса к теме и желания сохранить полезный опыт. Когда свободного времени стало меньше, поддерживать его ради самого факта обновления оказалось трудно.</p>
</p>
<p class="wp-block-paragraph">
<p align="justify">Все эти годы сайт продолжал работать, но фактически превратился в архив. Статьи оставались доступными через поиск и ссылки, а его техническая основа всё сильнее отставала от времени.</p>
</p>
</div>
</div>
<h4 class="wp-block-heading">Почему я решил обновиться</h4>
<p class="wp-block-paragraph">
<p align="justify">За прошедшие годы изменился не только WordPress. Началась эпоха генеративного искусственного интеллекта, и вместе с ней возник более общий вопрос: нужны ли теперь такие технические блоги?</p>
</p>
<p class="wp-block-paragraph">
<p align="justify">Я и сам стал заметно реже искать ответы в отдельных статьях. Во многих случаях проще задать вопрос ИИ, уточнить несколько деталей и получить объяснение именно в том виде, который нужен сейчас. Не приходится собирать ответ по кускам из документации, форумов и материалов десятилетней давности. С этой точки зрения возвращение к старому блогу может показаться немного странным. Зачем вкладывать время в сайт, если читатель всё равно спросит у нейросети? Но есть и другая сторона. ИИ хорошо обобщает уже существующие знания, однако этим знаниям всё равно нужно откуда-то появляться. Особую ценность имеют не очередные пересказы документации, а первичный опыт: что действительно заработало, где документация оказалась неполной, какие ограничения обнаружились в эксплуатации и что пришлось исправлять вручную. Именно такие материалы когда-то и составляли основную ценность UCExpert. Кроме того, мне не хотелось однажды потерять весь накопленный архив только потому, что устаревший движок больше невозможно запустить на современном сервере. Поэтому я решил сначала привести в порядок сам сайт, а вопрос о регулярности новых публикаций оставить открытым.</p>
</p>
<h4 class="wp-block-heading">Старый WordPress</h4>
<p class="wp-block-paragraph">
<p align="justify">Исходное состояние было типичным для сайта, который долго работал без серьёзного обслуживания. Старый WordPress зависел от старой версии PHP. Обновить PHP мешала тема оформления Arthemia, разработчик которой давно прекратил выпускать новые версии. Тема, в свою очередь, использовала устаревшие функции WordPress и JavaScript-библиотеки прежних лет. Несколько старых плагинов тоже давно не поддерживались. Получилась цепочка зависимостей: нельзя обновить один компонент, не затронув остальные. Простое нажатие кнопки «Обновить» могло закончиться белой страницей, ошибками PHP или неработающей административной панелью. На руках у меня были архив файлов сайта и дамп базы данных. С них мы и начали. Я говорю «мы», потому что вторым участником этой работы стал Codex — ИИ-агент, который умеет разбирать проект, изменять код, запускать команды и проверять результат. Первым делом была собрана локальная копия сайта в Docker. WordPress с Apache и PHP работал в одном контейнере, база MySQL — в другом. Это позволило экспериментировать без риска для действующего сайта, повторять обновления с чистого состояния и перед каждым опасным изменением делать резервную копию. Основной принцип был простым: не переделывать всё сразу и не пытаться превратить старый блог в совершенно другой сайт. Мне хотелось сохранить узнаваемый вид UCExpert, но убрать технические ограничения, из-за которых он застрял в прошлом.</p>
</p>
<h4 class="wp-block-heading">Этапы обновления</h4>
<p class="wp-block-paragraph">
<p align="justify">Со стороны работа с ИИ иногда выглядит почти магически: сформулировал задачу, подождал и получил готовый результат. В реальности этот проект выглядел иначе. За время обновления получилось около сотни коротких итераций. Я открывал сайт, проверял конкретный экран, находил новую проблему, присылал описание, снимок экрана или фрагмент журнала. Codex изучал связанный код, предлагал или сразу вносил исправление, после чего всё проверялось заново. Финальная серия изменений, связанных с развёртыванием сайта, была разделена на двенадцать отдельных коммитов.</p>
</p>
<p class="wp-block-paragraph">
<p align="justify">Такой режим оказался гораздо полезнее попытки заранее составить один огромный запрос. Старый сайт хранит много неочевидных связей между темой, плагинами, настройками и данными. Часть проблем проявляется только после входа в административную панель, отправки формы или открытия конкретной статьи десятилетней давности. При этом ИИ не всегда оказывался прав с первой попытки. Например, несколько вариантов нового логотипа визуально отличались от оригинала, хотя технически выглядели лучше. В итоге нашёлся исходный EPS-файл, из которого удалось подготовить аккуратную векторную версию, сохранив прежние пропорции и цвет. В другой момент попытка улучшить расположение анонсов нарушила сетку страницы, и изменение пришлось пересмотреть. Такие ситуации хорошо напоминают, что окончательное решение всё равно принимает человек, который знает, каким должен быть результат.</p>
</p>
<h4 class="wp-block-heading">Сложности при обновлении и переработки блога</h4>
<p class="wp-block-paragraph">
<p align="justify">Главной трудностью была не какая-то одна большая ошибка, а множество небольших несовместимостей. Панель настроек Arthemia сначала открывалась пустой. Когда её удалось вернуть, выяснилось, что блоки параметров нельзя перетащить в рабочую область: старый JavaScript рассчитывал на поведение библиотек, давно изменившееся в WordPress. Отдельно пришлось восстанавливать загрузчик изображений и другие элементы административного интерфейса. Некоторые страницы панели управления открывались примерно по двадцать секунд, хотя сам сайт отвечал быстро. Причиной оказался старый механизм проверки обновлений темы. Он пытался связаться с давно не существующим сервером разработчика и каждый раз ждал сетевого тайм-аута. После отключения этого механизма административная панель снова стала работать нормально.</p>
</p>
<p class="wp-block-paragraph">
<p align="justify">В старом содержимом тоже нашлись неожиданные проблемы. Повреждённое изображение могло вызвать критическую ошибку при создании миниатюры. Блоки команд, которые когда-то красиво оформлялись плагином, после изменений превращались в красный текст или обычные абзацы. Встречались устаревшие и уже перехваченные посторонними владельцами ссылки. Несколько десятков материалов пришлось просматривать отдельно: восстанавливать разметку кода, исправлять явные опечатки, убирать лишние рамки у изображений и осторожно обновлять пояснения, не переписывая историю задним числом.</p>
</p>
<p class="wp-block-paragraph">
<p align="justify">Даже отправка почты потребовала отдельного расследования. Один SMTP-порт на сервере оказался недоступен, а другой работал нормально. Чтобы отправка формы не заставляла посетителя ждать ответа внешнего почтового сервера, письма были вынесены в фоновую очередь с повторными попытками. Были и обычные инфраструктурные детали: получение HTTPS-сертификата зависит от DNS и доступности сервера извне; контейнер может сохранить старые файлы WordPress в томе даже после замены образа; а настройки сайта находятся не только в Git, но и в базе данных. Всё это пришлось не только исправить, но и подробно записать, чтобы через год не разгадывать собственную систему заново.</p>
</p>
<h4 class="wp-block-heading">Результаты</h4>
<p class="wp-block-paragraph">
<p align="justify">Сейчас сайт работает на WordPress 7, PHP 8.3 и MySQL 8. Старую тему Arthemia удалось сохранить, но её код был адаптирован к современным версиям PHP и WordPress. Работают её настройки, административная панель, медиабиблиотека, виджеты и основные шаблоны страниц.</p>
</p>
<p class="wp-block-paragraph">
<p align="justify">Все плагины были пересмотрены. Ненужные и заброшенные удалены, используемые обновлены, а изменения, которые должны переживать обновление сторонних компонентов, вынесены из их кода. Для сайта появились два небольших самостоятельных плагина: интерактивное облако тегов и собственная форма обратной связи.</p>
</p>
<p class="wp-block-paragraph">
<p align="justify">Старые комментарии сохранены как часть материалов, но добавление новых отключено. Из базы формы обратной связи были удалены накопившиеся за годы тысячи спам-сообщений. Новая форма использует капчу, скрытое поле-приманку и ограничение частоты отправок. Сообщение сохраняется в базе на ограниченный срок, а его копия отправляется администратору по электронной почте.</p>
</p>
<p class="wp-block-paragraph">
<p align="justify">Отдельно были исправлены русские подписи в теме, даты, футер, архивы, результаты поиска и отображение комментариев. Для фрагментов кода вернулось нормальное оформление с моноширинным шрифтом и номерами строк. Миниатюры статей теперь ведут к самой статье, а не открывают бесполезную увеличенную копию изображения.</p>
</p>
<p class="wp-block-paragraph">
<p align="justify">Сайт получил векторный логотип и корректную иконку, адаптацию для мобильных экранов, автоматические описания страниц архивов и меток, а также счётчик Яндекс Метрики. Это не превращает старую тему в современный дизайн с нуля, но делает её аккуратнее и пригоднее для нынешних браузеров и поисковых систем.</p>
</p>
<p class="wp-block-paragraph">
<p align="justify">Изменилась и серверная часть. Конфигурация хранится отдельно от содержимого сайта, секреты не попадают в репозиторий, база данных не публикуется в интернет. Caddy принимает веб-трафик и автоматически продлевает HTTPS-сертификаты. Доступ к административной панели можно ограничить доверенными адресами и сетями. Для файлов и базы подготовлены сценарии резервного копирования, восстановления и переноса на другой сервер.</p>
</p>
<p class="wp-block-paragraph">
<p align="justify">В результате получился не просто сайт, который однажды удалось запустить, а воспроизводимая схема: её можно проверить локально, развернуть на новом сервере и восстановить из резервной копии.</p>
</p>
<h4 class="wp-block-heading">О работе с ИИ</h4>
<p class="wp-block-paragraph">
<p align="justify">Для такого проекта ИИ оказался особенно полезен не потому, что написал много нового кода. Основная работа напоминала техническую археологию: прочитать чужой код пятнадцатилетней давности, понять его намерение, найти несовместимость, сопоставить её с журналами и аккуратно изменить только необходимое. Человеку такая работа быстро становится утомительной. Codex мог последовательно просматривать десятки файлов, искать одинаковые конструкции, сравнивать настройки, готовить сценарии миграции и одновременно вести техническую документацию. Он заметно ускорил путь от сообщения «здесь пустая страница» до конкретной причины в старом PHP или JavaScript. Но этот опыт не подтвердил идею, что ИИ можно просто оставить наедине с проектом. Ему требовалась обратная связь: как выглядит страница, соответствует ли результат оригиналу, действительно ли письмо пришло, не сломалась ли мобильная версия. Иногда он исправлял техническую проблему, но предлагал визуальное решение, которое мне не нравилось. Иногда новая правка обнаруживала более старую скрытую ошибку. Лучше всего сработало разделение ролей. Я определял, что важно сохранить, проверял сайт глазами пользователя и принимал решения. Codex быстро исследовал техническую часть, выполнял рутинную работу и фиксировал результат. Без одного из этих участников итог был бы хуже.</p>
</p>
<h4 class="wp-block-heading">Будущее</h4>
<p class="wp-block-paragraph">
<p align="justify">Я пока не готов сказать, что UCExpert снова будет обновляться. Моя работа изменилась, а вместе с ней изменился и набор тем, о которых я могу писать на основании реального опыта.</p>
</p>
<p class="wp-block-paragraph">
<p align="justify">Да и формат технической информации становится другим. Краткую справку, типовую конфигурацию или объяснение протокола сегодня действительно проще получить у ИИ. Вероятно, доля статей, которые лишь пересказывают документацию, будет уменьшаться. Но это не означает, что писать больше незачем. Скорее, возрастает ценность материалов, в которых есть личный опыт, проверяемый результат и контекст. ИИ может объяснить, как в общем случае обновляется WordPress, но сам по себе он не знает историю конкретного старого сайта, не видел его ошибок и не принимал решений о том, что стоит сохранить. Пока кто-то не опишет такой опыт, обобщать будет нечего.</p>
</p>
<p class="wp-block-paragraph">
<p align="justify">Я не столько «вернул блог», сколько снова сделал продолжение возможным. Сайт больше не держится на версии PHP десятилетней давности, его можно резервировать, переносить и обновлять. А будет ли здесь следующая статья и о чём она окажется — теперь это снова содержательный вопрос, а не ограничение старого движка. UCExpert может оставаться живым архивом и иногда пополняться материалами, для которых у меня действительно есть собственные наблюдения. Эта статья — как раз один из таких материалов.</p></p><p>The post <a href="https://ucexpert.ru/archives/7471">После семилетней паузы: как я обновил UCExpert с ИИ</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Управление iptables при помощи CGI-скриптов</title>
		<link>https://ucexpert.ru/archives/7400</link>
					<comments>https://ucexpert.ru/archives/7400#comments</comments>
		
		<dc:creator><![CDATA[Игнат Кудрявцев]]></dc:creator>
		<pubDate>Wed, 29 May 2019 15:50:44 +0000</pubDate>
				<category><![CDATA[Техно]]></category>
		<guid isPermaLink="false">http://www.ucexpert.ru/?p=7400</guid>

					<description><![CDATA[<p>Использование функционала CGI, скриптов bash (равно как и на другом языке программирования), веб-сервера и авторизации по ключам ssh позволяет легко реализовать полезные в администрировании веб-приложения. Ниже представлен практический пример: удалённое управление сетевым фильтром iptables через ...</p>
<p>The post <a href="https://ucexpert.ru/archives/7400">Управление iptables при помощи CGI-скриптов</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Использование функционала CGI, скриптов bash (равно как и на другом языке программирования), веб-сервера и авторизации по ключам ssh позволяет легко реализовать полезные в администрировании веб-приложения. Ниже представлен практический пример: удалённое управление сетевым фильтром iptables через веб-интерфейс.</p>
<p><span id="more-7400"></span></p>
<p>Задача: при помощи веб-форм размещённых на веб-сервере, добавлять удалять и просматривать правила сетевого фильтра iptables на удалённых серверах, также запускать ping и traceroute, получать результат вывода в веб-интерфейс. Такой функциона полезен для упрощения процесса конфигурирования сетевого экрана, позволяет исключить использование консоли при конфигурировании, и соответственно не давать доступ пользователям в shell, если есть дублирующие сервера, управлять правилами сетевых фильтров на всех одновременно.<br />
Ниже представлена общая схема работы. Данный материал не приследует цель дать полную инструкцию по реализации такой схемы, а лишь даёт идею для реализации с некоторыми техническим подробностями.
</p>
<p><a href="/wp-content/uploads/2019/05/scheme-of-firewall-editor.jpg"><img loading="lazy" decoding="async" src="/wp-content/uploads/2019/05/scheme-of-firewall-editor.jpg" alt="" width="658" height="350" class="aligncenter size-full wp-image-7424 no-frame" /></a></p>
<p>
Пользователь, при помощи веб-браузера, авторизуется (при помощи встроенного в веб-сервера Apache механизма) на странице, которая сорержит CGI-скрипт, когда пользователь добавляет удаляет или просматриваем правила в iptables через веб-форму, скрипт по ssh &#171;дёргает&#187; другие скрипты находящиеся на удалённом сервере и возвращает в веб-браузер клиента результат выполнения скрипта с удалённого сервера.</p>
<p>Процесс настройки выглядит следующим образом:<br />
1) Настройка веб-сервера Apache и его работу с CGI<br />
2) Защита логином и паролем директорию веб-сервера где находятся скрипты<br />
3) Создание пользователя на удалённом хосте, где будут выполняться команды от CGI скриптов<br />
при помощи ssh<br />
4) Добавление прав пользователю на выполнения команд требующих повышения прав при помощи sudo<br />
5) Загрузка bash скриптов обработчиков команд по ssh от веб-сервера на удалённом хосте<br />
6) Разрешаем авторизацию по ключам для sshd<br />
7) Настройка авторизации по ключам ssh<br />
8) Загрузка bash скриптов в директорию CGI назначение им прав<br />
9) Тестирование работы</p>
<p><strong>Шаг 1. Настройка веб-сервера Apache и cgi</strong></p>
<p>В Linux Centos открываем <code>/etc/httpd/conf/ httpd.conf</code>, находим строки:</p>
<pre><code>ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
#
# "/var/www/cgi-bin" should be changed to whatever your ScriptAliased
# CGI directory exists, if you have that configured.
#
&lt;Directory "/var/www/cgi-bin"&gt;
    #AllowOverride None
    AllowOverride All
    Options None
    Order allow,deny
    Allow from all
&lt;/Directory&gt;</code></pre>
<p>Здесь нас интересует параметр <code>AllowOverride</code>, который по умолчанию установлен как <code>None</code>, меняем её на <code>AllowOverride All</code>.</p>
<p>Далее рестартуем Apache:</p>
<p><code>/etc/init.d/httpd restart</code></p>
<p>Тоже самое, но для Debian, здесь будет отличаться настройка Apache.</p>
<p>Переходим в <code>/etc/apache2/sites-available</code><br />
создаём файл <code>firewall-web</code><br />
<code># > firewall-web</code><br />
Порт 80 на котором будет находиться виртуальный хост:</p>
<pre><code>Listen *:80
&lt;VirtualHost *:80&gt;
ServerAdmin ignat@spb.ru

DocumentRoot /usr/lib/cgi-bin
&lt;Directory /&gt;
Options FollowSymLinks
AllowOverride None
&lt;/Directory&gt;
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
&lt;Directory "/usr/lib/cgi-bin"&gt;
AllowOverride All
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Order allow,deny
Allow from all
&lt;/Directory&gt;

ErrorLog ${APACHE_LOG_DIR}/error-firewall-web.log

# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/access-firewall-wb.log combined
&lt;/VirtualHost&gt;</code></pre>
<p>Сохраняем.</p>
<p>Далее переходим в директорию <code>/etc/apache2/sites-enabled </code><br />
И создаём символическую ссылку на <code>/etc/apache2/sites-available/firewall-web</code></p>
<p>Теперь делаем <em>reload</em> конфигурации Apache:</p>
<p><code>#/etc/init.d/apache2 reload</code></p>
<p>Также нужно проверить что в <code>/etc/apache2/mods-enabled</code> есть ссылка на файл <code>/etc/apache2/mods-available/cgi.load</code><br />
Если нет, то создать, и перечитать конфигурацию веб-сервера:<br />
<code>#/etc/init.d/apache2 reload</code><br />
Отлично, теперь надо защитить наши скрипты от неавторизованного доступа, один из простейших вариантов добавить http аутентификацию и авторизацию.</p>
<p><strong>Шаг 2. Защита логином и паролем директорию веб-сервера где находятся скрипты</strong></p>
<p>Настройка простой аутентификации и авторизации в Apache</p>
<p>Настраивается аутентификация либо в файле httpd.conf, либо в файле .htaccess. При настройке посредством .htaccess, необходимо сначала убедиться, что директива AllowOverride в файле httpd.conf разрешает получение настроек из файла .htaccess. Директива AllowOverride может принимать следующие значения:</p>
<ul>&#8212; AllowOverride None — файлы .htaccess игнорируются веб-сервером. Данное значение оказывает положительное влияние на быстродействие веб-сервера.</ul>
<ul>&#8212; AllowOverride All — обрабатываются все без исключения директивы из файлов .htaccess.</ul>
<ul>&#8212; AllowOverride AuthConfig — разрешены директивы аутентификации-авторизации, такие как AuthName, AuthType, AuthUserFile, AuthGroupFile, Require и т.д.</ul>
<p>Чтобы авторизация заработала, нам надо сделать следующее:</p>
<ul>&#8212; Разрешить аутентификацию в конфигурационном файле Apache (файл httpd.conf)</ul>
<ul>&#8212; Прописать защищаемый ресурс в конфигурацию Apache (в файле .htaccess).</ul>
<ul>&#8212; Создать файл с паролями .htpasswd.</ul>
<p>Далее, предполгаем что наши скрипты лежат в директории <code>/var/www/cgi-bin/</code>.<br />
Мы защищаем директорию с нашими скриптами <code>/var/www/cgi-bin/</code> поэтому создаём в ней файл .htaccess с правами apache:</p>
<pre><code>#&gt; .htaccess
#chown apache:apache .htaccess
В файл .htaccess добавим:
AuthName "Authentication"
AuthType Basic
AuthUserFile /var/www/cgi-bin/.htpasswd
require valid-user</code></pre>
<p>Что обозначает каждая из директив:</p>
<p><strong>AuthName</strong> – текст содержащийся в данной директиве, выводится в окне ввода пароля. Он должен быть написан в одну строку и заключен в двойные кавычки.<br />
<strong>AuthType</strong> — типы аутентификации: Basic или Digest. Рекомендуется использовать первый, так как второй поддерживается не всеми браузерами.<br />
<strong>AuthUserFile</strong> — полный путь к файлу с логинами и паролями, для аутентификации пользователей. Пароли содержаться в шифрованном виде. Рекомендуется хранить данный файл в папке, к которой нет доступа для пользователей, это необходимо, чтобы предотвратить кражу паролей.<br />
<strong>require valid-user</strong> – директива предписывает, что к URL получают доступ только, пользователи, успешно прошедшие аутентификацию.</p>
<p>Сохраняем. Теперь нужно создать файл <code>.htpasswd</code><br />
Это делается при помощи утилиты <code>htpasswd</code><br />
Ключи:<br />
-cm — ключи утилиты:<br />
-с – указывает, что необходимо создать новый файл<br />
-m –шифрует пароли по алгоритму MD5<br />
<code>.htpasswd</code> – имя файла с паролями<br />
<code>firewall</code> – логин<br />
Создаём пользователя с новом файле:</p>
<pre><code>#htpasswd -cm .htpasswd firewall</code></pre>
<p>Дважды вводим пароль для пользователя firewall.<br />
Листинг содержимого получившегося файла:</p>
<pre><code># cat .htpasswd
firewall:$apr1$xMW8mAaG$259lBs0uXj.M/t1Yu7T2u1</code></pre>
<p>Добавить ещё одного пользователя в существующий файл:<br />
<code>#htpasswd -m .htpasswd ignat</code></p>
<p>Теперь при открытии адреса <code>http://192.168.1.252/cgi-bin/</code> будет появляться окно авторизации:<br />
<a href="/wp-content/uploads/2019/05/apache-auth-e1559055695607.png"><img loading="lazy" decoding="async" src="/wp-content/uploads/2019/05/apache-auth-e1559055695607.png" alt="" width="690" height="447" class="aligncenter size-full wp-image-7419 no-frame" /></a><br />
После успешной перезагрузки переходим в директорию <code>/usr/lib/cgi-bin</code> и размещаем здесь файлы CGI-скриптов.</p>
<p><strong>Шаг 3. Создание пользователя на удалённом хосте, где будут выполняться команды от CGI-скриптов при помощи ssh</strong></p>
<p>Добавляем авторизацию по ключам ssh. Мы поставили веб-сервер Apache на одной машине 192.168.1.252, залить туда скрипты и при помощи команд SSH удалённо выполнять команды на хосте 192.168.1.16 и анализировать из результат, например:</p>
<pre><code>ssh firewall-edit @192.168.1.16 'uptime'
13:32:59 up 584 days,  1:26,  4 users,  load average: 0.41, 0.34, 0.27</code></pre>
<p>Для этого нужно настроить авторизацию по ключам на ssh-клиенте (192.168.1.252) и на удалённом ssh-сервере (192.168.1.16).</p>
<p>Создадим пользователя на удалённом сервере, дадим ему права на выполнение без пароля команд <code>iptables</code> и <code>iptables-save:</code>
</p>
<pre><code>#useradd firewall-edit  --create-home --comment 'Remote firewall editor' --shell /bin/bash
#passwd firewall-edit</code></pre>
<p><strong>Шаг. 4 Добавление прав пользователю на выполнения команд требующих повышения прав при помощи sudo</strong></p>
<p>Отлично, теперь нужно добавить возможно выполнять команды iptables и iptables-save без прав root.<br />
Пропишем в /etc/sudoers, из под root отредактируем данный файл:</p>
<pre><code>#aptitiude install sudo
#sudoedit /etc/sudoers</code></pre>
<p>Добавим следующие строки:</p>
<pre><code>firewall-edit  ALL=(ALL) NOPASSWD:/sbin/iptables
firewall-edit  ALL=(ALL) NOPASSWD:/sbin/iptables-save</code></pre>
<p>Сохраняем.</p>
<p><strong>Шаг. 5 Загрузка bash скриптов обработчиков команд по ssh от веб-сервера на удалённом хосте</strong></p>
<p>Конечно, можно посылать по ssh просто команды, затем обрабатывать их вывод на веб-сервере (192.168.1.252), но зачем «гонять» лишние данные? Поэтому загрузим скрипты которым будут передаваться нужные параметры, они буду их обрабатывать и выдавать результат, который мы передадим назад веб-серверу и покажем пользователю на веб-странице.</p>
<p>Ниже пример:
</p>
<pre><code>ucexpert.ru:/home/firewall-edit# cat firewall-find-ip.sh
#!/bin/bash 
sudo iptables -L CLIENTS -n -v --line-number| sed '1,1d'| grep $1 |  awk '{print "&lt;tr&gt;&lt;td&gt;" $1 "&lt;/td&gt;&lt;td&gt;" $9 "&lt;/td&gt;&lt;/tr&gt;"}'</code></pre>
<p>
Обращаю внимание что в вывод сразу же добавлена html разметка для отображении в веб-браузере клиента.<br />
На стороне веб-сервера (192.168.1.252) этот скрипт будет вызываться так:
</p>
<pre><code>sudo ssh firewall-edit@192.168.1.16 "./firewall-find-ip.sh $IP"</code></pre>
<p>Первый скрипт получает IP-адрес, ищет его в таблице и отправляет результат.</p>
<pre><code>ucexpert.ru:/home/firewall-edit# cat firewall-get-ip.sh
#!/bin/bash 
sudo /sbin/iptables -L CLIENTS -n -v --line-number| sed '1,1d' |  awk '{print "&lt;tr&gt;&lt;td&gt;" $1 "&lt;/td&gt;&lt;td&gt;" $9 "&lt;/td&gt;&lt;/tr&gt;"}'</code></pre>
<p>На стороне веб-сервера (192.168.1.252) этот скрипт будет передаваться как:</p>
<pre><code>sudo ssh firewall-edit@192.168.1.16 './firewall-get-ip.sh'</code></pre>
<p>Второй скрипт возвращает назад все правила с номерами (<code>--line-number</code>) в цепочке CLIENTS, в виде html таблицы.</p>
<p>Команды ping и traceroute будем запускать без скриптов.
</p>
<pre><code>sudo ssh firewall-edit@192.168.1.16 "ping $IP -I $RTU -c 5" 
sudo ssh firewall-edit@192.168.1.16 "traceroute $IP"</code></pre>
<p><b>Создаём окружение для скриптов на 192.168.1.16</b></p>
<p>Создаём файл iptables в нашей домашней директории, сюда мы будем сохранять правила iptables.</p>
<pre><code>/home/firewall-edit# &gt; iptables</code></pre>
<p>Копируем скрипты:</p>
<pre><code>firewall-find-ip.sh
firewall-get-ip.sh
firewall.sh</code></pre>
<p>Далее, назначаем необходимые права нашему пользователю, который будет удалённо выполнят команды:</p>
<pre><code>#/home/firewall-edit# chown firewall-edit:firewall-edit firewall.sh
#/home/firewall-edit# chown firewall-edit:firewall-edit iptables</code></pre>
<p>Скрипте на сервере запускаем при помощи sudo</p>
<pre><code>#sudo /sbin/iptables -L -n -v | grep 84.84.84.84
#sudo ./firewall.sh add 84.84.84.84
#sudo ./firewall.sh del  84.84.84.84</code></pre>
<p>Устанавливаем права на скрипты, пример:</p>
<pre><code>#/home/firewall-edit# chown www-data:www-data firewall.sh
#/home/firewall-edit# chmod +x firewall.sh</code></pre>
<p>Для отладки команд, которые передаются на удалённый сервер по SSH можно также использовать ttyrec или поставить утилиту snoopy:</p>
<pre><code>ucexpert.ru:/home/firewall-edit# #aptitude install snoopy</code></pre>
<p>Данная утилита логирует пользовательские команды, интерактивно смотреть их при помощи команды:</p>
<pre><code>ucexpert.ru:/home/firewall-edit# #tail -f /var/log/auth
Apr 13 11:25:43 rtu4-1 sshd[3273]: Accepted publickey for firewall-edit from 192.168.1.252 port 53822 ssh2
Apr 13 11:25:43 rtu4-1 sshd[3273]: pam_unix(sshd:session): session opened for user firewall-edit by (uid=0)
Apr 13 11:25:43 rtu4-1 sudo: firewall-edit : TTY=unknown ; PWD=/home/firewall-edit ; USER=root ; COMMAND=/sbin/iptables -L CLIENTS -n -v --line-number
Apr 13 11:25:43 rtu4-1 sshd[3296]: Received disconnect from 192.168.1.252: 11: disconnected by user</code></pre>
<p><b>Шаг 6. Разрешаем авторизацию по ключам для sshd на удалённом хосте</b><br />
Открываем <code>/etc/ssh/sshd_config</code><br />
Проверяем, что следующие строки присутствуют и не закомментированы:</p>
<pre><code>RSAAuthentication yes
PubkeyAuthentication yes</code></pre>
<p>
После чего перезапускаем sshd.</p>
<p><b>Шаг 7. Настройка авторизации по ключам ssh</b></p>
<p>На клиенте (192.168.1.16) локальной машине нужно сгенерировать пару ключей:</p>
<p><b>приватный id_rsa</b> – хранится у клиента в файле <code>/home/$user/.ssh/id_rsa</code><br />
<b>публичный id_rsa.pub</b> – хранится в файле <code>/home/$user/.ssh/id_rsa.pub</code></p>
<p>Где <code>$user</code> пользователь который генерирует ключ. Для root этот путь будет <code> /root/.ssh </code></p>
<p>Мы генерируем файл из под root, соответственно чтобы подключаться по ssh веб-сервере и пользователь www-data должны запускать ssh с правами root или sudo ssh.</p>
<p>Сгенерируем пару ключей на клиенте (192.168.1.252) при помощи утилиты ssh-keygen (если ключ уже создан для нового хоста его генерировать не требуется)
</p>
<pre><code># ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:GXgitSSV+S66HjiNW9A9pcehP3WECulLpi5tuPrt2bs root@CDR-serv
The key's randomart image is:
+---[RSA 2048]----+
|    ..+o         |
|     +o+   .     |
|    . *.= . .    |
|   . + O.= .     |
|  . . O.S . .    |
|   = +.=.. .     |
|  +o=...o        |
|  o*++   .       |
|.o+*B.Eo         |
+----[SHA256]-----+</code></pre>
<p>Чтобы авторизоваться на 192.168.1.16, предварительно открытый или публичный ключ должен быть загружен на сервер, для этого загрузим ключ на сервер 192.168.1.16 при помощи утилиты <code>ssh-copy-id</code>:</p>
<pre><code># ssh-copy-id firewall-edit@192.168.1.16
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
The authenticity of host '192.168.1.16 (192.168.1.16)' can't be established.
RSA key fingerprint is SHA256:Ma5zmprv9jGPkwdSwEgwFK2L4jyzCqc1xxoXYW5I7e0.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
firewall-edit@192.168.1.16's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'firewall-edit@192.168.1.16'"
and check to make sure that only the key(s) you wanted were added.</code></pre>
<p>Таким образом ключ успешно инсталлирован.</p>
<p>Проверим работу авторизации по ключу:</p>
<pre><code># ssh firewall-edit@192.168.1.16 'uptime'
 18:13:03 up 582 days,  6:06,  2 users,  load average: 0.14, 0.21, 0.19</code></pre>
<p>Теперь проверяем: из под пользователя <code>firewall-edit</code> заходим на удалённый хост по ключу и запускаем команду iptables.</p>
<pre><code># ssh firewall-edit@192.168.1.16 ' sudo /sbin/iptables -L -n -v '</code></pre>
<p>Если будет возвращён вывод запущенной конфигурации iptables, то всё настроено правильно.<br />
На этом настройка авторизации по ssh ключам завершена.</p>
<p><b>Шаг 8. Загрузка bash скриптов в директорию CGI веб-сервера 192.168.1.252 назначение им прав </b></p>
<p>Создаём окружение для скриптов на клиенте.</p>
<p>Здесь есть один важный момент: скрипты запускаются из под пользователя www-data<br />
Чтобы запускать ssh с авторизацией по ключам надо повысить уровень прав, нам поможет sudo.<br />
Пропишем в <code>/etc/sudoers</code>, из под root отредактируем данный файл:</p>
<p><code>#sudoedit /etc/sudoers</code></p>
<p>Добавим следующие строки:
</p>
<pre><code>www-data  ALL=(ALL) NOPASSWD: /usr/bin/ssh</code></pre>
<p>Сохраняем.</p>
<p>Теперь создаём cgi скрипт который будет выполняться при открытии и успешной авторизации в веб-браузере ссылки <code> http://192.168.1.252/cgi-bin</code> </p>
<p>Листинг скрпита <code>index.cgi</code> с комментариями:</p>
<pre><code>root@CDR-serv:/var/www/html/cgi-bin# cat index.cgi
#!/bin/bash
echo "Content-type: text/html"
echo ""
echo '&lt;html&gt;'
echo '&lt;head&gt;'
echo '&lt;meta http-equiv="Content-Type" application/x-www-form-urlencoded; charset=UTF-8"&gt;'
#Загружаем favicon
echo '&lt;link rel="icon" href="http://192.168.1.252/favicon.png" sizes="32x32" /&gt;'
echo '&lt;link rel="shortcut icon" href="http://192.168.1.252/favicon.png" /&gt;'

#Заголовок страницы
echo '&lt;title&gt;FIREWALL EDITOR for RTU4 &lt;/title&gt;'
echo '&lt;/head&gt;'
echo '&lt;body&gt;'
#Заголовок 3 уровня на странице
echo '&lt;h3&gt;' RTU 4 FIREWALL EDITOR
echo '&lt;/h3&gt;'
echo '&lt;p&gt;'Проветить есть IP-адрес в списке разрешённых \(можно ввести часть, например: 84.52.\) без маски или префикса сети:
echo '&lt;/p&gt;'
#Начало формы поиска разрешённых IP-адресов в списке
echo "&lt;form method="POST" action="find-ip-addr.cgi"&gt;"
 echo '&lt;table nowrap&gt;
                  &lt;tr&gt;&lt;td&gt;IP-адрес&lt;/td&gt;&lt;td&gt;&lt;input type="text" name="IP" pattern="^[0-9\.]{3,15}$" size="12"&gt; &lt;/td&gt;
                                      &lt;/tr&gt;&lt;/table&gt;
                                      &lt;button type="submit"&gt;Проверить&lt;/button&gt;
                                      &lt;input type="reset" value="Очистить"&gt; &lt;/form&gt;'
echo '&lt;p&gt;'Добавить IP-адрес и префикс сети \(опционально, например 29\):
echo '&lt;/p&gt;'
echo "&lt;form method="POST" action="firewall-add.cgi"&gt;"
 echo '&lt;table nowrap&gt;
                  &lt;tr&gt;&lt;td&gt;IP-адрес&lt;/td&gt;&lt;td&gt;&lt;input type="text" name="IP" pattern="^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$" size=12&gt;&lt;/td&gt;&lt;/tr&gt;
                            &lt;tr&gt;&lt;td&gt;Префикс сети&lt;/td&gt;&lt;td&gt;&lt;input type="text" pattern="[0-9]{1,2}" name="MASK" size=12 value=""&gt;&lt;/td&gt;&lt;/tr&gt;
                                &lt;tr&gt;&lt;td&gt;Комментарий: &lt;/td&gt;&lt;td&gt;&lt;textarea rows="5" cols="22" autocomplete="off" placeholder="Опционально" name="COMMENT" &gt;&lt;/textarea&gt; &lt;/td&gt;
                                      &lt;/tr&gt;&lt;/table&gt;
                                      &lt;button type="submit"&gt;Добавить&lt;/button&gt;
                                      &lt;input type="reset" value="Очистить"&gt; &lt;/form&gt;'

#Конец формы поиска IP-адрес в списке разрешённых, при нажатии кнопки "Проверить" выполнится скрипт find-ip-addr.cgi причём он примет единственный аргумент IP и в браузер вернётся результат выполнения скрипта
echo '&lt;p&gt;'Удалить IP-адрес \(без маски или префикса сети\):
echo '&lt;/p&gt;'

#Начало формы добавления IP-адреса или подсети в список разрешённых, тут кроме аргумента IP - адреса и MASK - маску IP которую следует удалить, может опционально передаваться комментарий
echo '&lt;p&gt;'Добавить IP-адрес и префикс сети \(опционально, например 29\):
echo '&lt;/p&gt;'

echo "&lt;form method="POST" action="firewall-add.cgi"&gt;"
 echo '&lt;table nowrap&gt;
                  &lt;tr&gt;&lt;td&gt;IP-адрес&lt;/td&gt;&lt;td&gt;&lt;input type="text" name="IP" pattern="^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$" size=12&gt;&lt;/td&gt;&lt;/tr&gt;
                            &lt;tr&gt;&lt;td&gt;Префикс сети&lt;/td&gt;&lt;td&gt;&lt;input type="text" pattern="[0-9]{1,2}" name="MASK" size=12 value=""&gt;&lt;/td&gt;&lt;/tr&gt;
                                &lt;tr&gt;&lt;td&gt;Комментарий: &lt;/td&gt;&lt;td&gt;&lt;textarea rows="5" cols="22" autocomplete="off" placeholder="Опционально" name="COMMENT" &gt;&lt;/textarea&gt; &lt;/td&gt;
                                      &lt;/tr&gt;&lt;/table&gt;
                                      &lt;button type="submit"&gt;Добавить&lt;/button&gt;
                                      &lt;input type="reset" value="Очистить"&gt; &lt;/form&gt;'

#Конец формы добавления IP-адреса в списке разрешённых, при нажатии кнопки "Добавить" выполнится скрипт firewall-add.cgi, с входными аргументами - IP-адрес и маску, опционально комментарий и в браузер вернётся результат выполнения скрипта			
				
#Аналогично, начало формы удаления IP-адреса из iptables.				
echo '&lt;p&gt;'Удалить IP-адрес \(без маски или префикса сети\):
echo '&lt;/p&gt;'

echo "&lt;form method="POST" action="firewall-del.cgi"&gt;"
 echo '&lt;table nowrap&gt;
                  &lt;tr&gt;&lt;td&gt;IP-адрес&lt;/TD&gt;&lt;TD&gt;&lt;input type="text" name="IP" pattern="^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$" size=12&gt;&lt;/td&gt;&lt;/tr&gt;
                 &lt;tr&gt;&lt;td&gt;Комментарий: &lt;/td&gt;&lt;td&gt;&lt;textarea rows="5" cols="22" autocomplete="off" placeholder="Опционально" name="COMMENT" &gt;&lt;/textarea&gt; &lt;/td&gt;
                                      &lt;/tr&gt;&lt;/table&gt;
                                      &lt;button type="submit"&gt;Удалить&lt;/button&gt;
                                      &lt;input type="reset" value="Очистить"&gt; &lt;/form&gt;'
									  
#Конец формы. При нажатии на кнопку "Удалить" выполнится скрипт firewall-del.cgi

#Форма отображения полного списка разрешённых IP-адресов
echo '&lt;p&gt;' Показать полный список разрешенныйх IP-адресов для транков РТУ 4
echo '&lt;/p&gt;'
echo "&lt;form method="POST" action="get-ip-list.cgi"&gt; &lt;button type="Submit"/&gt;Показать&lt;/button&gt;&lt;/form&gt;"
#Конец формы отображения полного списка разрешённых IP-адресов.
echo '&lt;/body&gt;'
echo '&lt;/html&gt;'
exit</code></pre>
<p>При обращении к веб-серверу по адресу <code>http://192.168.1.252/cgi-bin/</code> выполняется скрипт написанный на языке bash, а результат его выполения отдаётся веб-сервером в веб-браузер клиенту который запросил страницу, логично что это должен быть код HTML (хотя и не обязательно)<br />
А а вот как будет выгядеть html-код страницы когда скрипт index.cgi будет выполнен и результат его работы будет возращён в веб-браузер клиента.</p>
<pre><code>&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" application/x-www-form-urlencoded; charset=UTF-8"&gt;
&lt;link rel="icon" href="http://192.168.1.252/favicon.png" sizes="32x32" /&gt;
&lt;link rel="shortcut icon" href="http://192.168.1.252/favicon.png" /&gt;
&lt;title&gt;FIREWALL EDITOR for RTU4 and NET DIAGNOSTIC&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;h3&gt; RTU 4 FIREWALL EDITOR
&lt;/h3&gt;

Листинг скрпита find-ip-addr.cgi который запускается из скрпита index.cgi при использовании веб-формы поиска IP-адреса:

Проветить есть IP-адрес в списке разрешённых (можно ввести часть, например: 84.52.) без маски или префикса сети:

&lt;form method=POST action=find-ip-addr.cgi&gt;

&lt;table nowrap&gt;
                  
&lt;tr&gt;
&lt;td&gt;IP-адрес&lt;/td&gt;
&lt;td&gt;&lt;input type="text" name="IP" pattern="^[0-9\.]{3,15}$" size="12"&gt; &lt;/td&gt;

                                      &lt;/tr&gt;
&lt;/table&gt;

                                      &lt;button type="submit"&gt;Проверить&lt;/button&gt;
                                      &lt;input type="reset" value="Очистить"&gt; &lt;/form&gt;

Добавить IP-адрес и префикс сети (опционально, например 29):

&lt;form method=POST action=firewall-add.cgi&gt;

&lt;table nowrap&gt;
                  
&lt;tr&gt;
&lt;td&gt;IP-адрес&lt;/td&gt;
&lt;td&gt;&lt;input type="text" name="IP" pattern="^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$" size=12&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Префикс сети&lt;/td&gt;
&lt;td&gt;&lt;input type="text" pattern="[0-9]{1,2}" name="MASK" size=12 value=""&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Комментарий: &lt;/td&gt;
&lt;td&gt;&lt;textarea rows="5" cols="22" autocomplete="off" placeholder="Опционально" name="COMMENT" &gt;&lt;/textarea&gt; &lt;/td&gt;

                                      &lt;/tr&gt;
&lt;/table&gt;

                                      &lt;button type="submit"&gt;Добавить&lt;/button&gt;
                                      &lt;input type="reset" value="Очистить"&gt; &lt;/form&gt;

Удалить IP-адрес (без маски или префикса сети):

&lt;form method=POST action=firewall-del.cgi&gt;

&lt;table nowrap&gt;
                  
&lt;tr&gt;
&lt;td&gt;IP-адрес&lt;/TD&gt;
&lt;TD&gt;&lt;input type="text" name="IP" pattern="^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$" size=12&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Комментарий: &lt;/td&gt;
&lt;td&gt;&lt;textarea rows="5" cols="22" autocomplete="off" placeholder="Опционально" name="COMMENT" &gt;&lt;/textarea&gt; &lt;/td&gt;

                                      &lt;/tr&gt;
&lt;/table&gt;

                                      &lt;button type="submit"&gt;Удалить&lt;/button&gt;
                                      &lt;input type="reset" value="Очистить"&gt; &lt;/form&gt;

 Показать полный список разрешенныйх IP-адресов для транков РТУ 4

&lt;form method=POST action=get-ip-list.cgi&gt; &lt;button type=Submit/&gt;Показать&lt;/button&gt;&lt;/form&gt;

&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>Здесь скриптом генеририуются html формы, затем этими веб-формами может воспользоваться клиент, к каждой веб-форме привязан скрипт (например, <code>find-ip-addr.cgi</code>), который также выполниться при запуске веб-формы и вернет результат обработки. Этот скрипт &#171;лезет&#187; на удалённый сервер, запускает другой скрипт, например firewall.sh и возвращает результат назад, затем результат в виде веб-страницы возвращается пользователю.</p>
<p>Теперь рассмотрим файл <code>find-ip-addr.cgi</code></p>
<pre><code>#!/bin/bash

echo "Content-type: text/html"
echo ""
echo '&lt;html&gt;'

echo '&lt;head&gt;'

echo '
 &lt;style type="text/css"&gt;
   TABLE {
    width: 300px; /* Ширина таблицы */
    border-collapse: collapse; /* Убираем двойные линии между ячейками */
   }
   TD, TH {
    padding: 3px; /* Поля вокруг содержимого таблицы */
    border: 1px solid black; /* Параметры рамки */
    text-align: center;
   }
   TH {
    background: #b0e0e6; /* Цвет фона */
   }
    hr {
    border: none; /* Убираем границу */
    background-color: black; /* Цвет линии */
    color: black; /* Цвет линии для IE6-7 */
    height: 2px; /* Толщина линии */
   }
}
html,
body {
  height: 100%;
}
.wrapper {
  display: flex;
  flex-direction: column;
  height: 100%;
}
.content {
  flex: 1 0 auto;
}
.footer {
  flex: 0 0 auto;
}
  &lt;/style&gt;'

echo '&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"&gt;'
echo '&lt;link rel="icon" href="http://192.168.1.252/favicon.png" sizes="32x32" /&gt;'
echo '&lt;link rel="stylesheet" href="http://www.megacorp.com/style.css" type="text/css"&gt;'

echo '&lt;title&gt;Firewall&lt;/title&gt;'

echo '&lt;/head&gt;'

echo '&lt;body&gt;'

echo '&lt;h3&gt;'Результат поиска:
echo '&lt;/h3&gt;'
DATE=`date +%Y-%m-%d-%H:%M:%S`

if [ "$REQUEST_METHOD" = "POST" ]; then
    QUERY_STRING=`cat -`
    fi
    #echo `cat -` #Дебаг
    #echo "QUERY_STRING ==&gt;&lt;&gt; $QUERY_STRING &lt;/br&gt;" #Дебаг
    IP=`echo $QUERY_STRING | sed -n 's/^.*IP=\([^&amp;]*\).*$/\1/p' | sed "s/%20/ /g"` #Дебаг
    COMMENT=`echo $QUERY_STRING | sed -n 's/^.*COMMENT=\([^&amp;]*\).*$/\1/p' | sed "s/%20/ /g"` #Дебаг
    REMOTE_USER=`echo $REMOTE_USER`
    REMOTE_ADDR=`echo $REMOTE_ADDR`
    HTTP_USER_AGENT=`echo $HTTP_USER_AGENT`
    #echo "IP ==&gt; $IP &lt;/br&gt;" #Дебаг
    echo "&lt;b&gt;Результат поиска для введённого IP-адреса: $IP &lt;/b&gt;&lt;/br&gt;&lt;/br&gt;"
echo "&lt;b&gt;Найдены правила в таблице брандмауэра РТУ 4:&lt;/b&gt;&lt;/br&gt;&lt;/br&gt;"
echo '&lt;table border=1 cellpadding="4" cellspacing="0"&gt;'
echo '&lt;td&gt;№ Правила&lt;/td&gt;&lt;td&gt;IP-адрес или подсеть&lt;/td&gt;&lt;/tr&gt;'
sudo ssh firewall-edit@192.168.1.16 "./firewall-find-ip.sh $IP"
export LANG="ru_RU.UTF-8" # Это очень важный момент, без неё скрипту insert-log.py не передаётся аргумент закодированный кириллицей
echo '&lt;/table&gt;'
echo '&lt;pre&gt;'
./insert-log.py "$DATE" "ПОИСК" "$IP" "N/A" "$REMOTE_ADDR" "$REMOTE_USER" "$HTTP_USER_AGENT" "N/A" "$COMMENT"
echo '&lt;/pre&gt;'
./get-ip-history.py "$IP"
echo "&lt;br&gt;&lt;br&gt;&lt;small&gt;Дата запроса: $DATE &lt;/small&gt;&lt;/br&gt;"
echo "&lt;small&gt;Пользователь: $REMOTE_USER &lt;/small&gt;&lt;/br&gt;"
echo "&lt;small&gt;Ваш адрес: $REMOTE_ADDR &lt;/small&gt;&lt;/br&gt;"
echo '&lt;/body&gt;'
echo '&lt;/html&gt;'</code></pre>
<p>Ниже пример листинга скрипта <code>firewall-find-ip.sh</code> который выполняется на 192.168.1.16 который ищет запрошенные пользователем правила iptables.</p>
<pre><code>#!/bin/bash 
sudo iptables -L CLIENTS -n -v --line-number| sed '1,1d'| grep $1 |  awk '{print "&lt;tr&gt;&lt;td&gt;" $1 "&lt;/td&gt;&lt;td&gt;" $9 "&lt;/td&gt;&lt;/tr&gt;"}</code></pre>
<p><b>Шаг 9. Тестирование работы</b></p>
<p>Вот как выглядит веб-страница сгенерированная index.cgi:<br />
<a href="/wp-content/uploads/2019/05/Firewall-editor-cgi.png"><img loading="lazy" decoding="async" src="/wp-content/uploads/2019/05/Firewall-editor-cgi-300x233.png" alt="" width="690" height="535" class="aligncenter size-medium wp-image-7417 no-frame" srcset="https://ucexpert.ru/wp-content/uploads/2019/05/Firewall-editor-cgi-300x233.png 300w, https://ucexpert.ru/wp-content/uploads/2019/05/Firewall-editor-cgi-768x596.png 768w, https://ucexpert.ru/wp-content/uploads/2019/05/Firewall-editor-cgi.png 829w" sizes="auto, (max-width: 690px) 100vw, 690px" /></a></p>
<p>Мы запускаем поиск первых трёх актетов IP-адреса, например <code>84.52.72</code><br />
<a href="/wp-content/uploads/2019/05/find-ip-add-form.jpg"><img loading="lazy" decoding="async" src="/wp-content/uploads/2019/05/find-ip-add-form.jpg" alt="" width="826" height="138" class="aligncenter size-full wp-image-7432 no-frame" srcset="https://ucexpert.ru/wp-content/uploads/2019/05/find-ip-add-form.jpg 826w, https://ucexpert.ru/wp-content/uploads/2019/05/find-ip-add-form-300x50.jpg 300w, https://ucexpert.ru/wp-content/uploads/2019/05/find-ip-add-form-768x128.jpg 768w" sizes="auto, (max-width: 826px) 100vw, 826px" /></a><br />
и нажимаем кнопку &#171;Проверить&#187;. Ниже результат:</p>
<p><a href="/wp-content/uploads/2019/05/find-ip-add-form-result.jpg"><img loading="lazy" decoding="async" src="/wp-content/uploads/2019/05/find-ip-add-form-result.jpg" alt="" width="390" height="277" class="aligncenter size-full wp-image-7433 no-frame" srcset="https://ucexpert.ru/wp-content/uploads/2019/05/find-ip-add-form-result.jpg 390w, https://ucexpert.ru/wp-content/uploads/2019/05/find-ip-add-form-result-300x213.jpg 300w" sizes="auto, (max-width: 390px) 100vw, 390px" /></a></p>
<p>Найдено несколько правил и они выведены в виде таблицы. Что произошло: пользователь загрузил страницу <code>index.cgi</code> с несколькими формами, передал переменную <code>84.52.72</code> в форму поиска IP-адреса, которая в свою очередь передала управление CGI-скрипту <code>find-ip-addr.cgi</code> данный скрипт выполняет команду</p>
<pre><code>sudo ssh firewall-edit@192.168.1.16 "./firewall-find-ip.sh $IP"</code></pre>
<p> То есть, подключается к удалённому серверу <code>192.168.1.16</code>, выполняет на нём скрипт <code>firewall-find-ip.sh</code> и возвращает результат в веб-браузер клиенту.
</p>
<p> Автор: Игнат Кудрявцев</p><p>The post <a href="https://ucexpert.ru/archives/7400">Управление iptables при помощи CGI-скриптов</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://ucexpert.ru/archives/7400/feed</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Получение кодов отбоя SIP и стороны завершившей вызов в Asterisk</title>
		<link>https://ucexpert.ru/archives/7386</link>
		
		<dc:creator><![CDATA[Игнат Кудрявцев]]></dc:creator>
		<pubDate>Thu, 14 Mar 2019 05:49:18 +0000</pubDate>
				<category><![CDATA[Советы]]></category>
		<category><![CDATA[Техно]]></category>
		<category><![CDATA[Asterisk]]></category>
		<category><![CDATA[IP PBX]]></category>
		<category><![CDATA[SIP]]></category>
		<guid isPermaLink="false">http://www.ucexpert.ru/?p=7386</guid>

					<description><![CDATA[<p>В последних релизах Asterisk есть возможность получить коды отбоя Asterisk или SIP-код отбоя при помощи функции HANGUPCAUSE. В заметке приводится практический пример того как это сделать,а затем записать результаты в БД MySQL. Также приведен пример ...</p>
<p>The post <a href="https://ucexpert.ru/archives/7386">Получение кодов отбоя SIP и стороны завершившей вызов в Asterisk</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>В последних релизах Asterisk есть возможность получить коды отбоя Asterisk или SIP-код отбоя при помощи функции <strong>HANGUPCAUSE</strong>. В заметке приводится практический пример того как это сделать,а затем записать результаты в БД MySQL. Также приведен пример того, как в Asterisk узнать какая из сторон была инициатором завершения вызова.
</p>
<p><span id="more-7386"></span></p>
<p>В консоли Asterisk посмотрим описание функции HANGUPCAUSE.</p>
<pre><code>CLI&gt; core show function HANGUPCAUSE

  -= Info about function 'HANGUPCAUSE' =-

[Synopsis]
Gets per-channel hangupcause information from the channel.

[Description]
Gets technology-specific or translated Asterisk cause code information from the
channel for the specified channel that resulted from a dial.

[Syntax]
HANGUPCAUSE(channel,type)

[Arguments]
channel
    The name of the channel for which to retrieve cause information.
type
    Parameter describing which type of information is requested. Types are:
    tech - Technology-specific cause information
    ast - Translated Asterisk cause code

[See Also]
HANGUPCAUSE_KEYS, HangupCauseClear()</code></pre>
<p>
Всё достаточно просто. Но есть нюанс, что каналы, которые участвовали в соединении, могут не иметь коды отбоев.<br />
Поэтому в Asterisk есть специальная функция <code>HANGUPCAUSE_KEYS</code>, которая содержим имена каналов, содержащие коды отбоя:
</p>
<pre><code>*CLI&gt; core show function HANGUPCAUSE_KEYS

  -= Info about function 'HANGUPCAUSE_KEYS' =-

[Synopsis]
Gets the list of channels for which hangup causes are available.

[Description]
Returns a comma-separated list of channel names to be used with the HANGUPCAUSE
function.

[Syntax]
HANGUPCAUSE_KEYS()

[Arguments]
Not available

[See Also]
HANGUPCAUSE, HangupCauseClear()</code></pre>
<p>
Всё вместе это выглядит так:
</p>
<pre><code>h =&gt; {

if ($[${LEN(${HANGUPCAUSE_STRING})} = 0])
 goto stop;

NoOp(SIP cause:  ${HANGUPCAUSE(${HANGUPCAUSE_KEYS()},tech)});
NoOp(Ast cause:  ${HANGUPCAUSE(${HANGUPCAUSE_KEYS()},ast)});
NoOp(Hangupcause keys: ${HANGUPCAUSE_KEYS()});
Set(CDR(userfield)=${HANGUPCAUSE(${HANGUPCAUSE_KEYS()},tech)} | ${HANGUPCAUSE(${HANGUPCAUSE_KEYS()},ast)} |  ${HANGUPCAUSE_KEYS()});

stop:
 NoOp(HANGUPCAUSE is empty);
};</code></pre>
<p>
В дайлплане удачный звонок на номер 5500:
</p>
<pre><code>-- Channel SIP/CCM61-WC-00006071 left 'simple_bridge' basic-bridge &lt;5e218c7f-08e4-402b-a201-9fe95e43645c&gt;
    -- Channel SIP/AST-CC-ERT-2-00006070 left 'simple_bridge' basic-bridge &lt;5e218c7f-08e4-402b-a201-9fe95e43645c&gt;
  == Spawn extension (ERT-IN, 5500, 6) exited non-zero on 'SIP/AST-CC-ERT-2-00006070'
    -- Executing [h@ERT-IN:1] NoOp("SIP/AST-CC-ERT-2-00006070", "SIP cause:  SIP 200 OK") in new stack
    -- Executing [h@ERT-IN:2] NoOp("SIP/AST-CC-ERT-2-00006070", "Ast cause:  Normal Clearing") in new stack
    -- Executing [h@ERT-IN:3] NoOp("SIP/AST-CC-ERT-2-00006070", "Hangupcause keys: SIP/CCM61-WC-00006071") in new stack
    -- Executing [h@ERT-IN:4] Set("SIP/AST-CC-ERT-2-00006070", "CDR(userfield)=SIP 200 OK | Normal Clearing | SIP/CCM61-WC-00006071") in new stack</code></pre>
<p>
То есть в бридже у нас были каналы <code>SIP/CCM61-WC-00006071</code> и <code>SIP/AST-CC-ERT-2-00006070</code>, первым брижд покинул <code>Channel SIP/CCM61-WC-00006071</code>, то есть он является инициатором отбоя, но в переменной HANGUPCAUSE_KEYS() содержится только код отбоя второго канала <code>SIP/AST-CC-ERT-2-00006070</code>.
</p>
<p>
Теперь, посмотрим что содержит сама переменная:
</p>
<ul>
<li>
<div class="li"> Translated Asterisk cause code: Normal Clearing</div>
</li>
<li>
<div class="li"> Translated Asterisk cause code: SIP 200 OK </div>
</li>
</ul>
<p>
Если вызов состоялся, а переменная пустая, то значит ни один канал не содержал кода отбоя.
</p>
<p>
Возьмём звонок на сервис, то есть по сути с одним плечом SIP, в таком случае переменная <code>HANGUPCAUSE_KEYS()</code> будет пустая:
</p>
<pre><code>[Jan 22 18:17:15] WARNING[13817][C-0000306d]: func_hangupcause.c:140 hangupcause_read: Unable to find information for channel
    -- Executing [h@WC-IN:1] NoOp("SIP/CCM61-WC-0000608c", "SIP cause:  ") in new stack
[Jan 22 18:17:15] WARNING[13817][C-0000306d]: func_hangupcause.c:140 hangupcause_read: Unable to find information for channel
    -- Executing [h@WC-IN:2] NoOp("SIP/CCM61-WC-0000608c", "Ast cause:  ") in new stack
    -- Executing [h@WC-IN:3] NoOp("SIP/CCM61-WC-0000608c", "Hangup keys: ") in new stack
[Jan 22 18:17:15] WARNING[13817][C-0000306d]: func_hangupcause.c:140 hangupcause_read: Unable to find information for channel
[Jan 22 18:17:15] WARNING[13817][C-0000306d]: func_hangupcause.c:140 hangupcause_read: Unable to find information for channel
    -- Executing [h@WC-IN:4] Set("SIP/CCM61-WC-0000608c", "CDR(userfield)= |  |  ") in new stack</code></pre>
<p>
Вызов который завершился неудачей:
</p>
<pre><code>-- Got SIP response 503 "Service Unavailable" back from 10.101.1.7:5060
    -- SIP/ASTERISK-ERT-1-00006090 is circuit-busy
  == Everyone is busy/congested at this time (1:0/1/0)
    -- Executing [22000@WC-IN:7] NoOp("SIP/CCM61-WC-0000608f", "CONGESTION") in new stack
    -- Executing [22000@WC-IN:8] Goto("SIP/CCM61-WC-0000608f", "sw_378_CONGESTION,10") in new stack
    -- Goto (WC-IN,sw_378_CONGESTION,10)
    -- Executing [sw_378_CONGESTION@WC-IN:10] Hangup("SIP/CCM61-WC-0000608f", "") in new stack
  == Spawn extension (WC-IN, sw_378_CONGESTION, 10) exited non-zero on 'SIP/CCM61-WC-0000608f'
    -- Executing [h@WC-IN:1] NoOp("SIP/CCM61-WC-0000608f", "SIP cause:  SIP 503 Service Unavailable") in new stack
    -- Executing [h@WC-IN:2] NoOp("SIP/CCM61-WC-0000608f", "Ast cause:  Circuit/channel congestion") in new stack
    -- Executing [h@WC-IN:3] NoOp("SIP/CCM61-WC-0000608f", "Hangup keys: SIP/ASTERISK-ERT-1-00006090") in new stack
    -- Executing [h@WC-IN:4] Set("SIP/CCM61-WC-0000608f", "CDR(userfield)=SIP 503 Service Unavailable | Circuit/channel congestion | SIP/ASTERISK-ERT-1-00006090 ") in new stack</code></pre>
<p>
Посмотрим что содержит сама переменная:
</p>
<ul>
<li>
<div class="li"> Hangup keys: <code>SIP/ASTERISK-ERT-1-00006090</code></div>
</li>
<li>
<div class="li"> Translated Asterisk cause code: <code>Circuit/channel congestion</code></div>
</li>
<li>
<div class="li"> Translated Asterisk cause code: <code>SIP 503 Service Unavailable</code> </div>
</li>
</ul>
<p>Я заметил, что если lastapp в CDR != Hangup, а Dial, то поля в CDR которые я пытаюсь обновить CDR(userfield|dialstatus) не обновляются, вот пример с одним uniqueid и две записи:
</p>
<pre><code>mysql&gt; select * from  cdr where uniqueid=1548253072.2783;
+-----+---------------------+----------------------------+--------+-------------+----------+-----------------------+-----------------------------+---------+------------------------------+----------+---------+-------------+----------+-------------+-----------------+------------+--------------------------------------------------------------+
| id  | calldate            | clid                       | src    | dst         | dcontext | channel               | dstchannel                  | lastapp | lastdata                     | duration | billsec | disposition | amaflags | accountcode | uniqueid        | dialstatus | userfield                                                    |
+-----+---------------------+----------------------------+--------+-------------+----------+-----------------------+-----------------------------+---------+------------------------------+----------+---------+-------------+----------+-------------+-----------------+------------+--------------------------------------------------------------+
| 986 | 2019-01-23 17:17:52 | "Kudr Ignat" &lt;015166&gt; | 015166 | 12345       | WC-IN    | SIP/CCM61-WC-00000706 | SIP/ASTERISK-ERT-1-00000707 | Dial    | SIP/ASTERISK-ERT-1/12345,,tT |        4 |       0 | BUSY        |        3 |             | 1548253072.2783 |            |                                                              |
| 987 | 2019-01-23 17:17:56 | "Kudr Ignat" &lt;015166&gt; | 015166 | sw_525_BUSY | WC-IN    | SIP/CCM61-WC-00000706 |                             | Hangup  |                              |        0 |       0 | BUSY        |        3 |             | 1548253072.2783 |            | SIP 486 Busy Here | User busy |  SIP/ASTERISK-ERT-1-00000707 |
+-----+---------------------+----------------------------+--------+-------------+----------+-----------------------+-----------------------------+---------+------------------------------+----------+---------+-------------+----------+-------------+-----------------+------------+--------------------------------------------------------------+
2 rows in set (0.01 sec)</code></pre>
<p>
Это связано с тем, что вызов хоть и попал на h, но CDR не записался на диск.<br />
<a href="https://wiki.asterisk.org/wiki/pages/viewpage.action?pageId=20185363" class="urlextern" title="https://wiki.asterisk.org/wiki/pages/viewpage.action?pageId=20185363" rel="nofollow">Who Hung Up? Asterisk Wiki</a>
</p>
<p>
По ссылке описывается более сложный пример, в нём мы разбираем пременную HANGUPCAUSE_KEYS(), ведь он в теории может содержать больше имени одного канала, и тогда в моём примере попросту будет ошибка. Но у меня было максимум 1 переменная.
</p>
<p>
Приведу пример ниже:
</p>
<pre><code>[foo]
exten =&gt; s,1,Dial(SIP/bar)
 
exten =&gt; h,1,noop()
exten =&gt; h,n,set(HANGUPCAUSE_STRING=${HANGUPCAUSE_KEYS()})
; start loop
exten =&gt; h,n(hu_begin),noop()
 
; check exit condition (no more array to check)
exten =&gt; h,n,gotoif($[${LEN(${HANGUPCAUSE_STRING})} = 0]?hu_exit)
 
; pull the next item
exten =&gt; h,n,set(ARRAY(item)=${HANGUPCAUSE_STRING})
exten =&gt; h,n,set(HANGUPCAUSE_STRING=${HANGUPCAUSE_STRING:${LEN(${item})}})
 
; display the channel ID and cause code
exten =&gt; h,n,noop(got channel ID ${item} with pvt cause ${HANGUPCAUSE(${item},tech)})
 
; check exit condition (no more array to check)
exten =&gt; h,n,gotoif($[${LEN(${HANGUPCAUSE_STRING})} = 0]?hu_exit)
 
; we still have entries to process, so strip the leading comma
exten =&gt; h,n,set(HANGUPCAUSE_STRING=${HANGUPCAUSE_STRING:1})
; go back to the beginning of the loop
exten =&gt; h,n,goto(hu_begin)
exten =&gt; h,n(hu_exit),noop(All HANGUPCAUSE entries processed)</code></pre>
<p>
Можно создать свою таблицу CDR или содержащую иную информацию по вкусу и записывать в БД.<br />
В примере ниже, по результатам вызова, в таблицу Mysql c именем cdr_custom записываются нужные переменные CDR плюс коды отбоя, ниже приводится подробный пример.
</p>
<p>
Предпологается? что мы будем использовать ранее созданное MySQL ODBC соединение.<br />
Все поля, кроме dialstatus и REL будем брать из функции CDR().
</p>
<p>
Переменная REL формируется из функции HANGUPCAUSE:
</p>
<pre><code>Set(REL=${HANGUPCAUSE(${HANGUPCAUSE_KEYS()},tech)} | ${HANGUPCAUSE(${HANGUPCAUSE_KEYS()},ast)} |  ${HANGUPCAUSE_KEYS()});</code></pre>
<p>
Переменная <code>${DIALSTATUS}</code> также стандартная переменная.
</p>
<pre><code>${DIALSTATUS}: This is the status of the call
    CHANUNAVAIL
    CONGESTION
    NOANSWER
    BUSY
    ANSWER
    CANCEL
    DONTCALL: For the Privacy and Screening Modes. Will be set if the called
    party chooses to send the calling party to the 'Go Away' script.
    TORTURE: For the Privacy and Screening Modes. Will be set if the called
    party chooses to send the calling party to the 'torture' script.
    INVALIDARGS</code></pre>
<p>
Ниже строка дайлплана Asterisk:
</p>
<pre><code>NoOp(${CDR(uniqueid)},${CDR(start)},${CDR(clid)},${CDR(src)},${CDR(dst)},${CDR(dcontext)},${CDR(channel)},${CDR(dstchannel)},${CDR(duration)},${CDR(billsec)},${CDR(disposition)},${DIALSTATUS},${REL})</code></pre>
<p>
В консоли Asterisk строка выше с подставленными переменными будет выглядить так:
</p>
<pre><code>1548251202.2649,2019-01-23 16:46:42,"79210001122" &lt;79210001122&gt;,79210001122,600,WC-IN,SIP/CCM61-WC-000006aa,SIP/AST-CC-ERT-1-000006ab,409,409,ANSWERED,ANSWER,SIP 200 OK | Normal Clearing</code></pre>
<p>
Теперь все эти переменные нужно записать подготовленную для этих целей таблицу MySQL при помощи функции ODBC которая будет вызаться из дайлплана на экстеншене h.
</p>
<p>
Создадим новую таблицу cdr_custom в БД MySQL
</p>
<pre><code>mysql&gt; use ertx_ast_cdr;
mysql&gt; CREATE TABLE cdr_custom ( 
        id int(11) unsigned NOT NULL auto_increment PRIMARY KEY,
        uniqueid varchar(32) NOT NULL default '', 
        calldate datetime NOT NULL default '0000-00-00 00:00:00', 
        clid varchar(80) NOT NULL default '', 
        src varchar(80) NOT NULL default '', 
        dst varchar(80) NOT NULL default '', 
        dcontext varchar(80) NOT NULL default '', 
        channel varchar(80) NOT NULL default '', 
        dstchannel varchar(80) NOT NULL default '', 
        duration int(11) NOT NULL default '0', 
        billsec int(11) NOT NULL default '0', 
        disposition varchar(45) NOT NULL default '', 
        dialstatus varchar(17) NOT NULL default '' ,cause varchar(120) NOT NULL default '' );

mysql&gt; desc cdr_custom;
+-------------+------------------+------+-----+---------------------+----------------+
| Field       | Type             | Null | Key | Default             | Extra          |
+-------------+------------------+------+-----+---------------------+----------------+
| id          | int(11) unsigned | NO   | PRI | NULL                | auto_increment |
| uniqueid    | varchar(32)      | NO   |     |                     |                |
| calldate    | datetime         | NO   |     | 0000-00-00 00:00:00 |                |
| clid        | varchar(80)      | NO   |     |                     |                |
| src         | varchar(80)      | NO   |     |                     |                |
| dst         | varchar(80)      | NO   |     |                     |                |
| dcontext    | varchar(80)      | NO   |     |                     |                |
| channel     | varchar(80)      | NO   |     |                     |                |
| dstchannel  | varchar(80)      | NO   |     |                     |                |
| duration    | int(11)          | NO   |     | 0                   |                |
| billsec     | int(11)          | NO   |     | 0                   |                |
| disposition | varchar(45)      | NO   |     |                     |                |
| dialstatus  | varchar(17)      | NO   |     |                     |                |
| cause       | varchar(120)     | NO   |     |                     |                |
+-------------+------------------+------+-----+---------------------+----------------+
14 rows in set (0.00 sec)</code></pre>
<p>
Теперь создадим функцию в <code>/etc/asterisk/func_odbc.conf</code>
</p>
<pre><code>[INSERT_CUSTOM_CDR]
dsn=asterisk
writesql=INSERT INTO cdr_custom (uniqueid,calldate,clid,src,dst,dcontext,channel,dstchannel,duration,billsec,disposition,dialstatus,cause) VALUES ('${ARG1}','${ARG2}','${ARG3}','${ARG4}','${ARG5}','${ARG6}','${ARG7}','${ARG8}','${ARG9}','${ARG10}','${ARG11}','${ARG12}','${ARG13}')</code></pre>
<p>
Настала очередь dialplan.
</p>
<p>
Ловим вызова на специальном экстеншене h куда попадает вызов после заверешния:
</p>
<pre><code>&gt;h =&gt; {
Set(REL=${HANGUPCAUSE(${HANGUPCAUSE_KEYS()},tech)} | ${HANGUPCAUSE(${HANGUPCAUSE_KEYS()},ast)} |  ${HANGUPCAUSE_KEYS()});
Set(ODBC_INSERT_CUSTOM_CDR(${CDR(uniqueid)},${CDR(start)},${CDR(clid)},${CDR(src)},${CDR(dst)},${CDR(dcontext)},${CDR(channel)},${CDR(dstchannel)},${CDR(duration)},${CDR(billsec)},${CDR(disposition)},${DIALSTATUS},${REL})=);

{</code></pre>
<p>
Причём обращаю внимание, что для записи значений из dialplan в ODBC нужно использовать SET!!!
</p>
<p>
<strong>Если в дайлплане используется case</strong>
</p>
<p>
Тогда в CDR в столбце dst может быть вместо Б-номера может быть значение <code>sw_564_CHANUNAVAIL</code> или что-то похожее вместо Б-номера:
</p>
<pre><code>mysql&gt; select * from ertx_ast_cdr.cdr_custom where src in ('49000','015136') and calldate &gt;= '2019-03-06 09:00:00';
+-------+------------------+---------------------+---------------------------+--------+--------------------+----------+-----------------------+-----------------------------+----------+---------+-------------+------------+------------------------------------------------------------------+
| id    | uniqueid         | calldate            | clid                      | src    | dst                | dcontext | channel               | dstchannel                  | duration | billsec | disposition | dialstatus | cause                                                            |
+-------+------------------+---------------------+---------------------------+--------+--------------------+----------+-----------------------+-----------------------------+----------+---------+-------------+------------+------------------------------------------------------------------+
| 27633 | 1551942737.86893 | 2019-03-07 10:12:17 | Kudryavcev Ignat &lt;015136&gt; | 015136 | 450000              | WC-IN    | SIP/CCM61-WC-0000de97 | SIP/ASTERISK-ERT-1-0000de98 |        2 |       0 | NO ANSWER   | CANCEL     | SIP 180 Ringing | Normal Clearing |  SIP/ASTERISK-ERT-1-0000de98 |
| 27634 | 1551942783.86900 | 2019-03-07 10:13:03 | Kudryavcev Ignat &lt;015136&gt; | 015136 | sw_564_CHANUNAVAIL | WC-IN    | SIP/CCM61-WC-0000de9d |                             |        0 |       0 | CONGESTION  | CONGESTION |  |  |  SIP/ASTERISK-ERT-2-0000de9f                               |
| 27635 | 1551942795.86906 | 2019-03-07 10:13:15 | Kudryavcev Ignat &lt;015136&gt; | 015136 | 450000              | WC-IN    | SIP/CCM61-WC-0000dea0 | SIP/ASTERISK-ERT-1-0000dea1 |        2 |       0 | NO ANSWER   | CANCEL     | SIP 180 Ringing | Normal Clearing |  SIP/ASTERISK-ERT-1-0000dea1 |
| 27636 | 1551942821.86912 | 2019-03-07 10:13:41 | Kudryavcev Ignat &lt;015136&gt; | 015136 | sw_577_BUSY        | WC-IN    | SIP/CCM61-WC-0000dea5 |                             |        0 |       0 | BUSY        | BUSY       | SIP 486 Busy here | User busy |  SIP/ASTERISK-ERT-1-0000dea6     |</code></pre>
<p>
Ниже пример Dialplan в котором может возникнуть такая ситуация:
</p>
<pre><code>_[56]XX =&gt; {
            NoOp(Call from Westcall);
            //Set(CALLERID(num)=01${CALLERID(num)});
            Set(CALLERID(num)=${IF($[${LEN(${CALLERID(num)})} = 4]?01${CALLERID(num)}:${CALLERID(num)})});
            Verbose(!!! DEBUG Call from Westcall to ERTEL from ${CALLERID(num)} ${CALLERID(name)} --called-number-&gt; ${EXTEN} !!!);
            Verbose(!!! ${CALLERID(all)} !!!);
            Set(_REAL_DST=${EXTEN});
            Dial(SIP/${EXTEN}@AST-CC-ERT-1,,tT);
            //Dial(SIP/5136@10.10.10.10);
            NoOp(${DIALSTATUS});
            switch(${DIALSTATUS}) {
        case BUSY:
                  Hangup;
        case ANSWER:
                  Hangup;
        case NOANSWER:
                  Hangup;
        case CONGESTION:
                  Hangup;
        default:
                  Dial(SIP/${EXTEN}@AST-CC-ERT-2,,tT);
                  Hangup;</code></pre>
<p>
В данном примере, мы пытаемся перемаршрутизировать вызов на резервный сервер в зависимости от ответа основного.<br />
Поэтому сохраним набранный номер в переменную <code>Set(_REAL_DST=${EXTEN});</code>
</p>
<p>
Затем при сохранении CDR заменим сохранение dst как <code>${CDR(dst)}</code> на <code>${REAL_DST}</code>
</p>
<p>
На Asterisk перезагрузить func_odbc.so и dialplan (dialplan reload/ael reload)
</p>
<pre><code>voip-gate-aster*CLI&gt; module reload func_odbc.so
Module 'func_odbc.so' reloaded successfully.
    -- Reloading module 'func_odbc.so' (ODBC lookups)
  == Parsing '/etc/asterisk/func_odbc.conf': Found
  == Unregistered custom function ODBC_PRESENCE
  == Unregistered custom function ODBC_ANTIGF
  == Unregistered custom function ODBC_SQL
  == Registered custom function 'ODBC_SQL'
  == Registered custom function 'ODBC_ANTIGF'
  == Registered custom function 'ODBC_PRESENCE'
  == Registered custom function 'ODBC_INSERT_CUSTOM_CDR'
  
  voip-gate-aster*CLI&gt; odbc write ODBC_
ODBC_ANTIGF      ODBC_PRESENCE    ODBC_INSERT_CUSTOM_CDR  ODBC_SQL</code></pre>
<p>
Запустим в dialplan:
</p>
<pre><code>-- Executing [h@WC-IN:1] Set("SIP/CCM61-WC-000006fa", "REL=SIP 200 OK | Normal Clearing |  SIP/ASTERISK-ERT-1-000006fb") in new stack
    -- Executing [h@WC-IN:2] Set("SIP/CCM61-WC-000006fa", "ODBC_INSERT_CUSTOM_CDR(1548252647.2763,2019-01-23 17:10:47,"" &lt;015139&gt;,015139,450000,WC-IN,SIP/CCM61-WC-000006fa,SIP/ASTERISK-ERT-1-000006fb,1,1,ANSWERED,ANSWER,SIP 200 OK | Normal Clearing |  SIP/ASTERISK-ERT-1-000006fb)=") in new stack</code></pre>
<p>
В таблице CDR:
</p>
<pre><code>mysql&gt; select * from  cdr_custom  order by id desc limit 2;
+-----+-----------------+---------------------+---------------------------+-------------+-------+----------+---------------------------+-----------------------------+----------+---------+-------------+------------+-------------------------------------------------------------+
| id  | uniqueid        | calldate            | clid                      | src         | dst   | dcontext | channel                   | dstchannel                  | duration | billsec | disposition | dialstatus | cause                                                       |
+-----+-----------------+---------------------+---------------------------+-------------+-------+----------+---------------------------+-----------------------------+----------+---------+-------------+------------+-------------------------------------------------------------+
| 230 | 1548253896.2820 | 2019-01-23 17:31:36 | Kudr Ignat &lt;015040&gt;   | 015040      | 450000 | WC-IN    | SIP/CCM61-WC-0000071c     | SIP/ASTERISK-ERT-1-0000071d |       56 |      36 | ANSWERED    | ANSWER     | SIP 200 OK | Normal Clearing |  SIP/ASTERISK-ERT-1-0000071d |
| 229 | 1548253402.2799 | 2019-01-23 17:23:22 | 79053332211 &lt;79053332211&gt; | 79053332211 | 5500  | ERT-IN   | SIP/AST-CC-ERT-2-0000070e | SIP/CCM61-WC-0000070f       |      348 |     348 | ANSWERED    | ANSWER     | SIP 200 OK | Normal Clearing |  SIP/CCM61-WC-0000070f       |
+-----+-----------------+---------------------+---------------------------+-------------+-------+----------+---------------------------+-----------------------------+----------+---------+-------------+------------+-------------------------------------------------------------+
2 rows in set (0.00 sec)</code></pre>
<h3>Как в Asterisk узнать, какая из сторон была инициатором отбоя?</h3>
<p>Пример дайлплана:</p>
<pre><code>exten =&gt; _1XX,1,Set(HANGUPSIDE=originator)
exten =&gt; _1XX,2,Dial(SIP/${EXTEN},,g)
exten =&gt; _1XX,3,Set(HANGUPSIDE=terminator)
exten =&gt; _1XX,4,NoOp(${HANGUPSIDE})
exten =&gt; h,1,NoOp(${HANGUPSIDE})</code></pre>
<p>На первом шаге мы устанавливаем, что по умолчанию в переменной HANGUPSIDE оригинатор завершит вызов.<br />
На втором шаге мы отправляем вызов терминатору, но указываем, в приложении Dial опцию g.<br />
Что такое опция g описано в Help Asterisk:</p>
<pre><code>g: Proceed with dialplan execution at the next priority in the current
    extension if the destination channel hangs up.</code></pre>
<p>Без опций, приложение Dial, после отбоя любой из сторон передаёт вызов сразу же на экстеншен h текущего контекста, выполнение следующего шага дайлплана не происходит.<br />
Если поставить опцию g, то следующий шаг дайлплана после Dial будет выполняться если терминирующий канал первым завершил вызов, в данном случае установка переменной HANGUPSIDE равной terminator.<br />
Таким образом легко установить, какая сторона является инициатором завершения, что иногда может очень сильно помочь в диагностике проблем.</p>
<p>Автор: Игнат Кудрявцев</p><p>The post <a href="https://ucexpert.ru/archives/7386">Получение кодов отбоя SIP и стороны завершившей вызов в Asterisk</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Сравниваем конфигурации FreeSWITCH и Asterisk для одной задачи</title>
		<link>https://ucexpert.ru/archives/7377</link>
		
		<dc:creator><![CDATA[Игнат Кудрявцев]]></dc:creator>
		<pubDate>Wed, 27 Feb 2019 06:45:56 +0000</pubDate>
				<category><![CDATA[Техно]]></category>
		<category><![CDATA[Asterisk]]></category>
		<category><![CDATA[Freeswitch]]></category>
		<guid isPermaLink="false">http://www.ucexpert.ru/?p=7377</guid>

					<description><![CDATA[<p>Для чемпионата мира в России, который прошёл в 2018 году, нужно было решить задачу авторизации пользователей для услуги Wi-Fi при помощи звонка на телефонный номер как один из способов авторизации. Для решения использованы аналогичные конфигурации ...</p>
<p>The post <a href="https://ucexpert.ru/archives/7377">Сравниваем конфигурации FreeSWITCH и Asterisk для одной задачи</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Для чемпионата мира в России, который прошёл в 2018 году, нужно было решить задачу авторизации пользователей для услуги Wi-Fi при помощи звонка на телефонный номер как один из способов авторизации. Для решения использованы аналогичные конфигурации FreeSWITCH и Asterisk.</p>
<p><span id="more-7377"></span></p>
<p>Смысл в том, что пользователь вводит номер телефона своего смартфона\планшета\компьютера через веб-форму авторизации в Wi-Fi сети, далее, пользователь выбирает каким способом он подтвердит, что это действительно его мобильный номер: при помощи отправки SMS-сообщения или звонком на номер телефона, где ему должна проиграться голосовая подсказка о успешности\неуспешности авторизации, в зависимости от языка интерфейса (русский, английский, французский, немецкий или испанский). Голосовая платформа Asterisk\FreeSWITCH передаёт номер позвонившего серверу авторизации, сервер сверяет телефонный номер полученный через веб-форму с номером, который передала голосовая платформа, в ответ возвращается успешный или неуспешный код. Сообщение должно проигрываться в предответном состоянии до начала тарификации, чтобы абонент не платил деньги за звонок. Так как Asterisk и FreeSWITCH в этой схеме выполняют функции медиасерверов, будем называть далее их именно так.<br />
Терминация из телефонных сетей на медиасерверы работала через два транковых шлюза Eltex SMG1016M, голосовых платформ тоже две: первая Asterisk 15.3.0 установленный на ОС Linux Debian 9.4, вторая FreeSWITCH Version 1.6.20 установленная на ОС Linux Debian 8.10. В июне 2018 FreeSWITCH ещё не поддерживал ОС Linux Debian 9 для «продакшен» режима.<br />
Asterisk и FreeSWITCH запущены на виртуальных машинах, основные пики нагрузки приходились, когда начинались футбольные матчи.<br />
Главный минус схемы с такой авторизацией – иногда из телефонной сети общего пользования может приходить искажённый номер вызывающего абонента (А-номер), в таком случае пользователь не будет авторизован, хотя правильно указал свои данные. Данная ситуация была замечена у одного сотового оператора для парных номеров: федеральный номер плюс местный городской номер в которых равны последние 7 цифр номера.</p>
<p><strong>Техническая реализация</strong></p>
<p>Создан пул телефонных номеров равный количеству языков – 5, звонки на любой из 5 телефонных номеров по очереди попадает на шлюзы SMG1016: 192.168.25.8 и 192.168.25.9, на каждом из шлюзов созданы транковые направления терминации состоящие из двух транковых групп, по одной на медиасервер (Asterisk и FreeSWITCH), алгоритм работы направлений для терминации: последовательно вперёд.</p>
<p><div id="attachment_7358" style="width: 690px" class="wp-caption aligncenter"><a href="/wp-content/uploads/2019/02/Транковое-направление-SMG.png"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-7358" class="size-full wp-image-7358 no-frame" src="/wp-content/uploads/2019/02/Транковое-направление-SMG.png" alt="" width="680" height="159" srcset="https://ucexpert.ru/wp-content/uploads/2019/02/Транковое-направление-SMG.png 680w, https://ucexpert.ru/wp-content/uploads/2019/02/Транковое-направление-SMG-300x70.png 300w" sizes="auto, (max-width: 680px) 100vw, 680px" /></a><p id="caption-attachment-7358" class="wp-caption-text">Транковое направление SMG</p></div></p>
<p>Заметку по маршрутизации на шлюзах Элекс SMG можно найти по данной<a href="/archives/6495" target="_blank" rel="noopener"> ссылке</a>.<br />
Оба шлюза подключены к городской АТС, где также создана группа терминации с алгоритмом работы по очереди. Такая схема даёт равномерное распределение нагрузки по шлюзам и медиасерверам.<br />
Когда медиасервер получает вызов, он делает запрос по http на сервер авторизации куда в формате JSON передаёт номер телефонный позвонившего и телефонный номер для авторизации куда позвонил пользователь:</p>
<pre><code>data={'user_phone': user_phone,'gw_phone': gw_phone}</code></pre>
<p>В ответ сервер передаёт код ответа и результат в формате:</p>
<pre><code>resultCode=1&amp;resultMessage=accepted</code></pre>
<p>Если,<br />
<b></b></p>
<ul>
<li><em>resultCode = 1</em> – проиграть подсказку об успешной авторизации</li>
<li>Любой другой код – проиграть сообщение об ошибке</li>
</ul>
<p>В статье я не буду касаться вопросов инсталляции Asterisk и FreeSWITCH, рассмотрю только необходимую конфигурацию внешнего канала SIP и дайлплана, также скриптов которые делают запрос по http и возвращают результат.</p>
<p><strong>Медиасервер Asterisk</strong></p>
<p><em>IP-адрес=192.168.25.32</em></p>
<p>Здесь из дайлплана при помощи AGI вызываем внешний скрипт, который сделает запрос на сервер и вернёт результат.</p>
<p>Настройка внешних каналов SIP для приёма трафика от шлюзов<b>,</b> файл <em>/etc/asterisk/sip.conf</em></p>
<pre><code>[FIFA-1]
type=peer
context=FIFA-IN
host=192.168.25.8 ;Шлюз 1 SMG1016M
insecure=port,invite
disallow=all
allow=ulaw
nat=no
canreinvite=no
use_q850_reason = yes

[FIFA-2]
type=peer
context=FIFA-IN
host=192.168.25.9 ;Шлюз 2 SMG1016M
insecure=port,invite
disallow=all
allow=ulaw
nat=no
canreinvite=no
use_q850_reason = yes</code></pre>
<p>Здесь вызовы с любого из двух шлюзов отправляются в контекст FIFA-IN.<br />
Дайлплан Asterisk, файл<em> /etc/asterisk/extensions.ael</em><br />
Приведу только первые два номера, напомню, что всего языков подсказок 5 и номеров столько же, соответственно.</p>
<pre><code>context FIFA-IN
{
78120002915 =&gt; {
        AGI(get-res.py,${CALLERID(num)},${EXTEN:1});
Set(CDR(userfield)=${ANSWER});
NoOp(RES =&gt; ${RES});
        switch (${RES}) {
                    case 1:
                    Progress();
                    Playback(/var/lib/asterisk/sounds/fifa/success_readyRUS1,noanswer);
                    Busy(10);
                    Hangup(16);
                  default:
                    Progress();
                    Playback(/var/lib/asterisk/sounds/fifa/Fail_RUS1,noanswer);
                    //Playback(/var/lib/asterisk/sounds/ru/agent-alreadyon,noanswer);
                    Busy(10);
                    Hangup(16);

                };
        };

78120002916 =&gt; {                                                                //English
        AGI(get-res.py,${CALLERID(num)},${EXTEN:1});
Set(CDR(userfield)=${ANSWER});
NoOp(RES =&gt; ${RES});
        switch (${RES}) {
                    case 1:
                    Progress();
                    Playback(/var/lib/asterisk/sounds/fifa/Success_readyEN1,noanswer);
                    Busy(10);
                    Hangup(16);
                  default:
                    Progress();
                    Playback(/var/lib/asterisk/sounds/fifa/Fail_EN1,noanswer);
                    //Playback(/var/lib/asterisk/sounds/ru/agent-alreadyon,noanswer);
                    Busy(10);
                    Hangup(16);

                };
        };

};</code></pre>
<p>Любой вызов, пришедший со шлюзов 192.168.25.8 и 192.168.25.9 попадает в контекст FIFA-IN дайлплана Asterisk, здесь, в зависимости от одного из пяти набранных номеров, вызов попадает на нужный экстеншен, например, 78120002916, при помощи приложения AGI вызывается внешний скрипт из директории по умолчанию<em> /var/lib/asterisk/agi-bin</em>. Результат работы скрипта передаётся оператору выбора case, далее, приложение <em>Progress()</em> указывает Asterisk что не нужно посылать SIP <em>200OK</em>, что равно соединению и началу тарификации, а проиграть голосовое сообщение в режиме предответа (<em>early media</em>) с помощью приложения Playback, затем послать сигнал занято — <em>Busy(10)</em> и повесить трубку <em>Hangup</em>. Аудиофайлы, которые нужно проиграть загружаются в <em>/var/lib/asterisk/sounds/ru/</em>.<br />
Для контроля содержимого ответа в CDR Asterisk добавим содержимое переменной <em>ANSWER</em> при помощи приложения <em>Set</em>,<br />
<em>Set(CDR(userfield)=${ANSWER});</em><br />
Далее, в примере CDR содержимое полученного значения переменной будет продемонстрировано.<br />
Ниже два примера скрипта написанные на bash и Python3, скрипты передают номера и возвращают в дайлплан результат.<br />
#cat /var/lib/asterisk/agi-bin/get-res.sh</p>
<pre><code>#!/bin/bash

res=`curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d"user_phone=$1&amp;gw_phone=$2" http://wfff-loginpage:8008/ivr_auth| sed -n 's/^.*resultCode=\([^&amp;]*\).*$/\1/p' | sed "s/%20/ /g"`

echo $res
echo -e "SET VARIABLE RES $res";
sleep 0
exit 0</code></pre>
<p>Здесь я использовал консольную утилиту curl для http запроса на сервер авторизации. Кстати, последняя строчка <em>exit 0</em>, иначе в консоли Asterisk будут появляться ошибки результаты работы AGI-скрипта.<br />
Ниже аналогичный скрипт на языке Python3, который я использовал в &#171;боевой&#187; конфигурации.</p>
<pre><code>#!/usr/bin/env python3

import requests
from sys import argv
user_phone,gw_phone = argv[1:]
answer = requests.post('http://wfff-loginpage:8008/ivr_auth',headers={'Content-Type': 'application/x-www-form-urlencoded'},data={'user_phone': user_phone,'gw_phone': gw_phone})
#res='resultCode=0&amp;resultMessage=rejected'
answer=str(answer.content)
print("SET VARIABLE RES %s" % answer[13] +"\n"+"SET VARIABLE ANSWER %s" % answer)</code></pre>
<p>Здесь я использовал отличный модуль для http запросов <em>requests</em>. На этом настройка Asterisk закончена.</p>
<p>В CDR вызовы будут выглядить так:</p>
<pre><code>"","+00000637658","sw_5_0","FIFA-IN",""""" &lt;+00000637658&gt;","SIP/FIFA-1-000034c0","","Busy","10","2018-07-15 18:54:34",,"2018-07-15 18:54:41",7,0,"BUSY","DOCUMENTATION","1531670074.27007","b'resultCode=0&amp;resultMessage=rejected'"

"","79060003159","sw_4_1","FIFA-IN",""""" &lt;79060003159&gt;","SIP/FIFA-2-000034c1","","Busy","10","2018-07-15 18:55:22",,"2018-07-15 18:55:31",8,0,"BUSY","DOCUMENTATION","1531670122.27010","b'resultCode=1&amp;resultMessage=accepted'"</code></pre>
<p>По мониторингу Asterisk использую следующие основные параметры, ниже пример конфигурации для Zabbix файл<em> /etc/zabbix/zabbix_agentd.conf</em> в <em>UserParameter</em>:</p>
<pre><code>### Option: UserParameter
#Текущие вызовы
UserParameter=asterisk.core.show.calls,/usr/bin/sudo /usr/sbin/asterisk -rx 'core show calls' | grep active| awk '{print $1}'
#Текущие каналы SIP
UserParameter=asterisk.sip.show.channels,/usr/bin/sudo /usr/sbin/asterisk -rx 'sip show channels' | grep "active SIP dialog" | awk '{print $1}'
#Обработанные звонки, накопительный счётчик
UserParameter=asterisk.sip.show.calls.processed,/usr/bin/sudo /usr/sbin/asterisk -rx 'core show calls' | grep processed | awk '{print $1}'</code></pre>
<p><b>Медиасервер FreeSWITCH</b></p>
<p><em>IP-адрес=192.168.25.32</em><br />
У FreeSWITCH есть встроенный модуль curl.<br />
Нам надо добавить модуль <em>mod_curl</em> поэтому, при компиляции снимаем комментарий с требуемых модулей в<br />
<em>/usr/src/freeswitch/modules.conf</em></p>
<pre><code>languages/mod_python
applications/mod_curl</code></pre>
<p>Сохраняем. Запускаем конфигурирование, сборку и инсталляцию ещё раз:</p>
<pre><code>./configure
make
make install</code></pre>
<p>Теперь в конфигурационных файлах FreeSWITCH <em>/usr/local/freeswitch/conf/autoload_configs/modules.conf.xml</em>, удаляем комментарии:</p>
<pre><code>&lt;load module="mod_curl"/&gt;
&lt;load module="mod_python"/&gt;</code></pre>
<p>Проверим что модуль есть:</p>
<pre><code>#fs_cli
$fs_cli
freeswitch@FS1.6&gt; module_exists mod_python
true
freeswitch@FS1.6&gt; module_exists mod_curl
true</code></pre>
<p>В файле <em>/freeswitch/conf/autoload_configs/switch.conf.xml</em> можно увеличить следующие параметры:</p>
<pre><code>&lt;param name="max-sessions" value="1000"/&gt;
    &lt;!--Most channels to create per second --&gt;
    &lt;param name="sessions-per-second" value="30"/&gt;
    &lt;!-- Default Global Log Level - value is one of debug,info,notice,warning,err,crit,alert --&gt;
    &lt;param name="loglevel" value="debug"/&gt;</code></pre>
<p>Внешние каналы SIP, добавим новый профиль:</p>
<pre><code>#touch /freeswitch/conf/sip_profiles/fifa.xml</code></pre>
<p>Добавим в файл следующие строки:</p>
<pre><code>&lt;settings&gt;
    &lt;param name="debug" value="0"/&gt;
    &lt;param name="sip-trace" value="no"/&gt;
    &lt;param name="sip-capture" value="no"/&gt;
    &lt;param name="rfc2833-pt" value="101"/&gt;
    &lt;param name="sip-port" value="$${external_sip_port}"/&gt;
    &lt;param name="dialplan" value="XML"/&gt;
    &lt;param name="context" value="fifa"/&gt;
    &lt;param name="dtmf-duration" value="2000"/&gt;
    &lt;param name="inbound-codec-prefs" value="$${global_codec_prefs}"/&gt;
    &lt;param name="outbound-codec-prefs" value="$${outbound_codec_prefs}"/&gt;
    &lt;param name="hold-music" value="$${hold_music}"/&gt;
    &lt;param name="rtp-timer-name" value="soft"/&gt;
    &lt;param name="local-network-acl" value="localnet.auto"/&gt;
    &lt;param name="manage-presence" value="false"/&gt;
  &lt;param name="rtp-ip" value="192.168.25.32"/&gt;
    &lt;param name="sip-ip" value="192.168.25.32"/&gt;
  &lt;/settings&gt;</code></pre>
<p>Значение <em>$${external_sip_port}</em> это глобальный параметр, его значение указано в /freeswitch/conf/vars.xml, и выглядит так: <em>external_sip_port=5080.</em></p>
<p>Запустим наш новый профиль:</p>
<pre><code>freeswitch@wfff-media2&gt; sofia profile fifa start
Reload XML [Success]
fifa started successfully</code></pre>
<p>В консоли Linux, проверим, что IP и порт прослушивает FreeSWITCH:</p>
<pre><code>root@wfff-media2:/freeswitch/conf/sip_profiles# netstat -anp | grep 5080
tcp        0      0 192.168.25.32:5080      0.0.0.0:*               LISTEN      5499/freeswitch
udp        0      0 192.168.25.32:5080      0.0.0.0:*                           5499/freeswitch</code></pre>
<p>Теперь переходим к настройке дайлплана, файл <em>/freeswitch/conf/dialplan/fifa.xml</em>:</p>
<pre><code>&lt;include&gt;
  &lt;context name="fifa"&gt;
&lt;extension name="FIFA_NUM_POOL" continue="true"&gt;
    &lt;condition field="destination_number" expression="^(.*)$"&gt;
            &lt;action application="curl" data="http://wfff-loginpage:8008/ivr_auth content-type 'application/x-www-form-urlencoded' post user_phone=${caller_id_number}&amp;gw_phone=${destination_number:1}" inline="true"/&gt;
            &lt;!--action application="set" data="answer=resultCode=0&amp;resultMessage=rejected"/--&gt;
            &lt;!--action application="set" data="respdata=${curl_response_data}"/--&gt;
            &lt;action application="set" data="result=${curl_response_data:11:1}" inline="true"/&gt;
            &lt;action application="log" data="INFO result is ${result}" inline="true"/&gt;
    &lt;/condition&gt;
    &lt;condition field="destination_number" expression="^78120002915$" break="on-true"&gt;   &lt;!-- Russian --&gt;
        &lt;action application="log" data="ANI NUMBER IS ${ani} "/&gt;
        &lt;action application="log" data="78120002915 WARNING RESULT IS ${result} "/&gt;
        &lt;action application="pre_answer"/&gt;
        &lt;action application="playback" data="${cond(${result} == 1 ? /usr/local/freeswitch/sounds/fifa/success_readyRUS1.wav : /usr/local/freeswitch/sounds/fifa/Fail_RUS1.wav)}"/&gt;
        &lt;action application="sleep" data="3000"/&gt;
        &lt;action application="hangup" data="USER_BUSY"/&gt;
    &lt;/condition&gt;
        &lt;condition field="destination_number" expression="^78120002916$" break="on-true"&gt; &lt;!-- English --&gt;
        &lt;action application="log" data="RESULT IS ${result} "/&gt;
        &lt;action application="pre_answer"/&gt;
        &lt;action application="playback" data="${cond(${result} == 1 ? /usr/local/freeswitch/sounds/fifa/Success_readyEN1.wav : /usr/local/freeswitch/sounds/fifa/Fail_EN1.wav"/&gt;
        &lt;action application="hangup" data="USER_BUSY"/&gt;
    &lt;/condition&gt;
 &lt;/context&gt;
 &lt;/include&gt;</code></pre>
<p>Затем перезагружаем дайлплан:</p>
<pre><code>freeswitch@wfff-media2&gt; reloadxml
+OK [Success]

2019-02-22 13:32:23.277861 [INFO] mod_enum.c:879 ENUM Reloaded
2019-02-22 13:32:23.277861 [INFO] switch_time.c:1423 Timezone reloaded 1750 definitions</code></pre>
<p>Всё, на этом настройка закончена.</p>
<p><em>Что происходит в дайлплан?</em></p>
<p>В модуль SIP медиасервера FreeSWITCH (использует Sofia) приходит вызов, в соответствии с созданным sip профилем FIFA вызов направляется в контекст fifa для обработки.<br />
Контекст fifa содержит единственный эктеншен с именем FIFA_NUM_POOL. В первое условие (condition) содержит правило</p>
<pre><code>&lt;condition field="destination_number" expression="^(.*)$"&gt;</code></pre>
<p>Поэтому туда попадает любой позвонивший пользователь. Начинается первая фаза <em>ROUTING</em> – формирования найденного по совпавшим в условиям списка действий (actions) <em>TODO</em>. Значение <em>break</em> в первом условии (condition) отсутствует, это равно <em>break=”on-false”</em>, то есть<br />
не проверять следующее условие condition, если это условие ложно, но оно всегда в нашем случае истинно. Далее, проверяются остальные условия conditions которые содержат 5 номеров, соответствующих языку, на котором воспроизводятся голосовые подсказки, в примере я показываю только два номера 78120002915 и 78120002916. Когда условие по номеру позвонившего или <em>destination_number</em> совпадает с набранным пользователем номером, срабатывает директива <em>break=&#187;on-true&#187;</em>, что значит прервать просмотр условий (condition) и запустить те условия, которые совпали. То есть первое и второе, одно из пяти. Причём условия как бы стекируются и связаны межу собой оператором <em>И (AND)</em>.<br />
Список на выполнение или <em>TODO</em> список действии (action) составлен, начинается фаза выполнения <em>State EXECUTE.</em><br />
Запускается первое приложение<em> curl</em>:</p>
<pre><code>&lt;action application="curl" data="http://wfff-loginpage:8008/ivr_auth content-type 'application/x-www-form-urlencoded' post user_phone=${caller_id_number}&amp;gw_phone=${destination_number:1}"/&gt;</code></pre>
<p>Мы отправляем сообщение <em>POST</em> в формате <em>JSON</em> номер звонящего и номер телефона на который позвонили, при этому удаляем первую цифру номера.<br />
В ответ получаем ответ, наподобие</p>
<pre><code>resultCode=1&amp;resultMessage=accepted</code></pre>
<p>Приложение curl возвращает результа в стандартную переменную <em>curl_response_data</em><br />
Так как интересующее нас значение находится в 11 символе, извлечём её при помощи конструкции</p>
<pre><code>&lt;action application="set" data="result=${curl_response_data:11:1}" inline="true"/&gt;</code></pre>
<p>и присвоим переменной <em>result</em>.<br />
Здесь запускается приложение curl, которое проверяет телефонный номер и возвращает результат в переменную ${result}. Далее, выполняются действия из второго найденного условия, во-первых</p>
<pre><code>&lt;action application="pre_answer"/&gt;</code></pre>
<p>означает что мы будем проигрывать сообщение в предответном состоянии, без начала тарификации.<br />
Следующее действие:</p>
<pre><code>&lt;action application="playback" data="${cond(${result} == 1 ? /usr/local/freeswitch/sounds/fifa/success_readyRUS1.wav : /usr/local/freeswitch/sounds/fifa/Fail_RUS1.wav)}"/&gt;</code></pre>
<p>Тут мы воспроизводим файл success_readyRUS1.wav, если значение переменной<em> ${result}=1</em> или файл <em>Fail_RUS1.wav</em> в противном случае.<br />
Сследующие действия:</p>
<pre><code>&lt;action application="sleep" data="3000"/&gt;
        &lt;action application="hangup" data="USER_BUSY"/&gt;</code></pre>
<p>Ждём 3000 миллисекунд и запускаем приложение «отбой» с кодом <em>USER_BUSY</em> или <em>SIP 486</em>.<br />
Результат в <em>CDR FreeSWITCH</em> представлен ниже.<br />
Если абонент авторизован:</p>
<pre><code>"70002783772","70002783772","78120002915","fifa","2018-07-17 13:40:58","","2018-07-17 13:41:05","7","0","ORIGINATOR_CANCEL","c6337123-7a94-4ba2-96ee-17d00d2e460b","","","PCMA","PCMA","resultCode=1&amp;resultMessage=accepted"</code></pre>
<p>Если абоненту отказано в авторизации:</p>
<pre><code>"70002254963","70002254963","78120002918","fifa","2018-07-17 17:13:23","","2018-07-17 17:13:34","11","0","USER_BUSY","854529fc-62c6-479a-8c10-4c639fa624d9","","","PCMA","PCMA","resultCode=0&amp;resultMessage=rejected"</code></pre>
<p>Как видно, в cdr отображается содержимое переменной<em> ${curl_response_data}</em></p>
<p>Чтобы добавить её в CDR, нужно сделать следующее:</p>
<p>Открыть на редактирование файл <em>/usr/local/freeswitch/conf/autoload_configs/cdr_csv.conf.xml</em>, далее, смотрим какой используется темплейт для CDR:</p>
<pre><code>&lt;param name=«default-template» value=«example»/&gt;</code></pre>
<p>Затем, в</p>
<pre><code>&lt;template name=«example»&gt;</code></pre>
<p>добавляем в конце по образцу &#171;<em>${curl_response_data}</em>&#187;<br />
Получится:</p>
<pre><code>&lt;template name="example"&gt;"${caller_id_name}","${caller_id_number}","${destination_number}","${context}","${start_stamp}","${answer_stamp}","${end_stamp}","${duration}","${billsec}","${hangup_cause}","${uuid}","${bleg_uuid}","${accountcode}","${read_codec}","${write_codec}","${curl_response_data}"&lt;/template&gt;</code></pre>
<p>Сохраняем.</p>
<p>Затем делаем перезагрузку модуля из <em>fs_cli</em></p>
<pre><code>freeswitch@debian8&gt; reload mod_cdr_csv</code></pre>
<p>Ниже лог примера выполнения дайлплана FreeSWITCH.</p>
<pre><code>====Вызов пришёл в модуль Sofia SIP====

2019-02-22 17:38:40.497865 [NOTICE] switch_channel.c:1104 New Channel sofia/fifa/79500090900@192.168.25.9 [dac48249-f16f-4026-b176-d29d0719b8dc]
2019-02-22 17:38:40.497865 [DEBUG] switch_core_state_machine.c:584 (sofia/fifa/79500090900@192.168.25.9) Running State Change CS_NEW (Cur 1 Tot 13675)
2019-02-22 17:38:40.497865 [DEBUG] sofia.c:9873 sofia/fifa/79500090900@192.168.25.9 receiving invite from 192.168.25.9:5060 version: 1.6.20 git 43a9feb 2018-05-07 18:56:11Z 64bit
2019-02-22 17:38:40.497865 [DEBUG] sofia.c:7084 Channel sofia/fifa/79500090900@192.168.25.9 entering state [received][100]
2019-02-22 17:38:40.497865 [DEBUG] sofia.c:7094 Remote SDP:
v=0
o=- 1060 847210 IN IP4 192.168.25.9
s=SMG SIP session
c=IN IP4 192.168.25.9
t=0 0
m=audio 25862 RTP/AVP 8 0
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=ptime:20

2019-02-22 17:38:40.497865 [DEBUG] sofia.c:7486 (sofia/fifa/79500090900@192.168.25.9) State Change CS_NEW -&gt; CS_INIT
2019-02-22 17:38:40.497865 [DEBUG] switch_core_state_machine.c:603 (sofia/fifa/79500090900@192.168.25.9) State NEW
2019-02-22 17:38:40.497865 [DEBUG] switch_core_state_machine.c:584 (sofia/fifa/79500090900@192.168.25.9) Running State Change CS_INIT (Cur 1 Tot 13675)
2019-02-22 17:38:40.497865 [DEBUG] switch_core_state_machine.c:627 (sofia/fifa/79500090900@192.168.25.9) State INIT
2019-02-22 17:38:40.497865 [DEBUG] mod_sofia.c:90 sofia/fifa/79500090900@192.168.25.9 SOFIA INIT
2019-02-22 17:38:40.497865 [DEBUG] switch_core_state_machine.c:40 sofia/fifa/79500090900@192.168.25.9 Standard INIT
2019-02-22 17:38:40.497865 [DEBUG] switch_core_state_machine.c:48 (sofia/fifa/79500090900@192.168.25.9) State Change CS_INIT -&gt; CS_ROUTING
2019-02-22 17:38:40.497865 [DEBUG] switch_core_state_machine.c:627 (sofia/fifa/79500090900@192.168.25.9) State INIT going to sleep
2019-02-22 17:38:40.517818 [DEBUG] switch_core_state_machine.c:584 (sofia/fifa/79500090900@192.168.25.9) Running State Change CS_ROUTING (Cur 1 Tot 13675)
2019-02-22 17:38:40.517818 [DEBUG] switch_channel.c:2249 (sofia/fifa/79500090900@192.168.25.9) Callstate Change DOWN -&gt; RINGING
2019-02-22 17:38:40.517818 [DEBUG] switch_core_state_machine.c:643 (sofia/fifa/79500090900@192.168.25.9) State ROUTING
2019-02-22 17:38:40.517818 [DEBUG] mod_sofia.c:143 sofia/fifa/79500090900@192.168.25.9 SOFIA ROUTING
2019-02-22 17:38:40.517818 [DEBUG] switch_core_state_machine.c:236 sofia/fifa/79500090900@192.168.25.9 Standard ROUTING
2019-02-22 17:38:40.517818 [INFO] mod_dialplan_xml.c:637 Processing 79500090900 &lt;79500090900&gt;-&gt;78120002915 in context fifa

=== Вызов ушёл в контекст fifa =====

Dialplan: sofia/fifa/79500090900@192.168.25.9 parsing [fifa-&gt;FIFA_NUM_POOL] continue=false
Dialplan: sofia/fifa/79500090900@192.168.25.9 Regex (PASS) [FIFA_NUM_POOL] destination_number(78120002915) =~ /^(.*)$/ break=on-false

===Условие сработало, добавить действия в этом условии в TODO список, фаза 1 ===

Dialplan: sofia/fifa/79500090900@192.168.25.9 Action curl(http://wfff-loginpage:8008/ivr_auth content-type 'application/x-www-form-urlencoded' post user_phone=${caller_id_number}&amp;gw_phone=${destination_number:1})
Dialplan: sofia/fifa/79500090900@192.168.25.9 Action set(result=${curl_response_data:11:1})
Dialplan: sofia/fifa/79500090900@192.168.25.9 Action log(INFO result is ${result})
Dialplan: sofia/fifa/79500090900@192.168.25.9 Regex (FAIL) [FIFA_NUM_POOL] ani(79500090900) =~ /^71110007780$/ break=on-true
Dialplan: sofia/fifa/79500090900@192.168.25.9 Regex (PASS) [FIFA_NUM_POOL] destination_number(78120002915) =~ /^78120002915$/ break=on-true

===Условие destination_number(78120002915)  сработало, добавить действия в этом условии в TODO список, другие условия проверяться не будут так как установлено break=on-true ===

Dialplan: sofia/fifa/79500090900@192.168.25.9 Action log(ANI NUMBER IS ${ani} )
Dialplan: sofia/fifa/79500090900@192.168.25.9 Action log(78120002915 WARNING RESULT IS ${result} )
Dialplan: sofia/fifa/79500090900@192.168.25.9 Action pre_answer()
Dialplan: sofia/fifa/79500090900@192.168.25.9 Action playback(${cond(${result} == 1 ?  /usr/local/freeswitch/sounds/fifa/success_readyRUS1.wav : /usr/local/freeswitch/sounds/fifa/Fail_RUS1.wav)})
Dialplan: sofia/fifa/79500090900@192.168.25.9 Action sleep(3000)
Dialplan: sofia/fifa/79500090900@192.168.25.9 Action hangup(USER_BUSY)
2019-02-22 17:38:40.517818 [DEBUG] switch_core_state_machine.c:286 (sofia/fifa/79500090900@192.168.25.9) State Change CS_ROUTING -&gt; CS_EXECUTE
2019-02-22 17:38:40.517818 [DEBUG] switch_core_state_machine.c:643 (sofia/fifa/79500090900@192.168.25.9) State ROUTING going to sleep
2019-02-22 17:38:40.517818 [DEBUG] switch_core_state_machine.c:584 (sofia/fifa/79500090900@192.168.25.9) Running State Change CS_EXECUTE (Cur 1 Tot 13675)
2019-02-22 17:38:40.517818 [DEBUG] switch_core_state_machine.c:650 (sofia/fifa/79500090900@192.168.25.9) State EXECUTE
2019-02-22 17:38:40.517818 [DEBUG] mod_sofia.c:198 sofia/fifa/79500090900@192.168.25.9 SOFIA EXECUTE
2019-02-22 17:38:40.517818 [DEBUG] switch_core_state_machine.c:328 sofia/fifa/79500090900@192.168.25.9 Standard EXECUTE

====Начало запуска условии в состоянии EXECUTE, фаза 2. Выполняются действия из совпавших условий.

EXECUTE sofia/fifa/79500090900@192.168.25.9 curl(http://wfff-loginpage:8008/ivr_auth content-type 'application/x-www-form-urlencoded' post user_phone=79500090900&amp;gw_phone=8120002915)
2019-02-22 17:38:40.517818 [DEBUG] mod_curl.c:182 method: post, url: http://wfff-loginpage:8008/ivr_auth, content-type: application/x-www-form-urlencoded
2019-02-22 17:38:40.517818 [DEBUG] mod_curl.c:211 Post data: user_phone=79500090900&amp;gw_phone=8120002915
EXECUTE sofia/fifa/79500090900@192.168.25.9 set(result=0)

=== От curl получен результат 0 ===

2019-02-22 17:38:40.557875 [DEBUG] mod_dptools.c:1548 SET sofia/fifa/79500090900@192.168.25.9 [result]=[0]
EXECUTE sofia/fifa/79500090900@192.168.25.9 log(INFO result is 0)
2019-02-22 17:38:40.557875 [INFO] mod_dptools.c:1742 result is 0
EXECUTE sofia/fifa/79500090900@192.168.25.9 log(ANI NUMBER IS 79500090900 )
2019-02-22 17:38:40.557875 [DEBUG] mod_dptools.c:1742 NUMBER IS 79500090900
EXECUTE sofia/fifa/79500090900@192.168.25.9 log(78120002915 WARNING RESULT IS 0 )
EXECUTE sofia/fifa/79500090900@192.168.25.9 pre_answer()

=== Состояние предответа ===

2019-02-22 17:38:40.557875 [INFO] mod_dptools.c:1355 Sending early media
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [PCMA:8:8000:20:64000:1]/[opus:116:48000:20:0:1]
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [PCMA:8:8000:20:64000:1]/[G722:9:8000:20:64000:1]
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [PCMA:8:8000:20:64000:1]/[PCMU:0:8000:20:64000:1]
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [PCMA:8:8000:20:64000:1]/[PCMA:8:8000:20:64000:1]
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4504 Audio Codec Compare [PCMA:8:8000:20:64000:1] ++++ is saved as a match
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [PCMU:0:8000:20:64000:1]/[opus:116:48000:20:0:1]
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [PCMU:0:8000:20:64000:1]/[G722:9:8000:20:64000:1]
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [PCMU:0:8000:20:64000:1]/[PCMU:0:8000:20:64000:1]
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4504 Audio Codec Compare [PCMU:0:8000:20:64000:1] ++++ is saved as a match
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [PCMU:0:8000:20:64000:1]/[PCMA:8:8000:20:64000:1]
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:3061 Set Codec sofia/fifa/79500090900@192.168.25.9 PCMA/8000 20 ms 160 samples 64000 bits 1 channels
2019-02-22 17:38:40.557875 [DEBUG] switch_core_codec.c:111 sofia/fifa/79500090900@192.168.25.9 Original read codec set to PCMA:8
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4738 No 2833 in SDP. Liberal DTMF mode adding 101 as telephone-event.
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:4767 sofia/fifa/79500090900@192.168.25.9 Set 2833 dtmf send payload to 101 recv payload to 101
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:6878 AUDIO RTP [sofia/fifa/79500090900@192.168.25.9] 192.168.25.32 port 16452 -&gt; 192.168.25.9 port 25862 codec: 8 ms: 20
2019-02-22 17:38:40.557875 [DEBUG] switch_rtp.c:4137 Starting timer [soft] 160 bytes per 20ms
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:7180 sofia/fifa/79500090900@192.168.25.9 Set 2833 dtmf send payload to 101
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:7187 sofia/fifa/79500090900@192.168.25.9 Set 2833 dtmf receive payload to 101
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:7210 sofia/fifa/79500090900@192.168.25.9 Set rtp dtmf delay to 40
2019-02-22 17:38:40.557875 [NOTICE] sofia_media.c:92 Pre-Answer sofia/fifa/79500090900@192.168.25.9!
2019-02-22 17:38:40.557875 [DEBUG] switch_channel.c:3474 (sofia/fifa/79500090900@192.168.25.9) Callstate Change RINGING -&gt; EARLY
2019-02-22 17:38:40.557875 [DEBUG] switch_core_media.c:6861 Audio params are unchanged for sofia/fifa/79500090900@192.168.25.9.
2019-02-22 17:38:40.557875 [DEBUG] mod_sofia.c:2364 Ring SDP:
v=0
o=FreeSWITCH 1550829868 1550829869 IN IP4 192.168.25.32
s=FreeSWITCH
c=IN IP4 192.168.25.32
t=0 0
m=audio 16452 RTP/AVP 8 101
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=ptime:20
a=sendrecv

=== Начало проигрывания звукового файла Fail_RUS1.wav ===

EXECUTE sofia/fifa/79500090900@192.168.25.9 playback(/usr/local/freeswitch/sounds/fifa/Fail_RUS1.wav)
2019-02-22 17:38:40.557875 [DEBUG] sofia.c:7084 Channel sofia/fifa/79500090900@192.168.25.9 entering state [early][183]
2019-02-22 17:38:40.557875 [DEBUG] switch_ivr_play_say.c:1498 Codec Activated L16@8000hz 1 channels 20ms
2019-02-22 17:38:40.657867 [DEBUG] switch_rtp.c:7308 Correct audio ip/port confirmed.
2019-02-22 17:38:49.677867 [DEBUG] sofia.c:7084 Channel sofia/fifa/79500090900@192.168.25.9 entering state [terminated][487]
2019-02-22 17:38:49.677867 [NOTICE] sofia.c:8273 Hangup sofia/fifa/79500090900@192.168.25.9 [CS_EXECUTE] [ORIGINATOR_CANCEL]
2019-02-22 17:38:49.677867 [DEBUG] switch_ivr_play_say.c:1942 done playing file /usr/local/freeswitch/sounds/fifa/Fail_RUS1.wav
2019-02-22 17:38:49.677867 [DEBUG] switch_core_session.c:2815 sofia/fifa/79500090900@192.168.25.9 skip receive message [APPLICATION_EXEC_COMPLETE] (channel is hungup already)
2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:650 (sofia/fifa/79500090900@192.168.25.9) State EXECUTE going to sleep
2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:584 (sofia/fifa/79500090900@192.168.25.9) Running State Change CS_HANGUP (Cur 1 Tot 13675)
2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:850 (sofia/fifa/79500090900@192.168.25.9) Callstate Change EARLY -&gt; HANGUP
2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:852 (sofia/fifa/79500090900@192.168.25.9) State HANGUP
2019-02-22 17:38:49.677867 [DEBUG] mod_sofia.c:438 Channel sofia/fifa/79500090900@192.168.25.9 hanging up, cause: ORIGINATOR_CANCEL
2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:60 sofia/fifa/79500090900@192.168.25.9 Standard HANGUP, cause: ORIGINATOR_CANCEL
2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:852 (sofia/fifa/79500090900@192.168.25.9) State HANGUP going to sleep
2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:619 (sofia/fifa/79500090900@192.168.25.9) State Change CS_HANGUP -&gt; CS_REPORTING
2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:584 (sofia/fifa/79500090900@192.168.25.9) Running State Change CS_REPORTING (Cur 1 Tot 13675)
2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:938 (sofia/fifa/79500090900@192.168.25.9) State REPORTING
2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:174 sofia/fifa/79500090900@192.168.25.9 Standard REPORTING, cause: ORIGINATOR_CANCEL
2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:938 (sofia/fifa/79500090900@192.168.25.9) State REPORTING going to sleep
2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:610 (sofia/fifa/79500090900@192.168.25.9) State Change CS_REPORTING -&gt; CS_DESTROY
2019-02-22 17:38:49.677867 [DEBUG] switch_core_session.c:1665 Session 13675 (sofia/fifa/79500090900@192.168.25.9) Locked, Waiting on external entities
2019-02-22 17:38:49.677867 [NOTICE] switch_core_session.c:1683 Session 13675 (sofia/fifa/79500090900@192.168.25.9) Ended
2019-02-22 17:38:49.677867 [NOTICE] switch_core_session.c:1687 Close Channel sofia/fifa/79500090900@192.168.25.9 [CS_DESTROY]
2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:741 (sofia/fifa/79500090900@192.168.25.9) Running State Change CS_DESTROY (Cur 0 Tot 13675)
2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:751 (sofia/fifa/79500090900@192.168.25.9) State DESTROY
2019-02-22 17:38:49.677867 [DEBUG] mod_sofia.c:343 sofia/fifa/79500090900@192.168.25.9 SOFIA DESTROY
2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:181 sofia/fifa/79500090900@192.168.25.9 Standard DESTROY
2019-02-22 17:38:49.677867 [DEBUG] switch_core_state_machine.c:751 (sofia/fifa/79500090900@192.168.25.9) State DESTROY going to sleep</code></pre>
<p>По мониторингу FreeSWITCH использую следующие основные параметры, ниже пример конфигурации для Zabbix файл <em>/etc/zabbix/zabbix_agentd.conf в UserParameter</em>:</p>
<pre><code>### Option: UserParameter
####Channel count
UserParameter=fs.channels.count.current, /usr/local/freeswitch/bin/fs_cli -x "show channels count" | grep total | awk {'print $1'}
UserParameter=fs.channels.count.max.5.min, /usr/local/freeswitch/bin/fs_cli -x "status" | grep 'session(s) - peak' |  awk '{print $8}'
####CPS count
UserParameter=fs.cps.count.current, /usr/local/freeswitch/bin/fs_cli -x "status" | grep ' session(s) - peak' | awk '{print $1}'
UserParameter=fs.cps.count.max.5.min,/usr/local/freeswitch/bin/fs_cli -x "status" | grep 'session(s) per Sec out of max' | awk '{print $13}'
###Sessions count since startup
UserParameter=fs.sessions.count.since.startup,/usr/local/freeswitch/bin/fs_cli -x "status" | grep "session(s) since startup" | awk {'print $1'}</code></pre>
<p><strong>Итог</strong></p>
<p>Для задачи авторизации в сети Wi-Fi по звонку отлично подойдёт любое из решений, Asterisk проще в конфигурировании, FreeSWITCH несколько сложнее, зато у него есть модуль <em>curl</em> и не нужно вызывать внешний скрипт, но скрипт написать не сложно. По производительности я не заметил разницы, наверное, потому что нагрузка была не существенная. Вот по качеству воспроизведения подсказок, по моей субъективной оценке, FreeSWITCH звучал лучше. По отладке и мониторингу, больше нравится FreeSWITCH, потому что логичнее и понятнее сообщения FreeSWITCH, также можно мониторить больше переменных, особенно порадовало наличие параметра <em>Call per Second (CPS)</em>. В целом, по логической организации FreeSWITCH тоже больше нравится, но xml конфигурация FreeSWITCH несколько сложнее для восприятия, чем язык ael дайлплана Asterisk, хотя со временем чтение и написание xml не вызывает никаких сложностей.</p>
<p>Автор: Игнат Кудрявцев</p><p>The post <a href="https://ucexpert.ru/archives/7377">Сравниваем конфигурации FreeSWITCH и Asterisk для одной задачи</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Обзор Homer 5</title>
		<link>https://ucexpert.ru/archives/7276</link>
					<comments>https://ucexpert.ru/archives/7276#comments</comments>
		
		<dc:creator><![CDATA[Игнат Кудрявцев]]></dc:creator>
		<pubDate>Fri, 15 Jun 2018 22:07:02 +0000</pubDate>
				<category><![CDATA[Обзоры и тесты]]></category>
		<category><![CDATA[Рекомендуемое]]></category>
		<category><![CDATA[Monitoring]]></category>
		<category><![CDATA[SIP]]></category>
		<category><![CDATA[Voice Quality Monitoring]]></category>
		<category><![CDATA[VoIP]]></category>
		<guid isPermaLink="false">http://www.ucexpert.ru/?p=7276</guid>

					<description><![CDATA[<p>Всем известно, что Гомер Симпсон (Homer Simpson) любит есть, Гомер, о котором пойдёт речь сегодня, также обожает есть, но не пончики, а SIP-трафик и то, что к нему полагается. И фамилия у нашего Гомера, могла ...</p>
<p>The post <a href="https://ucexpert.ru/archives/7276">Обзор Homer 5</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Всем известно, что Гомер Симпсон (Homer Simpson) любит есть, Гомер, о котором пойдёт речь сегодня, также обожает есть, но не пончики, а SIP-трафик и то, что к нему полагается. И фамилия у нашего Гомера, могла бы быть SIPson.<br />
Итак, Homer это БЕСПЛАТНОЕ решение, предназначенное для захвата, анализа и мониторинга SIP и RTCP-трафика с широкими возможностями масштабирования способное «перемалывать» огромные объёмы трафика свойственные VoIP-операторам малого или среднего размера.<span id="more-7276"></span></p>
<p>Эта система призвана облегчить инженерам поиск и устранение неисправностей в VoIP-сетях при помощи мощного анализа и визуализации SIP-диалогов между узлами и детальный просмотр всех SIP-сообщений. Решение позволяет сохранять выгружать SIP-трейсы вызовов в виде pcap дампов или текстовых файлов. Еще одним преимуществом решения является возможность разнесения компонентов системы по разным узлам, что позволяет масштабировать систему.</p>
<p>Обзор похожего, но платного решения, разработка которого, к сожалению, давно прекращена можно найти по данной ссылке – <a href="/archives/1821" target="_blank" rel="noopener">Мониторинг сети VoIP с помощью VQManager</a><br />
Решение Homer состоит из нескольких  подсистем. Рассмотрим эти подсистемы и механизм их взаимодействия межу собой.</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px" title="image" src="/wp-content/uploads/2018/06/image-8.png" alt="image" width="590" height="354" /></p>
<p>В составе Homer можно выделить три основные подсистемы:</p>
<ul>
<li><strong>HOMER CAPTURE AGENT</strong> – агент захватывает трафик из VoIP-сети, копирует и инкапсулирует  SIP и RTCP пакеты  при помощи протокола HEP/EPP и передаёт их на CAPTURE SERVER, причём агент может представлять из себя как модуль для SIP-сервера (Asterisk, FreeSWITCH, Kamailio,OpenSIPS), так и сервис захвата «сырого» трафика с сетевого интерфейса, который может зеркалироваться с порта (-ов) ethernet-коммутатора куда подключен SIP-сервер (например, модуль транзита трафика РТУ МТТ) на порт (-ы) CAPTURE AGENT.</li>
<li><strong>HOMER CAPTURE SERVER</strong> – сервер на базе SIP маршрутизатора Kamailio с базой данных MySQL, где аккумулируется и хранятся SIP и RTCP пакеты полученные от CAPTURE AGENT</li>
<li>
<div align="justify"><strong>HOMER USER INTERFACE</strong> – веб-интерфейс для поиска, анализа и визуализации SIP-трейсов которые хранятся в CAPTURE SERVER.</div>
</li>
</ul>
<p>Итак, общая схема работы  Homer выглядит так:<br />
CAPTURE AGENT — это системная служба которая постоянно запущена на узле. Через узел проходит VoIP-трафик требующий анализа. CAPTURE AGENT захватывает трафик и создает копии сигнальных SIP-сообщений, затем инкапсулирует эти копии пакетов в формат HEP/ EEP и передаёт их по сети в коллектор сервера CAPTURE SERVER, сервер получает SIP и RTCP пакеты, разбирает их и помещает в базу данных MySQL. Фактически все SIP-сообщения целиком хранятся в базе данных, но естественно не просто так, а с метаданными, которые и позволяют существенно ускорить поиск и отображение запрашиваемой из веб-интерфейса информации.<br />
Веб-интерфейс USER INTERFACE подключается к базе данных CAPTURE SERVER и загружает данные запрашиваемые пользователем веб-интерфейса.</p>
<p><strong>Основные функции компонентов Homer</strong></p>
<p><em>Capture Server</em></p>
<ul>
<li>Высокая производительность – тысячи пакетов в секунду</li>
<li>Поддержка нескольких баз данных</li>
<li>Мощный пользовательский интерфейс для поиска и фильтрации</li>
<li>Визуальные диалоги SIP  и возможность их вызгрузки в pcap-файлы</li>
<li>Графики со статистикой и аналитикой</li>
<li>Поддержка REST API и виджетов</li>
<li>Авторизация пользователей по RADIUS и LDAP</li>
<li>Angular/JS интерфейс пользователя</li>
</ul>
<p><em>Capture Agent</em></p>
<ul>
<li>HEP3 инкапсуляция</li>
<li>Шифрование и сжатие содержимого</li>
<li>Модульный дизайн</li>
<li>SIP,RTP/RTCP,Журналы,CDRs</li>
<li>Поддержка TLS</li>
<li>Высокопроизводительный</li>
<li>Поддержка Linux,Solaris,BSD/OSX,Win32</li>
</ul>
<p><em>Функции  Ядра</em></p>
<ul>
<li>Протокол HEP/EEP</li>
<li>SIP-сигналинг</li>
<li>WebRTC-сигналинг</li>
<li>Протокол RTCP</li>
<li>Протокол RTCP-XR</li>
<li>Коллектор журналов</li>
<li>Гео-меппинг</li>
<li>Поддержка Docker</li>
</ul>
<p><strong>Варианты использования Homer</strong></p>
<p>На сайте Homer по адресу sipcapture.org предлагают два метода.<br />
Первый – облачный (cloud), заказчик устанавливает у себя в сети HEP Capture Agent который копирует VoIP-трафик из сети заказчика, упаковывает в HEP пакеты, если надо шифрует при помощи SSL/TLS и отправляет в облако SIPCAPTURE.IO где находится Capture Server и Homer UI – веб-интерфейс Homer. В таком случае заказчику не придётся думать о поддержке и обновления Homer. Услуга конечно же не бесплатная, и в зависимости от пакета составляет от 80 до 500 евро в месяц.<br />
<img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border-width: 0px" title="HOMER VOIP" src="/wp-content/uploads/2018/06/image-9.png" alt="HOMER VOIP" width="590" height="474" /></p>
<p>Второй – в сети заказчика (on-permise), заказчик инсталлирует, обслуживает и обновляет все компоненты Homer в своей сети. Мы рассмотрим второй вариант.</p>
<p><strong>Требования к программному обеспечению Homer 5</strong></p>
<ul>
<li>Apache2 or Nnginx</li>
<li>PHP-5, MySQL + InnoDB (barracuda) ( &gt;= 5.6)</li>
<li>Kamailio + sipcapture</li>
<li>Homer-API + Homer-UI</li>
</ul>
<p><strong>Аппаратные требования и тестирование производительности</strong></p>
<p>Каких-либо официальных аппаратных требований на сайтах sipcapture.org или github.com/sipcapture я не нашёл. Для тестирования производительности, решил сравнить две копии Homer запущенные на разных серверах но с абсолютно одинаковым реальным трафиком следующего объёма:<br />
Зеркалируемый узел: 310 одновременных вызовов в среднем. CPS  в среднем 3,48 макс 19 вызовов в секунду, все данные за сутки.<br />
Вызовов за 24 часа примерно 650000<br />
В основном SIP-вызовы без SIP-регистраций, OPTIONS и других сообщений свойственным терминалом.<br />
<em>Узел 1:</em><br />
&#8212; Сервер: HP Proliant DL380 G5<br />
&#8212; 1 CPU Xeon E5420 4 2.5 GHz 4 Cores<br />
&#8212; RAM 8 GB DDR2 677Mhz ECC<br />
&#8212; RAID0 2 x 2.5 SAS 10K RPM  + Controller P400 256Mbt<br />
&#8212; 2NIC 1000Mb\sec</p>
<p> <a href="/wp-content/uploads/2018/06/image-10.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER VOIP" src="/wp-content/uploads/2018/06/image_thumb-6.png" alt="HOMER VOIP" width="590" height="427" /></a><br />
Нагрузка на машину не большая, хотя она молотит. Ниже вывод htop.</p>
<p><a href="/wp-content/uploads/2018/06/image-11.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER VOIP" src="/wp-content/uploads/2018/06/image_thumb-7.png" alt="HOMER VOIP" width="590" height="467" /></a></p>
<pre># :/var/lib/mysql# date;du -h -c
Thu Apr 20 14:12:49 MSK 2017
676K    ./sys
22M     ./mysql
1.1M    ./performance_schema
439M    ./homer_statistic
1.1M    ./homer_configuration
71G     ./homer_data
72G     .
72G     total</pre>
<p><em>72 Гигабайта за 10 дней.Узел 2:</em></p>
<p>&#8212; Система виртуализации VMWare ESX6.5<br />
Виртуальная машина с максимально возможными ресурсами.<br />
&#8212; Сервер: Intel S3210SH<br />
&#8212; Система виртуализации VMWare ESX5.5<br />
&#8212; 1 CPU Intel Core 2 Quad Q6700 2.66 Mhz 4 Cores<br />
&#8212; RAM 8GB DDR2 677Mhz nonECC<br />
&#8212; 2 DISK Seagate 3.5 SATA 7.2K RPM<br />
&#8212; 2 NIC 1000Mb\sec</p>
<p>На нём виртуальна машина со следующими ресурсами:<br />
&#8212; 4 ядра процессора<br />
&#8212; RAM 5GB</p>
<p>Под эту виртуальную машину зарезервирован отдельный физический диск под виртуальную машину.</p>
<p><a href="/wp-content/uploads/2018/06/image-12.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER VOIP" src="/wp-content/uploads/2018/06/image_thumb-8.png" alt="HOMER VOIP" width="590" height="442" /></a></p>
<p>Постоянное число регистраций: 8 тысяч и 149 одновременных вызовов в среднем.</p>
<pre># :/var/lib/mysql# date;du -h -c
Thu Apr 20 14:11:52 MSK 2017
100G    ./homer_data
22M     ./mysql
1.1M    ./performance_schema
2.7G    ./homer_statistic
676K    ./sys
1.1M    ./homer_configuration
103G    .
103G    total</pre>
<p><em>103 Гигабайта за 10 дней.</em></p>
<p>В течение двух месяцев работы система показала отличные результаты как по скорости работы так и по аппаратным ресурсам необходимым для работы.<br />
Через несколько месяцев на второй машине накрылся жесткий диск SATA 7200<br />
Данный диск был заменен на новый, но его через месяц постигла та же участь.<br />
Поэтому при большой нагрузке рекомендую использовать SAS + RAID 0</p>
<p><strong>Или попробовать вынести файлы базы данных Mysql на отдельный диск</strong></p>
<p>Например, подклюаем отдельный диск с точкой монтирования <em>/var/lib/mysq</em>l</p>
<pre>cat /etc/fstab
UUID=4a439b75-c7aa-4bd6-ad27-88ff5f44d38d /var/lib/mysql  ext4    defaults        0       2

# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1       397G  1.9G  375G   1% /
udev             10M     0   10M   0% /dev
tmpfs           1.6G  8.6M  1.6G   1% /run
tmpfs           4.0G     0  4.0G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           4.0G     0  4.0G   0% /sys/fs/cgroup

# /etc/init.d/mysql stop
# mv /var/lib/mysql /var/lib/mysql_temp
# mkdir /var/lib/mysql
# mount /var/lib/mysql
# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1       397G  1.9G  375G   1% /
udev             10M     0   10M   0% /dev
tmpfs           1.6G  8.5M  1.6G   1% /run
tmpfs           4.0G     0  4.0G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           4.0G     0  4.0G   0% /sys/fs/cgroup
/dev/sdb1       413G  264M  392G   1% /var/lib/mysql

# cp -r /var/lib/mysql_temp/* /var/lib/mysql
# chown mysql:mysql -R /var/lib/mysql
# chmod 755 /var/lib/mysql
# /etc/init.d/mysql start
[ ok ] Starting mysql (via systemctl): mysql.service.
# /etc/init.d/mysql status
● mysql.service - MySQL Community Server
   Loaded: loaded (/lib/systemd/system/mysql.service; enabled)
   Active: active (running) since Tue 2017-12-26 15:00:11 MSK; 12s ago
  Process: 12878 ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid (code=exited, status=0/SUCCESS)
  Process: 12842 ExecStartPre=/usr/share/mysql/mysql-systemd-start pre (code=exited, status=0/SUCCESS)
 Main PID: 12881 (mysqld)
   CGroup: /system.slice/mysql.service
           └─12881 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid

Dec 26 15:00:11 Homer-2 systemd[1]: Started MySQL Community Server.</pre>
<p>Если mysql запустится нормально и все файлы на месте, то можно удалить временную директорию.</p>
<pre># rm -rf /var/lib/mysql_temp</pre>
<p><strong>Инсталляция Homer</strong></p>
<p>Установка состоит из двух этапов.<br />
<em>Первый этап</em>. Установка самого Homer состоящего из “HEP-коллектора” в виде SIP машрутизатора Kamailio, который складывает полученные от него пакеты в БД, плюс к этому, сервер Apache2 на котором находятся файлы API-скриптов и GUI-интерфейса Homer. Именно GUI -интерфейс используя API  Homer фильтрует и «рисует» SIP-трейсы, графики и выводит прочую информацию.<br />
<em>Второй этап.</em> Установка агента, который перерабатывает трейсы и статистику, приходящую из специального модуля программных SIP-серверов, таких как Asterisk, FreeSWITCH, Kamailio и OpenSIPS и передает по протоколу HEP в коллектор Homer. Также возможен вариант установки агента, который берет данные от зеркалированного на порты коммутатора VoIP-трафика, в таком случае неважно какой SIP-сервер используется и никакие модули на него не нужно устанавливать.</p>
<p>Для VMWare, создаём VM и сети.</p>
<p><a href="/wp-content/uploads/2018/06/image-13.png"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER VOIP" src="/wp-content/uploads/2018/06/image_thumb-9.png" alt="HOMER VOIP" width="590" height="526" /></a></p>
<p>Создаём сети:</p>
<p><a href="/wp-content/uploads/2018/06/image-14.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER VOIP" src="/wp-content/uploads/2018/06/image_thumb-10.png" alt="HOMER VOIP" width="590" height="436" /></a></p>
<p>Причем для <em>Mirror-Interface</em>, на вкладке <em>Security </em>для <em>Promiscuous Mode</em> ставим галку и выбираем <em>Accept.</em></p>
<p>Для установки используем дистрибутив<em> Debian 8.7 (jessie</em>), также оттестировано на <em>Debian 9.2.</em></p>
<pre>/etc/network/interfaces
source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug eth0
#iface eth0 inet dhcp
iface eth0 inet static
        address 172.17.36.37/26
        gateway 172.17.36.26
        # dns-* options are implemented by the resolvconf package, if installed
        dns-nameservers 84.52.107.107 195.177.123.1
        post-up /sbin/route add -net 192.168.133.0/24 gw 172.17.36.62
allow-hotplug eth1
iface eth1 inet static
address 0.0.0.0</pre>
<p>Самый простой способ и лёгкий способ выполнить команды:</p>
<pre>#aptitude install curl (если у вас он не установлен)
# bash &lt;( curl -s https://cdn.rawgit.com/sipcapture/homer-installer/master/homer_installer.sh )</pre>
<p>С сайта будет автоматически загружен и выполнен скрипт homer_installer.sh, который сам всё скачает и установит. Нужно будет задать пользователя и пароль пользователя Mysql, который будет работать с БД Homer.</p>
<p>Сервисы:</p>
<ul>
<li>Kamailio</li>
<li>Apache2</li>
<li>Сервер MySQL</li>
</ul>
<p>Будут автоматически добавлены в автозагрузку. Диалог инсталляции будет выглядить примерно так:</p>
<pre>**************************************************************

      ,;;;;;,       HOMER SIP CAPTURE (http://sipcapture.org)
     ;;;;;;;;;.     Single-Node Auto-Installer (beta 5.0.1)
   ;;;;;;;;;;;;;
  ;;;;  ;;;  ;;;;   &lt;--------------- INVITE ---------------
  ;;;;  ;;;  ;;;;    --------------- 200 OK ---------------&gt;
  ;;;;  ...  ;;;;
  ;;;;       ;;;;   WARNING: This installer is intended for
  ;;;;  ;;;  ;;;;   dedicated/vanilla OS setups without any
  ,;;;  ;;;  ;;;;   customization and with default settings
   ;;;;;;;;;;;;;
    :;;;;;;;;;;     THIS SCRIPT IS PROVIDED AS-IS, USE AT
     ^;;;;;;;^      YOUR *OWN* RISK, REVIEW LICENSE &amp; DOCS

**************************************************************
OS: Dectecting System....
OS: DEBIAN detected
This script expect a Vanilla OS and will override settings. Continue (y/N)? y

Затем установка таких пакетов, как apache2,php5, git, cpp, gcc и  вспомогательных библиотек.	

Module php5 already enabled
Enabling module rewrite.
To activate the new configuration, you need to run:
  service apache2 restart
Generating a 2048 bit RSA private key
..................+++
.............+++
writing new private key to '/etc/ssl/localcerts/apache.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:RU
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:Saint-Petersburg
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Westcall LTD
Organizational Unit Name (eg, section) []:Homer-1
Common Name (e.g. server FQDN or YOUR name) []:Ignat
Email Address []:i.kudryavtsev@somemail.com</pre>
<p>Далее будут сгенерированы сертификаты для ssl.<br />
Далее будут установлены пакеты Kamailio и БД MySQL.<br />
После успешной установки, скрипт предложит сконфигурировать БД MySQL.</p>
<p><em>База данных</em>: Homer_1<br />
<em>Пользователь БД</em>: Homer_1<br />
<em>Пароль:</em> БД:121212badrebZL</p>
<p>Если всё ок, в конце установки будет нечто похожее:</p>
<pre>cp: omitting directory ‘/usr/src/homer-api/scripts/old’
cp: omitting directory ‘/usr/src/homer-api/scripts/pgsql’
no crontab for root
Enter the SQL User details for the HOMER Client: Homer_1
MYSQL Homer User: (empty for default) Homer_1_password

MYSQL Homer Pass: (empty for randomized) 121212badrebZL _
WARNING: Choose a password for MySQL ROOT account (empty by default!)
Beginning initial data load....
Starting mysqld
Starting mysql (via systemctl): mysql.service.
Creating Databases...
Creating Tables...
ERROR 1062 (23000) at line 1: Duplicate entry '1' for key 'PRIMARY'
Setting root password....
Patching Homer configuration...
Restarting apache2 (via systemctl): apache2.service.
Restarting kamailio (via systemctl): kamailio.serviceroot@homer:~# .
*************************************************************
      ,;;;;,
     ;;;;;;;;.     Congratulations! HOMER has been installed!
   ;;;;;;;;;;;;
  ;;;;  ;;  ;;;;   &lt;--------------- INVITE ---------------
  ;;;;  ;;  ;;;;    --------------- 200 OK ---------------&gt;
  ;;;;  ..  ;;;;
  ;;;;      ;;;;   Your system should be now ready to rock!
  ;;;;  ;;  ;;;;   Please verify/complete the configuration
  ,;;;  ;;  ;;;;   files generated by the installer below.
   ;;;;;;;;;;;;
    :;;;;;;;;;     THIS SCRIPT IS PROVIDED AS-IS, USE AT
     ;;;;;;;;      YOUR *OWN* RISK, REVIEW LICENSE &amp; DOCS

*************************************************************

     * Verify configuration for HOMER-API:
         '/var/www/html//api/configuration.php'
         '/var/www/html//api/preferences.php'

     * Verify capture settings for Homer/Kamailio:
         '/etc/kamailio/kamailio.cfg'

     * Start/stop Homer SIP Capture:
         '/sbin/kamctl start|stop'

     * Access HOMER UI:
         http://192.168.85.150 or http://192.168.85.150
         [default: admin/test123 or test1234]

     * Send HEP/EEP Encapsulated Packets:
         hep://192.168.85.150:9060

**************************************************************

 IMPORTANT: Do not forget to send Homer node some traffic! ;)
 For our capture agents, visit http://github.com/sipcapture
 For more help and information visit: http://sipcapture.org

**************************************************************
 Installer Log saved to: /tmp/homer_installer.log</pre>
<p>Как следует из журнала установки коллектор HEP это 192.168.85.150:9060</p>
<p>Доступ на веб-интерфейс Homer <a href="http://192.168.85.150">http://192.168.85.150</a></p>
<p>Также на странице sipcapture сайта github описана ручная установка Homer. Если кратко, то она состоит из следующих этапов:<br />
С github качаем файлы homer-api и homer-ui, ставим Apache2, копируем эти файлы в директорию Apache2. Далее, ставим MySQL-сервер, затем добавляем базы данных <em>homer_data, homer_users, homer_configuration, homer_statistic</em> и создаём в них структуру из соответствующих шаблонах в .sql файлах. Затем создаём пользователя mysql и даём ему полные права на эти БД, затем конфигурируем Homer API путём редактирования php файла к с конфигурацией <em>/var/www/html/api/configuration.php</em>, дополнительно настраиваем ротацию данных в БД homer по времени. Теперь ставим kamailio, настраиваем файл конфигурации <em>kamailio.cfg</em> (копируем из примера), запускаем Kamailio. Проверяем что он запущен и порт коллектора HEP, например, 9060 открыт. Проверяем, что веб-интерфейс работает, открыв IP-адрес сервера в веб-браузере. Логин и пароль по умолчанию:  <em>admin / test123</em> его можно поменять в БД или посмотреть в файле шаблона <em>schema_configuration.sql</em></p>
<p><strong>Установка Сaptagent</strong></p>
<p>Дистрибутив Linux Debian 8.7 (jessie). Установим дополнительные пакеты:</p>
<pre>#apt-get install libexpat-dev libpcap-dev libjson0-dev libtool automake flex bison libuv-dev make</pre>
<p>Клонирование при помощи git и компиляция:</p>
<pre> #cd /usr/src
 #git clone https://github.com/sipcapture/captagent.git captagent
 #cd captagent
 #./build.sh
 #./configure</pre>
<p>Если всё ок, то будет такой результат: Если всё ок, то будет такой результат:</p>
<pre>captagent 6.2.0.2

Build directory............. :
Installation prefix......... : /usr/local/captagent
HEP Compression............. : no
IPv6 support.................: no
HEP SSL/TLS................. : no
Flex........................ : flex
Bison....................... : bison -y

Build with REDIS............ : no
Build with MySQL............ : no
Build with PCRE............. : no
Build with LibUV............ : yes</pre>
<p>Далее, последние команды для сборки и установки:</p>
<pre># make &amp;&amp; make install</pre>
<p>Если всё ок, ошибок не будет, по окончании будут сообщения что библиотеки успешно инсталлированы:</p>
<pre>Libraries have been installed in:
   /usr/local/captagent/lib/captagent/modules

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
   - add LIBDIR to the `LD_LIBRARY_PATH' environment variable
     during execution
   - add LIBDIR to the `LD_RUN_PATH' environment variable
     during linking
   - use the `-Wl,-rpath -Wl,LIBDIR' linker flag
   - have your system administrator add LIBDIR to `/etc/ld.so.conf'

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------
make[5]: Leaving directory '/usr/src/captagent/src/modules/interface/http'
make[4]: Leaving directory '/usr/src/captagent/src/modules/interface/http'
make[3]: Leaving directory '/usr/src/captagent/src/modules/interface/http'
make[2]: Leaving directory '/usr/src/captagent/src'
make[1]: Leaving directory '/usr/src/captagent/src'
Making install in include
make[1]: Entering directory '/usr/src/captagent/include'
make[2]: Entering directory '/usr/src/captagent/include'
make[2]: Nothing to be done for 'install-exec-am'.
make[2]: Nothing to be done for 'install-data-am'.
make[2]: Leaving directory '/usr/src/captagent/include'
make[1]: Leaving directory '/usr/src/captagent/include'
make[1]: Entering directory '/usr/src/captagent'
make[2]: Entering directory '/usr/src/captagent'
make[2]: Nothing to be done for 'install-exec-am'.
make[2]: Nothing to be done for 'install-data-am'.
make[2]: Leaving directory '/usr/src/captagent'
make[1]: Leaving directory '/usr/src/captagent'</pre>
<p><b>Настройка </b><b>Captagent</b></p>
<p>Модули ядра загружаются через основной файл конфигурации captagent.xml, таким образом, они могут быть легко объединены для создания нескольких независимых цепей захвата трафика. Графически это можно представить следующим образом:</p>
<p><a href="/wp-content/uploads/2018/06/clip_image001-1.png"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="HOMER CAPTAGENT" src="/wp-content/uploads/2018/06/clip_image001_thumb-1.png" alt="HOMER CAPTAGENT" width="324" height="297" /></a></p>
<p>SOCKET -&gt; PROFILE -&gt; CAPTURE PLAN &lt;&#8212;&gt; MODULES (функции)</p>
<p>Те мы используем, например, pcap захват трафика, тогда в файле <em>socket_pcap.xml</em>, прописываем в нём &#171;ловить&#187; SIP и  RTCP на определенном интерфейсе и определённых портах. И указываем планы захвата трафика <em>sip_capture_plan.cfg</em> и <em>rtcp_capture_plan.cfg</em> для способа захвата через pcap.</p>
<ul>
<li>Файлы конфигурации: <em>/usr/local/etc/captagent</em></li>
<li>Файлы Capture Plans: <em>/usr/local/etc/captagent/captureplans</em></li>
<li>Файлы Modules:<em> /usr/local/lib/captagent/modules</em></li>
</ul>
<p>Итак, начнём настройку в указанной выше последовательности.</p>
<p>Исходные данные:</p>
<ul>
<li>Устройство-приёмник для зеркалирования: eth1</li>
<li>Порт SIP: 9955</li>
<li>Порт RTCP: 10000-25999</li>
<li>Файл Capture Plan: sip_capture_plan.cfg</li>
</ul>
<p>Настройка интерфейса eth1 для зеркалирования /etc/network/interfaces</p>
<pre>allow-hotplug eth1
iface eth1 inet static
address 0.0.0.0</pre>
<p>На коммутаторе Cisco 3750G</p>
<pre>SW-3750#monitor session 1 source interface Gi1/0/2 - 7 , Gi1/0/9
SW-3750#monitor session 1 destination interface Gi1/0/25</pre>
<p><em>Настройка PROFILE</em>. Основная конфигурация находится в файле <em>/usr/local/captagent/etc/captagent/captagent.xml. </em>По умолчанию данный файл конфигурации редактировать не нужно.<br />
<em>Настройка SOCKET</em>. Проверим и изменим конфигурацию в файле <em>/usr/local/captagent/etc/captagent/socket_pcap.xml</em></p>
<pre>&lt;profile name="socketspcap_sip" description="HEP Socket" enable="true" serial="2014010402"&gt;
&lt;settings&gt;
&lt;param name="dev" value="any"/&gt;
&lt;param name="promisc" value="true"/&gt;
&lt;param name="reasm" value="false"/&gt; // comments here to explain the option?
&lt;param name="tcpdefrag" value="false"/&gt; // comments here to explain the option?
&lt;param name="capture-plan" value="sip_capture_plan.cfg"/&gt;
&lt;param name="filter"&gt;
&lt;value&gt;portrange 9955&lt;/value&gt;
&lt;/param&gt;
&lt;/settings&gt;
&lt;/profile&gt;</pre>
<p>Обращаю внимание, что значение <b></b>может не сработать, тогда нужно указывать конкретный интерфейс, например, <em>eth1.</em> Если нужно поставить более точный фильтр можно сделать так:</p>
<pre>portrange 9955 and host 90.90.90.90
portrange 5060-5090 and (host 10.0.0.1 or host 10.0.0.2)</pre>
<p>Плюс к этому настроим RTCP статистику в том же файле:</p>
<pre>&lt;profile name="socketspcap_rtcp" description="RTCP Socket" enable="false" serial="2014010402"&gt;
&lt;settings&gt;
&lt;param name="dev" value="eth1"/&gt;
&lt;param name="promisc" value="true"/&gt;
&lt;param name="reasm" value="false"/&gt;
&lt;!-- size in MB --&gt;
&lt;param name="ring-buffer" value="20"/&gt;
&lt;!-- for rtp &amp;&amp; rtcp &lt; 250 --&gt;
&lt;param name="snap-len" value="256"/&gt;
&lt;param name="capture-filter" value="rtcp"/&gt;
&lt;param name="capture-plan" value="rtcp_capture_plan.cfg"/&gt;
&lt;param name="filter"&gt;
&lt;value&gt;portrange 10000-25999 and len &gt;=50 &lt;/value&gt;
&lt;/param&gt;
&lt;/settings&gt;
&lt;/profile&gt;
&lt;/module&gt;
&lt;/document&gt;</pre>
<p>В данном файле указывается устройство <strong>dev=eth1</strong> откуда снимать трафик и разрешить неразборчивый режим <strong>promisc=true</strong>. Также в строках:</p>
<pre>&lt;profile name="socketspcap_sip" description="HEP Socket" enable="true" serial="2014010402"&gt;
&lt;profile name="socketspcap_rtcp" description="RTCP Socket" enable="false" serial="2014010402"&gt;</pre>
<p><b>Параметр enable должен стоять &#171;true&#187; иначе не будет работать!!!</b></p>
<p>Примечание: В версии 6.2.11 если sip (порт 9955) и rtcp (10000-25999) включить одновременно, то возникает ошибка – по HEP не улетает ни одного сообщения в коллектор kamailio, хотя диапазоны портов не пересекаются. Если они пересекутся, то официально это не рабочая схема.<br />
<em>Настройка CAPTURE PLAN</em>. Теперь переходим к <em>/usr/src/captagent/conf/captureplans/sip_capture_plan.cfg</em></p>
<pre>capture[pcap] {
# Perform checks against source/destination IP/port, message size
if(msg_check("size", "100")) {
if(source_ip(“10.0.0.99”)) { drop; }
# Parse the Message
if(parse_sip()) {
# Send using one or multiple profiles defined in transport_hep.xml
if(!send_hep("hepsocket")) {
clog("ERROR", "Error sending HEP!!!!");
}
}
}
drop;
}</pre>
<p>Тут ничего менять не надо, если конфигурация по умолчанию устраивает. Здесь же, как и в файле <em>captagent.xml,</em> можно устанавливать фильтры на трафик, наподобие <em>if (source_ip (“10.0.0.99”)) { drop; }</em></p>
<p><em>Настройка Transport Modules</em>. Далее, переходим к конфигурации транспортного сокета. Транспортный сокет необходим для доставки инкапсулированных пакетов в коллектор сервера Homer. Файл конфигурации <em>/usr/local/captagent/etc/captagent/transport_hep.xml</em> В нашем случае, файл будет выглядить так:</p>
<pre>&lt;?xml version="1.0"?&gt;
&lt;document type="captagent_module/xml"&gt;
&lt;module name="transport_hep" description="HEP Protocol" serial="2014010402"&gt;
&lt;profile name="hepsocket" description="Transport HEP" enable="true" serial="2014010402"&gt;
&lt;settings&gt;
&lt;param name="version" value="3"/&gt;
&lt;param name="capture-host" value="127.0.0.1"/&gt;
&lt;param name="capture-port" value="9060"/&gt;
&lt;param name="capture-proto" value="udp"/&gt;
&lt;param name="capture-id" value="2001"/&gt;
&lt;param name="capture-password" value=" "/&gt;
&lt;param name="payload-compression" value="false"/&gt;
&lt;/settings&gt;
&lt;/profile&gt;
&lt;/module&gt;
&lt;/document&gt;
</pre>
<p>То есть, конфигурация говорит, что коллектор сервера Homer находится по адресу 127.0.0.1, порт 9060, пароль пустой.</p>
<p><em>Настройка Protocol Modules.</em> Модули протоколов загружаются из файла <em>/usr/local/captagent/etc/captagent/captagent.xml</em></p>
<pre>&lt;configuration name="modules.conf" description="Modules"&gt;
&lt;modules&gt;
...
&lt;load module="transport_hep" register="local"/&gt;
&lt;load module="protocol_sip" register="local"/&gt;
&lt;load module="database_hash" register="local"/&gt;
&lt;load module="protocol_rtcp" register="local"/&gt;&gt;
&lt;load module="socket_pcap" register="local"/&gt; 
...
&lt;/modules&gt;
&lt;/configuration&gt;

</pre>
<p>Тут можно всё оставить по умолчанию и проверить что загружаются модули SIP и RTCP. Теперь необходимо настроить ротацию данных в БД Homer, если этого не сделать, то на рабочей системе размеры БД могут достигнуть огромных размеров что скажется не только на объёме свободного на диске, но и на скорости обработки и выдачи поисковых запросов в веб-интерфейсе Homer. Для этого запускаем редактор cron, командой <em>crontab -e</em>, и проверяем наличие строки:</p>
<pre>30 3 * * * /opt/homer/homer_rotate &gt;&gt; /var/log/cron.log 2&gt;&amp;1</pre>
<p>которая указывает что нужно ежедневно, в 3-30 нужно выполнять скрипт ротации /<em>opt/homer/homer_rotate</em>. В данном скрипте, есть ссылка на<em> /opt/homer/rotation.ini,</em> где настраивается сколько дней какие данные требуется хранить. Нас интересует раздел, <em>DATA_TABLE_ROTATION</em>, в котором всё понятно без дополнительных комментариев.</p>
<pre>[DATA_TABLE_ROTATION]
    #how long data keeps
    sip_capture_call = 10 #days
    sip_capture_registration = 10 # 10 days
    sip_capture_rest = 10 # 10 days
    rtcp_capture = 10 # days
    logs_capture = 10 # days
    report_capture = 10 # days
    webrtc_capture_all = 10 # days
    isup_capture_all = 10</pre>
<p>Обращаю внимание, что в разделе<em> [MYSQL]</em> находятся данные для подключения к БД Homer, которые используются для ротации.<br />
<em>Запуск Captagent.</em> Исполняемый файл находится по следующему пути:</p>
<pre>/usr/local/captagent/sbin/captagent</pre>
<p>Проверим версию:</p>
<pre>#./captagent -v
version: 6.2.0.2</pre>
<p>Параметры запуска могут быть следующие:</p>
<pre>./captagent -h
usage: captagent &lt;-vh&gt; &lt;-f config&gt;
   -h  is help/usage
   -v  is version information
   -f  is the config file
   -D  is use specified pcap file instead of a device from the config
   -c  is checkout
   -d  is daemon mode
   -n  is foreground mode
   -K  is hardware key of your system</pre>
<p>Самый простой вариант запуска:</p>
<p><em>#/usr/local/captagent/sbin/captagent -f /usr/local/captagent/etc/captagent/captagent.xml -n</em></p>
<p>Для отладки такой способ запуска полезен, вот пример запуска с ошибкой в конфигурации:</p>
<pre>root@homer-1:/usr/local/captagent/sbin# ./captagent -f /usr/local/captagent/etc/captagent/captagent.xml
[NOTICE] Loaded core config
[ERR] socket_pcap.c:657 Failed to compile filter "portrange 9955,5060": illegal token: ,
[ERR] protocol_sip.c:377 sipPacket CALLID has 0 len
[ERR] protocol_sip.c:353 SIP PARSE ERROR [-1]

[ERR] protocol_sip.c:372 bad parsing
[ERR] protocol_sip.c:353 SIP PARSE ERROR [-1]

[ERR] protocol_sip.c:372 bad parsing
[ERR] protocol_sip.c:353 SIP PARSE ERROR [-1]

Или вот такая ошибка:

[ERR] protocol_sip.c:133 Couldnot find this call

IS RTCP

[DEBUG] database_hash.c:165 IP PORT: 192.168.250.250:10535
[DEBUG] database_hash.c:280 IP PORT: [192.168.250.250:10535]
[DEBUG] database_hash.c:280 IP PORT: [192.168.250.245:25363]</pre>
<p>Тут проблема в том, что коллектор получает RTCP статистику и не может понять к чему она относится. В интернете чаще всего пишут, что причина в том, что диапазоны RTCP и SIP портов пересекаются. У меня проблема оказалось что по дебагу запуска captagent в профилях <em>socketspcap_sip</em> и <em>socketspcap_rtcp</em>, нужно выставить параметр <em>enable=&#187;true&#187;</em>, а в конфигурации по умолчанию стояло<em> false</em> именно для SIP.</p>
<pre>…
[DEBUG] socket_pcap.c:609 Activated device: [eth1]

[NOTICE] Using filter: (portrange 10000-25999 and len &gt;=50 ) and (ip and ip[6] &amp; 0x2 = 0 and ip[6:2] &amp; 0x1fff = 0 and udp and udp[8] &amp; 0xc0 = 0x80 and udp[9] &gt;= 0xc8 &amp;&amp; udp[9] &lt;= 0xcc)
[DEBUG] conf_function.c:453 find_export_record: found  in module protocol_sip [/usr/local/captagent/lib/captagent/modules]
…</pre>
<p>Явно грузился только RTCP фильтр в файле <em>socket_pcap.xml.</em> Плюс к этому, в основном файле конфигурации <em>captagent.xml</em> можно установить параметра более высокий, например, 9, тогда отладочные сообщения будут выводиться более детальными. Но это не очень удобно. Поэтому сделаем авто запуск captagent и добавим стартовый скрипт. Переходим в директорию, где находятся исходники captagent и копируем init.d скрипт, затем меняем права доступа к нему:<br />
#cp /usr/src/captagent/init/deb/debian/captagent.init /etc/init.d/captagent<br />
#chmod 755 /etc/init.d/captagent<br />
В скрипте /etc/init.d/captagent проверим значения:</p>
<pre>DAEMON=/usr/local/captagent/sbin/captagent
CFGFILE=/usr/local/captagent/etc/captagent/captagent.xml
#USER=captagent
#GROUP=captagent</pre>
<p>Обращаю внимание что пользователь и группа закомментированы. Тк они не существуют. Также копируем конфигурационный файл для запуска captagent в<em> /etc/default/#cp /usr/src/captagent/init/deb/debian/captagent.default /etc/default/captagent</em><br />
В данном файле /etc/default/captagent проверим настройки:</p>
<pre># Set to yes to enable captagent, once configured properly.
RUN_CAPTAGENT=yes

# Config file
CFGFILE=/usr/local/captagent/etc/captagent/captagent.xml</pre>
<p>Добавим созданный скрпипт в автозапуск #update-rc.d captagent defaults Если требуется удалить скрипт из автозапуска:<br />
<em># update-rc.d -f captagent remove</em><br />
Теперь после перезагрузки системы captagent будет запускаться автоматически. Если требуется перезапустить вручную:<br />
<em># /etc/init.d/captagent restart [ ok ] Restarting captagent (via systemctl): captagent.service.</em><br />
Советую перезагрузить машину и проверить сервис автоматически стартует. После успешного запуска, проверим корректность работы captagent 1) Что отзеркалированный трафик приходит на порт <em>eth1</em>:</p>
<pre>root@homer: # tshark -i eth1 -f "port 9955" -Y "sip"
  3   0.605801 192.168.85.148 -&gt; 84.52.103.XX SIP 485 Request: REGISTER sip:84.52.103.XX:9955  (remove 1 binding) |
  4   0.607631 84.52.103.XX -&gt; 192.168.85.148 SIP 549 Status: 200 Ok  (removed 2 bindings) |
  5   1.879704 192.168.85.148 -&gt; 84.52.103.XX SIP 585 Request: REGISTER sip:84.52.103.XX:9955  (1 binding) |
  6   1.881698 84.52.103.37 -&gt; 192.168.85.148 SIP 534 Status: 401 Unauthorized |
  7   1.882641 192.168.85.148 -&gt; 84.52.103.XX SIP 766 Request: REGISTER sip:84.52.103.XX:9955  (1 binding) |
  8   1.966359 84.52.103.XX -&gt; 192.168.85.148 SIP 553 Status: 200 Ok  (1 binding) |</pre>
<p>Отлично, трафик есть. Теперь, то, что captagent отправляет трафик в коллектор Homer:</p>
<pre>#:/usr/local/captagent/etc/captagent# tshark -i lo -f "port 9060"
  1   0.000000    127.0.0.1 -&gt; 127.0.0.1    UDP 590 Source port: 56044  Destination port: 9060
  2   0.000659    127.0.0.1 -&gt; 127.0.0.1    UDP 654 Source port: 56044  Destination port: 9060
  3   1.191771    127.0.0.1 -&gt; 127.0.0.1    UDP 690 Source port: 56044  Destination port: 9060
  4   1.193478    127.0.0.1 -&gt; 127.0.0.1    UDP 639 Source port: 56044  Destination port: 9060</pre>
<p>Трафик есть. Можно использовать команду с ключом (-V), чтобы убедиться, что приходит содержимое SIP-пакетов и RTCP-статистика. Также можно сравнить сколько сообщений на интерфейс:</p>
<pre>tshark -i eth1 -f "host 109.167.135.20" -V | grep @192_168_1_169</pre>
<p>И сколько отправлено по HEP:</p>
<pre>tshark -i any -f "port 9060" -V | grep @192_168_1_169
mysql&gt; select * from homer_data.sip_capture_call_20171110 where callid='62507640C928E0E9AD0249F00C4AF61B';
mysql&gt;  select * from homer_data.sip_capture_call_20171110 where callid like '%192_168_1_169%';</pre>
<p>На этом настройка закончена.</p>
<p><strong>Поддержка  GeoIP </strong></p>
<p>GeoIP позволяет отслеживать из каких стран от клиентов приходит SIP-трафик. В Debian, проверим что пакеты ниже установлены в системе:</p>
<pre># apt-get install geoip-database geoip-database-extra</pre>
<p>В файле <em>/etc/kamailio/kamailio.cfg </em>находим</p>
<pre>##!define WITH_HOMER_GEO</pre>
<p>Проверяем что есть:</p>
<pre>#!ifdef WITH_HOMER_GEO
modparam("geoip", "path", "/usr/share/GeoIP/GeoIPCity.dat")
#!endif</pre>
<p>Для версии MySQL больше 5.7 в конфигурационном файле my.cnf редактируем его, в моём случае <em>/etc/mysql/mysql.conf.d/mysqld.cnf</em></p>
<pre>В секции [mysqld]
добавил
sql_mode = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLE

Плюс сразу же добавил
bind-address    = 172.17.36.37</pre>
<p>В веб-интерфейсе Homer выглядит как карта с “температурой” количества регистраций по странам мира:</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border-width: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image-15.png" alt="HOMER web interface" width="590" height="374" /></p>
<p>У себя на абонентском сервере я этот функционал в итоге отключил.</p>
<p><strong>Возможные проблемы</strong></p>
<p>Не подходит пароль по умолчанию. Установленный по умолчанию пароль можно посмотреть в шаблоне БД который копировался в БД Homer.</p>
<pre>$GIT/homer-api/sql/schema_configuration.sql</pre>
<p>Если вы зашли в в веб-интерфейс (admin / test123), а там <em>«No Data Available».</em></p>
<p><a href="/wp-content/uploads/2018/06/image-16.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-11.png" alt="HOMER web interface" width="590" height="293" /></a></p>
<p>При этом вы уверены в следующем: Трафик от агента поступает в коллектор и настройки фильтрации по временному интервалу для этого трафика установлены корректно. То нужно проверить следующее:<br />
Настройки в <em>Panels -&gt; System Admin</em>, апплет <em>Admin Node.</em> Здесь находим запись нужную нам, например, с <em>id 1.</em></p>
<p><a href="/wp-content/uploads/2018/06/image-17.png"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-12.png" alt="HOMER web interface" width="590" height="179" /></a></p>
<p>Затем, смотрим учётные данные.</p>
<p><a href="/wp-content/uploads/2018/06/image-18.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-13.png" alt="HOMER web interface" width="590" height="293" /></a></p>
<p>Проверяем учётную запись:</p>
<pre># mysql -uhomer_user -pmysql_password
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'homer_user'@'localhost' (using password: YES)</pre>
<p>Заходим под root и проверяем пользователей:</p>
<pre>mysql&gt; select User from mysql.user;
+-----------+
| User      |
+-----------+
| homer     |
| mysql.sys |
| root      |
+-----------+
3 rows in set (0.00 sec)</pre>
<p>Видим, что такого пользователя нет.</p>
<pre>mysql&gt; show grants for homer;
+--------------------------------------------+
| Grants for homer@%                         |
+--------------------------------------------+
| GRANT ALL PRIVILEGES ON *.* TO 'homer'@'%' |
+--------------------------------------------+
1 row in set (0.00 sec)</pre>
<p>Посмотреть пароль для пользователя homer можно в конфигурации kamailio, файл <em>/etc/kamailio/kamailio.cfg</em>, строки:</p>
<pre>#!substdef "!HOMER_DB_USER!homer!g"
#!substdef "!HOMER_DB_PASSWORD!0msFqy2RF!g"
#!substdef "!HOMER_DB_HOST!127.0.0.1!g"
#!substdef "!HOMER_LISTEN_PROTO!udp!g"
#!substdef "!HOMER_LISTEN_IF!0.0.0.0!g"
#!substdef "!HOMER_LISTEN_PORT!9060!g"

Пароль 0msFqy2RF</pre>
<p>Проверяем:</p>
<pre># mysql -uhomer -p0msFqy2RF</pre>
<p>Список БД:</p>
<pre>mysql&gt; show databases;
+---------------------+
| Database            |
+---------------------+
| information_schema  |
| homer_configuration |
| homer_data          |
| homer_statistic     |
| mysql               |
| performance_schema  |
| sys                 |
+---------------------+
7 rows in set (0.00 sec)</pre>
<p>Заодно проверим сохраняются ли данные из коллектора:</p>
<pre>mysql&gt; homer_data;
mysql&gt; select * from  homer_data.sip_capture_call_20170208 limit 1;

+----+---------------------+------------------+--------+--------------+-----------------------------------+-------------+--------------+-------------+--------------+----------------------------------+-------------+--------------+--------+----------+--------------+-----------+----------------------------------+-------------+-----------------------------------------------------------------------------------------+-------------------------------------------+--------------+-----------+--------+-----------------+------+-----------------+----------------+-------------+----------------+------------------+----------------+--------------+---------------+-----------------+---------+----------------------------------+---------------+---------------+---------------+-------+--------+----------+------+-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| id | date                | micro_ts         | method | reply_reason | ruri                              | ruri_user   | ruri_domain  | from_user   | from_domain  | from_tag                         | to_user     | to_domain    | to_tag | pid_user | contact_user | auth_user | callid                           | callid_aleg | via_1                                                                                   | via_1_branch                              | cseq         | diversion | reason | content_type    | auth | user_agent      | source_ip      | source_port | destination_ip | destination_port | contact_ip     | contact_port | originator_ip | originator_port | expires | correlation_id                   | custom_field1 | custom_field2 | |
+----+---------------------+------------------+--------+--------------+-----------------------------------+-------------+--------------+-------------+--------------+----------------------------------+-------------+--------------+--------+----------+--------------+-----------+----------------------------------+-------------+-----------------------------------------------------------------------------------------+-------------------------------------------+--------------+-----------+--------+-----------------+------+-----------------+----------------+-------------+----------------+------------------+----------------+--------------+---------------+-----------------+---------+----------------------------------+---------------+---------------+---------------+-------+--------+----------+------+-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|  1 | 2017-02-08 14:52:50 | 1486554770263477 | INVITE |              | sip:79627277780@84.52.103.XX:9955 | 79627277780 | 84.52.103.XX | 327$td | 84.52.103.XX | 81d174040f934c7cbe2702c755b52a79 | 79627277780 | 84.52.103.XX |        |          | 327$td  |           | bee940acfd204d13a6b1347c34104daa |             | SIP/2.0/UDP 192.168.85.148:50933;rport;branch=z9hG4bKPj556ce0e730e84e38b7513b761e8005c4 | z9hG4bKPj556ce0e730e84e38b7513b761e8005c4 | 24262 INVITE |           |        | application/sdp |      | MicroSIP/3.11.0 | 192.168.85.148 |       50933 | 84.52.103.XX   |             9955 | 192.168.85.148 |        50933 |               |               0 |      -1 | bee940acfd204d13a6b1347c34104daa |               |               |               |     1 |      2 |          |    1 | homer01:0 | INVITE sip:79627277780@84.52.103.XX:9955 SIP/2.0
Via: SIP/2.0/UDP 192.168.85.148:50933;rport;branch=z9hG4bKPj556ce0e730e84e38b7513b761e8005c4
Max-Forwards: 70
From: ;tag=81d174040f934c7cbe2702c755b52a79
To: 
Contact: 
Call-ID: bee940acfd204d13a6b1347c34104daa
CSeq: 24262 INVITE
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Supported: replaces, 100rel, timer, norefersub
Session-Expires: 1800
Min-SE: 90
User-Agent: MicroSIP/3.11.0
Content-Type: application/sdp
Content-Length:   554

v=0
o=- 3695554377 3695554377 IN IP4 192.168.1.239
s=pjmedia
b=AS:84
t=0 0
a=X-nat:0
m=audio 4008 RTP/AVP 117 107 9 8 0 110 96 97 3 18 101
c=IN IP4 192.168.1.239
b=TIAS:64000
a=rtcp:4009 IN IP4 192.168.1.239
a=sendrecv
a=rtpmap:117 speex/16000
a=rtpmap:107 SILK/16000
a=rtpmap:9 G722/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:110 speex/8000
a=rtpmap:96 SILK/8000
a=rtpmap:97 iLBC/8000
a=fmtp:97 mode=30
a=rtpmap:3 GSM/8000
a=rtpmap:18 G729/8000
a=fmtp:18 annexb=no
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
 |
+----+---------------------+------------------+--------+--------------+-----------------------------------+-------------+--------------+-------------+--------------+----------------------------------+-------------+--------------+--------+----------+--------------+-----------+----------------------------------+-------------+-----------------------------------------------------------------------------------------+-------------------------------------------+--------------+-----------+--------+-----------------+------+-----------------+----------------+-------------+----------------+------------------+----------------+--------------+---------------+-----------------+---------+----------------------------------+---------------+---------------+---------------+-------+--------+----------+------+-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql&gt; select id,date,method from  homer_data.sip_capture_call_20170208 order by date desc limit 10;
+----+---------------------+--------+
| id | date                | method |
+----+---------------------+--------+
|  5 | 2017-02-08 14:52:50 | 100    |
|  6 | 2017-02-08 14:52:50 | 100    |
| 20 | 2017-02-08 14:53:02 | 100    |
| 22 | 2017-02-08 14:53:02 | 100    |
| 35 | 2017-02-08 14:53:34 | 100    |
| 36 | 2017-02-08 14:53:34 | 100    |
| 50 | 2017-02-08 14:55:03 | 100    |
| 51 | 2017-02-08 14:55:04 | 100    |
|  9 | 2017-02-08 14:52:52 | 200    |
| 12 | 2017-02-08 14:52:52 | 200    |
+----+---------------------+--------+
10 rows in set (0.00 sec)

mysql&gt; select id,date,method from  homer_data.sip_capture_registration_20170208 order by date desc limit 10;
+----+---------------------+--------+
| id | date                | method |
+----+---------------------+--------+
|  2 | 2017-02-08 14:53:29 | 200    |
|  3 | 2017-02-08 14:58:24 | 200    |
|  5 | 2017-02-08 15:03:19 | 200    |
|  7 | 2017-02-08 15:08:14 | 200    |
|  9 | 2017-02-08 15:10:45 | 200    |
| 14 | 2017-02-08 15:10:46 | 200    |
| 15 | 2017-02-08 15:12:24 | 200    |
| 20 | 2017-02-08 15:12:26 | 200    |
| 21 | 2017-02-08 15:17:21 | 200    |
| 23 | 2017-02-08 15:22:16 | 200    |
+----+---------------------+--------+
10 rows in set (0.00 sec)</pre>
<p>Теперь с учётом данных настроек, правим пользователя, также можно поправить имя ноды.</p>
<p><a href="/wp-content/uploads/2018/06/image-19.png"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-14.png" alt="HOMER web interface" width="590" height="290" /></a></p>
<p>Вторую запись «external» – пример подключения ноды с БД MySQL находящуюся на внешнем сервере, можно деактивировать или удалить.</p>
<p><b>Включение HEP на Asterisk</b></p>
<p>Очень просто, но поддерживается только pjsip стек!!! С обычным sip который используется у многих HEP работать не будет!!! Asterisk версий 12+ в Проверяем что модули загружены:</p>
<pre>asterisk*CLI&gt; module show like res_hep
Module                         Description                              Use Count  Status      Support Level
res_hep.so                     HEPv3 API                                0          Running          extended
res_hep_rtcp.so                RTCP HEPv3 Logger                        0          Running           unknown</pre>
<p>Далее, редактируем <em>/etc/asterisk/hep.conf</em></p>
<pre>;
; res_hep Module configuration for Asterisk
;

; All settings are currently set in the general section.
[general]
enabled = yes                       ; Enable/disable forwarding of packets to a
                                   ; HEP server. Default is "yes".
capture_address = 172.17.36.36:9060 ; The address of the HEP capture server.
capture_password = foo             ; If specified, the authorization passsword
                                   ; for the HEP server. If not specified, no
                                   ; authorization password will be sent.
capture_id = 1235                  ; A unique integer identifier for this
                                   ; server. This ID will be embedded sent
                                   ; with each packet from this server.
uuid_type = call-id                ; Specify the preferred source for the Homer
                                   ; correlation UUID. Valid options are:
                                   ; - 'call-id' for the PJSIP SIP Call-ID
                                   ; - 'channel' for the Asterisk channel name</pre>
<p>Применяем конфигурацию:</p>
<pre>asterisk*CLI&gt; module reload res_hep.so
Module 'res_hep.so' reloaded successfully.
    -- Reloading module 'res_hep.so' (HEPv3 API)
  == Parsing '/etc/asterisk/hep.conf': Found
asterisk *CLI&gt; module reload res_rtp_asterisk.so
Module 'res_rtp_asterisk.so' reloaded successfully.
    -- Reloading module 'res_rtp_asterisk.so' (Asterisk RTP Stack)</pre>
<p>Отправка трафика в коллектор при помощи sngrep и sipgrep</p>
<pre>sngrep -H udp:192.168.85.150:9060 -N –q
sipgrep  -H 192.168.85.150:9060

sngrep -H udp:172.17.36.36:9060 -N –q
sipgrep  -H 172.17.36.36:9060</pre>
<p><b>Ограничение в выдаче поиска на 100 записей</b></p>
<p>Нужно добавить поле <em>«Add Form Field»</em> с именем <em>Limit Query</em>. По умолчанию оно равно 100, далее изменить на нужное значение. Пример ниже.</p>
<p><a href="/wp-content/uploads/2018/06/image-20.png"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-15.png" alt="HOMER web interface" width="590" height="332" /></a></p>
<p><b>Что делать если Homer теряет пакеты</b></p>
<p>Ответ: увеличивать производительность. Чаще всего слабое место – дисковая подсистема. Если трафика много, то нагрузка на неё сильно возрастает. Самый простой способ посмотреть что происходит можно при помощи утилиты <strong>iotop:</strong></p>
<pre>#iotop
Total DISK READ :       0.00 B/s | Total DISK WRITE :       4.81 M/s
Actual DISK READ:       0.00 B/s | Actual DISK WRITE:       4.84 M/s
  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO&gt;    COMMAND
  328 be/3 root        0.00 B/s    0.00 B/s  0.00 % 95.36 % [jbd2/sdb1-8]
  630 be/4 mysql       0.00 B/s    0.00 B/s  0.00 %  4.54 % mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
  921 be/4 mysql       0.00 B/s   92.40 K/s  0.00 %  4.44 % mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
  635 be/4 mysql       0.00 B/s    4.29 M/s  0.00 %  3.04 % mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
  932 be/4 mysql       0.00 B/s  161.70 K/s  0.00 %  0.76 % mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
  925 be/4 mysql       0.00 B/s   80.85 K/s  0.00 %  0.61 % mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
  927 be/4 mysql       0.00 B/s  100.10 K/s  0.00 %  0.18 % mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
  929 be/4 mysql       0.00 B/s   88.55 K/s  0.00 %  0.17 % mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
  607 be/4 root        0.00 B/s    3.85 K/s  0.00 %  0.00 % rsyslogd -n [rs:main Q:Reg]</pre>
<p><strong>Total DISK WRITE: 4.81 M/s</strong></p>
<p><em>Способ 0. Не писать не нужные пакеты.</em></p>
<p>Для этого отключим запись OPTIONS, Notify и всё остальное. Также GeoIP Все метоты типа OPTIONS и другие сливаются в таблицы <em>ip_capture_rest_годмесяцдень.</em> Посмотрим такую таблицу:</p>
<pre>mysql&gt; select date,method  from sip_capture_rest_20180510 ORDER BY date desc limit 5;
+---------------------+-----------+
| date                | method    |
+---------------------+-----------+
| 2018-05-10 14:04:57 | 501       |
| 2018-05-10 14:04:57 | NOTIFY    |
| 2018-05-10 14:04:57 | 404       |
| 2018-05-10 14:04:57 | SUBSCRIBE |
| 2018-05-10 14:04:56 | 501       |
+---------------------+-----------+
5 rows in set (0.01 sec)</pre>
<p>Видим, что туда оно и пишется. Открываем <em>kamailio.cfg</em> и меняем строки:</p>
<pre>route[STORE] {

        if($rm == "REGISTER") {
                $var(table) = "sip_capture_registration";.......
	drop; #DROP registrations!!!
        }
        else if($rm =~ "(INVITE|UPDATE|BYE|ACK|PRACK|REFER|CANCEL)$")
        {
                $var(table) = "sip_capture_call";
        }.
        else if($rm =~ "(NOTIFY)$" &amp;&amp; is_present_hf("Event") &amp;&amp; $hdr(Event)=~"refer;")
        {
        #        $var(table) = "sip_capture_call";
	drop; # DROP NOTIFY PACKETS!
        }
        else if($rm =~ "(INFO)$")
        {
                $var(table) = "sip_capture_call";
        }
        else if($rm =~ "(OPTIONS)$" )
        {
        #    $var(table) = "sip_capture_rest";
	drop; # DROP OPTIONS PACKETS!
        }
        else {...
        #    $var(table) = "sip_capture_rest";
	drop; #DROP OTHER!!!!
        }</pre>
<p>Можно также частично или полностью отключить регистрации Например, не принимать пакеты REGISER из локальных сетей, редактируем <em>kamailio.cfg:</em></p>
<pre>              if($rm == "REGISTER") {

if(src_ip=~ "192.168.|172.2|10.25") {
drop;
}
                $var(table) = "sip_capture_registration";
#drop; #DROP registrations!!!
        }</pre>
<p>Проверяем:</p>
<pre>use homer_data;
mysql&gt; select date,method,source_ip  from sip_capture_registration_20180510 ORDER BY date desc limit 20;
+---------------------+----------+----------------+
| date                | method   | source_ip      |
+---------------------+----------+----------------+
| 2018-05-10 17:37:27 | REGISTER | XX.250.251.34  |
| 2018-05-10 17:37:27 | REGISTER | XX.244.27.158  |
| 2018-05-10 17:37:27 | 200      | XX.52.103.50   |
| 2018-05-10 17:37:27 | REGISTER | XX.187.187.229 |
| 2018-05-10 17:37:27 | REGISTER | XX.138.73.46   |
| 2018-05-10 17:37:27 | REGISTER | XX.203.170.220 |
| 2018-05-10 17:37:27 | 200      | XX.52.103.50   |
| 2018-05-10 17:37:27 | 200      | XX.52.103.50   |
| 2018-05-10 17:37:27 | 200      | XX.52.103.50   |
| 2018-05-10 17:37:27 | 200      | XX.52.103.50   |
| 2018-05-10 17:37:27 | REGISTER | XX.249.183.10  |
| 2018-05-10 17:37:27 | REGISTER | XX.244.27.158  |
| 2018-05-10 17:37:27 | 200      | XX.52.103.50   |
| 2018-05-10 17:37:27 | REGISTER | XX.244.27.158  |
| 2018-05-10 17:37:27 | REGISTER | XX.244.27.158  |
| 2018-05-10 17:37:27 | 200      | XX.52.103.50   |
| 2018-05-10 17:37:27 | 401      | XX.52.103.50   |
| 2018-05-10 17:37:27 | 200      | XX.52.103.50   |
| 2018-05-10 17:37:27 | 200      | XX.52.103.50   |
| 2018-05-10 17:37:27 | REGISTER | XX.244.27.158  |
+---------------------+----------+----------------+
20 rows in set (0.00 sec)</pre>
<p>Регистрации из серых сетей <em>192.168.|172.2|10.25</em> действительно исчезли.</p>
<p><em>Способ 1. Можно перенести БД на отдельный физический диск.Способ 2. Частичное или полное отключение журналирования файловой системы.</em></p>
<p>О режимах журналирования ФС: О режимах: Режим <em>data=writeback &gt;</em> файловая система не производит какого либо журналирования данных. При неожиданных перезагрузках системы это может вызвать потерю данных в обновляемых файлах. Данный режим обеспечивает самую высокую производительность. Режим data=ordered &gt; файловая система журналирует только метаданные (данные и метаданные группируются в один модуль – транзакцию). Этот режим, хотя без гарантии, защищает данные при неожиданной перезагрузке, в отличие от предыдущего. Тем не менее полного журналирования не происходит. Производительность уступает <em>data=writeback</em>, но она гораздо быстрее полного журналирования. Режим <em>data=journal &gt;</em> обеспечивает полное журналирование метаданных и самих данных. Данные сначала пишутся в журнал и потом только переносятся на постоянное место. При аварийных ситуациях журнал можно перечитать – приведя данные в непротиворичивое состояние. Данный режим самый медленный, но в отдельных случаях он показывает хорошие результаты. Он имеет преимущества при одновременных операциях ввода/вывода данных (при записи и одновременном чтении, скорость чтения в тестах была выше на порядок чем при других режимах). Попробуем:</p>
<pre># df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1       397G  2.2G  375G   1% /
udev             10M     0   10M   0% /dev
tmpfs           1.6G  149M  1.5G  10% /run
tmpfs           4.0G     0  4.0G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           4.0G     0  4.0G   0% /sys/fs/cgroup
/dev/sdb1       413G   17G  376G   5% /var/lib/mysql

# /etc/init.d/captagent stop
[ ok ] Stopping captagent (via systemctl): captagent.service.
# /etc/init.d/kamailio stop
[ ok ] Stopping kamailio (via systemctl): kamailio.service.
# /etc/init.d/mysql stop
[ ok ] Stopping mysql (via systemctl): mysql.service.

В /etc/fstab выставляем data=ordered для нашего раздела mysql

UUID=4a439b75-c7aa-4bd6-ad27-88ff5f44d38d /var/lib/mysql  ext4    defaults,data=ordered        0       2

# umount /dev/sdb1
# tune2fs -o journal_data_ordered /dev/sdb1
# tune2fs 1.42.12 (29-Aug-2014)
# e2fsck -f /dev/sdb1
# e2fsck -f /dev/sdb1
e2fsck 1.42.12 (29-Aug-2014)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/sdb1: 485/27475968 files (13.2% non-contiguous), 5957890/109886720 blocks

Проверить как работает:

# dumpe2fs /dev/sdb1 | more
Default mount options:    journal_data_ordered user_xattr acl

# mount /dev/sdb1

# cat /var/log/messages
Dec 28 17:00:02 Homer-2 kernel: [174342.839424] EXT4-fs (sdb1): mounted filesystem with ordered data mode. Opts: (null)

# /etc/init.d/mysql start
# /etc/init.d/kamailio start
# /etc/init.d/captagent start</pre>
<p>Режим отключения журналирования.</p>
<p>Очень осторожно, операционная система может не загрузиться. Если мы меняем настройку – ключ ядра, то после старта система пытается проверять раздел sdb и в итоге не грузится вообще. С режимом полного отключения журналирования в журалируемой ФС надо быть крайне осторожным.</p>
<pre># nano /etc/default/grub.cfg</pre>
<p>Добавляем в существующие строки:</p>
<pre>GRUB_CMDLINE_LINUX="rootflags=data=writeback"</pre>
<p>Обновляем grub.</p>
<pre>sudo update-grub</pre>
<p>Правим fstab:</p>
<pre>mcedit /etc/fstab</pre>
<p>В моём случае, добавляем data=writeback:</p>
<pre># /var/lib/mysql was on /dev/sdc1 during installation

 UUID=4a439b75-c7aa-4bd6-ad27-88ff5f44d38d /var/lib/mysql ext4 defaults,data=writeback 0 2
 
Выполняем:

  tune2fs -o journal_data_writeback /dev/sdb1</pre>
<p>Проверяем:</p>
<pre>tune2fs -l /dev/sdb1</pre>
<p>Этот метод чреват тем, что можете потерять некоторые данные при неожиданном выключении системы, например если у вас неожиданно отключилось питание (мне это не грозит, поскольку у меня ещё батарея есть)</p>
<p><b>Веб-интерфейс Homer</b></p>
<p>Открываем IP-адрес сервера в веб-браузере, логин и пароль по умолчанию:  <em>admin / test123.<br />
</em>После успешной авторизации мы попадаем в главное меню где размещаются настраиваемые виджеты</p>
<p><a href="/wp-content/uploads/2018/06/image-21.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-16.png" alt="HOMER web interface" width="590" height="401" /></a></p>
<p>Виджет вверху слева – быстрый поиск, справа – график количества различных SIP-сообщений за указанный интервал. Сам интервал выбирается в верхнем правом углу. С выбором интервала нужно быть очень внимательным. Система запоминает какой  интервал был выбран даже после повторной авторизации. Так, после повторного входа через месяц установиться временной интервал месячной давности. Он же будет использован при поиске SIP-трейсов и отображения статистики, со всеми вытекающими “No Data Available”.</p>
<p>Меню выбора даты выглядит вот так:</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image-22.png" alt="HOMER web interface" width="537" height="453" /></p>
<p>Выставляем нужный интервал и интервал по шаблону. Можно выставить авто обновление диапазона времени. Основное меню выглядит следующим образом:</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image-23.png" alt="HOMER web interface" width="467" height="405" /></p>
<p>SIP-search – меню поиска по сохранённым SIP-трейсам. Ниже форма поиска, она настраивается.</p>
<p><a href="/wp-content/uploads/2018/06/image-24.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-17.png" alt="HOMER web interface" width="590" height="415" /></a></p>
<p>Поиск можно осуществлять как по одному из полей так и по их комбинации “И”. Можно использовать не точный поиск  наподобие <em>%7962727%.<br />
</em>Значение параметра <em>Limit Query</em> определяет какое максимальное количество результатов будет выдаваться за раз. Обращаю внимание на параметр DB Node. В Homer можно подключить кроме локальной БД, любое количество внешних БД и одновременно искать в них нужные трейсы. Например, у меня есть две инсталляции Homer с двумя отдельными БД, я подключил обе БД в веб-интерфейсе и могу искать нужные мне вызовы или в одной или сразу в двух БД. Это очень удобно. Таким образом можно агрегировать огромный объём трафика и разделить нагрузку и ускорить поиск нужных данных.</p>
<p>Не забыть проверить:</p>
<pre>root@homer-2:/etc/mysql/conf.d#  netstat -anp | grep mysql
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      12015/mysqld

nano /etc/mysql/mysql.conf.d/mysqld.cnf

#bind-address = 127.0.0.1
bind-address = 0.0.0.0


root@homer-2:/etc/mysql/mysql.conf.d# /etc/init.d/mysql restart
[ ok ] Restarting mysql (via systemctl): mysql.service.
root@homer-2:/etc/mysql/mysql.conf.d# netstat -anp | grep mysql
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      12219/mysqld</pre>
<p>Ищем по двум БД:</p>
<p><a href="/wp-content/uploads/2018/06/image-25.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-18.png" alt="HOMER web interface" width="590" height="428" /></a></p>
<p>Получаем следующий вывод:</p>
<p><a href="/wp-content/uploads/2018/06/image-26.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-19.png" alt="HOMER web interface" width="590" height="197" /></a></p>
<p>Мы нашли SIP-трейсы для указанного номера на двух узлах. При нажатии на <em>CallID</em> вызова всплывает модальное окно с детальным обменом SIP-сообщениями.</p>
<p><a href="/wp-content/uploads/2018/06/image-27.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-20.png" alt="HOMER web interface" width="590" height="613" /></a></p>
<p>Здесь есть 3 вкладки, собственно <em>Call-Flow</em> это сам трейс. Он представлен в графическом виде, стрелками указаны направления сообщений – кто инициатор и кто получатель. При нажатии на каждое из SIP-сообщений диалога открывается его полный листинг (вкладка <em>Messages</em>)</p>
<p><a href="/wp-content/uploads/2018/06/image-28.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-21.png" alt="HOMER web interface" width="590" height="489" /></a></p>
<p>На вкладке <em>Details</em> представлены все поля по которым может быть найдено сообщение. В примере ниже на изображении часть из них.</p>
<p><a href="/wp-content/uploads/2018/06/image-29.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-22.png" alt="HOMER web interface" width="540" height="848" /></a></p>
<p>Рассмотрим другие вкладки.</p>
<p>Вкладка <em>QoS Reports</em> показывает RTP статистику:</p>
<p><a href="/wp-content/uploads/2018/06/image-30.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-23.png" alt="HOMER web interface" width="590" height="349" /></a></p>
<p>Вкладка <em>Export</em> служит для экспорта вызова в различных форматах</p>
<p><a href="/wp-content/uploads/2018/06/image-31.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-24.png" alt="HOMER web interface" width="590" height="322" /></a></p>
<ul>
<li>PCAP дамп</li>
<li>Текстовый файл</li>
<li>Изображение png</li>
<li>Архивом</li>
<li>Share Cloud и Share Link крайне удобно чтобы просто отправить ссылку но настраивается отдельно.</li>
</ul>
<p>Следующий пункт меню <em>Alarm Settings.</em></p>
<p>Здесь можно добавить оповещение администратора о том что превышена заданное число тех или иных сообщений</p>
<p><a href="/wp-content/uploads/2018/06/image-32.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-25.png" alt="HOMER web interface" width="590" height="293" /></a></p>
<p>Пункт <em>Geo Chart</em> отображает статистику по IP-адресам на карте мира.<br />
Пункт <em>Get Started</em> – краткий обзор веб-интерфейса<br />
Пункт Stats: <em>VoIP Traffic</em> – статистика по трафику за заданный интервал.</p>
<p><a href="/wp-content/uploads/2018/06/image-33.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-26.png" alt="HOMER web interface" width="590" height="509" /></a></p>
<p>Пункт <em>System Admin. </em>Здесь настраиваются:</p>
<ul>
<li>Пользователи и их права. Каждый пользователь может настроить персонально виджеты и их расположение.</li>
<li>Алиасы узлов, например, чтобы в выдаче поиска вместо его IP-адреса 10.10.10.10 Homer показывал алиас 3053_CCM6-pub</li>
<li>БД Homer</li>
</ul>
<p><a href="/wp-content/uploads/2018/06/image-34.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-27.png" alt="HOMER web interface" width="590" height="211" /></a></p>
<p>Вкладка <em>IP-network</em> показывает статистику по IP.</p>
<p><a href="/wp-content/uploads/2018/06/image-35.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="HOMER web interface" src="/wp-content/uploads/2018/06/image_thumb-28.png" alt="HOMER web interface" width="590" height="374" /></a></p>
<p>Homer также имеет API при помощи которых можно получить нужную информацию путём HTTP запросов в формате JSON.</p>
<p><strong>Выводы</strong></p>
<p>Homer является отличным бесплатным решением для анализа SIP-трафика. Уже сегодня  активно используется различными компаниями и операторами связи.</p>
<p>Плюсы</p>
<ul>
<li>Простота установки и настройки</li>
<li>Отсутствие лицензирования</li>
<li>“Перемалывает” большие объёмы трафика</li>
<li>Хорошая визуализация SIP-трейсов</li>
<li>Возможность экспорта SIP-трейсов в различные форматы</li>
</ul>
<p>Минусы</p>
<ul>
<li>Отсутствие подробной документации</li>
<li>Требователен к дисковой подсистеме</li>
<li>“Тихая” потеря трафика при высокой нагрузке</li>
</ul>
<p><em>Автор: Игнат Кудрявцев</em></p><p>The post <a href="https://ucexpert.ru/archives/7276">Обзор Homer 5</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://ucexpert.ru/archives/7276/feed</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Cisco RPS 2300 и замена БП Catalyst 3750</title>
		<link>https://ucexpert.ru/archives/7249</link>
					<comments>https://ucexpert.ru/archives/7249#comments</comments>
		
		<dc:creator><![CDATA[Игнат Кудрявцев]]></dc:creator>
		<pubDate>Sat, 28 Apr 2018 20:43:41 +0000</pubDate>
				<category><![CDATA[Советы]]></category>
		<category><![CDATA[Catalyst]]></category>
		<category><![CDATA[Cisco]]></category>
		<category><![CDATA[Коммутаторы]]></category>
		<guid isPermaLink="false">http://www.ucexpert.ru/?p=7249</guid>

					<description><![CDATA[<p>Главная проблема системы резервного питания Cisco RPS 2300 из за которой вообще нужен мануал и точное понимание, что вы делаете в следующем: при отключении кабеля<br />
резервного питания RPS от коммутатора  при работающем основном источнике ЭЛЕКТРОПИТАНИЕ НА ...</p>
<p>The post <a href="https://ucexpert.ru/archives/7249">Cisco RPS 2300 и замена БП Catalyst 3750</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Главная проблема системы резервного питания Cisco RPS 2300 из за которой вообще нужен мануал и точное понимание, что вы делаете в следующем: при отключении кабеля<br />
<span id="more-7249"></span>резервного питания RPS от коммутатора  при работающем основном источнике ЭЛЕКТРОПИТАНИЕ НА КОММУТАТОРЕ ОТКЛЮЧИТСЯ, если не перевести в Standby линию электропитания RPS. То есть, получается следующая ситуация: если вы воткнули кабель от RPS в коммутатор, то без манипуляций с RPS вы его без потери питания на коммутаторе не отключите. А чтобы всё сделать правильно, нужно очень внимательно прочитать мануал, а ещё лучше сначала протестировать, как это работает, такая возможность есть не всегда. Итак, вкратце (подробно в инструкции Cisco по RPS): есть «голова» на ней всего две кнопки управления. Три диода (см. рисунок ниже) состояния  всей системы резервного питания  RPS 2300 (номера 1-3) и номер 4 состоящий 6 диодов для каждого из шести разъёмов резервного электропитания коммутаторов.</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="image" src="/wp-content/uploads/2018/04/image-20.png" alt="image" width="451" height="325" /><br />
Значения 1 кнопки Standby/Active LED приведены в таблице ниже:</p>
<div align="center">
<table cellspacing="0" cellpadding="0" align="center">
<tbody>
<tr>
<td valign="top" width="111">Название диода (LED)</td>
<td valign="top" width="99">Off</td>
<td valign="top" width="118">Зелёный</td>
<td valign="top" width="118">Мигает жёлтым</td>
<td valign="top" width="118">Желтый</td>
</tr>
<tr>
<td valign="top" width="111">Standby/Active</td>
<td valign="top" width="99">Устройство выключено</td>
<td valign="top" width="118">RPS 2300 в активном режиме может резервировать электропитание от коммутатора</td>
<td valign="top" width="118">RPS 2300 в режиме выбора.<br />
Выбранный порт в режиме ожидания и не готов резервировать электропитание коммутатора</td>
<td valign="top" width="118">Модули электропитания не совместимы друг с другом, или RPS перегрелся или еще с ним что-то.</td>
</tr>
</tbody>
</table>
</div>
<p>Значения на первом из шести диодов линий резервного электропитания DC Output LED показывают статус линии. Каждый диод отвечает за соответствующее гнездо, куда включен кабель от коммутатора (всё вместе образует линию электропитания).</p>
<table cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="278">
<p>Цвет диода</p>
</td>
<td valign="top" width="288">Статус линии DC Output LED</td>
</tr>
<tr>
<td valign="top" width="278">
<p>Off</p>
</td>
<td valign="top" width="288">RPS не включен или ничего не подключено к DC Output коннектору (линии)</td>
</tr>
<tr>
<td valign="top" width="278">
<p>Зелёный</p>
</td>
<td valign="top" width="288">К RPS подключена к коммутатору и она готова к резервированию питания</td>
</tr>
<tr>
<td valign="top" width="278">
<p>Мигает зелёным</p>
</td>
<td valign="top" width="288">На на RPS переключился коммутатор и он получает с неё электропитание.</td>
</tr>
<tr>
<td valign="top" width="278">
<p>Мигает жёлтым</p>
</td>
<td valign="top" width="288">RPS в режиме Standby или в режиме ожидания.(есть питание на RPS но она не включена)</td>
</tr>
<tr>
<td valign="top" width="278">
<p>Жёлтый</p>
</td>
<td valign="top" width="288">RPS недоступна</td>
</tr>
<tr>
<td valign="top" width="278">
<p>Мигает жёлтым и зелёным</p>
</td>
<td valign="top" width="288">Когда вы нажимаете кнопку</p>
<p>Select, диод DC output LEDs показывает статус каждого порта электропитания, когда вы выбираете нужный порт</p>
<p>LED этого порта мигает зелёным и жёлтым.</td>
</tr>
</tbody>
</table>
<p>Кнопка Select служит для выбора или всех портов или индивидуального порта RPS<br />
Кнопка Standby/Active для изменения  выбранных портов (или всех портов) между режимом ожидания standby mode (мигает жёлтым) или активного режима (горит зелёным). STDBY/ACTIVE LED диод отображает статус конкретного порта.<br />
После включения RPS 2300 все порты находятся в активном режиме<br />
Для изменения состояния всего RPS 2300 или конкретного пора в активный режим или режим ожидания, нужно сделать следующее:<br />
Нажать кнопку Select. При нажатии один раз, будут выбраны все порты – они одновременно замигают желтым и зелёным цветом, продолжайте нажимать кнопку Select пока не замигает нужный порт, также зелёным и жёлтым цветом, теперь нажмите кнопку Standby/Active для установки порта линии электропитания в активный или режим ожидания, повторите процедуру для всех нужных портов.<br />
Важно!!! Если вы нажмёте кнопку Standby/Active на RPS 2300 до нажатия кнопки Select, RPS ПЕРЕКЛЮЧИТ ВСЕ 6 ПОРТОВ между активным режимом и режимом ожидания. Если это произошло нужно нажать кнопку Select ещё раз для выбора нужного порта.<br />
Когда RPS 2300 в режиме ожидания, все диоды портов к которым подключены коммутаторы мигают жёлтым, это значит что RPS 2300 подключен, но не функционирует.<br />
При нажатии кнопки Standby/Active на выбранном порте линии электропитания, цвет диода порта изменит цвет на зелёный указывая что RPS 2300 резервировать линию электропитания порта.</p>
<p>Если основное электропитание на коммутаторе отключилось, то диод DC Output LED будет мигать зелёным сигнализируя что электропитание переключено на RPS 2300.<br />
Теперь, даже если на основном источнике вновь появилось электропитание, коммутатор всё равно будет брать его от RPS и если вы просто вытащите из коммутатора кабель резервного питания, то он попросту выключится, автоматом назад он не переключится. И тут многие сразу удивятся, ведь любой сервер с двумя блоками питания или подобное устройство с нормальным резервированием питания не выключится! Но не устройство зарезервированное Cisco RPS2300!<br />
Чтобы его переключить назад, надо перевести  линию коммутатора (а не всю RPS!) на RPS в режим Standy путём нажатия на кнопку Standby/Active,  затем  кнопкой Select выбрать нужную линию (должна замигать желто-зелёным), нажать Standby/Active, диод линии должен замигать Жёлтым и соответствующий коннектор DC Output также замигать жёлтым.<br />
Вот после этого коммутатор вновь начнёт работать от основного источника.<br />
Если коммутатор переключился на резервное питание, лучше перевести его назад, так как если что случиться с RPS коммутатор выключится.<br />
Есть ещё один вариант: из консоли свитча перевести порт rps из состояния active в standby это описано на странице 12-29 руководства Catalyst 3750 Switch Software Configuration Guide:</p>
<blockquote>
<p>If you do not want the RPS 2300 to provide power to a switch, but do not want to disconnect the cable between the switch and the RPS 2300, use the power rps switch-number port rps-port-id mode standby user EXEC command.<br />
mode –  Set the mode of the RPS 2300 port:<br />
•    active  – The RPS 2300 can provide the power to a switch when the switch internal<br />
power supply cannot.<br />
•    Standby –The RPS 2300 is not providing power to a switch. The default mode for RPS ports is active.</p>
</blockquote>
<p>Итак,<br />
чтобы переключать на нужный порт нужно нажать кнопку Select столько раз чтобы замигал номер диода соответствующий разъёму (DC Output LEDs) куда подключен кабель.<br />
Если диод Standby/Active LED мигает жёлтым то RPS 2300 находится в режиме Standby, те выключено. При отключении основного питания на RPS переключения не будет и коммутатор отключится.<br />
Если Standby/Active LED выключен, то один из блоков питания RPS  не подключен.<br />
Если один или больше разъём RPS (DC Output LEDs) мигает жёлтым, то он находится в режиме Standby, при помощи кнопки Standby/Active его нужно переключить в активный режим (Ready), еще может быть вариант что RPS не может подключиться к устройству.<br />
Если коммутатор подключен к основному питанию, нужно убедиться что RPS Standby/Active LEDs горит зелёным, если это не так, мигает жёлтым, то система не будет резервировать питание.<br />
Далее, включаем коммутатор в коннектор DC Output при помощи силового кабеля, порт должен загореться зелёным, это значит, что коммутатор готов резервировать систему.<br />
Мануал где всё описано <a href="https://www.cisco.com/c/en/us/td/docs/switches/power_supplies/rps2300/hardware/installation/guide/2300hig.html" target="_blank">Cisco Redundant Power System 2300 Hardware Installation Guide</a>.</p>
<p>Лучше сразу купить коммутатор с двумя блоками питания, чем потом докупать такую хитрую штуку, которая, кстати, давно уже End-of-sale, а если вам нужно её использовать, то очень внимательно читайте инструкцию во избежание потери питания на коммутаторе.</p>
<p><strong>Несколько фотографий RPS 2300</strong></p>
<p>Шасси и вытащенные из него блоки питания.</p>
<p><a href="/wp-content/uploads/2018/04/IMG_1535.jpg" target="_blank"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Cisco RPS 2300" src="/wp-content/uploads/2018/04/IMG_1535_thumb.jpg" alt="Cisco RPS 2300" width="590" height="393" /></a></p>
<p><a href="/wp-content/uploads/2018/04/IMG_1563.jpg" target="_blank"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Cisco RPS 2300" src="/wp-content/uploads/2018/04/IMG_1563_thumb.jpg" alt="Cisco RPS 2300" width="590" height="393" /></a></p>
<p><a href="/wp-content/uploads/2018/04/IMG_1520.jpg" target="_blank"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Cisco RPS 2300" src="/wp-content/uploads/2018/04/IMG_1520_thumb.jpg" alt="Cisco RPS 2300" width="590" height="393" /></a></p>
<p>Порты линий электропитания для подключения силовых кабелей.</p>
<p><a href="/wp-content/uploads/2018/04/IMG_1512.jpg" target="_blank"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Cisco RPS 2300" src="/wp-content/uploads/2018/04/IMG_1512_thumb.jpg" alt="Cisco RPS 2300" width="590" height="393" /></a></p>
<p><a href="/wp-content/uploads/2018/04/IMG_1544.jpg" target="_blank"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Cisco RPS 2300" src="/wp-content/uploads/2018/04/IMG_1544_thumb.jpg" alt="Cisco RPS 2300" width="590" height="393" /></a></p>
<p>Кабель питания для коммутаторов, очень добротно сделан. Стоят такие кабели доброго наверное из за логотипа Cisco на них.</p>
<p><a href="/wp-content/uploads/2018/04/IMG_1567.jpg" target="_blank"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Cisco RPS 2300" src="/wp-content/uploads/2018/04/IMG_1567_thumb.jpg" alt="Cisco RPS 2300" width="590" height="393" /></a></p>
<p><a href="/wp-content/uploads/2018/04/IMG_1568.jpg" target="_blank"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Cisco RPS 2300" src="/wp-content/uploads/2018/04/IMG_1568_thumb.jpg" alt="Cisco RPS 2300" width="590" height="393" /></a></p>
<p><a href="/wp-content/uploads/2018/04/IMG_1569.jpg" target="_blank"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Cisco RPS 2300" src="/wp-content/uploads/2018/04/IMG_1569_thumb.jpg" alt="Cisco RPS 2300" width="590" height="393" /></a></p>
<p>Заглушки шасси.</p>
<p><a href="/wp-content/uploads/2018/04/IMG_1576.jpg" target="_blank"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Cisco RPS 2300" src="/wp-content/uploads/2018/04/IMG_1576_thumb.jpg" alt="Cisco RPS 2300" width="590" height="393" /></a></p>
<p>Комплект крепления шасси.</p>
<p><a href="/wp-content/uploads/2018/04/IMG_1577.jpg" target="_blank"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Cisco RPS 2300" src="/wp-content/uploads/2018/04/IMG_1577_thumb.jpg" alt="Cisco RPS 2300" width="590" height="393" /></a></p>
<p><strong>Замена блока питания на коммутаторе Cisco Catlyst 3750</strong></p>
<p>Заказал такой БП: LITEON PA-1201-1 Cisco</p>
<p>Вообще, купил Cisco RPS2300 потому что на Cisco Catlyst 3750 сгорел блок питания, вероятно из за скачка напряжения. Коммутатор работал до этого около пяти лет постоянно. Заменил в нем БП на такой как на фотографии ниже, это достаточно просто сделать. А вот найти и купить такой блок питания было не просто.</p>
<p><a href="/wp-content/uploads/2018/04/IMG_1546.jpg" target="_blank"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="LITEON PA-1201-1 Cisco блок питания Catalyst 3750" src="/wp-content/uploads/2018/04/IMG_1546_thumb.jpg" alt="LITEON PA-1201-1 Cisco блок питания Catalyst 3750" width="590" height="393" /></a></p>
<p><a href="/wp-content/uploads/2018/04/IMG_1548.jpg" target="_blank"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="LITEON PA-1201-1 Cisco блок питания Catalyst 3750" src="/wp-content/uploads/2018/04/IMG_1548_thumb.jpg" alt="LITEON PA-1201-1 Cisco блок питания Catalyst 3750" width="590" height="393" /></a></p>
<p>Коммутатор Cisco Catalyst 3750 в разобранном состоянии без блока питания<br />
<a href="/wp-content/uploads/2018/04/IMG_1580.jpg" target="_blank"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="LITEON PA-1201-1 Cisco блок питания Catalyst 3750" src="/wp-content/uploads/2018/04/IMG_1580_thumb.jpg" alt="LITEON PA-1201-1 Cisco блок питания Catalyst 3750" width="590" height="393" /></a></p>
<p>Уже с новым блоком питания</p>
<p><a href="/wp-content/uploads/2018/04/IMG_1586.jpg" target="_blank"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="LITEON PA-1201-1 Cisco блок питания Catalyst 3750" src="/wp-content/uploads/2018/04/IMG_1586_thumb.jpg" alt="LITEON PA-1201-1 Cisco блок питания Catalyst 3750LITEON PA-1201-1 Cisco блок питания Catalyst 3750" width="590" height="393" /></a></p>
<p>Подключается вот таким коннектором</p>
<p><a href="/wp-content/uploads/2018/04/IMG_1583.jpg" target="_blank"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="LITEON PA-1201-1 Cisco блок питания Catalyst 3750" src="/wp-content/uploads/2018/04/IMG_1583_thumb.jpg" alt="LITEON PA-1201-1 Cisco блок питания Catalyst 3750" width="590" height="393" /></a><br />
После установки коммутатор заработал как и прежде.</p><p>The post <a href="https://ucexpert.ru/archives/7249">Cisco RPS 2300 и замена БП Catalyst 3750</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://ucexpert.ru/archives/7249/feed</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Обзор удачной реализации интерфейса виртуальной АТС (ВАТС)</title>
		<link>https://ucexpert.ru/archives/7211</link>
		
		<dc:creator><![CDATA[Игнат Кудрявцев]]></dc:creator>
		<pubDate>Mon, 02 Apr 2018 20:50:39 +0000</pubDate>
				<category><![CDATA[Обзоры и тесты]]></category>
		<category><![CDATA[IP PBX]]></category>
		<category><![CDATA[IP АТС]]></category>
		<category><![CDATA[VoIP]]></category>
		<category><![CDATA[Виртуальтая АТС]]></category>
		<guid isPermaLink="false">http://www.ucexpert.ru/?p=7211</guid>

					<description><![CDATA[<p>В обзоре представлен пример простой и понятной реализации веб-интерфейса для виртуальной АТС (ВАТС) или облачной АТС (ОАТС). Так как обзор не рекламный, никаких упоминаний о разработчике в обзоре не будет. Обзор ориентирован скорее не на ...</p>
<p>The post <a href="https://ucexpert.ru/archives/7211">Обзор удачной реализации интерфейса виртуальной АТС (ВАТС)</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>В обзоре представлен пример простой и понятной реализации веб-интерфейса для виртуальной АТС (ВАТС) или облачной АТС (ОАТС). Так как обзор не рекламный, никаких упоминаний о разработчике в обзоре не будет. Обзор ориентирован скорее не на конечных потребителей услуги, а на специалистов занимающихся данной услугой, которым было бы интересно познакомиться с вариантом реализации логики такой услуги.</p>
<p><span id="more-7211"></span></p>
<p>Простота и удобство настройки виртуальной АТС через веб-интерфейс сегодня зачастую определяет успех и востребованность той или иной виртуальной АТС на рынке, поэтому многие разработчики борются за юзабилити графического интерфейса дабы реализовать концепцию «Easy PBX»(перевод с англ. Простая АТС), это когда ВАТС может настроить и использовать потребитель услуги не являющийся специалистом в области телефонии, тем более, технологий VoIP. Данная реализация является простой и удобной, приближенной к «Easy PBX», поэтому я решил написать о ней. Кстати, на вопрос чем отличается облачная АТС (ОАТС) от виртуальной АТС (ВАТС) могу дать ответ: в целом ничем не отличается, просто разные названия одной сути.</p>
<p>Данная ВАТС полностью управляется через веб-браузер при помощи веб-интерфейса.</p>
<p>В веб-интерфейсе есть два уровня доступа:</p>
<ul>
<li>
<div align="justify">Администратор с полными правами – «видит” все настройки ВАТС.</div>
</li>
<li>
<div align="justify">Пользователь, «не видит” никаких настроек – рабочей области сценария и элементы схемы, но видит всю (и свою и чужую) историю вызовов и записи разговоров</div>
</li>
</ul>
<p><a href="/wp-content/uploads/2018/04/image.png"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Визулазированный Call Flow ВАТС" src="/wp-content/uploads/2018/04/image_thumb.png" alt="Визулазированный Call Flow ВАТС" width="590" height="356" /></a></p>
<p>Мне очень понравилась идея настройки виртуальной АТС (ВАТС) – слева в меню элементы схемы кружки – логические модули содержащие функции обработки вызова, например, голосовое меню, группа пользователей, анонс, внутренний пользователь, справа «рабочий стол» или область сценария, на который помещаются эти логические элементы в нужном порядке, начиная от точки поступления вызова вверху (например, входящий звонок с городского номера) и его выхода из логики виртуальной АТС внизу (например, на SIP-абонента), затем, в зависимости от желаемого сценария, модули соединяются линиями – логическими связями, которые определяют какой логический модуль будет следовать после завершения обработки вызова в предыдущем модуле. Например, модуль, «Входящий вызов» с городского номера – сюда первым делом попадает позвонивший в компанию клиент, в модуле можно включить мелодию вместо гудков, дальше, в соответствии с тем как мы решили строить сценарий, для нашего входящего вызова, перетаскиваем следующий модуль из меню слева – «Элементы схемы» и соединяем с предыдущим, например, фильтр звонков. В модуле «Фильтр звонков» вводим А-номера нежелательных клиентов, которых хотим отфильтровать, на выходе из этого модуля есть два варианта:</p>
<p>«Да» – вызов уходит по этому пути если в фильтре «попался» указанный номер, отправляем его на следующий модуль «Анонс», где проигрывается сообщение что компания не работает, затем передается уведомление по API – следующий модуль и отбой,</p>
<p>«Нет» – в этом случае на модуль «График работы». В модуле «График работы» проверяем расписание, если сейчас не рабочие часы компании, что соответствует результату «Нет», отправляем вызов на модуль «Анонс» где ему сообщается что «Мы закрыты» и вешается трубка. Если в данный момент рабочие часы, то вызов направляется на по пути «Да» на следующий модуль «Голосовое меню», где позвонившему проигрывается приветствие, здесь он может нажатием кнопки на телефоне (DTMF-сигналом) выбрать с каким отделом соединиться или подождать ответа оператора. И так далее.<br />
Схема получается очень простой и наглядной. Для тестирования я создал сценарий представленный ниже.</p>
<p><a href="/wp-content/uploads/2018/04/image-1.png"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Визулазированный Call Flow ВАТС" src="/wp-content/uploads/2018/04/image_thumb-1.png" alt="Визулазированный Call Flow ВАТС" width="590" height="730" /></a></p>
<p>Теперь по каждому модулю виртуальной АТС (ВАТС). Как я написал выше, модуль — это логический элемент общего сценария обработки вызова, пример которого представлен выше. Вызов с городского номера попадает в сценарий, двигается сверху вниз, проходя через логические модули обрабатывается в соответствии с настройками, указанными в этих модулях. На исходящую связь на внутренних номерах каждый из которых представлен отдельным модулем указывается каким городским номером закрывать внутренний номер.</p>
<p>При добавлении модулей в рабочую область они автоматически сохраняются, но клонировать модули нельзя. Если в дереве ошибка – сразу сброс. Есть интерактивная справка – описание большинства полей. Плюс есть общая справка с анимацией.</p>
<p><b>Модуль «Входящий звонок»</b></p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль Входящий звонок" src="/wp-content/uploads/2018/04/image-2.png" alt="Модуль Входящий звонок" width="205" height="93" /></p>
<p>Модуль является отправной точкой обработки входящего вызова. Тут можно настроить только мелодию вместо гудков.</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль Входящий звонок ВАТС" src="/wp-content/uploads/2018/04/image-3.png" alt="Модуль Входящий звонок ВАТС" width="383" height="558" /></p>
<p><b>Модуль «Фильтр звонков»</b></p>
<p>Позволяет отфильтровать вызовы оп А-номерам или их маскам.</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль «Фильтр звонков» ВАТС" src="/wp-content/uploads/2018/04/image-4.png" alt="Модуль «Фильтр звонков» ВАТС" width="256" height="113" /></p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль «Фильтр звонков» ВАТС" src="/wp-content/uploads/2018/04/image-5.png" alt="Модуль «Фильтр звонков» ВАТС" width="385" height="400" /></p>
<p>Определяет куда пойдут вызовы по условию Фильтра – подключаем на «Да». Будь то Сотрудник, Группа или другой элемент. На «Нет» уйдут все остальные звонки.</p>
<p><b>Модуль «График Работы»</b></p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль График Работы" src="/wp-content/uploads/2018/04/image-6.png" alt="Модуль График Работы" width="234" height="107" /></p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль График Работы" src="/wp-content/uploads/2018/04/image-7.png" alt="Модуль График Работы" width="382" height="549" /></p>
<p>Проверяет время, если фильтр по временным интервалам совпал с текущем временем, вызов уходит по направлению «Да», в противном случае – «Нет»</p>
<p>Ограничения:</p>
<ul>
<li>
<div align="justify">Только недельное расписание на 7 дней, без дат в году</div>
</li>
<li>
<div align="justify">Нельзя настроить несколько рабочих интервалов для одного дня, но это можно решить каскадированием модулей «График работы» один за другим</div>
</li>
</ul>
<p><b>Модуль «Голосовое меню»</b></p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль Голосовое меню" src="/wp-content/uploads/2018/04/clip_image001.png" alt="Модуль Голосовое меню" width="279" height="95" /></p>
<p><a href="/wp-content/uploads/2018/04/clip_image002.png"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль Голосовое меню" src="/wp-content/uploads/2018/04/clip_image002_thumb.png" alt="Модуль Голосовое меню" width="383" height="532" /></a><b></b></p>
<p>Здесь можно загрузить свой голосовой файл или ввести текст, который проговаривает речевой синтезатор, когда вызов попадает в данный модуль. Загруженное голосовое меню можно сразу же проиграть просто, нажав кнопку. Может проговорить женским или мужским голосом, мужской голос показался совсем не похожим не настоящий.</p>
<p>Цифры выбора с 0-9,*(звёздочка) — соответствуют кнопкам при нажатии абонента на которые вызов переводится на указанный в меню модуль. Выбор «E» – соответствует ошибочному вводу абонента.<br />
Ограничения:</p>
<ul>
<li>
<div align="justify">Нельзя указать таймаут ожидания ввода цифры меню</div>
</li>
<li>
<div align="justify">Нельзя указать сколько раз проиграть аудио файл голосового меню</div>
</li>
<li>
<div align="justify">Нельзя больше одно раза сделать ошибку ввода и остаться в меню</div>
</li>
<li>
<div align="justify">Нет возможности разрешать/запрещать набор внутреннего номера сотрудника через меню – он просто всегда работает</div>
</li>
</ul>
<p><b>Модуль «Анонс</b></p>
<p>Здесь можно загрузить свой голосовой файл или ввести текст, который проговаривает речевой синтезатор, когда вызов попадает в данный модуль. Если анонс пустой, то модуль не пропускает вызовы, сообщает звонящему что нужно загрузить файл.</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль Анонс" src="/wp-content/uploads/2018/04/clip_image003.png" alt="Модуль Анонс" width="196" height="123" /></p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль Анонс" src="/wp-content/uploads/2018/04/clip_image004.png" alt="Модуль Анонс" width="379" height="535" /></p>
<p><b>Модуль «Уведомление»</b></p>
<p>Присылает уведомления по SMS с текстом, который указан в поле «Текст уведомления» + номер звонящего.</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль Уведомление" src="/wp-content/uploads/2018/04/clip_image005.png" alt="Модуль Уведомление" width="216" height="106" /><b></b></p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль Уведомление" src="/wp-content/uploads/2018/04/image-8.png" alt="Модуль Уведомление" width="387" height="491" /></p>
<p>Ограничения:</p>
<ul>
<li>Нельзя отправлять уведомления по e-mail.</li>
</ul>
<p><b>Модуль «</b><b>API»</b></p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль API" src="/wp-content/uploads/2018/04/clip_image0017.png" alt="Модуль API" width="217" height="115" /><b></b></p>
<p>Как работает непонятно, в документации ничего нет.</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль API" src="/wp-content/uploads/2018/04/clip_image0026.png" alt="Модуль API" width="384" height="450" /></p>
<p>Вот что прилетело на сервер 84.52.94.245  (видимо стиль Call Tuch):</p>
<pre><code>47  14.093872 91.217.178.35 -&gt; 84.52.94.245 HTTP 278 GET /action=callconnected&amp;apikeytest&amp;sessionid=1521725382.23&amp;callid=1521725382.23&amp;callerid=74732500000&amp;phonenumber=78123332211 HTTP/1.1
49  14.095428 84.52.94.245 -&gt; 91.217.178.35 HTTP 868 HTTP/1.1 500 Internal Server Error  (text/html)</code></pre>
<p>А и Б номер и некие ID.</p>
<p><b>Модуль «Группа пользователей»</b></p>
<p>Модуль реализует функционал группового вызова. Когда вызов попадает в данный модуль, вызываются указанные в настройках внутренние пользователи по определённому алгоритму с определённым таймаутом.</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль «Группа пользователей»" src="/wp-content/uploads/2018/04/clip_image0036.png" alt="Модуль «Группа пользователей»" width="278" height="117" /><b></b></p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль «Группа пользователей»" src="/wp-content/uploads/2018/04/clip_image0046.png" alt="Модуль «Группа пользователей»" width="385" height="345" /><b></b></p>
<p>Примечательно, что если соединить разные цифры с одним пользователем – возникает критическая ошибка. И все соединительные линии исчезают.</p>
<p>Вероятно, в группе может быть до 9 участников. Т – это таймаут обзвона (Время в очереди), может принимать дискретные значения из списка от 30 секунд до 10 минут, также при помощи соединительной линии с T можно «запетлевать» вызов.</p>
<p>В общем это группа с функцией очереди.</p>
<p>Есть следующие стратегии (алгоритмы) обзвона</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Стратегии (алгоритмы) обзвона" src="/wp-content/uploads/2018/04/clip_image0055.png" alt="Стратегии (алгоритмы) обзвона" width="206" height="203" /></p>
<p><b>Модуль «Внутренний пользователь»</b></p>
<p>Внутренний SIP-абонент.</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль «Внутренний пользователь»" src="/wp-content/uploads/2018/04/clip_image006.png" alt="Модуль «Внутренний пользователь»" width="187" height="98" /><b></b></p>
<p>Модуль добавляет внутреннего пользователя, на котором может быть 1 SIP-терминал.</p>
<p>Вкладка «Основные»:</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль «Внутренний пользователь» ВАТС" src="/wp-content/uploads/2018/04/image-9.png" alt="Модуль «Внутренний пользователь» ВАТС" width="384" height="782" /></p>
<p>Можно добавить переадресацию на мобильный. Здесь выбирается каким городским А-номером (или АОНом) на исходящую связь закрывать данный внутренний номер. Включить или выключить запись разговоров.<br />
Тут же ещё есть одна интересная настройка «Номер в роуминге»:<br />
Выбираем нужного пользователя и вызываем меню настройки. Вводим номер сотрудника в роуминге. Сохраняем изменения.<br />
Теперь при звонке с роумингового номера на ВАТС, вызов будет отбит. Затем АТС перезвонит, и для связи с нужным абонентом нужно просто ввести его телефон.<br />
Иными словами – это обратный вызов с контролем по А-номеру. Единственный минус – не всегда А-номер из за границы корректно передаётся (может прилететь “левый” номер).</p>
<p>Настройки SIP-терминала:</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль «Внутренний пользователь» ВАТС" src="/wp-content/uploads/2018/04/image-10.png" alt="Модуль «Внутренний пользователь» ВАТС" width="382" height="470" /></p>
<p>Веб-доступ:</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль «Внутренний пользователь» ВАТС" src="/wp-content/uploads/2018/04/image-11.png" alt="Модуль «Внутренний пользователь» ВАТС" width="384" height="368" /></p>
<p>Если включить администратора, то пользователь может настраивать ВАТС, иначе сможет только просмотреть ВСЕ вызовы и послушать ВСЕ записи вызовов, а не только свои. И логин 20179 (хотя учётная запись будет основного администратора домена) трудновато запомнить, пароль тоже символьный.</p>
<p><b>Модуль «Звонок с сайта»</b></p>
<p>Заставить его работать не удалось. Но в принципе сделано просто и симпатично.<br />
Настраивается на 3 вкладках, я так и не понял, как указать кому из менеджеров должен прийти вызов.</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Модуль «Звонок с сайта» ВАТС" src="/wp-content/uploads/2018/04/image-12.png" alt="Модуль «Звонок с сайта» ВАТС" width="590" height="627" /></p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Модуль «Звонок с сайта» ВАТС" src="/wp-content/uploads/2018/04/image-13.png" alt="Модуль «Звонок с сайта» ВАТС" width="590" height="486" /></p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Модуль «Звонок с сайта» ВАТС" src="/wp-content/uploads/2018/04/image-14.png" alt="Модуль «Звонок с сайта» ВАТС" width="590" height="846" /></p>
<p>Вот как выглядит на сайте:<br />
<img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль «Звонок с сайта» ВАТС" src="/wp-content/uploads/2018/04/clip_image0019.png" alt="Модуль «Звонок с сайта» ВАТС" width="572" height="538" /></p>
<p><b><br />
</b>При нажатии на трубку разворачивается форма.</p>
<p><b>Модуль «</b><b>SIP-номер»</b></p>
<p>Можно завернуть на ВАТС SIP-номер от другого оператора.</p>
<p>Но только на входящую связь. То есть купить ВАТС без номера оператора не получится.</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль «SIP-номер»" src="/wp-content/uploads/2018/04/image-15.png" alt="Модуль «SIP-номер»" width="213" height="104" /></p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль «SIP-номер»" src="/wp-content/uploads/2018/04/image-16.png" alt="Модуль «SIP-номер»" width="381" height="450" /></p>
<p>С внешними SIP-провайдерами работает отлично.</p>
<p><b>Модуль «Удалённый доступ»</b></p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль «Удалённый доступ»" src="/wp-content/uploads/2018/04/clip_image00111.png" alt="Модуль «Удалённый доступ»" width="210" height="93" /><b></b></p>
<p>Удаленный доступ – элемент используется в схеме для того, чтобы сотрудники смогли звонить через ВАТС со своих мобильных на другие внешние номера, например, на междугородние и международные.</p>
<p>Если сотрудник звонит с мобильного, затем попадает на этот модуль, сверяется его А-номер, если он в разрешён, сотрудник может набирать любой номер и звонить от имени ВАТС.</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль «Удалённый доступ»" src="/wp-content/uploads/2018/04/image-17.png" alt="Модуль «Удалённый доступ»" width="380" height="379" /></p>
<p><b>Модуль «Внешняя АТС»</b></p>
<p>Здесь можно подключить свою АТС. На виртуальной АТС выделяется SIP-акаунт, своя АТС (например, Asterisk клиента) регистрируется при помощи этого аккаунта. Можно авторизоваться по логину и паролю, можно по IP-адресу.<br />
Выбрать городской А-номер, которым будут закрываться вызовы в город через виртуальную АТС, чтобы позвонить на АТС выделяется номер 400, внутренний абонент, например, 201 набирает 400 и попадает на виртуальная АТС.</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Модуль «Внешняя АТС»" src="/wp-content/uploads/2018/04/image-18.png" alt="Модуль «Внешняя АТС»" width="385" height="602" /></p>
<p><b>История вызовов и записи разговоров</b></p>
<p>Отлично сделано — всё просто, но вся необходимая информация присутствует. Сразу видно кто куда звонил, во сколько, кто принял вызов. Вызовы можно прослушать в браузере или скачать.<br />
Единственное – нет массовой выгрузки. Здесь не отображается стоимость совершённых вызовов.</p>
<p><a href="/wp-content/uploads/2018/04/image-19.png"><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="История вызовов и записи разговоров ВАТС" src="/wp-content/uploads/2018/04/image_thumb-2.png" alt="История вызовов и записи разговоров ВАТС" width="590" height="388" /></a></p>
<p><b>Готовые шаблоны ВАТС</b></p>
<p>Для совсем «ленивых» есть готовые шаблоны настроек, нажимаешь кнопку и есть преднастроенный вариант, например, «малый бизнес», «горячая линия», «интернет магазин» и так далее.</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; float: none; padding-top: 0px; padding-left: 0px; margin: 0px auto 5px; display: block; padding-right: 0px; border: 0px" title="Готовые шаблоны АТС" src="/wp-content/uploads/2018/04/clip_image00113.png" alt="Готовые шаблоны АТС" width="412" height="641" /><b></b></p>
<p><b>Выводы</b></p>
<p>Реализация удачная, виртуальную АТС действительно просто настроить и использовать. Тут просто один рабочий стол и конструктор. Есть готовые шаблоны настроек. Причём абонент может под своей учётной записью может настроить просто SIP-линию или целую виртуальную АТС. Грани между классическим услугами SIP-линии и виртуальной АТС стираются.<br />
Минусы:</p>
<ul>
<li>
<div align="justify">Почти полное отсутствие интеграции с CRM. Так как в графической схеме обмен с CRM может происходить в разных точках, интересно как это будет реализовать на практике.</div>
</li>
<li>
<div align="justify">Все уведомления построены только на SMS, хорошо бы добавить, e-mail и месседжер Telegram или подобный</div>
</li>
<li>
<div align="justify">Не все по всем модулям есть справка</div>
</li>
<li>
<div align="justify">Нет сервиса отправки факсов</div>
</li>
<li>
<div align="justify">Нет личного кабинета для абонента, нельзя посмотреть только свои CDR и записи вызовов</div>
</li>
<li>
<div align="justify">Нет массовой выгрузки записанных разговоров</div>
</li>
<li>
<div align="justify">В истории вызовов не отображается их стоимость</div>
</li>
<li>
<div align="justify">Ограниченная гибкость в настройки сценариев за счёт простоты – реализуются только базовые сценарии обработки вызовов</div>
</li>
<li>
<div align="justify">Завести номера сторонних операторов можно только на входящую связь</div>
</li>
<li>
<div align="justify">Сервер указан в виде IP-адреса, а не DNS имени. Для всех одинаковый</div>
</li>
<li>
<div align="justify">Для RTP используется отдельный IP-адрес, который нигде не афишируется</div>
</li>
<li>
<div align="justify">Внутренние номера нельзя менять, идут поп порядку с 200 при создании</div>
</li>
<li>
<div align="justify">В состоянии регистрации нельзя посмотреть IP-адрес с которого зарегистрирован и модель терминала (UA) пользователя</div>
</li>
<li>
<div align="justify">Есть ограничения в модуле «голосовом меню», подробнее в описании работы модуля</div>
</li>
<li>
<div align="justify">Есть ограничения в модуле «график работы», подробнее в описании работы модуля</div>
</li>
<li>
<div align="justify">Не удалось заставить работать модуль «Звонок с сайта». Также я не понял где указывается с кем из абонентов станции соединять посетителя сайта, который заказал вызов на сайте</div>
</li>
</ul><p>The post <a href="https://ucexpert.ru/archives/7211">Обзор удачной реализации интерфейса виртуальной АТС (ВАТС)</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Настройка IP-телефонов Cisco 79-й серии для работы за NAT и отладка</title>
		<link>https://ucexpert.ru/archives/7160</link>
					<comments>https://ucexpert.ru/archives/7160#comments</comments>
		
		<dc:creator><![CDATA[Игнат Кудрявцев]]></dc:creator>
		<pubDate>Thu, 15 Mar 2018 10:38:27 +0000</pubDate>
				<category><![CDATA[Техно]]></category>
		<category><![CDATA[Cisco]]></category>
		<category><![CDATA[IP-телефон]]></category>
		<category><![CDATA[IP-телефония]]></category>
		<category><![CDATA[NAT]]></category>
		<guid isPermaLink="false">http://www.ucexpert.ru/?p=7160</guid>

					<description><![CDATA[<p>Телефоны Cisco 79-й серии могут работать за NAT. Но всё не так просто. Через веб-интерфейс телефон не настроить, это связано с тем что эти телефоны предназначены для работы с АТС Cisco и автоматически настраиваются через ...</p>
<p>The post <a href="https://ucexpert.ru/archives/7160">Настройка IP-телефонов Cisco 79-й серии для работы за NAT и отладка</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Телефоны Cisco 79-й серии могут работать за NAT. Но всё не так просто. Через веб-интерфейс телефон не настроить, это связано с тем что эти телефоны предназначены для работы с АТС Cisco и автоматически настраиваются через интерфейс данной АТС, всё остальное &#8212; ручная настройка вне штатного сценария Cisco. Но так как телефоны очень хорошие, имеет смысл это сделать.</p>
<p><span id="more-7160"></span></p>
<p><strong>Примечание на 2026 год.</strong> Cisco 79XX за NAT работает, но это хрупкая legacy-схема. По возможности держите телефоны и АТС в одной управляемой сети или используйте VPN/SBC. Внешний адрес в примере ниже &#8212; документационный <code>203.0.113.10</code>; замените его на свой реальный публичный IP.</p>
<p>Пример ниже написан для телефона Cisco 7945, но также подойдет для остальных телефонов серии, например Cisco 7942, Cisco 7940 и т.д. Итак, проблемы с которыми придётся столкнуться при настройке телефона:</p>
<ul>
<li>Отсутствие веб-интерфейса (он есть, но в нём ничего не настроить)</li>
<li>Необходимость использовать TFTP-сервер и написать конфигурацию в формате XML.</li>
<li>Есть особенности настройки телефона за NAT</li>
<li>Нужно знать как посмотреть состояние телефона и включить отладку</li>
</ul>
<p>Сначала нужно обновить телефон правильной версии SIP-прошивки (cmterm-7945_7965-sip.8-5-4.zip), инструкция находится здесь: <a href="/archives/5468">/archives/5468</a></p>
<p>У нас будет две линии. Ниже приводится пример настройки для оператора Telphin.</p>
<pre><code>Линия L1:
userid/auth=000155555
pass=ClasddfH
812 3090000</code></pre>
<pre><code>Линия L2:
userid/auth=000155556
pass=ddfHClas
812 3090001
server=voice.telphin.com
port=5068</code></pre>
<p>Внешний IP-адрес и порт маршрутизатора (документационный пример внешнего IP):</p>
<pre><code>203.0.113.10:5068</code></pre>
<p>Тут важный момент, что мы указываем для первой и второй линии один и тот же входящий порт 5068 (теги &lt;sipPort&gt; на первой и второй линиях), хотя можно использовать любой другой порт. На маршрутизаторе с внешним IP-адресом (203.0.113.10) нужно его прокинуть на IP-адрес телефона (192.168.2.5) и порт (5068). В нашем примере это 192.168.2.5, порт 5068. Также мы указываем телефону, что он находится за NAT и указываем внешний IP-адрес, который будет подставляться в тегах SIP-сообщений.</p>
<pre><code>&lt;natEnabled&gt;true&lt;/natEnabled&gt;
&lt;natAddress&gt;203.0.113.10&lt;/natAddress&gt;</code></pre>
<p>Для отладки телефона нужен доступ к его консоли по SSH, для этого нужно указать логин и пароль для доступа при помощи следующих тегов:</p>
<pre><code>&lt;sshUserId&gt;cisco&lt;/sshUserId&gt;
&lt;sshPassword&gt;badpassword&lt;/sshPassword&gt;</code></pre>
<p>В примере 192.168.2.5 это IP-адрес телефона Cisco 7945. Пишем конфигурацию и загружаем её в телефон (подробности как это сделать в предыдущей инструкции <a href="/archives/5468">/archives/5468</a>):</p>
<pre><code>cat SEP00235E186B89.cnf.xml
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;device  xsi:type="axl:XIPPhone" ctiid="966" uuid="{ec039a47-2b24-d05b-6ae3-2c18e269a9df}"&gt;
&lt;fullConfig&gt;true&lt;/fullConfig&gt;
&lt;deviceProtocol&gt;SIP&lt;/deviceProtocol&gt;
&lt;sshUserId&gt;cisco&lt;/sshUserId&gt;
&lt;sshPassword&gt;56awesZ&lt;/sshPassword&gt;
&lt;devicePool&gt;
&lt;revertPriority&gt;0&lt;/revertPriority&gt;
&lt;name&gt;Default&lt;/name&gt;
&lt;dateTimeSetting&gt;
&lt;name&gt;CMLocal&lt;/name&gt;
&lt;dateTemplate&gt;D.M.Y&lt;/dateTemplate&gt;
&lt;timeZone&gt;Saudi Arabia Standard Time&lt;/timeZone&gt;
&lt;ntps&gt;
&lt;ntp&gt;
&lt;name&gt;192.168.2.5&lt;/name&gt;
&lt;ntpMode&gt;Unicast&lt;/ntpMode&gt;
&lt;/ntp&gt;
&lt;/ntps&gt;
&lt;/dateTimeSetting&gt;
&lt;callManagerGroup&gt;
&lt;name&gt;Default&lt;/name&gt;
&lt;tftpDefault&gt;false&lt;/tftpDefault&gt;
&lt;members&gt;
&lt;member  priority="0"&gt;
&lt;callManager&gt;
&lt;name&gt;Telphin&lt;/name&gt;
&lt;description&gt;ucexpert.ru&lt;/description&gt;
&lt;ports&gt;
&lt;ethernetPhonePort&gt;2000&lt;/ethernetPhonePort&gt;
&lt;sipPort&gt;5068&lt;/sipPort&gt;
&lt;securedSipPort&gt;5061&lt;/securedSipPort&gt;
&lt;mgcpPorts&gt;
&lt;listen&gt;2427&lt;/listen&gt;
&lt;keepAlive&gt;2428&lt;/keepAlive&gt;
&lt;/mgcpPorts&gt;
&lt;/ports&gt;
&lt;processNodeName&gt;127.0.0.1&lt;/processNodeName&gt;
&lt;/callManager&gt;
&lt;/member&gt;
&lt;/members&gt;
&lt;/callManagerGroup&gt;
&lt;srstInfo&gt;
&lt;name&gt;Disable&lt;/name&gt;
&lt;srstOption&gt;Disable&lt;/srstOption&gt;
&lt;userModifiable&gt;false&lt;/userModifiable&gt;
&lt;ipAddr1&gt;&lt;/ipAddr1&gt;
&lt;port1&gt;2000&lt;/port1&gt;
&lt;ipAddr2&gt;&lt;/ipAddr2&gt;
&lt;port2&gt;2000&lt;/port2&gt;
&lt;ipAddr3&gt;&lt;/ipAddr3&gt;
&lt;port3&gt;2000&lt;/port3&gt;
&lt;sipIpAddr1&gt;&lt;/sipIpAddr1&gt;
&lt;sipPort1&gt;5068&lt;/sipPort1&gt;
&lt;sipIpAddr2&gt;&lt;/sipIpAddr2&gt;
&lt;sipPort2&gt;5068&lt;/sipPort2&gt;
&lt;sipIpAddr3&gt;&lt;/sipIpAddr3&gt;
&lt;sipPort3&gt;5068&lt;/sipPort3&gt;
&lt;isSecure&gt;false&lt;/isSecure&gt;
&lt;/srstInfo&gt;
&lt;mlppDomainId&gt;-1&lt;/mlppDomainId&gt;
&lt;mlppIndicationStatus&gt;Default&lt;/mlppIndicationStatus&gt;
&lt;preemption&gt;Default&lt;/preemption&gt;
&lt;connectionMonitorDuration&gt;120&lt;/connectionMonitorDuration&gt;
&lt;/devicePool&gt;
&lt;sipProfile&gt;
&lt;sipProxies&gt;
&lt;registerWithProxy&gt;true&lt;/registerWithProxy&gt;
&lt;/sipProxies&gt;
&lt;sipCallFeatures&gt;
&lt;cnfJoinEnabled&gt;true&lt;/cnfJoinEnabled&gt;
&lt;callForwardURI&gt;x-cisco-serviceuri-cfwdall&lt;/callForwardURI&gt;
&lt;callPickupURI&gt;x-cisco-serviceuri-pickup&lt;/callPickupURI&gt;
&lt;callPickupListURI&gt;x-cisco-serviceuri-opickup&lt;/callPickupListURI&gt;
&lt;callPickupGroupURI&gt;x-cisco-serviceuri-gpickup&lt;/callPickupGroupURI&gt;
&lt;meetMeServiceURI&gt;x-cisco-serviceuri-meetme&lt;/meetMeServiceURI&gt;
&lt;abbreviatedDialURI&gt;x-cisco-serviceuri-abbrdial&lt;/abbreviatedDialURI&gt;
&lt;rfc2543Hold&gt;false&lt;/rfc2543Hold&gt;
&lt;callHoldRingback&gt;2&lt;/callHoldRingback&gt;
&lt;localCfwdEnable&gt;true&lt;/localCfwdEnable&gt;
&lt;semiAttendedTransfer&gt;true&lt;/semiAttendedTransfer&gt;
&lt;anonymousCallBlock&gt;2&lt;/anonymousCallBlock&gt;
&lt;callerIdBlocking&gt;2&lt;/callerIdBlocking&gt;
&lt;dndControl&gt;0&lt;/dndControl&gt;
&lt;remoteCcEnable&gt;true&lt;/remoteCcEnable&gt;
&lt;retainForwardInformation&gt;false&lt;/retainForwardInformation&gt;
&lt;/sipCallFeatures&gt;
&lt;sipStack&gt;
&lt;sipInviteRetx&gt;6&lt;/sipInviteRetx&gt;
&lt;sipRetx&gt;10&lt;/sipRetx&gt;
&lt;timerInviteExpires&gt;180&lt;/timerInviteExpires&gt;
&lt;timerRegisterExpires&gt;300&lt;/timerRegisterExpires&gt;
&lt;timerRegisterDelta&gt;5&lt;/timerRegisterDelta&gt;
&lt;timerKeepAliveExpires&gt;120&lt;/timerKeepAliveExpires&gt;
&lt;timerSubscribeExpires&gt;120&lt;/timerSubscribeExpires&gt;
&lt;timerSubscribeDelta&gt;5&lt;/timerSubscribeDelta&gt;
&lt;timerT1&gt;500&lt;/timerT1&gt;
&lt;timerT2&gt;4000&lt;/timerT2&gt;
&lt;maxRedirects&gt;70&lt;/maxRedirects&gt;
&lt;remotePartyID&gt;true&lt;/remotePartyID&gt;
&lt;userInfo&gt;None&lt;/userInfo&gt;
&lt;/sipStack&gt;
&lt;autoAnswerTimer&gt;1&lt;/autoAnswerTimer&gt;
&lt;autoAnswerAltBehavior&gt;false&lt;/autoAnswerAltBehavior&gt;
&lt;autoAnswerOverride&gt;true&lt;/autoAnswerOverride&gt;
&lt;transferOnhookEnabled&gt;false&lt;/transferOnhookEnabled&gt;
&lt;enableVad&gt;false&lt;/enableVad&gt;
&lt;preferredCodec&gt;none&lt;/preferredCodec&gt;
&lt;dtmfAvtPayload&gt;101&lt;/dtmfAvtPayload&gt;
&lt;dtmfDbLevel&gt;3&lt;/dtmfDbLevel&gt;
&lt;dtmfOutofBand&gt;avt&lt;/dtmfOutofBand&gt;
&lt;kpml&gt;3&lt;/kpml&gt;
&lt;natEnabled&gt;true&lt;/natEnabled&gt;
&lt;natAddress&gt;203.0.113.10&lt;/natAddress&gt;
&lt;phoneLabel&gt;Some Label&lt;/phoneLabel&gt;
&lt;stutterMsgWaiting&gt;2&lt;/stutterMsgWaiting&gt;
&lt;callStats&gt;true&lt;/callStats&gt;
&lt;offhookToFirstDigitTimer&gt;15000&lt;/offhookToFirstDigitTimer&gt;
&lt;silentPeriodBetweenCallWaitingBursts&gt;10&lt;/silentPeriodBetweenCallWaitingBursts&gt;
&lt;disableLocalSpeedDialConfig&gt;true&lt;/disableLocalSpeedDialConfig&gt;
&lt;poundEndOfDial&gt;false&lt;/poundEndOfDial&gt;
&lt;startMediaPort&gt;16384&lt;/startMediaPort&gt;
&lt;stopMediaPort&gt;32766&lt;/stopMediaPort&gt;
&lt;sipLines&gt;
&lt;line  button="1" lineIndex="1"&gt;
&lt;featureID&gt;9&lt;/featureID&gt;
&lt;featureLabel&gt;812 3090000&lt;/featureLabel&gt;
&lt;proxy&gt;voice.telphin.com&lt;/proxy&gt;
&lt;port&gt;5068&lt;/port&gt;
&lt;name&gt;000155555&lt;/name&gt;
&lt;displayName&gt;000155555&lt;/displayName&gt;
&lt;autoAnswer&gt;
&lt;autoAnswerEnabled&gt;2&lt;/autoAnswerEnabled&gt;
&lt;/autoAnswer&gt;
&lt;callWaiting&gt;3&lt;/callWaiting&gt;
&lt;authName&gt;000155555&lt;/authName&gt;
&lt;authPassword&gt;ClasddfH&lt;/authPassword&gt;
&lt;sharedLine&gt;false&lt;/sharedLine&gt;
&lt;messageWaitingLampPolicy&gt;3&lt;/messageWaitingLampPolicy&gt;
&lt;messageWaitingAMWI&gt;0&lt;/messageWaitingAMWI&gt;
&lt;messagesNumber&gt;&lt;/messagesNumber&gt;
&lt;ringSettingIdle&gt;4&lt;/ringSettingIdle&gt;
&lt;ringSettingActive&gt;5&lt;/ringSettingActive&gt;
&lt;contact&gt;000155555&lt;/contact&gt;
&lt;forwardCallInfoDisplay&gt;
&lt;callerName&gt;true&lt;/callerName&gt;
&lt;callerNumber&gt;false&lt;/callerNumber&gt;
&lt;redirectedNumber&gt;false&lt;/redirectedNumber&gt;
&lt;dialedNumber&gt;true&lt;/dialedNumber&gt;
&lt;/forwardCallInfoDisplay&gt;
&lt;/line&gt;
&lt;line  button="2" lineIndex="2"&gt;
&lt;featureID&gt;9&lt;/featureID&gt;
&lt;featureLabel&gt;812 3090001&lt;/featureLabel&gt;
&lt;proxy&gt;voice.telphin.com&lt;/proxy&gt;
&lt;port&gt;5068&lt;/port&gt;
&lt;name&gt;000155556&lt;/name&gt;
&lt;displayName&gt;000155556&lt;/displayName&gt;
&lt;autoAnswer&gt;
&lt;autoAnswerEnabled&gt;2&lt;/autoAnswerEnabled&gt;
&lt;/autoAnswer&gt;
&lt;callWaiting&gt;3&lt;/callWaiting&gt;
&lt;authName&gt;000155556&lt;/authName&gt;
&lt;authPassword&gt;ddfHClas&lt;/authPassword&gt;
&lt;sharedLine&gt;false&lt;/sharedLine&gt;
&lt;messageWaitingLampPolicy&gt;3&lt;/messageWaitingLampPolicy&gt;
&lt;messageWaitingAMWI&gt;0&lt;/messageWaitingAMWI&gt;
&lt;messagesNumber&gt;&lt;/messagesNumber&gt;
&lt;ringSettingIdle&gt;4&lt;/ringSettingIdle&gt;
&lt;ringSettingActive&gt;5&lt;/ringSettingActive&gt;
&lt;contact&gt;000155556&lt;/contact&gt;
&lt;forwardCallInfoDisplay&gt;
&lt;callerName&gt;true&lt;/callerName&gt;
&lt;callerNumber&gt;false&lt;/callerNumber&gt;
&lt;redirectedNumber&gt;false&lt;/redirectedNumber&gt;
&lt;dialedNumber&gt;true&lt;/dialedNumber&gt;
&lt;/forwardCallInfoDisplay&gt;
&lt;/line&gt;
&lt;/sipLines&gt;
&lt;externalNumberMask&gt;&lt;/externalNumberMask&gt;
&lt;voipControlPort&gt;5068&lt;/voipControlPort&gt;
&lt;dscpForAudio&gt;184&lt;/dscpForAudio&gt;
&lt;dscpVideo&gt;136&lt;/dscpVideo&gt;
&lt;ringSettingBusyStationPolicy&gt;0&lt;/ringSettingBusyStationPolicy&gt;
&lt;dialTemplate&gt;dialplan.xml&lt;/dialTemplate&gt;
&lt;alwaysUsePrimeLine&gt;false&lt;/alwaysUsePrimeLine&gt;
&lt;alwaysUsePrimeLineVoiceMail&gt;false&lt;/alwaysUsePrimeLineVoiceMail&gt;
&lt;/sipProfile&gt;
&lt;MissedCallLoggingOption&gt;10&lt;/MissedCallLoggingOption&gt;
&lt;commonProfile&gt;
&lt;phonePassword&gt;&lt;/phonePassword&gt;
&lt;backgroundImageAccess&gt;true&lt;/backgroundImageAccess&gt;
&lt;callLogBlfEnabled&gt;3&lt;/callLogBlfEnabled&gt;
&lt;/commonProfile&gt;
&lt;loadInformation&gt;SIP45.8-5-4S&lt;/loadInformation&gt;
&lt;vendorConfig&gt;
&lt;disableSpeaker&gt;false&lt;/disableSpeaker&gt;&lt;disableSpeakerAndHeadset&gt;false&lt;/disableSpeakerAndHeadset&gt;&lt;forwardingDelay&gt;1&lt;/forwardingDelay&gt;&lt;pcPort&gt;0&lt;/pcPort&gt;&lt;settingsAccess&gt;1&lt;/settingsAccess&gt;&lt;garp&gt;1&lt;/garp&gt;&lt;voiceVlanAccess&gt;0&lt;/voiceVlanAccess&gt;&lt;videoCapability&gt;0&lt;/videoCapability&gt;&lt;autoSelectLineEnable&gt;0&lt;/autoSelectLineEnable&gt;&lt;webAccess&gt;0&lt;/webAccess&gt;&lt;daysDisplayNotActive&gt;&lt;/daysDisplayNotActive&gt;&lt;displayOnTime&gt;&lt;/displayOnTime&gt;&lt;displayOnDuration&gt;&lt;/displayOnDuration&gt;&lt;displayIdleTimeout&gt;01:00&lt;/displayIdleTimeout&gt;&lt;spanToPCPort&gt;1&lt;/spanToPCPort&gt;&lt;loggingDisplay&gt;1&lt;/loggingDisplay&gt;&lt;loadServer&gt;&lt;/loadServer&gt;&lt;recordingTone&gt;0&lt;/recordingTone&gt;&lt;recordingToneLocalVolume&gt;100&lt;/recordingToneLocalVolume&gt;&lt;recordingToneRemoteVolume&gt;50&lt;/recordingToneRemoteVolume&gt;&lt;recordingToneDuration&gt;&lt;/recordingToneDuration&gt;&lt;displayOnWhenIncomingCall&gt;0&lt;/displayOnWhenIncomingCall&gt;&lt;rtcp&gt;0&lt;/rtcp&gt;&lt;moreKeyReversionTimer&gt;5&lt;/moreKeyReversionTimer&gt;&lt;autoCallSelect&gt;1&lt;/autoCallSelect&gt;&lt;logServer&gt;&lt;/logServer&gt;&lt;g722CodecSupport&gt;0&lt;/g722CodecSupport&gt;&lt;headsetWidebandUIControl&gt;0&lt;/headsetWidebandUIControl&gt;&lt;headsetWidebandEnable&gt;0&lt;/headsetWidebandEnable&gt;&lt;peerFirmwareSharing&gt;0&lt;/peerFirmwareSharing&gt;&lt;enableCdpSwPort&gt;1&lt;/enableCdpSwPort&gt;&lt;enableCdpPcPort&gt;1&lt;/enableCdpPcPort&gt;&lt;enableLldpSwPort&gt;1&lt;/enableLldpSwPort&gt;&lt;enableLldpPcPort&gt;1&lt;/enableLldpPcPort&gt;&lt;lldpAssetId&gt;&lt;/lldpAssetId&gt;&lt;powerPriority&gt;0&lt;/powerPriority&gt;&lt;ehookEnable&gt;0&lt;/ehookEnable&gt;&lt;detectCMConnectionFailure&gt;0&lt;/detectCMConnectionFailure&gt;&lt;minimumRingVolume&gt;0&lt;/minimumRingVolume&gt;&lt;handsetHeadsetMonitor&gt;1&lt;/handsetHeadsetMonitor&gt;&lt;useEnblocDialing&gt;1&lt;/useEnblocDialing&gt;&lt;SWRemoteConfig&gt;0&lt;/SWRemoteConfig&gt;&lt;PCRemoteConfig&gt;0&lt;/PCRemoteConfig&gt;&lt;PortAutoLinkSync&gt;0&lt;/PortAutoLinkSync&gt;&lt;/vendorConfig&gt;
&lt;userLocale&gt;
&lt;name&gt;English_United_States&lt;/name&gt;
&lt;uid&gt;1&lt;/uid&gt;
&lt;langCode&gt;en_US&lt;/langCode&gt;
&lt;version&gt;&lt;/version&gt;
&lt;winCharSet&gt;UTF-8&lt;/winCharSet&gt;
&lt;/userLocale&gt;
&lt;networkLocale&gt;United_States&lt;/networkLocale&gt;
&lt;networkLocaleInfo&gt;
&lt;name&gt;United_States&lt;/name&gt;
&lt;uid&gt;64&lt;/uid&gt;
&lt;version&gt;&lt;/version&gt;
&lt;/networkLocaleInfo&gt;
&lt;deviceSecurityMode&gt;1&lt;/deviceSecurityMode&gt;
&lt;idleTimeout&gt;0&lt;/idleTimeout&gt;
&lt;authenticationURL&gt;http://192.168.2.254/ccmcip/authenticate.jsp&lt;/authenticationURL&gt;
&lt;directoryURL&gt;http://192.168.2.254/xmldirectory.xml&lt;/directoryURL&gt;
&lt;idleURL&gt;&lt;/idleURL&gt;
&lt;informationURL&gt;http://192.168.2.254/GetTelecasterHelpText.jsp&lt;/informationURL&gt;
&lt;messagesURL&gt;&lt;/messagesURL&gt;
&lt;proxyServerURL&gt;&lt;/proxyServerURL&gt;
&lt;servicesURL&gt;http://192.168.2.254/xmldirectory.xml&lt;/servicesURL&gt;
&lt;dscpForSCCPPhoneConfig&gt;96&lt;/dscpForSCCPPhoneConfig&gt;
&lt;dscpForSCCPPhoneServices&gt;0&lt;/dscpForSCCPPhoneServices&gt;
&lt;dscpForCm2Dvce&gt;96&lt;/dscpForCm2Dvce&gt;
&lt;transportLayerProtocol&gt;4&lt;/transportLayerProtocol&gt;
&lt;dndCallAlert&gt;5&lt;/dndCallAlert&gt;
&lt;phonePersonalization&gt;0&lt;/phonePersonalization&gt;
&lt;singleButtonBarge&gt;0&lt;/singleButtonBarge&gt;
&lt;joinAcrossLines&gt;0&lt;/joinAcrossLines&gt;
&lt;capfAuthMode&gt;0&lt;/capfAuthMode&gt;
&lt;capfList&gt;
&lt;capf&gt;
&lt;phonePort&gt;3804&lt;/phonePort&gt;
&lt;processNodeName&gt;192.168.2.254&lt;/processNodeName&gt;
&lt;/capf&gt;
&lt;/capfList&gt;
&lt;certHash&gt;&lt;/certHash&gt;
&lt;encrConfig&gt;false&lt;/encrConfig&gt;
&lt;advertiseG722Codec&gt;1&lt;/advertiseG722Codec&gt;
&lt;mobility&gt;
&lt;handoffdn&gt;&lt;/handoffdn&gt;
&lt;dtmfdn&gt;&lt;/dtmfdn&gt;
&lt;ivrdn&gt;3999&lt;/ivrdn&gt;
&lt;dtmfHoldCode&gt;*81&lt;/dtmfHoldCode&gt;
&lt;dtmfExclusiveHoldCode&gt;*82&lt;/dtmfExclusiveHoldCode&gt;
&lt;dtmfResumeCode&gt;*83&lt;/dtmfResumeCode&gt;
&lt;dtmfTxfCode&gt;*84&lt;/dtmfTxfCode&gt;
&lt;dtmfCnfCode&gt;*85&lt;/dtmfCnfCode&gt;
&lt;/mobility&gt;
&lt;/device&gt;</code></pre>
<p>Загрузили всё в телефон и нет регистрации, что делать? Как понять что происходит, и посмотреть состояние телефона?Телефон представляет собой маленький компьютер, куда установлена операционная система, а в качестве системы ввода-вывода используются клавиатура, экран и трубка. К телефону можно подключиться по SSH, а затем посмотреть его логи, проверить состояние и прочее. Единственное что я не смог сделать &#8212; это перезагрузить телефон удаленно.<br />
Итак, в загруженной нами конфигурации мы указали логин и пароль <code>cisco badpassword</code><br />
Открываем любой SSH клиент, например putty, используя логин и пароль выше подключаемся.<br />
Сразу после ввода учётных данных нужно будет снова ввести логин и пароль пользователя, под которым мы будем выполнять дальнейшие действия.</p>
<p>Доступны следующие варианты, если посмотреть <code>/etc/passwd:</code></p>
<pre><code>$ cat /etc/passwd
root:8:0:0:Superuser:/:/bin/nologin
syslog:8:1:0:System Logging:/usr:/bin/nologin
netwk:8:2:0:Network Admin:/etc/inetd:/bin/nologin
security:8:3:1:Security Processes:/usr:/bin/nologin
debug:BQTMQYWL:4:256:Debug Shell:/usr/local:/bin/debugsh
log:OYPTEZXR:5:256:trace shell:/var:/sbin/strace
default:MZPUHGQY:256:256:Default User:/home/default:/bin/sh</code></pre>
<p>Как видно, есть три реальных пользователя, под которыми мы можем залогиниться на телефон:</p>
<pre><code>debug:BQTMQYWL:4:256:Debug Shell:/usr/local:/bin/debugsh
log:OYPTEZXR:5:256:trace shell:/var:/sbin/strace
default:MZPUHGQY:256:256:Default User:/home/default:/bin/sh</code></pre>
<p><code>default</code> &#8212; это пользователь, для которого загружается шелл операционной системы телефона под названием CNU-OS <code>debugsh</code> &#8212; под этим пользователем запускается дебаг шелл с несколькими полезными командами. <code>log</code> &#8212; под этим пользователем мы не можем вводить команды, но увидим все журналы которые включили под пользователем <code>debugsh</code>.</p>
<p>Логинимся под <code>default</code> со стандартным паролем <code>user</code>, попадаем в shell. Например, пропингуем хост ya.ru:</p>
<pre><code>$ ping ya.ru
ping: reply received from 87.250.250.242, time = 2ms
ping: reply received from 87.250.250.242, time = 1ms
ping: reply received from 87.250.250.242, time = 1ms
^C
$</code></pre>
<p>Кстати <code>voice.telphin.com</code> на ping не отвечает.</p>
<p>Дальше мы будем смотреть состояние телефона и включать нужные журналы под пользователем <code>debugsh</code>, для его запуска просто выполним команду:</p>
<pre><code>$ /bin/debugsh

00235E186B89&gt;</code></pre>
<p>Для вывода полного списка команд:</p>
<p><p>Для вывода полного списка команд:</p>
</p>
<pre><code>00235E186B89&gt; ?</code></pre>
<p>Вот некоторые полезные команды.</p>
<p>Информация о SIP-регистрациях:</p>
<pre><code>00235E186B89&gt; show register

00235E186B89&gt;
LINE REGISTRATION TABLE
Proxy Registration: ENABLED, state: REGISTERED
line  APR  state          timer       expires     proxy:port
----  ---  -------------  ----------  ----------  ----------------------------
1     .11  REGISTERED     55          37          voice.telphin.com:5068
2     .11  REGISTERED     55          37          voice.telphin.com:5068
3     ...  NONE           0           0           undefined:0
4     ...  NONE           0           0           undefined:0
5     ...  NONE           0           0           undefined:0
6     ...  NONE           0           0           undefined:0</code></pre>
<p>Вся информация по настройкам SIP, ниже часть вывода команды:</p>
<pre><code>00235E186B89&gt; show tech-sip

00235E186B89&gt;
 --------------- Show Tech Sip -----------------

 ------------- Show config-cache --------------
------ Current *Cache* Configuration ------
startMediaPort : 16384
endMediaPort : 32766
callerIdBlocking : 0
anonymousCallBlock : 0
dndCallAlert : 5
preferredCodec : none
dtmfOutofBand : avt
dtmfAvtPayload : 101
dtmfDbLevel : 3
sipRetx : 10
sipInviteRetx : 6
timerT1 : 500
timerT2 : 4000
timerInviteExpires : 180
timerRegisterExpires : 300
registerWithProxy : 1
backupProxy :
backupProxyPort : 5060
emergencyProxy :
emergencyProxyPort : 5060
outboundProxy :
outboundProxyPort : 5060
natReceivedProcessing : 0
userInfo : none
cnfJoinEnabled : 1
remotePartyID : 1
semiAttendedTransfer : 1
callHoldRingback : 0
stutterMsgWaiting : 0
cfwd_URL :
callStats : 1
autoAnswer : 0
localCfwdEnable : 1
timerRegisterDelta : 5
MaxRedirects : 70
rfc2543Hold : 0
ccm1_address : 127.0.0.1
ccm2_address :
ccm3_address :
ccm1_sipPort : 0
ccm2_sipPort : 0
ccm3_sipPort : 0
ccm1_securityLevel : 0
ccm2_securityLevel : 0
ccm3_securityLevel : 0
ccm1_isValid : 0
ccm2_isValid : 0
ccm3_isValid : 0
ccmTftp_ipAddr :
ccmTftp_port : 0
ccmTftp_isValid : 0
ccmTftp_securityLevel : 0
ccmSrst_sipIpAddr1 :
ccmSrst_sipPort1 : 5060
ccmSrst_isValid : 0
ccmSrst_securityLevel : 0
ccmSrst_isSecure : 0
connectionMonitorDuration : 120
callPickupURI : x-cisco-serviceuri-pickup
callPickupListURI : x-cisco-serviceuri-opickup
callPickupGroupURI : x-cisco-serviceuri-gpickup
meetMeServiceURI : x-cisco-serviceuri-meetme
callForwardUri : x-cisco-serviceuri-cfwdall
abbreviatedDialURI : x-cisco-serviceuri-abbrdial
callLogBlfEnabled : 1
remoteCcEnabled : 1
timerKeepaliveExpires : 120
timerSubscribeExpires : 120
timerSubscribeDelta : 5
transportLayerProtocol : 4
kpml : 3
natEnabled : 1
natAddress : 203.0.113.10
voipControlPort : 5068
myIpAddr : 192.168.2.5
myMacAddr : 0023:5e18:6b89
enableVad : 0
autoAnswerAltBehavior : 0
autoAnswerTimer : 1
autoAnswerOverride : 1
offhookToFirstDigitTimer : 15000
silentPeriodBetweenCallWaitingBursts : 10
ringSettingBusyStationPolicy : 0
dscpForCm2Dvce : 96
speakerEnabled : 1
transferOnhookEnabled : 0
retainForwardInformation : 0
dndReminderTimer : 0
rollover : 2
joinAcrossLines : 0
blfAlertToneIdle : 0
blfAlertToneBusy : 0
autoPickupEnabled : 0
loadFileName : SIP45.8-5-4S
interDigitTimer : 15000
line1_featureID : 9
line2_featureID : 9
line3_featureID : 0
line4_featureID : 0
line5_featureID : 0
line6_featureID : 0
line7_featureID : 0</code></pre>
<p>Регистрация первой линии:</p>
<pre><code>00235E186B89&gt; register line 1 1
00235E186B89&gt; Registering line 1</code></pre>
<p>Есть множество команд для включения отладки, вот их список:</p>
<pre><code>00235E186B89&gt; ?

  alias
      Creates a pseudonym or shorthand for a command

  clear cpr-memory
      cpr-memory

  clear mwi
      mwi

  cfg ui prompt
      Change prompt to a specified string

  exit
      Exit the shell

  help
      Display help for a command

  help commands
      Display this list

  debug all
      Enable/Disable all debugging

  debug cc
      cc

  debug auth
      auth

  debug config-app
      config-app

  debug cdp
      Enable cdp process debug settings

  debug cc-msg
      cc-msg

  debug cpr-memory
      cpr-memory

  debug cpr-info
      cpr-info

  debug config-cache
      config-cache

  debug dialplan
      dialplan

  debug dsp
      Enable dsp process debug settings

  debug dns
      Enable dns process debug settings

  debug fim
      fim

  debug gsm
      gsm

  debug fsm
      fsm

  debug flashfs
      Enable flashfs process debug settings

  debug dtmf
      dtmf

  debug dhcp
      Enable dhcp process debug settings

  debug inetd
      Enable inetd process debug settings

  debug jvm ALL
      NOTICE

  debug jvm AppStatus
      NOTICE

  debug jvm AutoService
      NOTICE

  debug jvm Application
      NOTICE

  debug jvm CallUI
      NOTICE

  debug jvm Go4
      NOTICE

  debug jvm Config
      NOTICE

  debug jvm Component
      NOTICE

  debug jvm CallAgent
      NOTICE

  debug jvm Http
      NOTICE

  debug jvm MediaManager
      NOTICE

  debug jvm Localization
      NOTICE

  debug jvm MIDP-LCDUI
      NOTICE

  debug jvm MIDP-MIDlet
      NOTICE

  debug jvm MIDP-Media
      NOTICE

  debug jvm MIDP-RMS
      NOTICE

  debug jvm MIDP-PushRegistry
      NOTICE

  debug jvm MIDP-MIDletSuite
      NOTICE

  debug jvm MIDP-IO
      NOTICE

  debug jvm Graphics
      NOTICE

  debug jvm PushService
      NOTICE

  debug jvm Services
      NOTICE

  debug jvm Security
      NOTICE

  debug jvm SIPCC
      NOTICE

  debug jvm SideCar
      NOTICE

  debug jvm Settings
      NOTICE

  debug jvm SubscriptionFramework
      NOTICE

  debug jvm Tftp
      NOTICE

  debug jvm System
      NOTICE

  debug jvm Util
      NOTICE

  debug jvm XML
      NOTICE

  debug jvm Video
      NOTICE

  debug jvm UserIO
      NOTICE

  debug jvm StartUp
      NOTICE

  debug jvm Properties
      NOTICE

  debug lsm
      lsm

  debug kpml
      kpml

  debug init
      Enable init process debug settings

  debug ntp
      Enable ntp process debug settings

  debug remote-cc
      remote-cc

  debug process
      Enable process process debug settings

  debug netkern
      Enable netkern process debug settings

  debug sip-adapter
      sip-adapter

  debug sip-dnd
      sip-dnd

  debug sip-dm
      sip-dm

  debug sip-presence
      sip-presence

  debug sip-reg-state
      sip-reg-state

  debug sip-messages
      sip-messages

  debug sip-trx
      sip-trx

  debug sip-task
      sip-task

  debug timers
      timers

  debug vcm
      vcm

  debug ui
      Enable UI debug setting

  debug tftpClient
      Enable tftpClient process debug settings

  debug sip-state
      sip-state

  debug secd
      Enable secure daemon debug settings

  debug imageauth
      Debug imgauthd process

  jvm logging level
      Enable jvm process to allow individual module debugging

  register bulk
      bulk

  register line
      line

  quit
      Alias for 'exit'
  test hide
      hide

  test close
      close

  test show
      show

  test open
      open

  test key
      key

  store sip-debugs
      sip-debugs

  show bulkreginfo
      bulkreginfo

  show cdp
      Show cdp configuration information

  show cpr-memory
      cpr-memory

  show cpr-msgq
      cpr-msgq

  show config-cache
      config-cache

  show dialplan
      dialplan

  show dhcp
      Show dhcp configuration information

  show dnd-settings
      dnd-settings

  show fim
      fim

  show driver
      Shows loaded drivers in the system

  show diskspace
      Displays disk usage statistics

  show fsmcnf
      fsmcnf

  show fsmb2bcnf
      fsmb2bcnf

  show fsmicom
      fsmicom

  show fsmxfr
      fsmxfr

  show fsmrelay
      fsmrelay

  show fsmdef
      fsmdef

  show fsm
      fsm

  show debug
      debug

  show inventory
      shows unique device identifier

  show kpml
      kpml

  show jvm Config

  show ipc stat
      shows ipc statistics

  show lsm
      lsm

  show memory
      show memory usage

  show load history
      shows load/image history

  show register
      register

  show sip-subscription-statistics
      sip-subscription-statistics

  show sip-publish-statistics
      sip-publish-statistics

  show remote-cc
      remote-cc

  show strpool
      strpool

  show tech
      Shows tech support related information

  show version
      Display current CNU version

  show tech-sip
      tech-sip

  show socket
      show socket information

  show process
      shows process information

  show inetd
      Show inetd configuration information

  history
      Displays the command history list</code></pre>
<p>Нас интересует SIP:</p>
<pre><code>debug sip-reg-state
debug sip-messages
debug sip-adapter</code></pre>
<p>Теперь можно посмотреть включенные журналы по команде <code>debug</code>, выходим из оболочки:</p>
<pre><code>00235E186B89&gt; exit
Exiting shell...

Logging out...</code></pre>
<p>Команда <code>$ /sbin/strace</code> запускает просмотр включенных ранее трассировок.</p>
<p>Также в телефоне есть оболочка cnush для работы с файлами телефона запускается она <code>$ /bin/cnush</code></p>
<p>В списке команд:</p>
<pre><code>% help
alias [name [command]]
unalias name
cd [dirname]
clear
exec filename [args]
exit
groups
help [args] ...
id
load svrIPaddr filename
limit [-h] [resource [limit]]
unlimit [resource]
logout
pwd
quit
resume
set [-r] var = value
unset var
setnet
shownet
setenv name value
printenv
shpri priority
size file ...
. filename
source filename
sync
touch filename
umask [mask]
ver file ...
where program
whoami</code></pre>
<p>Если не получается зайти в оболочку или включить трассировку, то, скорее всего, в системе завис процесс, например, /bin/debugsh:</p>
<pre><code>$ /bin/debugsh

Another debugsh session active. Exiting...
$</code></pre>
<p>Его легко можно удалить вот так:</p>
<pre><code>$ ps -a

 pid %cpu   state tty command
  24  0.0     run   0 /bin/login
   5  0.0     run   0 /sbin/espd
   2  0.1     run   0 /sbin/syslogd
   3  3.9     run   0 /bin/sshd
   1  0.0     run   0 /sbin/init
  19  0.0     run   0 /bin/tftpClient
  27  0.0     run   0 /sbin/rtsold
  22  1.5     run   0 /bin/sshd
   6  0.2     run   0 /sbin/strace
   4  0.0     run   0 /sbin/dhcp6
  10  0.0     run   0 /sbin/pae
   8  0.0     run   0 /sbin/imgauthd
  30  0.0     run   0 /sbin/inetd
   0 92.5     run   0 sysIdle
   9  0.0     run   0 /ubin/vieo
  18  0.0     run   0 /bin/ps
  11  0.5     run   0 /ubin/dsp
  16  8.3     run   0 /tmp/sunvm.unzip/sunvm.cnu
  20  0.0     run   0 /sbin/dhcp
  21  0.1     run   0 /sbin/dns
  29  0.0     run   0 /bin/secd
  28  0.5     run   0 /bin/sshd
  15  0.0     run   0 /bin/sh
  13  0.2     run   0 /sbin/strace
  31  0.0     run   0 /bin/ntp
  14  0.0     run   0 /bin/sh
  12  0.0     run   0 /bin/debugsh
  26  0.0     run   0 /sbin/cdp
   7  0.0     run   0 /bin/sh

$ kill 12</code></pre>
<p>С этими знаниями можно настроить телефон Cisco за NAT.</p><p>The post <a href="https://ucexpert.ru/archives/7160">Настройка IP-телефонов Cisco 79-й серии для работы за NAT и отладка</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://ucexpert.ru/archives/7160/feed</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Разграничение видов связи на Eltex SMG2016 и SMG1016M</title>
		<link>https://ucexpert.ru/archives/7148</link>
		
		<dc:creator><![CDATA[Игнат Кудрявцев]]></dc:creator>
		<pubDate>Fri, 07 Jul 2017 17:29:32 +0000</pubDate>
				<category><![CDATA[Советы]]></category>
		<category><![CDATA[Eltex]]></category>
		<category><![CDATA[SIP шлюз]]></category>
		<category><![CDATA[SMG]]></category>
		<category><![CDATA[Транковый шлюз]]></category>
		<category><![CDATA[Элтекс]]></category>
		<guid isPermaLink="false">http://www.ucexpert.ru/?p=7148</guid>

					<description><![CDATA[<p>Специалисты по Элтексу часто советуют настраивать разграничения видов связи для SIP-абонентов SMG при помощи категорий доступа. Но есть другой способ – при помощи PBX профилей и таблицы модификаторов.</p>
<p>Итак идея в общем: мы создадим несколько SIP ...</p>
<p>The post <a href="https://ucexpert.ru/archives/7148">Разграничение видов связи на Eltex SMG2016 и SMG1016M</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Специалисты по Элтексу часто советуют настраивать разграничения видов связи для SIP-абонентов SMG при помощи категорий доступа. Но есть другой способ – при помощи PBX профилей и таблицы модификаторов.</p>
<p><span id="more-7148"></span></p>
<p>Итак идея в общем: мы создадим несколько SIP профилей, по числу наборов ограничений или, иными словами, видов связи. Затем, для каждого SIP-профиля, создадим и назначим ему свою таблицу модификаторов. Каждая запись в таблице модификаторов, будет или отправлять вызов в нулевой план набора, где вызов будет уходить по одному из маршрутов или в другой план набора, где все вызовы будут сразу же терминироваться.<br />
У нас есть нулевой план, с несколькими маршрутами:</p>
<ul>
<li>SS – спецслужбы</li>
<li>Local – местная</li>
<li>Zone – Mg – зоновая и междугородняя</li>
<li>Mn – Междугородняя</li>
</ul>
<p>Все вызовы улетают в транковую группу «SS7-Vimpelcom».</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Рис. Eltex SMG. Параметры плана нумерации" src="/wp-content/uploads/2017/07/1.jpg" alt="Рис. Eltex SMG. Параметры плана нумерации" width="590" height="586" /></p>
<p><em>Рис. Eltex SMG. Параметры плана нумерации</em></p>
<p>Теперь добавим ещё один план нумерации «План #2».<br />
Для этого перейдём в «Системные параметры» и увеличим значение «Количество активных планов нумерации» на один, у меня это будет три, так как было два плана нумерации.</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Рис. Eltex SMG. Системные параметры" src="/wp-content/uploads/2017/07/2.jpg" alt="Рис. Eltex SMG. Системные параметры" width="542" height="257" /></p>
<p><em>Рис. Eltex SMG. Системные параметры</em></p>
<p>Применяем.<br />
Теперь переходим в новый план нумерации, у меня это «NumberPlan#2»<br />
затем добавляем префикс с маской <b>(x.) </b>который уходит в пустую транковую группу.</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Рис.Eltex SMG. План нумерации" src="/wp-content/uploads/2017/07/3.jpg" alt="Рис.Eltex SMG. План нумерации" width="590" height="437" /><br />
<em>Рис.Eltex SMG. План нумерации</em></p>
<p>Таким образом, любой вызов попавший в этот план набора отобьется в SIP<br />
вот так:</p>
<p><code>6.881720137 84.52.72.26 -&gt; 194.154.91.66 SIP/SDP 1212 Request: INVITE sip:81033147756180@194.154.91.66:9955 | , with session description<br />
6.912345534 194.154.91.66 -&gt; 84.52.72.26 SIP 441 Status: 100 Trying |<br />
6.957838076 194.154.91.66 -&gt; 84.52.72.26 SIP 516 Status: 404 Not Found |<br />
6.967055910 84.52.72.26 -&gt; 194.154.91.66 SIP 703 Request: ACK sip:81033147756180@194.154.91.66:9955 |<br />
</code></p>
<p>То есть &#8212; «Not Found».</p>
<p>В CDR строка будет выглядить так:</p>
<p><code>;2017-07-07 13:20:59;0;2;unavailable trunk line;192.168.1.245;sip-user;Subscriber#001;747311110001;;0.0.0.0;;;81033147756180;;2017-07-07 13:20:59;2017-07-07 13:20:59;</code></p>
<p>С причиной q.931 равной <b>2 -No route to destination.</b><br />
Теперь создадим таблицу модификаторов, которая разрешает только вызовы на спецслужбы, 8800 и местные вызовы по городу Воронеж. В конце добавим правило, которое запретит все остальные вызовы.</p>
<p>Имя модификатора для примера – «Line-SS7-local»</p>
<p>Добавляем модификаторы которые «ловят» вызовы по маске Б-номеров, затем нормализуют -номера в формат E.164, не изменяют план нумерации, вызов попадёт в «правильный» нулевой план нумерации.<br />
Например, 8800:</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Рис. Eltex SMG. Модификатор плана нумерации" src="/wp-content/uploads/2017/07/4.jpg" alt="Рис. Eltex SMG. Модификатор плана нумерации" width="552" height="945" /></p>
<p><em>Рис. Eltex SMG. Модификатор плана нумерации<br />
</em>Таким образом, создаём остальные правила.<br />
В конце добавим правило, которое запрещает всё – создадим модификатор, который ловим Б-номер по wildcard (x.)</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Рис. Eltex SMG. Модификатор плана нумерации" src="/wp-content/uploads/2017/07/5.jpg" alt="Рис. Eltex SMG. Модификатор плана нумерации" width="569" height="544" /></p>
<p><em>Рис. Eltex SMG. Модификатор плана нумерации</em></p>
<p>Правило «Deny All» запрещает МГ МН и международную связь, на вкладке «Модификация общая», мы меняем план нумерации на план, где у нас терминируются все вызовы, в нашем примере План нумерации «NumerPlan#2».<br />
В итоге должно получиться вот так:</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Рис. Eltex SMG. Таблица модификаторов" src="/wp-content/uploads/2017/07/6.jpg" alt="Рис. Eltex SMG. Таблица модификаторов" width="522" height="382" /></p>
<p><em>Рис. Eltex SMG. Таблица модификаторов</em></p>
<p>А теперь создадим PBX-профиль с именем «PBX_Profile#1-to-SS7-local» и для входящей связи и номера «CdPN» назначим созданный нами модификатор «Line-SS7-local».</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Рис. Eltex SMG. PBX профили" src="/wp-content/uploads/2017/07/7.jpg" alt="Рис. Eltex SMG. PBX профили" width="525" height="575" /></p>
<p><em>Рис. Eltex SMG. PBX профили</em><br />
Всё готово.<br />
Теперь данный профиль нужно назначить SIP-абонентам для которых разрешена только местная связь.</p>
<p><img loading="lazy" decoding="async" class="no-frame" style="background-image: none; padding-top: 0px; padding-left: 0px; margin: 0px 10px 5px 0px; display: inline; padding-right: 0px; border: 0px" title="Рис. Eltex SMG. Редактирование SIP-абонента" src="/wp-content/uploads/2017/07/8.jpg" alt="Рис. Eltex SMG. Редактирование SIP-абонента" width="568" height="704" /></p>
<p><em>Рис. Eltex SMG. Редактирование SIP-абонента</em><br />
Таким образом, можно создавать любые наборы ограничений – чаще всего это виды связи: местная, зоновая, междугородняя и международная.</p>
<p>Автор: Игнат Кудрявцев</p><p>The post <a href="https://ucexpert.ru/archives/7148">Разграничение видов связи на Eltex SMG2016 и SMG1016M</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Настройка уведомления о записи разговора для исходящих и входящих вызовов в Asterisk</title>
		<link>https://ucexpert.ru/archives/7124</link>
		
		<dc:creator><![CDATA[Игнат Кудрявцев]]></dc:creator>
		<pubDate>Tue, 11 Apr 2017 07:03:46 +0000</pubDate>
				<category><![CDATA[Техно]]></category>
		<guid isPermaLink="false">http://www.ucexpert.ru/?p=7124</guid>

					<description><![CDATA[<p>В прошлой статье мы перевели соответствия внешних и внутренних номеров на АТС Asterisk в базу данных MySQL. В данном материале мы рассмотрим пример добавления уведомления о записи разговоров для входящей и исходящей связи. Причём уведомление ...</p>
<p>The post <a href="https://ucexpert.ru/archives/7124">Настройка уведомления о записи разговора для исходящих и входящих вызовов в Asterisk</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></description>
										<content:encoded><![CDATA[<p style="text-align: justify;">В прошлой статье мы перевели соответствия внешних и внутренних номеров на АТС Asterisk в базу данных MySQL. В данном материале мы рассмотрим пример добавления уведомления о записи разговоров для входящей и исходящей связи. Причём уведомление может быть любым, ведь по сути мы добавляем воспроизведение произвольного аудиофайла перед соединением с клиентом. Это очень востребованная функция, так как если разговор записывается, то клиент, по закону, должен быть уведомлён об этом.<span id="more-7124"></span><br />
Итак, сценарий работы у нас будет следующий – для исходящей связи:<br />
В базе данных мы проставляем для каждого внутреннего номера признак проигрывать или не проигрывать уведомление о записи разговора. При исходящем вызове в базу данных передаётся внутренний номер абонента станции (в примере ниже 650), который совершает исходящий вызов, в ответ возвращается значение которое определят проигрывать или не проигрывать аудиофайл вызываемому абоненту.<br />
Для входящей связи – при входящем вызове на городской номер АТС, вызываемый городской номер (в примере 78121234567) передаётся в базу данных, откуда возвращается значение, на основании которого АТС определяет проигрывать или не проигрывать аудиофайл уведомления о записи разговора.<br />
Причём, мы рассмотрим два случая: первый – проигрывание уведомления о записи разговора после ответа АТС – состояния “сonnected” и старта тарификации вызова, второй – проигрывание уведомления о записи разговора до ответа АТС и состояния “connected”, соответственно до тарификации. Таким образом, абонент не будет платить за вызов если абонент АТС не ответил.<br />
Теперь рассмотрим техническую реализацию описанных выше сценариев.</p>
<p style="text-align: justify;"><strong>Исходящая связь<br />
</strong><br />
Чтобы проиграть аудиофайл <code>/var/lib/asterisk/sounds/ivr/razgovor_record</code> в приложении <code>Dial</code> используем параметр <code>A(имя_аудиофайла)</code>. После соединения указанный в скобках аудиофайл будет проигран.<br />
Но нам необходимо управлять через базу данных, для исходящих вызовов, с каких внутренних номеров аудиофайл уведомления о записи разговора нужно проигрывать, а для каких не нужно.<br />
Для этого добавим новый столбец в существующей таблице <code>outbound</code>.<br />
Добавим этот новый столбец после столбца <code>callerid</code> с именем <code>notification_enabled</code>, значения в столбце могут принимать следующие значения:<br />
1 – Проиграть аудиофайл уведомления<br />
0 – Не проигрывать аудиофайл уведомления<br />
Добавим столбец в <code>notification_enabled</code> таблицу <code>outbound</code>, далее приведён пример запроса в СУБД MySQL.</p>
<pre><code>mysql&gt; use astcdrdb;
mysql&gt; ALTER TABLE `outbound` ADD `notification_enabled` INT( 1 ) NOT NULL DEFAULT '0' AFTER `callerid`;</code></pre>
<p style="text-align: justify;">Теперь таблица <code>outbound</code> будет выглядеть следующим образом:</p>
<pre><code>mysql&gt; select * from outbound where internal=650;
+-----+----------+-------------+----------------------+-------+
| id | internal | callerid | <strong>notification_enabled</strong> | Notes |
+-----+----------+-------------+----------------------+-------+
| 210 | 650 | 78121234567 | <strong>0</strong> | |
+-----+----------+-------------+----------------------+-------+
1 row in set (0.00 sec)
</code></pre>
<p style="text-align: justify;">Добавим функцию, которая будет проверять значение столбца <code>notification_enabled</code> в файл <code>func_odbc.conf</code>.</p>
<pre><code>[CHECK_NOTIF_OUT_ENABLE]
dsn=asterisk
readsql=SELECT notification_enabled FROM outbound where internal='${ARG1}'</code></pre>
<p style="text-align: justify;">В консоли Asterisk применим функцию:</p>
<pre><code>aster*CLI&gt; module reload func_odbc.so</code></pre>
<p style="text-align: justify;">В выводе консоли Asterisk увидим:</p>
<pre><code>  == Registered custom function 'ODBC_CHECK_NOTIF_OUT_ENABLE'
</code></pre>
<p style="text-align: justify;">Теперь модифицируем дайлплан, файл extensions.conf.<br />
Чтобы проиграть аудиофайл <code>/var/lib/asterisk/sounds/ivr/razgovor_record</code> в приложении <code>Dial</code> используем параметр <code>A(имя_аудиофайла)</code>. После соединения указанный в параметре аудиофайл будет проигран.<br />
Начнём с контекста <code>[mg-out]</code>. Исходный вид:</p>
<pre><code>exten =&gt; _9[78][123456780]XXXXXXXXX,2,Set(__CALLER=${CALLERID(ANI)})
exten =&gt; _9[78][123456780]XXXXXXXXX,3,Set(__CALLED=7${EXTEN:2})
exten =&gt; _9[78][123456780]XXXXXXXXX,4,Set(__UID=${UNIQUEID})
exten =&gt; _9[78][123456780]XXXXXXXXX,5,Dial(SIP/RTU/7${EXTEN:2},,tTM(startrec))
</code></pre>
<p style="text-align: justify;">Модифицируем контекст, новые строки выделены жирным текстом:</p>
<pre><code>exten =&gt; _9[78][123456780]XXXXXXXXX,2,Set(__CALLER=${CALLERID(ANI)})
exten =&gt; _9[78][123456780]XXXXXXXXX,3,Set(__CALLED=7${EXTEN:2})
exten =&gt; _9[78][123456780]XXXXXXXXX,4,Set(__UID=${UNIQUEID})
<strong>exten =&gt; _9[78][123456780]XXXXXXXXX,5,NoOp(${ODBC_CHECK_NOTIF_OUT_ENABLE(${CALLER})})
exten =&gt; _9[78][123456780]XXXXXXXXX,6,Set(NOTIFICATION=${IF($["${ODBC_CHECK_NOTIF_OUT_ENABLE(${CALLER})}" = "1"]?/var/lib/asterisk/sounds/ivr/razgovor_record)})</strong>
exten =&gt; _9[78][123456780]XXXXXXXXX,7,Dial(SIP/RTU/7${EXTEN:2},,tTM(startrec)<strong>A(${NOTIFICATION})</strong>)
</code></pre>
<p style="text-align: justify;">Далее, перечитываем дайлплан командой из консоли Asterisk: <code>dialplan reload</code>.</p>
<p style="text-align: justify;">При вызове, если <code>notification_enabled=0</code>, отладочный вывод в консоли Asterisk будет следующим:</p>
<pre><code>   -- Executing [981116275136@mn:1] Set("SIP/650-00003bb2", "CALLERID(num)=78121234567") in new stack
    -- Executing [981116275136@mn:2] Set("SIP/650-00003bb2", "__CALLER=650") in new stack
    -- Executing [981116275136@mn:3] Set("SIP/650-00003bb2", "__CALLED=71116275136") in new stack
    -- Executing [981116275136@mn:4] Set("SIP/650-00003bb2", "__UID=1490019065.32064") in new stack
    -- Executing [981116275136@mn:5] NoOp("SIP/650-00003bb2",<strong> "0"</strong>) in new stack
    -- Executing [981116275136@mn:6] Set("SIP/650-00003bb2", <strong>"NOTIFICATION="</strong>) in new stack
    -- Executing [981116275136@mn:7] Dial("SIP/650-00003bb2", "SIP/RTU/71116275136,,tTM(startrec)<strong>A()</strong>") in new stack
</code></pre>
<p style="text-align: justify;">При вызове, если <code>notification_enabled=1</code>:</p>
<pre><code>  == Using SIP RTP CoS mark 5
    -- Executing [981116275136@mn:1] Set("SIP/650-00003b70", "CALLERID(num)=78121234567") in new stack
    -- Executing [981116275136@mn:2] Set("SIP/650-00003b70", "__CALLER=650") in new stack
    -- Executing [981116275136@mn:3] Set("SIP/650-00003b70", "__CALLED=71116275136") in new stack
    -- Executing [981116275136@mn:4] Set("SIP/650-00003b70", "__UID=1490018964.31913") in new stack
    -- Executing [981116275136@mn:5] NoOp("SIP/650-00003b70", <strong>"1"</strong>) in new stack
    -- Executing [981116275136@mn:6] Set("SIP/650-00003b70", <strong>"NOTIFICATION=/var/lib/asterisk/sounds/ivr/razgovor_record"</strong>) in new stack
    -- Executing [981116275136@mn:7] Dial("SIP/650-00003b70", "SIP/RTU/71116275136,,tTM(startrec)<strong>A(/var/lib/asterisk/sounds/ivr/razgovor_record)</strong>") in new stack
</code></pre>
<p><strong>Исходящая связь</strong></p>
<p style="text-align: justify;">В <a href="/archives/7025" target="_blank">предыдущем материале</a> посвященном Asterisk мы переводили входящую связь через БД, MySQL и запрашивали параметры входящего вызова из БД, существующие строки в дайлплане:</p>
<pre><code>same =&gt; n,NoOp(GET FORWARD ring_timeout,forward_after_enable,forward_after_numer,timeout_ring_after ==  ${ODBC_GET_FORWARD_AFTER_HG(${EXTEN})})
same =&gt; n,Set(ARRAY(RING_TIMEOUT,FORWARD_AFTER_ENABLE,FORWARD_AFTER_NUMBER,TIMEOUT_RING_AFTER)=${ODBC_GET_FORWARD_AFTER_HG(${EXTEN})})
</code></pre>
<p style="text-align: justify;">В данные строки нужно добавить получение ещё одного параметра <code>notification_enabled</code> из таблицы <code>inbound</code>, который будет указывать на то, нужно ли проигрывать уведомление или нет.<br />
Добавим новый столбец запросом в mysql:</p>
<pre><code>mysql&gt; use astcdrdb;
mysql&gt; ALTER TABLE `inbound` ADD `notification_enabled` INT( 1 ) NULL DEFAULT '0' AFTER `timeout_ring_after`</code></pre>
<p style="text-align: justify;">Модифицируем функцию в <code>ODBC_GET_FORWARD_AFTER_HG</code> в файле <code>func_odbc.conf</code>, то что добавлено выделено жирным шрифтом:</p>
<pre><code>[GET_FORWARD_AFTER_HG]
dsn=asterisk
readsql=SELECT ring_timeout,forward_after_enable,forward_after_numer,timeout_ring_after, <strong>notification_enabled</strong> from inbound where did='${ARG1}'
</code></pre>
<p style="text-align: justify;">Затем строки в extensions.conf:</p>
<pre><code>same =&gt; n,NoOp(GET FORWARD ring_timeout,forward_after_enable,forward_after_numer,timeout_ring_after, <strong>notification_enabled</strong> ==  ${ODBC_GET_FORWARD_AFTER_HG(${EXTEN})})
same =&gt; n,Set(ARRAY(RING_TIMEOUT,FORWARD_AFTER_ENABLE,FORWARD_AFTER_NUMBER,TIMEOUT_RING_AFTER,<strong>NOTIFICATION_ENABLED</strong>)=${ODBC_GET_FORWARD_AFTER_HG(${EXTEN})})
</code></pre>
<p style="text-align: justify;">Перечитаем файл с функциями odbc:</p>
<pre><code>aster*CLI&gt; module reload func_odbc.so
Module 'func_odbc.so' reloaded successfully.
    -- Reloading module 'func_odbc.so' (ODBC lookups)
  == Parsing '/etc/asterisk/func_odbc.conf': Found
…
  == Registered custom function 'ODBC_GET_FORWARD_AFTER_HG'
…
</code></pre>
<p style="text-align: justify;">Далее, переходим в контекст <code>[HG-NEW]</code>. Закомментируем первую строку и добавляю <code>NoOp</code>, также две строки выделенные жирным цветом. Здесь проверяется разрешено ли уведомление – значение <code>NOTIFICATION_ENABLED</code> равно 1. Если 0, то переменная <code>NOTIFICATION</code> принимает значение <code>skip</code>, в опции приложения <code>Playback</code> из переменной <code>NOTIFICATION</code> добавляется данный ключ, который указывает что если канал не в ответном состоянии, то приложение <code>Playback</code> не будет проигрывать указанный файл <code>/var/lib/asterisk/sounds/ivr/razgovor_record</code>. Первой строкой мы закомментировали приложение <code>Answer</code>, которое переводит канал в ответное состояние Connected в самом начале контекста. Поэтому эта комбинация будет работать.</p>
<p style="text-align: justify;">Получится вот так:</p>
<pre><code>;exten =&gt; _X.,1, Answer
exten =&gt; _X.,1,NoOp
same =&gt; n,Set(_MONITOR_FILENAME=IN-${EXTEN}-${STRFTIME(${EPOCH},,%Y_%m_%d[%H_%M])}-${CALLERID(num)}-${EXTEN}-${UNIQUEID})
same =&gt; n, NoOp(!!!!CALLED=${CALLED})
same =&gt; n, Set(H1=${IF($["${m1}" != ""]?SIP/${m1})})
same =&gt; n, Set(H2=${IF($["${m2}" != ""]?&amp;SIP/${m2})})
same =&gt; n, Set(H3=${IF($["${m3}" != ""]?&amp;SIP/${m3})})
same =&gt; n, Set(H4=${IF($["${m4}" != ""]?&amp;SIP/${m4})})
same =&gt; n, Set(H5=${IF($["${m5}" != ""]?&amp;SIP/${m5})})
same =&gt; n, Set(H6=${IF($["${m6}" != ""]?&amp;SIP/${m6})})
same =&gt; n, Set(H7=${IF($["${m7}" != ""]?&amp;SIP/${m7})})
same =&gt; n, Set(H8=${IF($["${m8}" != ""]?&amp;SIP/${m8})})
same =&gt; n, Set(H9=${IF($["${m9}" != ""]?&amp;SIP/${m9})})
same =&gt; n, Set(H11=${IF($["${m11}" != ""]?&amp;SIP/${m11})})
same =&gt; n, Set(H12=${IF($["${m12}" != ""]?&amp;SIP/${m12})})
same =&gt; n, Set(H13=${IF($["${m13}" != ""]?&amp;SIP/${m13})})
same =&gt; n, Set(H14=${IF($["${m14}" != ""]?&amp;SIP/${m14})})
same =&gt; n, Set(H15=${IF($["${m15}" != ""]?&amp;SIP/${m15})})
<strong>
same =&gt; n,Set(NOTIFICATION=${IF($["${NOTIFICATION_ENABLED}" = "1"]?:skip)})
same =&gt; n,Playback(/var/lib/asterisk/sounds/ivr/razgovor_record,${NOTIFICATION})</strong>

same =&gt; n,Dial(${H1}${H2}${H3}${H4}${H5}${H6}${H7}${H8}${H9}${H10}${H11}${H12}${H13}${H14}${H15},${RING_TIMEOUT},TtrM(monext))
...</code></pre>
<p style="text-align: justify;">Если переменная <code>NOTIFICATION</code> принимает значение пусто(“”), то <code>Playback</code> посылает 200OK с SDP (Connect), переводит канал в ответное состояние и проигрывает файл <code>/var/lib/asterisk/sounds/ivr/razgovor_record</code>.<br />
Таким образом аудиофайл будет воспроизводиться вне зависимости поддерживает ли операторское оборудование early media.<br />
Ниже SIP-трейс обмена сообщениями:</p>
<pre><code>Capturing on eth0
  2.329733 192.168.103.45 -&gt; 192.168.126.210 SIP/SDP 1235 Request: INVITE sip:78121234567@192.168.126.210;user=phone, with session description
  2.332353 192.168.126.210 -&gt; 192.168.103.45 SIP 631 Status: 100 Trying
  2.365530 192.168.126.210 -&gt; 192.168.103.45 SIP/SDP 913 Status: 200 OK, with session description
  2.368216 192.168.103.45 -&gt; 192.168.126.210 SIP 502 Request: ACK sip:78121234567@192.168.126.210:5060
<strong>&lt;проигрывается уведомление, состояние ответа, тарификация вызова началась&gt;
&lt;Далее вызов на внутреннего абонента&gt;</strong>
  6.840698 192.168.126.210 -&gt; 192.168.85.148 SIP/SDP 955 Request: INVITE sip:350@192.168.85.148:64141;rinstance=6372aa4716dea7bf, with session description
  6.961023 192.168.85.148 -&gt; 192.168.126.210 SIP 462 Status: 180 Ringing
 10.469290 192.168.85.148 -&gt; 192.168.126.210 SIP/SDP 841 Status: 200 OK, with session description
 10.469761 192.168.126.210 -&gt; 192.168.85.148 SIP 505 Request: ACK sip:350@192.168.85.148:64141;rinstance=6372aa4716dea7bf
 11.479193 192.168.85.148 -&gt; 192.168.126.210 SIP 578 Request: BYE sip:78121234567@192.168.126.210:5060
 11.480282 192.168.126.210 -&gt; 192.168.85.148 SIP 563 Status: 200 OK
 11.481937 192.168.126.210 -&gt; 192.168.103.45 SIP 574 Request: BYE sip:78121234567@192.168.103.45:5063;user=phone
 11.484585 192.168.103.45 -&gt; 192.168.126.210 SIP 503 Status: 200 OK
</code></pre>
<p style="text-align: justify;">Если встречный оператор поддерживает режим early media или отправку вызывающей стороне аудио в голосовом канале, то cтроку с приложением <code>Playback</code> можно модифицировать вот так:</p>
<pre><code>same =&gt; n,Set(NOTIFICATION=${IF($["${NOTIFICATION_ENABLED}" = "1"]?noanswer:skip)})</code></pre>
<p style="text-align: justify;">То есть, добавить ключ <code>noanswer</code>, вместо “”(пусто), тогда <code>Playback</code> будет проигрывать файл в предответном состоянии, то есть до состояния Connect:</p>
<pre><code>same =&gt; n,Playback(/var/lib/asterisk/sounds/razgovor_zapis1,${NOTIFICATION})</code></pre>
<p style="text-align: justify;">В sip.conf нужно<br />
Выставить в общих настройках(секция <code>[general]</code>) параметр</p>
<pre><code>prematuremedia=no</code></pre>
<p style="text-align: justify;">SIP-трейсировка будет следующий:</p>
<pre><code>0.000000 192.168.103.45 -&gt; 192.168.126.210 SIP/SDP 1235 Request: INVITE sip:78121234567@192.168.126.210;user=phone, with session description
  0.000815 192.168.126.210 -&gt; 192.168.103.45 SIP 631 Status: 100 Trying
  0.031701 192.168.126.210 -&gt; 192.168.103.45 SIP/SDP 929 Status: 183 Session Progress, with session description
  0.031775 192.168.126.210 -&gt; 192.168.103.45 RTP 214 PT=ITU-T G.711 PCMU, SSRC=0x6439ADF6, Seq=43650, Time=160, Mark
  0.032872 192.168.103.45 -&gt; 192.168.126.210 RTCP 122 Sender Report   Source description
  0.032922 192.168.103.45 -&gt; 192.168.126.210 SIP 640 Request: OPTIONS sip:78121234567@192.168.126.210;user=phone
  0.033428 192.168.126.210 -&gt; 192.168.103.45 SIP 668 Status: 200 OK
  0.051935 192.168.126.210 -&gt; 192.168.103.45 RTP 214 PT=ITU-T G.711 PCMU, SSRC=0x6439ADF6, Seq=43651, Time=320
  0.071893 192.168.126.210 -&gt; 192.168.103.45 RTP 214 PT=ITU-T G.711 PCMU, SSRC=0x6439ADF6, Seq=43652, Time=480
  0.091958 192.168.126.210 -&gt; 192.168.103.45 RTP 214 PT=ITU-T G.711 PCMU, SSRC=0x6439ADF6, Seq=43653, Time=640
<strong>&lt;проговаривание аудиофайла&gt;</strong>
…
  4.438201 192.168.126.210 -&gt; 192.168.103.45 SIP 597 Status: 180 Ringing
<strong>&lt;КПВ вызывающему абоненту&gt;
</strong></code></pre>
<p style="text-align: justify;">Вариант с поддержкой early media будет выглядеть вот так:</p>
<pre><code>;exten =&gt; _X.,1, Answer
exten =&gt; _X.,1, NoOp
same =&gt; n,Set(_MONITOR_FILENAME=IN-${EXTEN}-${STRFTIME(${EPOCH},,%Y_%m_%d[%H_%M])}-${CALLERID(num)}-${EXTEN}-${UNIQUEID})
same =&gt; n, NoOp(!!!!CALLED=${CALLED})
same =&gt; n, Set(H1=${IF($["${m1}" != ""]?SIP/${m1})})
same =&gt; n, Set(H2=${IF($["${m2}" != ""]?&amp;SIP/${m2})})
same =&gt; n, Set(H3=${IF($["${m3}" != ""]?&amp;SIP/${m3})})
same =&gt; n, Set(H4=${IF($["${m4}" != ""]?&amp;SIP/${m4})})
same =&gt; n, Set(H5=${IF($["${m5}" != ""]?&amp;SIP/${m5})})
same =&gt; n, Set(H6=${IF($["${m6}" != ""]?&amp;SIP/${m6})})
same =&gt; n, Set(H7=${IF($["${m7}" != ""]?&amp;SIP/${m7})})
same =&gt; n, Set(H8=${IF($["${m8}" != ""]?&amp;SIP/${m8})})
same =&gt; n, Set(H9=${IF($["${m9}" != ""]?&amp;SIP/${m9})})
same =&gt; n, Set(H11=${IF($["${m11}" != ""]?&amp;SIP/${m11})})
same =&gt; n, Set(H12=${IF($["${m12}" != ""]?&amp;SIP/${m12})})
same =&gt; n, Set(H13=${IF($["${m13}" != ""]?&amp;SIP/${m13})})
same =&gt; n, Set(H14=${IF($["${m14}" != ""]?&amp;SIP/${m14})})
same =&gt; n, Set(H15=${IF($["${m15}" != ""]?&amp;SIP/${m15})})

<strong>same =&gt; n,Set(NOTIFICATION=${IF($["${NOTIFICATION_ENABLED}" = "1"]?noanswer:skip)})
same =&gt; n,Playback(/var/lib/asterisk/sounds/ivr/razgovor_record,${NOTIFICATION})</strong>
same =&gt; n,Dial(${H1}${H2}${H3}${H4}${H5}${H6}${H7}${H8}${H9}${H10}${H11}${H12}${H13}${H14}${H15},${RING_TIMEOUT},TtrM(monext))
same =&gt; n,GotoIf($["${FORWARD_AFTER_ENABLE}" != "1"]?end)
same =&gt; n,GotoIf($[${REGEX("@" ${FORWARD_AFTER_NUMBER})}]?nochangecid)
same =&gt; n,Set(CALLERID(num)=${IF($["${REGEX("^7812.......$" ${EXTEN})}"]?${EXTEN}:78120001122)})
same =&gt; n(nochangecid),Dial(${FORWARD_AFTER_NUMBER},${TIMEOUT_RING_AFTER},TtrM(monext))
same =&gt; n,Goto(CHECK_BUSY_FORWARD,${EXTEN},1)
same =&gt; n(end),Hangup
</code></pre>
<p style="text-align: justify;">Старое оборудование, которое установлено у операторов связи оможет &#171;криво&#187; поддерживать или не поддерживать early media вовсе. Например, по SIP-дампу в RTP трафике в плеере wireshark уведомление на участке между АТС и оператором слышно, а у абоненента в сети ТфОП тишина. В таком случае нужно сообщение connect и следует использовать первый вариант.</p>
<p>Таким образом мы добавили воспроизведение аудиофайла, в частности уведомление о записи разговоара, которое всегда проигрывается только одной стороне &#8212; клиенту, а не обоим сторонам вызова. Причём включение и отключение уведомления регулируется путём установки параметра в базе данных MySQL. Поэтому сделать интерфейс для абонентов, где они самостоятельно устанавливать этот параметр не составит труда. Это также можно реализовать через служебные комбинации или старкоды.</p><p>The post <a href="https://ucexpert.ru/archives/7124">Настройка уведомления о записи разговора для исходящих и входящих вызовов в Asterisk</a> first appeared on <a href="https://ucexpert.ru">Unified Communications Expert</a>.</p>]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
