Skip to content

Commit de71efb

Browse files
committed
Added provider field and exception handling for incorrect BIN database.
1 parent 4a8ef44 commit de71efb

File tree

3 files changed

+63
-68
lines changed

3 files changed

+63
-68
lines changed

LICENSE.TXT

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2020 IP2Location.com
3+
Copyright (c) 2021 IP2Location.com
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ Below are the methods supported in this package.
4242
|GetAs|Return the autonomous system name of the proxy.|
4343
|GetLastSeen|Return the number of days that the proxy was last seen.|
4444
|GetThreat|Return the threat type of the proxy.|
45+
|GetProvider|Return the provider of the proxy.|
4546

4647
## Usage
4748

@@ -54,7 +55,7 @@ import (
5455
)
5556

5657
func main() {
57-
db, err := ip2proxy.OpenDB("./IP2PROXY-IP-PROXYTYPE-COUNTRY-REGION-CITY-ISP-DOMAIN-USAGETYPE-ASN-LASTSEEN-THREAT-RESIDENTIAL.BIN")
58+
db, err := ip2proxy.OpenDB("./IP2PROXY-IP-PROXYTYPE-COUNTRY-REGION-CITY-ISP-DOMAIN-USAGETYPE-ASN-LASTSEEN-THREAT-RESIDENTIAL-PROVIDER.BIN")
5859

5960
if err != nil {
6061
return
@@ -84,6 +85,7 @@ func main() {
8485
fmt.Printf("AS: %s\n", all["AS"])
8586
fmt.Printf("LastSeen: %s\n", all["LastSeen"])
8687
fmt.Printf("Threat: %s\n", all["Threat"])
88+
fmt.Printf("Provider: %s\n", all["Provider"])
8789

8890
db.Close()
8991
}

ip2proxy.go

Lines changed: 59 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ package ip2proxy
77
import (
88
"bytes"
99
"encoding/binary"
10+
"errors"
1011
"fmt"
1112
"io"
12-
"math"
1313
"math/big"
1414
"net"
1515
"os"
@@ -35,6 +35,9 @@ type ip2proxymeta struct {
3535
ipv6indexbaseaddr uint32
3636
ipv4columnsize uint32
3737
ipv6columnsize uint32
38+
productcode uint8
39+
producttype uint8
40+
filesize uint32
3841
}
3942

4043
// The IP2Proxyrecord struct stores all of the available
@@ -52,6 +55,7 @@ type IP2Proxyrecord struct {
5255
As string
5356
Last_seen string
5457
Threat string
58+
Provider string
5559
Is_proxy int8
5660
}
5761

@@ -70,6 +74,7 @@ type DB struct {
7074
as_position_offset uint32
7175
lastseen_position_offset uint32
7276
threat_position_offset uint32
77+
provider_position_offset uint32
7378

7479
country_enabled bool
7580
region_enabled bool
@@ -82,25 +87,27 @@ type DB struct {
8287
as_enabled bool
8388
lastseen_enabled bool
8489
threat_enabled bool
90+
provider_enabled bool
8591

8692
metaok bool
8793
}
8894

8995
var defaultDB = &DB{}
9096

91-
var country_position = [11]uint8{0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3}
92-
var region_position = [11]uint8{0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4}
93-
var city_position = [11]uint8{0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5}
94-
var isp_position = [11]uint8{0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6}
95-
var proxytype_position = [11]uint8{0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2}
96-
var domain_position = [11]uint8{0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7}
97-
var usagetype_position = [11]uint8{0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8}
98-
var asn_position = [11]uint8{0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9}
99-
var as_position = [11]uint8{0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10}
100-
var lastseen_position = [11]uint8{0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11}
101-
var threat_position = [11]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12}
102-
103-
const module_version string = "3.1.0"
97+
var country_position = [12]uint8{0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}
98+
var region_position = [12]uint8{0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4}
99+
var city_position = [12]uint8{0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5}
100+
var isp_position = [12]uint8{0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6}
101+
var proxytype_position = [12]uint8{0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}
102+
var domain_position = [12]uint8{0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7}
103+
var usagetype_position = [12]uint8{0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8}
104+
var asn_position = [12]uint8{0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9}
105+
var as_position = [12]uint8{0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10}
106+
var lastseen_position = [12]uint8{0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11}
107+
var threat_position = [12]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12}
108+
var provider_position = [12]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13}
109+
110+
const module_version string = "3.2.0"
104111

105112
var max_ipv4_range = big.NewInt(4294967295)
106113
var max_ipv6_range = big.NewInt(0)
@@ -125,13 +132,15 @@ const asn uint32 = 0x00200
125132
const as uint32 = 0x00400
126133
const lastseen uint32 = 0x00800
127134
const threat uint32 = 0x01000
135+
const provider uint32 = 0x02000
128136

129-
const all uint32 = countryshort | countrylong | region | city | isp | proxytype | isproxy | domain | usagetype | asn | as | lastseen | threat
137+
const all uint32 = countryshort | countrylong | region | city | isp | proxytype | isproxy | domain | usagetype | asn | as | lastseen | threat | provider
130138

131139
const msg_not_supported string = "NOT SUPPORTED"
132140
const msg_invalid_ip string = "INVALID IP ADDRESS"
133141
const msg_missing_file string = "MISSING FILE"
134142
const msg_ipv6_unsupported string = "IPV6 ADDRESS MISSING IN IPV4 BIN"
143+
const msg_invalid_bin string = "Incorrect IP2Proxy BIN file format. Please make sure that you are using the latest IP2Proxy BIN file."
135144

136145
// get IP type and calculate IP number; calculates index too if exists
137146
func (d *DB) checkip(ip string) (iptype uint32, ipnum *big.Int, ipindex uint32) {
@@ -262,32 +271,6 @@ func (d *DB) readstr(pos uint32) (string, error) {
262271
return retval, nil
263272
}
264273

265-
// read float from slices
266-
func (d *DB) readfloat_row(row []byte, pos uint32) float32 {
267-
var retval float32
268-
data := row[pos : pos+4]
269-
bits := binary.LittleEndian.Uint32(data)
270-
retval = math.Float32frombits(bits)
271-
return retval
272-
}
273-
274-
// read float
275-
func (d *DB) readfloat(pos uint32) (float32, error) {
276-
pos2 := int64(pos)
277-
var retval float32
278-
data := make([]byte, 4)
279-
_, err := d.f.ReadAt(data, pos2-1)
280-
if err != nil {
281-
return 0, err
282-
}
283-
buf := bytes.NewReader(data)
284-
err = binary.Read(buf, binary.LittleEndian, &retval)
285-
if err != nil {
286-
fmt.Printf("binary read failed: %v", err)
287-
}
288-
return retval, nil
289-
}
290-
291274
func fatal(db *DB, err error) (*DB, error) {
292275
_ = db.f.Close()
293276
return nil, err
@@ -362,6 +345,22 @@ func OpenDBWithReader(reader DBReader) (*DB, error) {
362345
if err != nil {
363346
return fatal(db, err)
364347
}
348+
db.meta.productcode, err = db.readuint8(30)
349+
if err != nil {
350+
return fatal(db, err)
351+
}
352+
db.meta.producttype, err = db.readuint8(31)
353+
if err != nil {
354+
return fatal(db, err)
355+
}
356+
db.meta.filesize, err = db.readuint32(32)
357+
if err != nil {
358+
return fatal(db, err)
359+
}
360+
// check if is correct BIN (should be 2 for IP2Proxy BIN file), also checking for zipped file (PK being the first 2 chars)
361+
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
362+
return fatal(db, errors.New(msg_invalid_bin))
363+
}
365364
db.meta.ipv4columnsize = uint32(db.meta.databasecolumn << 2) // 4 bytes each column
366365
db.meta.ipv6columnsize = uint32(16 + ((db.meta.databasecolumn - 1) << 2)) // 4 bytes each column, except IPFrom column which is 16 bytes
367366

@@ -411,6 +410,10 @@ func OpenDBWithReader(reader DBReader) (*DB, error) {
411410
db.threat_position_offset = uint32(threat_position[dbt]-2) << 2
412411
db.threat_enabled = true
413412
}
413+
if provider_position[dbt] != 0 {
414+
db.provider_position_offset = uint32(provider_position[dbt]-2) << 2
415+
db.provider_enabled = true
416+
}
414417

415418
db.metaok = true
416419

@@ -523,6 +526,7 @@ func loadmessage(mesg string) IP2Proxyrecord {
523526
x.As = mesg
524527
x.Last_seen = mesg
525528
x.Threat = mesg
529+
x.Provider = mesg
526530
x.Is_proxy = -1
527531

528532
return x
@@ -674,6 +678,7 @@ func (d *DB) GetAll(ipaddress string) (map[string]string, error) {
674678
x["AS"] = data.As
675679
x["LastSeen"] = data.Last_seen
676680
x["Threat"] = data.Threat
681+
x["Provider"] = data.Provider
677682

678683
return x, err
679684
}
@@ -750,6 +755,12 @@ func (d *DB) GetThreat(ipaddress string) (string, error) {
750755
return data.Threat, err
751756
}
752757

758+
// GetProvider will return the provider of the proxy.
759+
func (d *DB) GetProvider(ipaddress string) (string, error) {
760+
data, err := d.query(ipaddress, provider)
761+
return data.Provider, err
762+
}
763+
753764
// IsProxy checks whether the queried IP address was a proxy. Returned value: -1 (errors), 0 (not a proxy), 1 (a proxy), 2 (a data center IP address or search engine robot).
754765
func (d *DB) IsProxy(ipaddress string) (int8, error) {
755766
data, err := d.query(ipaddress, isproxy)
@@ -852,7 +863,6 @@ func (d *DB) query(ipaddress string, mode uint32) (IP2Proxyrecord, error) {
852863
var firstcol uint32 = 4 // 4 bytes for ip from
853864
if iptype == 6 {
854865
firstcol = 16 // 16 bytes for ipv6
855-
// rowoffset = rowoffset + 12 // coz below is assuming all columns are 4 bytes, so got 12 left to go to make 16 bytes total
856866
}
857867

858868
row := make([]byte, colsize-firstcol) // exclude the ip from field
@@ -863,8 +873,6 @@ func (d *DB) query(ipaddress string, mode uint32) (IP2Proxyrecord, error) {
863873

864874
if d.proxytype_enabled {
865875
if mode&proxytype != 0 || mode&isproxy != 0 {
866-
// x.Proxy_type = readstr(readuint32(rowoffset + proxytype_position_offset))
867-
// x.Proxy_type = readstr(readuint32_row(row, proxytype_position_offset))
868876
if x.Proxy_type, err = d.readstr(d.readuint32_row(row, d.proxytype_position_offset)); err != nil {
869877
return x, err
870878
}
@@ -873,96 +881,80 @@ func (d *DB) query(ipaddress string, mode uint32) (IP2Proxyrecord, error) {
873881

874882
if d.country_enabled {
875883
if mode&countryshort != 0 || mode&countrylong != 0 || mode&isproxy != 0 {
876-
// countrypos = readuint32(rowoffset + country_position_offset)
877-
// countrypos = readuint32_row(row, country_position_offset)
878884
countrypos = d.readuint32_row(row, d.country_position_offset)
879885
}
880886
if mode&countryshort != 0 || mode&isproxy != 0 {
881-
// x.Country_short = readstr(countrypos)
882887
if x.Country_short, err = d.readstr(countrypos); err != nil {
883888
return x, err
884889
}
885890
}
886891
if mode&countrylong != 0 {
887-
// x.Country_long = readstr(countrypos + 3)
888892
if x.Country_long, err = d.readstr(countrypos + 3); err != nil {
889893
return x, err
890894
}
891895
}
892896
}
893897

894898
if mode&region != 0 && d.region_enabled {
895-
// x.Region = readstr(readuint32(rowoffset + region_position_offset))
896-
// x.Region = readstr(readuint32_row(row, region_position_offset))
897899
if x.Region, err = d.readstr(d.readuint32_row(row, d.region_position_offset)); err != nil {
898900
return x, err
899901
}
900902
}
901903

902904
if mode&city != 0 && d.city_enabled {
903-
// x.City = readstr(readuint32(rowoffset + city_position_offset))
904-
// x.City = readstr(readuint32_row(row, city_position_offset))
905905
if x.City, err = d.readstr(d.readuint32_row(row, d.city_position_offset)); err != nil {
906906
return x, err
907907
}
908908
}
909909

910910
if mode&isp != 0 && d.isp_enabled {
911-
// x.Isp = readstr(readuint32(rowoffset + isp_position_offset))
912-
// x.Isp = readstr(readuint32_row(row, isp_position_offset))
913911
if x.Isp, err = d.readstr(d.readuint32_row(row, d.isp_position_offset)); err != nil {
914912
return x, err
915913
}
916914
}
917915

918916
if mode&domain != 0 && d.domain_enabled {
919-
// x.Domain = readstr(readuint32(rowoffset + domain_position_offset))
920-
// x.Domain = readstr(readuint32_row(row, domain_position_offset))
921917
if x.Domain, err = d.readstr(d.readuint32_row(row, d.domain_position_offset)); err != nil {
922918
return x, err
923919
}
924920
}
925921

926922
if mode&usagetype != 0 && d.usagetype_enabled {
927-
// x.Usage_type = readstr(readuint32(rowoffset + usagetype_position_offset))
928-
// x.Usage_type = readstr(readuint32_row(row, usagetype_position_offset))
929923
if x.Usage_type, err = d.readstr(d.readuint32_row(row, d.usagetype_position_offset)); err != nil {
930924
return x, err
931925
}
932926
}
933927

934928
if mode&asn != 0 && d.asn_enabled {
935-
// x.Asn = readstr(readuint32(rowoffset + asn_position_offset))
936-
// x.Asn = readstr(readuint32_row(row, asn_position_offset))
937929
if x.Asn, err = d.readstr(d.readuint32_row(row, d.asn_position_offset)); err != nil {
938930
return x, err
939931
}
940932
}
941933

942934
if mode&as != 0 && d.as_enabled {
943-
// x.As = readstr(readuint32(rowoffset + as_position_offset))
944-
// x.As = readstr(readuint32_row(row, as_position_offset))
945935
if x.As, err = d.readstr(d.readuint32_row(row, d.as_position_offset)); err != nil {
946936
return x, err
947937
}
948938
}
949939

950940
if mode&lastseen != 0 && d.lastseen_enabled {
951-
// x.Last_seen = readstr(readuint32(rowoffset + lastseen_position_offset))
952-
// x.Last_seen = readstr(readuint32_row(row, lastseen_position_offset))
953941
if x.Last_seen, err = d.readstr(d.readuint32_row(row, d.lastseen_position_offset)); err != nil {
954942
return x, err
955943
}
956944
}
957945

958946
if mode&threat != 0 && d.threat_enabled {
959-
// x.Threat = readstr(readuint32(rowoffset + threat_position_offset))
960-
// x.Threat = readstr(readuint32_row(row, threat_position_offset))
961947
if x.Threat, err = d.readstr(d.readuint32_row(row, d.threat_position_offset)); err != nil {
962948
return x, err
963949
}
964950
}
965951

952+
if mode&provider != 0 && d.provider_enabled {
953+
if x.Provider, err = d.readstr(d.readuint32_row(row, d.provider_position_offset)); err != nil {
954+
return x, err
955+
}
956+
}
957+
966958
if x.Country_short == "-" || x.Proxy_type == "-" {
967959
x.Is_proxy = 0
968960
} else {
@@ -1004,5 +996,6 @@ func Printrecord(x IP2Proxyrecord) {
1004996
fmt.Printf("as: %s\n", x.As)
1005997
fmt.Printf("last_seen: %s\n", x.Last_seen)
1006998
fmt.Printf("threat: %s\n", x.Threat)
999+
fmt.Printf("provider: %s\n", x.Provider)
10071000
fmt.Printf("is_proxy: %d\n", x.Is_proxy)
10081001
}

0 commit comments

Comments
 (0)