Së fundmi, ne fituam statusin LIR dhe një bllok IPv6 me /29. Menjëherë pas kësaj, u shfaq nevoja për të mbajtur regjistrin e nënrrjeteve të caktuara. Duke qenë se fakturimi ynë është shkruar në PHP, duhej të merresha pak me këtë çështje dhe të kuptoja se ky gjuhë nuk është më e lehta për të punuar me IPv6. Poshtë - zgjidhjet tona për detyrat që u panë lidhur me adresat dhe intervalet. Ndoshta jo më elegante, por ato realizojnë detyrat e vendosura.

Pak teori
Diskleimer. Nëse jeni të njohur me atë se çfarë është IPv6 dhe si funksionon, kjo pjesë mund të jetë e mërzitshme për ju. Ndoshta jo.
Një njerëz që e shohin për herë të parë dokumentin e IPv6, mund të jetë goxha i frikshëm. Pas elegancës 64.233.177.101 ne papritmas përballemi me 2607:f8b0:4002:c08::8b dhe mund të jemi të paqartë. Të dyja janë vetëm një përfaqësim njerëzor i 32 dhe 128 bitëve përkatësisht. Çdo paketë IP përmban një kokë me një destinim të rreptë të standardizuar për çdo bit. Pa shkuar thellë në strukturën e koka, duhet të nxjerrim një përfundim: për operacionet me adresat IP dhe intervalet, është më e përshtatshme të përdorim matematikën binare dhe operacione bit për bit. Të ruash ato në bazën e të dhënave është gjithashtu më e lehtë si BINARY(4) për IPv4 dhe BINARY(16) për IPv6.
Një aspekt tjetër i rëndësishëm që do të ishte mirë të përmendet, janë maskat e rrjetit dhe notacioni CIDR. CIDR është një akronim për Classless Inter-Domain Routing (). Kjo koncept i erdhi në zëvendësimin e klasës në çështjen e përcaktimit se cila pjesë e adresës IP është prefiksi i rrjetit dhe cila është adresa e ndërfaqes së rrjetit brenda këtij rrjeti. Në praktikë, bitët e parë n që korrespondon me prefiksin do të kenë vlerat 1, ndërsa bitët e tjerë do të jenë 0.
Në mënyrë të kuptueshme, kjo shprehet si ip.add.re.ss/cidr. Për shembull, 64.233.177.0/24 tregon se 24 bitët e parë lidhën me prefiksin. Bitët e fundit 8, që janë numri i fundit në shprehjen njerëzore, i përkasin adresës brenda nënrrjetit. Edhe disa ushtrime. 64.233.177.101/32 dhe 2607:f8b0:4002:c08::8b/128 është një adresë e caktuar. 2607:f8b0:4002:c08::/64 janë 64 bitët e parë (grupet e para 4) - prefiksi, ndërsa 64 bitët e tjerë - pjesa lokale. Për më tepër, nëse dikush shqetësohet për "::" në shprehje, dyshja e dyfishta zëvendëson një numër të rastësishëm sekcionesh që përmbajnë 0. Ajo mund të shfaqet në dokument vetëm 1 herë. Në terma të tjerë, 2607:f8b0:4002:c08::8b = 2607:f8b0:4002:c08:0:0:0:8b.
Çfarë duhet të nxjerrim nga gjithçka kjo? Së pari, adresa e parë dhe e fundit e nënpodit mund të merret me anë të AND dhe OR binar, duke ditur maskën në formën binar. Së dyti, nënpodhe të ardhshme të madhësisë (dmth. me CIDR) n mund të llogariten duke i shtuar 1 pozitat n-të në reprezentimin binar. Me pamjen binare nënkuptoj rezultatin e përdorimit të funksioneve pack() dhe inet_pton() dhe përdorimin e mëtejshëm të , nën binar kuptoj reprezentimin në sistemin binar, që mund të merret, të themi, përmes base_convert().
Kronologjia historikePara adresimit të pa klasave kishte një segregacion klasor. Në ato vite të largëta, askush nuk mendonte se do të kishte kaq shumë nënpodhe, i jepnin ato për të djathtën dhe të majtën me blloqe të mëdha: klasa A — prefiksi ishin 8 bit të parët (dmth. numri i parë), me bitin udhëheqës 0; klasa B — 16 të parët (dy numrat e parë), bitët udhëheqës 10; klasa C — 24 bit të parët, bitët udhëheqës 110. Këta bitë udhëheqës përcaktonin intervalet, në të cilat jepeshin adresat e klasës së caktuar: 0.0.0.0 — 127.255.255.255 për klasën A, 128.0.0.0 — 191.255.255.255 — klasa B, 192.0.0.0 — 223.255.255.255 — klasa C. Ndërsa interneti përhapej në planet, rregullatorët kuptuan se kishin bërë një gabim, dhe në fillim të viteve '90 zhvilluan konceptin pa klasa, që lejonte të mos ishte e varur nga bitët udhëheqës. Disa detaje të mëtejshme mund të marrësh, të themi, në .
Të kalojmë në praktikë
Në praktikë do të realizojmë tri detyra më të mundshme, siç më duket,
- marrja e adresës së parë dhe të fundit të intervalit;
- marrja e intervalit të ardhshëm me madhësinë e caktuar (CIDR);
- kontrolli mbi përkatësinë e adresës në interval.
Implementimi do të jetë për IPv6, por nëse është e nevojshme, logjika mund të adaptohet lehtësisht. Disa ide kam marrë , por kam realizuar pak ndryshe. Gjithashtu, në shembuj nuk ka kontroll mbi gabimet e hyrjes. Pra, le të fillojmë.
Siç e përmenda më parë, adresa e parë dhe e fundit e intervalit mund të përcaktohen me anë të operacioneve bit për bit, duke ditur fillimin e intervalit dhe maskën binar të nënpodit. Pra, së pari duhet ta kthejmë CIDR në maskë binar. Për këtë do të mbledhim reprezentimin e saj hex dhe do ta paketojmë në binar.
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);
}Thirrja pack(‘H*’, $mask) paketon reprezentimin hex ashtu siç bën inet_pton(). Me ndryshimin e vetëm që ndodh pack() të gjithë 0 duhet të jenë në vendet e tyre, ndërsa dy pika në shënim nuk duhet të jenë, ndryshe nga shënimi i kuptueshëm për njerëzit.
Hapi tjetër është llogaritja e fillimit dhe përfundimit të intervalit. Dhe këtu do të ketë nuanca. Operacionet bit për bit janë të kufizuara nga bitët e procesorit. Prandaj, në CubieTruck-in tim 32-bitësh, të cilin herë pas here e përdor për eksperimente të ndryshme, nuk do të jetë e mundur të procesoj të gjitha 128 bit adresën në një operacion. Megjithatë, asgjë nuk na pengon ta ndajmë atë në grupe prej 32 bitësh (për çdo rast, kush e di se në cilët procesorë do të drejtohemi).
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);
}
}Për përdorim të ardhshëm, do të parashikojmë mundësinë e kalimit të IP-së dhe marrjen e rezultatit në format binar dhe në formë të lexueshme për njeriun. Parametri $which këtu përcakton, nëse duam të marrim fillimin apo përfundimin e intervalit (vlerat 'start' ose 'end' përkatësisht).
Detyra tjetër (e cila gjithashtu është më praktike për kompaninë tonë) është llogaritja e intervalit të ardhshëm. Për këtë detyrë, asgjë më e mirë nuk më ka ardhur në mend mendimin përveçse të shndërroj adresën në një varg binar dhe të shtoj 1 në pozicionin e duhur, pas së cilës ta kthej përsëri. Që të mos ketë artefakte, vendosa që gjatë shpërndarjes dhe rikthimit ta ndaj adresën sipas byte-ve.
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);
}
}Në daljen do të kemi prefiksin e intervalit të ardhshëm me përmasat e caktuara në $cidr. Me këtë funksion ne ndanë blloqet e adresave klientëve tanë.
Së fundmi, kontrollimi nëse adresa i përket intervalit. Për shembull, ne kemi ndarë një bllok /48 për shpërndarjen e blloqeve /64 klientëve tanë dhe duhet të sigurohemi se gjatë caktimit nuk dalim jashtë kufijve të bllokut të ndarë (në praktikë kjo ndodh rrallë, por mundësia ekziston). Këtu është shumë e thjeshtë. Marrim fillimin dhe përfundimin e intervalit në formë binar dhe kontrollojmë nëse adresa është brenda kufijve.
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);
}Shpresoj se ka qenë e dobishme. Cilat funksione të tjera lidhur me adresat mendoj se mund të jenë të dobishme? Çdo shtesë, koment dhe rishikim kodi janë mirëpritur ngrohtësisht në komentet.
Nëse jeni tashmë klienti ynë ose thjesht po mendoni të bëheni, për rastin e publikimit të këtij artikulli, ju ofrojmë një bllok /64 krejtësisht falas për të gjitha shërbimet vps ose serverin e dedikuar në qendrën e të dhënave Equinix Tier IV, Holandë, me kërkesë në departamentin e shitjeve, duke ofruar lidhjen me këtë artikull në tiketë. Oferta është e vlefshme deri në mars 2020.
Pak reklamë 🙂
Faleminderit që po qëndroni me ne. Ju pëlqen artikujt tanë? Doni të shihni më shumë materiale interesante? Na mbështesni duke bërë një porosi ose duke rekomanduar tek miqtë tuaj, , një analog unik i serverëve entry-level që e kemi shpikur për Ju: (opcionet me RAID1 dhe RAID10, deri në 24 bërthama dhe deri në 40GB DDR4 janë të disponueshme).
Dell R730xd dyfish më i lirë në qendër të të dhënave Equinix Tier IV në Amsterdam? Vetëm te ne në Holandë! Dell R420 — 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB — nga $99! Lexoni rreth
Burimi: habr.com
