@@ -10,10 +10,12 @@ import (
1010 "errors"
1111 "fmt"
1212 "io"
13+ "lukechampine.com/uint128"
1314 "math/big"
1415 "net"
1516 "os"
1617 "strconv"
18+ "unsafe"
1719)
1820
1921// Implement db reader interface
@@ -43,9 +45,9 @@ type ip2proxyMeta struct {
4345 fileSize uint32
4446}
4547
46- // The ip2proxyRecord struct stores all of the available
48+ // The IP2ProxyRecord struct stores all of the available
4749// proxy info found in the IP2Proxy database.
48- type ip2proxyRecord struct {
50+ type IP2ProxyRecord struct {
4951 countryShort string
5052 countryLong string
5153 region string
@@ -113,15 +115,15 @@ var providerPosition = [12]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13}
113115
114116const moduleVersion string = "3.4.1"
115117
116- var maxIPV4Range = big . NewInt (4294967295 )
117- var maxIPV6Range = big . NewInt (0 )
118- var fromV4Mapped = big . NewInt (281470681743360 )
119- var toV4Mapped = big . NewInt (281474976710655 )
120- var from6To4 = big . NewInt (0 )
121- var to6To4 = big . NewInt (0 )
122- var fromTeredo = big . NewInt (0 )
123- var toTeredo = big . NewInt (0 )
124- var last32Bits = big . NewInt (4294967295 )
118+ var maxIPV4Range = uint128 . From64 (4294967295 )
119+ var maxIPV6Range = uint128 . From64 (0 )
120+ var fromV4Mapped = uint128 . From64 (281470681743360 )
121+ var toV4Mapped = uint128 . From64 (281474976710655 )
122+ var from6To4 = uint128 . From64 (0 )
123+ var to6To4 = uint128 . From64 (0 )
124+ var fromTeredo = uint128 . From64 (0 )
125+ var toTeredo = uint128 . From64 (0 )
126+ var last32Bits = uint128 . From64 (4294967295 )
125127
126128const countryShort uint32 = 0x00001
127129const countryLong uint32 = 0x00002
@@ -147,10 +149,10 @@ const msgIPV6Unsupported string = "IPV6 ADDRESS MISSING IN IPV4 BIN"
147149const msgInvalidBin string = "Incorrect IP2Proxy BIN file format. Please make sure that you are using the latest IP2Proxy BIN file."
148150
149151// get IP type and calculate IP number; calculates index too if exists
150- func (d * DB ) checkIP (ip string ) (ipType uint32 , ipNum * big. Int , ipIndex uint32 ) {
152+ func (d * DB ) checkIP (ip string ) (ipType uint32 , ipNum uint128. Uint128 , ipIndex uint32 ) {
151153 ipType = 0
152- ipNum = big . NewInt (0 )
153- ipNumTmp := big . NewInt (0 )
154+ ipNum = uint128 . From64 (0 )
155+ ipNumTmp := uint128 . From64 (0 )
154156 ipIndex = 0
155157 ipAddress := net .ParseIP (ip )
156158
@@ -159,43 +161,43 @@ func (d *DB) checkIP(ip string) (ipType uint32, ipNum *big.Int, ipIndex uint32)
159161
160162 if v4 != nil {
161163 ipType = 4
162- ipNum . SetBytes ( v4 )
164+ ipNum = uint128 . From64 ( uint64 ( binary . BigEndian . Uint32 ( v4 )) )
163165 } else {
164166 v6 := ipAddress .To16 ()
165167
166168 if v6 != nil {
167169 ipType = 6
168- ipNum .SetBytes (v6 )
170+ ipNum .PutBytes (v6 )
169171
170172 if ipNum .Cmp (fromV4Mapped ) >= 0 && ipNum .Cmp (toV4Mapped ) <= 0 {
171173 // ipv4-mapped ipv6 should treat as ipv4 and read ipv4 data section
172174 ipType = 4
173- ipNum .Sub (ipNum , fromV4Mapped )
175+ ipNum = ipNum .Sub (fromV4Mapped )
174176 } else if ipNum .Cmp (from6To4 ) >= 0 && ipNum .Cmp (to6To4 ) <= 0 {
175177 // 6to4 so need to remap to ipv4
176178 ipType = 4
177- ipNum .Rsh (ipNum , 80 )
178- ipNum .And (ipNum , last32Bits )
179+ ipNum = ipNum .Rsh (80 )
180+ ipNum = ipNum .And (last32Bits )
179181 } else if ipNum .Cmp (fromTeredo ) >= 0 && ipNum .Cmp (toTeredo ) <= 0 {
180182 // Teredo so need to remap to ipv4
181183 ipType = 4
182- ipNum . Not ( ipNum )
183- ipNum .And (ipNum , last32Bits )
184+ ipNum = uint128. Uint128 { ^ ipNum . Lo , ^ ipNum . Hi }
185+ ipNum = ipNum .And (last32Bits )
184186 }
185187 }
186188 }
187189 }
188190 if ipType == 4 {
189191 if d .meta .ipV4Indexed {
190- ipNumTmp .Rsh (ipNum , 16 )
191- ipNumTmp .Lsh (ipNumTmp , 3 )
192- ipIndex = uint32 (ipNumTmp .Add (ipNumTmp , big . NewInt ( int64 (d .meta .ipV4IndexBaseAddr ))).Uint64 () )
192+ ipNumTmp = ipNum .Rsh (16 )
193+ ipNumTmp = ipNumTmp .Lsh (3 )
194+ ipIndex = uint32 (ipNumTmp .Add (uint128 . From64 ( uint64 (d .meta .ipV4IndexBaseAddr ))).Lo )
193195 }
194196 } else if ipType == 6 {
195197 if d .meta .ipV6Indexed {
196- ipNumTmp .Rsh (ipNum , 112 )
197- ipNumTmp .Lsh (ipNumTmp , 3 )
198- ipIndex = uint32 (ipNumTmp .Add (ipNumTmp , big . NewInt ( int64 (d .meta .ipV6IndexBaseAddr ))).Uint64 () )
198+ ipNumTmp = ipNum .Rsh (112 )
199+ ipNumTmp = ipNumTmp .Lsh (3 )
200+ ipIndex = uint32 (ipNumTmp .Add (uint128 . From64 ( uint64 (d .meta .ipV6IndexBaseAddr ))).Lo )
199201 }
200202 }
201203 return
@@ -250,33 +252,33 @@ func (d *DB) readUint32(pos uint32) (uint32, error) {
250252}
251253
252254// read unsigned 128-bit integer from slices
253- func (d * DB ) readUint128Row (row []byte , pos uint32 ) * big. Int {
254- retVal := big . NewInt (0 )
255+ func (d * DB ) readUint128Row (row []byte , pos uint32 ) uint128. Uint128 {
256+ retVal := uint128 . From64 (0 )
255257 data := row [pos : pos + 16 ]
256258
257259 // little endian to big endian
258260 for i , j := 0 , len (data )- 1 ; i < j ; i , j = i + 1 , j - 1 {
259261 data [i ], data [j ] = data [j ], data [i ]
260262 }
261- retVal .SetBytes (data )
263+ retVal .PutBytes (data )
262264 return retVal
263265}
264266
265267// read unsigned 128-bit integer
266- func (d * DB ) readUint128 (pos uint32 ) (* big. Int , error ) {
268+ func (d * DB ) readUint128 (pos uint32 ) (uint128. Uint128 , error ) {
267269 pos2 := int64 (pos )
268- retVal := big . NewInt (0 )
270+ retVal := uint128 . From64 (0 )
269271 data := make ([]byte , 16 )
270272 _ , err := d .f .ReadAt (data , pos2 - 1 )
271273 if err != nil {
272- return nil , err
274+ return uint128 . From64 ( 0 ) , err
273275 }
274276
275277 // little endian to big endian
276278 for i , j := 0 , len (data )- 1 ; i < j ; i , j = i + 1 , j - 1 {
277279 data [i ], data [j ] = data [j ], data [i ]
278280 }
279- retVal .SetBytes (data )
281+ retVal .PutBytes (data )
280282 return retVal , nil
281283}
282284
@@ -291,7 +293,7 @@ func (d *DB) readStr(pos uint32) (string, error) {
291293 return "" , err
292294 }
293295 strLen := data [0 ]
294- retVal = string (data [1 :(strLen + 1 )])
296+ retVal = convertBytesToString (data [1 :(strLen + 1 )])
295297 return retVal , nil
296298}
297299
@@ -316,11 +318,25 @@ func OpenDB(dbPath string) (*DB, error) {
316318func OpenDBWithReader (reader dbReader ) (* DB , error ) {
317319 var db = & DB {}
318320
319- maxIPV6Range .SetString ("340282366920938463463374607431768211455" , 10 )
320- from6To4 .SetString ("42545680458834377588178886921629466624" , 10 )
321- to6To4 .SetString ("42550872755692912415807417417958686719" , 10 )
322- fromTeredo .SetString ("42540488161975842760550356425300246528" , 10 )
323- toTeredo .SetString ("42540488241204005274814694018844196863" , 10 )
321+ _maxIPV6Range := big .NewInt (0 )
322+ _maxIPV6Range .SetString ("340282366920938463463374607431768211455" , 10 )
323+ maxIPV6Range = uint128 .FromBig (_maxIPV6Range )
324+
325+ _from6To4 := big .NewInt (0 )
326+ _from6To4 .SetString ("42545680458834377588178886921629466624" , 10 )
327+ from6To4 = uint128 .FromBig (_from6To4 )
328+
329+ _to6To4 := big .NewInt (0 )
330+ _to6To4 .SetString ("42550872755692912415807417417958686719" , 10 )
331+ to6To4 = uint128 .FromBig (_to6To4 )
332+
333+ _fromTeredo := big .NewInt (0 )
334+ _fromTeredo .SetString ("42540488161975842760550356425300246528" , 10 )
335+ fromTeredo = uint128 .FromBig (_fromTeredo )
336+
337+ _toTeredo := big .NewInt (0 )
338+ _toTeredo .SetString ("42540488241204005274814694018844196863" , 10 )
339+ toTeredo = uint128 .FromBig (_toTeredo )
324340
325341 db .f = reader
326342
@@ -509,8 +525,8 @@ func (d *DB) DatabaseVersion() string {
509525}
510526
511527// populate record with message
512- func loadMessage (mesg string ) ip2proxyRecord {
513- var x ip2proxyRecord
528+ func loadMessage (mesg string ) IP2ProxyRecord {
529+ var x IP2ProxyRecord
514530
515531 x .countryShort = mesg
516532 x .countryLong = mesg
@@ -530,13 +546,20 @@ func loadMessage(mesg string) ip2proxyRecord {
530546 return x
531547}
532548
533- func handleError (rec ip2proxyRecord , err error ) ip2proxyRecord {
549+ func handleError (rec IP2ProxyRecord , err error ) IP2ProxyRecord {
534550 if err != nil {
535551 fmt .Print (err )
536552 }
537553 return rec
538554}
539555
556+ // convertBytesToString provides a no-copy []byte to string conversion.
557+ // This implementation is adopted by official strings.Builder.
558+ // Reference: https://github.com/golang/go/issues/25484
559+ func convertBytesToString (b []byte ) string {
560+ return * (* string )(unsafe .Pointer (& b ))
561+ }
562+
540563// GetAll will return all proxy fields based on the queried IP address.
541564//
542565// Deprecated: No longer being updated.
@@ -658,27 +681,8 @@ func IsProxy(ipAddress string) int8 {
658681}
659682
660683// GetAll will return all proxy fields based on the queried IP address.
661- func (d * DB ) GetAll (ipAddress string ) (map [string ]string , error ) {
662- data , err := d .query (ipAddress , all )
663-
664- var x = make (map [string ]string )
665- s := strconv .Itoa (int (data .isProxy ))
666- x ["isProxy" ] = s
667- x ["ProxyType" ] = data .proxyType
668- x ["CountryShort" ] = data .countryShort
669- x ["CountryLong" ] = data .countryLong
670- x ["Region" ] = data .region
671- x ["City" ] = data .city
672- x ["ISP" ] = data .isp
673- x ["Domain" ] = data .domain
674- x ["UsageType" ] = data .usageType
675- x ["ASN" ] = data .asn
676- x ["AS" ] = data .as
677- x ["LastSeen" ] = data .lastSeen
678- x ["Threat" ] = data .threat
679- x ["Provider" ] = data .provider
680-
681- return x , err
684+ func (d * DB ) GetAll (ipAddress string ) (IP2ProxyRecord , error ) {
685+ return d .query (ipAddress , all )
682686}
683687
684688// GetCountryShort will return the ISO-3166 country code based on the queried IP address.
@@ -766,7 +770,7 @@ func (d *DB) IsProxy(ipAddress string) (int8, error) {
766770}
767771
768772// main query
769- func (d * DB ) query (ipAddress string , mode uint32 ) (ip2proxyRecord , error ) {
773+ func (d * DB ) query (ipAddress string , mode uint32 ) (IP2ProxyRecord , error ) {
770774 x := loadMessage (msgNotSupported ) // default message
771775
772776 // read metadata
@@ -795,9 +799,9 @@ func (d *DB) query(ipAddress string, mode uint32) (ip2proxyRecord, error) {
795799 var row []byte
796800 var fullRow []byte
797801 var readLen uint32
798- ipFrom := big . NewInt (0 )
799- ipTo := big . NewInt (0 )
800- maxIP := big . NewInt (0 )
802+ ipFrom := uint128 . From64 (0 )
803+ ipTo := uint128 . From64 (0 )
804+ maxIP := uint128 . From64 (0 )
801805
802806 if ipType == 4 {
803807 baseAddr = d .meta .ipV4DatabaseAddr
@@ -827,7 +831,7 @@ func (d *DB) query(ipAddress string, mode uint32) (ip2proxyRecord, error) {
827831 }
828832
829833 if ipNo .Cmp (maxIP ) >= 0 {
830- ipNo .Sub (ipNo , big . NewInt (1 ))
834+ ipNo = ipNo .Sub (uint128 . From64 (1 ))
831835 }
832836
833837 for low <= high {
@@ -843,10 +847,10 @@ func (d *DB) query(ipAddress string, mode uint32) (ip2proxyRecord, error) {
843847
844848 if ipType == 4 {
845849 ipFrom32 := d .readUint32Row (fullRow , 0 )
846- ipFrom = big . NewInt ( int64 (ipFrom32 ))
850+ ipFrom = uint128 . From64 ( uint64 (ipFrom32 ))
847851
848852 ipTo32 := d .readUint32Row (fullRow , colSize )
849- ipTo = big . NewInt ( int64 (ipTo32 ))
853+ ipTo = uint128 . From64 ( uint64 (ipTo32 ))
850854 } else {
851855 ipFrom = d .readUint128Row (fullRow , 0 )
852856
0 commit comments