Darbs ar IPv6 PHP

Nesen mēs ieguvām LIR statusu un \/29 IPv6 bloku. Un drÄ«z radās nepiecieÅ”amÄ«ba uzskaitÄ«t pieŔķirtās apakÅ”tÄ«klus. Un tā kā mÅ«su rēķināŔanas sistēma ir uzrakstÄ«ta PHP, nācās nedaudz iepazÄ«ties ar Å”o jautājumu un saprast, ka Ŕī valoda nav visdraudzÄ«gākā IPv6 apstrādei. Zemāk – mÅ«su risinājums radÄ«tajām problēmām ar adresēm un diapazoniem. VarbÅ«t ne visai elegants, bet uzdevumi tiek izpildÄ«ti.

Darbs ar IPv6 PHP

Nedaudz teorijas

Atruna. Ja esat pazÄ«stams ar to, kas ir IPv6 un kā tas darbojas, Ŕī daļa var jums likties garlaicÄ«ga. VarbÅ«t arÄ« nē.

Cilvēkus, kuri pirmo reizi redz IPv6 anotāciju, tā var pat nobiedēt. Pēc elegantiem 64.233.177.101 mēs pēkŔņi saskaramies ar 2607:f8b0:4002:c08::8b un varam apjukt. Abas ir cilvēkiem saprotamas 32 un 128 bitu attēlojumos attiecÄ«gi. Ikviens IP datu pakets satur galveni ar stingri standartizētu katra bita mērÄ·i. NeiegrimuÅ”i vēl dziļāk galvenes struktÅ«rā, no Å”ejienes mums jāsecina: IP adresu un diapazonu operācijām galvenokārt ir ērti izmantot bināro matemātiku un bitu operācijas. Visērtāk ir saglabāt tos datubāzē kā BINARY(4) IPv4 un BINARY(16) IPv6.

Vēl viens svarÄ«gs aspekts, ko vērts pieminēt, ir tÄ«kla maskas un CIDR notācija. CIDR ir akronÄ«ms no Classless Inter-Domain Routing (bezŔķirņu adresēŔana). Å Ä« koncepcija aizstāja klasisko pieeju attiecÄ«bā uz to, kāda daļa IP adreses ir tÄ«kla prefikss, un kāda daļa ir adreses tÄ«kla saskarnē. Praksē pirmajiem n bitiem, kas atbilst prefiksam, bÅ«s vērtÄ«bas 1, bet pārējiem – 0.

Cilvēkiem saprotamā veidā to raksta kā ip.add.re.ss\/cidr. Piemēram, 64.233.177.0/24 norāda, ka pirmie 24 bitu pieder prefiksam. Pēdējie 8 biti, kas ir pēdējais skaitlis cilvēkam saprotamā ierakstā, attiecas uz adresi apakÅ”tÄ«klā. Vēl pāris vingrinājumu. 64.233.177.101/32 un 2607:f8b0:4002:c08::8b\/128 — viens konkrēts adrese. 2607:f8b0:4002:c08::\/64 — pirmie 64 biti (pirmās 4 grupas) ir prefikss, pārējie 64 biti ir lokālā daļa. Starp citu, ja kādu mulsina "::" ierakstā, divreiz kolons aizstāj neierobežotu skaitu sekciju, kurās ir 0. Tas var parādÄ«ties anotācijā tikai 1 reizi. Citādi sakot, 2607:f8b0:4002:c08::8b = 2607:f8b0:4002:c08:0:0:0:8b.

Kas no tā visa mums jāņem? Pirmkārt, pirmo un pēdējo apakÅ”netes adresi var iegÅ«t, izmantojot bināros AND un OR, zinot masku binārā formātā. Otrkārt, nākamo apakÅ”neti izmēra (t.i., ar CIDR) n var aprēķināt, pievienojot 1 n-tā pozÄ«cijā binārajā attēlā. Zem binārā es domāju rezultātu, izmantojot funkcijas pack() un inet_pton() un turpmāko bitu operatoru izmantoÅ”anu, zem bināra — attēlojums binārajā sistēmā, ko var iegÅ«t, piemēram, arbase_convert() Bezklasiskai iepriekŔēja klasiskā segregācija adresēŔana. Tajās senajās dienās neviens negaidÄ«ja, ka bÅ«s tik daudz apakÅ”netu, tās pieŔķīra pa kreisi un pa labi lielos blokos: klase A — prefikss bija pirmie 8 biti (t.i., pirmais skaitlis), ar vadoÅ”o bitu 0; klase B — pirmie 16 (pirmie divi skaitļi), vadoÅ”ie biti 10; klase C — pirmie 24 biti, vadoÅ”ie biti 110. Å ie vadoÅ”ie biti noteica diapazonus, kuros tika pieŔķirta adresi attiecÄ«gajā klasē:.

Vēsturiskā informācijaklase A, 0.0.0.0 — 127.255.255.255 — klase B, 192.0.0.0 — 223.255.255.255 — klase C. Laika gaitā, kā internets izplatÄ«jās pa planētu, regulatoriem kļuva skaidrs, ka viņi kļūdÄ«jās, un 90-to gadu sākumā tika izstrādāta bezklasiskā koncepcija, kas ļāva neierobežoties ar vadoÅ”ajiem bitiem. Mazliet vairāk detaļu var uzzināt, piemēram, 128.0.0.0 — 191.255.255.255 lielajā un viszinÄ«gajā Pāriesim uz praksi.

Praksē Ä«stenosim trÄ«s visdrÄ«zākās, kā man Ŕķita, uzdevumus:

pirmās un pēdējās adreses iegūŔana diapazonā;

  1. nākamā diapazona iegūŔana noteikta izmēra (CIDR);
  2. pārbaude par adreses piederību diapazonam.
  3. IevieŔana būs IPv6, taču, ja nepiecieŔams, loģiku var viegli pielāgot. Dažas idejas es ieguvu

