Notes about IT

Позднее Ctrl + ↑

Развертывание ip-телефонии для небольшой компании

Случилось мне столкнуться с заданием: настроить ip-телефонию для небольшой компании (в городе А) с филиалом (только для заключения договоров) в другом городе (городе Б).
Тех. задание было простое: есть sip номер города филиала с тремя линиями, нужно заставить его работать для экономии денежных средств из основного офиса города А абонентам города Б + обеспечение внутренней связи между офисом и филиалами и запись разговоров.
Задача поставлена, начнем реализацию.

Подбор оборудования и ПО

Компания небольшая, сотрудников менее 30, значит подойдет машина не старше 5ти лет (CPU 2.5-3GHz, RAM 4Gb, HDD 1Tb). В работе было использовано следующее железо:
CPU AMD Athlon 64 X2 3GHz
RAM 2x2Gb
HDD 1x1Tb

С ПО вопрос решился моментально — это Asterisk в ввиду его бесплатности и большой базе знаний, да и на слуху именно он, но т. к. я с этим сталкиваюсь впервые, то мне нужен был GUI, а тут выбор богат (FreePBX, Elastix, TrixBox, Asterisk GUI, etc.)

Выбор дистрибутива

Первое что я попробовал был Aserisk NOW с FreePBX в качестве GUI, но как-то не задалось с ним изначально — очень тяжело для первоначального изучения.
Вторым дистрибутивом стал Elastix. Были скачены Elastix 3.0.0 RC 1 и Elastix 2.4.0 Stable.

Все дистрибутивы я качал только 64-битные

Первая была установлена версия Elastix 3.0.0 RC 1 и она мне визуально очень понравилась, НО изменения в web-интерфейсе не отражались в конфигурационных файлах и, как выяснилось позднее, отсутсвуют многие пункты меню. В общем, из-за этих косяков я потратил пару дней и решил накатить версию Elastix 2.4.0 Stable. Вся дальнейшая настройка будет именно в этой версии.

Разворачивание дистрибутива

Установить Elastix 2.4.0 Stable не составит труда. Пишем скаченный образ на диск и загружаемся с него. В начале отвечаем на простые вопросы (имя машины, как будем получать IP адрес, выбрать город для установки часового пояса, разметка диска). Перезагрузка. Задаем пароль root, пароль root для MySQL и пароль для admin от web морды Elastix.
После установки рекомендую подключиться к серверу по ssh и обновиться (на все вопросы отвечаем Y):

yum update

После обновления проверяем версии

# cat /etc/redhat-release
CentOS release 5.10 (Final)
# asterisk -V
Asterisk 11.10.0

Настройка IP-АТС

Допустим, SIP-провайдер (mtt.ru) выдал нам:
номер 74995647814
логин 74995647814
пароль 1234567890
адрес подключения voip.mtt.ru

Заходим в web-интерфейс https://ip-adress/ с логином admin и паролем, который забили самый последний (пароль для superadmin).
Дашборд можно немного настроить под себя, скрыв ненужные для вас аплеты.

Для смены пароля/заведения новых пользователей web-морды идем в System — Users. Там же можно создать свои группы и назначить им права.

В System — Backup/Restore делаем бекапы с возможностью разворачивания.

Основная настройка происходит в меню PBX — PBX Configuration

Создание транка

Первое, что нужно сделать — это подключить выданный sip-номер.
Заходим в PBX — PBX Configuration — Trunks и создаем новый SIP-транк

Заполняем поля:
Секция General Settings
Trunk Name — пишем название нашего транка (я обозвал его tr74995647814)

Секция Outgoing Settings
Trunk Name — пишем название нашего транка (я обозвал его tr74995647814)
PEER Details — параметры подключения к sip-провайдеру, кодеки и пр.
; — знак комментария

type=peer
defaultuser=74995647814
fromuser=74995647814
secret=1234567890
insecure=port,invite
host=voip.mtt.ru
fromdomain=voip.mtt.ru
;nat=yes
;qualify=3000
dtmfmode=rfc2833
;directmedia=no
disallow=all
allow=alaw,ulaw,g729

Секция Incoming Settings
Очищаем все поля

Секция Registration
Register String — строка подключения, имеет вид: login:pass@voip.mtt.ru/login

74995647814:1234567890@voip.mtt.ru/74995647814

Сохраняем — Submit

Создание входящих/исходящих правил

Создадим исходящее правило
Исходящие правила создаются в меню PBX — PBX Configuration — Outbound Routes


Идем в PBX — PBX Configuration — Outbound Routes и начинаем заполнять поля:
Route Name: — название правила (я обозвал его out74995647814)
Поля Dial Patterns that will use this Route заполняем так:

(prepend) + prefix | [7XXXXXXXXXX] / XXX
(+7) + [78] | [XXXXXXXXXX] / XXX

Этим мы разрешили звонить на +7 и сделали автозамену +7 на 8.

Из выпадающего списка номер 0 Trunk Sequence for Matched Routes выбираем наш транк — tr74995647814

Сохраняем — Submit

Создадим входящее правило
Входящие правила в PBX — PBX Configuration — Inbound Routes
Идем в PBX — PBX Configuration — Inbound Routes и начинаем заполнять поля:
Description — название правила (я обозвал его in74995647814)
Language — указываем ru
В секции Set Destination пока выберем Terminate Call — Hungup

Сохраняем — Submit

Создание внутренних номеров

Для начала нужно определиться с форматом внутренних номеров, я делал так:
100, 200,300 и т.д — это номера отцела целиком
101-199, 201-299, 301-399 и т. д. — номера сотрудников отделов
Думаю, что идея понятна.

Внутренние номера создаются в меню PBX — PBX Configuration — Extensions
Жмем Add Extension, выбираем Device — Generic SIP Device и жмем Submit

Секция Add Extension
User Extension — внутренний номер абонента
Display Name — отображаемое имя при звонке

Секция Device Options
secret — пароль

Секция Language
В поле Language Code прописываем ru

Секция Recording Options
В полях Record Incoming и Record Outgoing выбираеем Always

Сохраняем — Submit

Создаем нужное количество внутренних номеров.

Работа с очередями

Очереди позволяют организовать для поступающих звонков ожидание освободившегося оператора, возможность предоставить абоненту, ожидающему соединения, переход из очереди в интерактивное меню. С их помощью удобнее всего организовывать call-центры.
Очереди создаются в меню PBX — PBX Configuration — Queues

Секция Add Queue
Queue Number — номер очереди (у меня это номер отдела)
Queue Name — название очереди (наизвание отдела, например)
Static Agents — сотрудники отдела. Поле заполняется при выборе из выпадающего списка параметра Extension Quick Pick.

Секция Queue Options
Max Wait Time — максимальное время нахождения звонящего в очереди на ожидании
Max Callers — максимальное количество абонентов, ожидающих в очереди
Ring Strategy — определяет стратегию дозвона в очередь: ringall — звонят все телефонные аппараты в очереди, leastrecent — поступление звонка на наименее загруженного оператора, fewestcalls — поступление звонка на оператора с наименьшим количеством законченных разговоров, random — звонок поступает на случайным образом выбранного оператора, rrmemory — поступает на любого доступного оператора с учетом последнего ответившего, rrordered — похоже на предыдущую стратегию, но с учетом агентов в конфиг файле, linear — звонок поступает на агентов в том порядке в котором они перечислены, для динамических агентов — в порядке их регистрации, wrandom — звонок поступает на случайно выбранного оператора с учетом занятости.
Agent Timeout — время поступления звонка на оператора, до выдачи сообщения о недоступности
Skip busy agents — пропуск занятых операторов

Секция Caller Position Announcements
Отвечает за оповещение звонящего, каким по счету он является в очереди
Frequency — частота оповещения
Announce Position — оповещать о позиции в очереди
Announce Hold Time — оповещать о примерном времени ожидания

Секция Fail Oxer Destination
Выбираем куда отправится звонок по истечению времени ожидания (никто не ответил)
Пока выберем Terminate Call — Hungup (положить трубку)

Создаем нужное количество групп

Создание голосового меню (IVR)

Для голосового меню нам нужны записаные фразы, записываем в любой любимой программе (например, Sound Forge) в формате PCM Encoded, 16 Bits, at 8000Hz.
Записать нужно:
1) Приветствие (01-hello.wav) — Здравствуйте, вы позвонили в компанию РиК.
2) Меню (02-menu.wav) — Нажмите 1 для связи с отделом А. Нажмите 2 для связи с отделом Б. Или дождитесь ответа.
3) Если никто не берет трубку (03-buzy.wav) — Извините, в данный момент все заняты, ожидайте.
4) Если долго никто не берет трубку (04-buzy_call_later.wav) — Извините, все операторы заняты, перезвоните позже.
5) Время работы компании (05-work_time.wav) — Наша компания работает с понедельника по пятницу с 9:00 до 17:00.

Теперь нужно все эти записи передать Asterisk, для этого идем в меню PBX — PBX Configuration — System Recordings
Выбираем файл hello.wav и присваеваем имя нашей записи в поле Name this Recording (например, Hello)
Сохраняем — Save

Так же загружаем оставшиеся файлы.

Теперь можно приступить к созданию самого голосового меню
Голосовые меню создаются в меню PBX — PBX Configuration — IVR
Для создания нажимаем Add IVR
Change Name — название меню
Announcement — выбираем наше приветствие (01-hello)
Timeout — время ожидания нажатия клавиши (в секундах)
Enable Direct Dial — ставим галочку, если нужно, чтобы дозвонившийся мог набрать внутренний номер сотрудника
Дальше создаем наше меню:

1 Queuse 100
2 Queuse 200
3 Extensions 301
t Extensions 301
i Extensions 301

Цифра 1 — отправляем звонок в очередь 100
Цифра 2 — отправляем звонок в очередь 200
Цифра 3 — отправляем звонок на номер 301 (секретарь)
Если ничего не нажато после 10 секунд отправляем звонок на секретаря
Если нажата любая другая клавиша (кроме 1,2 и 3) отправляем звонок на секретаря

Сохраняем — Save

Создадим дополнительные анонсы для нашего меню
Переходим в меню PBX — PBX Configuration — Announcements
Создаем анонс — Add Announcement
Description — название (All buzy call later)
Recording — выбираем нашу хапись 04-buzy_call_later
В секции Destination after playback выбираем:

