Skip to content

Commit 760997b

Browse files
Added support for threats (PX9) & residential proxies (PX10)
1 parent a980609 commit 760997b

5 files changed

Lines changed: 104 additions & 25 deletions

File tree

ChangeLog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Revision history for ip2proxy
22

3+
## 3.0.0 -- 2020-08-11
4+
5+
* Added support for PX9 to PX10 packages.
6+
37
## 2.2.1 -- 2020-04-22
48

59
* Modified version requirement for base module.

IP2Proxy.hs

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ This Haskell package allows users to query an IP address to determine if it was
1010
1111
IP2Proxy LITE BIN databases are available for free at http://lite.ip2location.com/
1212
-}
13-
module IP2Proxy (Meta, IP2ProxyRecord(..), getModuleVersion, getPackageVersion, getDatabaseVersion, open, getAll, getCountryShort, getCountryLong, getRegion, getCity, getISP, getProxyType, getDomain, getUsageType, getASN, getAS, getLastSeen, isProxy) where
13+
module IP2Proxy (Meta, IP2ProxyRecord(..), getModuleVersion, getPackageVersion, getDatabaseVersion, open, getAll, getCountryShort, getCountryLong, getRegion, getCity, getISP, getProxyType, getDomain, getUsageType, getASN, getAS, getLastSeen, getThreat, isProxy) where
1414

1515
import qualified Data.ByteString.Lazy as BS
1616
import qualified Data.ByteString.Lazy.Char8 as BS8
@@ -44,6 +44,8 @@ data IP2ProxyRecord = IP2ProxyRecord {
4444
as :: String,
4545
-- | Last seen
4646
last_seen :: String,
47+
-- | Threat
48+
threat :: String,
4749
-- | Is proxy
4850
is_proxy :: Int
4951
} deriving (Show)
@@ -99,7 +101,7 @@ getMeta = do
99101
The 'getModuleVersion' function returns a string containing the module version.
100102
-}
101103
getModuleVersion :: String
102-
getModuleVersion = "2.2.1"
104+
getModuleVersion = "3.0.0"
103105

