The IP database on the network is the most popular in the pure real version. This article does not study the format and only converts it to text format.
The format of the pure IP database. This article references Luma's article and lumaqq's ipseeker class code, which is written in C language. Originally, I wanted to write a class specifically designed to read pure IP database, so the code in this article was originally a test code, and I didn't continue to do it when I was lazy, so the code looks messy, hey.
// File: getlist. c
# Include <stdio. h>
# Include <stdlib. h>
# Include <unistd. h>
# Include <fcntl. h>
# Include <assert. h>
# Include <string. h>
# Include <ARPA/inet. h>
# Include <sys/types. h>
# Include <sys/Mman. h>
# Include <sys/STAT. h>
# Define ip_dbpath "/usr/local/lumaqq/qqwry. dat"
# Define head_size 8
Char * record_mmap;
# Define ip_quad_format_string "% 03u. % 03u. % 03u. % 03u"
# Define ip_quad_le (X )/
* (Unsigned char *) x + 3 ),/
* (Unsigned char *) x + 2 ),/
* (Unsigned char *) x + 1 ),/
* (Unsigned char *) x + 0)
Void oops (const char * MSG)
{
Perror (MSG );
Exit (1 );
}
// Proto: Unsigned long int_of_4byte_le (const char * Data)
// Function: read 4 byte from data, convert it to unsigned
// Integer in little endian order.
// Argument: Data in little endian (LE) Order
// Return: value of 4 byte data in Le
Unsigned long int_of_4byte_le (const char * Data)
{
Const unsigned char * P = (const unsigned char *) data;
Return (P [0]) +
(P [1] <8) +
(P [2] <16) +
(P [3] <24)
);
}
Unsigned long int_of_3byte_le (const char * Data)
{
Const unsigned char * P = (const unsigned char *) data;
Return (P [0]) +
(P [1] <8) +
(P [2] <16)
);
}
Void read_record (off_t offset)
{
Const char * P = record_mmap;
Const char * Country = NULL;
Const char * Territory = NULL;
Printf (ip_quad_format_string, ip_quad_le (p + offset ));
P + = offset + 4;
Do {
If (P [0] = 0x01 ){
P = record_mmap + int_of_3byte_le (p + 1 );
Continue;
}
If (P [0] = 0x02 ){
Country = record_mmap + int_of_3byte_le (p + 1 );
P + = 4;
While (P [0] = 0x01 | P [0] = 0x02 ){
P = record_mmap + int_of_3byte_le (p + 1 );
}
Territory = P;
Break;
}
Country = P;
P = strchr (p, 0) + 1;
While (P [0] = 0x01 | P [0] = 0x02 ){
P = record_mmap + int_of_3byte_le (p + 1 );
}
Territory = P;
} While (! Country |! Territory );
Printf ("/T % S/T % s/n", country, territory );
}
Void iterate_index (INT dB)
{
Char record [7];
Int N;
Int offset;
Do {
N = read (dB, record, 7 );
If (n = 0) break;
Assert (n = 7 );
Offset = int_of_3byte_le (record + 4 );
/* Printf (ip_quad_format_string "@ % # 010x-> ",
Ip_quad_le (record ),
Offset
);*/
Read_record (offset );
} While (1 );
}
Int main (INT argc, char ** argv)
{
Char Buf [head_size];
Unsigned int index_beg, index_end;
Int dB;
If (DB = open (ip_dbpath, o_rdonly) =-1) Oops ("opendb error! ");
If (read (dB, Buf, head_size )! = Head_size) Oops ("read data Header error! ");
Index_beg = int_of_4byte_le (BUF );
Index_end = int_of_4byte_le (BUF + 4 );
Assert (index_end-index_beg) % 7 = 0 );
// Printf ("index start from: % # 08x/N"
// "End at: % # 08x/N ",
// Index_beg, index_end );
Record_mmap = MMAP (null, index_beg, prot_read, map_shared, DB, 0 );
If (record_mmap = (void *)-1) Oops ("MMAP error ");
Lseek (dB, index_beg-8, seek_cur );
// Printf ("indexes:/N ");
Iterate_index (db );
}
Run it when you use it.
./Getlist> chunzhenip. GB
./Getlist | iconv-f gb-T UTF-8> chunzhengip. UTF-8
The format is
IP segment/T level 1 place name/T level 2 Place Name/n
Then we can use the text analysis tools awk/SED/perl to analyze them.