Terminate Call  Hangup

Сохраняем — Submit Changes

Создадим еще одно меню IVR-CALL-LATER
Announcement — выбираем 04-buzy_call_later
Timeout — 1
Enable Direct Dial — галочку не ставим
В опицях указываем:

t Terminate Call  Hangup

При переходе в это меню будет сказана фраза, чтобы перезвнили позже и через 1 секунду повесится трубка.

Отредактируем наши очереди.
Открываем очередь 100 и секции Fail Over Destination выбираем IVR IVR-CALL-LATER и сохраняем. То же проделываем с остальными очередями.

Не забываем после внесеныых изменений принимать их, нажимая на Apply Configuration Changes Here.

Голосовое меню в рабочее и не рабочее время

Создадим анонс WorkingTime с нашим звуковым файлом 05-work_time в меню PBX — PBX Configuration — Announcements

Перейдем в меню PBX — PBX Configuration — Time Group и создадим группу:
Description — название (TG-WorkingTime)
Time to start — 09:00
Time to finish — 17:00
Week Day Start — Monday
Week Day finish — Friday

Сохраняем — Submit

Переходим в меню PBX — PBX Configuration — Time Condition и создаем условие:
Time Condition name — название (TC-WorkingTime)
Time Group — выбираем созданную группу TG-WorkingTime
Destination if time matches — назначение при совпадении времени с тем, что указано в TG-WorkingTime.

IVR  IVR-MAIN

Destination if time does not match — назначение при несовпадении времени с тем, что указано в TG-WorkingTime.

Announcements  WorkingTime

Сохраняем — Submit

Устанавливаем русские звуки

Скачиваем необходимые голосовые фразы: стандартные и расширенные
Сохраняем и разархивируем во временной директории на локальном компьютере
Содержимое архива закачиваем на Elastix в директорию /var/lib/asterisk/sounds/ru
В sip_general_custom.conf добавляем строку language=ru (отредактировать файл можно через веб-интерфейс, меню PBX-Tools-Asterisk File Editor)
Сохраняем — Save

Прием факсов

Для того, чтобы научить наш Elastix/Asterisk принимать факс, необходимо следующее:
Переходим в меню PBX — PBX Configuration — Extensions
Создаем Generic IAX2 Device
Прописываем номер в User Extension (например, 901)
Даем имя в Display name (например, Fax)
Задаем пароль в secret

Секция Recording Options
Record Inbound — Never
Record Outbound — Never

Сохраняем — Submit

Далее зайдем и отредактируем созданный номер:
Секция Device Options
disallow — all
allow — alaw

Сохраняем — Submit

Переходим в меню Fax — New Virtual Fax
Virtual Fax Name — название
Associated Email — e-mail куда будет отсылаться факс
Fax Extension (IAX) — созданный выше Extension
Secret (IAX) — пароль
Country Code — префикс страны (8)
Area Code — код города

Сохраняем — Save

Если очень хочется, то можно руссифицировать письмо с факсом в меню Fax — Email Template

Вызов внешнего номера

Что бы сделать вызов внешнего номера из голосового меню, необходимо узнать номер голосого меню (ivr), присвоенный системой, для этого идем в файл extensions_additional.conf и просматриваем наличие [ivr-<номер>], т. к. в этой статье создали два меню, то можно будет обнаружить два таких фрагмента. Определить нужный просто. Тот где много строк — нужный (например, [ivr-2]).
Необходимо, чтобы внутри массива ivr была строка include => ivr-<номер>-custom (например, include => ivr-2-custom)
После того, как узнали номер IVR, нужно в конце файла extensions_custom.conf прописать

[ivr-2-custom]
exten => _9,1,Dial(SIP/{Trunk}/{number})

где _9 — цифра вызова внешнего номера
SIP/{Trunk} — это строка SIP/tr74995647814 (см. создание транка)
{number} — внешний номер

Работает это так: звонит клиент, ему что-то говорится в меню, он нажимает 9 и Asterisk перекидывает звонок на внешний номер, а сам кладет трубку.

Работа за NAT

Для полноценной работы за NAT требуется доступ к портам 5060/UDP, 10000-20000/UDP и следующее содержание файла sip_nat.conf

nat=route
bindaddr=0.0.0.0/0.0.0.0
externip=88.88.88.88
localnet=192.168.0.1/255.255.255.0
canreivite=no
qualify=yes
directmedia=no

externip — внешний IP-адрес
localnet — внутренний IP-адрес/маска сети

Своя мелодия при ожидании

Как и для голосового меню мелодии нужно сохранить в формате PCM Encoded, 16 Bits, at 8000Hz.
Имея 2-3 готовых файла идем в меню PBX — PBX Configuration — Music on Hold
Создаем новую категорию — Add Music Category, вводим в поле Category Name название и жмем Submit Changes.
Переходим в созданную категорию и заливаем наши файлы с мелодиями. Если хотите, чтобы каждый раз проигрывалась произвольная мелодия, необходимо прожать Enable Random Play.
Не забываем применить настойки кликом на Apply Configuration Changes Here.

Дальше необходимо отредактировать все очереди
Секция Queue Options
Music on Hold Class — выбираем созданную группу с мелодиями

Сохраняем — Submit Changes

Мониторинг транков

Мониторить состояние транков можно в консоле командой:

asterisk -rx "sip show registy"

Смена RTP портов

RTP порты прописаны в файле rtp.conf

;
; RTP Configuration
;
[general]
;
; RTP start and RTP end configure start and end addresses
; These are the addresses where your system will RECEIVE audio and video streams.
; If you have connections across a firewall, make sure that these are open.
;
rtpstart=10000
rtpend=20000

Звонки в разные города с разных SIP номеров

После развертывания АТС обнаружилось, что нужно совершать звонки в другой город, например Томск (код города 3822), а звонить с московского номера (в примере 74995647814) дорого. Для минимизации расходов было принято решение приобрести томский sip номер. Сказано — сделано.
Допустим, SIP-провайдер (mtt.ru) выдал нам:
номер 73822555555
логин 73822555555
пароль 1234567890
адрес подключения voip.mtt.ru

Заводим новый транк как делали это выше
После этого создадим исходящее правило для нового транка, но в полях секции Dial Patterns that will use this Route указываем следующее:

(prepend) + prefix | [73822XXXXXX] / XXX
+7 + [78] | [73822XXXXXX] / XXX

В секции Trunk Sequence for Matched Routes выбираем наш новый транк.
Этими правилами мы указываем, что при исходящем звонке на номера вида +7(3822) XX-XX-XX набор пойдет через томский номер +7(3822) 55-55-55

Так же не стоит забывать, что правила применяются сверху вниз, а это значит, что пока мы наше новое правила не поставим выше предыдущего все звонки будут идти с московского номера +7(499) 564-78-14, т. к. в исходящем правиле out74995647814 у нас прописаны строки вида

(prepend) + prefix | [7XXXXXXXXXX] / XXX
(+7) + [78] | [XXXXXXXXXX] / XXX

Что бы поставить правило out73822555555 выше out74995647814 нужно в выпадающем списке Route Position выбрать First before out4995647814 и сохранить изменения.

Таким образом мы подключили два sip номера к Asterisk и настроили исходящие звонки для всех внутренних номеров в Томск через томский номер, а все остальные звонки — через московский номер.

2014   voip

Что делать, если БД в состоянии Suspend?

Случилось, что после вынужденного выключения сервера БД одна из баз свалилась в состояние Suspend. Конечно лучше делать бекапы, но не было их на тестовом сервере. Вот скрипт, который можно и в GUI проделать, который мне помог восстановить базу:

EXEC sp_resetstatus [DB];
ALTER DATABASE [DB]SET EMERGENCY
DBCC checkdb([DB])
ALTER DATABASE [DB]SET SINGLE_USER WITH ROLLBACK IMMEDIATE
DBCC CheckDB ([DB], REPAIR_ALLOW_DATA_LOSS)
ALTER DATABASE [DB]SET MULTI_USER

Вместо [DB] вставить свою БД.

2014   sql   windows

Утилизация RAM Metafile в Windows 2008 R2

Как часто вы видели в Диспетчере задач (Task Manager) 100% загрузку RAM, хотя суммарно по процессам там было не более 30%?
На скриншотах ниже показана не 100% загрузка, но ощутить неприятный момент дадут.

Хорошо, что у нас уже есть инструменты Windows Sysinternals, а конкретно RAMMap. Качаем, запускаем (не требует установки) и видим следующую картину:

Некие Metafiles отъедают львиную долю оперативки и, если посчитать, именно этот объем мы не увидим в Диспетчере задач.
Погуглив на тему Metafiles я нашел описание:

Metafile is part of the system cache and consists of NTFS metadata. NTFS metadata includes the MFT as well as the other various NTFS metadata files… In the MFT each file attribute record takes 1KB and each file has at least one attribute record. Add to this the other NTFS metadata files and you can see why the Metafile category can grow quite large on servers with lots of files

Что же, основным содержание одного из дисков являются jpg-файлы (>1.8Tb). Поиск по фразам «how to clean / reduce METAfIle size» выдал решение в виде установки Dynamic Cache Service. В первый раз я не установил данную службу, поэтому не могу сказать при ее работоспособность, но говорят, что под Windows Server 2008 R2 Web edition она не работает.
Что же делать, если нужно срочно освободить RAM или служба Dynamic Cache Service не приводит к желаемому результату? Открываем RAMMap, меню Empty — Empty System Wokring Set

После этого вы увидите пропавшие гигабайты.

2014   windows

Поиск цепочек блокировок на SQL Server с помощью процедуры sp_locks

Введение

Параллелизм в отношении БД можно определить как число пользователей, способных работать с данной БД, не мешая и не пересекаясь друг с другом. Чем больше число одновременно работающих пользователей, тем выше параллелизм.

SQL Server блокирует данные для обеспечения их целостности. Это необходимо в любой БД, где данные подвергаются изменениям. Чтобы подчеркнуть это, скажу, что если БД находится в состоянии READ_ONLY, SQL Server не создает блокировок считываемых данных, поскольку они не могут быть изменены и, следовательно, защищать данные не нужно. Поэтому SQL Server только помечает объекты, к которым происходит обращение, блокировкой Intense Share (IS), чтобы исключить выполнение таких DDL-выражений, как удаление таблицы, из которой производится чтение.

