Имя пользователя:
Пароль:
 

Название темы: [решено] Подсчет маски
Показать сообщение отдельно

Старожил


Сообщения: 415
Благодарности: 257

Профиль | Отправить PM | Цитировать


Цитата Magenta:
мне нужна именно маска в формате IP/x.x.x.x »
Допустим, у вас есть IP 85.17.28.149. Вы с помощью вашей утилиты выясняете, что у него диапазон адресов - от 85.17.28.0 до 85.17.30.255.
85.17.28.0 - это начальный адрес диапазона, он у вас идет вот сюда: 85.17.28.0/XXX.XXX.XXX.XXX
Далее, запускаете приведенный ниже скрипт вот таким кодом (или прямо из PHP, если вы говорите, что можете выполнять из него консольные утилиты или батники)
Код: Выделить весь код
For /F %%A In ('netmask.cmd 85.17.28.0 85.17.30.255') Do Echo %%A
На выходе получаете маску 255.255.252.0, которая и завершает запись в нужном вам формате: 85.17.28.0/255.255.252.0

Собственно, сам скрипт получения маски подсети из диапазона адресов.
Код: Выделить весь код
@Echo Off
:: Subnet mask from IP range
:: Inquisitor, 2012
:: Distributed under GNU GPL v2 license
:: http://www.gnu.org/licenses/gpl-2.0.html
SetLocal EnableDelayedExpansion
Set NetworkHostBoundary=false
Set NetMask=

:: Если вызывается не из консоли, а из другого батника,
:: вызывать нужно из цикла for для корректной работы
:: Пример:
rem For /F %%A In ('netmask.cmd 192.168.1.0 192.168.8.255') Do Echo %%A

:: Проверка на запуск с аргументами
:: Если без аргументов - пример использования и выход
If "%*"=="" (Echo USAGE: %~nx0 192.168.1.0 192.168.3.255&GoTo :EOF)

:: Разбор входящих аргументов, cравнение начального и конечного
:: адресов по октетам
For /F "tokens=1-8 delims=. " %%A In ("%*") Do (
	Call :Mask %%A %%E
	Call :Mask %%B %%F
	Call :Mask %%C %%G
	Call :Mask %%D %%H
)
:: Вывод в stdout результата и выход, раскомментировать нужное
:: Вывод _БЕЗ_ перевода строки
rem<Nul Set /P Echo=!NetMask!
:: Вывод _С_ переводом строки
Echo !NetMask!
GoTo :EOF


:DEC2BIN
:: Функция перевода числа из десятеричной системы в двоичную
:: Принимает один аргумент, результат возвращается в %Result%
Set Result=
Set Data=%~1
:d2b_loop
:: Проверяем, есть ли остаток от деления
Set /A x1=Data/2
Set /A x2=x1*2
If "%x2%"=="%Data%" (Set Mod=0) Else (Set Mod=1)
:: Устанавливаем в качестве входных данных результат деления
Set Data=%x1%
:: Пишем результат поразрядно, в обратном порядке
Set Result=%Mod%%Result%
:: Следующая итерация или выход после окончания
If Not "%x1%"=="0" GoTo d2b_loop
:: Перед выходом - дополнение ведущими нулями до двух в восьмой
:: Требуется для корректного сравнения двух чисел без сдвига
Call :LeadingZero %Result%
GoTo :EOF

:BIN2DEC
:: Функция перевода числа из двоичной системы в десятеричную
:: Принимает один аргумент, результат возвращается в %Result%
Set Result=
:: Значение -1 для начала значения счетчика с нуля
Set i=-1
Set Data=%1
:b2d_loop
:: Получаем текущий разряд числа
Set /A i+=1
Set x1=%Data:~-1%
:: Используем бинарный сдвиг для получения степени двойки
Set /A x2="x1 * (1 << i)"
:: Добавляем к результату
Set /A Result+=%x2%
:: Следующая итерация или выход после окончания
If Not "%Data:~,-1%"=="" (Set Data=%Data:~,-1%&GoTo b2d_loop)
GoTo :EOF

:LeadingZero
:: Дополнение ведушими нулями до двух в восьмой (один байт)
:: Принимает один аргумент, результат возвращается в %Result%
Set Result=
Set Data=%~1
For /L %%A In (1,1,8) Do (
	If Not "!Data!"=="" (
		Set Result=!Data:~-1!!Result!
		Set Data=!Data:~,-1!
	) Else (
		Set Result=0!Result!
	)
) 
GoTo :EOF

:FastCompare
:: Быстрое сравнение, если найдены различия - вызывается функция
:: более детального сравнения для поиска самого различия
:: Принимает два аргумента, результат возвращается в %Result%
If Not !NetworkHostBoundary!==true (
	If "%1"=="%2" (
		Set Result=11111111
		GoTo :EOF
	) Else (
		Call :Compare %1 %2
	)
) Else (
	Set Result=00000000
)
GoTo :EOF

:Compare
:: Сравнение двух однобайтных чисел поразрядно, локализация начала различий
:: и забивание всего после первого различия нулями
:: Принимает два аргумента, результат возвращается в %Result%
:: Ведущие нули у обоих чисел обязательны
Set x1=%1&Set x2=%2
Set Result=
For /L %%A In (1,1,8) Do (
:: Получение ведущего разряда от каждого из чисел
	Set n1=!x1:~,1!
	Set n2=!x2:~,1!
:: Сравнение двух чисел и инвертирование бита
	Set /A Data="1 ^ (n1 ^ n2)"
:: Установка флага начала различия
	If !Data!==0 Set NetworkHostBoundary=true
:: Обнуление всех последующих после различия разрядов
	If !NetworkHostBoundary!==true Set Data=0
:: Поразрядная запись результата
	Set Result=!Result!!Data!
:: Устанавливаем остаток в качестве входных данных для следующей итерации
	Set x1=!x1:~1!
	Set x2=!x2:~1!
)
GoTo :EOF

:Mask
:: Генерация одного октета маски
:: Принимает два аргумента, результат дописывается к %NetMask%
Call :DEC2BIN %1&&Set From=!Result!
Call :DEC2BIN %2&&Set To=!Result!
Call :FastCompare !From! !To!
Call :BIN2DEC !Result!
If "!NetMask!"=="" (Set NetMask=!Result!) Else (Set NetMask=!NetMask!.!Result!)
GoTo :EOF
Отдельное спасибо Iska за вот это сообщение, без которого я вряд ли бы обратил внимание на такие замечательные возможности Set /A, как двоичные операторы.
Это сообщение посчитали полезным следующие участники:

Отправлено: 21:45, 28-07-2012 | #2

Название темы: [решено] Подсчет маски