0,0
рейтинг
23 июля 2013 в 20:20

Разработка → Работаем с реестром запрещенных ресурсов из песочницы

Автоматизация получения реестра запрещенных ресурсов средствами C#, OpenSSL и фильтрация средствами RouterOS на базе оборудования MikroTik

image

Внимание! Статья изменена согласно последних изменений на 19/03/2014


Вводное



В работе будем руководствоваться памяткой оператора связи.
Работа состоит из следующих пунктов:
  1. Создание запроса
  2. Установка и настройка OpenSSL
  3. Подпись запроса
  4. Подача запроса и получение результата обработки запроса
  5. Обработка результата
  6. Добавление в фильтр на MikroTik`е


Создание запроса



Для подачи запроса на получение выгрузки из реестра необходимо прикрепить файл запроса в формате XML. Файл имеет следующий вид:

<?xml version="1.0" encoding="windows-1251"?>
<request>
 <requestTime>2012-01-01T01:01:01.000+04:00</requestTime>
 <operatorName><![CDATA[Наименование оператора]]></operatorName>
 <inn>1234567890</inn>
 <ogrn>1234567890123</ogrn>
 <email>email@email.ru</email>
</request>


  • requestTime – дата и время формирования запроса с указанием временной зоны;
  • operatorName – полное наименование оператора связи;
  • inn – ИНН оператора связи (10 цифр для юридических лиц, 12 цифр для ИП);
  • ogrn – ОГРН оператора связи (13 цифр для юридических лиц, 15 цифр для ИП);
  • email – электронный адрес технического специалиста, ответственного за использование механизма получения выгрузки; может
    использоваться для оперативной обратной связи в случае возникновения технических вопросов или проблем. Необязательный параметр.


Главное получить время в формате 2012-01-01T01:01:01.000+04:00 и сохранить файл с кодировкой windows-1251.

Код функции генерации запроса на C#:

public static String GeneratingRequest(String operatorName, String inn, String ogrn, String email)
{
	String result = "<?xml version=\"1.0\" encoding=\"windows-1251\"?>";
	result += "<request><requestTime>";
	result += DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffzzz");
	result += "</requestTime><operatorName>";
	result += "<![CDATA[" + operatorName + "]]>";
	result += "</operatorName><inn>";
	result += inn;
	result += "</inn><ogrn>";
	result += ogrn;
	result += "</ogrn><email>";
	result += email;
	result += "</email></request>";
 
	return result;
}


Теперь сохраняем файл в кодировке windows-1251:
String Request = GeneratingRequest("Наименование оператора", "1234567890", "1234567890123", "email@email.ru")
StreamWriter swRequest = new StreamWriter(@"C:\request.xml", false, Encoding.GetEncoding("Windows-1251"));
swRequest.Write(Request);
swRequest.Close();


После создания запроса нам необходимо его подписать. Для этого воспользуемся криптографическим пакетом с открытым исходным кодом для работы с SSL/TLSOpenSSL. Установим и настроем.

OpenSSL


Качаем пакет с этого сайта — slproweb.com. В моем случае это был Win64 OpenSSL v1.0.1g.

Да эта сборка требует для работы установленного Visual C++ 2008 Redistributables, который можно скачать там же.
Устанавливаем. При установке в диалоге «Select Additional Tasks» следует выбрать «The OpenSSL” binaries (/bin) directory» более хитростей нет.
Далее переходим в папку куда установили: C:/OpenSSL/bin и редактируем файл openssl.cfg. В начало файла добавим:

openssl_conf = openssl_def

В конце:
[openssl_def]
engines=engine_section

[engine_section]
gost=gost_section

[gost_section]
engine_id=gost
dynamic_path = C:/OpenSSL/bin/gost.dll
default_algorithms=ALL

Все практически уже работает осталось настроить переменные среды:
OPENSSL_CONF = C:/OpenSSL/bin/openssl.cfg — полный путь к openssl.cfg
ну и в PATH += C:/OpenSSL/bin;

Теперь нам нужна ЭЦП. Приобрести ее можно в доверенном удостоверяющем центре. Ключ необходимо экспортировать в формате PKCS#12 из криптоконтейнера в Windows с помощью утилиты P12FromGostCSP

Почему P12FromGostCSP
Цитирую комментарий xtron из статьи Взаимодействие php-soap на linux с авторизацией по сертификатам с использованием алгоритмов ГОСТ

Не все так просто как кажется на первый взгляд. На самом деле сертификат, экспортируемый через стандартный диалог просмотра сертификата не распознается openssl. Получается такая ошибка:
MAC verified OK
Bag Attributes
localKeyID: 01 00 00 00
friendlyName: REGISTRY\\mstaff
Microsoft CSP Name: Crypto-Pro GOST R 34.10-2001 Cryptographic Service Provider
Error outputting keys and certificates
140017040754368:error:06074079:digital envelope routines:EVP_PBE_CipherInit:unknown pbe algorithm:evp_pbe.c:167:TYPE=1.2.840.113549.1.12.1.80
140017040754368:error:23077073:PKCS12 routines:PKCS12_pbe_crypt:pkcs12 algor cipherinit error:p12_decr.c:83:
140017040754368:error:2306A075:PKCS12 routines:PKCS12_item_decrypt_d2i:pkcs12 pbe crypt error:p12_decr.c:130:

Вот как раз эта утилита и позволяет избежать такой ошибки. Цитирую разработчиков данной утилиты:

Контейнер PKCS#12, создаваемый утилитой P12FromGostCSP полностью совместим с аналогичными контейнерами, создаваемыми ООО «КриптоКом» (в рамках проекта openssl) и ООО «Топ Кросс», чего, к сожалению, не скажешь о контейнере, создаваемом программными средствами, входящими в состав КриптоПро CSP (начиная с версии R3).

Просмотреть ASN1-структуры контейнера PKCS#12, созданного средствами КриптоПро CSP R3, и контейнеров, созданных другими средствами, удобно утилитами openssl или lirssl следующего вида:

#openssl asn1parse –inform DER –in <контейнер PKCS#12>

Если вы сравните эти структуры, то вам сразу бросится в глаза, что, например, вместо алгоритма хэширования ГОСТ Р 34.11-94 в контейнере от КриптоПро используется SHA1. Еще более интересный результат вы получите, если попробуете посмотреть содержимое контейнера, выполнив следующую команду:

#openssl pkcs12 –in <контейнер PKCS#12>



Файл PKCS#12 должен содержать сертификат и закрытый ключ! Проверить это можно командой:

openssl.exe pkcs12 -in C:/key.pfx -nodes


image

Далее преобразовать его в PEM. В OpenSSL это делается так (через командную строку — может запросить пароль которым защищен Ключ PKCS#12):

openssl.exe pkcs12 -in C:/key.pfx -out C:/key.pem -nodes -clcerts


image

Все теперь мы в состоянии подписать наш запрос.

Подпись запроса



Подписать запрос можно через OpenSSL следующей командой:

openssl.exe smime -sign -in C:/request.xml -out C:/request.xml.sign -signer C:/key.pem -outform DER


image

Реализация функции подписи файла на C#:

public static Boolean SignRequest()
{
	Boolean ret = true;
 
	String OpenSSLPath = @"C:\OpenSSL\bin";
	String RequestPath = @"C:\request.xml";   
	String SignRequestPath = @"C:\request.xml.sign";
	String KeyPEMPath = @"C:\key.pem";
 
	try
	{
 
		Process cmdProcess = new Process();
 
		/*
		 * Строку ниже можно убрать 
		 * если переменная среды PATH
		 * имеет путь до OpenSSL
		 */
		cmdProcess.StartInfo.WorkingDirectory = OpenSSLPath;
		cmdProcess.StartInfo.FileName = "openssl.exe";
		cmdProcess.StartInfo.Arguments = String.Format("smime -sign -in {0} -out {1} -signer {2} -outform DER", RequestPath, SignRequestPath, KeyPEMPath);
 
		cmdProcess.StartInfo.CreateNoWindow = true;
		cmdProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
		cmdProcess.Start();

		//Спасибо dimzon541
		if (!cmdProcess.WaitForExit(5000))
		{
			cmdProcess.Kill();
			ret = false;
		}  
	}
	catch (Exception)
	{
		ret = false;
	}
 
	return ret;
}


Теперь проверим нашу работу. Подтверждение подлинности ЭП: gosuslugi.ru, выбираем — Подтверждение подлинности электронного документа. ЭП — отсоединенная, в формате PKCS#7

Можно проверить и средствами OpenSSL, но для этого нужно извлечь сертификат издателя, которая предоставила ЭЦП и конвертировать ее в PEM формат (сертификат можно еще взять тут):
openssl x509 -inform der -in C:/most.cer -out C:/most.pem


И проверяем нашу подпись:
openssl.exe smime -verify -in C:/request.xml.sign -content C:/request.xml -CAfile C:/most.pem -inform DER -out C:/validrequest.xml


В результате мы увидим строчку:
Verification successful

а в файле validrequest.xml будет лежать содержимое request.xml.

Переходим непосредственно к запросу дампа реестра запрещенных ресурсов.

Подача запроса и выгрузка реестра



В ручную все просто: Форма подачи запроса, отправляем файл запроса и его подпись (C:/request.xml и C:/request.xml.sign)

image

Если все нормально то результатом будет — Идентификатор запроса, с помощью его можно проверять результат обработки запроса. Как правило если все нормально то реестр будет выгружен минут через 5 в ZIP формате в архиве будет два файла dump.xml — дамп реестра и его цифровая подпись.

Проверить файл можно OpenSSL или gosuslugi.ru:
openssl.exe smime -verify -in C:/dump.xml.sig -content C:/dump.xml -CAfile C:/cartk.pem -inform DER -out C:/validdump.xml


В результате мы увидим строчку:
Verification successful

а в файле validdump.xml будет лежать содержимое dump.xml.

Теперь автоматизируем данный процесс. Для выгрузки есть сервис работающий по протоколу доступа SOAP, адрес: сервиса. WSDL схема доступна по адресу: WSDL схема.

Сервис состоит из 4-х методов:

  • getLastDumpDateEx
    Метод предназначен для получения временной метки последнего обновления выгрузки из реестра. В ответ присылает lastDumpDatelong дата приходит в формате UNIX Timestamp, но не в секундах, а в миллисекундах, а так же lastDumpDateUrgently — Момент времени, когда в выгрузку последний раз были внесены изменения, требующие незамедлительного реагирования (так же приходит в формате UNIX Timestamp, но не в секундах, а в миллисекундах).
  • getLastDumpDate
    Оставлен для совместимости. Аналогичен getLastDumpDateEx, но возвращает только один параметр lastDumpDate., long дата приходит в формате UNIX Timestamp, но не в секундах, а в миллисекундах.
  • sendRequest
    Метод предназначен для направления запроса на получение выгрузки из реестра, Принимает requestFile и signatureFile в base64Binary формате — файл запроса и его подписи (C:/request.xml и C:/request.xml.sign) В ответ присылает result — Результат обработки запроса в boolean формате и если все удачно, то code — Идентификатор запроса, строка по которой необходимо получить выгрузку из реестра в формате string. Так же resultComment — Комментарий к результату обработки запроса в формате string.
  • getResult
    Метод предназначен для получения результата обработки запроса — выгрузки из реестра, принимает code — Идентификатор запроса, строка по которой необходимо получить выгрузку из реестра в формате string. В ответ присылает result — Результат обработки запроса в boolean формате и если все удачно, то registerZipArchive — Файл zip-архив с выгрузкой из реестра в формате base64Binary. Так же resultComment — Комментарий к результату обработки запроса в формате string.


Возможные значения тега resultComment:
  • запрос обрабатывается
  • неверный алгоритм ЭП
  • неверный формат ЭП
  • недействительный сертификат ЭП
  • некорректное значение ЭП
  • ошибка проверки сертификата ЭП
  • у заявителя отсутствует лицензия, дающая право оказывать услуги по предоставлению доступа к информационно-телекоммуникационной сети Интернет


Информация по обратной связи для разрешения проблем приведена в Памятке оператору связи в этом разделе.

Логика работы с сервисом:
  1. Проверить, обновилась ли выгрузка из реестра. Для этого вызвать метод getLastDumpDateEx и сравнить полученное значение со значением, полученным на предыдущей итерации. В случае если значение lastDumpDateUrgently изменилось, то незамедлительно запросить обновленную выгрузку. В остальных случаях обновлять выгрузку на усмотрение, но не реже одного раза в сутки.
  2. В случае, если выгрузка обновилась, направить запрос на получение выгрузки с использованием метода sendRequest.
  3. Через несколько минут вызвать метод getResult для получения результата обработки запроса. В случае если запрос не обработан еще (см. содержимое поля resultComment) повторить шаг 3 через несколько минут.


Добавляем в ресурсы сервис, передавая адрес WSDL схемы.
Код функций getLastDumpDate, sendRequest, getResult

MaxReceivedMessageSize
Недавно стали появляться ошибки вида: Превышена квота максимального размера сообщения для входящих сообщений (65536). Для увеличения квоты используйте свойство MaxReceivedMessageSize соответствующего элемента привязки.

Ввиду чего пришлось увеличить свойство MaxReceivedMessageSize.
Комментарий службы поддержки:
На данный момент ответ метода getResult содержит xml-блок данных, размер которого чуть больше 65536 байт.



public static Int64 LastDumpDate()
{
	Int64 lastDumpDate = 0;
 
	BasicHttpBinding HttpBinding = new BasicHttpBinding();
	HttpBinding.MaxReceivedMessageSize = 1*1024*1024*1024; //1Gb

	using (ChannelFactory<ServiceReference.OperatorRequestPortType> scf = new ChannelFactory<ServiceReference.OperatorRequestPortType>(
		HttpBinding, new EndpointAddress("http://vigruzki.rkn.gov.ru/services/OperatorRequest/")))
	{
		ServiceReference.OperatorRequestPortType channel = scf.CreateChannel();
		ServiceReference.getLastDumpDateResponse glddr = channel.getLastDumpDate(new ServiceReference.getLastDumpDateRequest());
		lastDumpDate = glddr.lastDumpDate;
	}
 
	return lastDumpDate;
}
 
public static Boolean SendRequest(out String resultComment, out String code, Byte[] requestFile, Byte[] signatureFile)
{
	Boolean result = false;
	code = null;
	 
	BasicHttpBinding HttpBinding = new BasicHttpBinding();
	HttpBinding.MaxReceivedMessageSize = 1*1024*1024*1024; //1Gb

	using (ChannelFactory<ServiceReference.OperatorRequestPortType> scf = new ChannelFactory<ServiceReference.OperatorRequestPortType>(
		HttpBinding, new EndpointAddress("http://vigruzki.rkn.gov.ru/services/OperatorRequest/")))
	{
		ServiceReference.OperatorRequestPortType channel = scf.CreateChannel();
		ServiceReference.sendRequestRequestBody srrb = new ServiceReference.sendRequestRequestBody();
 
		srrb.requestFile = requestFile;
		srrb.signatureFile = signatureFile;
 
		ServiceReference.sendRequestResponse srr = channel.sendRequest(new ServiceReference.sendRequestRequest(srrb));
 
		resultComment = srr.Body.resultComment;
 
		if (result = srr.Body.result)
		{
			code = srr.Body.code;
		}
	}
 
	return result;
}
 
public static Boolean GetResult(out String resultComment, out Byte[] registerZipArchive, String code)
{
	Boolean result = false;
	registerZipArchive = null;
 
	BasicHttpBinding HttpBinding = new BasicHttpBinding();
	HttpBinding.MaxReceivedMessageSize = 1*1024*1024*1024; //1Gb

	using (ChannelFactory<ServiceReference.OperatorRequestPortType> scf = new ChannelFactory<ServiceReference.OperatorRequestPortType>(
		HttpBinding, new EndpointAddress("http://vigruzki.rkn.gov.ru/services/OperatorRequest/")))
	{
		ServiceReference.OperatorRequestPortType channel = scf.CreateChannel();
		ServiceReference.getResultRequestBody grrb = new ServiceReference.getResultRequestBody();
 
		grrb.code = code;
 
		ServiceReference.getResultResponse grr = channel.getResult(new ServiceReference.getResultRequest(grrb));
 
		resultComment = grr.Body.resultComment;
 
		if (result = grr.Body.result)
		{
			registerZipArchive = grr.Body.registerZipArchive;
		}
	}
 
	return result;
}


Например отправим запрос:

String resultComment, code;
if(SendRequest(out resultComment, out code, File.ReadAllBytes(@"C:/request.xml"), File.ReadAllBytes(@"C:/request.xml.sign")))
{
	//... Все удачно
}


Временную метку последнего обновления выгрузки из реестра можно конвертировать из UNIX Timestamp в DateTime вот так:
DateTime LastDumpDate = (new DateTime(1970, 1, 1, 0, 0, 0, 0)).AddSeconds(LastDumpDate()/1000);


Разбираем дамп реестра



Надо распаковать архив:
// Byte[] registerZipArchive - Получен при удачной выгрузке GetResult();
File.WriteAllBytes(@"C:/register.zip", registerZipArchive);
ZipFile.ExtractToDirectory(@"C:/register.zip", @"C:/register");


В результате получаем дамп реестра C:/register/dump.xml
Пример содержимого дампа:
<?xml version="1.0" encoding="windows-1251"?>
<reg:register updateTime="2014-02-02T12:00:00+04:00" xmlns:reg="http://rsoc.ru" xmlns:tns="http://rsoc.ru" updateTimeUrgently="2014-02-01T11:00:00"> 
    <content id="68" includeTime="2013-12-01T10:00:05">
        <decision date="2013-12-01" number="9" org="Роспотребнадзор"/>
        <url><![CDATA[http://site1.com/index.php]]></url>
        <domain><![CDATA[site1.com]]></domain>
        <ip>1.1.1.1</ip>
    </content>
    <content id="68" includeTime="2013-12-01T10:00:05">
        <decision date="2013-12-01" number="9" org="Мосгорсуд"/>
        <url><![CDATA[http://site2.com/page1.php]]></url>
        <url><![CDATA[http://site2.com/page2.php]]></url>
        <url><![CDATA[http://site2.com/page3.php]]></url>
        <domain><![CDATA[site2.com]]></domain>
        <ip>1.1.1.1</ip>
        <ip>1.1.1.2</ip>
    </content>
    <content id="9999" includeTime="2014-02-01T15:17:51" urgencyType="1">
        <decision date="2014-02-01" number="номер документа" org="Генпрокуратура"/>
        <url><![CDATA[http://site3.com/page1.html]]></url>
        <domain><![CDATA[site3.com]]></domain>
        <ip>1.2.3.4</ip>
    </content>
</reg:register>


Парсим XML

Для этого создадим два класса: первый RegisterDump будет содержать поле UpdateTime и список объектов content, Второй ItemRegisterDump представляет один объект content со всеми полями.

public class RegisterDump
{
	/*
	 * <reg:register updateTime="2013-07-15T10:05:00+04:00" xmlns:reg="http://rsoc.ru" xmlns:tns="http://rsoc.ru">
	 *    <content></content>
	 *    <content></content>
	 *       ...
	 *    <content></content>
	 * </reg:register>
	 */
 
	public List<ItemRegisterDump> Items { get; set; }
	public String UpdateTime { get; set; }
 
	public RegisterDump()
	{
		this.Items = new List<ItemRegisterDump>();
		this.UpdateTime = String.Empty;
	}
 
	public RegisterDump(String UpdateTime, List<ItemRegisterDump> Items)
	{
		this.Items = Items;
		this.UpdateTime = UpdateTime;
	}
}
 
public class ItemRegisterDump
{
	/*
	 * <content id="60" includeTime="2013-01-12T16:33:38">
	 *    <decision date="2013-11-03" number="МИ-6" org="РосКосМопсПопс"/>
	 *    <url><![CDATA[http://habrahabr.ru/post/187574/]]></url>
	 *    <ip>123.45.67.89</ip>
	 * </content>
	 * <content id="69" includeTime="2013-05-12T12:43:34">
	 *    <decision date="2013-10-02" number="ФБИ" org="СФНК"/>
	 *    <domain><![CDATA[chelaxe.ru]]></domain>
	 *    <ip>123.45.67.89</ip>
	 *    <ip>87.65.43.210</ip>
	 * </content>
	 */
 
	public String id { get; set; }
	public String includeTime { get; set; }
 
	public String date { get; set; }
	public String number { get; set; }
	public String org { get; set; }
 
	public List<String> url { get; set; }
	public List<String> domain { get; set; }
	public List<String> ip { get; set; }
 
	public ItemRegisterDump()
	{
		id = String.Empty;
		includeTime = String.Empty;
 
		date = String.Empty;
		number = String.Empty;
		org = String.Empty;
 
		url = new List<String>();
		domain = new List<String>();
		ip = new List<String>();
	}
}


Парсим:

RegisterDump Register = new RegisterDump();
String dumpfile = @"C:/register/dump.xml";
 
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(dumpfile);
 
Register.UpdateTime = xmlDoc.GetElementsByTagName("reg:register")[0].Attributes.GetNamedItem("updateTime").InnerText;
XmlNodeList content = xmlDoc.GetElementsByTagName("content");
 
for (int i = 0; i < content.Count; i++)
{
	ItemRegisterDump item = new ItemRegisterDump();
	item.id = content[i].Attributes.GetNamedItem("id").InnerText;
	item.includeTime = content[i].Attributes.GetNamedItem("includeTime").InnerText;
	foreach (XmlNode node in content[i].ChildNodes)
	{ 
		switch(node.Name)
		{
			case "decision":
				item.date = node.Attributes.GetNamedItem("date").InnerText;
				item.number = node.Attributes.GetNamedItem("number").InnerText;
				item.org = node.Attributes.GetNamedItem("org").InnerText;
				break;
			case "url":
				item.url.Add(node.InnerText);
				break;
			case "domain":
				item.domain.Add(node.InnerText);
				break;
			case "ip":
				item.ip.Add(node.InnerText);
				break;
		}
	}
	Register.Items.Add(item);
}


Теперь блокируем все это добро на нашем MikroTik.

Блокируем средством MikroTik


Делаем мы это с помощью layer7-protocol и добавляем в фильтры.

Вот пример:
/ip firewall layer7-protocol add name=12 comment=register regexp=^.+(chelaxe.ru).*$
/ip firewall filter add action=drop chain=forward disabled=no dst-port=80 layer7-protocol=12 protocol=tcp src-address=192.168.0.0/24 comment=register

image
image
image
image

Все теперь все пакеты для подсети 192.168.0.0/24 приходящие по TCP на 80 порт с содержанием подстроки chelaxe.ru отбрасываются.
В комментарии надпись register добавляется не с проста. Она нужна нам будет для удаления всех правил прежде чем добавить обновленные.

Вот скрипт который удалит все записи:

/ip firewall layer7-protocol remove [find comment=register]
/ip firewall filter remove [find comment=register]

image

Общение с MikroTik роутером будет посредством API, необходимую библиотеку с примерами нам уже написали: wiki/API C#

Используя эту библиотеку (класс) и принцип блокирования контента разобранный выше реализуем все это на C#

public static Boolean AddFilterL7(String ip, String username, String password, RegisterDump dump, String SRCAddress)
{
	Boolean ret = true;
 
	try
	{
		//Класс MK смотри здесь http://wiki.mikrotik.com/wiki/API_in_C_Sharp
		MK mikrotik = new MK(IPAddress.Parse(ip).ToString());
 
		if (mikrotik.Login(username, password))
		{
			mikrotik.Send("/system/script/add");
			mikrotik.Send("=name=cleaner");
			mikrotik.Send("=source=/ip firewall layer7-protocol remove [find comment=register]\n/ip firewall filter remove [find comment=register]", true);

			mikrotik.Read();

			mikrotik.Send("/system/script/run");
			mikrotik.Send("=number=cleaner", true);

			mikrotik.Read();

			/* Cleaner
			 * /ip firewall layer7-protocol remove [find comment=register]
			 * /ip firewall filter remove [find comment=register]
			 */

			foreach (ItemRegisterDump item in dump.Items)
			{
				for (Int32 i = 0; i < item.domain.Count; i++ )
				{
					mikrotik.Send("/ip/firewall/layer7-protocol/add");
					mikrotik.Send("=name=" + item.id + "_" + i);
					mikrotik.Send("=comment=register");
					mikrotik.Send("=regexp=^.+(" + item.domain[i] + ").*$", true);

					mikrotik.Read();

					mikrotik.Send("/ip/firewall/filter/add");
					mikrotik.Send("=action=drop");
					mikrotik.Send("=chain=forward");
					mikrotik.Send("=disabled=no");
					mikrotik.Send("=dst-port=80");
					mikrotik.Send("=layer7-protocol=" + item.id + "_" + i);
					mikrotik.Send("=protocol=tcp");
					mikrotik.Send("=src-address=" + SRCAddress);
					mikrotik.Send("=comment=register", true);

					mikrotik.Read();
				}
			}
		}
	}
	catch (Exception)
	{
		ret = false;
	}
 
	return ret;
}


В примере я использовал блокировку по домену, но это не совсем верно. Для блокировки по URL можно использовать следующие регулярное выражение для layer7-protocol:

^.*(/summary).*(chelaxe.ru).*$

Причем выражение должно быть в нижнем регистре при использовании версий RouterOS из 5 ветки, в следствии допущенной ошибки MikroTik.

Исходники доступны здесь.

При создании руководствовался:
Памятка оператора связи
OpenSSL 1.0.1с + libGOST.so + КриптоПРО + ключ из ruToken
Как мы получали доступ к базе реестра запрещенных ресурсов
Роскомнадзор объявил о введении в работу реестра сайтов с «пиратскими» фильмами
RegExr intuitive tool for learning, writing, and testing Regular Expressions
Александр Ф. Михайлов @chelaxe
карма
13,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (22)

  • +11
    Ну теперь осталось дописать чтоб блокированные запросы перенаправлялись на поднятый до штатов VPN и тогда будет совсем зашибись
    • –3
      Статью не читай @ сразу отвечай
    • 0
      Можно реализовать с помощью mangle пометив пакеты подходящие по правилу layer7, а далее в nat перенаправляем куда надо.
  • +3
    Люди зря вы статью минусуете. Понятно что самый поездатый реестр никто не любит, но изложенный пример можно ведь просто применять в офисе для фильтрации вирусных ресурсов, чтобы уменьшить вероятность заражения машин. Adblock не панацея, а прописывать в каждом браузере черный список не всегда возможно.
    • 0
      В Adblock нет геморроя с выгрузкой фильтров. Никаких тебе ключей и цифровых подписей.
      Скажите, пожалуйста, а почему этот реестр может быть полезен для офиса для фильтрации вирусных ресурсов? Если я правильно понимаю — этот реестр для операторов связи (то есть для провайдера, к которому этот офис и подключён).
      • 0
        Я к тому что никто не мешает применять описанную методику, с некоторыми доработками, без использования реестра. Можно же составить свой собственный черный список. Мыслите шире!

        Adblock я тоже применяю, но кроме него у меня давно ведется свой собственный черный список в Opera, таким образом я отсеиваю максимальное количество рекламы. Если я вижу явно рекламный блок, который пролез через все фильтры, то я смотрю с какого ресурса он взят и если ресурс исключительно рекламный, то добавляю его в черный список Opera.

        Теперь представьте — выбрасываем из методики статьи реестр к чертовой бабушке и используем свой собственный накопленный черный список. Как результат у всего оффиса организации очищенный интернет.
  • +2
    Thread.Sleep(2500)
    

    рукалицо.жпег
    msdn.microsoft.com/ru-ru/library/fb4aw7b8.aspx
    • 0
      за WaitForExit() спасибо. Данная часть еще обдумывается — хочу обрабатывать вывод из консоли и уже на этом делать логику. Правда интереснее вот это OpenSSL.NET, но с ним не все гладко.
  • 0
    Тут более актуальный список УЦ e-trust.gosuslugi.ru/CA
  • 0
    Читая статью, ожидал увидеть, как этот закрытый реестр скачивается, и разворачивается для всеобщего рассмотрения на публичный ресурс. Вместо этого автор решал задачу «как технически лучше взять под козырек». Лучше бы по DNS блокировали с выдачей пользователям побуждающего к размышлениям баннера, ей-богу.
  • 0
    На сколько я понимаю, частично данный пост основан на информации из написанного мной поста, опубликованного чуть меньше года назад? Взять, например, заглавную иллюстрацию в которой я пошутил на тему того, что Роскомнадзор периодически выдает совершенно непонятную капчу:

    image

    Или конфиг для openssl.

    Разумеется, я только за то, чтобы он оказался кому-либо полезным, но прошу указать в тексте статьи ссылку на источник.
  • 0
    Поправил код согласно нововведениям.
    1. Изменился адрес реестра;
    2. Изменилась Памятка оператора связи;
    3. Форма для подачи запроса теперь здесь;
    4. Изменился адрес сервиса;
    5. Изменился адрес WSDL схемы;
    6. Изменился формат дампа реестра. Теперь поля ip, domain, url могут отсутствовать или их может быть несколько.

    Ну и реестр сайтов с «пиратскими» фильмами объединен с реестром запрещенных сайтов.
  • 0
    парни
    это все может пригодиться, тем у кого есть лицензия оператора связи, но он не предоставляет доступ в Интернет. Но пять же обязан исполнять приказ и получать реестр…
  • 0
    Огромная благодарность за данную статью.
    И, так как мне по воле случая потребовалось написать похожее решение на Java, выкладываю ссылку.

    Задача, правда, немного отличалась: было необходимо лишь организовать загрузку и сохранение XML.
    Вместо работы с getLastDumpDate реализован цикл, сохраняющий результаты в файлы с цифровым инкрементом в названии.
    Блокирования ресурсов не требовалось.
    Сорсы там же, настройки в ".properties".
    Вдруг кому-то пригодится.
  • 0
    А вы не пробовали подписывать запрос спомощью криптоПро?
    • 0
      Нет. Изначально искали open-source инструмент.
  • 0
    Попробовал. Есть ряд вопросов связанных с производительностью.

    У меня стоит Cloud Core, 36 ядер и 16Гб памяти. При установке правил дико тормозит железка.

    Пробовал как в filter так и в mangle. Результат не радует… Нет идей как оптимизировать данное решение?
    • 0
      со временем пришлось перейти на web-proxy того же mikrotik… l7 слишком требователен к производительности железа.
  • 0
    И еще одно предложение:

    mikrotik.Send("/ip/firewall/filter/add");

    mikrotik.Send("=place-before=0");
  • 0
    В итоге реализовал следующим образом:

    1. Добавляю не доменные имена, а ip адреса в Address List
    2. Можно либо блокировать в Filter либо маркировать выставив DST Address List.

    При таком варианте нагрузка 0%.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.