Kohë më parë ne morëm statusin LIR dhe bllokun IPv6 /29. Ndaj lindi nevoja për të mbajtur një regjistër të nënrrjeteve të caktuar. Dhe pasi që sistemin tonë të faturimit e kemi shkruar në PHP, duhej të merreshim pak me këtë çështje dhe të kuptonim se ky nuk është gjuha më miqësore për punë me IPv6. Poshtë është zgjidhja jonë për problemet e shfaqura në punën me adresat dhe diapazoneve.

Pak teori
Diskleimer. Nëse jeni të njohur me atë që është IPv6 dhe për çfarë shërben, kjo pjesë mund të jetë e mërzitshme për ju. Apo ndoshta jo.
Njerëzit që e shohin për herë të parë një përshkrim IPv6, mund të jetë disi të frikësuar. Pas elegancës, 64.233.177.101 ne papritmas përballemi me 2607:f8b0:4002:c08::8b dhe mund të ngatërrohemi. Të dyja janë thjesht një përfaqësim që kuptohet nga njeriu për 32 dhe 128 bita përkatësisht. Çdo paketë IP përmban një titull me një qëllim të standardizuar për çdo bit. Pa u thelluar më tej në strukturën e titujve, kemi nevojë të nxjerrim një gjë nga kjo: për operacionet me adresat IP dhe diapazonet, është më e lehtë të përdorim matematikën binare dhe operatorët bit për bit. Të ruajmë në databazë ë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ë duhet të trajtohet është maskat e rrjetit dhe notacioni CIDR. CIDR është akronimi për Classless Inter-Domain Routing (). Kjo koncept erdhi në vend të klasës në lidhje me përcaktimin e 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ë, bitet e para n që korrespondon me prefiksin do të kenë vlera 1, të tjerat do të jenë 0.
Në formë të kuptueshme, kjo shkruhet si ip.add.re.ss/cidr. Për shembull, 64.233.177.0/24 të cilat tregojnë se bitet e pare 24 i përkasin prefiksit. Bitët e fundit 8, që janë numri i fundit në shëmbëlltyrën e kuptueshme, i përkasin adresës brenda nënrrjetit. Edhe disa ushtrime tjetër. 64.233.177.101/32 dhe 2607:f8b0:4002:c08::8b/128 - një adresë të caktuar. 2607:f8b0:4002:c08::/64 - bitët e pare 64 (grupet e para 4) janë prefiks, 64 bitët e mbetur janë pjesa lokale. Për by the way, nëse dikush shqetësohet për "::" në shëmbëlltyrë, dy pika zëvendësojnë numrin e arbitrave të seksioneve që përmbajnë 0. Ajo mund të paraqitet në përshkrim vetëm një herë. Në fjalë të tjera, 2607:f8b0:4002:c08::8b = 2607:f8b0:4002:c08:0:0:0:8b.
Çfarë duhet të nxjerrim nga të gjithë këto? Së pari, adresa e parë dhe e fundit e nënrrjetit mund të merret përmes AND dhe OR binare, duke ditur maskën në formë binare. Së dyti, nënrrjeti tjetër i madhësisë (dmth. me CIDR) n mund të llogaritet duke shtuar 1 në n-tën pozite në përfaqësimin binar. Nga binar kuptoj rezultatin e përdorimit të funksioneve pack() dhe inet_pton() dhe përdorimin e mëtejmë të base_convert() Pa klasa, parashikonte ndarjen e klasës së adresës. Në ato vite të largët, askush nuk kishte supozuar se do të kishte kaq shumë nënrrjete, ndaheshin në të djathtë dhe të majtë me blloqe të mëdhenj: klasa A - prefiksi ishin 8 bitët e parë (dmth. numri i parë), me bitin udhëheqës 0; klasa B - 16 të parat (numrat e parë dy), bitët udhëheqës 10; klasa C - bitët e parë 24, bitët udhëheqës 110. Këto bitët udhëheqës përcaktonin diapazonet, në të cilat adresa e caktuar të klasës jepeshin:.
HistorikuSë parashikuar, adresa pa klasa i parapriu segregimit të adresave. Në ato vite të largëta, askush nuk e mendonte që do të kishte kaq shumë nënshtresa, duke i shpërndarë ato në mënyrë të madhe: klasa A — prefiksi ishin 8 bitët e parë (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ë, bitët udhëheqës 110. Këta bitë udhëheqës përcaktonin intervalet në të cilat adresa e klasës përkatëse do të jepeshin: 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. Me rritjen e internetit nëpër botë, rregullatorët kuptuan se kishin gabuar, dhe në fillim të viteve '90 zhvilluan konceptin pa klasë, duke lejuar që të mos lihet pas bitëve udhëheqës. Një pak më shumë detaje mund të nxirren, le të themi, në .
Të kalojmë në praktikë
Në praktikë do të realizojmë tre detyrat më të mundshme, ashtu siç m'u dukën:
- merrni adresën e parë dhe të fundit të diapazoneve;
- merrni diapazonin tjetër të caktuar (CIDR);
- kontrolloni për përkatësinë e adresës në diapazone.
Zbatimi do të jetë për IPv6, por logjika mund të adaptohet lehtësisht nëse është e nevojshme. Disa ide kam marrë, , por e realizova pak ndryshe. Po ashtu, në shembuj nuk ka kontroll për gabimet e hyrjes. Pra, fillojmë.
Siç e kam përmendur, adresa e parë dhe e fundit e diapazonit mund të përcaktohen përmes operatorëve bit për bit, duke ditur fillimin e diapazonit dhe maskën binarë të nënrrjetit. Pra, gjëja e parë që na duhet është të kthejmë CIDR në maskën binare. Për këtë, do të mbledhim përfaqësimin 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 përfaqësimin hex ashtu siç bën inet_pton(). Me dallimin se me thirrje pack() të gjithë 0 duhet të jenë në vendin e tyre, dhe dy pika në përshkrim nuk duhet të jenë, ndryshe nga shëmbëlltyra kuptohet.
Hapi i ardhshëm është llogaritja e fillimit dhe fundi i gamës. Dhe këtu do të lindin nuanca. Operacionet bit per bit janë të kufizuara nga kapaciteti i procesorit. Prandaj, në CubieTruck-in tim 32-bit, të cilin e përdor herë pas here për ndonjë testim, nuk do të mund 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ë cilat procesorë do të startojmë).
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ë për të kaluar IP dhe për të marrë rezultatin si në formë binarike, ashtu edhe në formë të lexueshme nga njeriu. Parametri $which këtu përcakton, nëse duam të marrim fillimin apo fundin e gamës (vlerat 'start' ose 'end' përkatësisht).
Detyra e ardhshme (po ashtu, më praktike për kompaninë tonë) është llogaritja e gamës së ardhshme. Për këtë detyrë, nuk më erdhi asgjë më mirë në mendje përveçse të shndërroj adresën në një varg binar dhe të shtoj 1 në pozitat e nevojshme, pas së cilës do ta rikthejmë gjithçka prapa. Që të mos shfaqen artefakte, vendosa që gjatë shndërrimit dhe rikthimit të ndaj adresën në byte.
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ë marrim prefiksin e gamës së ardhshme me madhësinë e specifikuar në $cidr.Me këtë funksion ne ndalojmë blloqet e adresave për klientët tanë.
Finalmente, kontrolli nëse adresa i përket gamës. Për shembull, ne kemi ndarë një bllok \/48 për shpërndarjen e blloqeve \/64 për klientët, dhe na nevojitet të sigurohemi se gjatë ndarjes nuk po dalim jashtë kufijve të bllokut të ndarë (në praktikë, ky do të ndodhë shumë rrallë, por gjithsesi ka një mundësi). Këtu gjithçka është e thjeshtë. Marrim fillimin dhe fundin e gamës në formë binarike dhe kontrollojmë nëse adresa ndodhet 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 ishte e dobishme. Cilat funksione të tjera që lidhen me adresat mund të jenë të dobishme në mendimin tuaj? Çdo shtesë, koment dhe rishikim të kodit janë të mirëseardhura në komentet.
Nëse ju tashmë jeni klienti ynë apo po mendoni të bëheni, për rastin e publikimit të këtij artikulli, ne ju ofrojmë një bllok \/64 krejtësisht falas për të gjitha shërbimet vps ose server dedikuar në qendrën e të dhënave Equinix Tier IV, Holandë, me kërkesë në departamentin e shitjeve, duke ofruar një lidhje me këtë artikull në tiketë. Oferta është në fuqi deri në mars 2020.
Pak reklamë 🙂
Faleminderit që qëndroni me ne. Ju pëlqejnë artikujt tanë? Dëshironi të shihni më shumë materiale interesante? Na mbështetni duke bërë një porosi ose duke na rekomanduar njohurive tuaj, , një analog unik i serverëve entry-level, i ndërtuar për ju: (disponohen variante me RAID1 dhe RAID10, deri në 24 bërthama dhe deri në 40GB DDR4).
Dell R730xd dyfish më i lirë në qendrën e të dhënave Equinix Tier IV në Amsterdam? Vetëm këtu në Holandë! Dell R420 — 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB — nga $99! Lexoni rreth
Burimi: habr.com