Блокировки данных существуют в любой среде, где модифицируются данные (то есть БД находится в состоянии READ_WRITE, в противоположность предыдущему примеру), и это совершенно нормально. SQL Server удерживает необходимые блокировки для защиты целостности данных и освобождает данные, как только отпадает необходимость в блокировке.

Краткосрочные блокировки не оказывают негативного воздействия, они — часть нормальной работы SQL Ser­ver. Проблемы возникают, когда продолжительность блокировок становится большой, то есть в несколько секунд, и в этом случае в игру вступает sp_locks.

sp_locks

sp_locks — это полезное средство, помогающее в поиске и устранении проблем в сценариях с блокировками и параллелизмом.

Листинг 1. Процедура sp_locks.

USE [master];
SET QUOTED_IDENTIFIER ON; SET ANSI_NULLS ON;

IF  EXISTS (SELECT * FROM sys.objects 
              WHERE object_id = OBJECT_ID(N'[dbo].[sp_Locks]') 
                AND type IN (N'P', N'PC')
)
  DROP PROCEDURE dbo.sp_Locks;
GO
  
  
CREATE PROCEDURE dbo.sp_Locks
(
   @Mode int = 2,
   @Wait_Duration_ms int = 1000 /* 1 seconds */
)
/*
  19/04/2008 Yaniv Etrogi
  http://www.sqlserverutilities.com  
*/
AS
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

--EXEC sp_Locks @Mode = 3, @Wait_Duration_ms = 1000

/* return the one result set */
IF @Mode = 1
BEGIN;
  SELECT
      t.blocking_session_id           AS blocking,
      t.session_id                    AS blocked,
      p2.[program_name]               AS program_blocking,
      p1.[program_name]               AS program_blocked,
      DB_NAME(l.resource_database_id) AS [database],
      p2.[hostname]                   AS host_blocking,
      p1.[hostname]                   AS host_blocked,
      t.wait_duration_ms,
      l.request_mode,
      l.resource_type,
      t.wait_type,
      (SELECT SUBSTRING(st.text, (r.statement_start_offset/2) + 1, 
              ((CASE r.statement_end_offset 
                  WHEN -1 THEN DATALENGTH(st.text) 
                  ELSE r.statement_end_offset END
                - r.statement_start_offset) /2 ) + 1)
        FROM sys.dm_exec_requests AS r 
          CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS st 
        WHERE r.session_id = l.request_session_id) AS statement_blocked,
      CASE WHEN t.blocking_session_id &gt; 0 THEN 
        (SELECT st.text 
          FROM sys.sysprocesses AS p 
            CROSS APPLY sys.dm_exec_sql_text(p.sql_handle) AS st
          WHERE p.spid = t.blocking_session_id)
      ELSE NULL END AS statement_blocking
       --,t.resource_description AS blocking_resource_description
       --,l.resource_associated_entity_id
    FROM sys.dm_os_waiting_tasks AS t
      INNER JOIN sys.dm_tran_locks AS l 
        ON t.resource_address = l.lock_owner_address
      INNER JOIN sys.sysprocesses p1 ON p1.spid = t.session_id
      INNER JOIN sys.sysprocesses p2 ON p2.spid = t.blocking_session_id
    WHERE t.session_id &gt; 50 AND t.wait_duration_ms &gt; @Wait_Duration_ms;
END;

/* return the first two result sets */
IF @Mode = 2
BEGIN;
SELECT 
    spid,
    [status],
    CONVERT(CHAR(3), blocked) AS blocked,
    loginame,
    SUBSTRING([program_name] ,1,25) AS program,
    SUBSTRING(DB_NAME(p.dbid),1,10) AS [database],
    SUBSTRING(hostname, 1, 12) AS host,
    cmd,
    waittype,
    t.[text]
  FROM sys.sysprocesses p
    CROSS APPLY sys.dm_exec_sql_text (p.sql_handle) t
  WHERE spid IN (SELECT blocked FROM sys.sysprocesses WHERE blocked &lt;&gt; 0) 
    AND blocked = 0;

SELECT
    t.blocking_session_id            AS blocking,
    t.session_id                     AS blocked,
    p2.[program_name]                AS program_blocking,
    p1.[program_name]                AS program_blocked,
    DB_NAME(l.resource_database_id)  AS [database],
    p2.[hostname]                    AS host_blocking,
    p1.[hostname]                    AS host_blocked,
    t.wait_duration_ms,
    l.request_mode,
    l.resource_type,
    t.wait_type,
    (SELECT SUBSTRING(st.text, (r.statement_start_offset / 2) + 1, 
              ((CASE r.statement_end_offset 
                  WHEN -1 THEN DATALENGTH(st.text)
                  ELSE r.statement_end_offset END
                - r.statement_start_offset) / 2) + 1
            )
      FROM sys.dm_exec_requests AS r
        CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS st 
      WHERE r.session_id = l.request_session_id) AS statement_blocked,
    CASE WHEN t.blocking_session_id &gt; 0 THEN 
          (SELECT st.text 
            FROM sys.sysprocesses AS p 
              CROSS APPLY sys.dm_exec_sql_text(p.sql_handle) AS st 
            WHERE p.spid = t.blocking_session_id) ELSE NULL 
         END AS statement_blocking
  FROM sys.dm_os_waiting_tasks AS t
    INNER JOIN sys.dm_tran_locks AS l
      ON t.resource_address = l.lock_owner_address
    INNER JOIN sys.sysprocesses p1 ON p1.spid = t.session_id
    INNER JOIN sys.sysprocesses p2 ON p2.spid = t.blocking_session_id
  WHERE t.session_id &gt; 50 AND t.wait_duration_ms &gt; @Wait_Duration_ms;
END;


/* return all three result sets */
IF @Mode = 3
BEGIN;
SELECT 
    spid,
    [status],
    CONVERT(CHAR(3), blocked) AS blocked,
    loginame,
    SUBSTRING([program_name], 1, 25)   AS program,
    SUBSTRING(DB_NAME(p.dbid), 1, 10)  AS [database],
    SUBSTRING(hostname, 1, 12)         AS host,
    cmd,
    waittype,
    t.[text]
  FROM sys.sysprocesses p
  CROSS APPLY sys.dm_exec_sql_text (p.sql_handle) t
  WHERE spid IN (SELECT blocked FROM sys.sysprocesses WHERE blocked &lt;&gt; 0)
    AND blocked = 0;

  
SELECT
    t.blocking_session_id                AS blocking,
    t.session_id                        AS blocked,
    SUBSTRING(p2.[program_name], 1, 25)  AS program_blocking,
    SUBSTRING(p1.[program_name], 1, 25)  AS program_blocked,
    DB_NAME(l.resource_database_id)      AS [database],
    p2.[hostname]                        AS host_blocking,
    p1.[hostname]                        AS host_blocked,
    t.wait_duration_ms,
    l.request_mode,
    l.resource_type,
    t.wait_type,
    (SELECT SUBSTRING(st.text, (r.statement_start_offset/2) + 1, 
            ((CASE r.statement_end_offset WHEN -1 THEN DATALENGTH(st.text)
              ELSE r.statement_end_offset 
              END - r.statement_start_offset) / 2) + 1) 
      FROM sys.dm_exec_requests AS r 
        CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS st 
      WHERE r.session_id = l.request_session_id) AS statement_blocked,
    CASE WHEN t.blocking_session_id &gt; 0 THEN 
           (SELECT st.text 
              FROM sys.sysprocesses AS p 
                CROSS APPLY sys.dm_exec_sql_text(p.sql_handle) AS st 
              WHERE p.spid = t.blocking_session_id) ELSE NULL 
         END AS statement_blocking
    --,t.resource_description        AS blocking_resource_description
    --,l.resource_associated_entity_id
  FROM sys.dm_os_waiting_tasks AS t
    INNER JOIN sys.dm_tran_locks AS l 
      ON t.resource_address = l.lock_owner_address
    INNER JOIN sys.sysprocesses p1 ON p1.spid = t.session_id
    INNER JOIN sys.sysprocesses p2 ON p2.spid = t.blocking_session_id
  WHERE t.session_id &gt; 50 AND t.wait_duration_ms &gt; @Wait_Duration_ms;

SELECT DISTINCT
    r.session_id             AS spid,
    r.percent_complete       AS [percent],
    r.open_transaction_count AS open_trans,
    r.[status],
    r.reads,
    r.logical_reads,
    r.writes,
    s.cpu,
    DB_NAME(r.database_id)   AS [db_name],
    s.[hostname],
    s.[program_name],
  --s.loginame,
  --s.login_time,
    r.start_time,
  --r.wait_type,
    r.wait_time,
    r.last_wait_type,
    r.blocking_session_id    AS blocking,
    r.command,
    (SELECT SUBSTRING(text, statement_start_offset / 2 + 1,
            (CASE WHEN statement_end_offset = -1 THEN
                    LEN(CONVERT(NVARCHAR(MAX),text)) * 2 
                  ELSE statement_end_offset 
                  END - statement_start_offset) / 2)
      FROM sys.dm_exec_sql_text(r.sql_handle)) AS [statement],
    t.[text]
    --,query_plan 
  FROM sys.dm_exec_requests r
    INNER JOIN sys.sysprocesses s ON s.spid = r.session_id
    CROSS APPLY sys.dm_exec_sql_text (r.sql_handle) t
    --CROSS APPLY sys.dm_exec_query_plan (r.plan_handle) 
  WHERE r.session_id &gt; 50 AND r.session_id &lt;&gt; @@spid
    AND s.[program_name] NOT LIKE 'SQL Server Profiler%'
    --AND db_name(r.database_id) NOT LIKE N'distribution'
    --AND r.wait_type IN ('SQLTRACE_LOCK', 'IO_COMPLETION', 'TRACEWRITE')
  ORDER BY s.CPU DESC;
END;
GO

В отличие от хранимой процедуры sp_helpindex2, выбирающей информацию, связанную с контекстом текущей БД, sp_locks выбирает информацию уровня сервера, и поэтому она не должна быть помечена как системная хранимая процедура. Однако использование префикса sp_ позволяется воспользоваться тем, что SQL Server сперва ищет все объекты с таким префиксом в БД master. Это дает возможность вызвать процедуру из любой БД, не используя имя из трех частей (например, database.schema.object), что удобно.

Процедура возвращает до трех наборов результатов, что регулируется входным параметром @Mode.

