Nedávno sme dostali stav LIR a /29 blokovanie IPv6. A potom vznikla potreba sledovať pridelené podsiete. A keďže naše účtovanie je napísané v PHP, museli sme sa do problematiky trochu ponoriť a uvedomiť si, že tento jazyk nie je práve najprívetivejší z hľadiska práce s IPv6. Pod rezom je naše riešenie problémov, ktoré vznikajú pri práci s adresami a rozsahmi. Možno nie najelegantnejší, ale robí svoju prácu.

Niektoré teórie
Vylúčenie zodpovednosti. Ak ste oboznámení s tým, čo je IPv6 a s čím prichádza, táto časť môže byť pre vás nudná. Možno nie.
Ľudia, ktorí vidia anotáciu IPv6 prvýkrát, to môže zdať dosť skľučujúce. Po elegantnom 64.233.177.101 zrazu čelíme 2607:f8b0:4002:c08::8b a môžeme byť zmätení. Obidve sú len ľudsky čitateľné reprezentácie 32 a 128 bitov. Každý IP paket obsahuje hlavičku s prísne štandardizovaným účelom pre každý bit. Bez toho, aby sme zachádzali hlbšie do štruktúry hlavičiek, jednu vec, ktorú si z toho musíme odniesť, je, že pre operácie s IP adresami a rozsahmi je vo všeobecnosti vhodné použiť binárnu matematiku a bitové operácie. Najvýhodnejšie je tiež uložiť ich do databázy ako BINÁRNE (4) pre IPv4 a BINÁRNE (16) pre IPv6.
Ďalším dôležitým aspektom, ktorého sa oplatí dotknúť, sú masky siete a zápis CIDR. CIDR je skratka pre beztriedne smerovanie medzi doménami (). Tento koncept nahradil koncept triedy pri určovaní, ktorá časť IP adresy je predponou siete a ktorá časť je adresou sieťového rozhrania v rámci tejto siete. V praxi sa prvých n bitov zodpovedajúcich prefixu nastaví na 1, zvyšok na 0.
V ľudsky zrozumiteľnej forme je to napísané vo forme ip.add.re.ss/cidr, Napríklad 64.233.177.0/24 označuje, že prvých 24 bitov sa vzťahuje na predponu. Posledných 8 bitov, známych aj ako posledné číslo v ľudsky čitateľnom zápise, odkazuje na adresu v rámci podsiete. Ešte pár cvikov. 64.233.177.101/32 и 2607:f8b0:4002:c08::8b/128 - jedna konkrétna adresa. 2607:f8b0:4002:c08::/64 - prvých 64 bitov (prvé 4 skupiny) je prefix, zvyšných 64 bitov je lokálna časť. Mimochodom, ak je niekto zmätený „::“ v zázname, dvojitá dvojbodka nahradí ľubovoľný počet sekcií obsahujúcich 0. V anotácii sa môže objaviť iba raz. Inými slovami, 2607:f8b0:4002:c08::8b = 2607:f8b0:4002:c08:0:0:0:8b.
Čo sa z toho všetkého musíme naučiť? Po prvé, prvú a poslednú adresu podsiete je možné získať pomocou binárnych operátorov AND a OR, ak poznáme masku v binárnej forme. Po druhé, veľkosť ďalšej podsiete (t. j. s CIDR) n možno vypočítať pripočítaním 1 k n-tá pozícia v binárnom zobrazení. Binárnym mám na mysli výsledok používania funkcií balenie() и inet_pton() a ďalšie použitie , binárne je reprezentácia binárneho systému, ktorú možno získať, povedzme, base_convert().
Historické informácieBeztriednemu oslovovaniu predchádzala triedna segregácia. V tých vzdialených rokoch si nikto nepredstavoval, že bude toľko podsietí, boli rozdelené vľavo a vpravo vo veľkých blokoch: trieda A - predpona bola prvých 8 bitov (t. j. prvé číslo), s počiatočným bitom 0; trieda B - prvých 16 (prvé dve čísla), prvé bity 10; trieda C - prvých 24 bitov, úvodné bity 110. Tieto úvodné bity špecifikovali rozsahy, v ktorých bola vydaná adresa konkrétnej triedy: 0.0.0.0 - 127.255.255.255 pre triedu A, 128.0.0.0 - 191.255.255.255 - trieda B, 192.0.0.0 - 223.255.255.255 - trieda C. Ako sa internet šíril po celej planéte, regulátori si uvedomili, že minuli cieľ, a na začiatku 90. rokov vyvinuli beztriedny koncept, ktorý umožnil neviazať sa k vedúcim bitom. Trochu viac podrobností nájdete napr. .
Prejdime k praxi
V praxi implementujeme tri najpravdepodobnejšie, ako sa mi zdalo, úlohy:
- získanie prvej a poslednej adresy rozsahu;
- získať ďalší daný rozsah veľkostí (CIDR);
- kontrola, či adresa patrí do rozsahu.
Implementácia bude pre IPv6, no v prípade potreby sa dá logika jednoducho prispôsobiť. Dostal som nejaké nápady , ale implementovali ho trochu inak. Príklady tiež nekontrolujú chyby vstupu. Tak, poďme.
Ako som už spomenul, prvú a poslednú adresu rozsahu je možné určiť pomocou bitových operácií, pričom poznáme začiatok rozsahu a binárnu masku podsiete. Preto prvá vec, ktorú musíme urobiť, je zmeniť CIDR na binárnu masku. Aby sme to dosiahli, zhromaždíme jeho hexadecimálne zobrazenie a zabalíme ho do binárneho.
function cidrToMask ($cidr) {
$mask = str_repeat('f', ceil($cidr / 4));
$mask .= dechex(4 * ($cidr % 4));
$mask = str_pad($mask, 32, '0');
return pack('H*', $mask);
}volanie pack('H*', $mask) zabalí hexadecimálnu reprezentáciu rovnakým spôsobom ako inet_pton(). Rozdiel je len v tom, že pri volaní balenie() všetky 0 musia byť na svojich miestach a v položke by nemali byť žiadne dvojbodky, na rozdiel od položky čitateľnej pre človeka.
Ďalším krokom je výpočet začiatku a konca rozsahu. A tu vznikajú nuansy. Bitové operácie sú obmedzené bitovou kapacitou procesora. V súlade s tým na mojom 32-bitovom CubieTrucku, ktorý niekedy používam na všetky druhy testovacieho rozmaznávania, nebude možné spracovať všetkých 128 bitov adresy v jednej operácii. Nič nám však nebráni rozdeliť si ho do skupín po 32 bitoch (pre každý prípad, ktovie, na akých procesoroch budeme bežať).
function getRangeBoundary ($ip, $cidr, $which, $ipIsBin = false, $returnBin = false) {
$mask = cidrToMask($cidr);
if (!$ipIsBin) {
$ip = inet_pton($ip);
}
$ipParts = str_split($ip, 4);
$maskParts = str_split($mask, 4);
$rangeParts = [];
for ($i = 0; $i < count($ipParts); $i++) {
if ($which == 'start') {
/* Побитовый & адреса и маски оставит только биты префикса. */
$rangeParts[$i] = $ipParts[$i] & $maskParts[$i];
} else {
/* Побитовый | с обратной маской (~) оставит биты префикса и установит все биты локальной части в 1. */
$rangeParts[$i] = $ipParts[$i] | ~$maskParts[$i];
}
}
$rangeBoundary = implode($rangeParts);
if ($returnBin) {
return $rangeBoundary;
} else {
return inet_ntop($rangeBoundary);
}
}Pre budúce použitie poskytneme možnosť prenášať IP a prijímať výsledok v binárnej aj pre človeka čitateľnej forme. Parameter $ ktorý tu určuje, či chceme získať začiatok alebo koniec rozsahu (hodnoty 'start' alebo 'koniec' v uvedenom poradí).
Ďalšou úlohou (a zároveň najpraktickejšou pre našu spoločnosť) je výpočet ďalšieho rozsahu. Pre túto úlohu ma nenapadlo nič lepšie, ako rozbaliť adresu do binárneho reťazca a pridať 1 na požadovanú pozíciu a potom všetko zbaliť späť. Aby sa nikde neobjavili artefakty, rozhodol som sa pri rozklade a zostavovaní rozdeliť adresu podľa bajtov.
function getNextBlock ($ipStart, $cidr, $ipIsBin = false, $returnBin = false) {
if (!$ipIsBin) {
$ipStart = inet_pton($ipStart);
}
$ipParts = str_split($ipStart, 1);
$ipBin = '';
foreach ($ipParts as $ipPart) {
$ipBin .= str_pad(base_convert(unpack('H*', $ipPart)[1], 16, 2), 8, '0', STR_PAD_LEFT);
}
/* Добавляем 1 в нужном разряде двоичного представления строки "влоб" :) */
$i = $cidr - 1;
while ($i >= 0) {
if ($ipBin[$i] == '0') {
$ipBin[$i] = '1';
break;
} else {
$ipBin[$i] = '0';
}
$i--;
}
$ipBinParts = str_split($ipBin, 8);
foreach ($ipBinParts as $key => $ipBinPart) {
$ipParts[$key] = pack('H*', str_pad(base_convert($ipBinPart, 2, 16), 2, '0', STR_PAD_LEFT));
}
$nextIp = implode($ipParts);
if ($returnBin) {
return $nextIp;
} else {
return inet_ntop($nextIp);
}
}Na výstupe dostaneme predponu ďalšieho rozsahu veľkostí špecifikovaného v $cidr. Pomocou tejto funkcie prideľujeme bloky adries našim klientom.
Nakoniec skontrolujte, či adresa patrí do rozsahu. Napríklad sme vyčlenili jeden blok /48 na distribúciu blokov klientom /64, a treba si dať pozor, aby sme pri prideľovaní neprekročili pridelený blok (v praxi sa to tak skoro nestane, ale stále je tu možnosť). Všetko je tu jednoduché. Dostaneme začiatok a koniec rozsahu v binárnom tvare a skontrolujeme, či je adresa v medziach.
function ipInRange ($ip, $rangeStart, $cidr) {
$start = getRangeBoundary($rangeStart, $cidr, 'start',false, true);
$end = getRangeBoundary($rangeStart, $cidr, 'end',false, true);
$ipBin = inet_pton($ip);
return ($ipBin >= $start && $ipBin <= $end);
}Dúfam, že to bolo užitočné. Aké ďalšie funkcie na prácu s adresami môžu byť podľa vás užitočné? Akékoľvek dodatky, komentáre a recenzie kódu sú srdečne vítané v komentároch.
Ak už ste našim klientom alebo len uvažujete o tom, že sa ním stanete, pri príležitosti uverejnenia tohto článku vám ponúkame získanie bločku /64 úplne zadarmo pre všetky služby vps alebo dedikovaný server v dátovom centre Equinix Tier IV v Holandsku na požiadanie obchodnému oddeleniu poskytnutím odkazu na tento článok v tikete. Ponuka platí do marca 2020.
Nejaké inzeráty 🙂
Ďakujeme, že ste zostali s nami. Páčia sa vám naše články? Chcete vidieť viac zaujímavého obsahu? Podporte nás zadaním objednávky alebo odporučením priateľom, , jedinečný analóg serverov základnej úrovne, ktorý sme pre vás vymysleli: (k dispozícii s RAID1 a RAID10, až 24 jadier a až 40 GB DDR4).
Dell R730xd 2 krát lacnejší v dátovom centre Equinix Tier IV v Amsterdame? Len tu v Holandsku! Dell R420 – 2x E5-2430 2.2 GHz 6C 128 GB DDR3 2 x 960 GB SSD 1 Gb/s 100 TB – od 99 USD! Čítať o
Zdroj: hab.com
