@@ -32,6 +32,8 @@ type ip2proxyMeta struct {
3232 ipV4DatabaseAddr uint32
3333 ipV6DatabaseCount uint32
3434 ipV6DatabaseAddr uint32
35+ ipV4Indexed bool
36+ ipV6Indexed bool
3537 ipV4IndexBaseAddr uint32
3638 ipV6IndexBaseAddr uint32
3739 ipV4ColumnSize uint32
@@ -109,7 +111,7 @@ var lastSeenPosition = [12]uint8{0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11}
109111var threatPosition = [12 ]uint8 {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 12 , 12 , 12 }
110112var providerPosition = [12 ]uint8 {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 13 }
111113
112- const moduleVersion string = "3.3.2 "
114+ const moduleVersion string = "3.4.0 "
113115
114116var maxIPV4Range = big .NewInt (4294967295 )
115117var maxIPV6Range = big .NewInt (0 )
@@ -184,13 +186,13 @@ func (d *DB) checkIP(ip string) (ipType uint32, ipNum *big.Int, ipIndex uint32)
184186 }
185187 }
186188 if ipType == 4 {
187- if d .meta .ipV4IndexBaseAddr > 0 {
189+ if d .meta .ipV4Indexed {
188190 ipNumTmp .Rsh (ipNum , 16 )
189191 ipNumTmp .Lsh (ipNumTmp , 3 )
190192 ipIndex = uint32 (ipNumTmp .Add (ipNumTmp , big .NewInt (int64 (d .meta .ipV4IndexBaseAddr ))).Uint64 ())
191193 }
192194 } else if ipType == 6 {
193- if d .meta .ipV6IndexBaseAddr > 0 {
195+ if d .meta .ipV6Indexed {
194196 ipNumTmp .Rsh (ipNum , 112 )
195197 ipNumTmp .Lsh (ipNumTmp , 3 )
196198 ipIndex = uint32 (ipNumTmp .Add (ipNumTmp , big .NewInt (int64 (d .meta .ipV6IndexBaseAddr ))).Uint64 ())
@@ -211,6 +213,17 @@ func (d *DB) readUint8(pos int64) (uint8, error) {
211213 return retVal , nil
212214}
213215
216+ // read row
217+ func (d * DB ) readRow (pos uint32 , size uint32 ) ([]byte , error ) {
218+ pos2 := int64 (pos )
219+ data := make ([]byte , size )
220+ _ , err := d .f .ReadAt (data , pos2 - 1 )
221+ if err != nil {
222+ return nil , err
223+ }
224+ return data , nil
225+ }
226+
214227// read unsigned 32-bit integer from slices
215228func (d * DB ) readUint32Row (row []byte , pos uint32 ) uint32 {
216229 var retVal uint32
@@ -236,6 +249,19 @@ func (d *DB) readUint32(pos uint32) (uint32, error) {
236249 return retVal , nil
237250}
238251
252+ // read unsigned 128-bit integer from slices
253+ func (d * DB ) readUint128Row (row []byte , pos uint32 ) * big.Int {
254+ retVal := big .NewInt (0 )
255+ data := row [pos : pos + 16 ]
256+
257+ // little endian to big endian
258+ for i , j := 0 , len (data )- 1 ; i < j ; i , j = i + 1 , j - 1 {
259+ data [i ], data [j ] = data [j ], data [i ]
260+ }
261+ retVal .SetBytes (data )
262+ return retVal
263+ }
264+
239265// read unsigned 128-bit integer
240266func (d * DB ) readUint128 (pos uint32 ) (* big.Int , error ) {
241267 pos2 := int64 (pos )
@@ -257,19 +283,15 @@ func (d *DB) readUint128(pos uint32) (*big.Int, error) {
257283// read string
258284func (d * DB ) readStr (pos uint32 ) (string , error ) {
259285 pos2 := int64 (pos )
286+ readLen := 256 // max size of string field + 1 byte for the length
260287 var retVal string
261- lenByte := make ([]byte , 1 )
262- _ , err := d .f .ReadAt (lenByte , pos2 )
263- if err != nil {
264- return "" , err
265- }
266- strLen := lenByte [0 ]
267- data := make ([]byte , strLen )
268- _ , err = d .f .ReadAt (data , pos2 + 1 )
288+ data := make ([]byte , readLen )
289+ _ , err := d .f .ReadAt (data , pos2 )
269290 if err != nil {
270291 return "" , err
271292 }
272- retVal = string (data [:strLen ])
293+ strLen := data [0 ]
294+ retVal = string (data [1 :(strLen + 1 )])
273295 return retVal , nil
274296}
275297
@@ -302,67 +324,42 @@ func OpenDBWithReader(reader dbReader) (*DB, error) {
302324
303325 db .f = reader
304326
327+ var row []byte
305328 var err error
306- db .meta .databaseType , err = db .readUint8 (1 )
307- if err != nil {
308- return fatal (db , err )
309- }
310- db .meta .databaseColumn , err = db .readUint8 (2 )
311- if err != nil {
312- return fatal (db , err )
313- }
314- db .meta .databaseYear , err = db .readUint8 (3 )
315- if err != nil {
316- return fatal (db , err )
317- }
318- db .meta .databaseMonth , err = db .readUint8 (4 )
319- if err != nil {
320- return fatal (db , err )
321- }
322- db .meta .databaseDay , err = db .readUint8 (5 )
323- if err != nil {
324- return fatal (db , err )
325- }
326- db .meta .ipV4DatabaseCount , err = db .readUint32 (6 )
327- if err != nil {
328- return fatal (db , err )
329- }
330- db .meta .ipV4DatabaseAddr , err = db .readUint32 (10 )
331- if err != nil {
332- return fatal (db , err )
333- }
334- db .meta .ipV6DatabaseCount , err = db .readUint32 (14 )
335- if err != nil {
336- return fatal (db , err )
337- }
338- db .meta .ipV6DatabaseAddr , err = db .readUint32 (18 )
339- if err != nil {
340- return fatal (db , err )
341- }
342- db .meta .ipV4IndexBaseAddr , err = db .readUint32 (22 )
343- if err != nil {
344- return fatal (db , err )
345- }
346- db .meta .ipV6IndexBaseAddr , err = db .readUint32 (26 )
347- if err != nil {
348- return fatal (db , err )
349- }
350- db .meta .productCode , err = db .readUint8 (30 )
351- if err != nil {
352- return fatal (db , err )
353- }
354- db .meta .productType , err = db .readUint8 (31 )
355- if err != nil {
356- return fatal (db , err )
357- }
358- db .meta .fileSize , err = db .readUint32 (32 )
329+ readLen := uint32 (64 ) // 64-byte header
330+
331+ row , err = db .readRow (1 , readLen )
359332 if err != nil {
360333 return fatal (db , err )
361334 }
335+ db .meta .databaseType = row [0 ]
336+ db .meta .databaseColumn = row [1 ]
337+ db .meta .databaseYear = row [2 ]
338+ db .meta .databaseMonth = row [3 ]
339+ db .meta .databaseDay = row [4 ]
340+ db .meta .ipV4DatabaseCount = db .readUint32Row (row , 5 )
341+ db .meta .ipV4DatabaseAddr = db .readUint32Row (row , 9 )
342+ db .meta .ipV6DatabaseCount = db .readUint32Row (row , 13 )
343+ db .meta .ipV6DatabaseAddr = db .readUint32Row (row , 17 )
344+ db .meta .ipV4IndexBaseAddr = db .readUint32Row (row , 21 )
345+ db .meta .ipV6IndexBaseAddr = db .readUint32Row (row , 25 )
346+ db .meta .productCode = row [29 ]
347+ db .meta .productType = row [30 ]
348+ db .meta .fileSize = db .readUint32Row (row , 31 )
349+
362350 // check if is correct BIN (should be 2 for IP2Proxy BIN file), also checking for zipped file (PK being the first 2 chars)
363351 if (db .meta .productCode != 2 && db .meta .databaseYear >= 21 ) || (db .meta .databaseType == 80 && db .meta .databaseColumn == 75 ) { // only BINs from Jan 2021 onwards have this byte set
364352 return fatal (db , errors .New (msgInvalidBin ))
365353 }
354+
355+ if db .meta .ipV4IndexBaseAddr > 0 {
356+ db .meta .ipV4Indexed = true
357+ }
358+
359+ if db .meta .ipV6DatabaseCount > 0 && db .meta .ipV6IndexBaseAddr > 0 {
360+ db .meta .ipV6Indexed = true
361+ }
362+
366363 db .meta .ipV4ColumnSize = uint32 (db .meta .databaseColumn << 2 ) // 4 bytes each column
367364 db .meta .ipV6ColumnSize = uint32 (16 + ((db .meta .databaseColumn - 1 ) << 2 )) // 4 bytes each column, except IPFrom column which is 16 bytes
368365
@@ -793,8 +790,11 @@ func (d *DB) query(ipAddress string, mode uint32) (ip2proxyRecord, error) {
793790 var high uint32
794791 var mid uint32
795792 var rowOffset uint32
796- var rowOffset2 uint32
797793 var countryPos uint32
794+ var firstCol uint32 = 4 // 4 bytes for ip from
795+ var row []byte
796+ var fullRow []byte
797+ var readLen uint32
798798 ipFrom := big .NewInt (0 )
799799 ipTo := big .NewInt (0 )
800800 maxIP := big .NewInt (0 )
@@ -809,6 +809,7 @@ func (d *DB) query(ipAddress string, mode uint32) (ip2proxyRecord, error) {
809809 x = loadMessage (msgIPV6Unsupported )
810810 return x , nil
811811 }
812+ firstCol = 16 // 16 bytes for ip from
812813 baseAddr = d .meta .ipV6DatabaseAddr
813814 high = d .meta .ipV6DatabaseCount
814815 maxIP = maxIPV6Range
@@ -817,14 +818,12 @@ func (d *DB) query(ipAddress string, mode uint32) (ip2proxyRecord, error) {
817818
818819 // reading index
819820 if ipIndex > 0 {
820- low , err = d .readUint32 (ipIndex )
821- if err != nil {
822- return x , err
823- }
824- high , err = d .readUint32 (ipIndex + 4 )
821+ row , err = d .readRow (ipIndex , 8 ) // 4 bytes each for IP From and IP To
825822 if err != nil {
826823 return x , err
827824 }
825+ low = d .readUint32Row (row , 0 )
826+ high = d .readUint32Row (row , 4 )
828827 }
829828
830829 if ipNo .Cmp (maxIP ) >= 0 {
@@ -834,43 +833,29 @@ func (d *DB) query(ipAddress string, mode uint32) (ip2proxyRecord, error) {
834833 for low <= high {
835834 mid = ((low + high ) >> 1 )
836835 rowOffset = baseAddr + (mid * colSize )
837- rowOffset2 = rowOffset + colSize
836+
837+ // reading IP From + whole row + next IP From
838+ readLen = colSize + firstCol
839+ fullRow , err = d .readRow (rowOffset , readLen )
840+ if err != nil {
841+ return x , err
842+ }
838843
839844 if ipType == 4 {
840- ipFrom32 , err := d .readUint32 (rowOffset )
841- if err != nil {
842- return x , err
843- }
845+ ipFrom32 := d .readUint32Row (fullRow , 0 )
844846 ipFrom = big .NewInt (int64 (ipFrom32 ))
845847
846- ipTo32 , err := d .readUint32 (rowOffset2 )
847- if err != nil {
848- return x , err
849- }
848+ ipTo32 := d .readUint32Row (fullRow , colSize )
850849 ipTo = big .NewInt (int64 (ipTo32 ))
851850 } else {
852- ipFrom , err = d .readUint128 (rowOffset )
853- if err != nil {
854- return x , err
855- }
851+ ipFrom = d .readUint128Row (fullRow , 0 )
856852
857- ipTo , err = d .readUint128 (rowOffset2 )
858- if err != nil {
859- return x , err
860- }
853+ ipTo = d .readUint128Row (fullRow , colSize )
861854 }
862855
863856 if ipNo .Cmp (ipFrom ) >= 0 && ipNo .Cmp (ipTo ) < 0 {
864- var firstCol uint32 = 4 // 4 bytes for ip from
865- if ipType == 6 {
866- firstCol = 16 // 16 bytes for ipv6
867- }
868-
869- row := make ([]byte , colSize - firstCol ) // exclude the ip from field
870- _ , err := d .f .ReadAt (row , int64 (rowOffset + firstCol - 1 ))
871- if err != nil {
872- return x , err
873- }
857+ rowLen := colSize - firstCol
858+ row = fullRow [firstCol :(firstCol + rowLen )] // extract the actual row data
874859
875860 if d .proxyTypeEnabled {
876861 if mode & proxyType != 0 || mode & isProxy != 0 {
0 commit comments