Первый набор результатов возвращает информацию о Lead Blocker-процессе, если таковой существует, и нужен в ситуациях наличия высокой активности блокировок, приводящей к появлению цепочек блокировок.

Цепочка блокировок — это ситуация, когда есть много процессов, блокирующих другие процессы, которые, в свою очередь, блокируют данные или другие процессы. Во многих случаях это требует ручного вмешательства для разрешения конфликта, обычно это вмешательство принимает форму команды, завершающей исполнение процесса, выступающего в роли Lead Blocker.

Lead Blocker — это кличка для процесса, являющегося главной причиной, инициатором, с которого начинается цепочка блокировок — то есть этот процесс блокирует другой процесс, который, в свою очередь, будучи заблокированным, не может снять наложенные им блокировки, и тем самым сам становится блокирующим процессом. Это может продолжаться и продолжаться, вовлекая другие процессы, и порождая цепочки блокировок.

В таком сценарии страдает параллелизм работы с БД, и это, конечно, отражается на времени отклика приложений. Так что на момент, когда вы узнаете о наличии такой ситуации, вы, конечно, хотите как можно быстрее справиться с ней, чтобы минимизировать ее влияние на систему.

Этот набор результатов чаще всего содержит одну строку, но в сценарии эскалации блокировок вы можете увидеть и несколько строк (что означает, что имеется несколько блокирующих процессов и несколько цепочек блокировок).

На рисунке 1, где показано исполнение тестового сценария, блокирующим является процесс, выдавший команду UPDATE (spid 218). Этот процесс блокирует первый процесс, (spid 193), выдающий команду SELECT (/* connection 1 */), и любой последующий SELECT блокируется этим первым выражением SELECT.

Завершение подключения, выдавшего команду UPDATE, позволит всем блокированным (ожидающим) процессам продолжить работу и разрушит цепочку блокировок.

Заметьте, что если прервать любой другой процесс, сценарий эскалации блокировок не будет прерван и цепочка блокировок сохранится.

Второй набор результатов содержит информацию о блокирующих и блокированных процессах, обращаясь к трем ключевым DMV: sys.dm_os_waiting_tasks, sys.dm_­tran_locks и sys.sysprocesses.

Мы выполняем запрос sys.dm_os_waiting_tasks, поскольку именно это нас и интересует — задачи (процессы), находящиеся в состоянии ожидания, в данном случае — ожидающие возможности получить блокировку ресурсов. Приятно то, что это DMV можно соединить с sys.dm_tran_locks по колонке resource_address, которая содержит адрес в памяти ресурса, которого ожидает задача, а с другой стороны условия объединения имеется колонка lock_owner_address из sys.dm_tran_locks, являющаяся адресом в памяти внутренней структуры данных, используемой для отслеживания запросов на блокировки модулем LOCK_MANAGER SQL Server-а.

Эти два DMV дают ценную информацию о блокировках. Далее мы добавляем sys.sysprocesses, чтобы получить информацию более высокого уровня, о блокировках программ и хостов. Чтобы получить информацию о блокирующих и заблокированных процессах, мы дважды выполняем соединение с sys.sysprocesses — один экземпляр для блокирующих, а другой — для заблокированных процессов.

Это достигается соединением одного экземпляра sys.sysprocesses как p1 с sys.dm_os_waiting_tasks по колонке session_id, и второго экземпляра как p2 по колонке blocking_session_id из sys.dm_os_waiting_tasks.

Входной параметр @Wait_Duration_ms позволяет ограничить число выводимых строк теми процессами, чье время ожидание превышает число (время в миллисекундах), указанное в этом параметре. Это очень полезно, поскольку обычно вас не интересуют краткосрочные (в 2-3 секунды) ожидания (блокировки), не оказывающие отрицательного влияния на систему.

Третий набор результатов содержит информацию из sys.dm_exec_requests об активно исполняемых процессах. Этот набор результатов может быть полезным, когда нет активных блокировок, и первые два набора не содержат никаких строк, но вам все-таки нужно увидеть, что исполняется в данное время на сервере.

Листинг 2. Использование sp_lock

-- Возвратить только второй набор результатов
EXEC sp_Locks @Mode = 1, @Wait_Duration_ms = 1000;
-- Возвратить первый и второй наборы результатов
EXEC sp_Locks @Mode = 2, @Wait_Duration_ms = 1000;
-- Возвратить все три набора результатов
EXEC sp_Locks @Mode = 3, @Wait_Duration_ms = 1000;

Помещение информации о блокировках в таблицу

Чтобы сохранить информацию о блокировках в таблицу, используйте скрипт Capture_blocking_info.sql, который использует выражение INSERT…EXEC с sp_locks в @Mode = 2.

Листинг 3. Скрипт Capture_blocking_info.sql

/*

  Сохранение информации о блокировках в таблицу
  
  19/04/2008 Yaniv Etrogi   
  http://www.sqlserverutilities.com  

*/    
USE [tempdb];
SET ANSI_NULLS ON; SET QUOTED_IDENTIFIER ON;


IF  EXISTS (
  SELECT * 
    FROM sys.objects 
    WHERE object_id = OBJECT_ID(N'[dbo].[Blocks]') 
    AND type in (N'U'))
  DROP TABLE [dbo].[Blocks];
GO

CREATE TABLE [dbo].[Blocks](
  [Id] [int] identity(1,1) NOT NULL CONSTRAINT 
  [PK_Blocks] PRIMARY KEY NONCLUSTERED ([Id]),
  [InsertTime] datetime CONSTRAINT 
  [DF_Blocks_InsertTime] DEFAULT (getdate()) NOT NULL,
  [blocking] smallint NULL,
  [blocked] smallint NULL,
  [program_blocking] varchar(128) NULL,
  [program_blocked] varchar(128) NULL,
  [database] varchar(128) NULL,
  [host_blocking] varchar(128) NOT NULL,
  [host_blocked] varchar(128) NOT NULL,
  [wait_duration_ms] bigint NULL,
  [request_mode] varchar(60) NOT NULL,
  [resource_type] varchar(60) NOT NULL,
  [wait_type] varchar(60) NULL,
  [statement_blocked] varchar(max) NULL,
  [statement_blocking] varchar(max) NULL );
GO

CREATE CLUSTERED INDEX IXC_Blocks_InsertTime ON dbo.Blocks (InsertTime);

-- Бесконечный цикл до ручного прекращения исполнения 
-- или изменения условия WHEN
SET NOCOUNT ON;
DECLARE @i int; SELECT @i = 0;

WHILE (@i &lt; 1000000)
BEGIN;
INSERT INTO [dbo].[Blocks]
           ([blocking],
            [blocked],
            [program_blocking],
            [program_blocked],
            [database],
            [host_blocking],
            [host_blocked],
            [wait_duration_ms],
            [request_mode],
            [resource_type],
            [wait_type],
            [statement_blocked],
            [statement_blocking])
EXEC sp_Locks @Wait_Duration_ms = 1000, @Mode = 1;

SELECT @i = @i + 1;
IF @i % 100 = 0 PRINT @i;  --print every 100 iterations 
WAITFOR DELAY '00:00:10';  --10 seconds sleep
END;

-- Выборка полученных данных о блокировках.
SET NOCOUNT ON; 
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT TOP 100
       [Id],
       [InsertTime], 
       [blocking],
       [blocked],
       LEFT([program_blocking], 20) AS [program_blocking],
       LEFT([program_blocked], 20)  AS [program_blocked],
       [database],
       [host_blocking],
       [host_blocked],
       [wait_duration_ms],
       [request_mode],
       [resource_type],
       [wait_type],
       [statement_blocked],
       [statement_blocking]
FROM  [dbo].[Blocks]
ORDER BY [InsertTime] DESC;

Внутри блокировок

Чтобы получить представление о блокирующих и заблокированных процессах, возвращаемых sp_locks, можно использовать следующий скрипт, детализирующий причины блокировки.

Я использую его при поиске и воспроизведении сценария блокировки. Фильтрация по spid позволяет мне видеть только нужные мне данные и получить картину выделенных ресурсов и состояния их блокировок.

SET NOCOUNT ON; 
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 
SELECT --TOP 100
  l.request_session_id AS spid,
  DB_NAME(l.resource_database_id) AS [database],
  CASE WHEN l.resource_type = 'OBJECT' 
    THEN OBJECT_NAME(l.resource_associated_entity_id, l.resource_database_id)
  WHEN l.resource_associated_entity_id = 0 
    THEN 'NA' 
    ELSE OBJECT_NAME(p.object_id, l.resource_database_id) END AS [object],
      p.index_id,
      l.resource_type        AS [resource],
      l.resource_description AS [description],
      l.request_mode         AS [mode],
      l.request_status       AS [status],
      l.resource_associated_entity_id
FROM sys.dm_tran_locks l 
LEFT JOIN sys.partitions p ON p.hobt_id = l.resource_associated_entity_id
WHERE resource_type NOT LIKE 'DATABASE'
--AND l.request_session_id = @@SPID -- &lt;---- edit spid here
--AND DB_NAME(l.resource_database_id) NOT LIKE 'distribution'

При исполнении скрипта для тестового сценария при фильтрации по имени БД я вижу все вовлеченные процессы. Это четко показывает, что блокирующий процесс, spid 218, удерживает эксклюзивную (Х) блокировку ключа индекса (кластерного индекса в данном случае), и что это блокировка обновляемой строки. Эксклюзивная блокировка строки должна быть также помечена на уровне страницы, что и делается с помощью Intense Exclusive (IX) блокировки. Можно видеть, что это страница 154 в файле данных с номером 1. IX-блокировка страницы должна быть распространена до уровня таблицы, что и делается с помощью IX-блокировки этого объекта.

Листинг 4. Тестовый сценарий

USE [master];
SET ANSI_NULLS ON; SET QUOTED_IDENTIFIER ON;

IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = N'TEST')
  CREATE DATABASE TEST;
GO

USE [TEST];
IF EXISTS (
  SELECT * FROM sys.objects 
    WHERE object_id = OBJECT_ID(N'[dbo].[T1]') 
    AND type in (N'U'))
  DROP TABLE [dbo].[T1];
GO

USE [TEST];
IF EXISTS (
  SELECT * FROM sys.objects 
    WHERE object_id = OBJECT_ID(N'[dbo].[T1]') 
    AND type in (N'U'))
  DROP TABLE [dbo].[T1];
