├── Rakefile ├── .document ├── rb └── data │ └── PX12.SAMPLE.BIN ├── spec ├── assets │ └── PX12.SAMPLE.BIN ├── spec_helper.rb └── ip2proxy_ruby_database_spec.rb ├── docs ├── source │ ├── images │ │ ├── favicon.ico │ │ └── ipl-logo-square-1200.png │ ├── index.md │ ├── conf.py │ ├── code.md │ └── quickstart.md ├── requirements.txt ├── Makefile └── make.bat ├── .gitignore ├── Gemfile ├── lib ├── ip2proxy_ruby │ ├── i2p_ip_data.rb │ ├── i2p_string_data.rb │ ├── ip2proxy_config.rb │ ├── ip2proxy_record.rb │ └── i2p_database_config.rb └── ip2proxy_ruby.rb ├── .readthedocs.yaml ├── LICENSE.txt ├── example.rb ├── README.md └── ip2proxy_ruby.gemspec /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | task :default => :spec 3 | -------------------------------------------------------------------------------- /.document: -------------------------------------------------------------------------------- 1 | lib/**/*.rb 2 | bin/* 3 | - 4 | features/**/*.feature 5 | LICENSE.txt 6 | -------------------------------------------------------------------------------- /rb/data/PX12.SAMPLE.BIN: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ip2location/ip2proxy-ruby/HEAD/rb/data/PX12.SAMPLE.BIN -------------------------------------------------------------------------------- /spec/assets/PX12.SAMPLE.BIN: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ip2location/ip2proxy-ruby/HEAD/spec/assets/PX12.SAMPLE.BIN -------------------------------------------------------------------------------- /docs/source/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ip2location/ip2proxy-ruby/HEAD/docs/source/images/favicon.ico -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | -------------------------------------------------------------------------------- /docs/source/images/ipl-logo-square-1200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ip2location/ip2proxy-ruby/HEAD/docs/source/images/ipl-logo-square-1200.png -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in ip2proxy_ruby.gemspec 4 | gemspec 5 | gem 'bindata', "~> 2.4.15" 6 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | # Defining the exact version will make sure things don't break 2 | sphinx-book-theme==1.0.1 3 | # sphinx-pdj-theme==0.4.0 4 | myst-parser==2.0.0 5 | markdown-it-py==3.0.0 6 | sphinx-copybutton==0.5.2 -------------------------------------------------------------------------------- /lib/ip2proxy_ruby/i2p_ip_data.rb: -------------------------------------------------------------------------------- 1 | class I2pIpData < BinData::BasePrimitive 2 | def read_and_return_value(io) 3 | iv = eval_parameter(:ip_version) 4 | if iv == 4 5 | addr = BinData::Uint32le.read(io) 6 | elsif iv == 6 7 | addr = BinData::Uint128le.read(io) 8 | end 9 | end 10 | end -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) 2 | $LOAD_PATH.unshift(File.dirname(__FILE__)) 3 | require 'rspec' 4 | require 'ip2proxy_ruby' 5 | 6 | # Requires supporting files with custom matchers and macros, etc, 7 | # in ./support/ and its subdirectories. 8 | Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f} 9 | 10 | RSpec.configure do |config| 11 | 12 | end 13 | -------------------------------------------------------------------------------- /lib/ip2proxy_ruby/i2p_string_data.rb: -------------------------------------------------------------------------------- 1 | class I2pStringData < BinData::BasePrimitive 2 | 3 | def read_and_return_value(io) 4 | country_long = eval_parameter(:country_long) 5 | io.seekbytes(-4) if country_long 6 | file = io.instance_variable_get('@raw_io') 7 | addr = BinData::Uint32le.read(io) 8 | old_offset = file.tell 9 | country_long ? file.seek(addr + 3) : file.seek(addr) 10 | length = BinData::Uint8.read(file) 11 | res = BinData::String.new(:length => length).read(file) 12 | file.seek(old_offset) 13 | res 14 | end 15 | 16 | end -------------------------------------------------------------------------------- /lib/ip2proxy_ruby/ip2proxy_config.rb: -------------------------------------------------------------------------------- 1 | class Ip2proxyConfig < BinData::Record 2 | endian :little 3 | uint8 :databasetype 4 | uint8 :databasecolumn 5 | uint8 :databaseyear 6 | uint8 :databasemonth 7 | uint8 :databaseday 8 | # uint32 :databasecount 9 | # uint32 :databaseaddr 10 | # uint32 :ipversion 11 | uint32 :ipv4databasecount 12 | uint32 :ipv4databaseaddr 13 | uint32 :ipv6databasecount 14 | uint32 :ipv6databaseaddr 15 | uint32 :ipv4indexbaseaddr 16 | uint32 :ipv6indexbaseaddr 17 | uint8 :productcode 18 | uint8 :licensecode 19 | uint32 :databasesize 20 | end -------------------------------------------------------------------------------- /lib/ip2proxy_ruby/ip2proxy_record.rb: -------------------------------------------------------------------------------- 1 | class Ip2ProxyRecord 2 | def self.init(database, ip_version) 3 | cls = Class.new(BinData::Record) 4 | cls.class_eval { 5 | endian :little 6 | i2p_ip_data :ip_from, :ip_version => ip_version 7 | database.each do |col| 8 | if col.first == :country 9 | i2p_string_data :country_short 10 | i2p_string_data :country_long, :country_long => true 11 | else 12 | i2p_string_data col.first 13 | end 14 | end 15 | 16 | i2p_ip_data :ip_to, :ip_version => ip_version 17 | } 18 | cls 19 | end 20 | end -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the OS, Python version and other tools you might need 9 | build: 10 | os: ubuntu-22.04 11 | tools: 12 | python: "3.11" 13 | # You can also specify other tool versions: 14 | # nodejs: "19" 15 | # rust: "1.64" 16 | # golang: "1.19" 17 | 18 | # Build documentation in the "docs/" directory with Sphinx 19 | sphinx: 20 | configuration: docs/source/conf.py 21 | 22 | # Optionally build your docs in additional formats such as PDF and ePub 23 | # formats: 24 | # - pdf 25 | # - epub 26 | 27 | # Optional but recommended, declare the Python requirements required 28 | # to build your documentation 29 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 30 | python: 31 | install: 32 | - requirements: docs/requirements.txt -------------------------------------------------------------------------------- /docs/source/index.md: -------------------------------------------------------------------------------- 1 | [![Latest Stable Version](https://img.shields.io/gem/v/ip2proxy_ruby.svg)](https://rubygems.org/gems/ip2proxy_ruby) 2 | [![Total Downloads](https://img.shields.io/gem/dt/ip2proxy_ruby.svg)](https://rubygems.org/gems/ip2proxy_ruby) 3 | 4 | # IP2Proxy Ruby Library 5 | This module allows user to reverse search of IP address to detect VPN servers, open proxies, web proxies, Tor exit nodes, search engine robots, data center ranges, residential proxies, consumer privacy networks, and enterprise private networks using IP2Proxy BIN database. Other information available includes proxy type, country, state, city, ISP, domain name, usage type, AS number, AS name, threats, last seen date, provider names and potential risk score associated with IP address. It lookup the proxy IP address from **IP2Proxy BIN Data** file or web service. 6 | 7 | For more details, please visit: 8 | [https://www.ip2location.com/ip2proxy/developers/ruby](https://www.ip2location.com/ip2proxy/developers/ruby) 9 | 10 | 11 | ## Table of contents 12 | ```{eval-rst} 13 | .. toctree:: 14 | 15 | self 16 | quickstart 17 | code 18 | ``` -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 - 2025 IP2Location ( support@ip2location.com ) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /lib/ip2proxy_ruby/i2p_database_config.rb: -------------------------------------------------------------------------------- 1 | class I2pDbConfig 2 | COLUMNS = { 3 | :COUNTRY => [0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3], 4 | :REGION => [0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], 5 | :CITY => [0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], 6 | :ISP => [0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6], 7 | :PROXYTYPE => [0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], 8 | :DOMAIN => [0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7], 9 | :USAGETYPE => [0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8], 10 | :ASN => [0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9], 11 | :AS => [0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10], 12 | :LASTSEEN => [0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11], 13 | :THREAT => [0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 12], 14 | :PROVIDER => [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13], 15 | :FRAUD_SCORE => [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14] 16 | } 17 | 18 | def self.setup_database(db_index) 19 | # strip all 0 value & downcase keys 20 | cols = COLUMNS.inject({}) {|memo, (key, value)| 21 | (memo[key.to_s.downcase.to_sym] = value[db_index] if value[db_index] > 0) 22 | memo 23 | } 24 | # order by value 25 | col_array = cols.sort_by {|key,value| value} 26 | end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # Read https://www.sphinx-doc.org/en/master/usage/configuration.html for more options available 3 | 4 | # import sphinx_pdj_theme 5 | 6 | # -- Project information 7 | 8 | project = 'IP2Proxy Ruby' 9 | copyright = '2024, IP2Location' 10 | author = 'IP2Location' 11 | 12 | release = '0.1.0' 13 | version = '0.1.0' 14 | 15 | # -- General configuration 16 | 17 | extensions = [ 18 | 'sphinx.ext.duration', 19 | 'sphinx.ext.doctest', 20 | 'myst_parser', 21 | 'sphinx_copybutton', 22 | ] 23 | 24 | # https://myst-parser.readthedocs.io/en/latest/syntax/optional.html 25 | 26 | myst_enable_extensions = [ 27 | "colon_fence", 28 | "deflist", 29 | "fieldlist", 30 | ] 31 | 32 | # https://myst-parser.readthedocs.io/en/latest/configuration.html#setting-html-metadata 33 | myst_html_meta = { 34 | "description": "IP2Proxy Ruby library enables user to query an IP address if it was being used as open proxy, web proxy, VPN anonymizer and TOR exits.", 35 | "keywords": "IP2Proxy, Proxy, IP location, Ruby", 36 | "google-site-verification": "DeW6mXDyMnMt4i61ZJBNuoADPimo5266DKob7Z7d6i4", 37 | } 38 | 39 | # templates_path = ['_templates'] 40 | 41 | # -- Options for HTML output 42 | 43 | html_theme = 'sphinx_book_theme' 44 | # html_theme_path = [sphinx_pdj_theme.get_html_theme_path()] 45 | 46 | # PDJ theme options, see the list of available options here: https://github.com/jucacrispim/sphinx_pdj_theme/blob/master/sphinx_pdj_theme/theme.conf 47 | html_theme_options = { 48 | "use_edit_page_button": False, 49 | "use_source_button": False, 50 | "use_issues_button": False, 51 | "use_download_button": False, 52 | "use_sidenotes": False, 53 | } 54 | 55 | # The name of an image file (relative to this directory) to place at the top 56 | # of the sidebar. 57 | html_logo = 'images/ipl-logo-square-1200.png' 58 | 59 | # Favicon 60 | html_favicon = 'images/favicon.ico' 61 | 62 | html_title = "IP2Proxy Ruby" 63 | 64 | # html_baseurl = "https://ip2proxy-ruby.readthedocs.io/en/latest/" -------------------------------------------------------------------------------- /example.rb: -------------------------------------------------------------------------------- 1 | require 'ip2proxy_ruby' 2 | 3 | # open IP2Proxy BIN database for proxy lookup 4 | i2p = Ip2proxy.new.open("./data/PX12.SAMPLE.BIN") 5 | 6 | # get versioning information 7 | print 'Module Version: ' + i2p.get_module_version + "\n" 8 | print 'Package Version: ' + i2p.get_package_version + "\n" 9 | print 'Database Version: ' + i2p.get_database_version + "\n" 10 | 11 | # individual proxy data check 12 | print 'Is Proxy: ' + i2p.is_proxy('1.2.3.4').to_s + "\n" 13 | print 'Proxy Type: ' + i2p.get_proxytype('1.2.3.4') + "\n" 14 | print 'Country Code: ' + i2p.get_country_short('1.2.3.4') + "\n" 15 | print 'Country Name: ' + i2p.get_country_long('1.2.3.4') + "\n" 16 | print 'Region Name: ' + i2p.get_region('1.2.3.4') + "\n" 17 | print 'City Name: ' + i2p.get_city('1.2.3.4') + "\n" 18 | print 'ISP: ' + i2p.get_isp('1.2.3.4') + "\n" 19 | print 'Domain: ' + i2p.get_domain('1.2.3.4') + "\n" 20 | print 'Usage Type: ' + i2p.get_usagetype('1.2.3.4') + "\n" 21 | print 'ASN: ' + i2p.get_asn('1.2.3.4') + "\n" 22 | print 'AS: ' + i2p.get_as('1.2.3.4') + "\n" 23 | print 'Last Seen: ' + i2p.get_last_seen('1.2.3.4') + "\n" 24 | print 'Threat: ' + i2p.get_threat('1.2.3.4') + "\n" 25 | print 'Provider: ' + i2p.get_provider('1.2.3.4') + "\n" 26 | print 'Fraud Score: ' + i2p.get_fraud_score('1.2.3.4') + "\n" 27 | 28 | # single function to get all proxy data returned in array 29 | record = i2p.get_all('1.2.3.4') 30 | print 'is Proxy: ' + record['is_proxy'].to_s + "\n" 31 | print 'Proxy Type: ' + record['proxy_type'] + "\n" 32 | print 'Country Code: ' + record['country_short'] + "\n" 33 | print 'Country Name: ' + record['country_long'] + "\n" 34 | print 'Region Name: ' + record['region'] + "\n" 35 | print 'City Name: ' + record['city'] + "\n" 36 | print 'ISP: ' + record['isp'] + "\n" 37 | print 'Domain: ' + record['domain'] + "\n" 38 | print 'Usage Type: ' + record['usagetype'] + "\n" 39 | print 'ASN: ' + record['asn'] + "\n" 40 | print 'AS: ' + record['as'] + "\n" 41 | print 'Last Seen: ' + record['last_seen'] + "\n" 42 | print 'Threat: ' + record['threat'] + "\n" 43 | print 'Provider: ' + record['provider'] + "\n" 44 | print 'Fraud Score: ' + record['fraud_score'] + "\n" 45 | 46 | # close IP2Proxy BIN database 47 | i2p.close() -------------------------------------------------------------------------------- /docs/source/code.md: -------------------------------------------------------------------------------- 1 | # IP2Proxy Ruby API 2 | 3 | ## Database Class 4 | ```{py:function} open(database_file_path) 5 | Load the IP2Proxy BIN database. 6 | 7 | :param str database_file_path: (Required) The file path links to IP2Location BIN databases. 8 | ``` 9 | 10 | ```{py:function} get_package_version() 11 | Return the database's type, 1 to 12 respectively for PX1 to PX12. Please visit https://www.ip2location.com/databases/ip2proxy for details. 12 | 13 | :return: Returns the package version. 14 | :rtype: string 15 | ``` 16 | 17 | ```{py:function} get_module_version() 18 | Return the version of module. 19 | 20 | :return: Returns the module version. 21 | :rtype: string 22 | ``` 23 | 24 | ```{py:function} get_database_version() 25 | Return the database's compilation date as a string of the form 'YYYY-MM-DD'. 26 | 27 | :return: Returns the database version. 28 | :rtype: string 29 | ``` 30 | 31 | ```{py:function} get_all(ip_address) 32 | Retrieve geolocation information for an IP address. 33 | 34 | :param str ip_address: (Required) The IP address (IPv4 or IPv6). 35 | :return: Returns the geolocation information in array. Refer below table for the fields avaliable in the array 36 | :rtype: array 37 | 38 | **RETURN FIELDS** 39 | 40 | | Field Name | Description | 41 | | ---------------- | ------------------------------------------------------------ | 42 | | is_proxy | Determine whether if an IP address was a proxy or not. Returns 0 is not proxy, 1 if proxy, and 2 if it's data center IP | 43 | | country_short | Two-character country code based on ISO 3166. | 44 | | country_long | Country name based on ISO 3166. | 45 | | region | Region or state name. | 46 | | city | City name. | 47 | | isp | Internet Service Provider or company\'s name. | 48 | | domain | Internet domain name associated with IP address range. | 49 | | usagetype | Usage type classification of ISP or company. | 50 | | asn | Autonomous system number (ASN). | 51 | | as | Autonomous system (AS) name. | 52 | | last_seen | Proxy last seen in days. | 53 | | threat | Security threat reported. | 54 | | is_proxy | Type of proxy. | 55 | | provider | Name of VPN provider if available. | 56 | | fraud_score | Potential risk score (0 - 99) associated with IP address. | 57 | ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Latest Stable Version](https://img.shields.io/gem/v/ip2proxy_ruby.svg)](https://rubygems.org/gems/ip2proxy_ruby) 2 | [![Total Downloads](https://img.shields.io/gem/dt/ip2proxy_ruby.svg)](https://rubygems.org/gems/ip2proxy_ruby) 3 | 4 | # IP2Proxy Ruby Library 5 | This module allows user to reverse search of IP address to detect VPN servers, open proxies, web proxies, Tor exit nodes, search engine robots, data center ranges, residential proxies, consumer privacy networks, and enterprise private networks using IP2Proxy BIN database. Other information available includes proxy type, country, state, city, ISP, domain name, usage type, AS number, AS name, threats, last seen date and provider names. It lookup the proxy IP address from **IP2Proxy BIN Data** file or web service. 6 | 7 | For more details, please visit: 8 | [https://www.ip2location.com/documentation/ip2proxy-libraries/ruby](https://www.ip2location.com/documentation/ip2proxy-libraries/ruby) 9 | 10 | # Developer Documentation 11 | To learn more about installation, usage, and code examples, please visit the developer documentation at [https://ip2proxy-ruby.readthedocs.io/en/latest/index.html.](https://ip2proxy-ruby.readthedocs.io/en/latest/index.html) 12 | 13 | 14 | ### Proxy Type 15 | 16 | |Proxy Type|Description| 17 | |---|---| 18 | |VPN|Anonymizing VPN services| 19 | |TOR|Tor Exit Nodes| 20 | |PUB|Public Proxies| 21 | |WEB|Web Proxies| 22 | |DCH|Hosting Providers/Data Center| 23 | |SES|Search Engine Robots| 24 | |RES|Residential Proxies [PX10+]| 25 | |CPN|Consumer Privacy Networks. [PX11+]| 26 | |EPN|Enterprise Private Networks. [PX11+]| 27 | 28 | ### Usage Type 29 | 30 | |Usage Type|Description| 31 | |---|---| 32 | |COM|Commercial| 33 | |ORG|Organization| 34 | |GOV|Government| 35 | |MIL|Military| 36 | |EDU|University/College/School| 37 | |LIB|Library| 38 | |CDN|Content Delivery Network| 39 | |ISP|Fixed Line ISP| 40 | |MOB|Mobile ISP| 41 | |DCH|Data Center/Web Hosting/Transit| 42 | |SES|Search Engine Spider| 43 | |RSV|Reserved| 44 | 45 | ### Threat Type 46 | 47 | |Threat Type|Description| 48 | |---|---| 49 | |SPAM|Email and forum spammers| 50 | |SCANNER|Security Scanner or Attack| 51 | |BOTNET|Spyware or Malware| 52 | |BOGON|Unassigned or illegitimate IP addresses announced via BGP| 53 | 54 | # Dependencies 55 | 56 | This library requires IP2Proxy BIN data file to function. You may download the BIN data file at 57 | * IP2Proxy LITE BIN Data (Free): https://lite.ip2location.com 58 | * IP2Proxy Commercial BIN Data (Comprehensive): https://www.ip2location.com/proxy-database 59 | 60 | You can also sign up for [IP2Proxy Web Service](https://www.ip2location.com/web-service/ip2proxy) to lookup by IP2Proxy API. 61 | 62 | # Support 63 | 64 | Email: support@ip2location.com 65 | URL: [https://www.ip2location.com](https://www.ip2location.com) 66 | -------------------------------------------------------------------------------- /ip2proxy_ruby.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | Gem::Specification.new do |s| 4 | s.name = "ip2proxy_ruby" 5 | s.version = "3.4.0" 6 | s.authors = ["ip2location"] 7 | s.email = ["support@ip2location.com"] 8 | 9 | s.summary = "IP2Proxy Ruby library" 10 | s.description = "The official IP2Proxy Ruby library to detect VPN servers, open proxies, web proxies, Tor exit nodes, search engine robots, data center ranges and residential proxies using IP2Proxy BIN database. Other information available includes proxy type, country, state, city, ISP, domain name, usage type, AS number, AS name, threats, last seen date and provider names." 11 | s.homepage = "https://github.com/ip2location/ip2proxy-ruby" 12 | s.licenses = ["MIT"] 13 | s.require_paths = ["lib"] 14 | 15 | s.extra_rdoc_files = [ 16 | "LICENSE.txt", 17 | "README.md" 18 | ] 19 | s.files = [ 20 | ".document", 21 | ".gitignore", 22 | "Gemfile", 23 | "LICENSE.txt", 24 | "README.md", 25 | "Rakefile", 26 | "ip2proxy_ruby.gemspec", 27 | "example.rb", 28 | "lib/ip2proxy_ruby.rb", 29 | "lib/ip2proxy_ruby/i2p_database_config.rb", 30 | "lib/ip2proxy_ruby/i2p_ip_data.rb", 31 | "lib/ip2proxy_ruby/i2p_string_data.rb", 32 | "lib/ip2proxy_ruby/ip2proxy_config.rb", 33 | "lib/ip2proxy_ruby/ip2proxy_record.rb", 34 | "spec/assets/PX12.SAMPLE.BIN", 35 | "spec/ip2proxy_ruby_database_spec.rb", 36 | "spec/spec_helper.rb", 37 | "rb/data/PX12.SAMPLE.BIN" 38 | ] 39 | 40 | if s.respond_to?(:metadata=) 41 | s.metadata = { 42 | "bug_tracker_uri" => "https://github.com/ip2location/ip2proxy-ruby/issues", 43 | "documentation_uri" => "https://www.rubydoc.info/gems/ip2proxy_ruby", 44 | "homepage_uri" => "https://www.ip2location.com", 45 | "source_code_uri" => "https://github.com/ip2location/ip2proxy-ruby", 46 | } 47 | end 48 | 49 | if s.respond_to? :specification_version then 50 | s.specification_version = 4 51 | 52 | if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then 53 | s.add_runtime_dependency(%q, ["~> 2.4.15"]) 54 | s.add_development_dependency(%q, ["~> 2.8.0"]) 55 | s.add_development_dependency(%q, [">= 6.3.1"]) 56 | s.add_development_dependency(%q, [">= 1.2.0"]) 57 | else 58 | s.add_dependency(%q, ["~> 2.4.15"]) 59 | s.add_dependency(%q, ["~> 2.8.0"]) 60 | s.add_dependency(%q, [">= 6.3.1"]) 61 | s.add_dependency(%q, [">= 1.2.0"]) 62 | end 63 | else 64 | s.add_dependency(%q, ["~> 2.4.15"]) 65 | s.add_dependency(%q, ["~> 2.8.0"]) 66 | s.add_dependency(%q, [">= 6.3.1"]) 67 | s.add_dependency(%q, [">= 1.2.0"]) 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /docs/source/quickstart.md: -------------------------------------------------------------------------------- 1 | # Quickstart 2 | 3 | ## Dependencies 4 | 5 | This library requires IP2Proxy BIN database to function. You may download the BIN database at 6 | 7 | - IP2Proxy LITE BIN Data (Free): 8 | - IP2Proxy Commercial BIN Data (Comprehensive): 9 | 10 | 11 | :::{note} 12 | An outdated BIN database was provided in the data folder for your testing. You are recommended to visit the above links to download the latest BIN database. 13 | ::: 14 | 15 | ## Installation 16 | 17 | Install this package using the command as below: 18 | 19 | ``` 20 | gem install ip2proxy_ruby 21 | ``` 22 | 23 | ## Sample Codes 24 | 25 | ### Query geolocation information from BIN database 26 | 27 | You can query the geolocation information from the IP2Proxy BIN database as below: 28 | 29 | ```ruby 30 | require 'ip2proxy_ruby' 31 | 32 | # open IP2Proxy BIN database for proxy lookup 33 | i2p = Ip2proxy.new.open("./data/PX12.SAMPLE.BIN") 34 | 35 | # get versioning information 36 | print 'Module Version: ' + i2p.get_module_version + "\n" 37 | print 'Package Version: ' + i2p.get_package_version + "\n" 38 | print 'Database Version: ' + i2p.get_database_version + "\n" 39 | 40 | # individual proxy data check 41 | print 'Is Proxy: ' + i2p.is_proxy('1.2.3.4').to_s + "\n" 42 | print 'Proxy Type: ' + i2p.get_proxytype('1.2.3.4') + "\n" 43 | print 'Country Code: ' + i2p.get_country_short('1.2.3.4') + "\n" 44 | print 'Country Name: ' + i2p.get_country_long('1.2.3.4') + "\n" 45 | print 'Region Name: ' + i2p.get_region('1.2.3.4') + "\n" 46 | print 'City Name: ' + i2p.get_city('1.2.3.4') + "\n" 47 | print 'ISP: ' + i2p.get_isp('1.2.3.4') + "\n" 48 | print 'Domain: ' + i2p.get_domain('1.2.3.4') + "\n" 49 | print 'Usage Type: ' + i2p.get_usagetype('1.2.3.4') + "\n" 50 | print 'ASN: ' + i2p.get_asn('1.2.3.4') + "\n" 51 | print 'AS: ' + i2p.get_as('1.2.3.4') + "\n" 52 | print 'Last Seen: ' + i2p.get_last_seen('1.2.3.4') + "\n" 53 | print 'Threat: ' + i2p.get_threat('1.2.3.4') + "\n" 54 | print 'Provider: ' + i2p.get_provider('1.2.3.4') + "\n" 55 | print 'Fraud Score: ' + i2p.get_fraud_score('1.2.3.4') + "\n" 56 | 57 | # single function to get all proxy data returned in array 58 | record = i2p.get_all('1.2.3.4') 59 | print 'is Proxy: ' + record['is_proxy'].to_s + "\n" 60 | print 'Proxy Type: ' + record['proxy_type'] + "\n" 61 | print 'Country Code: ' + record['country_short'] + "\n" 62 | print 'Country Name: ' + record['country_long'] + "\n" 63 | print 'Region Name: ' + record['region'] + "\n" 64 | print 'City Name: ' + record['city'] + "\n" 65 | print 'ISP: ' + record['isp'] + "\n" 66 | print 'Domain: ' + record['domain'] + "\n" 67 | print 'Usage Type: ' + record['usagetype'] + "\n" 68 | print 'ASN: ' + record['asn'] + "\n" 69 | print 'AS: ' + record['as'] + "\n" 70 | print 'Last Seen: ' + record['last_seen'] + "\n" 71 | print 'Threat: ' + record['threat'] + "\n" 72 | print 'Provider: ' + record['provider'] + "\n" 73 | print 'Fraud Score: ' + record['fraud_score'] + "\n" 74 | 75 | # close IP2Proxy BIN database 76 | i2p.close() 77 | ``` -------------------------------------------------------------------------------- /spec/ip2proxy_ruby_database_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/spec_helper') 2 | 3 | describe "Ip2proxy" do 4 | it "work correctly with invalid ip" do 5 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 6 | record = i2p.get_all('1.0.0.x') 7 | expect(record['country_short']).to eq 'INVALID IP ADDRESS' 8 | end 9 | 10 | it "work correctly with get_all ipv4" do 11 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 12 | record = i2p.get_all('1.0.0.8') 13 | expect(record['country_short']).to eq '-' 14 | end 15 | 16 | it "work correctly with get_country_short" do 17 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 18 | record = i2p.get_country_short('1.0.0.8') 19 | expect(record).to eq '-' 20 | end 21 | 22 | it "work correctly with get_country_long" do 23 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 24 | record = i2p.get_country_long('1.0.0.8') 25 | expect(record).to eq '-' 26 | end 27 | 28 | it "work correctly with get_region" do 29 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 30 | record = i2p.get_region('1.0.0.8') 31 | expect(record).to eq '-' 32 | end 33 | 34 | it "work correctly with get_city" do 35 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 36 | record = i2p.get_city('1.0.0.8') 37 | expect(record).to eq '-' 38 | end 39 | 40 | it "work correctly with get_isp" do 41 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 42 | record = i2p.get_isp('1.0.0.8') 43 | expect(record).to eq '-' 44 | end 45 | 46 | it "work correctly with get_domain" do 47 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 48 | record = i2p.get_domain('1.0.0.8') 49 | expect(record).to eq '-' 50 | end 51 | 52 | it "work correctly with get_usagetype" do 53 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 54 | record = i2p.get_usagetype('1.0.0.8') 55 | expect(record).to eq '-' 56 | end 57 | 58 | it "work correctly with get_asn" do 59 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 60 | record = i2p.get_asn('1.0.0.8') 61 | expect(record).to eq '-' 62 | end 63 | 64 | it "work correctly with get_as" do 65 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 66 | record = i2p.get_as('1.0.0.8') 67 | expect(record).to eq '-' 68 | end 69 | 70 | it "work correctly with get_last_seen" do 71 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 72 | record = i2p.get_last_seen('1.0.0.8') 73 | expect(record).to eq '-' 74 | end 75 | 76 | it "work correctly with get_threat" do 77 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 78 | record = i2p.get_threat('1.0.0.8') 79 | expect(record).to eq '-' 80 | end 81 | 82 | it "work correctly with is_proxy" do 83 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 84 | record = i2p.is_proxy('1.0.0.8') 85 | expect(record).to eq 0 86 | end 87 | 88 | it "work correctly with get_proxytype" do 89 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 90 | record = i2p.get_proxytype('1.0.0.8') 91 | expect(record).to eq '-' 92 | end 93 | 94 | it "work correctly with get_provider" do 95 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 96 | record = i2p.get_provider('1.0.0.8') 97 | expect(record).to eq '-' 98 | end 99 | 100 | it "work correctly with get_fraud_score" do 101 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 102 | record = i2p.get_fraud_score('1.0.0.8') 103 | expect(record).to eq '0' 104 | end 105 | 106 | it "work correctly with get_all ipv6" do 107 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 108 | record = i2p.get_all('2c0f:ffa0::4') 109 | expect(record['country_short']).to eq '-' 110 | end 111 | 112 | it "work correctly with get_module_version" do 113 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 114 | record = i2p.get_module_version() 115 | expect(record).to eq '3.4.0' 116 | end 117 | 118 | it "work correctly with get_package_version" do 119 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 120 | record = i2p.get_package_version() 121 | expect(record).to eq '12' 122 | end 123 | 124 | it "work correctly with get_database_version" do 125 | i2p = Ip2proxy.new.open(File.dirname(__FILE__) + "/assets/PX12.SAMPLE.BIN") 126 | record = i2p.get_database_version() 127 | expect(record).to eq '2025.2.5' 128 | end 129 | end 130 | -------------------------------------------------------------------------------- /lib/ip2proxy_ruby.rb: -------------------------------------------------------------------------------- 1 | require 'bindata' 2 | require 'ipaddr' 3 | require 'net/http' 4 | require 'json' 5 | require_relative 'ip2proxy_ruby/ip2proxy_config' 6 | require_relative 'ip2proxy_ruby/i2p_database_config' 7 | require_relative 'ip2proxy_ruby/i2p_string_data' 8 | require_relative 'ip2proxy_ruby/i2p_ip_data' 9 | require_relative 'ip2proxy_ruby/ip2proxy_record' 10 | 11 | class Ip2proxy 12 | attr_accessor :record_class4, :record_class6, :v4, :file, :db_index, :count, :base_addr, :ipno, :record, :database, :columns, :ip_version, :ipv4databasecount, :ipv4databaseaddr, :ipv4indexbaseaddr, :ipv6databasecount, :ipv6databaseaddr, :ipv6indexbaseaddr, :databaseyear, :databasemonth, :databaseday, :last_err_msg 13 | 14 | VERSION = '3.4.0' 15 | FIELD_NOT_SUPPORTED = 'NOT SUPPORTED' 16 | INVALID_IP_ADDRESS = 'INVALID IP ADDRESS' 17 | INVALID_BIN_DATABASE = 'Incorrect IP2Proxy BIN file format. Please make sure that you are using the latest IP2Proxy BIN file.' 18 | 19 | def open(url) 20 | if url == '' 21 | self.last_err_msg = 'Ip2proxy.new.open() requires a database path name.' 22 | abort('Ip2proxy.new.open() requires a database path name.') 23 | end 24 | 25 | begin 26 | self.file = File.open(File.expand_path url, 'rb') 27 | rescue 28 | self.last_err_msg = 'Ip2proxy.new.open() error in opening ' + url +'.' 29 | abort('Ip2proxy.new.open() error in opening ' + url + '. No such file in the /your_ip2proxy_ruby_library_path/rb/ folder.') 30 | else 31 | end 32 | i2p = Ip2proxyConfig.read(file) 33 | if i2p.productcode == 2 34 | else 35 | if i2p.databaseyear <= 20 && i2p.productcode == 0 36 | else 37 | self.file.close 38 | self.last_err_msg = INVALID_BIN_DATABASE 39 | abort(INVALID_BIN_DATABASE) 40 | end 41 | end 42 | self.db_index = i2p.databasetype 43 | self.columns = i2p.databasecolumn + 0 44 | self.databaseyear = 2000 + i2p.databaseyear 45 | self.databasemonth = i2p.databasemonth 46 | self.databaseday = i2p.databaseday 47 | self.database = I2pDbConfig.setup_database(self.db_index) 48 | self.ipv4databasecount = i2p.ipv4databasecount 49 | self.ipv4databaseaddr = i2p.ipv4databaseaddr 50 | self.ipv6databasecount = i2p.ipv6databasecount 51 | self.ipv6databaseaddr = i2p.ipv6databaseaddr 52 | self.ipv4indexbaseaddr = i2p.ipv4indexbaseaddr 53 | self.ipv6indexbaseaddr = i2p.ipv6indexbaseaddr 54 | self.record_class4 = (Ip2ProxyRecord.init database, 4) 55 | self.record_class6 = (Ip2ProxyRecord.init database, 6) 56 | self 57 | end 58 | 59 | def close() 60 | self.file.close 61 | end 62 | 63 | def get_last_error_message() 64 | return self.last_err_msg 65 | end 66 | 67 | def get_module_version() 68 | return VERSION 69 | end 70 | 71 | def get_package_version() 72 | return (self.db_index).to_s 73 | end 74 | 75 | def get_database_version() 76 | return (self.databaseyear).to_s + "." + (self.databasemonth).to_s + "." + (self.databaseday).to_s 77 | end 78 | 79 | def get_record(ip) 80 | ipno = IPAddr.new(ip, Socket::AF_UNSPEC) 81 | self.ip_version, ipnum = validateip(ipno) 82 | self.v4 = ip_version == 4 ? true : false 83 | self.count = v4 ? self.ipv4databasecount + 0 : self.ipv6databasecount + 0 84 | self.base_addr = (v4 ? self.ipv4databaseaddr - 1 : self.ipv6databaseaddr - 1) 85 | col_length = columns * 4 86 | if ipv4indexbaseaddr > 0 || ipv6indexbaseaddr > 0 87 | indexpos = 0 88 | case ip_version 89 | when 4 90 | indexpos = ipv4indexbaseaddr + ((ipnum >> 16) << 3) 91 | realipno = ipnum 92 | # if ipnum reach MAX_IPV4_RANGE 93 | if realipno == 4294967295 94 | ipnum = realipno - 1 95 | end 96 | when 6 97 | indexpos = ipv6indexbaseaddr + ((ipnum >> 112) << 3) 98 | realipno = ipnum 99 | # if ipnum reach MAX_IPV6_RANGE 100 | if realipno == 340282366920938463463374607431768211455 101 | ipnum = realipno - 1 102 | end 103 | end 104 | low, high = read32x2(indexpos) 105 | return self.record = bsearch(low, high, ipnum, self.base_addr, col_length) 106 | else 107 | return self.record = bsearch(0, self.count, ipnum, self.base_addr, col_length) 108 | end 109 | end 110 | 111 | def get_country_short(ip) 112 | valid = !(IPAddr.new(ip) rescue nil).nil? 113 | if valid 114 | rec = get_record(ip) 115 | if !(rec.nil?) 116 | country_short = (defined?(rec.country_short) && rec.country_short != '') ? rec.country_short : FIELD_NOT_SUPPORTED 117 | else 118 | country_short = INVALID_IP_ADDRESS 119 | end 120 | else 121 | country_short = INVALID_IP_ADDRESS 122 | end 123 | return country_short 124 | end 125 | 126 | def get_country_long(ip) 127 | valid = !(IPAddr.new(ip) rescue nil).nil? 128 | if valid 129 | rec = get_record(ip) 130 | if !(rec.nil?) 131 | country_long = (defined?(rec.country_long) && rec.country_long != '') ? rec.country_long : FIELD_NOT_SUPPORTED 132 | else 133 | country_long = INVALID_IP_ADDRESS 134 | end 135 | else 136 | country_long = INVALID_IP_ADDRESS 137 | end 138 | return country_long 139 | end 140 | 141 | def get_region(ip) 142 | valid = !(IPAddr.new(ip) rescue nil).nil? 143 | if valid 144 | rec = get_record(ip) 145 | if !(rec.nil?) 146 | region = (defined?(rec.region) && rec.region != '') ? rec.region : FIELD_NOT_SUPPORTED 147 | else 148 | region = INVALID_IP_ADDRESS 149 | end 150 | else 151 | region = INVALID_IP_ADDRESS 152 | end 153 | return region 154 | end 155 | 156 | def get_city(ip) 157 | valid = !(IPAddr.new(ip) rescue nil).nil? 158 | if valid 159 | rec = get_record(ip) 160 | if !(rec.nil?) 161 | city = (defined?(rec.city) && rec.city != '') ? rec.city : FIELD_NOT_SUPPORTED 162 | else 163 | city = INVALID_IP_ADDRESS 164 | end 165 | else 166 | city = INVALID_IP_ADDRESS 167 | end 168 | return city 169 | end 170 | 171 | def get_isp(ip) 172 | valid = !(IPAddr.new(ip) rescue nil).nil? 173 | if valid 174 | rec = get_record(ip) 175 | if !(rec.nil?) 176 | isp = (defined?(rec.isp) && rec.isp != '') ? rec.isp : FIELD_NOT_SUPPORTED 177 | else 178 | isp = INVALID_IP_ADDRESS 179 | end 180 | else 181 | isp = INVALID_IP_ADDRESS 182 | end 183 | return isp 184 | end 185 | 186 | def get_proxytype(ip) 187 | valid = !(IPAddr.new(ip) rescue nil).nil? 188 | if valid 189 | rec = get_record(ip) 190 | if !(rec.nil?) 191 | proxytype = (defined?(rec.proxytype) && rec.proxytype != '') ? rec.proxytype : FIELD_NOT_SUPPORTED 192 | else 193 | proxytype = INVALID_IP_ADDRESS 194 | end 195 | else 196 | proxytype = INVALID_IP_ADDRESS 197 | end 198 | return proxytype 199 | end 200 | 201 | def get_domain(ip) 202 | valid = !(IPAddr.new(ip) rescue nil).nil? 203 | if valid 204 | rec = get_record(ip) 205 | if !(rec.nil?) 206 | domain = (defined?(rec.domain) && rec.domain != '') ? rec.domain : FIELD_NOT_SUPPORTED 207 | else 208 | domain = INVALID_IP_ADDRESS 209 | end 210 | else 211 | domain = INVALID_IP_ADDRESS 212 | end 213 | return domain 214 | end 215 | 216 | def get_usagetype(ip) 217 | valid = !(IPAddr.new(ip) rescue nil).nil? 218 | if valid 219 | rec = get_record(ip) 220 | if !(rec.nil?) 221 | usagetype = (defined?(rec.usagetype) && rec.usagetype != '') ? rec.usagetype : FIELD_NOT_SUPPORTED 222 | else 223 | usagetype = INVALID_IP_ADDRESS 224 | end 225 | else 226 | usagetype = INVALID_IP_ADDRESS 227 | end 228 | return usagetype 229 | end 230 | 231 | def get_asn(ip) 232 | valid = !(IPAddr.new(ip) rescue nil).nil? 233 | if valid 234 | rec = get_record(ip) 235 | if !(rec.nil?) 236 | asn = (defined?(rec.asn) && rec.asn != '') ? rec.asn : FIELD_NOT_SUPPORTED 237 | else 238 | asn = INVALID_IP_ADDRESS 239 | end 240 | else 241 | asn = INVALID_IP_ADDRESS 242 | end 243 | return asn 244 | end 245 | 246 | def get_as(ip) 247 | valid = !(IPAddr.new(ip) rescue nil).nil? 248 | if valid 249 | rec = get_record(ip) 250 | if !(rec.nil?) 251 | as = (defined?(rec.as) && rec.as != '') ? rec.as : FIELD_NOT_SUPPORTED 252 | else 253 | as = INVALID_IP_ADDRESS 254 | end 255 | else 256 | as = INVALID_IP_ADDRESS 257 | end 258 | return as 259 | end 260 | 261 | def get_last_seen(ip) 262 | valid = !(IPAddr.new(ip) rescue nil).nil? 263 | if valid 264 | rec = get_record(ip) 265 | if !(rec.nil?) 266 | last_seen = (defined?(rec.lastseen) && rec.lastseen != '') ? rec.lastseen : FIELD_NOT_SUPPORTED 267 | else 268 | last_seen = INVALID_IP_ADDRESS 269 | end 270 | else 271 | last_seen = INVALID_IP_ADDRESS 272 | end 273 | return last_seen 274 | end 275 | 276 | def get_threat(ip) 277 | valid = !(IPAddr.new(ip) rescue nil).nil? 278 | if valid 279 | rec = get_record(ip) 280 | if !(rec.nil?) 281 | threat = (defined?(rec.threat) && rec.threat != '') ? rec.threat : FIELD_NOT_SUPPORTED 282 | else 283 | threat = INVALID_IP_ADDRESS 284 | end 285 | else 286 | threat = INVALID_IP_ADDRESS 287 | end 288 | return threat 289 | end 290 | 291 | def is_proxy(ip) 292 | valid = !(IPAddr.new(ip) rescue nil).nil? 293 | if valid 294 | rec = get_record(ip) 295 | if !(rec.nil?) 296 | if self.db_index == 1 297 | isproxy = (rec.country_short == '-') ? 0 : 1 298 | else 299 | isproxy = (rec.proxytype == '-') ? 0 : (rec.proxytype == 'DCH' || rec.proxytype == 'SES') ? 2 : 1 300 | end 301 | else 302 | isproxy = -1 303 | end 304 | else 305 | isproxy = -1 306 | end 307 | return isproxy 308 | end 309 | 310 | def get_provider(ip) 311 | valid = !(IPAddr.new(ip) rescue nil).nil? 312 | if valid 313 | rec = get_record(ip) 314 | if !(rec.nil?) 315 | provider = (defined?(rec.provider) && rec.provider != '') ? rec.provider : FIELD_NOT_SUPPORTED 316 | else 317 | provider = INVALID_IP_ADDRESS 318 | end 319 | else 320 | provider = INVALID_IP_ADDRESS 321 | end 322 | return provider 323 | end 324 | 325 | def get_fraud_score(ip) 326 | valid = !(IPAddr.new(ip) rescue nil).nil? 327 | if valid 328 | rec = get_record(ip) 329 | if !(rec.nil?) 330 | fraud_score = (defined?(rec.fraud_score) && rec.fraud_score != '') ? rec.fraud_score : FIELD_NOT_SUPPORTED 331 | else 332 | fraud_score = INVALID_IP_ADDRESS 333 | end 334 | else 335 | fraud_score = INVALID_IP_ADDRESS 336 | end 337 | return fraud_score 338 | end 339 | 340 | def get_all(ip) 341 | valid = !(IPAddr.new(ip) rescue nil).nil? 342 | if valid 343 | rec = get_record(ip) 344 | if !(rec.nil?) 345 | country_short = (defined?(rec.country_short) && rec.country_short != '') ? rec.country_short : FIELD_NOT_SUPPORTED 346 | country_long = (defined?(rec.country_long) && rec.country_long != '') ? rec.country_long : FIELD_NOT_SUPPORTED 347 | region = (defined?(rec.region) && rec.region != '') ? rec.region : FIELD_NOT_SUPPORTED 348 | city = (defined?(rec.city) && rec.city != '') ? rec.city : FIELD_NOT_SUPPORTED 349 | isp = (defined?(rec.isp) && rec.isp != '') ? rec.isp : FIELD_NOT_SUPPORTED 350 | proxytype = (defined?(rec.proxytype) && rec.proxytype != '') ? rec.proxytype : FIELD_NOT_SUPPORTED 351 | domain = (defined?(rec.domain) && rec.domain != '') ? rec.domain : FIELD_NOT_SUPPORTED 352 | usagetype = (defined?(rec.usagetype) && rec.usagetype != '') ? rec.usagetype : FIELD_NOT_SUPPORTED 353 | asn = (defined?(rec.asn) && rec.asn != '') ? rec.asn : FIELD_NOT_SUPPORTED 354 | as = (defined?(rec.as) && rec.as != '') ? rec.as : FIELD_NOT_SUPPORTED 355 | last_seen = (defined?(rec.lastseen) && rec.lastseen != '') ? rec.lastseen : FIELD_NOT_SUPPORTED 356 | threat = (defined?(rec.threat) && rec.threat != '') ? rec.threat : FIELD_NOT_SUPPORTED 357 | provider = (defined?(rec.provider) && rec.provider != '') ? rec.provider : FIELD_NOT_SUPPORTED 358 | fraud_score = (defined?(rec.fraud_score) && rec.fraud_score != '') ? rec.fraud_score : FIELD_NOT_SUPPORTED 359 | if self.db_index == 1 360 | isproxy = (rec.country_short == '-') ? 0 : 1 361 | else 362 | isproxy = (rec.proxytype == '-') ? 0 : (rec.proxytype == 'DCH' || rec.proxytype == 'SES') ? 2 : 1 363 | end 364 | else 365 | country_short = INVALID_IP_ADDRESS 366 | country_long = INVALID_IP_ADDRESS 367 | region = INVALID_IP_ADDRESS 368 | city = INVALID_IP_ADDRESS 369 | isp = INVALID_IP_ADDRESS 370 | proxytype = INVALID_IP_ADDRESS 371 | domain = INVALID_IP_ADDRESS 372 | usagetype = INVALID_IP_ADDRESS 373 | asn = INVALID_IP_ADDRESS 374 | as = INVALID_IP_ADDRESS 375 | last_seen = INVALID_IP_ADDRESS 376 | threat = INVALID_IP_ADDRESS 377 | provider = INVALID_IP_ADDRESS 378 | fraud_score = INVALID_IP_ADDRESS 379 | isproxy = -1 380 | end 381 | else 382 | country_short = INVALID_IP_ADDRESS 383 | country_long = INVALID_IP_ADDRESS 384 | region = INVALID_IP_ADDRESS 385 | city = INVALID_IP_ADDRESS 386 | isp = INVALID_IP_ADDRESS 387 | proxytype = INVALID_IP_ADDRESS 388 | domain = INVALID_IP_ADDRESS 389 | usagetype = INVALID_IP_ADDRESS 390 | asn = INVALID_IP_ADDRESS 391 | as = INVALID_IP_ADDRESS 392 | last_seen = INVALID_IP_ADDRESS 393 | threat = INVALID_IP_ADDRESS 394 | provider = INVALID_IP_ADDRESS 395 | fraud_score = INVALID_IP_ADDRESS 396 | isproxy = -1 397 | end 398 | results = {} 399 | results['is_proxy'] = isproxy 400 | results['proxy_type'] = proxytype 401 | results['country_short'] = country_short 402 | results['country_long'] = country_long 403 | results['region'] = region 404 | results['city'] = city 405 | results['isp'] = isp 406 | results['domain'] = domain 407 | results['usagetype'] = usagetype 408 | results['asn'] = asn 409 | results['as'] = as 410 | results['last_seen'] = last_seen 411 | results['threat'] = threat 412 | results['provider'] = provider 413 | results['fraud_score'] = fraud_score 414 | return results 415 | end 416 | 417 | def bsearch(low, high, ipnum, base_addr, col_length) 418 | while low <= high do 419 | mid = (low + high) >> 1 420 | ip_from, ip_to = get_from_to(mid, base_addr, col_length) 421 | if ipnum >= ip_from && ipnum < ip_to 422 | from_base = ( base_addr + mid * (col_length + (self.v4 ? 0 : 12))) 423 | file.seek(from_base) 424 | if v4 425 | return self.record_class4.read(file) 426 | else 427 | return self.record_class6.read(file) 428 | end 429 | else 430 | if ipnum < ip_from 431 | high = mid - 1 432 | else 433 | low = mid + 1 434 | end 435 | end 436 | end 437 | end 438 | 439 | def get_from_to(mid, base_addr, col_length) 440 | from_base = (base_addr + mid * (col_length + (v4 ? 0 : 12))) 441 | data_length = col_length + (v4 ? 4 : (12 + 16)) 442 | file.seek(from_base) 443 | data_read = file.read(data_length) 444 | ip_from = v4 ? data_read[0..3].unpack('V').first : readipv6(data_read[0..15].unpack('V*')) 445 | ip_to = v4 ? data_read[(data_length - 4)..(data_length - 1)].unpack('V').first : readipv6(data_read[(data_length - 16)..(data_length - 1)].unpack('V*')) 446 | [ip_from, ip_to] 447 | end 448 | 449 | def validateip(ip) 450 | if ip.ipv4? 451 | ipv = 4 452 | ipnum = ip.to_i + 0 453 | else 454 | ipv = 6 455 | ipnum = ip.to_i + 0 456 | #reformat ipv4 address in ipv6 457 | if ipnum >= 281470681743360 && ipnum <= 281474976710655 458 | ipv = 4 459 | ipnum = ipnum - 281470681743360 460 | end 461 | #reformat 6to4 address to ipv4 address 2002:: to 2002:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF 462 | if ipnum >= 42545680458834377588178886921629466624 && ipnum <= 42550872755692912415807417417958686719 463 | ipv = 4 464 | #bitshift right 80 bits 465 | ipnum = ipnum >> 80 466 | #bitwise modulus to get the last 32 bit 467 | ipnum = ipnum % 4294967296 468 | end 469 | #reformat Teredo address to ipv4 address 2001:0000:: to 2001:0000:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF: 470 | if ipnum >= 42540488161975842760550356425300246528 && ipnum <= 42540488241204005274814694018844196863 471 | ipv = 4 472 | #bitwise not to invert binary 473 | ipnum = ~ipnum 474 | #bitwise modulus to get the last 32 bit 475 | ipnum = ipnum % 4294967296 476 | end 477 | end 478 | [ipv, ipnum] 479 | end 480 | 481 | def read32x2(indexp) 482 | file.seek(indexp - 1) 483 | data_read = file.read(8) 484 | data1 = data_read[0..3].unpack('V').first 485 | data2 = data_read[4..7].unpack('V').first 486 | return [data1, data2] 487 | end 488 | 489 | def readipv6(parts) 490 | return parts[0] + parts[1] * 4294967296 + parts[2] * 4294967296**2 + parts[3] * 4294967296**3 491 | end 492 | 493 | private :get_record, :bsearch, :get_from_to, :read32x2, :readipv6 494 | 495 | end 496 | 497 | class Ip2proxyWebService 498 | attr_accessor :ws_api_key, :ws_package, :ws_use_ssl 499 | 500 | def initialize(api_key, package, use_ssl) 501 | if !api_key.match(/^[0-9A-Z]{10}$/) && api_key != 'demo' 502 | raise Exception.new "Please provide a valid IP2Proxy web service API key." 503 | end 504 | if !package.match(/^PX[0-9]+$/) 505 | package = 'PX1' 506 | end 507 | if use_ssl == '' 508 | use_ssl = true 509 | end 510 | self.ws_api_key = api_key 511 | self.ws_package = package 512 | self.ws_use_ssl = use_ssl 513 | end 514 | 515 | def lookup(ip) 516 | if self.ws_use_ssl 517 | response = Net::HTTP.get(URI("https://api.ip2proxy.com/?key=" + self.ws_api_key + "&ip=" + ip + "&package=" + self.ws_package + "&format=json")) 518 | else 519 | response = Net::HTTP.get(URI("http://api.ip2proxy.com/?key=" + self.ws_api_key + "&ip=" + ip + "&package=" + self.ws_package + "&format=json")) 520 | end 521 | parsed_response = JSON.parse(response) 522 | if parsed_response.nil? 523 | return false 524 | end 525 | if parsed_response["response"] != "OK" 526 | raise Exception.new "Error: " + parsed_response["response"] 527 | end 528 | return parsed_response 529 | end 530 | 531 | def get_credit() 532 | if self.ws_use_ssl 533 | response = Net::HTTP.get(URI("https://api.ip2proxy.com/?key=" + self.ws_api_key + "&check=true")) 534 | else 535 | response = Net::HTTP.get(URI("http://api.ip2proxy.com/?key=" + self.ws_api_key + "&check=true")) 536 | end 537 | parsed_response = JSON.parse(response) 538 | if parsed_response.nil? 539 | return 0 540 | end 541 | if parsed_response["response"].nil? 542 | return 0 543 | end 544 | return parsed_response["response"] 545 | end 546 | end --------------------------------------------------------------------------------