Почему это выражение bor и bnot не дает ожидаемого результата в Powershell?

почему этот бор не дает ожидаемого результата в powershell?

Чтобы найти последний адрес в подсети ipv6, нужно выполнить операцию «двоичное или» и «двоичное не».

Статья, которую я читаю (https://www.codeproject.com/Articles/660429/Subnetting-with-IPv6-Part-1-2) описывает это так:

(2001:db8:1234::) | ~(ffff:ffff:ffff::) = 2001:db8:1234:ffff:ffff:ffff:ffff:ffff

Где | является "бинарным или" и
~ является "бинарным не"


Однако в powershell я пытаюсь сделать это так:

$mask = 0xffffffff
$someOctet = 0x0000
"{0:x4}" -f ($someOctet -bor -bnot ($mask) )

и я получаю 0000 вместо ffff

Почему это?


person leeand00    schedule 26.04.2018    source источник
comment
Почему вы ожидаете ffff? -bnot 0xffffffff это 0, почему 0x0000 -bor 0 должно быть не 0? Кстати, ffff:ffff:ffff:: — это краткая форма ffff:ffff:ffff:0000:0000:0000:0000:0000.   -  person user4003407    schedule 26.04.2018
comment
Из-за учебника... возможно, это плохой учебник.   -  person leeand00    schedule 26.04.2018
comment
Я пытаюсь сделать октет за раз.   -  person leeand00    schedule 26.04.2018


Ответы (1)


Учебное пособие выполняет -not всей маски подсети, поэтому ff00 инвертируется в 00ff и аналогично для более длинных F и 0; вы этого не делаете, поэтому вы не получите тех же результатов.

Полностью расширенный расчет, который вы показываете, делает это:

1. (2001:0db8:1234:0000:0000:0000:0000:0000) | ~(ffff:ffff:ffff:0000:0000:0000:0000:0000) 

2. (2001:0db8:1234:0000:0000:0000:0000:0000) |  (0000:0000:0000:ffff:ffff:ffff:ffff:ffff) 

3. = 2001:db8:1234:ffff:ffff:ffff:ffff:ffff

Обратите внимание, как в шагах с 1 по 2 not инвертирует шаблон F и 0, переключает маску подсети и переключает ее между битом, где заканчивается префикс, и бит, где начинается основная часть.

Затем на шаге 3 or берутся только установленные биты слева, чтобы эти числа оставались одинаковыми (ни нулевые, ни ffff'd), и все установленные биты справа (чтобы сбросить их, максимизируя их на максимальный IP-адрес в пределах этого префикса).

Другими словами, нет смысла делать это «по октету за раз». Это полный IP-адрес (или весь префикс) + вся операция по маске подсети.

Где в учебнике сказано:

& (И), | (ИЛИ), ~ (НЕ или битовый ИНВЕРТОР): Мы будем использовать эти три побитовых оператора в наших вычислениях. Я думаю, что все знакомы — по крайней мере, из университетских курсов цифровой логики — и знают, как они работают. Я не буду объяснять подробности здесь снова. Вы можете выполнить поиск «битовых операторов» для получения дополнительной информации.

Если вы не очень хорошо знакомы с тем, что они делают, стоит изучить это подробнее, прежде чем пытаться применять их к IP-подсетям. Потому что вы в основном спрашиваете, почему 0 or (not 1) это 0, и ответ таков, потому что так работает логическая логика «или» и «не».


Изменить для вашего комментария

[math]::pow(2,128) намного больше, чем [decimal]::maxvalue, поэтому я не думаю, что Decimal подойдет.

Я не знаю, какой рекомендуемый способ сделать это, но я полагаю, что если вы действительно хотите сделать все это в PowerShell с помощью -not, вам придется обрабатывать это с помощью [bigint] (например, [bigint]::Parse('20010db8123400000000000000000000', 'hex')).

Но, скорее всего, вы бы сделали что-то более многословное, например:

# parse the address and mask into IP address objects
# which saves you having to expand the short version to 
$ip = [ipaddress]::Parse('fe80::1')
$mask = [ipaddress]::Parse('ffff::')


# Convert them into byte arrays, then convert those into BitArrays
$ipBits = [System.Collections.BitArray]::new($ip.GetAddressBytes())
$maskBits = [System.Collections.BitArray]::new($mask.GetAddressBytes())


# ip OR (NOT mask) calculation using BitArray's own methods
$result = $ipBits.Or($maskBits.Not())


# long-winded way to get the resulting BitArray back to an IP
# via a byte array

$byteTemp = [byte[]]::new(16)
$result.CopyTo($byteTemp, 0)
$maxIP = [ipaddress]::new($byteTemp)

$maxIP.IPAddressToString

# fe80:ffff:ffff:ffff:ffff:ffff:ffff:ffff
person TessellatingHeckler    schedule 26.04.2018
comment
Итак, если в адресе ipv6 128 бит... вам придется хранить и это, и маску подсети в PowerShell как [decimal], поскольку тип данных [decimal] — 128-битный... это большая переменная! Если сохранить адрес следующим образом: [decimal]$ipv6addr=0x20010db812340, я останусь со всеми нулями после этого справа? Потому что, если я наберу [decimal]$ipv6addr=0x20010db8123400000000000000000000, все, что я сделаю, это будет кричать на pwsh с ParentContainsErrorRecordException - person leeand00; 27.04.2018
comment
Я отредактировал свой ответ, чтобы ответить, потому что есть что сказать больше, чем я могу добавить в комментарий. (Теперь я понимаю, почему вы пытались сделать это по октету за раз? ха-ха). - person TessellatingHeckler; 27.04.2018
comment
хе-хе... подождите, а почему это было? Почему я пытался сделать это по одному октету за раз? Я имею в виду, что я узнал о побитовых операторах в школе ... Буквально на днях я использовал битовые флаги в Powershell для отображения диалогового окна COM с моим выбором OK / OK и Отмена, а также Нет значка / Значок предупреждения / Значок остановки / Значок информации но это не совсем то же самое, что это... Я уверен, что битов было не так много; По-моему, их было всего 32. - person leeand00; 27.04.2018
comment
Я предполагал, что вы разделили его, потому что вы не можете поместить IPv6-адрес или маску в [int] (то есть [System.int32]), о чем я вообще не думал, пока вы не упомянули об этом. (IPv4 подходит для беззнакового [uint32], но для IPv6 нет ничего подобного) - person TessellatingHeckler; 27.04.2018
comment
Обратите внимание, что поиск максимального IP-адреса в подсети ipv6 напрямую зависит от того, сколько f's (15) вы указываете в строке 4 в приведенном выше примере. - person leeand00; 27.04.2018
comment
$ip = [ipaddress]::Parse('2001:0db8:1234::') # Определение максимального IP-адреса напрямую зависит от того, сколько f вы указали (маска): # # Например, если ваш префикс '2001: 0db8:1234::' # Тогда ваша маска должна быть 'ffff:ffff:ffff::' # $mask = [ipaddress]::Parse('ffff:ffff:ffff:f::') - person leeand00; 27.04.2018
comment
В маске должно быть установлено столько битов, сколько длина префикса в битах. В IPv4 это может означать, что маска ff.ff.ff.00 для /24, или ff.ff.80.00 для /23, или другие цифры, это не всегда f. Я не понял, как это проявляется в IPv6, возможно, они устроены так, что они всегда заканчиваются на четких границах, или это могут быть не все f все время. - person TessellatingHeckler; 27.04.2018