GO

CREATE TABLE [dbo].[T1]
(
  [c1] [int] IDENTITY(1,1) NOT NULL,
  [c2] [int] NOT NULL, PRIMARY KEY CLUSTERED([c1] ) 
);


INSERT T1 (c2) VALUES (10);
INSERT T1 (c2) VALUES (20);
INSERT T1 (c2) VALUES (30);
INSERT T1 (c2) VALUES (40);
INSERT T1 (c2) VALUES (50);
INSERT T1 (c2) VALUES (60);
/* Blocker */
-- Выполняет UPDATE и оставляет транзакцию открытой, так что эксклюзивная (X) 
-- блокировка, получаемая процессом, не освобождается. 
USE [TEST];
BEGIN TRAN; UPDATE T1 SET c2 = 100 WHERE c1 = 5;
--ROLLBACK

/* Blocked */
USE [TEST]; SELECT * FROM TEST..T1 /* connection 1 */ ;
USE [TEST]; SELECT * FROM TEST..T1 /* connection 2 */ ;
USE [TEST]; SELECT * FROM TEST..T1 /* connection 3 */ ;
USE [TEST]; SELECT * FROM TEST..T1 /* connection 4 */ ;
USE [TEST]; SELECT * FROM TEST..T1 /* connection 5 */ ;

Все остальные процессы, пытающиеся читать данные, имеют статус WAIT и ожидают освобождения ресурса, заблокированного выражением UPDATE.

Права

DMV (Dynamic Management Views) и DMF (Dynamic Management Function), используемые хранимой процедурой, требуют, чтобы вызывающая их сторона имела права VIEW SERVER STATE и, конечно, право на запуск процедур из БД master (EXECUTE).

/*
USE [master];
GRANT VIEW SERVER STATE TO Paul;
GRANT EXECUTE ON sp_locks TO Paul;
*/

(c) www.k-press.ru

2014   sql   windows

Экспорт и импорт сайтов и пулов приложений из/в IIS

When using multiple IIS server in a Load Balanced Environment it will be alot of work to create all your website twice with the same settings on each webserver. Therefor it is possible to export and import your configuration from one webserver to the other. This will also be usefull when your upgrading from IIS 7 (Windows Server 2008) to IIS 7.5 (Windows Server 2008 R2).

When you create a website in IIS 7 or 7.5 a unique application pool will also be created and used by this website, that’s why you need to import these application pools first on the second webserver before importing the website(s).

To Export the Application Pools on IIS 7:

%windir%\system32\inetsrv\appcmd list apppool /config /xml > c:\apppools.xml

This will export all the application pools on your webserver, therefor you need to edit the apppools.xml and remove the application that you do not need to import for example:

  • DefaultAppPool
  • Classic .NET AppPool
  • SecurityTokenServiceApplicationPool

And other apppools that already exist on the second webserver, appcmd doesn’t skip already existing apppools, it just quit’s and doesn’t import any.

To import the Application Pools:

%windir%\system32\inetsrv\appcmd add apppool /in < c:\apppools.xml

All the AppPools in the xml will be created on your second webserver.

To Export all your website:

%windir%\system32\inetsrv\appcmd list site /config /xml > c:\sites.xml

This will export all the websites on your webserver, therefor you need to edit the sites.xml and remove the websites that you do not need to import for example:

  • Default Website

And all other websites that already exist on the second webserver.

To Import the website:

%windir%\system32\inetsrv\appcmd add site /in < c:\sites.xml

It’s also possible to export a single website or application pool all you need to do is add the name of the Application Pool or Website to the command line:

To export/import a single application pool:

%windir%\system32\inetsrv\appcmd list apppool “MyAppPool” /config /xml > c:\myapppool.xml

Import:

%windir%\system32\inetsrv\appcmd add apppool /in < c:\myapppool.xml

To export/import a single website:

%windir%\system32\inetsrv\appcmd list site “MyWebsite” /config /xml > c:\mywebsite.xml

Import:

%windir%\system32\inetsrv\appcmd add site /in < c:\mywebsite.xml

(c) microsoftpro.nl

2014   iis   web   windows

Два провайдера и распределение по каналам

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

На пример веб сервер, выведенный через NAT на IP адрес первого провайдера получает запрос, а вот вероятность того, что ответ пойдет по нужному каналу уже не 100%. Какой же он после этого веб сервер?

Решить эту проблему нам поможет механизм маркировки пакетов.

Таблица MANGLE предназначена для операций по классификации и маркировке пакетов и соединений, а также модификации заголовков пакетов. В частности нас интересует цепочка PREROUTING, которая позволяет маркировать пакет до маршрутизации.

Попробуем разобраться с веб сервером.

Допустим у нас настроен NAT 80 порта с внешнего IP 192.168.1.116 (ISP1, первый провайдер) на 80 порт веб сервера в локальной сети и необходимо гарантировать, что все ответы, которые буду идти от веб сервера попадали на шлюз первого провайдера.

Вот правило для таблицы NAT.

[mkt@MikroTik] > ip firewall nat add chain=dstnat dst-address=192.168.1.116
protocol=tcp dst-port=80 action=dst-nat to-addresses=192.168.0.2 to-ports=80
comment="NAT 80 port from ISP1 to local web server"

[mkt@MikroTik] > ip firewall nat print
Flags: X - disabled, I - invalid, D - dynamic
0   chain=srcnat action=masquerade out-interface=!LOCAL

1   ;;; NAT 80 port from ISP1 to local web server
chain=dstnat action=dst-nat to-addresses=192.168.0.2 to-ports=80
protocol=tcp dst-address=192.168.1.116 dst-port=80

Первым шагом создадим правило в таблице MANGLE.

[mkt@MikroTik] > ip firewall mangle add chain=prerouting  src-address=192.168.0.2
protocol=tcp src-port=80 action=mark-routing new-routing-mark=to-isp1

[mkt@MikroTik] > ip firewall mangle print
Flags: X - disabled, I - invalid, D - dynamic
0   chain=prerouting action=add-src-to-address-list protocol=tcp
address-list=test_list address-list-timeout=0s dst-port=23

1   chain=prerouting action=mark-routing new-routing-mark=to-isp1
passthrough=yes protocol=tcp src-address=192.168.0.2 src-port=80

Пакеты с локального адреса 192.168.0.2 с 80 порта буду маркироваться как to-isp1.

Вторым шагом добавим правило в таблицу маршрутизации.

[mkt@MikroTik] > ip route add gateway=192.168.1.249 routing-mark=to-isp1

[mkt@MikroTik] > ip route print      
Flags: X - disabled, A - active, D - dynamic,
C - connect, S - static, r - rip, b - bgp, o - ospf, m - mme,
B - blackhole, U - unreachable, P - prohibit
#      DST-ADDRESS        PREF-SRC        GATEWAY            DISTANCE
0 A S  0.0.0.0/0                          192.168.1.249 r... 1
1 A S  0.0.0.0/0                          192.168.1.249 r... 1
                                        192.168.1.249 r...
                                        192.168.222.1 r...
2 ADC  192.168.0.0/24     192.168.0.1     LOCAL              0
3 ADC  192.168.1.0/24     192.168.1.116   ISP1               0
4 ADC  192.168.222.0/24   192.168.222.100 ISP2               0

Все что приходит с маркером to-isp1 отправляется на шлюз первого провайдера.

Теперь усложним ситуацию, допустим второй провайдер предоставят на выгодных условиях большую локальную сеть по всему городу и через эту сеть объединены все 10 филиалов вашей фирмы. Все филиалы и офис пользуются тем же сайтом, но какой смысл ходить на него через первого провайдера, когда можно настроить доступ к нему практически локально.

В первую очередь добавляем правило в таблицу NAT, по которому все запросы, пришедшие на внешний IP адрес, который предоставляет 2-ой провайдер, на 80 порт будут переадресовываться на 80 порт локального веб сервера.

[mkt@MikroTik] > ip firewall nat add chain=dstnat dst-address=192.168.222.100
protocol=tcp dst-port=80 action=dst-nat to-addresses=192.168.0.2 to-ports=80
comment="NAT 80 port from ISP2 to local web server"

[mkt@MikroTik] > ip firewall nat print
Flags: X - disabled, I - invalid, D - dynamic
0   chain=srcnat action=masquerade out-interface=!LOCAL

1   ;;; NAT 80 port from ISP1 to local web server
chain=dstnat action=dst-nat to-addresses=192.168.0.2 to-ports=80
protocol=tcp dst-address=192.168.1.116 dst-port=80

2   ;;; NAT 80 port from ISP2 to local web server
chain=dstnat action=dst-nat to-addresses=192.168.0.2 to-ports=80
protocol=tcp dst-address=192.168.222.100 dst-port=80

Следующим шагом добавим в таблицу MANGLE еще одно правило:

[mkt@MikroTik] > ip firewall mangle add chain=prerouting src-address=192.168.0.2
protocol=tcp src-port=80 dst-address=192.168.222.0/24 action=mark-routing
new-routing-mark=to-isp2

[mkt@MikroTik] > ip firewall mangle print
Flags: X - disabled, I - invalid, D - dynamic
0   chain=prerouting action=add-src-to-address-list protocol=tcp
address-list=test_list address-list-timeout=0s dst-port=23

1   chain=prerouting action=mark-routing new-routing-mark=to-isp2
passthrough=yes protocol=tcp src-address=192.168.0.2
dst-address=192.168.222.0/24 src-port=80

2   chain=prerouting action=mark-routing new-routing-mark=to-isp1
passthrough=yes protocol=tcp src-address=192.168.0.2 src-port=80

Пакеты с локального адреса 192.168.0.2 с 80 порта буду маркироваться как to-isp2 если они предназначены для подсети второго провайдера.

Ну и в заключении правило в таблице маршрутизации:

[mkt@MikroTik] > ip route add gateway=192.168.222.1 routing-mark=to-isp2
                                                              
[mkt@MikroTik] > ip route print      
Flags: X - disabled, A - active, D - dynamic,
C - connect, S - static, r - rip, b - bgp, o - ospf, m - mme,
B - blackhole, U - unreachable, P - prohibit
#      DST-ADDRESS        PREF-SRC        GATEWAY            DISTANCE
0 A S  0.0.0.0/0                          192.168.1.249 r... 1
1 A S  0.0.0.0/0                          192.168.222.1 r... 1
2 A S  0.0.0.0/0                          192.168.1.249 r... 1
                                        192.168.1.249 r...
                                        192.168.222.1 r...