, bet Ä«stenoju nedaudz citādāk. ArÄ« piemēros nav ievades kļūdu pārbaudes. Labi, sāksim. no Å”ejienesKā jau minēju, pirmo un pēdējo adresi diapazonā var noteikt, izmantojot bitu operācijas, zinot diapazona sākumu un bināro apakÅ”netes masku. AttiecÄ«gi pirmkārt mums jāpārveido CIDR binārā maske. Tāpēc mēs apkoposim tās hex attēlojumu un iepakosim binārā.

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); }

pack(ā€˜H*’, $mask)

Izsaukt iepako hex attēlojumu tieÅ”i tādā paŔā veidā kā . Ar to atŔķirÄ«bu, ka izsaukuma gadÄ«jumā inet_pton(). VienÄ«gā atŔķirÄ«ba ir tā, ka izsaukuma laikā pack() Visām 0 jābÅ«t savās vietās, un rakstā nedrÄ«kst bÅ«t kolonnas, atŔķirÄ«bā no cilvēkam saprotama ieraksta.

Nākamais solis ir noteikt diapazona sākumu un beigas. Un Å”eit var rasties nianses. Bitu operācijas ir ierobežotas procesora bitu skaitam. AttiecÄ«gi, manā 32 bitu CubieTruck, ko es dažreiz izmantoju dažādiem testēŔanas eksperimenti, nav iespējams apstrādāt visus 128 bitus adreses vienā operācijā. Tomēr nekas neliedz mums to sadalÄ«t grupās pa 32 bitiem (uz visiem gadÄ«jumiem, kas zina, uz kādiem procesoriem palaižam).

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);
    }
}

Nākotnē mēs paredzēsim iespēju pārsÅ«tÄ«t IP un saņemt rezultātu gan binārā, gan cilvēkam saprotamā formā. Parametrs $which Å”eit nosaka, vai mēs vēlamies saņemt sākumu vai beigas diapazonam (vērtÄ«bas ā€˜start’ vai ā€˜end’ attiecÄ«gi).

Nākamā uzdevuma (turklāt vispraktiskākā mÅ«su uzņēmumam) ir nākamā diapazona noteikÅ”ana. Å im uzdevumam nekas labāks nenāca prātā, kā sadalÄ«t adresi binārajā virknei un pievienot 1 vajadzÄ«gajā pozÄ«cijā, pēc tam saliekot visu atpakaļ. Lai neparādÄ«tos artefakti, es nolēmu, ka, iznākot un saliekot, adrese jāizsara pa baitiem.

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);
    }
}

Rezultātā mēs iegÅ«sim nākamā diapazona prefiksu, kura izmērs ir norādÄ«ts $cidr.Ar Å”o funkciju mēs pieŔķiram adreses blokiem mÅ«su klientiem.

Visbeidzot, jānodroÅ”ina, vai adrese pieder diapazonam. Piemēram, mēs pieŔķīrām vienu bloku /48 klientiem, lai pieŔķirtu blokiem /64, un mums jānodroÅ”ina, ka pieŔķirÅ”anas procesā neiznākam ārpus pieŔķirtā bloka (praktiski tas notiks reti, bet iespēja tomēr ir). Å eit viss ir vienkārÅ”i. IegÅ«stam diapazona sākumu un beigas binārā veidā un pārbaudām, vai adrese atrodas tai piemērotajās robežās.

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);
}

Ceru, ka tas bija noderÄ«gi. Kādas vēl funkcijas darbam ar adresēm, jÅ«suprāt, varētu bÅ«t noderÄ«gas? Jebkādi papildinājumi, komentāri un koda pārskatīŔana tiek laipni gaidÄ«ti komentāros.

Ja, ja esat mÅ«su klients vai tikai domājat par kļūŔanu par to, Ŕī raksta izdoÅ”anas gadÄ«jumā piedāvājam saņemt /64 bloku pilnÄ«gi bez maksas visām VPS vai dedikētā servera pakalpojumiem datu centrā Equinix Tier IV NÄ«derlandē, iesniedzot pieprasÄ«jumu pārdoÅ”anas nodaļā, norādot saiti uz Å”o rakstu biļetē. Piedāvājums ir spēkā lÄ«dz 2020. gada martam.

Mazliet reklāmas šŸ™‚

Paldies, ka paliekat ar mums. Vai jums patīk mūsu raksti? Vēlaties redzēt vairāk interesantus materiālus? Atbalstiet mūs, veicot pasūtījumu vai ieteicot draugiem, mākoņu VPS izstrādātājiem no $4.99, unikāls ieejas līmeņa serveru analogs, kuru mēs izstrādājām jums: Visa patiesība par VPS (KVM) E5-2697 v3 (6 kodoli) 10GB DDR4 480GB SSD 1Gbps no $19 vai kā pareizi dalīt serveri? (pieejami varianti ar RAID1 un RAID10, līdz 24 kodoliem un līdz 40GB DDR4).

Dell R730xd divas reizes lētāk datu centrā Equinix Tier IV Amsterdamā? Tikai pie mums 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100TB no $199 NÄ«derlandē! Dell R420 — 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB — no $99! Lasiet par to Kā izveidot korporatÄ«vas klases infrastruktÅ«ru, izmantojot Dell R730xd E5-2650 v4 serverus, kas maksā 9000 eiro par niekām?

Avots: habr.com

Iegādājieties uzticamu tÄ«mekļa hostingu ar DDoS aizsardzÄ«bu, VPS VDS serveriem šŸ”„ Iegādājieties uzticamu tÄ«mekļa hostingu ar DDoS aizsardzÄ«bu, VPS VDS serveriem | ProHoster