104106
{-|
105107
The 'getPackageVersion' function returns a string containing the package version.
@@ -215,16 +217,17 @@ countif f = length . filter f
215217

216218
readrecord :: BS.ByteString -> Int -> Int -> Int -> IP2ProxyRecord
217219
readrecord contents dbtype rowoffset mode = do
218-
let country_position = [0, 2, 3, 3, 3, 3, 3, 3, 3]
219-
let region_position = [0, 0, 0, 4, 4, 4, 4, 4, 4]
220-
let city_position = [0, 0, 0, 5, 5, 5, 5, 5, 5]
221-
let isp_position = [0, 0, 0, 0, 6, 6, 6, 6, 6]
222-
let proxytype_position = [0, 0, 2, 2, 2, 2, 2, 2, 2]
223-
let domain_position = [0, 0, 0, 0, 0, 7, 7, 7, 7]
224-
let usagetype_position = [0, 0, 0, 0, 0, 0, 8, 8, 8]
225-
let asn_position = [0, 0, 0, 0, 0, 0, 0, 9, 9]
226-
let as_position = [0, 0, 0, 0, 0, 0, 0, 10, 10]
227-
let lastseen_position = [0, 0, 0, 0, 0, 0, 0, 0, 11]
220+
let country_position = [0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3]
221+
let region_position = [0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4]
222+
let city_position = [0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5]
223+
let isp_position = [0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6]
224+
let proxytype_position = [0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2]
225+
let domain_position = [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7]
226+
let usagetype_position = [0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8]
227+
let asn_position = [0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9]
228+
let as_position = [0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10]
229+
let lastseen_position = [0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11]
230+
let threat_position = [0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12]
228231

229232
let countryshort_field = 1
230233
let countrylong_field = 2
@@ -238,8 +241,9 @@ readrecord contents dbtype rowoffset mode = do
238241
let asn_field = 512
239242
let as_field = 1024
240243
let lastseen_field = 2048
244+
let threat_field = 4096
241245

242-
let allcols = (take 1 (drop dbtype country_position)) ++ (take 1 (drop dbtype region_position)) ++ (take 1 (drop dbtype city_position)) ++ (take 1 (drop dbtype isp_position)) ++ (take 1 (drop dbtype proxytype_position)) ++ (take 1 (drop dbtype domain_position)) ++ (take 1 (drop dbtype usagetype_position)) ++ (take 1 (drop dbtype asn_position)) ++ (take 1 (drop dbtype as_position)) ++ (take 1 (drop dbtype lastseen_position))
246+
let allcols = (take 1 (drop dbtype country_position)) ++ (take 1 (drop dbtype region_position)) ++ (take 1 (drop dbtype city_position)) ++ (take 1 (drop dbtype isp_position)) ++ (take 1 (drop dbtype proxytype_position)) ++ (take 1 (drop dbtype domain_position)) ++ (take 1 (drop dbtype usagetype_position)) ++ (take 1 (drop dbtype asn_position)) ++ (take 1 (drop dbtype as_position)) ++ (take 1 (drop dbtype lastseen_position)) ++ (take 1 (drop dbtype threat_position))
243247
let cols = (countif (>0) allcols) `shiftL` 2
244248
let row = BS.take (fromIntegral cols) (BS.drop (fromIntegral rowoffset - 1) contents)
245249

@@ -293,13 +297,18 @@ readrecord contents dbtype rowoffset mode = do
293297
then readcolstringrow contents row dbtype lastseen_position
294298
else ""
295299

300+
let threat = if ((.&.) mode threat_field) /= 0
301+
-- then readcolstring contents dbtype rowoffset threat_position
302+
then readcolstringrow contents row dbtype threat_position
303+
else ""
304+
296305
let is_proxy = if (country_short == "-") || (proxy_type == "-")
297306
then 0
298307
else if (proxy_type == "DCH") || (proxy_type == "SES")
299308
then 2
300309
else 1
301310

302-
IP2ProxyRecord country_short country_long region city isp proxy_type domain usage_type asn as last_seen is_proxy
311+
IP2ProxyRecord country_short country_long region city isp proxy_type domain usage_type asn as last_seen threat is_proxy
303312

304313
searchtree :: BS.ByteString -> Integer -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> IP2ProxyRecord
305314
searchtree contents ipnum dbtype low high baseaddr colsize iptype mode = do
@@ -333,7 +342,7 @@ searchtree contents ipnum dbtype low high baseaddr colsize iptype mode = do
333342
searchtree contents ipnum dbtype (mid + 1) high baseaddr colsize iptype mode
334343
else do
335344
let x = "INVALID IP ADDRESS"
336-
IP2ProxyRecord x x x x x x x x x x x (-1)
345+
IP2ProxyRecord x x x x x x x x x x x x (-1)
337346

338347
search4 :: BS.ByteString -> Integer -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> IP2ProxyRecord
339348
search4 contents ipnum dbtype low high baseaddr indexbaseaddr colsize mode = do
@@ -369,7 +378,7 @@ tryfirst myIP = do
369378
-}
370379
getAll :: String -> Meta -> String -> IO IP2ProxyRecord
371380
getAll myfile meta myip = do
372-
result <- doQuery myfile meta myip 4095
381+
result <- doQuery myfile meta myip 8191
373382
return result
374383