3 ADC  192.168.0.0/24     192.168.0.1     LOCAL              0
4 ADC  192.168.1.0/24     192.168.1.116   ISP1               0
5 ADC  192.168.222.0/24   192.168.222.100 ISP2               0

Теперь на запросы, пришедшие со стороны первого провайдера, ответ пойдет на шлюз первого провайдера, а на запросы со стороны второго провайдера и из подсети второго провайдера ответ пойдет на шлюз второго провайдера.

(c) slagovskiy.blogspot.ru

2014   mikrotik   network

Два провайдера и балансировка нагрузки

В последнее время ситуация, когда доступны несколько провайдеров не нова, MikroTik Router OS позволяет настроить доступ сразу по нескольким сетевым интерфейсам, а так же настроить балансировку нагрузки в зависимости от ограничений, которые выставляет провайдер.

Первым шагом настроим дополнительный интерфейс.
Инициализируем сам интерфейс.

[mkt@MikroTik] /interface> print
Flags: D - dynamic, X - disabled, R - running, S - slave
#     NAME                      TYPE             MTU
0  R  ether1                    ether            1500
1  R  ether2                    ether            1500
2  X  ether3                    ether            1500

[mkt@MikroTik] /interface> enable 2

[mkt@MikroTik] /interface> print
Flags: D - dynamic, X - disabled, R - running, S - slave
#     NAME                      TYPE             MTU
0  R  ether1                    ether            1500
1  R  ether2                    ether            1500
2  R  ether3                    ether            1500

Для удобства все же пора дать более понятные имена интерфейсам.

[mkt@MikroTik] /interface> set ether1 name="ISP1"

[mkt@MikroTik] /interface> set ether2 name="LOCAL"

[mkt@MikroTik] /interface> set ether3 name="ISP2"

[mkt@MikroTik] /interface> print
Flags: D - dynamic, X - disabled, R - running, S - slave
#     NAME                       TYPE             MTU
0  R  ISP1                       ether            1500
1  R  LOCAL                      ether            1500
2  R  ISP2                       ether            1500

Теперь назначим IP адрес новому интерфейсу.

[mkt@MikroTik] > ip address add address=192.168.222.100/24 interface=ISP2

[mkt@MikroTik] > ip address print
Flags: X - disabled, I - invalid, D - dynamic
#   ADDRESS            NETWORK         BROADCAST       INTERFACE
0   192.168.1.116/24   192.168.1.0     192.168.1.255   ISP1
1   192.168.0.1/24     192.168.0.0     192.168.0.255   LOCAL
2   192.168.222.100/24 192.168.222.0   192.168.222.255 ISP2

Настало время изменить маршрутизацию по умолчанию. Для начала допустим, что оба провайдера предоставляют одинаковую скорость доступа к сети Internet, значит настроим балансировку (это когда для исходящих соединений каналы чередуются), так что бы запросы распеределялись равномерно, т. е. 50/50. Прежде всего удалим старый шлюз по умолчанию.

[mkt@MikroTik] > ip route print
Flags: X - disabled, A - active, D - dynamic,
C - connect, S - static, r - rip, b - bgp, o - ospf, m - mme,
B - blackhole, U - unreachable, P - prohibit
#      DST-ADDRESS        PREF-SRC        GATEWAY            DISTANCE
0 A S  0.0.0.0/0                          192.168.1.249 r... 1
1 ADC  192.168.0.0/24     192.168.0.1     LOCAL              0
2 ADC  192.168.1.0/24     192.168.1.116   ISP1               0
3 ADC  192.168.222.0/24   192.168.222.100 ISP2               0

[mkt@MikroTik] > ip route remove 0

[mkt@MikroTik] > ip route print
Flags: X - disabled, A - active, D - dynamic,
C - connect, S - static, r - rip, b - bgp, o - ospf, m - mme,
B - blackhole, U - unreachable, P - prohibit
#      DST-ADDRESS        PREF-SRC        GATEWAY            DISTANCE
0 ADC  192.168.0.0/24     192.168.0.1     LOCAL              0
1 ADC  192.168.1.0/24     192.168.1.116   ISP1               0
2 ADC  192.168.222.0/24   192.168.222.100 ISP2               0

И добавим новый, точнее новые.

[mkt@MikroTik] > ip route add dst-address=0.0.0.0/0
gateway=192.168.1.249,192.168.222.1

[mkt@MikroTik] > ip route print                                    
Flags: X - disabled, A - active, D - dynamic,
C - connect, S - static, r - rip, b - bgp, o - ospf, m - mme,
B - blackhole, U - unreachable, P - prohibit
#      DST-ADDRESS        PREF-SRC        GATEWAY            DISTANCE
0 A S  0.0.0.0/0                          192.168.1.249 r... 1
                                       192.168.222.1 r...
1 ADC  192.168.0.0/24     192.168.0.1     LOCAL              0
2 ADC  192.168.1.0/24     192.168.1.116   ISP1               0
3 ADC  192.168.222.0/24   192.168.222.100 ISP2               0

Предположим, что у первого провайдера скорость доступа в два раза выше чем у второго, тогда 2/3 исходящих запросов надо направить на первого, а оставшиеся 1/3 на второго.

[mkt@MikroTik] > ip route add dst-address=0.0.0.0/0
gateway=192.168.1.249,192.168.1.249,192.168.222.1

[mkt@MikroTik] > ip route print                                    
Flags: X - disabled, A - active, D - dynamic,
C - connect, S - static, r - rip, b - bgp, o - ospf, m - mme,
B - blackhole, U - unreachable, P - prohibit
#      DST-ADDRESS        PREF-SRC        GATEWAY            DISTANCE
0 A S  0.0.0.0/0                          192.168.222.1 r... 1
                                       192.168.1.249 r...
                                       192.168.1.249 r...
1 ADC  192.168.0.0/24     192.168.0.1     LOCAL              0
2 ADC  192.168.1.0/24     192.168.1.116   ISP1               0
3 ADC  192.168.222.0/24   192.168.222.100 ISP2               0

Это простейший вариант настройки, при котором получаем выход в интернет с балансировкой нагрузки, но у такого подхода есть ряд недостатков, на пример не будет работать доступ через на NAT к локальному серверу (сервисы web, smtp, pop, которые были настроены ранее), но не такая большая проблема, но об этом в следующий раз.

(c) slagovskiy.blogspot.ru

2014   mikrotik   network

Настройка Firewall на Mikrotik

Межсетевой экран, брендмауэр или Firewall выполняет фильтрацию пакетов являясь таким образом инструментом обеспечивающим безопасность и управление потоками данных, проходящими через маршрутизатор. Вместе с трансляцией сетевых адресов NAT файервол служит инструментом предотвращения несанкционированного проникновения в сеть компании. Возможно и наоборот применением фильтрации пакетов совместно с транспарентными Proxy серверами и NAT добиться запрета на использование определённых ресурсов и внешних сетей. Полезно Firewall использовать для ограничения доступа к заведомо незащищенным службам. Он может служить препятствием для внедрения ложных данных с помощью уязвимых служб злоумышленником. Также через него возможен контроль доступа к узлам сети, регистрирование попыток доступа как извне, так и из внутренней сети. Можно регламентировать порядок доступа к сети, осуществлять уведомление о подозрительной деятельности, попытках зондирования или атаки на узлы сети или сам экран.

Файервол Mikrotik RouterOS обладает мощными функциями и включает следующие возможности:
1 Фильтрация пакетов;
2 Фильтрация p2p протоколов
3 Классификация трафика по:
3.1 исходный MAC-адрес;
3.2 IP-адрес (сеть или список) и тип адреса (бродкаст, локальный, мультикаст, юникаст);
3.3 Порт или список портов;
3.4 IP-протокол;
3.5 Опции протокола (ICMP тип и другие коды, TCP флаги, IP опции и MSS);
3.6 Интерфейс, откуда получен пакет или куда он назначается;
3.7 Внутренний поток или маркированное подключение;
3.8 Байт ToS (DSCP);
3.9 Содержимое пакета;
3.10 Скорость получения пакетов и количество последовательностей;
3.11 Размер пакета;
3.12 Время получения пакета.

Основные принципы фильтрации

Оперирование файерволом осуществляется посредством правил. Правило определяет выражение, которое говорит роутеру что делать с индивидуальным IP-пакетом. Каждое правило состоит из двух частей: первое описывает параметры, по которым должны классифицироваться приходящие пакеты, второе отвечает за действие над пакетом. Правила, для лучшего управления, организованы в цепочки.
Устройство фильтра по-умолчанию имеет три цепочки: input, forward и output, которые отвечают за приходяший, перемещаемый внутри роутера и исходящий трафик соответственно. Пользователь может добавить новые цепочки, если это будет нужно.
Под эти цепочки трафик по-умолчанию не попадает. Для этого используется метод action=jump с параметром jump-target в одной из предустановленных цепочек.

Цепочки фильтра

Как говорилось раньше, правила фильтрации в файерволе сгруппированы в цепочки. Это позволяет пакету попавшему под некий критерий в одной цепочке переходить к следующему правилу и следующим цепочкам. К примеру пакетам с определённого адреса и порта нужно применить много правил. Конечно, эти правила можно перечислить в цепочке forward, однако правильнее будет создать для них отдельную цепочку, перебросить туда попавшие под условие пакеты и выполнить над ними нужные нам действия: /ip firewall filter add src-address=1.1.1.2/32 jump-target=«mychain». Это правило создаст новую цепочку mychain, в которую попадут все пакеты с адресом источника 1.1.1.2/32.

Три предустановленных цепочки, которые не могут быть удалены:
Input — применимо к пакетам, приходящим на маршрутизатор, у которых адрес получателя такой же, как и у интерфейса, на который этот пакет поступил. Пакеты, проходящие через маршрутизатор не попадают под действие правил цепочки input.
Forward — применимо к пакетам, проходящим через маршрутизатор;
Output — применимо к пакетам созданным маршратизатором, которые покидают его через один из интерфейсов. Пакеты, проходящие через маршрутизатор не попадают под действие цепочки output.
При попадании пакета в одну из цепочек, правила применяются от верхего к нижнему. Если пакет попадает под критерий одного из правил, над ним выполняется указанное в правиле действие и этот пакет не попадает больше под действие других правил из этой цепочки (исключение составляет только действие passthrough). Если пакет не попадает под действие ни одного из правил цепочки, к нему по умолчанию применяется действие Accept.

