Wurkje mei IPv6 yn PHP

Wy hawwe koartlyn LIR-status en /29 IPv6-blok krigen. En doe ûntstie de needsaak om de tawiisde subnetten by te hâlden. En om't ús fakturearring yn PHP skreaun is, moasten wy it probleem in bytsje ferdjipje en realisearje dat dizze taal net de freonlikste is yn termen fan wurkjen mei IPv6. Under de besuniging is ús oplossing foar de problemen dy't ûntsteane by it wurkjen mei adressen en berik. Miskien net de meast elegante, mar it docht it wurk.

Wurkje mei IPv6 yn PHP

In bytsje teory

Disclaimer. As jo ​​​​bekend binne mei wat IPv6 is en wat it komt mei, kin dit diel foar jo saai wêze. It kin net wêze.

Minsken dy't de IPv6-annotaasje foar it earst sjogge, kinne it nochal dreech fine. Na elegant 64.233.177.101 wy binne ynienen konfrontearre mei 2607:f8b0:4002:c08::8b en wy kinne yn 'e war wurde. Beide binne gewoan foar minsken lêsbere foarstellingen fan respektivelik 32 en 128 bits. Elk IP-pakket befettet in koptekst mei in strikt standerdisearre doel foar elke bit. Sûnder djipper yn 'e struktuer fan' e kopteksten te gean, ien ding dat wy hjirfan moatte nimme is dat it foar operaasjes mei IP-adressen en berik oer it algemien handich is om binêre wiskunde en bitwize operaasjes te brûken. It is ek it meast handich om se op te slaan yn 'e databank as BINARY(4) foar IPv4 en BINARY(16) foar IPv6.

In oar wichtich aspekt dat it wurdich is oan te raken is netwurkmaskers en CIDR-notaasje. CIDR is in akronym foar Classless Inter-Domain Routing (klasseleaze adressering). Dit konsept hat it klassekonsept ferfongen by it bepalen fan hokker diel fan it IP-adres it netwurkfoarheaksel is, en hokker diel it adres is fan it netwurkynterface binnen dit netwurk. Yn 'e praktyk sille de earste n bits dy't oerienkomme mei it foarheaksel wurde ynsteld op 1, de rest op 0.

Yn minsklik begryplike foarm is dit skreaun yn 'e foarm ip.add.re.ss/cidr. Bygelyks 64.233.177.0/24 jout oan dat de earste 24 bits ferwize nei it foarheaksel. De lêste 8 bits, ek wol bekend as it lêste nûmer yn minsklik lêsbere notaasje, ferwize nei it adres binnen it subnet. Noch in pear oefeningen. 64.233.177.101/32 и 2607:f8b0:4002:c08::8b/128 - ien spesifyk adres. 2607:f8b0:4002:c08::/64 - de earste 64 bits (de earste 4 groepen) binne it foarheaksel, de oerbleaune 64 bits binne it lokale diel. Trouwens, as immen betize wurdt troch de "::" yn 'e yngong, ferfangt de dûbele kolon in willekeurige oantal seksjes mei 0. It kin mar ien kear yn 'e annotaasje ferskine. Mei oare wurden, 2607:f8b0:4002:c08::8b = 2607:f8b0:4002:c08:0:0:0:8b.

Wat moatte wy fan dit alles leare? As earste kinne it earste en lêste subnetadres wurde krigen mei binêre EN en OR, mei it kennen fan it masker yn binêre foarm. Twad, de folgjende subnetgrutte (dus mei CIDR) n kin berekkene wurde troch it tafoegjen fan 1 oan n-dy posysje yn binêre fertsjintwurdiging. Mei binêr bedoel ik it resultaat fan it brûken fan funksjes pakke() и inet_pton() en fierder gebrûk bitwise operators, troch binêr is de binêre systeemfoarstelling dy't kin wurde krigen troch bygelyks, base_convert().

Histoaryske eftergrûnKlasseleaze adressering waard foarôfgien troch klasse segregaasje. Yn dy fiere jierren hie gjinien foarsteld dat der safolle subnetten wêze soene: se waarden lofts en rjochts ferdield yn grutte blokken: klasse A - it foarheaksel wie de earste 8 bits (dus it earste nûmer), mei in liedend bit fan 0; klasse B - earste 16 (earste twa nûmers), liedende bits 10; klasse C - de earste 24 bits, liedende bits 110. Dizze liedende bits spesifisearre de berik wêryn it adres fan in bepaalde klasse waard útjûn: 0.0.0.0 - 127.255.255.255 foar klasse A, 128.0.0.0 - 191.255.255.255 - klasse B, 192.0.0.0 - 223.255.255.255 - klasse C. Doe't it ynternet ferspraat oer de planeet, realisearre tafersjochhâlders dat se de mark miste, en yn 'e iere jierren '90 ûntwikkele se in klasseleas konsept dat it mooglik makke om net bûn te wurden nei de liedende stikken. In bytsje mear detail is te finen yn, sis, great en alwittend.

Litte wy trochgean nei de praktyk