375384
{-|
@@ -471,6 +480,15 @@ getLastSeen myfile meta myip = do
471480
result <- doQuery myfile meta myip 2048
472481
return (show (last_seen result))
473482

483+
{-|
484+
The 'getThreat' function returns the threat type of the proxy.
485+
It takes 3 arguments; the BIN database file path (String), the metadata from 'open' function (Meta record) & either IPv4 or IPv6 address (String).
486+
-}
487+
getThreat :: String -> Meta -> String -> IO String
488+
getThreat myfile meta myip = do
489+
result <- doQuery myfile meta myip 4096
490+
return (show (threat result))
491+
474492
{-|
475493
The 'isProxy' function returns 0 if IP is not a proxy, 1 if is a proxy and not data center IP, 2 if is a proxy and is a data center IP, -1 if error.
476494
It takes 3 arguments; the BIN database file path (String), the metadata from 'open' function (Meta record) & either IPv4 or IPv6 address (String).
@@ -497,7 +515,7 @@ doQuery myfile meta myip mode = do
497515
if ipnum == -1
498516
then do
499517
let x = "INVALID IP ADDRESS"
500-
return $ IP2ProxyRecord x x x x x x x x x x x (-1)
518+
return $ IP2ProxyRecord x x x x x x x x x x x x (-1)
501519
else if ipnum >= fromV4Mapped && ipnum <= toV4Mapped
502520
then do
503521
return $ search4 contents (ipnum - (toInteger fromV4Mapped)) (databasetype meta) 0 (ipv4databasecount meta) (ipv4databaseaddr meta) (ipv4indexbaseaddr meta) (ipv4columnsize meta) mode

README.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# IP2Proxy Haskell Module
22

3-
This Haskell package allows user to query an IP address if it was being used as VPN anonymizer, open proxies, web proxies, Tor exits, data center, web hosting (DCH) range and search engine robots (SES). It lookup the proxy IP address from **IP2Proxy BIN Data** file. This data file can be downloaded at
3+
This Haskell package allows user to query an IP address if it was being used as VPN anonymizer, open proxies, web proxies, Tor exits, data center, web hosting (DCH) range, search engine robots (SES) and residential (RES). It lookup the proxy IP address from **IP2Proxy BIN Data** file. This data file can be downloaded at
44

55
* Free IP2Proxy BIN Data: https://lite.ip2location.com
66
* Commercial IP2Proxy BIN Data: https://www.ip2location.com/database/ip2proxy
@@ -18,22 +18,23 @@ Below are the methods supported in this package.
1818
|Method Name|Description|
1919
|---|---|
2020
|open|Open the IP2Proxy BIN data for lookup.|
21-
|getPackageVersion|Get the package version (1 to 8 for PX1 to PX8 respectively).|
21+
|getPackageVersion|Get the package version (1 to 10 for PX1 to PX10 respectively).|
2222
|getModuleVersion|Get the module version.|
2323
|getDatabaseVersion|Get the database version.|
2424
|isProxy|Check whether if an IP address was a proxy. Returned value:<ul><li>-1 : errors</li><li>0 : not a proxy</li><li>1 : a proxy</li><li>2 : a data center IP address or search engine robot</li></ul>|
2525
|getAll|Return the proxy information in a record.|
26-
|getProxyType|Return the proxy type. Please visit <a href="https://www.ip2location.com/database/px8-ip-proxytype-country-region-city-isp-domain-usagetype-asn-lastseen" target="_blank">IP2Location</a> for the list of proxy types supported.|
26+
|getProxyType|Return the proxy type. Please visit <a href="https://www.ip2location.com/database/px10-ip-proxytype-country-region-city-isp-domain-usagetype-asn-lastseen-threat-residential" target="_blank">IP2Location</a> for the list of proxy types supported.|
2727
|getCountryShort|Return the ISO3166-1 country code (2-digits) of the proxy.|
2828
|getCountryLong|Return the ISO3166-1 country name of the proxy.|
2929
|getRegion|Return the ISO3166-2 region name of the proxy. Please visit <a href="https://www.ip2location.com/free/iso3166-2" target="_blank">ISO3166-2 Subdivision Code</a> for the information of ISO3166-2 supported.|
3030
|getCity|Return the city name of the proxy.|
3131
|getISP|Return the ISP name of the proxy.|
3232
|getDomain|Return the domain name of the proxy.|
33-
|getUsageType|Return the usage type classification of the proxy. Please visit <a href="https://www.ip2location.com/database/px8-ip-proxytype-country-region-city-isp-domain-usagetype-asn-lastseen" target="_blank">IP2Location</a> for the list of usage types supported.|
33+
|getUsageType|Return the usage type classification of the proxy. Please visit <a href="https://www.ip2location.com/database/px10-ip-proxytype-country-region-city-isp-domain-usagetype-asn-lastseen-threat-residential" target="_blank">IP2Location</a> for the list of usage types supported.|
3434
|getASN|Return the autonomous system number of the proxy.|
3535
|getAS|Return the autonomous system name of the proxy.|
3636
|getLastSeen|Return the number of days that the proxy was last seen.|
37+
|getThreat|Return the threat type of the proxy.|
3738

3839
## Example
3940

@@ -42,7 +43,7 @@ import IP2Proxy
4243

4344
main :: IO ()
4445
main = do
45-
let myfile = "./IP2PROXY-IP-PROXYTYPE-COUNTRY-REGION-CITY-ISP-DOMAIN-USAGETYPE-ASN-LASTSEEN.BIN"
46+
let myfile = "./IP2PROXY-IP-PROXYTYPE-COUNTRY-REGION-CITY-ISP-DOMAIN-USAGETYPE-ASN-LASTSEEN-THREAT-RESIDENTIAL.BIN"
4647
let ip = "199.83.103.79"
4748
meta <- open myfile
4849

@@ -62,6 +63,7 @@ main = do
6263
putStrLn $ "asn: " ++ (show (asn result))
6364
putStrLn $ "as: " ++ (show (as result))
6465
putStrLn $ "last_seen: " ++ (show (last_seen result))
66+
putStrLn $ "threat: " ++ (show (threat result))
6567
putStrLn $ "is_proxy: " ++ (show (is_proxy result))
6668

6769
result <- getCountryShort myfile meta ip
@@ -86,6 +88,8 @@ main = do
8688
putStrLn $ "as: " ++ result
8789
result <- getLastSeen myfile meta ip
8890
putStrLn $ "last_seen: " ++ result
91+
result <- getThreat myfile meta ip
92+
putStrLn $ "threat: " ++ result
8993
result <- isProxy myfile meta ip
9094
putStrLn $ "is_proxy: " ++ result
9195
```

ip2proxy.cabal

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ name: ip2proxy
1010
-- PVP summary: +-+------- breaking API changes
1111
-- | | +----- non-breaking API additions
1212
-- | | | +--- code changes with no API change
13-
version: 2.2.1
13+
version: 3.0.0
1414

1515
-- A short (one-line) description of the package.
1616
synopsis: IP2Proxy Haskell package for proxy detection.
1717

1818
-- A longer description of the package.
19-
description: This Haskell package allows users to query an IP address to determine if it was being used as VPN anonymizer, open proxies, web proxies, Tor exits, data center, web hosting (DCH) range and search engine robots (SES).
19+
description: This Haskell package allows users to query an IP address to determine if it was being used as VPN anonymizer, open proxies, web proxies, Tor exits, data center, web hosting (DCH) range, search engine robots (SES) and residential (RES).
2020

2121
-- URL for the project homepage or repository.
2222
homepage: https://www.ip2location.com
@@ -60,7 +60,7 @@ library
6060
-- other-extensions:
6161

6262
-- Other library packages from which modules are imported.
63-
build-depends: base >=4.11 && <=4.14, bytestring >=0.10 && <0.11, binary >=0.8.4 && <0.9, iproute >=1.7 && <1.8
63+
build-depends: base >=4.7 && <=4.14, bytestring >=0.10 && <0.11, binary >=0.8.8 && <0.9, iproute >=1.7 && <1.8
6464

6565
-- Directories containing source files.
6666
-- hs-source-dirs:

test.hs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import IP2Proxy
2+
3+
main :: IO ()
4+
main = do
5+
let myfile = "./IP2PROXY-IP-PROXYTYPE-COUNTRY-REGION-CITY-ISP-DOMAIN-USAGETYPE-ASN-LASTSEEN-THREAT-RESIDENTIAL.BIN"
6+
let ip = "123.25.30.87"
7+
meta <- open myfile
8+
9+
putStrLn $ "module_version: " ++ getModuleVersion
10+
putStrLn $ "package_version: " ++ (getPackageVersion meta)
11+
putStrLn $ "database_version: " ++ (getDatabaseVersion meta)
12+
13+
result <- getAll myfile meta ip
14+
putStrLn $ "country_short: " ++ (show (country_short result))
15+
putStrLn $ "country_long: " ++ (show (country_long result))
16+
putStrLn $ "region: " ++ (show (region result))
17+
putStrLn $ "city: " ++ (show (city result))
18+
putStrLn $ "isp: " ++ (show (isp result))
19+
putStrLn $ "proxy_type: " ++ (show (proxy_type result))
20+
putStrLn $ "domain: " ++ (show (domain result))
21+
putStrLn $ "usage_type: " ++ (show (usage_type result))
22+
putStrLn $ "asn: " ++ (show (asn result))
23+
putStrLn $ "as: " ++ (show (as result))
24+
putStrLn $ "last_seen: " ++ (show (last_seen result))
25+
putStrLn $ "threat: " ++ (show (threat result))
26+
putStrLn $ "is_proxy: " ++ (show (is_proxy result))
27+
28+
result <- getCountryShort myfile meta ip
29+
putStrLn $ "country_short: " ++ result
30+
result <- getCountryLong myfile meta ip
31+
putStrLn $ "country_long: " ++ result
32+
result <- getRegion myfile meta ip
33+
putStrLn $ "region: " ++ result
34+
result <- getCity myfile meta ip
35+
putStrLn $ "city: " ++ result
36+
result <- getISP myfile meta ip
37+
putStrLn $ "isp: " ++ result
38+
result <- getProxyType myfile meta ip
39+
putStrLn $ "proxy_type: " ++ result
40+
result <- getDomain myfile meta ip
41+
putStrLn $ "domain: " ++ result
42+
result <- getUsageType myfile meta ip
43+
putStrLn $ "usage_type: " ++ result
44+
result <- getASN myfile meta ip
45+
putStrLn $ "asn: " ++ result
46+
result <- getAS myfile meta ip
47+
putStrLn $ "as: " ++ result
48+
result <- getLastSeen myfile meta ip
49+
putStrLn $ "last_seen: " ++ result
50+
result <- getThreat myfile meta ip
51+
putStrLn $ "threat: " ++ result
52+
result <- isProxy myfile meta ip
53+
putStrLn $ "is_proxy: " ++ result

0 commit comments

Comments
 (0)