Описание параметров

action (accept | add-dst-to-address-list | add-src-to-address-list | drop | jump | log | passthrough | reject | return | tarpit; default: accept) — применяемое действие, если пакет совпал с правилом
accept — принять пакет. Не подразумевает каких-либо действий. Если пакет был принят, к нему больше не применяется никаких действий в цепочке.
add-dst-to-address-list — добавить адрес назначения пакета в address list , указанный в параметре address-list
add-src-to-address-list — добавить адрес источника пакета в address list , указанный в параметре address-list
drop — разрушить пакет (без посылки сообщения ICMP reject)
jump — перепрыгнуть в цепочку, указанную в параметре jump-target
log — каждое совпадение с этим действием добавит в системный лог сообщение
passthrough — игнорировать это правило и перейти к следующему
reject —отбросить этот пакет и постать сообщение ICMP reject
return — вернуть пакет в цепочку, из которой он был переброшен
tarpit — захватить и удерживать входящие TCP подключения (отвечать SYN/ACK на входящий TCP SYN пакет)
address-list (name) — указывает имя списка адресов, в которых хранятся IP-адреса из действий action=add-dst-to-address-list или action=add-src-to-address-list. Эти списки могут быть похже использованы в других правилах.
address-list-timeout (time; default: 00:00:00) — интервал времени, через который адреса будут удалены из списка, указанного в параметре address-list . Используется в сочетании с действиями add-dst-to-address-list или add-src-to-address-list .00:00:00 — означает оставить адреса в списке навсегда.
chain (forward | input | output | name) — указывает цепочку, в которую следует поместить правило. Разные типы трафика проходят через разные цепочки, поэтому будьте в курсе своего выбора, указывая то или иное значение этого параметра. Если указанное значение цепочки не совпадает ни с одним из уже существующих, система создаст новое правило с указанным именем.
comment (text) — комментарий описывает правило. В скриптах комментарии обычно служат для идентификации правил.
connection-bytes (integer-integer) — применять правило, если количество переданных байт через подключение превысило указанное значение. 0 — не ограничено, пример: connection-bytes=2000000-0 сработает в том случае, если количество данных, переданных через открытое подключение превысило 2MB;
connection-limit (integer,netmask) — ограничивает количество доступных подключений на адрес или блок адресов;
connection-mark (name) —пакеты, попавшие под действие правил в mangle и названные в соответствии с параметром connection mark
connection-state (established | invalid | new | related) — интерпретация состояния подключения посредством анализа данных из connection tracking .
established — пакет, принадлежащийa уже установленному подключению. К примеру ответ от маршрутизатора.
invalid — пакет, который не может быть идентифицирован по какой-либо причине. К примеру это может быть переполнение памяти и ICMP ошибки. К таким пакетам нужно применять действие DROP
new — пакет, начинающий создание TCP подключения
related — запрошенный пакет, который не принадлежит уже установленным подключениям. К примеру ICMP ошибки, или пакет, начинающий передачу данных по протоколу FTP( /ip firewall service-port)
connection-type (ftp | gre | h323 | irc | mms | pptp | quake3 | tftp) — определение типа подключения, базирующееся на использовании данных из connection tracking. Конфигурирование производится в /ip firewall service-port
content (text) — содержимое текстового пакета
dst-address (IP address/netmask | IP address-IP address) — указывает диапазон адресов, у которых IP-адрес назначения совпадает с параметром. При неправильном введении пары address/netmask система сама подстроит эти параметры. К примеру:1.1.1.1/24 будет заменено на 1.1.1.0/24
dst-address-list (name) — совпадение адреса назначения пакета с определенными ранее значениями в address list
dst-address-type (unicast | local | broadcast | multicast) — совпадение типа адреса назначения пакета с заданным предустановленным значением:
unicast — IP-адреса, используемые ля передачи от одной точки к другой. В таком типе пакетов существует только один отправитель и один получатель
local — совпадеине с адресами, назначенными сетевым интерфейсам маршрутизатора
broadcast — IP-пакет, посылаемый сразу всем членам подсети
multicast — этот тип пакета используется для передачи данных от одного отправителя многим получателям в сети.
dst-limit (integer/time{0,1},integer,dst-address | dst-port | src-address{+},time{0,1}) — ограничивает скорость пакетов в секунду (packet per second (pps)) на IP-адрес или порт.
В результате работы правила каждый IP-адрес или порт назначения получает свой лимит.
Параметр имеет следующие опции:
Count — среднее количество пакетов в секунду (packets per second (pps))за время Time
Time — интервал времени, за который производится подсчёт среднего количества пакетов
Burst — количество пакетов в пике
Mode — классификатор для ограничения скорости пакетов
Expire — указывает интервал, через который записанные IP адреса /порты будут удалены
dst-port (integer: 0..65535-integer: 0..65535{*}) — интервал портов назначения
hotspot (multiple choice: from-client | auth | local-dst | http) — сравнивает пакеты полученные от клиентов с различными хот-спотами. все значения могут быть отклонены/инвертированы
from-client — true, если пакеты получены от Hot-Spot клиента
auth — true, если пакеты получены от авторизированного Hot-Spot клиента
local-dst — true, если пакет имеет локальный адрес назначения
hotspot — true, если TCP пакет от клиента и назначается на 80 порт прозрачного прокси сервера или клиент имеет адрес прокси сконфигурированный и аналогичный адресу:порту пакета
icmp-options (integer:integer) — совпадение полей ICMP Type:Code
in-interface (name) — интерфейс, с которого пакет поступил в маршратизатор
ipv4-options (any | loose-source-routing | no-record-route | no-router-alert | no-source-routing | no-timestamp | none | record-route | router-alert | strict-source-routing | timestamp) — совпадение параметров заголовка ipv4
any — совпадает по крайней мере один пакет с установленной ipv4 опцией
loose-source-routing — пакеты с опцией loose source routing. Эта опция используется для направления интернет дейтаграм основаных на информации поставляемой источником
no-record-route — пакеты с опцией no record route. Эта опция используется для направления интернет дейтаграм основаных на информации поставляемой источником
no-router-alert — совпадение пакетов с опцией no router alter
no-source-routing — совпадение пакетов с опцией no source routing
no-timestamp — совпадение пакетов с опцией with no timestamp
record-route — совпадение пакетов с опцией record route
router-alert — совпадение пакетов с опцией router alter
strict-source-routing — совпадение пакетов с опцией strict source routing
timestamp — совпадение пакетов со штампом времени
jump-target (forward | input | output | name) — имя целевой цепочки куда должен быть отправлен пакет при использовании action=jump.
limit (integer/time{0,1},integer) — ограничивает поток пакетов. Используется для уменьшения количества сообщений в логах
Count — максимальное среднее количество пакетов, указанное в пакетах в секунду (PPS Packet Per Second) за время в опции Time
Time — указывает интервал времени за который будет производиться подсчёт среднего количества пакетов
Burst — количество пакетов при пике
log-prefix (text) — все сообщения, записываемые в лог, будут иметь этот префикс. Используется вместе с опцией action=log
nth (integer,integer: 0..15,integer{0,1}) — совпадение каждого n-ного пакета, попавшего в правило. Всего доступно 16 счётчиков
Every — совпадение каждого Every+1th пакета. К примеру, если Every=1 тогда под действие правила попадёт каждый второй пакет
Counter — указывает какой счётчик будет использоваться. Счётчик увеличивается на 1 с каждым новым правилом где указанна опция nth
Packet -совпадает с номером данного пакета. Значение по очевидным причинам должно быть между нулем и Every. Если опиция используется для данного счетчика, тогда должно быть по крайней мере Every+1 правило с этой опцией, охватывающее все значения между 0 и Every включительно out-interface (name) — интерфейс, через который пакеты будут покидать маршрутизатор
p2p (all-p2p | bit-torrent | blubster | direct-connect | edonkey | fasttrack | gnutella | soulseek | warez | winmx) — совпадение пакетов протоколов peer-to-peer (P2P)
packet-mark (text) — цепочка пакетов, промаркированная в разделе mangle файервола
packet-size (integer: 0..65535-integer: 0..65535{0,1}) — размер пакета в байтах
Min — указывает нижний предел диапазона размера пакета
Max — указывает верхний предел диапазона размера пакета

