@@ -24,6 +24,7 @@ Public Structure ProxyResult
2424End Structure
2525
2626Public Class Component
27+ Private ReadOnly _LockLoadBIN As New Object
2728 Private _DBFilePath As String = ""
2829 Private _MMF As MemoryMappedFile = Nothing
2930 Private ReadOnly _IndexArrayIPv4( 65535 , 1 ) As Integer
@@ -339,91 +340,104 @@ Public Class Component
339340 ' Description: Read BIN file into memory mapped file and create accessors
340341 Private Function LoadBIN() As Boolean
341342 Dim LoadOK As Boolean = False
342- If _DBFilePath <> "" Then
343- CreateMemoryMappedFile()
344-
345- If _MMF IsNot Nothing Then
346- ' below use temp accessor as we only need once to read meta data (use this even when in filestream mode)
347- Using _MetaAccessor As MemoryMappedViewAccessor = _MMF.CreateViewAccessor( 0 , 64 , MemoryMappedFileAccess.Read) ' 64 bytes header
348- _DBType = _MetaAccessor.ReadByte( 0 )
349- _DBColumn = _MetaAccessor.ReadByte( 1 )
350- _DBYear = _MetaAccessor.ReadByte( 2 )
351- _DBMonth = _MetaAccessor.ReadByte( 3 )
352- _DBDay = _MetaAccessor.ReadByte( 4 )
353- _DBCount = _MetaAccessor.ReadInt32( 5 ) '4 bytes
354- _BaseAddr = _MetaAccessor.ReadInt32( 9 ) '4 bytes
355- _DBCountIPv6 = _MetaAccessor.ReadInt32( 13 ) '4 bytes
356- _BaseAddrIPv6 = _MetaAccessor.ReadInt32( 17 ) '4 bytes
357- _IndexBaseAddr = _MetaAccessor.ReadInt32( 21 ) '4 bytes
358- _IndexBaseAddrIPv6 = _MetaAccessor.ReadInt32( 25 ) '4 bytes
359- _ProductCode = _MetaAccessor.ReadByte( 29 )
360- _ProductType = _MetaAccessor.ReadByte( 30 )
361- _FileSize = _MetaAccessor.ReadInt32( 31 ) '4 bytes
362-
363- ' check if is correct BIN (should be 2 for IP2Proxy BIN file), also checking for zipped file (PK being the first 2 chars)
364- If (_ProductCode <> 2 AndAlso _DBYear >= 21 ) OrElse (_DBType = 80 AndAlso _DBColumn = 75 ) Then ' only BINs from Jan 2021 onwards have this byte set
365- Throw New Exception(MSG_INVALID_BIN)
366- End If
343+ SyncLock _LockLoadBIN
344+ If _DBFilePath <> "" Then
345+ If _DBType = 0 Then
346+ Using _Filestream = New FileStream(_DBFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)
347+ Dim len = 64 ' 64-byte header
348+ Dim row(len - 1 ) As Byte
349+
350+ _Filestream.Seek( 0 , SeekOrigin.Begin)
351+ _Filestream.Read(row, 0 , len)
352+
353+ _DBType = Read8Header(row, 0 )
354+ _DBColumn = Read8Header(row, 1 )
355+ _DBYear = Read8Header(row, 2 )
356+ _DBMonth = Read8Header(row, 3 )
357+ _DBDay = Read8Header(row, 4 )
358+ _DBCount = Read32Header(row, 5 ) '4 bytes
359+ _BaseAddr = Read32Header(row, 9 ) '4 bytes
360+ _DBCountIPv6 = Read32Header(row, 13 ) '4 bytes
361+ _BaseAddrIPv6 = Read32Header(row, 17 ) '4 bytes
362+ _IndexBaseAddr = Read32Header(row, 21 ) '4 bytes
363+ _IndexBaseAddrIPv6 = Read32Header(row, 25 ) '4 bytes
364+ _ProductCode = Read8Header(row, 29 )
365+ ' below 2 fields just read for now, not being used yet
366+ _ProductType = Read8Header(row, 30 )
367+ _FileSize = Read32Header(row, 31 ) '4 bytes
368+
369+ ' check if is correct BIN (should be 2 for IP2Proxy BIN file), also checking for zipped file (PK being the first 2 chars)
370+ If (_ProductCode <> 2 AndAlso _DBYear >= 21 ) OrElse (_DBType = 80 AndAlso _DBColumn = 75 ) Then ' only BINs from Jan 2021 onwards have this byte set
371+ Throw New Exception(MSG_INVALID_BIN)
372+ End If
367373
368- _IPv4ColumnSize = _DBColumn << 2 ' 4 bytes each column
369- _IPv6ColumnSize = 16 + ((_DBColumn - 1 ) << 2 ) ' 4 bytes each column, except IPFrom column which is 16 bytes
370-
371- COUNTRY_POSITION_OFFSET = If (COUNTRY_POSITION(_DBType) <> 0 , (COUNTRY_POSITION(_DBType) - 2 ) << 2 , 0 )
372- REGION_POSITION_OFFSET = If (REGION_POSITION(_DBType) <> 0 , (REGION_POSITION(_DBType) - 2 ) << 2 , 0 )
373- CITY_POSITION_OFFSET = If (CITY_POSITION(_DBType) <> 0 , (CITY_POSITION(_DBType) - 2 ) << 2 , 0 )
374- ISP_POSITION_OFFSET = If (ISP_POSITION(_DBType) <> 0 , (ISP_POSITION(_DBType) - 2 ) << 2 , 0 )
375- PROXYTYPE_POSITION_OFFSET = If (PROXYTYPE_POSITION(_DBType) <> 0 , (PROXYTYPE_POSITION(_DBType) - 2 ) << 2 , 0 )
376- DOMAIN_POSITION_OFFSET = If (DOMAIN_POSITION(_DBType) <> 0 , (DOMAIN_POSITION(_DBType) - 2 ) << 2 , 0 )
377- USAGETYPE_POSITION_OFFSET = If (USAGETYPE_POSITION(_DBType) <> 0 , (USAGETYPE_POSITION(_DBType) - 2 ) << 2 , 0 )
378- ASN_POSITION_OFFSET = If (ASN_POSITION(_DBType) <> 0 , (ASN_POSITION(_DBType) - 2 ) << 2 , 0 )
379- AS_POSITION_OFFSET = If (AS_POSITION(_DBType) <> 0 , (AS_POSITION(_DBType) - 2 ) << 2 , 0 )
380- LASTSEEN_POSITION_OFFSET = If (LASTSEEN_POSITION(_DBType) <> 0 , (LASTSEEN_POSITION(_DBType) - 2 ) << 2 , 0 )
381- THREAT_POSITION_OFFSET = If (THREAT_POSITION(_DBType) <> 0 , (THREAT_POSITION(_DBType) - 2 ) << 2 , 0 )
382- PROVIDER_POSITION_OFFSET = If (PROVIDER_POSITION(_DBType) <> 0 , (PROVIDER_POSITION(_DBType) - 2 ) << 2 , 0 )
383-
384- COUNTRY_ENABLED = COUNTRY_POSITION(_DBType) <> 0
385- REGION_ENABLED = REGION_POSITION(_DBType) <> 0
386- CITY_ENABLED = CITY_POSITION(_DBType) <> 0
387- ISP_ENABLED = ISP_POSITION(_DBType) <> 0
388- PROXYTYPE_ENABLED = PROXYTYPE_POSITION(_DBType) <> 0
389- DOMAIN_ENABLED = DOMAIN_POSITION(_DBType) <> 0
390- USAGETYPE_ENABLED = USAGETYPE_POSITION(_DBType) <> 0
391- ASN_ENABLED = ASN_POSITION(_DBType) <> 0
392- AS_ENABLED = AS_POSITION(_DBType) <> 0
393- LASTSEEN_ENABLED = LASTSEEN_POSITION(_DBType) <> 0
394- THREAT_ENABLED = THREAT_POSITION(_DBType) <> 0
395- PROVIDER_ENABLED = PROVIDER_POSITION(_DBType) <> 0
396- End Using
397-
398- Using _IndexAccessor As MemoryMappedViewAccessor = _MMF.CreateViewAccessor(_IndexBaseAddr - 1 , _BaseAddr - _IndexBaseAddr, MemoryMappedFileAccess.Read) ' reading indexes
399- Dim Pointer As Integer = 0
400-
401- ' read IPv4 index
402- For x As Integer = _IndexArrayIPv4.GetLowerBound( 0 ) To _IndexArrayIPv4.GetUpperBound( 0 )
403- _IndexArrayIPv4(x, 0 ) = _IndexAccessor.ReadInt32(Pointer) '4 bytes for from row
404- _IndexArrayIPv4(x, 1 ) = _IndexAccessor.ReadInt32(Pointer + 4 ) '4 bytes for to row
405- Pointer += 8
406- Next
374+ _IPv4ColumnSize = _DBColumn << 2 ' 4 bytes each column
375+ _IPv6ColumnSize = 16 + ((_DBColumn - 1 ) << 2 ) ' 4 bytes each column, except IPFrom column which is 16 bytes
376+
377+ COUNTRY_POSITION_OFFSET = If (COUNTRY_POSITION(_DBType) <> 0 , (COUNTRY_POSITION(_DBType) - 2 ) << 2 , 0 )
378+ REGION_POSITION_OFFSET = If (REGION_POSITION(_DBType) <> 0 , (REGION_POSITION(_DBType) - 2 ) << 2 , 0 )
379+ CITY_POSITION_OFFSET = If (CITY_POSITION(_DBType) <> 0 , (CITY_POSITION(_DBType) - 2 ) << 2 , 0 )
380+ ISP_POSITION_OFFSET = If (ISP_POSITION(_DBType) <> 0 , (ISP_POSITION(_DBType) - 2 ) << 2 , 0 )
381+ PROXYTYPE_POSITION_OFFSET = If (PROXYTYPE_POSITION(_DBType) <> 0 , (PROXYTYPE_POSITION(_DBType) - 2 ) << 2 , 0 )
382+ DOMAIN_POSITION_OFFSET = If (DOMAIN_POSITION(_DBType) <> 0 , (DOMAIN_POSITION(_DBType) - 2 ) << 2 , 0 )
383+ USAGETYPE_POSITION_OFFSET = If (USAGETYPE_POSITION(_DBType) <> 0 , (USAGETYPE_POSITION(_DBType) - 2 ) << 2 , 0 )
384+ ASN_POSITION_OFFSET = If (ASN_POSITION(_DBType) <> 0 , (ASN_POSITION(_DBType) - 2 ) << 2 , 0 )
385+ AS_POSITION_OFFSET = If (AS_POSITION(_DBType) <> 0 , (AS_POSITION(_DBType) - 2 ) << 2 , 0 )
386+ LASTSEEN_POSITION_OFFSET = If (LASTSEEN_POSITION(_DBType) <> 0 , (LASTSEEN_POSITION(_DBType) - 2 ) << 2 , 0 )
387+ THREAT_POSITION_OFFSET = If (THREAT_POSITION(_DBType) <> 0 , (THREAT_POSITION(_DBType) - 2 ) << 2 , 0 )
388+ PROVIDER_POSITION_OFFSET = If (PROVIDER_POSITION(_DBType) <> 0 , (PROVIDER_POSITION(_DBType) - 2 ) << 2 , 0 )
389+
390+ COUNTRY_ENABLED = COUNTRY_POSITION(_DBType) <> 0
391+ REGION_ENABLED = REGION_POSITION(_DBType) <> 0
392+ CITY_ENABLED = CITY_POSITION(_DBType) <> 0
393+ ISP_ENABLED = ISP_POSITION(_DBType) <> 0
394+ PROXYTYPE_ENABLED = PROXYTYPE_POSITION(_DBType) <> 0
395+ DOMAIN_ENABLED = DOMAIN_POSITION(_DBType) <> 0
396+ USAGETYPE_ENABLED = USAGETYPE_POSITION(_DBType) <> 0
397+ ASN_ENABLED = ASN_POSITION(_DBType) <> 0
398+ AS_ENABLED = AS_POSITION(_DBType) <> 0
399+ LASTSEEN_ENABLED = LASTSEEN_POSITION(_DBType) <> 0
400+ THREAT_ENABLED = THREAT_POSITION(_DBType) <> 0
401+ PROVIDER_ENABLED = PROVIDER_POSITION(_DBType) <> 0
402+
403+ Dim readLen = _IndexArrayIPv4.GetLength( 0 )
404+ If _IndexBaseAddrIPv6 > 0 Then
405+ readLen += _IndexArrayIPv6.GetLength( 0 )
406+ End If
407407
408- If _IndexBaseAddrIPv6 > 0 Then
409- ' read IPv6 index
410- For x As Integer = _IndexArrayIPv6.GetLowerBound( 0 ) To _IndexArrayIPv6.GetUpperBound( 0 )
411- _IndexArrayIPv6(x, 0 ) = _IndexAccessor.ReadInt32(Pointer) '4 bytes for from row
412- _IndexArrayIPv6(x, 1 ) = _IndexAccessor.ReadInt32(Pointer + 4 ) '4 bytes for to row
413- Pointer += 8
408+ readLen *= 8 ' 4 bytes for both From/To
409+ Dim indexData(readLen - 1 ) As Byte
410+
411+ _Filestream.Seek(_IndexBaseAddr - 1 , SeekOrigin.Begin)
412+ _Filestream.Read(indexData, 0 , readLen)
413+
414+ Dim pointer As Integer = 0
415+
416+ ' read IPv4 index
417+ For x As Integer = _IndexArrayIPv4.GetLowerBound( 0 ) To _IndexArrayIPv4.GetUpperBound( 0 )
418+ _IndexArrayIPv4(x, 0 ) = Read32Header(indexData, pointer) '4 bytes for row
419+ _IndexArrayIPv4(x, 1 ) = Read32Header(indexData, pointer + 4 ) '4 bytes for to row
420+ pointer += 8
414421 Next
415- End If
416- End Using
417422
418- If _UseMemoryMappedFile Then
419- CreateAccessors()
420- Else
421- DestroyMemoryMappedFile()
423+ If _IndexBaseAddrIPv6 > 0 Then
424+ ' read IPv6 index
425+ For x As Integer = _IndexArrayIPv6.GetLowerBound( 0 ) To _IndexArrayIPv6.GetUpperBound( 0 )
426+ _IndexArrayIPv6(x, 0 ) = Read32Header(indexData, pointer) '4 bytes for row
427+ _IndexArrayIPv6(x, 1 ) = Read32Header(indexData, pointer + 4 ) '4 bytes for to row
428+ pointer += 8
429+ Next
430+ End If
431+ End Using
432+
433+ If _UseMemoryMappedFile Then
434+ CreateMemoryMappedFile()
435+ CreateAccessors()
436+ End If
437+ LoadOK = True
422438 End If
423- LoadOK = True
424439 End If
425- End If
426-
440+ End SyncLock
427441 Return LoadOK
428442 End Function
429443
@@ -477,6 +491,9 @@ Public Class Component
477491 Dim RowOffset2 As Long = 0
478492 Dim ColumnSize As Integer = 0
479493 Dim OverCapacity As Boolean = False
494+ Dim FullRow As Byte () = Nothing
495+ Dim Row As Byte ()
496+ Dim FirstCol As Integer = 4 ' IP From is 4 bytes
480497
481498 Try
482499 If IPAddress = "" OrElse IPAddress Is Nothing Then
@@ -572,6 +589,7 @@ Public Class Component
572589 High = _IndexArrayIPv4(IndexAddr, 1 )
573590 Case 6
574591 ' IPv6
592+ FirstCol = 16 ' IPv6 is 16 bytes
575593 If _DBCountIPv6 = 0 Then
576594 With Result
577595 .Is_Proxy = - 1
@@ -619,12 +637,17 @@ Public Class Component
619637 RowOffset2 = RowOffset + ColumnSize
620638
621639 If _UseMemoryMappedFile Then
640+ ' only reading the IP From fields
622641 OverCapacity = (RowOffset2 >= Accessor.Capacity)
642+ IPFrom = Read32Or128(RowOffset, IPType, Accessor, FS)
643+ IPTo = If (OverCapacity, BigInteger.Zero, Read32Or128(RowOffset2, IPType, Accessor, FS))
644+ Else
645+ ' reading IP From + whole row + next IP From
646+ FullRow = ReadRow(RowOffset, ColumnSize + FirstCol, Accessor, FS)
647+ IPFrom = Read32Or128Row(FullRow, 0 , FirstCol)
648+ IPTo = If (OverCapacity, BigInteger.Zero, Read32Or128Row(FullRow, ColumnSize, FirstCol))
623649 End If
624650
625- IPFrom = Read32Or128(RowOffset, IPType, Accessor, FS)
626- IPTo = If (OverCapacity, BigInteger.Zero, Read32Or128(RowOffset2, IPType, Accessor, FS))
627-
628651 If IPNum >= IPFrom AndAlso IPNum < IPTo Then
629652 Dim Is_Proxy As Integer = - 1
630653 Dim Proxy_Type As String = MSG_NOT_SUPPORTED
@@ -641,13 +664,14 @@ Public Class Component
641664 Dim Threat As String = MSG_NOT_SUPPORTED
642665 Dim Provider As String = MSG_NOT_SUPPORTED
643666
644- Dim FirstCol As Integer = 4 ' for IPv4, IP From is 4 bytes
645- If IPType = 6 Then ' IPv6
646- FirstCol = 16 ' 16 bytes for IPv6
647- End If
667+ Dim RowLen = ColumnSize - FirstCol
648668
649- ' read the row here after the IP From column (remaining columns are all 4 bytes)
650- Dim Row() As Byte = ReadRow(RowOffset + FirstCol, ColumnSize - FirstCol, Accessor, FS)
669+ If _UseMemoryMappedFile Then
670+ Row = ReadRow(RowOffset + FirstCol, RowLen, Accessor, FS)
671+ Else
672+ ReDim Row(RowLen - 1 )
673+ Array.Copy(FullRow, FirstCol, Row, 0 , RowLen) ' extract the actual row data
674+ End If
651675
652676 If PROXYTYPE_ENABLED Then
653677 If Mode = Modes.ALL OrElse Mode = Modes.PROXY_TYPE OrElse Mode = Modes.IS_PROXY Then
@@ -791,6 +815,12 @@ Public Class Component
791815 Return row
792816 End Function
793817
818+ Private Function Read32Or128Row( ByRef Row() As Byte , ByVal ByteOffset As Integer , ByVal Len As Integer ) As BigInteger
819+ Dim _Byte(Len - 1 ) As Byte
820+ Array.Copy(Row, ByteOffset, _Byte, 0 , Len)
821+ Return New BigInteger(_Byte)
822+ End Function
823+
794824 Private Function Read32Or128( ByVal _Pos As Long , ByVal _MyIPType As Integer , ByRef MyAccessor As MemoryMappedViewAccessor, ByRef MyFilestream As FileStream) As BigInteger
795825 If _MyIPType = 4 Then
796826 Return Read32(_Pos, MyAccessor, MyFilestream)
@@ -821,6 +851,20 @@ Public Class Component
821851 Return BigRetVal
822852 End Function
823853
854+ ' Read 8 bits in header
855+ Private Function Read8Header( ByRef Row() As Byte , ByVal ByteOffset As Integer ) As Integer
856+ Dim _Byte( 0 ) As Byte ' 1 byte
857+ Array.Copy(Row, ByteOffset, _Byte, 0 , 1 )
858+ Return _Byte( 0 )
859+ End Function
860+
861+ ' Read 32 bits in header
862+ Private Function Read32Header( ByRef Row() As Byte , ByVal ByteOffset As Integer ) As Integer
863+ Dim _Byte( 3 ) As Byte ' 4 bytes
864+ Array.Copy(Row, ByteOffset, _Byte, 0 , 4 )
865+ Return BitConverter.ToUInt32(_Byte, 0 )
866+ End Function
867+
824868 ' Read 32 bits in byte array
825869 Private Function Read32Row( ByRef Row() As Byte , ByVal ByteOffset As Integer ) As BigInteger
826870 Dim _Byte( 3 ) As Byte ' 4 bytes
@@ -843,22 +887,27 @@ Public Class Component
843887
844888 ' Read strings in the database
845889 Private Function ReadStr( ByVal _Pos As Long , ByRef Myfilestream As FileStream) As String
890+ Dim _Size = 256 ' max size of string field + 1 byte for the length
891+ Dim _Data(_Size - 1 ) As Byte
892+
846893 If _UseMemoryMappedFile Then
847- Dim _Byte1 As Byte
894+ Dim _Len As Byte
848895 Dim _Bytes() As Byte
849- _Pos -= _MapDataOffset
850- _Byte1 = _MapDataAccessor.ReadByte(_Pos)
851- ReDim _Bytes(_Byte1 - 1 )
852- _MapDataAccessor.ReadArray(_Pos + 1 , _Bytes, 0 , _Byte1)
896+ _Pos -= _MapDataOffset ' position stored in BIN file is for full file, not just the mapped data segment, so need to minus
897+ _MapDataAccessor.ReadArray( Of Byte )(_Pos, _Data, 0 , _Size)
898+ _Len = _Data( 0 )
899+ ReDim _Bytes(_Len - 1 )
900+ Array.Copy(_Data, 1 , _Bytes, 0 , _Len)
853901 Return Encoding.Default.GetString(_Bytes)
854902 Else
855- Dim _Bytes( 0 ) As Byte
856- Dim _Bytes2 () As Byte
903+ Dim _Len As Byte
904+ Dim _Bytes () As Byte
857905 Myfilestream.Seek(_Pos, SeekOrigin.Begin)
858- Myfilestream.Read(_Bytes, 0 , 1 )
859- ReDim _Bytes2(_Bytes( 0 ) - 1 )
860- Myfilestream.Read(_Bytes2, 0 , _Bytes( 0 ))
861- Return Encoding.Default.GetString(_Bytes2)
906+ Myfilestream.Read(_Data, 0 , _Size)
907+ _Len = _Data( 0 )
908+ ReDim _Bytes(_Len - 1 )
909+ Array.Copy(_Data, 1 , _Bytes, 0 , _Len)
910+ Return Encoding.Default.GetString(_Bytes)
862911 End If
863912 End Function
864913
0 commit comments