Yn 'e praktyk sille wy de trije meast wierskynlike taken útfiere, sa't it my like:

  1. it earste en lêste adres fan it berik krije;
  2. fa folgjende opjûne grutte berik (CIDR);
  3. kontrolearje oft in adres by in berik heart.

De ymplemintaasje sil foar IPv6 wêze, mar as it nedich is, kin de logika maklik oanpast wurde. Ik haw wat ideeën fan hjir, mar útfierd it in bytsje oars. Ek kontrolearje de foarbylden net op ynfierflaters. Dus, litte wy gean.

Lykas ik al neamde, kin it earste en lêste adres fan in berik bepaald wurde mei bitwize operaasjes, wittende it begjin fan it berik en it binêre subnetmasker. Dêrtroch is it earste ding dat wy moatte dwaan de CIDR omsette yn in binêre masker. Om dit te dwaan, sille wy de hex-representaasje sammelje en it yn in binêre pakke.

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

Challenge pack('H*', $mask) packs de hex fertsjintwurdiging op deselde wize as inet_pton(). It ienige ferskil is dat by it roppen pakke() alle 0's moatte op har plakken wêze, en d'r moatte gjin kolons yn 'e yngong wêze, yn tsjinstelling ta minsklik lêsbere yngong.

De folgjende stap is om it begjin en ein fan it berik te berekkenjen. En hjir ûntsteane nuânses. Bitwize operaasjes wurde beheind troch de bitkapasiteit fan 'e prosessor. Dêrnjonken sil it op myn 32-bit CubieTruck, dy't ik soms brûk foar alle soarten testferwenning, net mooglik wêze om alle 128 bits fan it adres yn ien operaasje te ferwurkjen. Neat foarkomt ús lykwols om it te dielen yn groepen fan 32 bits (foar it gefal, wa wit op hokker processors wy sille rinne).

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

Foar takomstich gebrûk sille wy de mooglikheid leverje om IP te ferstjoeren en it resultaat te ûntfangen yn sawol binêre as minsklik lêsbere foarm. Parameter $ hokker hjir spesifisearret it oan oft wy it begjin of ein fan it berik wolle krije (wearden 'start' of 'ein' respektivelik).

De folgjende taak (en ek de meast praktyske foar ús bedriuw) is it berekkenjen fan it folgjende berik. Foar dizze taak kaam neat better yn 't sin dan om it adres út te wreidzjen yn in binêre tekenrige en 1 ta te foegjen yn' e winske posysje, en dan alles werom te fallen. Om foar te kommen dat artefakten oeral ferskine, besleat ik it adres te splitsen foar byte by ûntbining en gearstalling.

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

By de útfier krije wy it foarheaksel fan it folgjende grutte berik spesifisearre yn $cidr. Mei dizze funksje tawize wy blokken fan adressen oan ús kliïnten.

As lêste, kontrolearje oft it adres heart by it berik. Wy hawwe bygelyks ien blok /48 tawiisd foar it fersprieden fan blokken oan kliïnten /64, en wy moatte der foar soargje dat wy by it tawizen net fierder gean as it tawiisde blok (yn 'e praktyk sil dit net gau barre, mar der is noch in mooglikheid). Alles is hjir ienfâldich. Wy krije it begjin en ein fan it berik yn binêre foarm en kontrolearje oft it adres binnen de grinzen is.

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

Ik hoopje dat dit nuttich wie. Hokker oare funksjes foar it wurkjen mei adressen kinne neffens jo nuttich wêze? Alle tafoegings, opmerkings en koadebeoardielingen binne fan herte wolkom yn 'e kommentaren.

As jo ​​​​al ús kliïnt binne of gewoan tinke om ien te wurden, by gelegenheid fan 'e publikaasje fan dit artikel biede wy jo in blok te ûntfangen /64 folslein fergees foar alle vps tsjinsten of tawijd tsjinner yn de Equinix Tier IV datacenter, Nederlân op oanfraach oan de ferkeap ôfdieling troch it jaan fan in keppeling nei dit artikel yn it kaartsje. It oanbod is jildich oant maart 2020.

Guon advertinsjes 🙂

Tankewol foar it bliuwen by ús. Hâld jo fan ús artikels? Wolle jo mear ynteressante ynhâld sjen? Stypje ús troch in bestelling te pleatsen of oan te befeljen oan freonen, wolk VPS foar ûntwikkelders fan $ 4.99, in unike analoog fan servers op yngongsnivo, dy't troch ús foar jo útfûn is: De hiele wierheid oer VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps fan $19 of hoe te dielen in tsjinner? (beskikber mei RAID1 en RAID10, oant 24 kearnen en oant 40GB DDR4).

Dell R730xd 2 kear goedkeaper yn Equinix Tier IV data sintrum yn Amsterdam? Allinne hjir 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV fan $199 yn Nederlân! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - fan $99! Lêze oer Hoe kinne jo Infrastructure Corp. klasse mei it brûken fan Dell R730xd E5-2650 v4 tsjinners wurdich 9000 euro foar in penny?

Boarne: www.habr.com

Keapje betroubere hosting foar siden mei DDoS-beskerming, VPS VDS-tsjinners 🔥 Keapje betroubere websidehosting mei DDoS-beskerming, VPS VDS-tsjinners | ProHoster