phys-in-interface (name) — физический интерфейс, указанный в качестве порта моста, по которому пакет поступил в маршрутизатор
phys-out-interface (name) — физический интерфейс, указанный в качестве порта моста, по которому пакет выйдет из маршрутизатора
protocol (ddp | egp | encap | ggp | gre | hmp | icmp | idrp-cmtp | igmp | ipencap | ipip | ipsec-ah | ipsec-esp | iso-tp4 | ospf | pup | rdp | rspf | st | tcp | udp | vmtp | xns-idp | xtp | integer) — совпадение IP протокола. Указывается имя протокола или его номер. Вы должны указать эту опцию, чтобы получить доступ к специфическим параметрам для каждого протокола.
psd (integer,time,integer,integer) — попытка определения сканирования TCP и UDP портов. Необходимо назначить меньшее значение портам с высокими номерами для того, чтобы уменьшить количество ложных срабатываний. К примеру, при использовании пассивного режима FTP.
WeightThreshold — полный вес последних TCP/UDP пакетов с различными портами назначения, поступающими с одного хоста, которые распознанные как один из методов сканирования
DelayThreshold — задержка между пакетами с разными портами назначения, поступающие с одного хоста и распознанные как возможная последовательность сканирования
LowPortWeight — вес пакетов при сканировании привилегированных портов (<=1024)
HighPortWeight — вес пакетов на непривилегированные порты назначения
random (integer: 1..99) — совпадение пакетов с заданным уровнем случайности
reject-with (icmp-admin-prohibited | icmp-echo-reply | icmp-host-prohibited | icmp-host-unreachable | icmp-net-prohibited | icmp-network-unreachable | icmp-port-unreachable | icmp-protocol-unreachable | tcp-reset | integer) — указывает причину по которой был отброшен пакет в action=reject
routing-mark (name) — совпадение пакетов, обозначенных в цепочке mangle параметром routing mark
src-address (IP address/netmask | IP address-IP address) — указывает диапазон адресов IP пакетов поступивших извне. Замечание: консоль конвертирует неправильно набранные IP значения address/netmask в правильный сетевой адрес. К примеру:1.1.1.1/24 будет конвертирован в 1.1.1.0/24
src-address-list (name) — совпадение адреса источника с списком IP-адресов в предустановленном пользователе address list
src-address-type (unicast | local | broadcast | multicast) — совпадение типа IP-адреса:
unicast — IP адрес используется для передачи данных между двумя узлами, где только один отправитель и один получатель
local — совпадение адреса, назначенного одному из интерфейсов маршрутизатора
broadcast — IP пакет был отправлен из одной точки всем получателям и IP подсети
multicast — этот типа IP адресации ответственен за передачу между одной или несколькими точками одной или набору других точек
src-mac-address (MAC address) — MAC адрес источника
src-port (integer: 0..65535-integer: 0..65535{*}) — диапазон портов источника
tcp-flags (ack | cwr | ece | fin | psh | rst | syn | urg) — tcp флаги
ack — запрос данных
cwr — принимающее окно уменьшено
ece — ECN-флаг echo (explicit congestion notification)
fin — закрытие подключения
psh — функция push
rst — разорвать подключение
syn — новое подключение
urg — urgent data
tcp-mss (integer: 0..65535) — совпадение значения TCP MSS IP пакета
time (time-time,sat | fri | thu | wed | tue | mon | sun{+}) — позволяет создать фильтр, базирующийся на времени получения пакета или дате. Для локально созданных пакетов дате отправки
tos (max-reliability | max-throughput | min-cost | min-delay | normal) — совпадение с полем «тип сервиса» Type of Service (ToS) в IP загаловке
max-reliability — максимальная надёжность (ToS=4)
max-throughput — максимальная пропускная способность (ToS=8)
min-cost — минимальная стоимость (ToS=2)
min-delay — минимальная задержка (ToS=16)
normal — нормальное обслуживание (ToS=0)

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

Примеры применения

Защита вашего маршрутизатора RouterOS

Для защиты вашего маршрутизатора сменить пароль администратора недостаточно и нужно воспользоваться фильтрацией пакетов. Все пакеты с адресом назначения маршрутизатора попадают во входную цепочку файервола INPUT. Заметьте, что попавшие в цепочку INPUT пакеты не будут проходить через маршрутизатор.

/ip firewall filter
add chain=input connection-state=invalid action=drop comment="Drop Invalid connections"
add chain=input connection-state=established action=accept comment="Allow Established connections"
add chain=input protocol=udp action=accept comment="Allow UDP"
add chain=input protocol=icmp action=accept comment="Allow ICMP"
add chain=input src-address=192.168.0.0/24 action=accept comment="Allow access to router from known network"
add chain=input action=drop comment="Drop anything else"

Для защиты сети проверяется весь трафик проходящий через маршрутизатор и блокировать нежелательные пакеты:

/ip firewall filter
add chain=forward protocol=tcp connection-state=invalid action=drop comment="drop invalid connections"
add chain=forward connection-state=established action=accept comment="allow already established connections"
add chain=forward connection-state=related action=accept comment="allow related connections"

Блокировать IP адреса, названные «bogons»:

add chain=forward src-address=0.0.0.0/8 action=drop
add chain=forward dst-address=0.0.0.0/8 action=drop
add chain=forward src-address=127.0.0.0/8 action=drop
add chain=forward dst-address=127.0.0.0/8 action=drop
add chain=forward src-address=224.0.0.0/3 action=drop
add chain=forward dst-address=224.0.0.0/3 action=drop

Перебросить их в другую цепочку:

add chain=forward protocol=tcp action=jump jump-target=tcp
add chain=forward protocol=udp action=jump jump-target=udp
add chain=forward protocol=icmp action=jump jump-target=icmp

Создать цепочку tcp и запретить некоторые tcp порты:

add chain=tcp protocol=tcp dst-port=69 action=drop comment="deny TFTP"
add chain=tcp protocol=tcp dst-port=111 action=drop comment="deny RPC portmapper"
add chain=tcp protocol=tcp dst-port=135 action=drop comment="deny RPC portmapper"
add chain=tcp protocol=tcp dst-port=137-139 action=drop comment="deny NBT"
add chain=tcp protocol=tcp dst-port=445 action=drop comment="deny cifs"
add chain=tcp protocol=tcp dst-port=2049 action=drop comment="deny NFS"
add chain=tcp protocol=tcp dst-port=12345-12346 action=drop comment="deny NetBus"
add chain=tcp protocol=tcp dst-port=20034 action=drop comment="deny NetBus"
add chain=tcp protocol=tcp dst-port=3133 action=drop comment="deny BackOriffice"
add chain=tcp protocol=tcp dst-port=67-68 action=drop comment="deny DHCP"

Запретить udp порты в цепочке udp:

add chain=udp protocol=udp dst-port=69 action=drop comment="deny TFTP"
add chain=udp protocol=udp dst-port=111 action=drop comment="deny PRC portmapper"
add chain=udp protocol=udp dst-port=135 action=drop comment="deny PRC portmapper"
add chain=udp protocol=udp dst-port=137-139 action=drop comment="deny NBT"
add chain=udp protocol=udp dst-port=2049 action=drop comment="deny NFS"
add chain=udp protocol=udp dst-port=3133 action=drop comment="deny BackOriffice"

Разрешить только необходимые коды icmp в цепочке с именем icmp:

add chain=icmp protocol=icmp icmp-options=0:0 action=accept comment="drop invalid connections"
add chain=icmp protocol=icmp icmp-options=3:0 action=accept comment="allow established connections"
add chain=icmp protocol=icmp icmp-options=3:1 action=accept comment="allow already established connections"
add chain=icmp protocol=icmp icmp-options=4:0 action=accept comment="allow source quench"
add chain=icmp protocol=icmp icmp-options=8:0 action=accept comment="allow echo request"
add chain=icmp protocol=icmp icmp-options=11:0 action=accept comment="allow time exceed"
add chain=icmp protocol=icmp icmp-options=12:0 action=accept comment="allow parameter bad"
add chain=icmp action=drop comment="deny all other types"

(c) netflow.by

2014   mikrotik   network

Nginx как прокси для Apache2

Имеем сервер под Linux Debian

# uname -a
Linux server 2.6.18-6-686 #1 SMP Mon Oct 13 16:13:09 UTC 2008 i686 GNU/Linux
# nginx -V
nginx version: nginx/1.1.17
# apache2 -V
Server version: Apache/2.2.9 (Debian)

Конфигурация Nginx

# cat /usr/local/nginx/conf/sites-enabled/blog.a-zazell.ru
server {

listen 93.190.18.10:80;
server_name blog.a-zazell.ru ;

root /var/www/a-zazell.ru/blog/wp;
index index.php;

access_log  /var/log/nginx/blog.a-zazell.ru_access.log;
error_log  /var/log/nginx/blog.a-zazell.ru_error.log;
# Все проксируем без кэширования на Apache2
location / {
    proxy_pass http://127.0.0.1:8888/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    proxy_redirect     off;
    client_max_body_size       10m;
    proxy_cache off;
}
# Статику отдает Nginx
location ~* \.(jpg|jpeg|gif|png|ico|css|bmp|swf|js|html|txt)$ {
    #log_not_found off;
}
# Если нет иконки, не надо мусорить в Лог
location = /favicon.ico {log_not_found off;access_log off;}
# Смотреть файлы с точки НЕЛЬЗЯ
location ~ /\. {deny all;access_log off;log_not_found off;}
# Роботам в Лог не сорить
location = /robots.txt { access_log off; log_not_found off; }

}
# Переносим Всех, кто зашел на http://a-zazell.ru в блог
server {
listen 93.190.18.10:80;
server_name www.a-zazell.ru a-zazell.ru;
return 301 http://blog.a-zazell.ru;
}

Конфигурация Apache2

# cat /etc/apache2/sites-enabled/blog.a-zazell.ru
<VirtualHost *:8888>

ServerName blog.a-zazell.ru
ServerAdmin mail@a-zazell.ru
DocumentRoot /ftp/httpd/a-zazell.ru/blog/wp

ErrorLog /var/log/apache2/blog.a-zazell.ru_error.log
TransferLog /var/log/apache2/blog.a-zazell.ru_access.log

RewriteEngine On
<Directory /var/www/a-zazell.ru/blog/wp/>
 Options -Indexes FollowSymLinks Includes ExecCGI
 AllowOverride All
 order deny,allow
 allow from all
</Directory>
</VirtualHost>

Вышеописанной конфигурации вполне достаточно. Еще не забудьте добавить в Apache2 модуль rpaf (libapache2-mod-rpaf).

(c) blog.a-zazell.ru

2014   nix   web

Что нужно не забыть при передаче роли PDC эмулятора

Проблема
Иногда возникает абсолютно жизненная ситуация — роли хозяина операций.
Сервер может переезжать на новую платформу, апгрейдится, или просто сломаться.
Здесь часто упускается довольно важная деталь- при передаче роли PDC эмулятора (чьей одной из многих забот является контроль точного времени в домене) автоматически не изменяется параметр реестра, отвечающий за эту настройку.
//(HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\W32Time\Parameters\Type)

Сценарий
Таким образом, представим ситуацию- у Вас имеется один лес, один домен и два сервера, являющихся контроллерами домена.
Отказывает один из контроллеров (PDC), и эта роль вручную передается второму контроллеру.
Что произойдет в этом случае? Параметр реестра, объявляющий сервер надежным источником точного времени, не «переедет» на нового владельца, и синхронизация времени нарушится.
Исправление

  1. На «старом» PDC Emulator, выполните:
w32tm /config /syncfromflags:domhier /reliable:no /update

net stop w32time
net start w32time
  1. Передайте роль PDC Emulator на новый контроллер домена.
  2. На «новом» PDC Emulator, выполните:
w32tm /config /manualpeerlist:PEERS /syncfromflags:manual /reliable:yes /update

где PEERS будут серверами-источниками точного времени,параметр может принимать значение DNS имени либо IP адреса.
Если источников больше одного, между ними необходимо ввести пробел, и также не забудьте про кавычки: «time.domain.com time1.domain.com».

(c) social.technet.microsoft.com

2014   ad   windows
Ранее Ctrl + ↓