OTHER PROSPECTS
Hello. You can check if the address is locked or not by accessing two bytes in two 8 KB data blocks. Yes, I'm serious ... Please be patient because it takes a little time to explain this.
THEORY
An IP address is an address, in fact a 4-byte number.
The question is, what if we do this to access bit positions ?.
Answer: Well, we will have
2^32 = 4 Giga Bits
addressing space and it will take
4Gb/8 = 512 Mega Bytes
distribution. Ouch! But don’t worry, we are not going to block everything in ipverse, and 512MB is an exaggeration.
This may open the door to a solution.
Liliput case
Think of a Lilliputian world in which there are only IP addresses from 0 to 65535. Thus, the addresses have a value of 0.1 or 42.42 to 255.255.
Now the king of this world wants to block several L-IP addresses (lilliput ip).
First, he creates a virtual two-dimensional bitmap with a length of 256 * 256 bits, which takes up:
64 K Bits = 8 K Bytes.
He decides to block this unpleasant “revolution” site, which he hates because he is king, for example, the address 56.28.
Address = (56 * 256) + 28 = 14364.(bit position in whole map) Byte in map = floor(14364 / 8) = 1795. Bit position= 14364 % 8 = 4.(modulus)
He opens the map file, accesses the 1795th byte and sets bit 4 (to | 16), then writes it back to mark the site as blocked.
When his script sees 56.28, it performs the same calculation and looks at the bit, and if it is set, it blocks the address.
Now, what is the moral of this story? Well, we can use this lilliputic structure.
PRACTICE
Real world thing
We can apply the Lilliput affair to the real world with “use it when you need it,” because allocating a 512 MB file is not a good choice.
Think of a database table called BLOCKS with these elements:
IpHead(key): unsigned 16 bit integer, Map : 8KB BLOB(fixed size), EntryCount : unsigned 16 bit integer.
And another table with only one record with the structure below called BASE
Map : 8KB BLOB(fixed size).
Now let's say you have an incoming address 56.28.10.2
Script accesses the BASE table and receives a map.
He is looking for IP numbers :
Address = (56 * 256) + 28 = 14364.(bit position in whole map) Byte in map = floor(14364 / 8) = 1795. Bit position= 14364 % 8 = 4.(modulus)
Look at the byte of 1795 bit 4 on the map.
If the bit is not set, further operation is not required, since there is no blocked IP address in the range 56.28.0.0 - 56.28.255.255.
If the bit is set, the script accesses the BLOCKS table.
Higher order IP numbers were 56.28, which gives 14364, so the script queries the BLOCKS table with index IpHead = 14364. Selects the entry. The record must exist, as it is marked on BASE.
Script calculates for a lower IP address
Address = (10 * 256) + 2 = 2562.(bit position in whole map) Byte in map = floor(2562 / 8) = 320. Bit position= 2562 % 8 = 2.(modulus)
He then checks to see if the address is blocked by looking at bit 2 of byte 320 of the field map.
The task is completed!
Q1: Why do we use BASE at all, we can directly request BLOCKS from 14364.
A1: Yes, we could, but a search in a BASE card will be faster than a BTREE search for any database server.
Q2: What is the EntryCount field in the BLOCKS table for?
A2:. The number of IP addresses is blocked in the map field in the same entry. So, if we unlock ip and EntryCount reaches 0, then the BLOCKS record will become unnecessary. It can be erased, and the corresponding bit on the BASE card will be canceled.
IMHO, this approach will be lightning fast. Also for highlighting 8K blob for recording. Since db servers store drops in separate files, file systems with 4K, 8K or multiples of 4K paging will respond quickly.
In case blocked addresses are too scattered
Well, this is a problem that will make the database table BLOCK unnecessarily.
But for such cases, an alternative is to use a 256 * 256 * 256-bit cube with a length of 16777216 bits, equal to 2097152 bytes = 2 MB.
In our previous example, a higher resolution Ip:
(56 * 65536)+(28 * 256)+10
So, the BASE will become a 2MB file instead of writing the db table to be opened (fopen, etc.), and the bit will be processed by searching (for example, fseek, never read the contents of the entire file, it is not necessary), then enter the BLOCKS table with structure below:
IpHead(key): unsigned 32 bit integer, (only 24 bit is used) Map : 32 unsigned 8 bit integers(char maybe),(256 bit fixed) EntryCount : unsigned 8 bit integer.
Here is a sample PHP code for checking the blocks of the bitplane-bitplane (8K 8K) version:
Side note: this script can be optimized by eliminating multiple calls, etc. But it is written so that it is easy to understand.
<? define('BLOCK_ON_ERROR', true); // WARNING if true errors block everyone $shost = 'hosturl'; $suser = 'username'; $spass = 'password'; $sdbip = 'database'; $slink = null; $slink = mysqli_connect($shost, $suser, $spass, $sdbip); if (! $slink) { $blocked = BLOCK_ON_ERROR; } else { $blocked = isBlocked(); mysqli_close($slink); // clean, tidy... } if ($blocked) { // do what ever you want when blocked } else { // do what ever you want when not blocked } exit(0); function getUserIp() { $st = array( 'HTTP_CLIENT_IP', 'REMOTE_ADDR', 'HTTP_X_FORWARDED_FOR' ); foreach ( $st as $v ) if (! empty($_SERVER[$v])) return ($_SERVER[$v]); return (""); } function ipToArray($ip) { $ip = explode('.', $ip); foreach ( $ip as $k => $v ) $ip[$k] = intval($v); return ($ip); } function calculateBitPos($IpH, $IpL) { $BitAdr = ($IpH * 256) + $IpL; $BytAdr = floor($BitAdr / 8); $BitOfs = $BitAdr % 8; $BitMask = 1; $BitMask = $BitMask << $BitOfs; return (array( 'bytePos' => $BytAdr, 'bitMask' => $BitMask )); } function getBaseMap($link) { $q = 'SELECT * FROM BASE WHERE id = 0'; $r = mysqli_query($link, $q); if (! $r) return (null); $m = mysqli_fetch_assoc($r); mysqli_free_result($r); return ($m['map']); } function getBlocksMap($link, $IpHead) { $q = "SELECT * FROM BLOCKS WHERE IpHead = $IpHead"; $r = mysqli_query($link, $q); if (! $r) return (null); $m = mysqli_fetch_assoc($r); mysqli_free_result($r); return ($m['map']); } function isBlocked() { global $slink; $ip = getUserIp(); if($ip == "") return (BLOCK_ON_ERROR); $ip = ipToArray($ip); // here you can embed preliminary checks like ip[0] = 10 exit(0) // for unblocking or blocking address range 10 or 192 or 127 etc.... // Look at base table base record. // map is a php string, which in fact is a good byte array $map = getBaseMap($slink); if (! $map) return (BLOCK_ON_ERROR); $p = calculateBitPos($ip[0], $ip[1]); $c = ord($map[$p['bytePos']]); if (($c & $p['bitMask']) == 0) return (false); // No address blocked // Look at blocks table related record $map = getBlocksMap($slink, $p[0]); if (! $map) return (BLOCK_ON_ERROR); $p = calculateBitPos($ip[2], $ip[3]); $c = ord($map[$p['bytePos']]); return (($c & $p['bitMask']) != 0); } ?>
Hope this helps.
If you have questions about the details, I will be happy to answer.