├── .github
└── workflows
│ └── run-geoip2dat.yml
├── .gitignore
├── CHANGELOG
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── geoip2fast-legacy
├── .gitignore
├── CHANGELOG
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── geoip2fast-1.1.11.tar.gz
├── geoip2fast
│ ├── __init__.py
│ ├── geoip2dat.py
│ ├── geoip2fast-asn-ipv6.dat.gz
│ ├── geoip2fast-asn.dat.gz
│ ├── geoip2fast-ipv6.dat.gz
│ ├── geoip2fast.dat.gz
│ └── geoip2fast.py
├── images
│ ├── cli.jpg
│ ├── clicode.png
│ ├── code_example.png
│ ├── coverage_test.jpg
│ ├── coverage_verbose.jpg
│ ├── geoip2dat01.jpg
│ ├── geoip2dat02.jpg
│ ├── geoip2dat03.jpg
│ ├── geoip2fast-win32.jpg
│ ├── geoip2fast.jpg
│ ├── geoip2fast_selftest.jpg
│ ├── geoip2fastv4.jpg
│ ├── geoip2fastv6.jpg
│ ├── geoipv6_coverage.jpg
│ └── speed_test.jpg
├── setup.py
└── tests
│ ├── .gitignore
│ ├── compare_with_mmdb.py
│ ├── coverage_test.py
│ ├── geoip2fast_test.py
│ ├── random_test.py
│ └── speed_test.py
├── geoip2fast
├── __init__.py
├── geoip2dat.py
├── geoip2fast-asn-ipv6.dat.gz
├── geoip2fast-asn.dat.gz
├── geoip2fast-city-asn-ipv6.dat.gz
├── geoip2fast-city-asn.dat.gz
├── geoip2fast-city-ipv6.dat.gz
├── geoip2fast-city.dat.gz
├── geoip2fast-ipv6.dat.gz
├── geoip2fast.dat.gz
├── geoip2fast.py
├── geoip2fastmin.py
├── geoip2fastminified.py
└── tests
│ ├── .gitignore
│ ├── compare_with_mmdb.py
│ ├── coverage_test.py
│ ├── geoip2fast_test.py
│ ├── random_test.py
│ └── speed_test.py
├── images
├── geoip2dat01.jpg
├── geoip2dat02.jpg
├── geoip2dat03.jpg
├── geoip2fast_selftest.jpg
├── geoip2fastcity.jpg
└── geoip2fastv4.jpg
└── setup.py
/.github/workflows/run-geoip2dat.yml:
--------------------------------------------------------------------------------
1 | name: Update GeoIP2Fast dat files
2 | on:
3 | repository_dispatch:
4 | workflow_dispatch:
5 | schedule:
6 | - cron: 0 22 * * 2,5
7 | jobs:
8 | run:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: Checkout repository
12 | uses: actions/checkout@v4.1.1
13 | - name: Download Geolite2 CSV files from Maxmind
14 | run: |
15 | mkdir -p geolite2
16 | wget -nv -O GeoLite2-ASN-CSV.zip "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-ASN-CSV&license_key=${{ secrets.MAXMIND_KEY }}&suffix=zip"
17 | wget -nv -O GeoLite2-Country-CSV.zip "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country-CSV&license_key=${{ secrets.MAXMIND_KEY }}&suffix=zip"
18 | wget -nv -O GeoLite2-City-CSV.zip "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City-CSV&license_key=${{ secrets.MAXMIND_KEY }}&suffix=zip"
19 | - name: Decompress Geolite2 zip files
20 | uses: TonyBogdanov/zip@1.0
21 | with:
22 | args: unzip -qq GeoLite2-*-CSV.zip
23 | - name: Prepare ENV variables
24 | run: |
25 | TAG_DATE=$(ls -d GeoLite2-Country-CSV_* | awk -F '_' '{print $2}')
26 | echo "TAG_DATE=$TAG_DATE" >> $GITHUB_ENV
27 | cat $GITHUB_ENV > Maxmind-Geolite2-CSV_$TAG_DATE
28 | - name: Copy GeoLite2 CSV files
29 | run: |
30 | cp -v GeoLite*/*.csv geolite2
31 |
32 | - name: Create v1.1.X geoip2fast.dat.gz with Country + IPv4
33 | run: |
34 | python3 geoip2fast-legacy/geoip2fast/geoip2dat.py --country-dir ./geolite2/ --output-dir ./
35 | mv -vf geoip2fast.dat.gz geoip2fast-legacy/geoip2fast/geoip2fast.dat.gz
36 | - name: Create v1.1.X geoip2fast.dat.gz with Country + IPv4 + IPv6
37 | run: |
38 | python3 geoip2fast-legacy/geoip2fast/geoip2dat.py --country-dir ./geolite2/ --output-dir ./ --with-ipv6
39 | mv -vf geoip2fast.dat.gz geoip2fast-legacy/geoip2fast/geoip2fast-ipv6.dat.gz
40 | - name: Create v1.1.X geoip2fast.dat.gz with Country + ASN + IPv4
41 | run: |
42 | python3 geoip2fast-legacy/geoip2fast/geoip2dat.py --country-dir ./geolite2/ --asn-dir ./geolite2/ --output-dir ./
43 | mv -vf geoip2fast.dat.gz geoip2fast-legacy/geoip2fast/geoip2fast-asn.dat.gz
44 | - name: Create v1.1.X geoip2fast.dat.gz with Country + ASN + IPv4 + IPv6
45 | run: |
46 | python3 geoip2fast-legacy/geoip2fast/geoip2dat.py --country-dir ./geolite2/ --asn-dir ./geolite2/ --output-dir ./ --with-ipv6
47 | # PERCENTAGE=$(python3 geoip2fast-legacy/geoip2fast/geoip2fast.py --coverage | grep IPv4 | awk '{print $4}' | sed 's/%//g')
48 | # python3 geoip2fast-legacy/geoip2fast/geoip2fast.py --coverage > "IPv4_Coverage_${PERCENTAGE}_percent.txt"
49 | mv -vf geoip2fast.dat.gz geoip2fast-legacy/geoip2fast/geoip2fast-asn-ipv6.dat.gz
50 |
51 | - name: Create v1.2.X geoip2fast.dat.gz with City + IPv4
52 | run: |
53 | python3 geoip2fast/geoip2dat.py --city-dir ./geolite2/ --output-dir ./
54 | mv -vf geoip2fast.dat.gz geoip2fast/geoip2fast-city.dat.gz
55 | - name: Create v1.2.X geoip2fast.dat.gz with City + IPv4 + IPv6
56 | run: |
57 | python3 geoip2fast/geoip2dat.py --city-dir ./geolite2/ --output-dir ./ --with-ipv6
58 | mv -vf geoip2fast.dat.gz geoip2fast/geoip2fast-city-ipv6.dat.gz
59 | - name: Create v1.2.X geoip2fast.dat.gz with City + ASN + IPv4
60 | run: |
61 | python3 geoip2fast/geoip2dat.py --city-dir ./geolite2/ --asn-dir ./geolite2/ --output-dir ./
62 | mv -vf geoip2fast.dat.gz geoip2fast/geoip2fast-city-asn.dat.gz
63 | - name: Create v1.2.X geoip2fast.dat.gz with City + ASN + IPv4 + IPv6
64 | run: |
65 | python3 geoip2fast/geoip2dat.py --city-dir ./geolite2/ --asn-dir ./geolite2/ --output-dir ./ --with-ipv6
66 | mv -vf geoip2fast.dat.gz geoip2fast/geoip2fast-city-asn-ipv6.dat.gz
67 | - name: Create v1.2.X geoip2fast.dat.gz with Country + IPv4
68 | run: |
69 | python3 geoip2fast/geoip2dat.py --country-dir ./geolite2/ --output-dir ./
70 | mv -vf geoip2fast.dat.gz geoip2fast/geoip2fast.dat.gz
71 | - name: Create v1.2.X geoip2fast.dat.gz with Country + IPv4 + IPv6
72 | run: |
73 | python3 geoip2fast/geoip2dat.py --country-dir ./geolite2/ --output-dir ./ --with-ipv6
74 | mv -vf geoip2fast.dat.gz geoip2fast/geoip2fast-ipv6.dat.gz
75 | - name: Create v1.2.X geoip2fast.dat.gz with Country + ASN + IPv4
76 | run: |
77 | python3 geoip2fast/geoip2dat.py --country-dir ./geolite2/ --asn-dir ./geolite2/ --output-dir ./
78 | mv -vf geoip2fast.dat.gz geoip2fast/geoip2fast-asn.dat.gz
79 | - name: Create v1.2.X geoip2fast.dat.gz with Country + ASN + IPv4 + IPv6
80 | run: |
81 | python3 geoip2fast/geoip2dat.py --country-dir ./geolite2/ --asn-dir ./geolite2/ --output-dir ./ --with-ipv6
82 | # PERCENTAGE=$(python3 geoip2fast/geoip2fast.py --coverage | grep IPv4 | awk '{print $4}' | sed 's/%//g')
83 | # python3 geoip2fast/geoip2fast.py --coverage > "IPv4_Coverage_${PERCENTAGE}_percent.txt"
84 | mv -vf geoip2fast.dat.gz geoip2fast/geoip2fast-asn-ipv6.dat.gz
85 |
86 | - name: Push to "main" branch
87 | run: |
88 | git config user.name "${{ github.actor }}"
89 | git config user.email "${{ github.actor }}@users.noreply.github.com"
90 | cd geoip2fast
91 | git add geoip2fast*.dat.gz
92 | git commit -m "Updated dat.gz files from Maxmind-${{ env.TAG_DATE }} for v1.2.X"
93 | cd ../geoip2fast-legacy/geoip2fast/
94 | git add geoip2fast*.dat.gz
95 | git commit -m "Updated dat.gz files from Maxmind-${{ env.TAG_DATE }} for v1.1.X"
96 | git remote set-url origin "https://${{ secrets.TOKEN }}@github.com/${{ github.repository }}"
97 | git push -f origin main
98 |
99 | - name: Delete LATEST and LEGACY release
100 | env:
101 | GH_TOKEN: ${{ github.token }}
102 | run: |
103 | gh release list
104 | gh release delete LATEST
105 | gh release delete LEGACY
106 | gh release list
107 |
108 | - name: Upload to Release Legacy v1.1.X
109 | uses: softprops/action-gh-release@v0.1.15
110 | env:
111 | GITHUB_TOKEN: ${{ secrets.TOKEN }}
112 | with:
113 | name: Latest DAT files ${{ env.TAG_DATE }} (Legacy)
114 | tag_name: LEGACY
115 | body: Latest dat.gz files for GeoIP2Fast v1.1.X (LEGACY) with Maxmind Geolite2 database from ${{ env.TAG_DATE }}
**To download dat.gz files for GeoIP2Fast v1.2.X, go to tag [LATEST](https://github.com/rabuchaim/geoip2fast/releases/tag/LATEST)**.
116 | token: ${{ secrets.TOKEN }}
117 | files: |
118 | Maxmind-Geolite2-CSV_*
119 | IPv4_Coverage_*
120 | geoip2fast-legacy/geoip2fast/*.gz
121 |
122 | - name: Upload to Release Latest v1.2.X
123 | uses: softprops/action-gh-release@v0.1.15
124 | env:
125 | GITHUB_TOKEN: ${{ secrets.TOKEN }}
126 | with:
127 | name: Latest DAT files ${{ env.TAG_DATE }}
128 | tag_name: LATEST
129 | body: Latest dat.gz files for GeoIP2Fast v1.2.X (LATEST) with Maxmind Geolite2 database from ${{ env.TAG_DATE }}.
**To download dat.gz files for GeoIP2Fast v1.1.X, go to tag [LEGACY](https://github.com/rabuchaim/geoip2fast/releases/tag/LEGACY)**.
130 | token: ${{ secrets.TOKEN }}
131 | files: |
132 | Maxmind-Geolite2-CSV_*
133 | IPv4_Coverage_*
134 | geoip2fast/*.gz
135 |
136 | - name: Set LATEST release
137 | env:
138 | GH_TOKEN: ${{ github.token }}
139 | run: |
140 | gh release list
141 | gh release edit LATEST --latest
142 | gh release list
143 |
144 | permissions:
145 | contents: write
146 | discussions: write
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 | .vscode
6 | .mypy_cache
7 | create_all_dat_files.sh
8 | geoip2fast-ipv4.dat.gz
9 | old*
10 | *egg-info/
11 | dist/
12 | build
13 | *turbo*.py
14 | *.tar.gz
15 | test*.py
16 | old*.py
17 | *old.py
18 | new*.py
19 | *new.py
20 | *2023*.gz
21 | *.json
22 | *.txt
23 | *tar.gz
24 | database-update.py
25 | *.php
26 | # C extensions
27 | *.so
28 |
29 | # Distribution / packaging
30 | .Python
31 | build/
32 | develop-eggs/
33 | dist/
34 | downloads/
35 | eggs/
36 | .eggs/
37 | lib/
38 | lib64/
39 | parts/
40 | sdist/
41 | var/
42 | wheels/
43 | share/python-wheels/
44 | *.egg-info/
45 | .installed.cfg
46 | *.egg
47 | MANIFEST
48 |
49 | # PyInstaller
50 | # Usually these files are written by a python script from a template
51 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
52 | *.manifest
53 | *.spec
54 |
55 | # Installer logs
56 | pip-log.txt
57 | pip-delete-this-directory.txt
58 |
59 | # Unit test / coverage reports
60 | htmlcov/
61 | .tox/
62 | .nox/
63 | .coverage
64 | .coverage.*
65 | .cache
66 | nosetests.xml
67 | coverage.xml
68 | *.cover
69 | *.py,cover
70 | .hypothesis/
71 | .pytest_cache/
72 | cover/
73 |
74 | # Translations
75 | *.mo
76 | *.pot
77 |
78 | # Django stuff:
79 | *.log
80 | local_settings.py
81 | db.sqlite3
82 | db.sqlite3-journal
83 |
84 | # Flask stuff:
85 | instance/
86 | .webassets-cache
87 |
88 | # Scrapy stuff:
89 | .scrapy
90 |
91 | # Sphinx documentation
92 | docs/_build/
93 |
94 | # PyBuilder
95 | .pybuilder/
96 | target/
97 |
98 | # Jupyter Notebook
99 | .ipynb_checkpoints
100 |
101 | # IPython
102 | profile_default/
103 | ipython_config.py
104 |
105 | # pyenv
106 | # For a library or package, you might want to ignore these files since the code is
107 | # intended to run in multiple environments; otherwise, check them in:
108 | # .python-version
109 |
110 | # pipenv
111 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
112 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
113 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
114 | # install all needed dependencies.
115 | #Pipfile.lock
116 |
117 | # poetry
118 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
119 | # This is especially recommended for binary packages to ensure reproducibility, and is more
120 | # commonly ignored for libraries.
121 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
122 | #poetry.lock
123 |
124 | # pdm
125 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
126 | #pdm.lock
127 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
128 | # in version control.
129 | # https://pdm.fming.dev/#use-with-ide
130 | .pdm.toml
131 |
132 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
133 | __pypackages__/
134 |
135 | # Celery stuff
136 | celerybeat-schedule
137 | celerybeat.pid
138 |
139 | # SageMath parsed files
140 | *.sage.py
141 |
142 | # Environments
143 | .env
144 | .venv
145 | env/
146 | venv/
147 | ENV/
148 | env.bak/
149 | venv.bak/
150 |
151 | # Spyder project settings
152 | .spyderproject
153 | .spyproject
154 |
155 | # Rope project settings
156 | .ropeproject
157 |
158 | # mkdocs documentation
159 | /site
160 |
161 | # mypy
162 | .mypy_cache/
163 | .dmypy.json
164 | dmypy.json
165 |
166 | # Pyre type checker
167 | .pyre/
168 |
169 | # pytype static type analyzer
170 | .pytype/
171 |
172 | # Cython debug symbols
173 | cython_debug/
174 |
175 | # PyCharm
176 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
177 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
178 | # and can be added to the global gitignore or merged into this file. For a more nuclear
179 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
180 | #.idea/
181 | geoip2fast.backup
182 |
--------------------------------------------------------------------------------
/CHANGELOG:
--------------------------------------------------------------------------------
1 |
2 | .oPYo. o .oPYo. .oPYo. ooooo o
3 | 8 8 8 8 8 `8 8 8
4 | 8 .oPYo. .oPYo. 8 o8YooP' oP' o8oo .oPYo. .oPYo. o8P
5 | 8 oo 8oooo8 8 8 8 8 .oP' 8 .oooo8 Yb.. 8
6 | 8 8 8. 8 8 8 8 8' 8 8 8 'Yb. 8
7 | `YooP8 `Yooo' `YooP' 8 8 8ooooo 8 `YooP8 `YooP' 8
8 | :....8 :.....::.....:..:..:::::.......:..:::::.....::.....:::..:
9 | :::::8 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::
10 | :::::..:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
11 |
12 | Author: Ricardo Abuchaim - ricardoabuchaim@gmail.com
13 | https://github.com/rabuchaim/geoip2fast/
14 |
15 | License: MIT
16 |
17 | ############################################################################
18 | What's new in v1.2.2 - 20/Jun/2024
19 | - DAT files updated with MAXMIND:GeoLite2-CSV_20240618
20 | - Removed the line "sys.tracebacklimit = 0" that was causing some problems
21 | in Django. This line is unnecessary (https://github.com/rabuchaim/geoip2fast/issues/10)
22 | - There are 2 reduced versions available for you to copy and paste
23 | into your own code without any dependencies and fast as always!
24 | Check these files in your library path:
25 | - geoip2fastmin.py (429 lines)
26 | - geoip2fastminified.py (183 lines)
27 | - As requested, 2 new methods to return a coverage of IPv4 and IPv6.
28 | def get_ipv4_coverage()->float
29 | def get_ipv6_coverage()->float
30 | - New function get_database_info() that returns a dictionary with
31 | detailed information about the data file currently in use.
32 | - Made some adjustments to the --missing-ips and --coverage functions.
33 | - Now you can specify the data filename to be used on geoip2fast cli:
34 | geoip2fast geoip2fast-ipv6.dat.gz --self-test
35 | geoip2fast 9.9.9.9,1.1.1.1,2a10:8b40:: geoip2fast-asn-ipv6.dat.gz
36 | - New functions to generate random IP addresses to be used in tests.
37 | Returns a list if more than 1 IP is requested, otherwise returns a
38 | string with only 1 IP address. If you request an IPv6 and the database
39 | loaded does not have IPv6 data, returns False. And the fuction of
40 | private address, returns an random IPv4 from network 10.0.0.0/8 or
41 | 172.16.0.0/12 or 192.168.0.0/16.
42 | def generate_random_private_address(self,num_ips=1)->string or a list
43 | def generate_random_ipv4_address(self,num_ips=1)->string or a list
44 | def generate_random_ipv6_address(self,num_ips=1)->string or a list
45 | - Removed functools.lru_cache. It is very useful when you have a function
46 | that is repeated several times but takes a long time, which is not the
47 | case of GeoIP2Fast where functions take milliseconds. On each call,
48 | functools checks whether the value is already cached or not, and this
49 | takes time. And we noticed that without functools and using the processor
50 | and operating system's own cache makes GeoIP2Fast much faster without it
51 | even if you are searching for an IP for the first time.
52 | If you want to use lru_cache, you can uncomment the respective lines
53 | of code. There are 5 lines commented with @functools.lru_cache
54 | - Put some flowers
55 |
56 | What's new in v1.2.1 - 01/Dec/2023
57 | - DAT files updated with MAXMIND:GeoLite2-CSV_20231201
58 | - Improved speed! faster than ever!
59 | - Automatic updates! you can update to the newest dat.gz file via command line or via code
60 |
61 | What's new in v1.2.0 - 27/Nov/2023
62 | - DAT files updated with MAXMIND:GeoLite2-CSV_20231124
63 | - CITY NAMES SUPPORT! We are fast and complete! beard, hair and mustache!
64 | - To don´t increase the package size, the CITY files were
65 | not included in the PyPI installation. If you need city names support
66 | with/without ASN or with IPv6, you have to create by your own OR download at
67 | https://github.com/rabuchaim/geoip2fast/releases/latest
68 | - Significant changes in geoip2dat.py file. Read the new instructions!
69 | - Data files generated with version 1.1.X will no longer work in versions 1.2.X
70 | Legacy dat.gz files will continue to be created and made available twice a week
71 | at the URL https://github.com/rabuchaim/geoip2fast/releases/tag/LEGACY_v1.1.9
72 | - Changes to the "source info" information of geoip2fast.py files. Nothing for
73 | worry unless you use this information. The --source-info option
74 | still working, but it is hidden in the geoip2dat.py menu.
75 | - New property "asn_cidr"
76 | - Fix in memory usage under MacOS
77 | - When trying to load a non-existent file it now raise an exception. Previously,
78 | the default file was loaded and no message was displayed.
79 | - a new method to return the path of the dat.gz file that is currently being used
80 | from geoip2fast import GeoIP2Fast
81 | G = GeoIP2Fast(geoip2fast_data_file="/tmp/geoip2fast-asn.dat.gz")
82 | G.get_database_path()
83 |
84 | What's new in v1.1.10 - 01/Dec/2023 (LEGACY)
85 | - Automatic download of dat.gz files.
86 | try: geoip2fast --download-all
87 |
88 | What's new in v1.1.9 - 22/Nov/2023
89 | - DAT files updated with MAXMIND:GeoLite2-CSV_20231121
90 | - Fix in memory usage under MacOS
91 | - Fix a problem when loading specific datafiles
92 | - a new method to return the path of the dat.gz file that is currently being used
93 | from geoip2fast import GeoIP2Fast
94 | G = GeoIP2Fast(geoip2fast_data_file="/tmp/geoip2fast-asn.dat.gz")
95 | G.get_database_path()
96 |
97 | What's new in v1.1.8 - 14/Nov/2023
98 | - DAT files updated with MAXMIND:GeoLite2-CSV_20231114
99 | - Fix in './geoip2fast.py --coverage' test when using IPv6 database
100 |
101 | What's new in v1.1.6 - 10/Nov/2023
102 | - DAT files updated with MAXMIND:GeoLite2-CSV_20231110
103 |
104 | What's new in v1.1.5 - 03/Nov/2023
105 | - DAT files updated with MAXMIND:GeoLite2-CSV_20231103
106 | - Fully tested with Python 3.12 and Python 3.13 (> 150.000 lookups/sec)
107 | - Fixed an issue in the function that adjusts the terminal window of the
108 | geoip2dat.py file. This problem prevented the geoip2dat.py script from
109 | being executed by crontab.
110 | - Added entry_points to setup.py, now it's possible to run geoip2fast and
111 | geoip2dat as an executable under Windows. If it doesn't work, you need
112 | to add the path of your python scripts directory to your PATH environment
113 | variable.
114 | - To see the path of your scripts directory on win32, run: pip show geoip2fast
115 | - Check the "Location" information, and change the "site-packages" word
116 | to "scripts" and add this path to your PATH environment variable (google it).
117 | - After this change, you can run geoip2fast and geoip2dat from any path
118 | of your Windows command prompt. Sometimes this change is unnecessary,
119 | try running 'geoip2fast' from any path of your Win32 command prompt.
120 |
121 | What's new in v1.1.4 - 27/Oct/2023
122 | - DAT files updated with MAXMIND:GeoLite2-CSV_20231027
123 |
124 | What's new in v1.1.3 - 20/Oct/2023
125 | - DAT files updated with MAXMIND:GeoLite2-CSV_20231020
126 | - Bug fix in the coverage test of v1.1.2. Didn´t affect the search accuracy.
127 |
128 | What's new in v1.1.2 - 03/Oct/2023
129 | - DAT files updated with MAXMIND:GeoLite2-Country-ASN-CSV_20231003
130 | - IPv6 transparent support!!! the same class, you just need to choose
131 | which data file you wanna use.
132 | - fast as always! the lookup speed is the same for any data file.
133 | - removed some useless code and put some colored flowers.
134 |
135 | What's new in v1.0.6 - 01/Oct/2023
136 | - geoip2fast.dat.gz updated with MAXMIND:GeoLite2-Country-CSV_20230929
137 | - geoip2fast-asn.dat.gz updated with MAXMIND:GeoLite2-ASN-CSV_20230929
138 | - bug fix: Fail on Windows while getting a memory usage
139 | - bug fix: Error when specifying the data file manually
140 |
141 | What's new in v1.0.5 - 20/Sep/2023
142 | - geoip2fast.dat.gz updated with MAXMIND:GeoLite2-Country-ASN-CSV_20230919
143 | - faster than ever!!! a lookup around ~0.00001
144 | - A new option in geoip2dat to create .dat.gz with asn support: --asn-dir
145 | - ASN support - the dat file already has support for ASN of the network
146 | ranges. The footprint was incresed to 64Mb. The speed is the same.
147 | - If you want, you can create an another dat file only with country data,
148 | just use the option --country-dir without the option --asn-dir
149 | - geoip2dat updated too! older versions won't work anymore. Sorry.
150 | - more flowers
151 |
152 | What's new in v1.0.4 - 13/Sep/2023
153 | - geoip2fast.dat.gz updated with MAXMIND:GeoLite2-Country-CSV_20230912
154 | - fix in search of IPs that end in ".0"
155 | - fix in _locate_database() function that search dat.gz file in
156 | $current_application_file path and library path
157 | - added some cli parameters: --speed-test, --self-test, and --coverage
158 | ( try: ./geoip2fast.py --coverage -v to see all networks included in
159 | dat file. )
160 | - added a parameter in tests: --missing-ips (take care, uses 100% of CPU)
161 | - geoip2dat updated too! older versions won't work anymore. Sorry.
162 | - more flowers
163 |
164 | What's new in v1.0.3 - 08/Sep/2023
165 | - geoip2fast.dat.gz updated with MAXMIND:GeoLite2-Country-CSV_20230908
166 | - IMPROVED SPEED!! >100.000 LOOKUPS PER SECOND! GeoIP2Flash!
167 | - geoip2fast.dat.gz decreased to ONE MEGABYTE! (-60%)
168 | - RAM footprint dropped to 25 MiB! (-50%)
169 | - load time around ~0,05 seconds! (-50%)
170 | - the number of networks and content still the same, we just
171 | converted all data to integers and sliced the lists a lot! This
172 | was necessary to implement the ASN data (not yet).
173 | - geoip2dat updated to create the new dat file structure
174 | - inserted a tag in dat file to record the version.
175 | - as requested, property elapsed_time_hostname for hostnames lookups
176 |
177 | What's new in v1.0.2 - 04/Sep/2023
178 | - geoip2fast.dat.gz updated with MAXMIND:GeoLite2-Country-CSV_20230901
179 | - fully tested with Python 3.11.5. Much faster than 3.10.12 >100K lookups/sec.
180 | - fix encoding of pp_json() method. Now it's showing all chars as it is.
181 | - in verbose mode it is now showing the memory footprint.
182 | - new test files at /usr/local/lib/python3.10/dist-packages/geoip2fast/tests/
183 | - new class CIDRDetail will be used to create gepip2fast.dat file
184 | - geoip2dat - a script to import Maxmind-Country-CSV into geoip2fast.dat.gz.
185 | You can update your geoip2fast.dat.gz file whenever you want. It should work
186 | with paid version also. Please let me know if there are any problems.
187 | - put some flowers;
188 |
189 | What's new in v1.0.1 - 1º/Sep/2023
190 | - geoip2fast.dat.gz updated with MAXMIND:GeoLite2-Country-CSV_20230901
191 | - improved speed in >20%! removed ipaddress module. Now we do some IP calcs.
192 | - new methods to set the error code for the situations PRIVATE NETWORKS and for
193 | NETWORKS NOT FOUND:
194 | GeoIP2Fast.set_error_code_private_networks(new_value)
195 | GeoIP2Fast.set_error_code_network_not_found(new_value)
196 | - new method to calculate the current speed. Returns a value of current lookups per
197 | seconds or print a formatted result:
198 | GeoIP2Fast.calculate_speed(print_result=True)
199 | - new method to calculate how many IPv4 of all internet are covered by geoip2fast.dat
200 | file. Returns a percentage relative to all possible IPv4 on the internet or print a
201 | formatted result. Useful to track the changes in getip2fast.dat.gz file:
202 | GeoIP2Fast.calculate_coverage(print_result=True)
203 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | ricardoabuchaim@gmail.com.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
130 | GeoIP2Fast v1.2.2
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Ricardo Abuchaim
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GeoIP2Fast v1.2.2
2 |
3 | GeoIP2Fast is the fastest GeoIP2 country/city/asn lookup library. A search takes less than 0.00003 seconds. It has its own data file updated with Maxmind-Geolite2-CSV, supports IPv4 and IPv6, works on Python3, Pypy3 and is Pure Python!
4 |
5 | With it´s own datafile (geoip2fast.dat.gz), can be loaded into memory in ~0.07 seconds and has a small footprint for all data, so you don´t need to make requests to any webservices or connect to an external database. And it works on Linux, Windows and MacOS!
6 |
7 | And now you can download .dat.gz from your own application or via the command line. See more at [Update your database automatically](#automatic-update-of-datgz-files)
8 |
9 | GeoIP2Fast returns ASN NAME, COUNTRY ISO CODE, COUNTRY NAME, CITY NAME/STATE/DISTRICT and CIDR. There is no external dependencies, you just need the ```geoip2fast.py``` file and the desired data file ```.dat.gz```. The lookup speed is the same for any data file.
10 |
11 | ### Country and ASN databases with IPv4 and IPv6
12 |
13 | | Download Content | File Name | File Size | Load Time | RAM Footprint |
14 | | ---------- | :---------: | ---------: | --------: | ---------: |
15 | | [Country IPv4](https://github.com/rabuchaim/geoip2fast/releases/latest/download/geoip2fast.dat.gz) | ```geoip2fast.dat.gz``` | 1.2 MiB | ~0.04 sec | ~22.0 MiB |
16 | | [Country IPv4+IPv6](https://github.com/rabuchaim/geoip2fast/releases/latest/download/geoip2fast-ipv6.dat.gz) | ```geoip2fast-ipv6.dat.gz``` | 1.8 MiB | ~0.07 sec | ~41.0 MiB |
17 | | [Country+ASN IPv4](https://github.com/rabuchaim/geoip2fast/releases/latest/download/geoip2fast-asn.dat.gz) | ```geoip2fast-asn.dat.gz``` | 2.3 MiB | ~0.08 sec | ~40.0 MiB |
18 | | [Country+ASN IPv4+IPv6](https://github.com/rabuchaim/geoip2fast/releases/latest/download/geoip2fast-asn-ipv6.dat.gz) | ```geoip2fast-asn-ipv6.dat.gz``` | 3.1 MiB | ~0.15 sec | ~97.0 MiB |
19 |
20 | ### City and ASN databases with IPv4 and IPv6
21 |
22 | City databases are not included in the pip installation package, if you want to:
23 | - download them manually from [DAT Files LATEST Release](https://github.com/rabuchaim/geoip2fast/releases/LATEST)
24 | - or create them yourself using ```geoip2dat.py```. *City data already includes country data.*
25 | - or download using the new function GeoIP2Fast.update_all() [read more below](#automatic-update-of-datgz-files)
26 |
27 | | Download Content | File Name | File Size | Load Time | RAM Footprint |
28 | | ---------- | :---------: | ---------: | --------: | ---------: |
29 | | [City IPv4](https://github.com/rabuchaim/geoip2fast/releases/latest/download/geoip2fast-city.dat.gz) | ```geoip2fast-city.dat.gz``` | 12 MiB | ~0.50 sec | ~270.0 MiB |
30 | | [City IPv4+IPv6](https://github.com/rabuchaim/geoip2fast/releases/latest/download/geoip2fast-city-ipv6.dat.gz) | ```geoip2fast-city-ipv6.dat.gz``` | 14 MiB | ~0.60 sec | ~400.0 MiB |
31 | | [City+ASN IPv4](https://github.com/rabuchaim/geoip2fast/releases/latest/download/geoip2fast-city-asn.dat.gz) | ```geoip2fast-city-asn.dat.gz``` | 13 MiB | ~0.60 sec | ~310.0 MiB |
32 | | [City+ASN IPv4+IPv6](https://github.com/rabuchaim/geoip2fast/releases/latest/download/geoip2fast-city-asn-ipv6.dat.gz) | ```geoip2fast-city-asn-ipv6.dat.gz``` | 17 MiB | ~0.70 sec | ~430.0 MiB |
33 |
34 | > *If you are using pypy3, the loading time will increase a little, but the speed will be a little faster and the memory footprint will be lower.*
35 |
36 | **The new v1.2.X databases are not compatible with versions equal to or older than v1.1.X, and vice versa, obviously. The last version with support only for countries and ASN only is v1.1.X, which is still available with this command line: ```pip install geoip2fast==1.1.10```.**
37 |
38 | ```
39 | What's new in v1.2.2 - 20/Jun/2024
40 | - DAT files updated with MAXMIND:GeoLite2-CSV_20240618
41 | - Removed the line "sys.tracebacklimit = 0" that was causing some problems
42 | in Django. This line is unnecessary (https://github.com/rabuchaim/geoip2fast/issues/10)
43 | - Maxmind inserted a new field into the CSV files called "is_anycast", and this broke
44 | geoip2dat.py CSV reader. Insertion of the new field in the list of "fields" of
45 | the CSV reader that generates the .dat.gz files so that they can be updated.
46 |
47 | - There are 2 reduced versions available for you to copy and paste
48 | into your own code without any dependencies and fast as always!
49 | Check these files in your library path:
50 | - geoip2fastmin.py (429 lines)
51 | - geoip2fastminified.py (183 lines)
52 | It's in testing, but please open an issue if you have any problems
53 | with either of these 2 versions.
54 |
55 | - Removed functools.lru_cache. It is very useful when you have a function
56 | that is repeated several times but takes a long time, which is not the
57 | case of GeoIP2Fast where functions take milliseconds. On each call,
58 | functools checks whether the value is already cached or not, and this
59 | takes time. And we noticed that without functools and using the processor
60 | and operating system's own cache makes GeoIP2Fast much faster without it
61 | even if you are searching for an IP for the first time.
62 | You can run tests and you will see that without functools.lru_cache
63 | it is faster. If you want to use lru_cache, you can uncomment the
64 | respective lines of code. There are 5 lines commented with @functools.lru_cache
65 |
66 | - As requested, 2 new methods to return a coverage of IPv4 and IPv6.
67 | def get_ipv4_coverage()->float
68 | def get_ipv6_coverage()->float
69 |
70 | - New function get_database_info() that returns a dictionary with
71 | detailed information about the data file currently in use.
72 |
73 | - Made some adjustments to the --missing-ips and --coverage functions.
74 |
75 | - Now you can specify the data filename to be used on geoip2fast cli:
76 | geoip2fast geoip2fast-ipv6.dat.gz --self-test
77 | geoip2fast 9.9.9.9,1.1.1.1,2a10:8b40:: geoip2fast-asn-ipv6.dat.gz
78 |
79 | - New functions to generate random IP addresses to be used in tests.
80 | Returns a list if more than 1 IP is requested, otherwise returns a
81 | string with only 1 IP address. If you request an IPv6 and the database
82 | loaded does not have IPv6 data, returns False. And the fuction of
83 | private address, returns an random IPv4 from network 10.0.0.0/8 or
84 | 172.16.0.0/12 or 192.168.0.0/16.
85 | def generate_random_private_address(self,num_ips=1)->string or a list
86 | def generate_random_ipv4_address(self,num_ips=1)->string or a list
87 | def generate_random_ipv6_address(self,num_ips=1)->string or a list
88 |
89 | - Put some flowers
90 |
91 | ```
92 |
93 |
94 | 
95 |
96 |
97 |
98 | ## Installation
99 | ```bash
100 | pip install geoip2fast
101 | ```
102 |
103 |
104 | ## DAT files updates
105 |
106 | - You can create your own dat.gz file using [geoip2dat.py](#geoip2dat---update-geoip2fastdatgz-file-anytime) file.
107 | - You can also [download the latest dat files](https://github.com/rabuchaim/geoip2fast/releases/tag/LATEST) that are updated automatically on Tuesdays and Fridays
108 | - And you can [update the dat files downloading from our releases repository](#automatic-update-of-datgz-files), via code or via command line.
109 |
110 |
111 |
112 | ## How does it work?
113 |
114 | GeoIP2Fast has 4 datafiles included. Tha main file is ```geoip2fast.dat.gz``` with support Country lookups and only IPv4. Usually, these files are located into the library directory (```/usr/local/lib/python3.XX/dist-packages/geoip2fast```), but you can place it into the same directory of your application. The library automatically checks both paths, And the directory of your application overlaps the directory of the library. You can use an specific location also.
115 |
116 | The ```bisect()``` function is used together with some ordered lists of integers to search the Network/CountryCode (Yes! an IP address has an integer representation, try to ping this number: ```ping 134744072``` or this ```ping 2130706433``` ).
117 |
118 | If GeoIP2Fast does not have a network IP address that was requested, a "not found in database" error will be returned. Unlike many other libraries that when not finding a requested network, gives you the geographical location of the network immediately below. The result is not always correct.
119 |
120 | Data file updates are made available twice a week in our [github releases](https://github.com/rabuchaim/geoip2fast/releases/latest). Files with City data and IPv6 support can also be downloaded there.
121 |
122 | There are network gaps in the files we use as a source of data, and these missing networks are probably addresses that those responsible have not yet declared their location. Of all IPv4 on the internet (almost 4.3 billions IPs), our coverage is around 99.64% and we do not have information on approximately 15 million of them (~0,36%). It must be remembered that the geographical accuracy is the responsibility of the network block owners. If the owner (aka ASN) of the XXX.YYY.ZZZ.D/24 network range declares that his network range is located at "Foo Island", we must believe that an IP address of that network is there.
123 |
124 | > *Don't go to Foo Island visit a girl you met on the internet just because you looked up her IP on GeoIP2Fast and the result indicated that she is there.*
125 |
126 |
127 |
128 | ## Quick Start
129 |
130 | Once the object is created, GeoIP2Fast loads automatically all needed data into memory. The lookup function returns an object called ```GeoIPDetail```. And you can get the values of it's properties just calling the name of proprerty: ```result.ip```, ```result.country_code```, ```result.country_name```, ```result.city.name```, ```result.city.subsubdivision_code```, ```result.city.subsubdivision_name```, ```result.cidr```, ```result.is_private```, ```result.asn_name```,```result.asn_cidr``` and ```result.elapsed_time```. Or use the function ```to_dict()``` to get the result as a dict. You can get values like ```result.to_dict()['country_code']```
131 |
132 | When using it as a Python library, if you want to load a file other than ```geoip2fast.dat.gz```, you simply create the object by typing the name of the file you want to work with. The library first looks for the given file in the current directory and then in the library directory. If desired, you can directly specify the path. If don´t specify any file, the default ```geoip2fast.dat.gz``` will be used. Example:
133 |
134 | ```python
135 | >>> from geoip2fast import GeoIP2Fast
136 | >>> geoip = GeoIP2Fast(geoip2fast_data_file="/my_data_files_path/geoip2fast-city-asn-ipv6.dat.gz",verbose=True)
137 | GeoIP2Fast v1.2.1 is ready! geoip2fast-city-asn-ipv6.dat.gz loaded with 4.488.721 networks in 0.54506 seconds and using 426.28 MiB.
138 | >>> print(geoip.lookup("191.251.128.1").pp_json())
139 | {
140 | "ip": "191.251.128.1",
141 | "country_code": "BR",
142 | "country_name": "Brazil",
143 | "city": {
144 | "name": "Araraquara",
145 | "subdivision_code": "SP",
146 | "subdivision_name": "Sao Paulo"
147 | },
148 | "cidr": "191.251.128.0/20",
149 | "hostname": "",
150 | "asn_name": "TELEFONICA BRASIL S.A",
151 | "asn_cidr": "191.250.0.0/15",
152 | "is_private": false,
153 | "elapsed_time": "0.000147356 sec"
154 | }
155 | >>> geoip.get_database_path()
156 | '/my_data_files_path/geoip2fast-city-asn-ipv6.dat.gz'
157 | >>>
158 | >>> result = geoip.lookup("3.2.35.65")
159 | >>> result.city.name
160 | 'São Paulo'
161 | >>> result.city.subdivision1_code
162 | 'SP'
163 | >>> result.country_name
164 | 'Brazil'
165 | >>> result.country_code
166 | 'BR'
167 | >>> result.asn_name
168 | 'AMAZON-02'
169 | >>> result.elapsed_time
170 | '0.000011612 sec'
171 | >>>
172 | >>> result = geoip.lookup("10.20.30.40")
173 | >>> result.country_name
174 | 'Private Network Class A'
175 | >>> result.cidr
176 | '10.0.0.0/8'
177 | >>> result.is_private
178 | True
179 | >>>
180 | ```
181 |
182 |
183 | ```python
184 | from geoip2fast import GeoIP2Fast
185 |
186 | GEOIP = GeoIP2Fast()
187 | result = GEOIP.lookup("200.204.0.10")
188 | print(result)
189 |
190 | # to use the country_code property
191 | print(result.country_code)
192 |
193 | # to print the ASN name property
194 | print(result.asn_name)
195 |
196 | # Before call the function get_hostname(), the property hostname will always be empty.
197 | print("Hostname: "+result.hostname)
198 | result.get_hostname()
199 | print("Hostname: "+result.hostname)
200 |
201 | # to work with output as a dict, use the function to_dict()
202 | print(result.to_dict()['country_code'],result.to_dict()['country_name'])
203 |
204 | # to check the date of the CSV files used to create the .dat file
205 | print(GEOIP.get_source_info())
206 |
207 | # to show the path of current loaded dat file
208 | print(GEOIP.get_database_path())
209 |
210 | # info about internal cache
211 | print(GEOIP.cache_info())
212 |
213 | # clear the internal cache
214 | print(GEOIP.clear_cache())
215 |
216 | # to see the difference after clear cache
217 | print(GEOIP.cache_info())
218 | ```
219 | There is a method to pretty print the result as json.dumps():
220 | ```python
221 | >>> result = MyGeoIP.lookup("191.251.128.1")
222 | >>> print(result.pp_json())
223 | {
224 | "ip": "191.251.128.1",
225 | "country_code": "BR",
226 | "country_name": "Brazil",
227 | "city": {
228 | "name": "Araraquara",
229 | "subdivision_code": "SP",
230 | "subdivision_name": "Sao Paulo"
231 | },
232 | "cidr": "191.251.128.0/20",
233 | "hostname": "",
234 | "asn_name": "TELEFONICA BRASIL S.A",
235 | "asn_cidr": "191.250.0.0/15",
236 | "is_private": false,
237 | "elapsed_time": "0.000147356 sec"
238 | }
239 | ```
240 | or simply: ```result.pp_json(print_result=True)```
241 |
242 | To see the start-up line without set ```verbose=True``` :
243 | ```python
244 | >>> from geoip2fast import GeoIP2Fast
245 | >>> G = GeoIP2Fast()
246 | >>> G.startup_line_text
247 | 'GeoIP2Fast v1.2.0 is ready! geoip2fast.dat.gz loaded with 459.270 networks in 0.03393 seconds and using 25.25 MiB.'
248 | >>>
249 | ```
250 |
251 | Private/Reserved networks were included in the database just to be able to provide an answer if one of these IPs is searched. When it happens, the country_code will return "--", the "network name" will be displayed in the country_name and the range of that network will be displayed in the cidr property, and the property **is_private** is setted to **True**.
252 |
253 | ```python
254 | >>> from geoip2fast import GeoIP2Fast
255 | >>> geoip = GeoIP2Fast(verbose=True)
256 | 'GeoIP2Fast v1.2.0 is ready! geoip2fast.dat.gz loaded with 459.270 networks in 0.03393 seconds and using 25.25 MiB.'
257 | >>>
258 | >>> G.lookup("10.20.30.40")
259 | {'ip': '10.20.30.40', 'country_code': '--', 'country_name': 'Private Network Class A', 'cidr': '10.0.0.0/8', 'hostname': '', 'asn_name': 'IANA.ORG', 'asn_cidr': '10.0.0.0/8', 'is_private': True, 'elapsed_time': '0.000015946 sec'}
260 | >>> G.lookup("169.254.10.20")
261 | {'ip': '169.254.10.20', 'country_code': '--', 'country_name': 'APIPA Automatic Priv.IP Addressing', 'cidr': '169.254.0.0/16', 'hostname': '', 'asn_name': 'IANA.ORG', 'asn_cidr': '169.254.0.0/16', 'is_private': True, 'elapsed_time': '0.000093106 sec'}
262 | >>>
263 | ```
264 |
265 | You can change the behavior of what will be returned in country_code property of "private networks" and for "networks not found":
266 |
267 | ```python
268 | >>> from geoip2fast import GeoIP2Fast
269 | >>> G = GeoIP2Fast()
270 | >>> G.set_error_code_private_networks("@@")
271 | '@@'
272 | >>> G.lookup("10.20.30.40")
273 | {'ip': '10.20.30.40', 'country_code': '@@', 'country_name': 'Private Network Class A', 'cidr': '10.0.0.0/8', 'hostname': '', 'asn_name': 'IANA.ORG', 'asn_cidr': '10.0.0.0/8', 'is_private': True, 'elapsed_time': '0.000144236 sec'}
274 | >>>
275 | >>> G.set_error_code_network_not_found("##")
276 | '##'
277 | >>> G.lookup("23.142.129.0")
278 | {'ip': '23.142.129.0', 'country_code': '##', 'country_name': '', 'cidr': '', 'hostname': '', 'asn_name': '', 'asn_cidr': '', 'is_private': False, 'elapsed_time': '0.000012352 sec'}
279 | >>>
280 | ```
281 | You can use it as a CLI also from any path:
282 |
283 | ```bash
284 | # geoip2fast
285 | GeoIP2Fast v1.2.0 Usage: geoip2fast.py [-h] [-v] [-d] ,,,...
286 | # geoip2fast 9.9.9.9,15.20.25.30 -d
287 | {
288 | "ip": "9.9.9.9",
289 | "country_code": "US",
290 | "country_name": "United States",
291 | "cidr": "9.9.9.9/32",
292 | "hostname": "dns9.quad9.net",
293 | "asn_name": "",
294 | "asn_cidr": "",
295 | "is_private": false,
296 | "elapsed_time": "0.000034214 sec",
297 | "elapsed_time_hostname": "0.001079759 sec"
298 | }
299 | {
300 | "ip": "15.20.25.30",
301 | "country_code": "US",
302 | "country_name": "United States",
303 | "cidr": "15.0.0.0/10",
304 | "hostname": "",
305 | "asn_name": "",
306 | "asn_cidr": "",
307 | "is_private": false,
308 | "elapsed_time": "0.000022537 sec"
309 | }
310 | # geoip2fast "2.3.4.5, 4.5.6.7, 8.9.10.11" | jq -r '.country_code'
311 | FR
312 | US
313 | US
314 | # geoip2fast 8.8.8.8,1.1.1.1,200.204.0.10 -d | jq -r '.hostname'
315 | dns.google
316 | one.one.one.one
317 | resolver1.telesp.net.br
318 | ```
319 |
320 | ## How fast is it?
321 |
322 | With an virtual machine with 1 CPU and 4Gb of RAM, we have lookups **lower than 0,00003 seconds**. And if the lookup still in library´s internal cache, the elapsed time goes down to 0,000003 seconds. **GeoIP2Fast can do more than 100K queries per second, per core**. It takes less than 0,07 seconds to load the datafile into memory and get ready to lookup. Use ```verbose=True``` to create the object GeoIP2Fast to see the spent time to start.
323 |
324 | Now some tests are included in the geoip2fast.py file.
325 |
326 | ```bash
327 | # geoip2fast -h
328 | GeoIP2Fast v1.2.2 Usage: geoip2fast.py [-h] [-v] [-d] ,,,...
329 |
330 | Tests parameters:
331 | --self-test Starts a self-test with some randomic IP addresses.
332 | --self-test-city Starts a self-test with some randomic IP addresses and with city names support.
333 | --speed-test Do a speed test with 1 million on randomic IP addresses.
334 | --random-test Start a test with 1.000.000 of randomic IPs and calculate a lookup average time.
335 |
336 | --coverage [-v] Shows a statistic of how many IPs are covered by current dat file.
337 | --missing-ips [-v] Print all IP networks that doesn't have geo information (only for IPv4).
338 |
339 | Automatic update:
340 | --update-all [-v] Download all dat.gz files available in the repository below:
341 | https://github.com/rabuchaim/geoip2fast/releases/download/LATEST/
342 |
343 | --update-file [-v]
344 | Download a specific filename from the repository. Only one file is allowed.
345 | Allowed values are: geoip2fast.dat.gz OR geoip2fast-ipv6.dat.gz OR
346 | geoip2fast-asn.dat.gz OR geoip2fast-asn-ipv6.dat.gz OR
347 | geoip2fast-city.dat.gz OR geoip2fast-city-ipv6.dat.gz OR
348 | geoip2fast-city-asn.dat.gz OR geoip2fast-city-asn-ipv6.dat.gz
349 |
350 | --dest [-v]
351 | Specify the destination directory for the downloaded files. When combined with
352 | the '--update-file' parameter, you can specify an existing directory, with or
353 | without a file name, or you can just specify a file name. In the absence of
354 | this parameter or directory information, the library directory will be used
355 | as default value. This parameter is optional. The filename must end
356 | with .dat.gz extension.
357 |
358 | Use the verbose parameter (-v) if you want to see the download progress,
359 | otherwise there will be no output. You also have to use this parameter
360 | to view possible errors in your console.
361 |
362 | More options:
363 | -d Resolve the DNS of given IP address.
364 | -h Show this help text.
365 | -v Verbose mode.
366 | -vvv Shows the location of current dat file in use.
367 | ```
368 |
369 | ```geoip2fast --self-test```
370 | ```bash
371 | # geoip2fast --self-test
372 | GeoIP2Fast v1.2.0 is ready! geoip2fast.dat.gz loaded with 459.270 networks in 0.09268 seconds and using 71.04 MiB.
373 |
374 | Starting a self-test...
375 |
376 | > 266.266.266.266 [0.000018189 sec] Cached > [0.000003038 sec]
377 | > 192,0x0/32 [0.000002468 sec] Cached > [0.000001868 sec]
378 | > 10.20.30.40 -- Private Network Class A [0.000020032 sec] Cached > [0.000001231 sec] IANA.ORG
379 | > 38.174.13.98 CA Canada [0.000015079 sec] Cached > [0.000001414 sec] AS-NSL-261
380 | > 102.195.139.98 -- [0.000004650 sec] Cached > [0.000000471 sec]
381 | > 139.5.38.161 IN India [0.000012635 sec] Cached > [0.000000845 sec] Five network Broadband Solution Pvt Ltd
382 | > 4.219.112.222 NO Norway [0.000009926 sec] Cached > [0.000000727 sec] MICROSOFT-CORP-MSN-AS-BLOCK
383 | > 137.44.167.24 GB United Kingdom [0.000009575 sec] Cached > [0.000000663 sec] Jisc Services Limited
384 | > 28.92.226.103 US United States [0.000009599 sec] Cached > [0.000000605 sec] DNIC-AS-00749
385 | > 180.115.120.126 CN China [0.000010468 sec] Cached > [0.000000702 sec] Chinanet
386 | (.....)
387 | ```
388 |
389 | ```geoip2fast --speed-test```
390 | ```bash
391 | # geoip2fast --speed-test
392 | GeoIP2Fast v1.2.0 is ready! geoip2fast.dat.gz loaded with 459.270 networks in 0.09292 seconds and using 71.05 MiB.
393 |
394 | Calculating current speed... wait a few seconds please...
395 |
396 | Current speed: 143159.49 lookups per second (1.000.000 IPs with an average of 0.000006985 seconds per lookup) [6.98522 sec]
397 | ```
398 |
399 | ```geoip2fast --coverage```
400 | ```bash
401 | # geoip2fast --coverage
402 | GeoIP2Fast v1.2.0 is ready! geoip2fast.dat.gz loaded with 4.488.723 networks in 0.47685 seconds and using 408.66 MiB.
403 |
404 | Use the parameter '-v' to see all networks included in your /opt/geoip2fast/geoip2fast/geoip2fast.dat.gz file.
405 |
406 | Current IPv4 coverage: 99.64% (4.279.552.038 IPv4 in 3.246.406 networks) [0.59747 sec]
407 | Current IPv6 coverage: 0.40% (1.364.444.943.175.748.876.962.337.373.462.462.464 IPv6 in 1.242.317 networks) [0.59747 sec]
408 | ```
409 | ```geoip2fast --coverage -v```
410 | ```bash
411 | # geoip2fast --coverage -v
412 | GeoIP2Fast v1.2.0 is ready! geoip2fast.dat.gz loaded with 753.871 networks in 0.13392 seconds and using 103.54 MiB.
413 |
414 | Use the parameter '-v' to see all networks included in your /usr/local/lib/python3.11/dist-packages/geoip2fast/geoip2fast.dat.gz file.
415 |
416 | - Network: 0.0.0.0/8 IPs: 16777216 -- Reserved for self identification 0.000042983 sec
417 | - Network: 1.0.0.0/24 IPs: 256 AU Australia 0.000017615 sec
418 | - Network: 1.0.1.0/24 IPs: 256 CN China 0.000011633 sec
419 | - Network: 1.0.2.0/23 IPs: 512 CN China 0.000009464 sec
420 | - Network: 1.0.4.0/22 IPs: 1024 AU Australia 0.000008925 sec
421 | (.....)
422 | - Network: 2c0f:ffc0::/32 IPs: 79228162514264337593543950336 ZA South Africa 0.000026057 sec
423 | - Network: 2c0f:ffc8::/32 IPs: 79228162514264337593543950336 ZA South Africa 0.000028565 sec
424 | - Network: 2c0f:ffd0::/32 IPs: 79228162514264337593543950336 ZA South Africa 0.000026283 sec
425 | - Network: 2c0f:ffd8::/32 IPs: 79228162514264337593543950336 ZA South Africa 0.000026832 sec
426 | - Network: 2c0f:ffe8::/32 IPs: 79228162514264337593543950336 NG Nigeria 0.000027137 sec
427 | - Network: 2c0f:fff0::/32 IPs: 79228162514264337593543950336 NG Nigeria 0.000028008 sec
428 | - Network: fd00::/8 IPs: 1329227995784915872903807060280344576 -- Reserved for Unique Local Addresses 0.000031203 sec
429 |
430 | Current IPv4 coverage: 99.64% (4.279.420.966 IPv4 in 459.270 networks) [64.13669 sec]
431 | Current IPv6 coverage: 0.40% (1.364.444.943.175.748.876.962.337.373.462.462.464 IPv6 in 294.601 networks) [64.13669 sec]
432 | ```
433 |
434 | ```geoip2fast --missing-ips```
435 | ```bash
436 | # geoip2fast --missing-ips
437 | GeoIP2Fast v1.2.0 is ready! geoip2fast.dat.gz loaded with 753.871 networks in 0.13392 seconds and using 103.54 MiB.
438 |
439 | Searching for missing IPs...
440 |
441 | From 1.34.65.179 to 1.34.65.179 > Network 1.34.65.180/32 > Missing IPs: 1
442 | From 1.46.23.235 to 1.46.23.235 > Network 1.46.23.236/32 > Missing IPs: 1
443 | From 2.12.211.171 to 2.12.211.171 > Network 2.12.211.172/32 > Missing IPs: 1
444 | (.....)
445 | From 220.158.148.0 to 220.158.151.255 > Network 220.158.152.0/22 > Missing IPs: 1024
446 | From 223.165.0.0 to 223.165.3.255 > Network 223.165.4.0/22 > Missing IPs: 1024
447 |
448 | >>> Valid IP addresses without geo information: 15.551.441 (0.36% of all IPv4) [27.17811 sec]
449 | ```
450 | > Some IPs are excluded as described in page "Do Not Sell My Personal Information Requests" at Maxmind website.
451 |
452 |
453 |
454 | ## GeoIP2Dat - update geoip2fast.dat.gz file anytime
455 |
456 | The updates of geoip2fast.dat.gz file will be published twice a week on Github https://github.com/rabuchaim/geoip2fast/releases/LATEST. You can also create your own dat file whenever you want, see instructions below.
457 |
458 | Download the Geolite2 (COUNTRY, CITY and ASN) CSV files from Maxmind website and place it into some diretory (in this example, was placed into ```/opt/maxmind/```). Extract all zip files in this directory and run ```geoip2dat``` to see the options.
459 |
460 | 
461 |
462 | 
463 |
464 | The options \(```--country-dir``` OR ```--city-dir```\) AND ```--output-dir``` are mandatory. Specify the path of extracted files in ```--country-dir``` or ```--city-dir``` option. And for ```--output-dir```, put the current path ```./```.
465 |
466 | If you want to add support for ASN data, add the option ```--asn-dir```. And if you want to add IPv6 support, just add ```--with-ipv6``` to your command line.
467 |
468 | You can choose the language of country locations. The default is ```en```.
469 |
470 | After creation of ```geoip2dat.dat.gz``` file, move or copy this file to the directory of your application or to the directory of GeoIP2Fast library. You choose.
471 |
472 | 
473 |
474 | **From now you don't depend on anyone to have your data file updated.** There's no point the code being open-source if you're dependent of a single file.
475 |
476 | > *The Philosophers call it 'Libertas'*
477 |
478 |
479 |
480 | ## Automatic update of dat.gz files
481 |
482 | From version v1.2.1 onwards, it is now possible to update the dat.gz files that were made available in our releases repository. You can update via command line or via code.
483 |
484 | - Download the file "geoip2fast-asn-ipv6.dat.gz" and save it as "geoip2fast.dat.gz":
485 |
486 | ```python
487 | >>> from geoip2fast import GeoIP2Fast
488 | >>> G = GeoIP2Fast(verbose=True)
489 | GeoIP2Fast v1.2.1 is ready! geoip2fast.dat.gz loaded with 459270 networks in 0.03297 seconds and using 25.12 MiB.
490 | >>> update_result = G.update_file('geoip2fast-asn-ipv6.dat.gz','geoip2fast.dat.gz',verbose=False)
491 | >>> G.reload_data(verbose=True)
492 | GeoIP2Fast v1.2.1 is ready! geoip2fast.dat.gz loaded with 753871 networks in 0.12917 seconds and using 113.54 MiBTrue
493 | >>>
494 | ```
495 | - Update all files:
496 |
497 | ```python
498 | >>> from geoip2fast import GeoIP2Fast
499 | >>> G = GeoIP2Fast()
500 | >>> update_result = G.update_all(verbose=True)
501 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LATEST/geoip2fast.dat.gz
502 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
503 | - Downloading geoip2fast.dat.gz... 100.00% of 1.06 MiB [6.51 MiB/s] [0.163 sec]
504 | - File saved to: /opt/geoip2fast/geoip2fast-legacy/geoip2fast/geoip2fast.dat.gz
505 |
506 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LATEST/geoip2fast-ipv6.dat.gz
507 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
508 | - Downloading geoip2fast-ipv6.dat.gz... 100.00% of 1.73 MiB [9.66 MiB/s] [0.179 sec]
509 | - File saved to: /opt/geoip2fast/geoip2fast-legacy/geoip2fast/geoip2fast-ipv6.dat.gz
510 |
511 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LATEST/geoip2fast-asn.dat.gz
512 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
513 | - Downloading geoip2fast-asn.dat.gz... 100.00% of 3.06 MiB [8.63 MiB/s] [0.354 sec]
514 | - File saved to: /opt/geoip2fast/geoip2fast-legacy/geoip2fast/geoip2fast-asn.dat.gz
515 |
516 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LATEST/geoip2fast-asn-ipv6.dat.gz
517 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
518 | - Downloading geoip2fast-asn-ipv6.dat.gz... 100.00% of 4.09 MiB [7.66 MiB/s] [0.534 sec]
519 | - File saved to: /opt/geoip2fast/geoip2fast-legacy/geoip2fast/geoip2fast-asn-ipv6.dat.gz
520 | >>>
521 | ```
522 | - Update all files silently and verify if there are errors:
523 | ```python
524 | >>> from geoip2fast import GeoIP2Fast
525 | >>> G = GeoIP2Fast()
526 | >>> update_result = G.update_all(verbose=False)
527 | >>> errors_result = [item for item in update_result if item['error'] is not None]
528 | >>> print(errors_result)
529 | []
530 | ```
531 | - You can change the update URL if you want.
532 | ```
533 | >>> G.get_update_url()
534 | 'https://github.com/rabuchaim/geoip2fast/releases/download/LATEST/'
535 | >>> G.set_update_url("https://github.com/YOUR_OWN_REPO/YOUR_PROJECT/releases/download/latest/")
536 | True
537 | >>> G.get_update_url()
538 | 'https://github.com/YOUR_OWN_REPO/YOUR_PROJECT/releases/download/latest/'
539 | >>>
540 | ```
541 | - Update the file "geoip2fast-asn-ipv6.dat.gz" and overwrite "geoip2fast.dat.gz" and print the result.
542 | ```python
543 | >>> from geoip2fast import GeoIP2Fast
544 | >>> G = GeoIP2Fast(verbose=True)
545 | GeoIP2Fast v1.2.1 is ready! geoip2fast.dat.gz loaded with 459270 networks in 0.04414 seconds and using 5.02 MiB.
546 | >>> update_result = G.update_file('geoip2fast-asn-ipv6.dat.gz','geoip2fast.dat.gz',verbose=False)
547 | >>> from pprint import pprint as pp
548 | >>> pp(update_result,sort_dicts=False)
549 | {'error': None,
550 | 'url': 'https://github.com/rabuchaim/geoip2fast/releases/download/LATEST/geoip2fast-asn-ipv6.dat.gz',
551 | 'remote_filename': 'geoip2fast-asn-ipv6.dat.gz',
552 | 'last_modified_date': 'Mon, 27 Nov 2023 02:40:08 GMT',
553 | 'file_size': 4289564,
554 | 'file_destination': '/opt/geoip2fast/geoip2fast-legacy/geoip2fast/geoip2fast.dat.gz',
555 | 'average_download_speed': '4.09 MiB/sec',
556 | 'elapsed_time': '0.587267'}
557 | >>>
558 | >>> G.reload_data(verbose=True)
559 | GeoIP2Fast v1.2.1 is ready! geoip2fast.dat.gz loaded with 753871 networks in 0.12245 seconds and using 57.55 MiB.
560 | >>>
561 |
562 | ```
563 | - **Using the command line, no message will be displayed on the console unless you use the -v parameter**
564 | - Update all files via command line and save them in '/tmp/' directory:
565 | ```bash
566 | # geoip2fast --update-all --dest /tmp/ -v
567 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LATEST/geoip2fast.dat.gz
568 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
569 | - Downloading geoip2fast.dat.gz... 100.00% of 1.06 MiB [10.41 MiB/s] [0.102 sec]
570 | - File saved to: /tmp/geoip2fast.dat.gz
571 |
572 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LATEST/geoip2fast-ipv6.dat.gz
573 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
574 | - Downloading geoip2fast-ipv6.dat.gz... 100.00% of 1.73 MiB [9.46 MiB/s] [0.183 sec]
575 | - File saved to: /tmp/geoip2fast-ipv6.dat.gz
576 |
577 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LATEST/geoip2fast-asn.dat.gz
578 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
579 | - Downloading geoip2fast-asn.dat.gz... 100.00% of 3.06 MiB [7.06 MiB/s] [0.433 sec]
580 | - File saved to: /tmp/geoip2fast-asn.dat.gz
581 |
582 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LATEST/geoip2fast-asn-ipv6.dat.gz
583 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
584 | - Downloading geoip2fast-asn-ipv6.dat.gz... 100.00% of 4.09 MiB [7.31 MiB/s] [0.560 sec]
585 | - File saved to: /tmp/geoip2fast-asn-ipv6.dat.gz
586 | ```
587 | - Update the file "geoip2fast-asn-ipv6.dat.gz" and overwrite "geoip2fast.dat.gz"
588 | ```bash
589 | # geoip2fast --update-file geoip2fast-asn-ipv6.dat.gz --dest geoip2fast.dat.gz -v
590 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LATEST/geoip2fast-asn-ipv6.dat.gz
591 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
592 | - Downloading geoip2fast-asn-ipv6.dat.gz... 100.00% of 4.09 MiB [4.29 MiB/s] [0.954 sec]
593 | - File saved to: /opt/geoip2fast/geoip2fast-legacy/geoip2fast/geoip2fast.dat.gz
594 | ```
595 | - Update the file "geoip2fast.dat.gz" and save it in the library path
596 | ```bash
597 | # geoip2fast --update-file geoip2fast.dat.gz -v
598 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LATEST/geoip2fast.dat.gz
599 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
600 | - Downloading geoip2fast.dat.gz... 100.00% of 1.06 MiB [9.54 MiB/s] [0.111 sec]
601 | - File saved to: /opt/geoip2fast/geoip2fast-legacy/geoip2fast/geoip2fast.dat.gz
602 | ```
603 | - Update the file "geoip2fast.dat.gz" and save it in the library path
604 |
605 | ```bash
606 | # geoip2fast --update-file geoip2fast.dat.gz
607 | # echo $?
608 | 0
609 | ```
610 | - An example of a simulated download failure:
611 | ```bash
612 | # geoip2fast.py --update-file geoip2fast.dat.gz -v
613 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/A_LATEST/geoip2fast.dat.gz
614 | - Error: HTTP Error 404: Not Found - https://github.com/rabuchaim/geoip2fast/releases/download/A_LATEST/geoip2fast.dat.gz
615 | # echo $?
616 | 1
617 | ```
618 | ```bash
619 | # geoip2fast.py --update-file geoip2fast.dat.gz -v
620 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LATEST/geoip2fast.dat.gz
621 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
622 | PermissionError: [Errno 1] Operation not permitted: '/opt/geoip2fast/geoip2fast-legacy/geoip2fast/geoip2fast.dat.gz'
623 | # echo $?
624 | 1
625 | ```
626 |
627 |
628 |
629 | ## Using your own networks
630 |
631 | I´m planning to create an option to include your own networks in the database. For example, imagine you have a large private network on AWS, and each subnet is in a different region. You will be able to include them in the database to use GeoIP2Fast in your application. For now, you can edit the **reservedNetworks** variable at the beginning of the ```geoip2dat.py``` file and then generate your own data file.
632 |
633 | Suggestions and ideas are welcome. The initial idea is to include an option ```--include-networks``` in ```geoip2dat.py``` where you enter a json file.
634 |
635 |
636 |
637 | ## Create your own GeoIP CLI with 6 lines
638 |
639 | 1. Create a file named ```geoipcli.py``` and save it in your home directory with the text below:
640 | ```python
641 | #!/usr/bin/env python3
642 | import os, sys, geoip2fast
643 | if len(sys.argv) > 1 and sys.argv[1] is not None:
644 | geoip2fast.GeoIP2Fast().lookup(sys.argv[1]).pp_json(print_result=True)
645 | else:
646 | print(f"Usage: {os.path.basename(__file__)} ")
647 | ```
648 | 2. Give execution permisstion to your file and create a symbolic link to your new file into ```/usr/sbin``` folder, like this (let's assume that you saved this file into directory ```/root```)
649 | ```bash
650 | chmod 750 /root/geoipcli.py
651 | ln -s /root/geoipcli.py /usr/sbin/geoipcli
652 | ```
653 | 3. Now, you just need to call ```geoipcli``` from any path.
654 | ```bash
655 | # geoipcli
656 | Usage: geoipcli
657 | # geoipcli 1.2.3.4
658 | {
659 | "ip": "1.2.3.4",
660 | "country_code": "AU",
661 | "country_name": "Australia",
662 | "cidr": "1.2.3.0/24",
663 | "hostname": "",
664 | "is_private": false,
665 | "elapsed_time": "0.000019727 sec"
666 | }
667 | ```
668 |
669 |
670 | ## GeoIP libraries that inspired me
671 |
672 | **GeoIP2Nation - https://pypi.org/project/geoip2nation/** (Created by Avi Asher)
673 |
674 | This library uses sqlite3 in-memory tables and use the same search concepts as GeoIP2Fast (based on search by the first´s IPs). Simple and fast! Unfortunately it is no longer being updated and that is why I developed GeoIP2Fast.
675 |
676 | **GeoIP2 - https://pypi.org/project/geoip2/** (Created by Maxmind)
677 |
678 | This is the best library to work with Maxmind paid subscription or with the free version. You can use http requests to Maxmind services or work with local Maxmind MMDB binary files. Pretty fast too. Sign-up to have access to all files of the free version https://dev.maxmind.com/geoip/geolite2-free-geolocation-data
679 |
680 | **\* Maxmind is a registered trademark** - https://www.maxmind.com
681 |
682 | ## TO DO list
683 | - a GeoIP2Fast Server that supports our dat.gz and any kind of mmdb file; **<<< In final tests! the FASTORNADO Server **
684 | - a version to support any kind of MMDB file with coordinates and more; **<<< ON THE WAY! **
685 | - a better manual, maybe at readthedocs.io;
686 | - a mod_geoip2fast for NGINX;
687 | - **Done in v1.1.10/v1.2.1** - automatic update of dat.gz files;
688 | - **Done in v1.2.0** - a version with cities;
689 | - **Done in v1.1.0** - *IPv6 support*.
690 | - **Done in v1.0.5** - *a version with ASN*.
691 | - **Done in v1.0.2** - *provide a script to update the base. If you have the paid subscription of Maxmind, you can download the files, extract into some directory and use this script to create your own geoip2fast.dat.gz file with the most complete, reliable and updated GeoIP information*.
692 |
693 | ## Sugestions, feedbacks, bugs, wrong locations...
694 | E-mail me: ricardoabuchaim at gmail.com
695 |
--------------------------------------------------------------------------------
/geoip2fast-legacy/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 | .vscode
6 | .mypy_cache
7 | create_all_dat_files.sh
8 | geoip2fast-ipv4.dat.gz
9 | geoip2fast-city*.dat.gz
10 | old*
11 | *egg-info/
12 | dist/
13 | build/
14 |
15 | # C extensions
16 | *.so
17 |
18 | # Distribution / packaging
19 | .Python
20 | build/
21 | develop-eggs/
22 | dist/
23 | downloads/
24 | eggs/
25 | .eggs/
26 | lib/
27 | lib64/
28 | parts/
29 | sdist/
30 | var/
31 | wheels/
32 | share/python-wheels/
33 | *.egg-info/
34 | .installed.cfg
35 | *.egg
36 | MANIFEST
37 |
38 | # PyInstaller
39 | # Usually these files are written by a python script from a template
40 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
41 | *.manifest
42 | *.spec
43 |
44 | # Installer logs
45 | pip-log.txt
46 | pip-delete-this-directory.txt
47 |
48 | # Unit test / coverage reports
49 | htmlcov/
50 | .tox/
51 | .nox/
52 | .coverage
53 | .coverage.*
54 | .cache
55 | nosetests.xml
56 | coverage.xml
57 | *.cover
58 | *.py,cover
59 | .hypothesis/
60 | .pytest_cache/
61 | cover/
62 |
63 | # Translations
64 | *.mo
65 | *.pot
66 |
67 | # Django stuff:
68 | *.log
69 | local_settings.py
70 | db.sqlite3
71 | db.sqlite3-journal
72 |
73 | # Flask stuff:
74 | instance/
75 | .webassets-cache
76 |
77 | # Scrapy stuff:
78 | .scrapy
79 |
80 | # Sphinx documentation
81 | docs/_build/
82 |
83 | # PyBuilder
84 | .pybuilder/
85 | target/
86 |
87 | # Jupyter Notebook
88 | .ipynb_checkpoints
89 |
90 | # IPython
91 | profile_default/
92 | ipython_config.py
93 |
94 | # pyenv
95 | # For a library or package, you might want to ignore these files since the code is
96 | # intended to run in multiple environments; otherwise, check them in:
97 | # .python-version
98 |
99 | # pipenv
100 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
101 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
102 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
103 | # install all needed dependencies.
104 | #Pipfile.lock
105 |
106 | # poetry
107 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
108 | # This is especially recommended for binary packages to ensure reproducibility, and is more
109 | # commonly ignored for libraries.
110 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
111 | #poetry.lock
112 |
113 | # pdm
114 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
115 | #pdm.lock
116 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
117 | # in version control.
118 | # https://pdm.fming.dev/#use-with-ide
119 | .pdm.toml
120 |
121 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
122 | __pypackages__/
123 |
124 | # Celery stuff
125 | celerybeat-schedule
126 | celerybeat.pid
127 |
128 | # SageMath parsed files
129 | *.sage.py
130 |
131 | # Environments
132 | .env
133 | .venv
134 | env/
135 | venv/
136 | ENV/
137 | env.bak/
138 | venv.bak/
139 |
140 | # Spyder project settings
141 | .spyderproject
142 | .spyproject
143 |
144 | # Rope project settings
145 | .ropeproject
146 |
147 | # mkdocs documentation
148 | /site
149 |
150 | # mypy
151 | .mypy_cache/
152 | .dmypy.json
153 | dmypy.json
154 |
155 | # Pyre type checker
156 | .pyre/
157 |
158 | # pytype static type analyzer
159 | .pytype/
160 |
161 | # Cython debug symbols
162 | cython_debug/
163 |
164 | # PyCharm
165 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
166 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
167 | # and can be added to the global gitignore or merged into this file. For a more nuclear
168 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
169 | #.idea/
170 | dist
171 |
--------------------------------------------------------------------------------
/geoip2fast-legacy/CHANGELOG:
--------------------------------------------------------------------------------
1 |
2 | .oPYo. o .oPYo. .oPYo. ooooo o
3 | 8 8 8 8 8 `8 8 8
4 | 8 .oPYo. .oPYo. 8 o8YooP' oP' o8oo .oPYo. .oPYo. o8P
5 | 8 oo 8oooo8 8 8 8 8 .oP' 8 .oooo8 Yb.. 8
6 | 8 8 8. 8 8 8 8 8' 8 8 8 'Yb. 8
7 | `YooP8 `Yooo' `YooP' 8 8 8ooooo 8 `YooP8 `YooP' 8
8 | :....8 :.....::.....:..:..:::::.......:..:::::.....::.....:::..:
9 | :::::8 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::
10 | :::::..:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
11 |
12 | Author: Ricardo Abuchaim - ricardoabuchaim@gmail.com
13 | https://github.com/rabuchaim/geoip2fast/
14 |
15 | License: MIT
16 |
17 | ############################################################################
18 | What's new in v1.1.11 - 20/Jun/2024
19 | - Moved line "sys.tracebacklimit = 0" to the main_function() because
20 | was causing some problems in Django. This line is unnecessary to
21 | the GeoIP2Fast class and was there only for the command line use.
22 | https://github.com/rabuchaim/geoip2fast/issues/10
23 | - Fix in geoip2dat.py so that future field insertions made
24 | by MaxMind in the CSV files no longer affect the creation of new
25 | dat.gz files.
26 |
27 | What's new in v1.1.10 - 27/Nov/2023
28 | - Automatic download of dat.gz files.
29 | try: geoip2fast --download-all -v
30 |
31 | What's new in v1.1.9 - 22/Nov/2023
32 | - DAT files updated with MAXMIND:GeoLite2-CSV_20231121
33 | - Fix in memory usage under MacOS
34 | - Fix a problem when loading specific datafiles
35 | - a new method to return the path of the dat.gz file that is currently being used
36 | from geoip2fast import GeoIP2Fast
37 | G = GeoIP2Fast(geoip2fast_data_file="/tmp/geoip2fast-asn.dat.gz")
38 | G.get_database_path()
39 |
40 | What's new in v1.1.8 - 14/Nov/2023
41 | - DAT files updated with MAXMIND:GeoLite2-CSV_20231114
42 | - Fix in './geoip2fast.py --coverage' test when using IPv6 database
43 |
44 | What's new in v1.1.6 - 10/Nov/2023
45 | - DAT files updated with MAXMIND:GeoLite2-CSV_20231110
46 |
47 | What's new in v1.1.5 - 03/Nov/2023
48 | - DAT files updated with MAXMIND:GeoLite2-CSV_20231103
49 | - Fully tested with Python 3.12 and Python 3.13 (> 150.000 lookups/sec)
50 | - Fixed an issue in the function that adjusts the terminal window of the
51 | geoip2dat.py file. This problem prevented the geoip2dat.py script from
52 | being executed by crontab.
53 | - Added entry_points to setup.py, now it's possible to run geoip2fast and
54 | geoip2dat as an executable under Windows. If it doesn't work, you need
55 | to add the path of your python scripts directory to your PATH environment
56 | variable.
57 | - To see the path of your scripts directory on win32, run: pip show geoip2fast
58 | - Check the "Location" information, and change the "site-packages" word
59 | to "scripts" and add this path to your PATH environment variable (google it).
60 | - After this change, you can run geoip2fast and geoip2dat from any path
61 | of your Windows command prompt. Sometimes this change is unnecessary,
62 | try running 'geoip2fast' from any path of your Win32 command prompt.
63 |
64 | What's new in v1.1.4 - 27/Oct/2023
65 | - DAT files updated with MAXMIND:GeoLite2-CSV_20231027
66 |
67 | What's new in v1.1.3 - 20/Oct/2023
68 | - DAT files updated with MAXMIND:GeoLite2-CSV_20231020
69 | - Bug fix in the coverage test of v1.1.2. Didn´t affect the search accuracy.
70 |
71 | What's new in v1.1.2 - 03/Oct/2023
72 | - DAT files updated with MAXMIND:GeoLite2-Country-ASN-CSV_20231003
73 | - IPv6 transparent support!!! the same class, you just need to choose
74 | which data file you wanna use.
75 | - fast as always! the lookup speed is the same for any data file.
76 | - removed some useless code and put some colored flowers.
77 |
78 | What's new in v1.0.6 - 01/Oct/2023
79 | - geoip2fast.dat.gz updated with MAXMIND:GeoLite2-Country-CSV_20230929
80 | - geoip2fast-asn.dat.gz updated with MAXMIND:GeoLite2-ASN-CSV_20230929
81 | - bug fix: Fail on Windows while getting a memory usage
82 | - bug fix: Error when specifying the data file manually
83 |
84 | What's new in v1.0.5 - 20/Sep/2023
85 | - geoip2fast.dat.gz updated with MAXMIND:GeoLite2-Country-ASN-CSV_20230919
86 | - faster than ever!!! a lookup around ~0.00001
87 | - A new option in geoip2dat to create .dat.gz with asn support: --asn-dir
88 | - ASN support - the dat file already has support for ASN of the network
89 | ranges. The footprint was incresed to 64Mb. The speed is the same.
90 | - If you want, you can create an another dat file only with country data,
91 | just use the option --country-dir without the option --asn-dir
92 | - geoip2dat updated too! older versions won't work anymore. Sorry.
93 | - more flowers
94 |
95 | What's new in v1.0.4 - 13/Sep/2023
96 | - geoip2fast.dat.gz updated with MAXMIND:GeoLite2-Country-CSV_20230912
97 | - fix in search of IPs that end in ".0"
98 | - fix in _locate_database() function that search dat.gz file in
99 | $current_application_file path and library path
100 | - added some cli parameters: --speed-test, --self-test, and --coverage
101 | ( try: ./geoip2fast.py --coverage -v to see all networks included in
102 | dat file. )
103 | - added a parameter in tests: --missing-ips (take care, uses 100% of CPU)
104 | - geoip2dat updated too! older versions won't work anymore. Sorry.
105 | - more flowers
106 |
107 | What's new in v1.0.3 - 08/Sep/2023
108 | - geoip2fast.dat.gz updated with MAXMIND:GeoLite2-Country-CSV_20230908
109 | - IMPROVED SPEED!! >100.000 LOOKUPS PER SECOND! GeoIP2Flash!
110 | - geoip2fast.dat.gz decreased to ONE MEGABYTE! (-60%)
111 | - RAM footprint dropped to 25 MiB! (-50%)
112 | - load time around ~0,05 seconds! (-50%)
113 | - the number of networks and content still the same, we just
114 | converted all data to integers and sliced the lists a lot! This
115 | was necessary to implement the ASN data (not yet).
116 | - geoip2dat updated to create the new dat file structure
117 | - inserted a tag in dat file to record the version.
118 | - as requested, property elapsed_time_hostname for hostnames lookups
119 |
120 | What's new in v1.0.2 - 04/Sep/2023
121 | - geoip2fast.dat.gz updated with MAXMIND:GeoLite2-Country-CSV_20230901
122 | - fully tested with Python 3.11.5. Much faster than 3.10.12 >100K lookups/sec.
123 | - fix encoding of pp_json() method. Now it's showing all chars as it is.
124 | - in verbose mode it is now showing the memory footprint.
125 | - new test files at /usr/local/lib/python3.10/dist-packages/geoip2fast/tests/
126 | - new class CIDRDetail will be used to create gepip2fast.dat file
127 | - geoip2dat - a script to import Maxmind-Country-CSV into geoip2fast.dat.gz.
128 | You can update your geoip2fast.dat.gz file whenever you want. It should work
129 | with paid version also. Please let me know if there are any problems.
130 | - put some flowers;
131 |
132 | What's new in v1.0.1 - 1º/Sep/2023
133 | - geoip2fast.dat.gz updated with MAXMIND:GeoLite2-Country-CSV_20230901
134 | - improved speed in >20%! removed ipaddress module. Now we do some IP calcs.
135 | - new methods to set the error code for the situations PRIVATE NETWORKS and for
136 | NETWORKS NOT FOUND:
137 | GeoIP2Fast.set_error_code_private_networks(new_value)
138 | GeoIP2Fast.set_error_code_network_not_found(new_value)
139 | - new method to calculate the current speed. Returns a value of current lookups per
140 | seconds or print a formatted result:
141 | GeoIP2Fast.calculate_speed(print_result=True)
142 | - new method to calculate how many IPv4 of all internet are covered by geoip2fast.dat
143 | file. Returns a percentage relative to all possible IPv4 on the internet or print a
144 | formatted result. Useful to track the changes in getip2fast.dat.gz file:
145 | GeoIP2Fast.calculate_coverage(print_result=True)
146 |
--------------------------------------------------------------------------------
/geoip2fast-legacy/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | ricardoabuchaim@gmail.com.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
--------------------------------------------------------------------------------
/geoip2fast-legacy/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Ricardo Abuchaim
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/geoip2fast-legacy/README.md:
--------------------------------------------------------------------------------
1 | # GeoIP2Fast v1.1.11
2 |
3 | GeoIP2Fast is the fastest GeoIP2 country/asn lookup library. A search takes less than 0.00003 seconds. It has its own data file updated with Maxmind-Geolite2-CSV, supports IPv4 and IPv6 and is Pure Python!
4 |
5 | With it´s own datafile (geoip2fast.dat.gz), can be loaded into memory in ~0.07 seconds and has a small footprint for all data, so you don´t need to make requests to any webservices or connect to an external database.
6 |
7 | There are 4 databases included in the installation package:
8 |
9 | | Content | File Name | File Size | Load Time | RAM Footprint | Download Latest |
10 | | ---------- | :---------: | ---------: | --------: | ---------: | :-------------: |
11 | | Country IPv4 | ```geoip2fast.dat.gz``` | 1.1 MiB | ~0.04 sec | ~22.0 MiB | [geoip2fast.dat.gz](https://github.com/rabuchaim/geoip2fast/releases/download/LEGACY/geoip2fast.dat.gz) |
12 | | Country IPv4+IPv6 | ```geoip2fast-ipv6.dat.gz``` | 1.1 MiB | ~0.08 sec | ~43.0 MiB | [geoip2fast-ipv6.dat.gz](https://github.com/rabuchaim/geoip2fast/releases/download/LEGACY/geoip2fast-ipv6.dat.gz) |
13 | | Country+ASN IPv4 | ```geoip2fast-asn.dat.gz``` | 3.1 MiB | ~0.11 sec | ~66.0 MiB | [geoip2fast-asn.dat.gz](https://github.com/rabuchaim/geoip2fast/releases/download/LEGACY/geoip2fast-asn.dat.gz) |
14 | | Country+ASN IPv4+IPv6 | ```geoip2fast-asn-ipv6.dat.gz``` | 4.0 MiB | ~0.15 sec | ~97.0 MiB | [geoip2fast-asn-ipv6.dat.gz](https://github.com/rabuchaim/geoip2fast/releases/download/LEGACY/geoip2fast-asn-ipv6.dat.gz) |
15 |
16 | GeoIP2Fast returns ASN NAME, COUNTRY ISO CODE, COUNTRY NAME and CIDR. There is no external dependencies, you just need the ```geoip2fast.py``` file and the desired data file ```.dat.gz```. **The lookup speed is the same for any data file**.
17 |
18 | **There is also version 1.2.X that returns city names, visit the previous directory [https://github.com/rabuchaim/geoip2fast/](https://github.com/rabuchaim/geoip2fast/)**
19 |
20 | ```
21 | What's new in v1.1.11 - 20/Jun/2024
22 | - Moved line "sys.tracebacklimit = 0" to the main_function() because
23 | was causing some problems in Django. This line is unnecessary to
24 | the GeoIP2Fast class and was there only for the command line use.
25 | https://github.com/rabuchaim/geoip2fast/issues/10
26 | - Fix in geoip2dat.py so that future field insertions made
27 | by MaxMind in the CSV files no longer affect the creation of new
28 | dat.gz files.
29 |
30 | What's new in v1.1.10 - 22/Nov/2023
31 | - DAT files updated with MAXMIND:GeoLite2-CSV_20231201
32 | - Automatic updates! you can update to the newest dat.gz file via command line or via code
33 | Using command line:
34 | geoip2fast --update-all -v
35 |
36 | Using the class GeoIP2Fast:
37 | from geoip2fast import GeoIP2Fast
38 | from pprint import pprint
39 | G = GeoIP2Fast(verbose=True)
40 | G.get_database_path()
41 | update_file_result = G.update_file(filename="geoip2fast-asn-ipv6.dat.gz",destination="geoip2fast.dat.gz",verbose=True)
42 | pprint(update_file_result,sort_dicts=False)
43 | G.reload_data(verbose=True)
44 | update_all_result = G.update_all(destination_path="",verbose=True)
45 | pprint(update_all_result,sort_dicts=False)
46 |
47 | ```
48 |
49 |
50 | 
51 |
52 |
53 |
54 | ## Installation
55 | ```bash
56 | pip install geoip2fast==1.1.11
57 | ```
58 |
59 |
60 |
61 | ## DAT files updates
62 |
63 | - You can create your own dat.gz file using [geoip2dat.py](#geoip2dat---update-geoip2fastdatgz-file-anytime) file.
64 | - You can also [download the latest dat files](https://github.com/rabuchaim/geoip2fast/releases/tag/LEGACY) that are updated automatically on Tuesdays and Fridays
65 | - And you can [update the dat files downloading from our releases repository](#automatic-update-of-datgz-files), via code or via command line.
66 |
67 |
68 |
69 | ## How does it work?
70 |
71 | GeoIP2Fast has 4 datafiles included. Tha main file is ```geoip2fast.dat.gz``` with support Country lookups and only IPv4. Usually, these files are located into the library directory (```/usr/local/lib/python3/dist-packages/geoip2fast```), but you can place it into the same directory of your application. The library automatically checks both paths, And the directory of your application overlaps the directory of the library. You can use an specific location also.
72 |
73 | The ```bisect()``` function is used together with some ordered lists of integers to search the Network/CountryCode (Yes! an IP address has an integer representation, try to ping this number: ```ping 134744072``` or this ```ping 2130706433``` ).
74 |
75 | If GeoIP2Fast does not have a network IP address that was requested, a "not found in database" error will be returned. Unlike many other libraries that when not finding a requested network, gives you the geographical location of the network immediately below. The result is not always correct.
76 |
77 | There are network gaps in the files we use as a source of data, and these missing networks are probably addresses that those responsible have not yet declared their location. Of all almost 4.3 billion IPv4 on the internet, we do not have information on approximately 15 million of them (~0,35%). It must be remembered that the geographical accuracy is the responsibility of the network block owners. If the owner (aka ASN) of the XXX.YYY.ZZZ.D/24 network range declares that his network range is located at "Foo Island", we must believe that an IP address of that network is there.
78 |
79 | > *Don't go to Foo Island visit a girl you met on the internet just because you looked up her IP on GeoIP2Fast and the result indicated that she is there.*
80 |
81 |
82 |
83 | ## Quick Start
84 |
85 | Once the object is created, GeoIP2Fast loads automatically all needed data into memory. The lookup function returns an object called ```GeoIPDetail```. And you can get the values of it's properties just calling the name of proprerty: ```result.ip, result.country_code, result.country_name, result.cidr, result.is_private, result.asn_name``` and ```result.elapsed_time```. Or use the function ```to_dict()``` to get the result as a dict. You can get values like ```result.to_dict()['country_code']```
86 |
87 | At the moment of creation, you can define which data you want to use. Country+IPv4, Country+IPv4+IPv6, Country+ASN+IPv4 or Country+ASN+IPv4+IPv6. If don´t specify any file, the default ```geoip2fast.dat.gz``` will be used.
88 |
89 |
90 | ```python
91 | from geoip2fast import GeoIP2Fast
92 |
93 | GEOIP = GeoIP2Fast()
94 | print(GEOIP.get_database_path())
95 |
96 | result = GEOIP.lookup("200.204.0.10")
97 | print(result)
98 |
99 | # to use the country_code property
100 | print(result.country_code)
101 |
102 | # to print the ASN name property
103 | print(result.asn_name)
104 |
105 | # Before call the function get_hostname(), the property hostname will always be empty.
106 | print("Hostname: "+result.hostname)
107 | result.get_hostname()
108 | print("Hostname: "+result.hostname)
109 |
110 | # to work with output as a dict, use the function to_dict()
111 | print(result.to_dict()['country_code'],result.to_dict()['country_name'])
112 |
113 | # to check the date of the CSV files used to create the .dat file
114 | print(GEOIP.get_source_info())
115 |
116 | # info about internal cache
117 | print(GEOIP.cache_info())
118 |
119 | # clear the internal cache
120 | print(GEOIP.clear_cache())
121 |
122 | # to see the difference after clear cache
123 | print(GEOIP.cache_info())
124 |
125 | ```
126 | There is a method to pretty print the result as json.dumps():
127 | ```python
128 | >>> result = MyGeoIP.lookup("100.200.100.200")
129 | >>> print(result.pp_json())
130 | {
131 | "ip": "100.200.100.200",
132 | "country_code": "US",
133 | "country_name": "United States",
134 | "cidr": "100.128.0.0/9",
135 | "hostname": "",
136 | "is_private": false,
137 | "asn_name": "T-MOBILE-AS21928",
138 | "elapsed_time": "0.000014487 sec"
139 | }
140 | ```
141 | or simply: ```result.pp_json(print_result=True)```
142 |
143 | To see the start-up line without set ```verbose=True``` :
144 | ```python
145 | >>> from geoip2fast import GeoIP2Fast
146 | >>> MyGeoIP = GeoIP2Fast()
147 | >>> MyGeoIP.startup_line_text
148 | 'GeoIP2Fast v1.1.10 is ready! geoip2fast.dat.gz loaded with 433468 networks in 0.04153 seconds and using 23.75 MiB.'
149 | ```
150 |
151 | If you call geoip2fast from command line, it´s only use ```geoip2fast.dat.gz``` file, so if you want more data like ASN or IPv6 support, you have to copy the respective file over ```geoip2fast.dat.gz``` file. If you are using GeoIP2Fast as a Python library, you don´t need to rename or copy any file, you can load the desired data file in the moment of object creation. The library first looks for the given file in the current directory and then in the library directory. If desired, you can directly specify the path.
152 |
153 | ```python
154 | >>> from geoip2fast import GeoIP2Fast
155 | >>> geoip = GeoIP2Fast(geoip2fast_data_file="geoip2fast-asn.dat.gz",verbose=True)
156 | GeoIP2Fast v1.1.10 is ready! geoip2fast-asn.dat.gz loaded with 456271 networks in 0.09355 seconds and using 66.99 MiB.
157 | >>> geoip.get_database_path()
158 | '/usr/local/lib/python3.11/dist-packages/geoip2fast/geoip2fast-asn.dat.gz'
159 | >>>
160 | >>> geoip.lookup("2a02:26f0:6d00:5bc::b63")
161 | {'ip': '2a02:26f0:6d00:5bc::b63', 'country_code': 'NL', 'country_name': 'Netherlands', 'cidr': '2a02:26f0:6d00::/40', 'hostname': '', 'is_private': False, 'asn_name': 'Akamai International B.V.', 'elapsed_time': '0.000600145 sec'}
162 | >>>
163 | >>> geoip = GeoIP2Fast(geoip2fast_data_file="/opt/maxmind/geoip2fast-asn.dat.gz",verbose=True)
164 | GeoIP2Fast v1.1.10 is ready! geoip2fast-asn.dat.gz loaded with 456271 networks in 0.11666 seconds and using 67.05 MiB.
165 | >>> geoip.get_database_path()
166 | '/opt/maxmind/geoip2fast-asn.dat.gz'
167 | ```
168 |
169 | Private/Reserved networks were included in the database just to be able to provide an answer if one of these IPs is searched. When it happens, the country_code will return "--", the "network name" will be displayed in the country_name and the range of that network will be displayed in the cidr property, and the property **is_private** is setted to **True**.
170 |
171 | ```python
172 | >>> from geoip2fast import GeoIP2Fast
173 | >>> geoip = GeoIP2Fast(verbose=True)
174 | GeoIP2Fast v1.1.10 is ready! geoip2fast.dat.gz loaded with 433468 networks in 0.04153 seconds and using 23.75 MiB.
175 | >>>
176 | >>> geoip.lookup("10.20.30.40")
177 | {'ip': '10.20.30.40', 'country_code': '--', 'country_name': 'Private Network Class A', 'cidr': '10.0.0.0/8', 'hostname': '', 'is_private': True, 'asn_name': 'IANA.ORG', 'elapsed_time': '0.000094584 sec'}
178 | >>>
179 | >>> geoip.lookup("169.254.10.20")
180 | {'ip': '169.254.10.20', 'country_code': '--', 'country_name': 'APIPA Automatic Priv.IP Addressing', 'cidr': '169.254.0.0/16', 'hostname': '', 'is_private': True, 'asn_name': 'IANA.ORG', 'elapsed_time': '0.000048402 sec'}
181 | ```
182 |
183 | You can change the behavior of what will be returned in country_code property of "private networks" and for "networks not found":
184 |
185 | ```python
186 | >>> from geoip2fast import GeoIP2Fast
187 | >>> geoip = GeoIP2Fast(verbose=True)
188 | GeoIP2Fast v1.1.10 is ready! geoip2fast.dat.gz loaded with 433468 networks in 0.04153 seconds and using 23.75 MiB.
189 | >>> geoip.set_error_code_private_networks("@@")
190 | '@@'
191 | >>>
192 | >>> geoip.lookup("10.20.30.40")
193 | {'ip': '10.20.30.40', 'country_code': '@@', 'country_name': 'Private Network Class A', 'cidr': '10.0.0.0/8', 'hostname': '', 'is_private': True, 'asn_name': 'IANA.ORG', 'elapsed_time': '0.000060297 sec'}
194 | >>>
195 | >>> geoip.set_error_code_network_not_found("##")
196 | '##'
197 | >>> geoip.lookup("57.242.128.144")
198 | {'ip': '57.242.128.144', 'country_code': '##', 'country_name': '', 'cidr': '', 'hostname': '', 'is_private': False, 'asn_name': '', 'elapsed_time': '0.000008152 sec'}
199 | >>>
200 | ```
201 |
202 |
203 |
204 | ## How fast is it?
205 |
206 | With an virtual machine with 1 CPU and 4Gb of RAM, we have lookups **lower than 0,00003 seconds**. And if the lookup still in library´s internal cache, the elapsed time goes down to 0,000003 seconds. **GeoIP2Fast can do more than 100K queries per second, per core**. It takes less than 0,07 seconds to load the datafile into memory and get ready to lookup. Use ```verbose=True``` to create the object GeoIP2Fast to see the spent time to start.
207 |
208 | ```geoip2fast --self-test```
209 | ```bash
210 | # geoip2fast --self-test
211 | GeoIP2Fast v1.1.19 is ready! geoip2fast.dat.gz loaded with 433468 networks in 0.04153 seconds and using 23.75 MiB.
212 |
213 | Starting a self-test...
214 |
215 | > 223.130.10.1 -- [0.000034988 sec] Cached > [0.000001427 sec]
216 | > 266.266.266.266 [0.000015505 sec] Cached > [0.000001393 sec]
217 | > 192,0x0/32 [0.000001101 sec] Cached > [0.000000881 sec]
218 | > 127.0.0.10 -- Localhost [0.000023153 sec] Cached > [0.000002716 sec] 127.0.0.0/8
219 | > 10.20.30.40 -- Private Network Class A [0.000012335 sec] Cached > [0.000001526 sec] 10.0.0.0/8
220 | > 200.204.0.10 BR Brazil [0.000014939 sec] Cached > [0.000002163 sec] 200.204.0.0/14
221 | > 57.242.128.144 -- [0.000004927 sec] Cached > [0.000000707 sec]
222 | > 192.168.10.10 -- Private Network Class C [0.000009447 sec] Cached > [0.000001244 sec] 192.168.0.0/16
223 | > 200.200.200.200 BR Brazil [0.000004481 sec] Cached > [0.000001852 sec] 200.200.200.200/32
224 | > 11.22.33.44 US United States [0.000005417 sec] Cached > [0.000001573 sec] 11.0.0.0/10
225 | > 200.147.0.20 BR Brazil [0.000004278 sec] Cached > [0.000001466 sec] 200.144.0.0/14
226 | (.....)
227 | ```
228 |
229 | ```geoip2fast --speed-test```
230 | ```bash
231 | # geoip2fast --speed-test
232 | GeoIP2Fast v1.1.10 is ready! geoip2fast.dat.gz loaded with 433468 networks in 0.04153 seconds and using 23.75 MiB.
233 |
234 | Calculating current speed... wait a few seconds please...
235 |
236 | Current speed: 136572.73 lookups per second (searched for 1,000,000 IPs in 7.322106013 seconds) [7.32211 sec]
237 | ```
238 |
239 | ```geoip2fast --coverage```
240 | ```bash
241 | # geoip2fast --coverage
242 | GeoIP2Fast v1.1.10 is ready! geoip2fast.dat.gz loaded with 748074 networks in 0.15510 seconds and using 98.30 MiB.
243 |
244 | Use the parameter '-v' to see all networks included in your /opt/pypi-geoip2fast/git-geoip2fast/geoip2fast/geoip2fast.dat.gz file.
245 |
246 | Current IPv4 coverage: 99.64% (4,279,396,946 IPv4 in 453615 networks) [0.12512 sec]
247 | Current IPv6 coverage: 0.40% (1,364,425,945,439,630,011,748,628,700,499,804,160 IPv6 in 294459 networks) [0.12518 sec]
248 | ```
249 | ```geoip2fast --coverage -v```
250 | ```bash
251 | # geoip2fast --coverage -v
252 | GeoIP2Fast v1.1.10 is ready! geoip2fast.dat.gz loaded with 748074 networks in 0.15510 seconds and using 98.30 MiB.
253 |
254 | Use the parameter '-v' to see all networks included in your /opt/pypi-geoip2fast/git-geoip2fast/geoip2fast/geoip2fast.dat.gz file.
255 |
256 | - Network: 0.0.0.0/8 IPs: 16777216 -- Reserved for self identification 0.000128794 sec
257 | - Network: 1.0.0.0/24 IPs: 256 AU Australia 0.000073830 sec
258 | - Network: 1.0.1.0/24 IPs: 256 CN China 0.000084977 sec
259 | - Network: 1.0.2.0/23 IPs: 512 CN China 0.000015769 sec
260 | - Network: 1.0.4.0/22 IPs: 1024 AU Australia 0.000015369 sec
261 | - Network: 1.0.8.0/21 IPs: 2048 CN China 0.000023131 sec
262 | - Network: 1.0.16.0/20 IPs: 4096 JP Japan 0.000095840 sec
263 | (.....)
264 | - Network: 2c0f:ffb8::/32 IPs: 79228162514264337593543950336 SD Sudan 0.000018255 sec
265 | - Network: 2c0f:ffc0::/32 IPs: 79228162514264337593543950336 ZA South Africa 0.000032078 sec
266 | - Network: 2c0f:ffc8::/32 IPs: 79228162514264337593543950336 ZA South Africa 0.000031547 sec
267 | - Network: 2c0f:ffd0::/32 IPs: 79228162514264337593543950336 ZA South Africa 0.000022423 sec
268 | - Network: 2c0f:ffd8::/32 IPs: 79228162514264337593543950336 ZA South Africa 0.000012151 sec
269 | - Network: 2c0f:ffe8::/32 IPs: 79228162514264337593543950336 NG Nigeria 0.000010622 sec
270 | - Network: 2c0f:fff0::/32 IPs: 79228162514264337593543950336 NG Nigeria 0.000017496 sec
271 | - Network: fd00::/8 IPs: 1329227995784915872903807060280344576 -- Reserved for Unique Local Addresses 0.000033054 sec
272 |
273 | Current IPv4 coverage: 99.64% (4,279,396,946 IPv4 in 453615 networks) [18.88599 sec]
274 | Current IPv6 coverage: 0.40% (1,364,425,945,439,630,011,748,628,700,499,804,160 IPv6 in 294459 networks) [18.88601 sec]
275 | ```
276 |
277 | ```geoip2fast --missing-ips```
278 | ```bash
279 | # geoip2fast --missing-ips
280 | GeoIP2Fast v1.1.10 is ready! geoip2fast.dat.gz loaded with 748074 networks in 0.15510 seconds and using 98.30 MiB.
281 |
282 | Searching for missing IPs...
283 |
284 | From 1.34.65.179 to 1.34.65.179 > Network 1.34.65.180/32 > Missing IPs: 1
285 | From 1.46.23.235 to 1.46.23.235 > Network 1.46.23.236/32 > Missing IPs: 1
286 | From 2.12.211.171 to 2.12.211.171 > Network 2.12.211.172/32 > Missing IPs: 1
287 | (.....)
288 | From 216.238.200.0 to 216.238.207.255 > Network 216.238.208.0/21 > Missing IPs: 2048
289 | From 217.26.216.0 to 217.26.223.255 > Network 217.26.224.0/21 > Missing IPs: 2048
290 | From 217.78.64.0 to 217.78.79.255 > Network 217.78.80.0/20 > Missing IPs: 4096
291 |
292 | >>> Valid IP addresses without geo information: 15,169,195 (0.35% of all IPv4) [44.30283 sec]
293 | ```
294 |
295 | > Some IPs are excluded as described in page "Do Not Sell My Personal Information Requests" at Maxmind website.
296 |
297 |
298 |
299 | ## You can use it as a CLI
300 |
301 | ```bash
302 | # geoip2fast -h
303 | GeoIP2Fast v1.1.3 Usage: geoip2fast [-h] [-v] [-d] ,,,...
304 |
305 | Tests parameters:
306 | --self-test Starts a self-test with some randomic IP addresses.
307 | --speed-test Do a speed test with 1 million on randomic IP addresses.
308 | --random-test Start a test with 1.000.000 of randomic IPs and calculate a lookup average time.
309 |
310 | --coverage [-v] Shows a statistic of how many IPs are covered by current dat file.
311 | --missing-ips [-v] Print all IP networks that doesn't have geo information.
312 |
313 | More options:
314 | -d Resolve the DNS of given IP address.
315 | -h Show this help text.
316 | -v Verbose mode.
317 | -vvv Shows the location of current dat file.
318 | ```
319 |
320 | ```bash
321 | # geoip2fast
322 | GeoIP2Fast v1.1.3 Usage: geoip2fast [-h] [-v] [-d] ,,,...
323 | # geoip2fast -v 9.9.9.9,15.20.25.30 -d
324 | GeoIP2Fast v1.1.3 is ready! geoip2fast.dat.gz loaded with 433468 networks in 0.10803 seconds and using 65.61 MiB.
325 | {
326 | "ip": "9.9.9.9",
327 | "country_code": "US",
328 | "country_name": "United States",
329 | "cidr": "9.9.9.9/32",
330 | "hostname": "dns9.quad9.net",
331 | "is_private": false,
332 | "asn_name": "QUAD9-AS-1",
333 | "elapsed_time": "0.000041463 sec",
334 | "elapsed_time_hostname": "0.014539683 sec"
335 | }
336 | {
337 | "ip": "15.20.25.30",
338 | "country_code": "US",
339 | "country_name": "United States",
340 | "cidr": "15.0.0.0/10",
341 | "hostname": "",
342 | "is_private": false,
343 | "asn_name": "ATT-IPFR",
344 | "elapsed_time": "0.000024009 sec"
345 | }
346 | # geoip2fast "2.3.4.5, 4.5.6.7, 8.9.10.11" | jq -r '.country_code'
347 | FR
348 | US
349 | US
350 | # ./geoip2fast.py 8.8.8.8,1.1.1.1,200.204.0.10 -d | jq -r '.hostname'
351 | dns.google
352 | one.one.one.one
353 | resolver1.telesp.net.br
354 | ```
355 |
356 |
357 | ## GeoIP2Dat - update geoip2fast.dat.gz file anytime
358 |
359 | The updates of geoip2fast.dat.gz file will be published twice a week on Github https://github.com/rabuchaim/geoip2fast/releases/tag/LEGACY. You can also create your own dat file whenever you want, see instructions below.
360 |
361 | Download the Geolite2 Country CSV files from Maxmind website and place it into some diretory (in this example, was placed into ```/opt/maxmind/```). Extract this zip file into this directory and run ```geoip2dat``` to see the options.
362 |
363 | 
364 |
365 | 
366 |
367 | The options ```--country-dir``` and ```--output-dir``` are mandatory. Specify the path of extracted files in ```--country-dir``` option. And for ```--output-dir```, put the current path ```./```.
368 |
369 | If you want to add support for ASN data, add the option ```--asn-dir```. And if you want to add IPv6 support, just add ```--with-ipv6``` to your command line.
370 |
371 | You can choose the language of country locations. The default is ```en```.
372 |
373 | After creation of ```geoip2dat.dat.gz``` file, move or copy this file to the directory of your application or to the directory of GeoIP2Fast library. You choose.
374 |
375 | 
376 |
377 | **From now you don't depend on anyone to have your data file updated.** There's no point the code being open-source if you're dependent of a single file.
378 |
379 | > *The Philosophers call it 'Libertas'*
380 |
381 |
382 |
383 | ## Automatic update of dat.gz files
384 |
385 | From version 1.1.10 onwards, it is now possible to update the dat.gz files that were made available in our releases repository. You can update via command line or via code.
386 |
387 | - Download the file "geoip2fast-asn-ipv6.dat.gz" and save it as "geoip2fast.dat.gz":
388 |
389 | ```python
390 | >>> from geoip2fast import GeoIP2Fast
391 | >>> G = GeoIP2Fast(verbose=True)
392 | GeoIP2Fast v1.1.10 is ready! geoip2fast.dat.gz loaded with 459270 networks in 0.03297 seconds and using 25.12 MiB.
393 | >>> update_result = G.update_file('geoip2fast-asn-ipv6.dat.gz','geoip2fast.dat.gz',verbose=False)
394 | >>> G.reload_data(verbose=True)
395 | GeoIP2Fast v1.1.10 is ready! geoip2fast.dat.gz loaded with 753871 networks in 0.12917 seconds and using 113.54 MiBTrue
396 | >>>
397 | ```
398 |
399 | - Update all files:
400 |
401 | ```python
402 | >>> from geoip2fast import GeoIP2Fast
403 | >>> G = GeoIP2Fast()
404 | >>> update_result = G.update_all(verbose=True)
405 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LEGACY/geoip2fast.dat.gz
406 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
407 | - Downloading geoip2fast.dat.gz... 100.00% of 1.06 MiB [6.51 MiB/s] [0.163 sec]
408 | - File saved to: /opt/geoip2fast/geoip2fast-legacy/geoip2fast/geoip2fast.dat.gz
409 |
410 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LEGACY/geoip2fast-ipv6.dat.gz
411 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
412 | - Downloading geoip2fast-ipv6.dat.gz... 100.00% of 1.73 MiB [9.66 MiB/s] [0.179 sec]
413 | - File saved to: /opt/geoip2fast/geoip2fast-legacy/geoip2fast/geoip2fast-ipv6.dat.gz
414 |
415 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LEGACY/geoip2fast-asn.dat.gz
416 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
417 | - Downloading geoip2fast-asn.dat.gz... 100.00% of 3.06 MiB [8.63 MiB/s] [0.354 sec]
418 | - File saved to: /opt/geoip2fast/geoip2fast-legacy/geoip2fast/geoip2fast-asn.dat.gz
419 |
420 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LEGACY/geoip2fast-asn-ipv6.dat.gz
421 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
422 | - Downloading geoip2fast-asn-ipv6.dat.gz... 100.00% of 4.09 MiB [7.66 MiB/s] [0.534 sec]
423 | - File saved to: /opt/geoip2fast/geoip2fast-legacy/geoip2fast/geoip2fast-asn-ipv6.dat.gz
424 | >>>
425 | ```
426 | - Update all files silently and verify if there are errors:
427 | ```python
428 | >>> from geoip2fast import GeoIP2Fast
429 | >>> G = GeoIP2Fast()
430 | >>> update_result = G.update_all(verbose=False)
431 | >>> errors_result = [item for item in update_result if item['error'] is not None]
432 | >>> print(errors_result)
433 | []
434 | ```
435 | - You can change the update URL if you want.
436 | ```
437 | >>> G.get_update_url()
438 | 'https://github.com/rabuchaim/geoip2fast/releases/download/LEGACY/'
439 | >>> G.set_update_url("https://github.com/YOUR_OWN_REPO/YOUR_PROJECT/releases/download/latest/")
440 | True
441 | >>> G.get_update_url()
442 | 'https://github.com/YOUR_OWN_REPO/YOUR_PROJECT/releases/download/latest/'
443 | >>>
444 | ```
445 | - Update the file "geoip2fast-asn-ipv6.dat.gz" and overwrite "geoip2fast.dat.gz" and print the result.
446 | ```python
447 | >>> from geoip2fast import GeoIP2Fast
448 | >>> G = GeoIP2Fast(verbose=True)
449 | GeoIP2Fast v1.1.10 is ready! geoip2fast.dat.gz loaded with 459270 networks in 0.04414 seconds and using 5.02 MiB.
450 | >>> update_result = G.update_file('geoip2fast-asn-ipv6.dat.gz','geoip2fast.dat.gz',verbose=False)
451 | >>> from pprint import pprint as pp
452 | >>> pp(update_result,sort_dicts=False)
453 | {'error': None,
454 | 'url': 'https://github.com/rabuchaim/geoip2fast/releases/download/LEGACY/geoip2fast-asn-ipv6.dat.gz',
455 | 'remote_filename': 'geoip2fast-asn-ipv6.dat.gz',
456 | 'last_modified_date': 'Mon, 27 Nov 2023 02:40:08 GMT',
457 | 'file_size': 4289564,
458 | 'file_destination': '/opt/geoip2fast/geoip2fast-legacy/geoip2fast/geoip2fast.dat.gz',
459 | 'average_download_speed': '4.09 MiB/sec',
460 | 'elapsed_time': '0.587267'}
461 | >>>
462 | >>> G.reload_data(verbose=True)
463 | GeoIP2Fast v1.1.10 is ready! geoip2fast.dat.gz loaded with 753871 networks in 0.12245 seconds and using 57.55 MiB.
464 | >>>
465 |
466 | ```
467 | - **Using the command line, no message will be displayed on the console unless you use the -v parameter**
468 | - Update all files via command line and save them in '/tmp/' directory:
469 | ```bash
470 | # geoip2fast --update-all --dest /tmp/ -v
471 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LEGACY/geoip2fast.dat.gz
472 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
473 | - Downloading geoip2fast.dat.gz... 100.00% of 1.06 MiB [10.41 MiB/s] [0.102 sec]
474 | - File saved to: /tmp/geoip2fast.dat.gz
475 |
476 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LEGACY/geoip2fast-ipv6.dat.gz
477 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
478 | - Downloading geoip2fast-ipv6.dat.gz... 100.00% of 1.73 MiB [9.46 MiB/s] [0.183 sec]
479 | - File saved to: /tmp/geoip2fast-ipv6.dat.gz
480 |
481 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LEGACY/geoip2fast-asn.dat.gz
482 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
483 | - Downloading geoip2fast-asn.dat.gz... 100.00% of 3.06 MiB [7.06 MiB/s] [0.433 sec]
484 | - File saved to: /tmp/geoip2fast-asn.dat.gz
485 |
486 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LEGACY/geoip2fast-asn-ipv6.dat.gz
487 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
488 | - Downloading geoip2fast-asn-ipv6.dat.gz... 100.00% of 4.09 MiB [7.31 MiB/s] [0.560 sec]
489 | - File saved to: /tmp/geoip2fast-asn-ipv6.dat.gz
490 | ```
491 | - Update the file "geoip2fast-asn-ipv6.dat.gz" and overwrite "geoip2fast.dat.gz"
492 | ```bash
493 | # geoip2fast --update-file geoip2fast-asn-ipv6.dat.gz --dest geoip2fast.dat.gz -v
494 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LEGACY/geoip2fast-asn-ipv6.dat.gz
495 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
496 | - Downloading geoip2fast-asn-ipv6.dat.gz... 100.00% of 4.09 MiB [4.29 MiB/s] [0.954 sec]
497 | - File saved to: /opt/geoip2fast/geoip2fast-legacy/geoip2fast/geoip2fast.dat.gz
498 | ```
499 | - Update the file "geoip2fast.dat.gz" and save it in the library path
500 | ```bash
501 | # geoip2fast --update-file geoip2fast.dat.gz -v
502 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LEGACY/geoip2fast.dat.gz
503 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
504 | - Downloading geoip2fast.dat.gz... 100.00% of 1.06 MiB [9.54 MiB/s] [0.111 sec]
505 | - File saved to: /opt/geoip2fast/geoip2fast-legacy/geoip2fast/geoip2fast.dat.gz
506 | ```
507 | - Update the file "geoip2fast.dat.gz" and save it in the library path
508 |
509 | ```bash
510 | # geoip2fast --update-file geoip2fast.dat.gz
511 | # echo $?
512 | 0
513 | ```
514 | - An example of a simulated download failure:
515 | ```bash
516 | # geoip2fast.py --update-file geoip2fast.dat.gz -v
517 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/aLEGACY_v1.1.9/geoip2fast.dat.gz
518 | - Error: HTTP Error 404: Not Found - https://github.com/rabuchaim/geoip2fast/releases/download/aLEGACY_v1.1.9/geoip2fast.dat.gz
519 | # echo $?
520 | 1
521 | ```
522 | ```bash
523 | # geoip2fast.py --update-file geoip2fast.dat.gz -v
524 | - Opening URL https://github.com/rabuchaim/geoip2fast/releases/download/LEGACY/geoip2fast.dat.gz
525 | - Last Modified Date: Mon, 27 Nov 2023 02:40:08 GMT
526 | PermissionError: [Errno 1] Operation not permitted: '/opt/geoip2fast/geoip2fast-legacy/geoip2fast/geoip2fast.dat.gz'
527 | # echo $?
528 | 1
529 | ```
530 | ## Create your own GeoIP CLI with 6 lines
531 |
532 | 1. Create a file named ```geoipcli.py``` and save it in your home directory with the text below:
533 | ```python
534 | #!/usr/bin/env python3
535 | import os, sys, geoip2fast
536 | if len(sys.argv) > 1 and sys.argv[1] is not None:
537 | geoip2fast.GeoIP2Fast().lookup(sys.argv[1]).pp_json(print_result=True)
538 | else:
539 | print(f"Usage: {os.path.basename(__file__)} ")
540 | ```
541 | 2. Give execution permisstion to your file and create a symbolic link to your new file into ```/usr/sbin``` folder, like this (let's assume that you saved the file into directory /root)
542 | ```bash
543 | chmod 750 /root/geoipcli.py
544 | ln -s /root/geoipcli.py /usr/sbin/geoipcli
545 | ```
546 | 3. Now, you just need to call ```geoipcli``` from any path.
547 | ```bash
548 | # geoipcli
549 | Usage: geoipcli
550 |
551 | # geoipcli 1.2.3.4
552 | {
553 | "ip": "1.2.3.4",
554 | "country_code": "AU",
555 | "country_name": "Australia",
556 | "cidr": "1.2.3.0/24",
557 | "hostname": "",
558 | "is_private": false,
559 | "elapsed_time": "0.000019727 sec"
560 | }
561 |
562 | # geoipcli x.y.z.w
563 | {
564 | "ip": "x.y.z.w",
565 | "country_code": "",
566 | "country_name": "",
567 | "cidr": "",
568 | "hostname": "",
569 | "is_private": false,
570 | "elapsed_time": "0.000012493 sec"
571 | }
572 |
573 | # geoipcli 57.242.128.144
574 | {
575 | "ip": "57.242.128.144",
576 | "country_code": "--",
577 | "country_name": "",
578 | "cidr": "",
579 | "hostname": "",
580 | "is_private": false,
581 | "elapsed_time": "0.000019127 sec"
582 | }
583 | ```
584 |
585 | ## GeoIP libraries that inspired me
586 |
587 | **GeoIP2Nation - https://pypi.org/project/geoip2nation/** (Created by Avi Asher)
588 |
589 | This library uses sqlite3 in-memory tables and use the same search concepts as GeoIP2Fast (based on search by the first´s IPs). Simple and fast! Unfortunately it is no longer being updated and that is why I developed GeoIP2Fast.
590 |
591 | **GeoIP2 - https://pypi.org/project/geoip2/** (created by Maxmind)
592 |
593 | This is the best library to work with Maxmind (paid subscription or with the free version). You can use http requests to Maxmind services or work with local Maxmind MMDB binary files. Pretty fast too. Sign-up to have access to all files of the free version https://dev.maxmind.com/geoip/geolite2-free-geolocation-data
594 |
595 | **\* Maxmind is a registered trademark** - https://www.maxmind.com
596 |
597 | ## TO DO list
598 | - a pure-python version for REDIS with a very small footprint (pure protocol, won´t use any REDIS library) **<<< On the way at https://github.com/rabuchaim/geoip2redis**
599 | - a GeoIP Server; **<<< On the way a docker container, your own GeoIP server inside your network. With rest API or socket (super fast)**
600 | - a mod_geoip2fast for NGINX;
601 | - a better manual, maybe at readthedocs.io;
602 | - **Done in v1.1.10/v1.2.1** - automatic update of dat.gz files;
603 | - **Done in v1.2.0** - a version with cities;
604 | - **Done in v1.1.0** - *IPv6 support*.
605 | - **Done in v1.0.5** - *a version with ASN*.
606 | - **Done in v1.0.2** - *provide a script to update the base. If you have the paid subscription of Maxmind, you can download the files, extract into some directory and use this script to create your own geoip2fast.dat.gz file with the most complete, reliable and updated GeoIP information*.
607 |
608 | ## Sugestions, feedbacks, bugs, wrong locations...
609 | E-mail me: ricardoabuchaim at gmail.com
610 |
--------------------------------------------------------------------------------
/geoip2fast-legacy/geoip2fast-1.1.11.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/geoip2fast-1.1.11.tar.gz
--------------------------------------------------------------------------------
/geoip2fast-legacy/geoip2fast/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # encoding: utf-8
3 | # -*- coding: utf-8 -*-
4 | """
5 | .oPYo. o .oPYo. .oPYo. ooooo o
6 | 8 8 8 8 8 `8 8 8
7 | 8 .oPYo. .oPYo. 8 o8YooP' oP' o8oo .oPYo. .oPYo. o8P
8 | 8 oo 8oooo8 8 8 8 8 .oP' 8 .oooo8 Yb.. 8
9 | 8 8 8. 8 8 8 8 8' 8 8 8 'Yb. 8
10 | `YooP8 `Yooo' `YooP' 8 8 8ooooo 8 `YooP8 `YooP' 8
11 | :....8 :.....::.....:..:..:::::.......:..:::::.....::.....:::..:
12 | :::::8 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::
13 | :::::..:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
14 | """
15 | __author__ = 'Ricardo Abuchaim'
16 | __license__ = 'MIT'
17 | __version__ = "1.1.11"
18 | __releasedate__ = "20/Jun/2024"
19 |
20 | from geoip2fast.geoip2fast import GeoIP2Fast,GeoIPDetail,UpdateGeoIP2Fast
--------------------------------------------------------------------------------
/geoip2fast-legacy/geoip2fast/geoip2fast-asn-ipv6.dat.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/geoip2fast/geoip2fast-asn-ipv6.dat.gz
--------------------------------------------------------------------------------
/geoip2fast-legacy/geoip2fast/geoip2fast-asn.dat.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/geoip2fast/geoip2fast-asn.dat.gz
--------------------------------------------------------------------------------
/geoip2fast-legacy/geoip2fast/geoip2fast-ipv6.dat.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/geoip2fast/geoip2fast-ipv6.dat.gz
--------------------------------------------------------------------------------
/geoip2fast-legacy/geoip2fast/geoip2fast.dat.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/geoip2fast/geoip2fast.dat.gz
--------------------------------------------------------------------------------
/geoip2fast-legacy/images/cli.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/images/cli.jpg
--------------------------------------------------------------------------------
/geoip2fast-legacy/images/clicode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/images/clicode.png
--------------------------------------------------------------------------------
/geoip2fast-legacy/images/code_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/images/code_example.png
--------------------------------------------------------------------------------
/geoip2fast-legacy/images/coverage_test.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/images/coverage_test.jpg
--------------------------------------------------------------------------------
/geoip2fast-legacy/images/coverage_verbose.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/images/coverage_verbose.jpg
--------------------------------------------------------------------------------
/geoip2fast-legacy/images/geoip2dat01.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/images/geoip2dat01.jpg
--------------------------------------------------------------------------------
/geoip2fast-legacy/images/geoip2dat02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/images/geoip2dat02.jpg
--------------------------------------------------------------------------------
/geoip2fast-legacy/images/geoip2dat03.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/images/geoip2dat03.jpg
--------------------------------------------------------------------------------
/geoip2fast-legacy/images/geoip2fast-win32.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/images/geoip2fast-win32.jpg
--------------------------------------------------------------------------------
/geoip2fast-legacy/images/geoip2fast.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/images/geoip2fast.jpg
--------------------------------------------------------------------------------
/geoip2fast-legacy/images/geoip2fast_selftest.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/images/geoip2fast_selftest.jpg
--------------------------------------------------------------------------------
/geoip2fast-legacy/images/geoip2fastv4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/images/geoip2fastv4.jpg
--------------------------------------------------------------------------------
/geoip2fast-legacy/images/geoip2fastv6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/images/geoip2fastv6.jpg
--------------------------------------------------------------------------------
/geoip2fast-legacy/images/geoipv6_coverage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/images/geoipv6_coverage.jpg
--------------------------------------------------------------------------------
/geoip2fast-legacy/images/speed_test.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast-legacy/images/speed_test.jpg
--------------------------------------------------------------------------------
/geoip2fast-legacy/setup.py:
--------------------------------------------------------------------------------
1 | import codecs
2 | from setuptools import setup, find_packages
3 |
4 | setup(
5 | name='geoip2fast',
6 | version='1.1.11',
7 | description='GeoIP2Fast is the fastest GeoIP2 country/asn lookup library that supports IPv4 and IPv6. A search takes less than 0.00003 seconds. It has its own data file updated twice a week with Maxmind-Geolite2-CSV, supports IPv4/IPv6 and is Pure Python!',
8 | url='https://github.com/rabuchaim/geoip2fast/tree/main/geoip2fast-legacy',
9 | author='Ricardo Abuchaim',
10 | author_email='ricardoabuchaim@gmail.com',
11 | maintainer='Ricardo Abuchaim',
12 | maintainer_email='ricardoabuchaim@gmail.com',
13 | project_urls={
14 | "Issue Tracker": "https://github.com/rabuchaim/geoip2fast/issues",
15 | "Source code": "https://github.com/rabuchaim/geoip2fast/tree/main/geoip2fast-legacy/",
16 | "Latest DAT files for v1.1.X": "https://github.com/rabuchaim/geoip2fast/releases/tag/LEGACY",
17 | },
18 | bugtrack_url='https://github.com/rabuchaim/geoip2fast/issues',
19 | license='MIT',
20 | keywords=['geoip','geoip2','geolite2','maxmind','geoip2fast','geolocation','geolocalization','geo ip','ipaddress','ip','geo','ipv4','ipv6','pure-python','purepython','pure python','geoiptofast','geoiptoofast','geoip2dat','mmdb','tools'],
21 | packages=['geoip2fast'],
22 | py_modules=['geoip2fast','geoip2dat'],
23 | package_dir = {'geoip2fast': 'geoip2fast'},
24 | include_package_data=True,
25 | zip_safe = False,
26 | package_data={
27 | 'geoip2fast': [
28 | 'CHANGELOG',
29 | 'geoip2fast.dat.gz',
30 | 'geoip2fast-ipv6.dat.gz',
31 | 'geoip2fast-asn.dat.gz',
32 | 'geoip2fast-asn-ipv6.dat.gz',
33 | 'tests/geoip2fast_test.py',
34 | 'tests/speed_test.py',
35 | 'tests/coverage_test.py',
36 | 'tests/compare_with_mmdb.py',
37 | 'tests/random_test.py',
38 | 'tests/geoipcli.py',
39 | ],
40 | },
41 | entry_points={
42 | 'console_scripts': [
43 | 'geoip2fast = geoip2fast.geoip2fast:main_function',
44 | 'geoip2dat = geoip2fast.geoip2dat:main_function'
45 | ]
46 | },
47 | python_requires=">=3.7",
48 | install_requires=[],
49 | classifiers=[
50 | 'Development Status :: 5 - Production/Stable',
51 | 'Topic :: Security',
52 | 'Topic :: Internet',
53 | 'Topic :: Internet :: Finger',
54 | 'Topic :: Scientific/Engineering',
55 | 'Topic :: System :: Monitoring',
56 | 'Topic :: System :: Networking',
57 | 'Topic :: System :: Systems Administration',
58 | 'Topic :: Software Development :: Libraries',
59 | 'Topic :: Software Development :: Libraries :: Python Modules',
60 | 'Topic :: Software Development :: Localization',
61 | 'Topic :: Utilities',
62 | 'Intended Audience :: Developers',
63 | 'Intended Audience :: Information Technology',
64 | 'Intended Audience :: System Administrators',
65 | 'Operating System :: MacOS',
66 | 'Operating System :: Microsoft :: Windows :: Windows 10',
67 | 'Operating System :: Microsoft :: Windows :: Windows 11',
68 | 'Operating System :: Unix',
69 | 'Operating System :: POSIX',
70 | 'Operating System :: POSIX :: Linux',
71 | 'Operating System :: POSIX :: BSD',
72 | 'Operating System :: POSIX :: BSD :: FreeBSD',
73 | 'Programming Language :: Python',
74 | 'Programming Language :: Python :: 3',
75 | 'Programming Language :: Python :: 3.7',
76 | 'Programming Language :: Python :: 3.8',
77 | 'Programming Language :: Python :: 3.9',
78 | 'Programming Language :: Python :: 3.10',
79 | 'Programming Language :: Python :: 3.11',
80 | 'Programming Language :: Python :: 3.12',
81 | 'Programming Language :: Python :: 3.13',
82 | 'Programming Language :: Python :: Implementation :: PyPy',
83 | 'License :: OSI Approved :: MIT License',
84 | ],
85 | long_description=codecs.open("README.md","r","utf-8").read(),
86 | long_description_content_type='text/markdown',
87 | )
88 |
--------------------------------------------------------------------------------
/geoip2fast-legacy/tests/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__
2 | GeoLite2-Country.mmdb
3 |
--------------------------------------------------------------------------------
/geoip2fast-legacy/tests/compare_with_mmdb.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | ##──── This test shows what GeoIP2Fast has that Maxmind's MMDB doesn't, and vice versa ──────────────────────────────────────────
4 | ##──── Download the file "GeoLite2-Country.mmdb" from Maxmind website and put it in the same directory ───────────────────────────
5 | ##──── of this script to run the test ────────────────────────────────────────────────────────────────────────────────────────────
6 | ##──── if you have geoipupdate installed, you should already have this file in the directory /var/lib/GeoIP/ It wIll works too ───
7 |
8 | ##──── The BLUE lines shows that GeoIP2Fast result is the same as the Maxmind result with MMDB files. ────────────────────────────
9 | ##──── Lines in RED means that there is a divergence between the base of GeoIP2Fast and Maxmind. ─────────────────────────────────
10 | ##──── You can confirm 'who is right' using whois or geoiplookup application in linux ────────────────────────────────────────────
11 |
12 | import os, sys, re, ctypes
13 | from geoip2fast import GeoIP2Fast
14 | from random import randrange
15 |
16 | try:
17 | import geoip2.database # pip install geoip2
18 | except:
19 | print("Run 'pip install geoip2' first and try again")
20 | sys.exit(1)
21 |
22 | def cRed(msg):
23 | return '\033[91m'+msg+'\033[0m'
24 | def cBlue(msg):
25 | return '\033[94m'+msg+'\033[0m'
26 |
27 | def create_iplist(quant):
28 | a_list = []
29 | for I in range(quant):
30 | IP = f"{randrange(1,224)}.{randrange(0,254)}.{randrange(0,254)}.{randrange(0,254)}"
31 | a_list.append(IP)
32 | if I % 5000 == 0:
33 | print("\rGenerating random IPs: "+str(I+1),end="")
34 | print(f"\rGenerating randomically {len(a_list)} IPs...")
35 | return a_list
36 |
37 | def get_geoip_from_mmdb(ipaddr)->str:
38 | try:
39 | response = reader.country(ipaddr)
40 | return str(response.country.iso_code)
41 | except Exception as ERR:
42 | # print(str(ERR))
43 | return "--"
44 |
45 | if __name__ == "__main__":
46 | GeoIP = GeoIP2Fast(verbose=False)
47 | if os.stat('/var/lib/GeoIP/GeoLite2-Country.mmdb').st_mode:
48 | reader = geoip2.database.Reader('/var/lib/GeoIP/GeoLite2-Country.mmdb',mode=geoip2.database.MODE_MMAP)
49 | else:
50 | reader = geoip2.database.Reader('GeoLite2-Country.mmdb',mode=geoip2.database.MODE_MMAP)
51 |
52 | gIpList = create_iplist(100000)
53 | counter = 0
54 | print("")
55 | print("This test shows what GeoIP2Fast has that Maxmind's MMDB files doesn't")
56 | print("")
57 | print(f"{'IP address'.center(20)}|{'from GeoIP2Fast'.center(20)}|{'from MMDB file'.center(20)}|")
58 | for IP in gIpList:
59 | geoip_info = GeoIP.lookup(IP)
60 | getFromLocal = geoip_info.country_code
61 | getFromMMDB = get_geoip_from_mmdb(IP)
62 |
63 | if getFromLocal == "":
64 | getFromLocal = "--"
65 |
66 | logString = (f"{('IP: '+IP).ljust(20)}|{str(getFromLocal).center(20)}|{str(getFromMMDB).center(20)}|")
67 |
68 | if getFromMMDB != getFromLocal:
69 | print(cRed("\r"+logString))
70 | counter += 1
71 | else:
72 | print(cBlue("\r"+logString),end="")
73 |
74 | # clear the last line
75 | if IP == gIpList[-1]:
76 | print("\r".ljust(105," "),end="")
77 |
78 | print("\n")
79 | print("Lines in RED means that there are a divergence between the base of GeoIP2Fast and Maxmind.")
80 | print("You can confirm 'who is right' checking different sources like a geoip lookup application ")
81 | print("like geoiplookup (ubuntu: apt install geoip-bin) or a whois service (ubuntu: apt install whois)")
82 | print("")
83 | print(" From %s random IP addresses tested, were found %s IP addresses"%((re.sub(r'(? "+IP.ljust(15)+" "+str(geoip.country_code).ljust(3)+str(geoip.country_name).ljust(35)+ \
21 | " ["+geoip.elapsed_time+"]\tAfter cache: ["+GEOIP.lookup(IP).elapsed_time+"] "+geoip.cidr)
22 |
23 | print("")
24 |
25 | result = GEOIP.lookup("200.204.0.10")
26 | print(result)
27 |
28 | # Before call the function get_hostname(), 'hostname' property will always be empty
29 | print("Hostname: "+result.hostname+"\t\t\t << must be empty before call result.get_hostname()")
30 | result.get_hostname()
31 |
32 | print(result)
33 |
34 | # to work with output as a dict, use the function to_dict()
35 | print(result.to_dict()['country_code'],result.to_dict()['country_name'])
36 |
37 | # To pretty print the object result like json.dumps()
38 | result = GEOIP.lookup("200.204.0.138")
39 | result.get_hostname()
40 | print(result.pp_json(indent=3,sort_keys=False))
41 |
42 | # info about internal cache
43 | print(GEOIP.cache_info())
44 |
45 | # clear the internal cache
46 | print(GEOIP.clear_cache())
47 |
48 | # info about internal cache
49 | print(GEOIP.cache_info())
50 |
51 | # to check the date of the CSV files used to create the .dat file
52 | print(GEOIP.get_source_info())
53 |
54 | print("")
55 |
56 | sys.exit(0)
--------------------------------------------------------------------------------
/geoip2fast-legacy/tests/random_test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | from geoip2fast import GeoIP2Fast
3 | from random import randrange
4 | from time import sleep
5 |
6 | MAX_IPS = 1000000
7 | GeoIP = GeoIP2Fast(verbose=True)
8 |
9 | print("\n- Starting a %d random IP test in"%(MAX_IPS),end="")
10 | print(" 3...",end="")
11 | sleep(1)
12 | print(" 2...",end="")
13 | sleep(1)
14 | print(" 1...",end="")
15 | sleep(1)
16 | print("\n")
17 |
18 | avgList, avgCacheList = [], []
19 |
20 | total = 0
21 | while total < MAX_IPS:
22 | IP = f"{randrange(1,223)}.{randrange(0,254)}.{randrange(0,254)}.{randrange(0,254)}"
23 | result = GeoIP.lookup(IP)
24 | avgList.append(float(result.elapsed_time.split(" ")[0]))
25 | total += 1
26 | cachedResult = GeoIP.lookup(IP)
27 | avgCacheList.append(float(cachedResult.elapsed_time.split(" ")[0]))
28 | print(f"IP {result.ip.ljust(20)}{result.country_code.ljust(4)}{result.country_name.ljust(40)}[{result.elapsed_time}] - Cached [{cachedResult.elapsed_time}]")
29 | print("")
30 | print("Test with %d randomic IP addresses."%(MAX_IPS))
31 | print("\t- Average Lookup Time: %.9f seconds. "%(sum(avgList)/MAX_IPS))
32 | print("\t- Average Cached Lookups: %.9f seconds. "%(sum(avgCacheList)/MAX_IPS))
33 | print("")
34 |
35 |
--------------------------------------------------------------------------------
/geoip2fast-legacy/tests/speed_test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | from geoip2fast import GeoIP2Fast
3 |
4 | GeoIP = GeoIP2Fast(verbose=True)
5 |
6 | print("\n- Starting 'lookups per second' test...\n")
7 | GeoIP.calculate_speed(print_result=True)
8 | print("")
9 |
--------------------------------------------------------------------------------
/geoip2fast/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # encoding: utf-8
3 | # -*- coding: utf-8 -*-
4 | """
5 | .oPYo. o .oPYo. .oPYo. ooooo o
6 | 8 8 8 8 8 `8 8 8
7 | 8 .oPYo. .oPYo. 8 o8YooP' oP' o8oo .oPYo. .oPYo. o8P
8 | 8 oo 8oooo8 8 8 8 8 .oP' 8 .oooo8 Yb.. 8
9 | 8 8 8. 8 8 8 8 8' 8 8 8 'Yb. 8
10 | `YooP8 `Yooo' `YooP' 8 8 8ooooo 8 `YooP8 `YooP' 8
11 | :....8 :.....::.....:..:..:::::.......:..:::::.....::.....:::..:
12 | :::::8 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::
13 | :::::..:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
14 | """
15 | __author__ = 'Ricardo Abuchaim'
16 | __license__ = 'MIT'
17 | __version__ = "1.2.2"
18 | __releasedate__ = "20/Jun/2024"
19 |
20 | from geoip2fast.geoip2fast import GeoIP2Fast,GeoIPDetail,GeoIPDetailCity,UpdateGeoIP2Fast
--------------------------------------------------------------------------------
/geoip2fast/geoip2fast-asn-ipv6.dat.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast/geoip2fast-asn-ipv6.dat.gz
--------------------------------------------------------------------------------
/geoip2fast/geoip2fast-asn.dat.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast/geoip2fast-asn.dat.gz
--------------------------------------------------------------------------------
/geoip2fast/geoip2fast-city-asn-ipv6.dat.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast/geoip2fast-city-asn-ipv6.dat.gz
--------------------------------------------------------------------------------
/geoip2fast/geoip2fast-city-asn.dat.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast/geoip2fast-city-asn.dat.gz
--------------------------------------------------------------------------------
/geoip2fast/geoip2fast-city-ipv6.dat.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast/geoip2fast-city-ipv6.dat.gz
--------------------------------------------------------------------------------
/geoip2fast/geoip2fast-city.dat.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast/geoip2fast-city.dat.gz
--------------------------------------------------------------------------------
/geoip2fast/geoip2fast-ipv6.dat.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast/geoip2fast-ipv6.dat.gz
--------------------------------------------------------------------------------
/geoip2fast/geoip2fast.dat.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/geoip2fast/geoip2fast.dat.gz
--------------------------------------------------------------------------------
/geoip2fast/geoip2fastmin.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # encoding: utf-8
3 | # -*- coding: utf-8 -*-
4 | """
5 | GeoIP2FastMin - Version v1.2.2
6 |
7 | Author: Ricardo Abuchaim - ricardoabuchaim@gmail.com
8 | https://github.com/rabuchaim/geoip2fast/
9 |
10 | License: MIT
11 |
12 | .oPYo. o .oPYo. .oPYo. ooooo o o o o
13 | 8 8 8 8 8 `8 8 8 8b d8
14 | 8 .oPYo. .oPYo. 8 o8YooP' oP' o8oo .oPYo. .oPYo. o8P 8`b d'8 o8 odYo.
15 | 8 oo 8oooo8 8 8 8 8 .oP' 8 .oooo8 Yb.. 8 8 `o' 8 8 8' `8
16 | 8 8 8. 8 8 8 8 8' 8 8 8 'Yb. 8 8 8 8 8 8
17 | `YooP8 `Yooo' `YooP' 8 8 8ooooo 8 `YooP8 `YooP' 8 8 8 8 8 8
18 | :....8 :.....::.....:..:..:::::.......:..:::::.....::.....:::..:::..::::..:....::..
19 | :::::8 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
20 | :::::..::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
21 |
22 | This version has been reduced to essential functions. Just copy the entire class and paste it into your
23 | code and use the GeoIP2Fast databases with countries, cities and asn. Is Pure Python! No dependencies.
24 |
25 | From GeoIP2Fast's natural code, we removed the coverage testing functions, missing ips, automatic updates,
26 | and a few other things. Nothing that affects speed. Usage examples:
27 |
28 | G = GeoIP2FastMin(verbose=False,geoip2fast_data_file="")
29 |
30 | print(G.startup_line_text)
31 | print(G.database_path)
32 |
33 | result = G.lookup("1.1.1.1")
34 |
35 | print(result.country_code)
36 | print(result.country_name)
37 | print(result.cidr)
38 | print(result.pp_json())
39 | G.self_test(max_ips=30)
40 |
41 | """
42 |
43 | class GeoIP2FastMin(object):
44 | import os, sys, bisect, pickle, ctypes, subprocess, gzip, json, random, socket, struct, binascii, time
45 | __appid__ = "GeoIP2Fast"
46 | __version__ = "1.2.2"
47 | GEOIP2FAST_DAT_GZ_FILE = os.path.join(os.path.dirname(__file__),"geoip2fast.dat.gz")
48 | os.environ["PYTHONWARNINGS"] = "ignore"
49 | os.environ["PYTHONIOENCODING"] = "utf-8"
50 | ##──── Define here what do you want to return if one of these errors occurs ─────────────────────────────────────────────────────
51 | ##──── ECCODE = Error Country Code ───────────────────────────────────────────────────────────────────────────────────────────────
52 | GEOIP_ECCODE_PRIVATE_NETWORKS, GEOIP_ECCODE_NETWORK_NOT_FOUND = "--", "--"
53 | GEOIP_ECCODE_INVALID_IP, GEOIP_ECCODE_LOOKUP_INTERNAL_ERROR = "", ""
54 | GEOIP_NOT_FOUND_STRING = ""
55 | GEOIP_INTERNAL_ERROR_STRING = ""
56 | GEOIP_INVALID_IP_STRING = ""
57 | ##──── Number os possible IPs in a network range. (/0, /1 .. /8 .. /24 .. /30, /31, /32) ─────────────────────────────────────────
58 | numIPsv4 = sorted([2**num for num in range(0,33)],reverse=True) # from 0 to 32
59 | numIPsv6 = sorted([2**num for num in range(0,129)],reverse=True) # from 0 to 128
60 | MAX_IPv4 = numIPsv4[0]
61 | ##──── CLASS INIT ────────────────────────────────────────────────────────────────────────────────────────────────────────────────
62 | def __init__(self, verbose=False, geoip2fast_data_file=""):
63 | self.name = "GeoIP2FastMin"
64 | self.ipv6, self.city, self.asn, self.is_loaded = False, False, False, False
65 | self.data_file, self._load_data_text = "", ''
66 | self.verbose = verbose
67 | if verbose == False:
68 | self._print_verbose = self.__print_verbose_empty
69 | ##──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
70 | self.error_code_private_networks = self.GEOIP_ECCODE_PRIVATE_NETWORKS
71 | self.error_code_network_not_found = self.GEOIP_ECCODE_NETWORK_NOT_FOUND
72 | self.error_code_invalid_ip = self.GEOIP_ECCODE_INVALID_IP
73 | self.error_code_lookup_internal_error = self.GEOIP_ECCODE_LOOKUP_INTERNAL_ERROR
74 | ##──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
75 | if geoip2fast_data_file != "":
76 | try:
77 | if self.os.path.isfile(geoip2fast_data_file) == True:
78 | self.data_file = geoip2fast_data_file
79 | else:
80 | if geoip2fast_data_file.find("/") < 0:
81 | databasePath = self.__locate_database_file(geoip2fast_data_file)
82 | if databasePath is False:
83 | raise self.GeoIPError("Unable to find GeoIP2Fast database file %s"%(self.os.path.basename(geoip2fast_data_file)))
84 | else:
85 | self.data_file = databasePath
86 | else:
87 | raise self.GeoIPError("Check path of specified file and try again.")
88 | except Exception as ERR:
89 | raise self.GeoIPError("Unable to access the specified file %s. %s"%(geoip2fast_data_file,str(ERR)))
90 |
91 | self.__load_data(self.data_file, verbose)
92 | ##──── GeoIP2Fast Exception Class ────────────────────────────────────────────────────────────────────────────────────────────────
93 | class GeoIPError(Exception):
94 | def __init__(self, message):
95 | self.message = message
96 | def __str__(self):
97 | return self.message
98 | def __repr__(self):
99 | return self.message
100 | class CityDetail(object):
101 | def __init__(self, city_string="||||"):
102 | try:
103 | self.name, self.subdivision_code, self.subdivision_name, self.subdivision2_code, self.subdivision2_name = city_string.split("|")
104 | except:
105 | self.name, self.subdivision_code, self.subdivision_name, self.subdivision2_code, self.subdivision2_name = GeoIP2FastMin.GEOIP_INTERNAL_ERROR_STRING,"","","",""
106 | def to_dict(self):
107 | return {
108 | "name": self.name,
109 | "subdivision_code": self.subdivision_code,
110 | "subdivision_name": self.subdivision_name}
111 | ##──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
112 | class GeoIPDetail(object):
113 | def __init__(self, ip, country_code="", country_name="", cidr="", is_private=False, asn_name="", asn_cidr="", elapsed_time=""):
114 | self.ip, self.country_code, self.country_name, self.cidr, self.hostname = ip, country_code, country_name, cidr, ""
115 | self.is_private, self.asn_name, self.asn_cidr, self.elapsed_time = is_private, asn_name, asn_cidr, elapsed_time
116 | @property
117 | def city(self):
118 | return GeoIP2FastMin.CityDetail()
119 | def __str__(self):
120 | return f"{self.__dict__}"
121 | def __repr__(self):
122 | return f"{self.to_dict()}"
123 | def get_hostname(self,dns_timeout=0.1):
124 | try:
125 | startTime = GeoIP2FastMin.time.perf_counter()
126 | self.socket.setdefaulttimeout(dns_timeout)
127 | result = self.socket.gethostbyaddr(self.ip)[0]
128 | self.hostname = result if result != self.ip else ""
129 | self.elapsed_time_hostname = "%.9f sec"%(GeoIP2FastMin.time.perf_counter()-startTime)
130 | return self.hostname
131 | except OSError as ERR:
132 | self.hostname = f"<{str(ERR.strerror)}>"
133 | return self.hostname
134 | except Exception as ERR:
135 | self.hostname = ""
136 | return self.hostname
137 | def to_dict(self):
138 | try:
139 | d = {
140 | "ip": self.ip,
141 | "country_code": self.country_code,
142 | "country_name": self.country_name,
143 | "city":'',
144 | "cidr": self.cidr,
145 | "hostname": self.hostname,
146 | "asn_name": self.asn_name,
147 | "asn_cidr": self.asn_cidr,
148 | "is_private": self.is_private,
149 | "elapsed_time": self.elapsed_time
150 | }
151 | if not hasattr(self, 'city'):
152 | del d['city']
153 | try:
154 | a = self.elapsed_time_hostname
155 | d['elapsed_time_hostname'] = self.elapsed_time_hostname
156 | except:
157 | pass
158 | return d
159 | except Exception as ERR:
160 | raise GeoIP2FastMin.GeoIPError("Failed to_dict() %s"%(str(ERR)))
161 | def pp_json(self,indent=3,sort_keys=False,print_result=False):
162 | try:
163 | dump = GeoIP2FastMin.json.dumps(self.to_dict(),sort_keys=sort_keys,indent=indent,ensure_ascii=False)
164 | if print_result == True:
165 | print(dump)
166 | return dump
167 | except Exception as ERR:
168 | raise GeoIP2FastMin.GeoIPError("Failed pp_json() %s"%(str(ERR)))
169 | class GeoIPDetailCity(GeoIPDetail):
170 | """Extended version of GeoIPDetail with city information
171 | """
172 | def __init__(self, ip, country_code="", country_name="", city=None, cidr="", is_private=False, asn_name="", asn_cidr="", elapsed_time=""):
173 | super().__init__(ip, country_code, country_name, cidr, is_private, asn_name, asn_cidr, elapsed_time)
174 | self._city = city if city else GeoIP2FastMin.CityDetail()
175 | @property
176 | def city(self):
177 | return self._city
178 | @city.setter
179 | def city(self, value):
180 | raise AttributeError("Cannot set 'city' attribute in GeoIPDetailCity")
181 | def to_dict(self):
182 | base_dict = super().to_dict()
183 | base_dict['city'] = self.city.to_dict()
184 | return base_dict
185 | ##──── Function used to avoid "if verbose == True". The code is swaped at __init__ ───────────────────────────────────────────────
186 | def __print_verbose_empty(self,msg):return
187 | def __print_verbose_regular(self,msg):
188 | print(msg,flush=True)
189 | def _print_debug(self,msg):
190 | print("[DEBUG] "+msg,flush=True)
191 | def _print_verbose(self,msg):
192 | print(msg,flush=True)
193 | ##────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
194 | ##──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
195 | def __locate_database_file(self, filename):
196 | try:
197 | curDir = self.os.path.join(self.os.path.abspath(self.os.path.curdir),filename) # path of your application
198 | libDir = self.os.path.join(self.os.path.dirname(__file__),filename) # path where the library is installed
199 | except Exception as ERR:
200 | raise GeoIP2FastMin.GeoIPError("Unable to determine the path of application %s. %s"%(filename,str(ERR)))
201 | try:
202 | self.os.stat(curDir).st_mode
203 | return curDir
204 | except Exception as ERR:
205 | try:
206 | self.os.stat(libDir).st_mode
207 | return libDir
208 | except Exception as ERR:
209 | raise GeoIP2FastMin.GeoIPError("Unable to determine the path of library %s - %s"%(filename,str(ERR)))
210 | ##──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
211 | def __load_data(self, gzip_data_file:str, verbose=False)->bool:
212 | global __DAT_VERSION__, source_info, totalNetworks,mainListNamesCountry,geoipCountryNamesDict,geoipCountryCodesList,\
213 | mainIndex,mainListNamesCountry,mainListFirstIP,mainListIDCountryCodes,mainListNetlength,\
214 | mainIndexASN,mainListNamesASN,mainListFirstIPASN,mainListIDASN,mainListNetlengthASN,\
215 | mainListNamesCity, mainListIDCity
216 | if self.is_loaded == True:
217 | return True
218 | self._print_verbose = self.__print_verbose_regular if verbose == True else self.__print_verbose_empty
219 | startMem = self.get_mem_usage()
220 | startLoadData = self.time.perf_counter()
221 | ##──── Try to locate the database file in the directory of the application that called GeoIP2Fast() ─────────────────────────
222 | ##──── or in the directory of the GeoIP2Fast Library ────────────────────────────────────────────────────────────────────────
223 | try:
224 | if gzip_data_file == "":
225 | gzip_data_file = GeoIP2FastMin.GEOIP2FAST_DAT_GZ_FILE
226 | try:
227 | databasePath = self.__locate_database_file(self.os.path.basename(gzip_data_file))
228 | if databasePath is False:
229 | raise GeoIP2FastMin.GeoIPError("(1) Unable to find GeoIP2Fast database file %s"%(self.os.path.basename(gzip_data_file)))
230 | else:
231 | self.data_file = databasePath
232 | except Exception as ERR:
233 | raise GeoIP2FastMin.GeoIPError("(2) Unable to find GeoIP2Fast database file %s %s"%(self.os.path.basename(gzip_data_file),str(ERR)))
234 | except Exception as ERR:
235 | raise GeoIP2FastMin.GeoIPError("Failed at locate data file %s"%(str(ERR)))
236 | ##──── Open the dat.gz file ──────────────────────────────────────────────────────────────────────────────────────────────────────
237 | try:
238 | try:
239 | inputFile = self.gzip.open(str(self.data_file),'rb')
240 | except:
241 | try:
242 | inputFile = open(str(self.data_file).replace(".gz",""),'rb')
243 | self.data_file = self.data_file.replace(".gz","")
244 | except Exception as ERR:
245 | raise GeoIP2FastMin.GeoIPError(f"Unable to find {gzip_data_file} or {gzip_data_file} {str(ERR)}")
246 | except Exception as ERR:
247 | raise GeoIP2FastMin.GeoIPError(f"Failed to 'load' GeoIP2Fast! the data file {gzip_data_file} appears to be invalid or does not exist! {str(ERR)}")
248 | ##────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
249 | self._database_path = self.os.path.realpath(self.data_file)
250 | ##──── Load the dat.gz file into memory ──────────────────────────────────────────────────────────────────────────────────────────
251 | try:
252 | __DAT_VERSION__, source_info, totalNetworks, mainDatabase = self.pickle.load(inputFile)
253 | if __DAT_VERSION__ != 120:
254 | raise GeoIP2FastMin.GeoIPError(f"Failed to pickle the data file {gzip_data_file}. Reason: Invalid version - requires 120, current {str(__DAT_VERSION__)}")
255 | self.source_info = source_info['info']
256 | self.country = source_info['country']
257 | self.city = source_info['city']
258 | self.asn = source_info['asn']
259 | ##──── ONLY COUNTRY ──────────────────────────────────────────────────────────────────────────────────────────────────────────────
260 | if self.country == True and self.asn == False:
261 | mainIndex,mainListNamesCountry,mainListFirstIP,mainListIDCountryCodes,mainListNetlength = mainDatabase
262 | ##──── COUNTRY WITH ASN ──────────────────────────────────────────────────────────────────────────────────────────────────────────
263 | elif self.country == True and self.asn == True:
264 | mainIndex,mainIndexASN,mainListNamesCountry,mainListNamesASN,mainListFirstIP,\
265 | mainListFirstIPASN,mainListIDCountryCodes,mainListIDASN,mainListNetlength,mainListNetlengthASN = mainDatabase
266 | ##──── ONLY CITY ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────
267 | elif self.city == True and self.asn == False:
268 | mainIndex,mainListNamesCountry,mainListNamesCity,mainListFirstIP,mainListIDCity,mainListNetlength = mainDatabase
269 | ##──── CITY WITH ASN ─────────────────────────────────────────────────────────────────────────────────────────────────────────────
270 | elif self.city == True and self.asn == True:
271 | mainIndex,mainIndexASN,mainListNamesCountry,mainListNamesCity,mainListNamesASN,\
272 | mainListFirstIP,mainListFirstIPASN,mainListIDCity,mainListIDASN,mainListNetlength,mainListNetlengthASN = mainDatabase
273 | self.ipv6 = mainIndex[-1] > GeoIP2FastMin.numIPsv4[0]
274 | geoipCountryNamesDict = {item.split(":")[0]:item.split(":")[1] for item in mainListNamesCountry}
275 | geoipCountryCodesList = list(geoipCountryNamesDict.keys())
276 | inputFile.close()
277 | del inputFile
278 | except Exception as ERR:
279 | raise GeoIP2FastMin.GeoIPError(f"Failed to pickle the data file {gzip_data_file} {str(ERR)}")
280 | ##──── Warming-up ────────────────────────────────────────────────────────────────────────────────────────────────────────────────
281 | try:
282 | [self._main_index_lookup(iplong) for iplong in [2894967295]]
283 | except Exception as ERR:
284 | raise GeoIP2FastMin.GeoIPError("Failed at warming-up... exiting... %s"%(str(ERR)))
285 | ##──── Load Time Info ──────────────────────────────────────────────────────────────────────────────────────────────────────────
286 | try:
287 | totalLoadTime = (self.time.perf_counter() - startLoadData)
288 | totalMemUsage = abs((self.get_mem_usage() - startMem))
289 | self._load_data_text = f"GeoIP2Fast v{self.__version__} is ready! {self.os.path.basename(gzip_data_file)} "+ \
290 | "loaded with %s networks in %.5f seconds and using %.2f MiB."%('{:,d}'.format(totalNetworks).replace(',','.'),totalLoadTime,totalMemUsage)
291 | self._print_verbose(self._load_data_text)
292 | except Exception as ERR:
293 | raise GeoIP2FastMin.GeoIPError("Failed at the end of load data %s"%(str(ERR)))
294 | ##────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
295 | self.is_loaded = True
296 | return True
297 | @property
298 | def startup_line_text(self):
299 | return self._load_data_text
300 | def _main_index_lookup(self,iplong):
301 | try:
302 | matchRoot = self.bisect.bisect_right(mainIndex,iplong)-1
303 | matchChunk = self.bisect.bisect_right(mainListFirstIP[matchRoot],iplong)-1
304 | first_ip2int = mainListFirstIP[matchRoot][matchChunk]
305 | netlen = mainListNetlength[matchRoot][matchChunk]
306 | if iplong <= GeoIP2FastMin.MAX_IPv4:
307 | last_ip2int = first_ip2int + GeoIP2FastMin.numIPsv4[netlen]-1
308 | else:
309 | last_ip2int = first_ip2int + GeoIP2FastMin.numIPsv6[netlen]-1
310 | return matchRoot, matchChunk, first_ip2int, last_ip2int, netlen
311 | except Exception as ERR:
312 | return GeoIP2FastMin.GeoIPError("Failed at _main_index_lookup: %s"%(str(ERR)))
313 | def _country_lookup(self,match_root,match_chunk):
314 | try:
315 | country_code_index = mainListIDCountryCodes[match_root][match_chunk]
316 | country_code, country_name = mainListNamesCountry[country_code_index].split(":")
317 | is_private = country_code_index < 16
318 | country_code = self.error_code_private_networks if is_private else country_code
319 | return country_code, country_name, is_private
320 | except Exception as ERR:
321 | return GeoIP2FastMin.GeoIPError("Failed at _country_lookup: %s"%(str(ERR)))
322 | def _city_country_name_lookup(self,country_code):
323 | try:
324 | country_name = geoipCountryNamesDict[country_code]
325 | country_code_index = geoipCountryCodesList.index(country_code)
326 | is_private = country_code_index < 16
327 | country_code = self.error_code_private_networks if is_private else country_code
328 | return country_code, country_name, is_private
329 | except Exception as ERR:
330 | return GeoIP2FastMin.GeoIPError("Failed at _city_country_name_lookup: %s"%(str(ERR)))
331 | def _city_lookup(self,match_root,match_chunk):
332 | try:
333 | code = mainListIDCity[match_root][match_chunk]
334 | country_code, city_name = mainListNamesCity[code].split(":")
335 | country_code, country_name, is_private = self._city_country_name_lookup(country_code)
336 | city_info = GeoIP2FastMin.CityDetail(city_name)
337 | return country_code, country_name, city_info, is_private
338 | except Exception as ERR:
339 | return GeoIP2FastMin.GeoIPError("Failed at _country_lookup: %s"%(str(ERR)))
340 | def _asn_lookup(self,iplong):
341 | if self.asn == False:
342 | return "", ""
343 | try:
344 | matchRoot = self.bisect.bisect_right(mainIndexASN,iplong)-1
345 | matchChunk = self.bisect.bisect_right(mainListFirstIPASN[matchRoot],iplong)-1
346 | first_ip2int = mainListFirstIPASN[matchRoot][matchChunk]
347 | asn_id = mainListIDASN[matchRoot][matchChunk]
348 | netlen = mainListNetlengthASN[matchRoot][matchChunk]
349 | if not self.ipv6:
350 | if iplong > ((first_ip2int + GeoIP2FastMin.numIPsv4[netlen]) - 1):
351 | return "", ""
352 | else:
353 | if iplong > ((first_ip2int + GeoIP2FastMin.numIPsv6[netlen]) - 1):
354 | return "", ""
355 | return mainListNamesASN[asn_id], self._int2ip(first_ip2int)+"/"+str(netlen)
356 | except Exception as ERR:
357 | return "", ""
358 | def _ip2int(self,ipaddr:str)->int:
359 | try:
360 | try:
361 | return int(self.struct.unpack('>L', self.socket.inet_aton(ipaddr))[0])
362 | except:
363 | return int.from_bytes(self.socket.inet_pton(self.socket.AF_INET6, ipaddr), byteorder='big')
364 | except Exception as ERR:
365 | raise GeoIP2FastMin.GeoIPError("Failed at ip2int: %s"%(str(ERR)))
366 | def _int2ip(self,iplong:int)->str:
367 | try:
368 | if iplong < GeoIP2FastMin.MAX_IPv4:
369 | return self.socket.inet_ntoa(self.struct.pack('>L', iplong))
370 | else:
371 | return self.socket.inet_ntop(self.socket.AF_INET6, self.binascii.unhexlify(hex(iplong)[2:].zfill(32)))
372 | except Exception as ERR:
373 | raise GeoIP2FastMin.GeoIPError("Failed at int2ip: %s"%(str(ERR)))
374 | def set_error_code_private_networks(self,new_value)->str:
375 | global GEOIP_ECCODE_PRIVATE_NETWORKS
376 | try:
377 | self.error_code_private_networks = new_value
378 | GEOIP_ECCODE_PRIVATE_NETWORKS = new_value
379 | return new_value
380 | except Exception as ERR:
381 | raise GeoIP2FastMin.GeoIPError("Unable to set a new value for GEOIP_ECCODE_PRIVATE_NETWORKS: %s"%(str(ERR)))
382 | def set_error_code_network_not_found(self,new_value)->str:
383 | global GEOIP_ECCODE_NETWORK_NOT_FOUND
384 | try:
385 | self.error_code_network_not_found = new_value
386 | GEOIP_ECCODE_NETWORK_NOT_FOUND = new_value
387 | return new_value
388 | except Exception as ERR:
389 | raise GeoIP2FastMin.GeoIPError("Unable to set a new value for GEOIP_ECCODE_NETWORK_NOT_FOUND: %s"%(str(ERR)))
390 | ##──── NO-CACHE: This function cannot be cached to don´t cache the elapsed timer. ────────────────────────────────────────────────────────────
391 | def lookup(self,ipaddr:str)->GeoIPDetail:
392 | startTime = self.time.perf_counter()
393 | try:
394 | iplong = self._ip2int(ipaddr)
395 | except Exception as ERR:
396 | return GeoIP2FastMin.GeoIPDetail(ipaddr,country_code=self.error_code_invalid_ip,\
397 | country_name=GeoIP2FastMin.GEOIP_INVALID_IP_STRING,elapsed_time='%.9f sec'%(self.time.perf_counter()-startTime))
398 | try:
399 | matchRoot, matchChunk, first_ip2int, last_ip2int, netlen = self._main_index_lookup(iplong)
400 | if iplong > last_ip2int:
401 | return GeoIP2FastMin.GeoIPDetail(ip=ipaddr,country_code=self.error_code_network_not_found, \
402 | country_name=GeoIP2FastMin.GEOIP_NOT_FOUND_STRING,elapsed_time='%.9f sec'%(self.time.perf_counter()-startTime))
403 | cidr = self._int2ip(first_ip2int)+"/"+str(netlen)
404 | asn_name, asn_cidr = self._asn_lookup(iplong)
405 | if self.country:
406 | country_code, country_name, is_private = self._country_lookup(matchRoot, matchChunk)
407 | ##──── SUCCESS! ────
408 | return GeoIP2FastMin.GeoIPDetail(ipaddr,country_code,country_name,cidr,is_private,asn_name,asn_cidr,elapsed_time='%.9f sec'%((self.time.perf_counter()-startTime)))
409 | else:
410 | country_code, country_name, city_info, is_private = self._city_lookup(matchRoot, matchChunk)
411 | ##──── SUCCESS! ────
412 | try:
413 | return GeoIP2FastMin.GeoIPDetailCity(ipaddr,country_code,country_name,city_info,cidr,is_private,asn_name,asn_cidr,elapsed_time='%.9f sec'%((self.time.perf_counter()-startTime)))
414 | except Exception as ERR:
415 | raise Exception(ERR)
416 | ##────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
417 | except Exception as ERR:
418 | return GeoIP2FastMin.GeoIPDetail(ip=ipaddr,country_code=self.error_code_lookup_internal_error,\
419 | country_name=GeoIP2FastMin.GEOIP_INTERNAL_ERROR_STRING,elapsed_time='%.9f sec'%(self.time.perf_counter()-startTime))
420 | #──── GET MEMORY USAGE ───────────────────────────────────────────────────────────────────────────────────────────────────────
421 | def get_mem_usage(self)->float:
422 | ''' Memory usage in MiB '''
423 | PROCESS_QUERY_INFORMATION = 0x0400
424 | PROCESS_VM_READ = 0x0010
425 | class PROCESS_MEMORY_COUNTERS(self.ctypes.Structure):
426 | _fields_ = [("cb", self.ctypes.c_ulong),
427 | ("PageFaultCount", self.ctypes.c_ulong),
428 | ("PeakWorkingSetSize", self.ctypes.c_size_t),
429 | ("WorkingSetSize", self.ctypes.c_size_t),
430 | ("QuotaPeakPagedPoolUsage", self.ctypes.c_size_t),
431 | ("QuotaPagedPoolUsage", self.ctypes.c_size_t),
432 | ("QuotaPeakNonPagedPoolUsage", self.ctypes.c_size_t),
433 | ("QuotaNonPagedPoolUsage", self.ctypes.c_size_t),
434 | ("PagefileUsage", self.ctypes.c_size_t),
435 | ("PeakPagefileUsage", self.ctypes.c_size_t)]
436 | try:
437 | result = self.subprocess.check_output(['ps', '-p', str(self.os.getpid()), '-o', 'rss='])
438 | return float(int(result.strip()) / 1024)
439 | except:
440 | try:
441 | pid = self.ctypes.windll.kernel32.GetCurrentProcessId()
442 | process_handle = self.ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, False, pid)
443 | counters = PROCESS_MEMORY_COUNTERS()
444 | counters.cb = self.ctypes.sizeof(PROCESS_MEMORY_COUNTERS)
445 | if self.ctypes.windll.psapi.GetProcessMemoryInfo(process_handle, self.ctypes.byref(counters), self.ctypes.sizeof(counters)):
446 | memory_usage = counters.WorkingSetSize
447 | return float((int(memory_usage) / 1024) / 1024)
448 | except:
449 | return 0.0
450 | def self_test(self,max_ips=30):
451 | """
452 | Do a self-test with some random IPs
453 | """
454 | ip_list = []
455 | ip_list.append("x"+self._int2ip(self.random.randint(16777216,3758096383)).replace(".",",")) # generates an invalid IP inserting the 'x' letter and changing dot by comma
456 | ip_list.append(self._int2ip(self.random.randint(16777216,3758096383))+"/32") # generates an invalid IP adding '/32' to the end. Is a valid CIDR but an invalid IP
457 | ip_list.append(self._int2ip(self.random.randint(397189376,397191423))) # generates a random IP between 23.172.161.0 and 23.172.168.255 to force a 'not found' response
458 | ip_list.append(self._int2ip(self.random.choice([self.random.randint(167772160,184549375),self.random.randint(3232235520,3232301055),self.random.randint(2886729728,2887778303)]))) # generates a random IP of a private network
459 | while len(ip_list) < max_ips:
460 | ip_list.append(self._int2ip(self.random.randint(16777216,3758096383)))
461 | print("\nStarting a self-test with %s randomic IPv4 addresses...\n"%('{:,d}'.format(len(ip_list))))
462 | avgList, avgCacheList = [], []
463 | for IP in ip_list:
464 | geoip = self.lookup(IP)
465 | avgList.append(float(geoip.elapsed_time.split(" ")[0]))
466 | cachedResult = self.lookup(IP)
467 | avgCacheList.append(float(cachedResult.elapsed_time.split(" ")[0]))
468 | print("> "+IP.ljust(18)+" "+str(geoip.country_code).ljust(3)+str(geoip.country_name[:30]).ljust(30)+ \
469 | " ["+geoip.elapsed_time+"] Cached > ["+cachedResult.elapsed_time+"] "+geoip.asn_name)
470 | print("\n\t- Average Lookup Time: %.9f seconds - Average Cached Lookups: %.9f seconds.\n"%(sum(sorted(avgList)[1:-1])/(len(ip_list)-2),sum(sorted(avgCacheList)[1:-1])/(len(ip_list)-2)))
471 |
472 | if __name__ == "__main__":
473 | G = GeoIP2FastMin(verbose=True,geoip2fast_data_file="")
474 | G.self_test()
--------------------------------------------------------------------------------
/geoip2fast/geoip2fastminified.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # encoding: utf-8
3 | # -*- coding: utf-8 -*-
4 | """
5 | GeoIP2FastMin - Version v1.2.2
6 |
7 | Author: Ricardo Abuchaim - ricardoabuchaim@gmail.com
8 | https://github.com/rabuchaim/geoip2fast/
9 |
10 | License: MIT
11 |
12 | .oPYo. o .oPYo. .oPYo. ooooo o o o o o d'b o 8
13 | 8 8 8 8 8 `8 8 8 8b d8 8 8
14 | 8 .oPYo. .oPYo. 8 o8YooP' oP' o8oo .oPYo. .oPYo. o8P 8`b d'8 o8 odYo. o8 o8P o8 .oPYo. .oPYo8
15 | 8 oo 8oooo8 8 8 8 8 .oP' 8 .oooo8 Yb.. 8 8 `o' 8 8 8' `8 8 8 8 8oooo8 8 8
16 | 8 8 8. 8 8 8 8 8' 8 8 8 'Yb. 8 8 8 8 8 8 8 8 8 8. 8 8
17 | `YooP8 `Yooo' `YooP' 8 8 8ooooo 8 `YooP8 `YooP' 8 8 8 8 8 8 8 8 8 `Yooo' `YooP'
18 | :....8 :.....::.....:..:..:::::.......:..:::::.....::.....:::..:::..::::..:....::..:..:..:::..:.....::.....:
19 | :::::8 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
20 | :::::..:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
21 |
22 | This version was minified by pyminify. Just copy the entire class and paste it into your code and use the
23 | GeoIP2Fast databases with countries, cities and asn. Is Pure Python! No dependencies.
24 |
25 | From GeoIP2Fast's natural code, we removed the coverage testing functions, missing ips, automatic updates,
26 | and a few other things. Nothing that affects speed. Usage examples:
27 |
28 | G = GeoIP2FastMin(verbose=False,geoip2fast_data_file="")
29 |
30 | print(G.startup_line_text)
31 | print(G.database_path)
32 |
33 | result = G.lookup("1.1.1.1")
34 |
35 | print(result.country_code)
36 | print(result.country_name)
37 | print(result.cidr)
38 | print(result.pp_json())
39 | G.self_test(max_ips=30)
40 |
41 | """
42 | class GeoIP2FastMin:
43 | import os,sys,bisect,pickle,ctypes,subprocess,gzip,json,random,socket,struct,binascii,time;__appid__='GeoIP2Fast';__version__='1.2.2';GEOIP2FAST_DAT_GZ_FILE=os.path.join(os.path.dirname(__file__),'geoip2fast.dat.gz');os.environ['PYTHONWARNINGS']='ignore';os.environ['PYTHONIOENCODING']='utf-8';GEOIP_ECCODE_PRIVATE_NETWORKS,GEOIP_ECCODE_NETWORK_NOT_FOUND='--','--';GEOIP_ECCODE_INVALID_IP,GEOIP_ECCODE_LOOKUP_INTERNAL_ERROR='','';GEOIP_NOT_FOUND_STRING='';GEOIP_INTERNAL_ERROR_STRING='';GEOIP_INVALID_IP_STRING='';numIPsv4=sorted([2**A for A in range(0,33)],reverse=True);numIPsv6=sorted([2**A for A in range(0,129)],reverse=True);MAX_IPv4=numIPsv4[0]
44 | def __init__(A,verbose=False,geoip2fast_data_file=''):
45 | C=verbose;B=geoip2fast_data_file;A.name='GeoIP2FastMin';A.ipv6,A.city,A.asn,A.is_loaded=False,False,False,False;A.data_file,A._load_data_text='','';A.verbose=C
46 | if C==False:A._print_verbose=A.__print_verbose_empty
47 | A.error_code_private_networks=A.GEOIP_ECCODE_PRIVATE_NETWORKS;A.error_code_network_not_found=A.GEOIP_ECCODE_NETWORK_NOT_FOUND;A.error_code_invalid_ip=A.GEOIP_ECCODE_INVALID_IP;A.error_code_lookup_internal_error=A.GEOIP_ECCODE_LOOKUP_INTERNAL_ERROR
48 | if B!='':
49 | try:
50 | if A.os.path.isfile(B)==True:A.data_file=B
51 | elif B.find('/')<0:
52 | D=A.__locate_database_file(B)
53 | if D is False:raise A.GeoIPError('Unable to find GeoIP2Fast database file %s'%A.os.path.basename(B))
54 | else:A.data_file=D
55 | else:raise A.GeoIPError('Check path of specified file and try again.')
56 | except Exception as E:raise A.GeoIPError('Unable to access the specified file %s. %s'%(B,str(E)))
57 | A.__load_data(A.data_file,C)
58 | class GeoIPError(Exception):
59 | def __init__(A,message):A.message=message
60 | def __str__(A):return A.message
61 | def __repr__(A):return A.message
62 | class CityDetail:
63 | def __init__(A,city_string='||||'):
64 | try:A.name,A.subdivision_code,A.subdivision_name,A.subdivision2_code,A.subdivision2_name=city_string.split('|')
65 | except:A.name,A.subdivision_code,A.subdivision_name,A.subdivision2_code,A.subdivision2_name=GeoIP2FastMin.GEOIP_INTERNAL_ERROR_STRING,'','','',''
66 | def to_dict(A):return{'name':A.name,'subdivision_code':A.subdivision_code,'subdivision_name':A.subdivision_name}
67 | class GeoIPDetail:
68 | def __init__(A,ip,country_code='',country_name='',cidr='',is_private=False,asn_name='',asn_cidr='',elapsed_time=''):A.ip,A.country_code,A.country_name,A.cidr,A.hostname=ip,country_code,country_name,cidr,'';A.is_private,A.asn_name,A.asn_cidr,A.elapsed_time=is_private,asn_name,asn_cidr,elapsed_time
69 | @property
70 | def city(self):return GeoIP2FastMin.CityDetail()
71 | def __str__(A):return f"{A.__dict__}"
72 | def __repr__(A):return f"{A.to_dict()}"
73 | def get_hostname(A,dns_timeout=.1):
74 | try:D=GeoIP2FastMin.time.perf_counter();A.socket.setdefaulttimeout(dns_timeout);B=A.socket.gethostbyaddr(A.ip)[0];A.hostname=B if B!=A.ip else'';A.elapsed_time_hostname='%.9f sec'%(GeoIP2FastMin.time.perf_counter()-D);return A.hostname
75 | except OSError as C:A.hostname=f"<{str(C.strerror)}>";return A.hostname
76 | except Exception as C:A.hostname='';return A.hostname
77 | def to_dict(A):
78 | try:
79 | B={'ip':A.ip,'country_code':A.country_code,'country_name':A.country_name,'city':'','cidr':A.cidr,'hostname':A.hostname,'asn_name':A.asn_name,'asn_cidr':A.asn_cidr,'is_private':A.is_private,'elapsed_time':A.elapsed_time}
80 | if not hasattr(A,'city'):del B['city']
81 | try:D=A.elapsed_time_hostname;B['elapsed_time_hostname']=A.elapsed_time_hostname
82 | except:pass
83 | return B
84 | except Exception as C:raise GeoIP2FastMin.GeoIPError('Failed to_dict() %s'%str(C))
85 | def pp_json(B,indent=3,sort_keys=False,print_result=False):
86 | try:
87 | A=GeoIP2FastMin.json.dumps(B.to_dict(),sort_keys=sort_keys,indent=indent,ensure_ascii=False)
88 | if print_result==True:print(A)
89 | return A
90 | except Exception as C:raise GeoIP2FastMin.GeoIPError('Failed pp_json() %s'%str(C))
91 | class GeoIPDetailCity(GeoIPDetail):
92 | 'Extended version of GeoIPDetail with city information\n '
93 | def __init__(A,ip,country_code='',country_name='',city=None,cidr='',is_private=False,asn_name='',asn_cidr='',elapsed_time=''):super().__init__(ip,country_code,country_name,cidr,is_private,asn_name,asn_cidr,elapsed_time);A._city=city if city else GeoIP2FastMin.CityDetail()
94 | @property
95 | def city(self):return self._city
96 | @city.setter
97 | def city(self,value):raise AttributeError("Cannot set 'city' attribute in GeoIPDetailCity")
98 | def to_dict(B):A=super().to_dict();A['city']=B.city.to_dict();return A
99 | def __print_verbose_empty(A,msg):0
100 | def __print_verbose_regular(A,msg):print(msg,flush=True)
101 | def _print_debug(A,msg):print('[DEBUG] '+msg,flush=True)
102 | def _print_verbose(A,msg):print(msg,flush=True)
103 | def __locate_database_file(A,filename):
104 | B=filename
105 | try:D=A.os.path.join(A.os.path.abspath(A.os.path.curdir),B);E=A.os.path.join(A.os.path.dirname(__file__),B)
106 | except Exception as C:raise GeoIP2FastMin.GeoIPError('Unable to determine the path of application %s. %s'%(B,str(C)))
107 | try:A.os.stat(D).st_mode;return D
108 | except Exception as C:
109 | try:A.os.stat(E).st_mode;return E
110 | except Exception as C:raise GeoIP2FastMin.GeoIPError('Unable to determine the path of library %s - %s'%(B,str(C)))
111 | def __load_data(A,gzip_data_file,verbose=False):
112 | C=gzip_data_file;global __DAT_VERSION__,source_info,totalNetworks,mainListNamesCountry,geoipCountryNamesDict,geoipCountryCodesList,mainIndex,mainListNamesCountry,mainListFirstIP,mainListIDCountryCodes,mainListNetlength,mainIndexASN,mainListNamesASN,mainListFirstIPASN,mainListIDASN,mainListNetlengthASN,mainListNamesCity,mainListIDCity
113 | if A.is_loaded==True:return True
114 | A._print_verbose=A.__print_verbose_regular if verbose==True else A.__print_verbose_empty;G=A.get_mem_usage();H=A.time.perf_counter()
115 | try:
116 | if C=='':
117 | C=GeoIP2FastMin.GEOIP2FAST_DAT_GZ_FILE
118 | try:
119 | F=A.__locate_database_file(A.os.path.basename(C))
120 | if F is False:raise GeoIP2FastMin.GeoIPError('(1) Unable to find GeoIP2Fast database file %s'%A.os.path.basename(C))
121 | else:A.data_file=F
122 | except Exception as B:raise GeoIP2FastMin.GeoIPError('(2) Unable to find GeoIP2Fast database file %s %s'%(A.os.path.basename(C),str(B)))
123 | except Exception as B:raise GeoIP2FastMin.GeoIPError('Failed at locate data file %s'%str(B))
124 | try:
125 | try:D=A.gzip.open(str(A.data_file),'rb')
126 | except:
127 | try:D=open(str(A.data_file).replace('.gz',''),'rb');A.data_file=A.data_file.replace('.gz','')
128 | except Exception as B:raise GeoIP2FastMin.GeoIPError(f"Unable to find {C} or {C} {str(B)}")
129 | except Exception as B:raise GeoIP2FastMin.GeoIPError(f"Failed to 'load' GeoIP2Fast! the data file {C} appears to be invalid or does not exist! {str(B)}")
130 | A.database_path=A.os.path.realpath(A.data_file)
131 | try:
132 | __DAT_VERSION__,source_info,totalNetworks,E=A.pickle.load(D)
133 | if __DAT_VERSION__!=120:raise GeoIP2FastMin.GeoIPError(f"Failed to pickle the data file {C}. Reason: Invalid version - requires 120, current {str(__DAT_VERSION__)}")
134 | A.source_info=source_info['info'];A.country=source_info['country'];A.city=source_info['city'];A.asn=source_info['asn']
135 | if A.country==True and A.asn==False:mainIndex,mainListNamesCountry,mainListFirstIP,mainListIDCountryCodes,mainListNetlength=E
136 | elif A.country==True and A.asn==True:mainIndex,mainIndexASN,mainListNamesCountry,mainListNamesASN,mainListFirstIP,mainListFirstIPASN,mainListIDCountryCodes,mainListIDASN,mainListNetlength,mainListNetlengthASN=E
137 | elif A.city==True and A.asn==False:mainIndex,mainListNamesCountry,mainListNamesCity,mainListFirstIP,mainListIDCity,mainListNetlength=E
138 | elif A.city==True and A.asn==True:mainIndex,mainIndexASN,mainListNamesCountry,mainListNamesCity,mainListNamesASN,mainListFirstIP,mainListFirstIPASN,mainListIDCity,mainListIDASN,mainListNetlength,mainListNetlengthASN=E
139 | A.ipv6=mainIndex[-1]>GeoIP2FastMin.numIPsv4[0];geoipCountryNamesDict={A.split(':')[0]:A.split(':')[1]for A in mainListNamesCountry};geoipCountryCodesList=list(geoipCountryNamesDict.keys());D.close();del D
140 | except Exception as B:raise GeoIP2FastMin.GeoIPError(f"Failed to pickle the data file {C} {str(B)}")
141 | try:[A._main_index_lookup(B)for B in[2894967295]]
142 | except Exception as B:raise GeoIP2FastMin.GeoIPError('Failed at warming-up... exiting... %s'%str(B))
143 | try:I=A.time.perf_counter()-H;J=abs(A.get_mem_usage()-G);A._load_data_text=f"GeoIP2Fast v{A.__version__} is ready! {A.os.path.basename(C)} "+'loaded with %s networks in %.5f seconds and using %.2f MiB.'%('{:,d}'.format(totalNetworks).replace(',','.'),I,J);A._print_verbose(A._load_data_text)
144 | except Exception as B:raise GeoIP2FastMin.GeoIPError('Failed at the end of load data %s'%str(B))
145 | A.is_loaded=True;return True
146 | @property
147 | def startup_line_text(self):return self._load_data_text
148 | def _main_index_lookup(F,iplong):
149 | B=iplong
150 | try:
151 | A=F.bisect.bisect_right(mainIndex,B)-1;C=F.bisect.bisect_right(mainListFirstIP[A],B)-1;D=mainListFirstIP[A][C];E=mainListNetlength[A][C]
152 | if B<=GeoIP2FastMin.MAX_IPv4:G=D+GeoIP2FastMin.numIPsv4[E]-1
153 | else:G=D+GeoIP2FastMin.numIPsv6[E]-1
154 | return A,C,D,G,E
155 | except Exception as H:return GeoIP2FastMin.GeoIPError('Failed at _main_index_lookup: %s'%str(H))
156 | def _country_lookup(D,match_root,match_chunk):
157 | try:B=mainListIDCountryCodes[match_root][match_chunk];A,E=mainListNamesCountry[B].split(':');C=B<16;A=D.error_code_private_networks if C else A;return A,E,C
158 | except Exception as F:return GeoIP2FastMin.GeoIPError('Failed at _country_lookup: %s'%str(F))
159 | def _city_country_name_lookup(C,country_code):
160 | A=country_code
161 | try:D=geoipCountryNamesDict[A];E=geoipCountryCodesList.index(A);B=E<16;A=C.error_code_private_networks if B else A;return A,D,B
162 | except Exception as F:return GeoIP2FastMin.GeoIPError('Failed at _city_country_name_lookup: %s'%str(F))
163 | def _city_lookup(B,match_root,match_chunk):
164 | try:C=mainListIDCity[match_root][match_chunk];A,D=mainListNamesCity[C].split(':');A,E,F=B._city_country_name_lookup(A);G=GeoIP2FastMin.CityDetail(D);return A,E,G,F
165 | except Exception as H:return GeoIP2FastMin.GeoIPError('Failed at _country_lookup: %s'%str(H))
166 | def _asn_lookup(A,iplong):
167 | B=iplong
168 | if A.asn==False:return'',''
169 | try:
170 | C=A.bisect.bisect_right(mainIndexASN,B)-1;D=A.bisect.bisect_right(mainListFirstIPASN[C],B)-1;E=mainListFirstIPASN[C][D];G=mainListIDASN[C][D];F=mainListNetlengthASN[C][D]
171 | if not A.ipv6:
172 | if B>E+GeoIP2FastMin.numIPsv4[F]-1:return'',''
173 | elif B>E+GeoIP2FastMin.numIPsv6[F]-1:return'',''
174 | return mainListNamesASN[G],A._int2ip(E)+'/'+str(F)
175 | except Exception as H:return'',''
176 | def _ip2int(A,ipaddr):
177 | B=ipaddr
178 | try:
179 | try:return int(A.struct.unpack('>L',A.socket.inet_aton(B))[0])
180 | except:return int.from_bytes(A.socket.inet_pton(A.socket.AF_INET6,B),byteorder='big')
181 | except Exception as C:raise GeoIP2FastMin.GeoIPError('Failed at ip2int: %s'%str(C))
182 | def _int2ip(A,iplong):
183 | B=iplong
184 | try:
185 | if BL',B))
186 | else:return A.socket.inet_ntop(A.socket.AF_INET6,A.binascii.unhexlify(hex(B)[2:].zfill(32)))
187 | except Exception as C:raise GeoIP2FastMin.GeoIPError('Failed at int2ip: %s'%str(C))
188 | def set_error_code_private_networks(B,new_value):
189 | A=new_value;global GEOIP_ECCODE_PRIVATE_NETWORKS
190 | try:B.error_code_private_networks=A;GEOIP_ECCODE_PRIVATE_NETWORKS=A;return A
191 | except Exception as C:raise GeoIP2FastMin.GeoIPError('Unable to set a new value for GEOIP_ECCODE_PRIVATE_NETWORKS: %s'%str(C))
192 | def set_error_code_network_not_found(B,new_value):
193 | A=new_value;global GEOIP_ECCODE_NETWORK_NOT_FOUND
194 | try:B.error_code_network_not_found=A;GEOIP_ECCODE_NETWORK_NOT_FOUND=A;return A
195 | except Exception as C:raise GeoIP2FastMin.GeoIPError('Unable to set a new value for GEOIP_ECCODE_NETWORK_NOT_FOUND: %s'%str(C))
196 | def lookup(A,ipaddr):
197 | B=ipaddr;C=A.time.perf_counter()
198 | try:D=A._ip2int(B)
199 | except Exception as E:return GeoIP2FastMin.GeoIPDetail(B,country_code=A.error_code_invalid_ip,country_name=GeoIP2FastMin.GEOIP_INVALID_IP_STRING,elapsed_time='%.9f sec'%(A.time.perf_counter()-C))
200 | try:
201 | I,J,N,O,P=A._main_index_lookup(D)
202 | if D>O:return GeoIP2FastMin.GeoIPDetail(ip=B,country_code=A.error_code_network_not_found,country_name=GeoIP2FastMin.GEOIP_NOT_FOUND_STRING,elapsed_time='%.9f sec'%(A.time.perf_counter()-C))
203 | K=A._int2ip(N)+'/'+str(P);L,M=A._asn_lookup(D)
204 | if A.country:F,G,H=A._country_lookup(I,J);return GeoIP2FastMin.GeoIPDetail(B,F,G,K,H,L,M,elapsed_time='%.9f sec'%(A.time.perf_counter()-C))
205 | else:
206 | F,G,Q,H=A._city_lookup(I,J)
207 | try:return GeoIP2FastMin.GeoIPDetailCity(B,F,G,Q,K,H,L,M,elapsed_time='%.9f sec'%(A.time.perf_counter()-C))
208 | except Exception as E:raise Exception(E)
209 | except Exception as E:return GeoIP2FastMin.GeoIPDetail(ip=B,country_code=A.error_code_lookup_internal_error,country_name=GeoIP2FastMin.GEOIP_INTERNAL_ERROR_STRING,elapsed_time='%.9f sec'%(A.time.perf_counter()-C))
210 | def get_mem_usage(A):
211 | ' Memory usage in MiB ';D=1024;E=16
212 | class C(A.ctypes.Structure):_fields_=[('cb',A.ctypes.c_ulong),('PageFaultCount',A.ctypes.c_ulong),('PeakWorkingSetSize',A.ctypes.c_size_t),('WorkingSetSize',A.ctypes.c_size_t),('QuotaPeakPagedPoolUsage',A.ctypes.c_size_t),('QuotaPagedPoolUsage',A.ctypes.c_size_t),('QuotaPeakNonPagedPoolUsage',A.ctypes.c_size_t),('QuotaNonPagedPoolUsage',A.ctypes.c_size_t),('PagefileUsage',A.ctypes.c_size_t),('PeakPagefileUsage',A.ctypes.c_size_t)]
213 | try:F=A.subprocess.check_output(['ps','-p',str(A.os.getpid()),'-o','rss=']);return float(int(F.strip())/1024)
214 | except:
215 | try:
216 | G=A.ctypes.windll.kernel32.GetCurrentProcessId();H=A.ctypes.windll.kernel32.OpenProcess(D|E,False,G);B=C();B.cb=A.ctypes.sizeof(C)
217 | if A.ctypes.windll.psapi.GetProcessMemoryInfo(H,A.ctypes.byref(B),A.ctypes.sizeof(B)):I=B.WorkingSetSize;return float(int(I)/1024/1024)
218 | except:return .0
219 | def self_test(A,max_ips=30):
220 | '\n Do a self-test with some random IPs\n ';B=[];B.append('x'+A._int2ip(A.random.randint(16777216,3758096383)).replace('.',','));B.append(A._int2ip(A.random.randint(16777216,3758096383))+'/32');B.append(A._int2ip(A.random.randint(397189376,397191423)));B.append(A._int2ip(A.random.choice([A.random.randint(167772160,184549375),A.random.randint(3232235520,3232301055),A.random.randint(2886729728,2887778303)])))
221 | while len(B) '+D.ljust(18)+' '+str(C.country_code).ljust(3)+str(C.country_name[:30]).ljust(30)+' ['+C.elapsed_time+'] Cached > ['+G.elapsed_time+'] '+C.asn_name)
224 | print('\n\t- Average Lookup Time: %.9f seconds - Average Cached Lookups: %.9f seconds.\n'%(sum(sorted(E)[1:-1])/(len(B)-2),sum(sorted(F)[1:-1])/(len(B)-2)))
225 | if __name__ == "__main__":
226 | G = GeoIP2FastMin(verbose=True,geoip2fast_data_file="")
227 | G.self_test()
--------------------------------------------------------------------------------
/geoip2fast/tests/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__
2 | GeoLite2-Country.mmdb
3 |
--------------------------------------------------------------------------------
/geoip2fast/tests/compare_with_mmdb.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | ##──── This test shows what GeoIP2Fast has that Maxmind's MMDB doesn't, and vice versa ──────────────────────────────────────────
4 | ##──── Download the file "GeoLite2-Country.mmdb" from Maxmind website and put it in the same directory ───────────────────────────
5 | ##──── of this script to run the test ────────────────────────────────────────────────────────────────────────────────────────────
6 | ##──── if you have geoipupdate installed, you should already have this file in the directory /var/lib/GeoIP/ It wIll works too ───
7 |
8 | ##──── The BLUE lines shows that GeoIP2Fast result is the same as the Maxmind result with MMDB files. ────────────────────────────
9 | ##──── Lines in RED means that there is a divergence between the base of GeoIP2Fast and Maxmind. ─────────────────────────────────
10 | ##──── You can confirm 'who is right' using whois or geoiplookup application in linux ────────────────────────────────────────────
11 |
12 | import os, sys, re, ctypes
13 | from geoip2fast import GeoIP2Fast
14 | from random import randrange
15 |
16 | try:
17 | import geoip2.database # pip install geoip2
18 | except:
19 | print("Run 'pip install geoip2' first and try again")
20 | sys.exit(1)
21 |
22 | def cRed(msg):
23 | return '\033[91m'+msg+'\033[0m'
24 | def cBlue(msg):
25 | return '\033[94m'+msg+'\033[0m'
26 |
27 | def create_iplist(quant):
28 | a_list = []
29 | for I in range(quant):
30 | IP = f"{randrange(1,224)}.{randrange(0,254)}.{randrange(0,254)}.{randrange(0,254)}"
31 | a_list.append(IP)
32 | if I % 5000 == 0:
33 | print("\rGenerating random IPs: "+str(I+1),end="")
34 | print(f"\rGenerating randomically {len(a_list)} IPs...")
35 | return a_list
36 |
37 | def get_geoip_from_mmdb(ipaddr)->str:
38 | try:
39 | response = reader.country(ipaddr)
40 | return str(response.country.iso_code)
41 | except Exception as ERR:
42 | # print(str(ERR))
43 | return "--"
44 |
45 | if __name__ == "__main__":
46 | GeoIP = GeoIP2Fast(verbose=True)
47 | if os.stat('/var/lib/GeoIP/GeoLite2-Country.mmdb').st_mode:
48 | reader = geoip2.database.Reader('/var/lib/GeoIP/GeoLite2-Country.mmdb',mode=geoip2.database.MODE_MMAP)
49 | else:
50 | reader = geoip2.database.Reader('GeoLite2-Country.mmdb',mode=geoip2.database.MODE_MMAP)
51 |
52 | gIpList = create_iplist(100000)
53 | counter = 0
54 | print("")
55 | print("This test shows what GeoIP2Fast has that Maxmind's MMDB files doesn't")
56 | print("")
57 | print(f"{'IP address'.center(20)}|{'from GeoIP2Fast'.center(20)}|{'from MMDB file'.center(20)}|")
58 | for IP in gIpList:
59 | geoip_info = GeoIP.lookup(IP)
60 | getFromLocal = geoip_info.country_code
61 | getFromMMDB = get_geoip_from_mmdb(IP)
62 |
63 | if getFromLocal == "":
64 | getFromLocal = "--"
65 |
66 | logString = (f"{('IP: '+IP).ljust(20)}|{str(getFromLocal).center(20)}|{str(getFromMMDB).center(20)}|")
67 |
68 | if getFromMMDB != getFromLocal:
69 | print(cRed("\r"+logString))
70 | counter += 1
71 | else:
72 | print(cBlue("\r"+logString),end="")
73 |
74 | # clear the last line
75 | if IP == gIpList[-1]:
76 | print("\r".ljust(105," "),end="")
77 |
78 | print("\n")
79 | print("Lines in RED means that there are a divergence between the base of GeoIP2Fast and Maxmind.")
80 | print("You can confirm 'who is right' checking different sources like a geoip lookup application ")
81 | print("like geoiplookup (ubuntu: apt install geoip-bin) or a whois service (ubuntu: apt install whois)")
82 | print("")
83 | print(" From %s random IP addresses tested, were found %s IP addresses"%((re.sub(r'(? "+IP.ljust(15)+" "+str(geoip.country_code).ljust(3)+str(geoip.country_name).ljust(35)+ \
21 | " ["+geoip.elapsed_time+"]\tAfter cache: ["+GEOIP.lookup(IP).elapsed_time+"] "+geoip.cidr)
22 |
23 | print("")
24 |
25 | result = GEOIP.lookup("200.204.0.10")
26 | print(result)
27 |
28 | # Before call the function get_hostname(), 'hostname' property will always be empty
29 | print("Hostname: "+result.hostname+"\t\t\t << must be empty before call result.get_hostname()")
30 | result.get_hostname()
31 |
32 | print(result)
33 |
34 | # to work with output as a dict, use the function to_dict()
35 | print(result.to_dict()['country_code'],result.to_dict()['country_name'])
36 |
37 | # To pretty print the object result like json.dumps()
38 | result = GEOIP.lookup("200.204.0.138")
39 | result.get_hostname()
40 | print(result.pp_json(indent=3,sort_keys=False))
41 |
42 | # info about internal cache
43 | print(GEOIP.cache_info())
44 |
45 | # clear the internal cache
46 | print(GEOIP.clear_cache())
47 |
48 | # info about internal cache
49 | print(GEOIP.cache_info())
50 |
51 | # to check the date of the CSV files used to create the .dat file
52 | print(GEOIP.get_source_info())
53 |
54 | print("")
55 |
56 | sys.exit(0)
--------------------------------------------------------------------------------
/geoip2fast/tests/random_test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | from geoip2fast import GeoIP2Fast
3 | from random import randrange
4 | from time import sleep
5 |
6 | MAX_IPS = 1000000
7 | GeoIP = GeoIP2Fast(verbose=True)
8 |
9 | print("\n- Starting a %d random IP test in"%(MAX_IPS),end="")
10 | print(" 3...",end="")
11 | sleep(1)
12 | print(" 2...",end="")
13 | sleep(1)
14 | print(" 1...",end="")
15 | sleep(1)
16 | print("\n")
17 |
18 | avgList, avgCacheList = [], []
19 |
20 | total = 0
21 | while total < MAX_IPS:
22 | IP = f"{randrange(1,223)}.{randrange(0,254)}.{randrange(0,254)}.{randrange(0,254)}"
23 | result = GeoIP.lookup(IP)
24 | avgList.append(float(result.elapsed_time.split(" ")[0]))
25 | total += 1
26 | cachedResult = GeoIP.lookup(IP)
27 | avgCacheList.append(float(cachedResult.elapsed_time.split(" ")[0]))
28 | print(f"IP {result.ip.ljust(20)}{result.country_code.ljust(4)}{result.country_name.ljust(40)}[{result.elapsed_time}] - Cached [{cachedResult.elapsed_time}]")
29 | print("")
30 | print("Test with %d randomic IP addresses."%(MAX_IPS))
31 | print("\t- Average Lookup Time: %.9f seconds. "%(sum(avgList)/MAX_IPS))
32 | print("\t- Average Cached Lookups: %.9f seconds. "%(sum(avgCacheList)/MAX_IPS))
33 | print("")
34 |
35 |
--------------------------------------------------------------------------------
/geoip2fast/tests/speed_test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | from geoip2fast import GeoIP2Fast
3 |
4 | GeoIP = GeoIP2Fast(verbose=True)
5 |
6 | print("\n- Starting 'lookups per second' test...\n")
7 | GeoIP.calculate_speed(print_result=True)
8 | print("")
9 |
--------------------------------------------------------------------------------
/images/geoip2dat01.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/images/geoip2dat01.jpg
--------------------------------------------------------------------------------
/images/geoip2dat02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/images/geoip2dat02.jpg
--------------------------------------------------------------------------------
/images/geoip2dat03.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/images/geoip2dat03.jpg
--------------------------------------------------------------------------------
/images/geoip2fast_selftest.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/images/geoip2fast_selftest.jpg
--------------------------------------------------------------------------------
/images/geoip2fastcity.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/images/geoip2fastcity.jpg
--------------------------------------------------------------------------------
/images/geoip2fastv4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rabuchaim/geoip2fast/5ce875696cef5f1c0c0fc6e3aa5951cbeb65278a/images/geoip2fastv4.jpg
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import codecs
2 | from setuptools import setup, find_packages
3 |
4 | setup(
5 | name='geoip2fast',
6 | version='1.2.2',
7 | description='GeoIP2Fast is the fastest GeoIP2 country/city/asn lookup library that supports IPv4 and IPv6. A search takes less than 0.00003 seconds. It has its own data file updated twice a week with Maxmind-Geolite2-CSV, supports IPv4/IPv6 and is Pure Python!',
8 | url='https://github.com/rabuchaim/geoip2fast',
9 | author='Ricardo Abuchaim',
10 | author_email='ricardoabuchaim@gmail.com',
11 | maintainer='Ricardo Abuchaim',
12 | maintainer_email='ricardoabuchaim@gmail.com',
13 | project_urls={
14 | "Issue Tracker": "https://github.com/rabuchaim/geoip2fast/issues",
15 | "Source code": "https://github.com/rabuchaim/geoip2fast",
16 | "Latest DAT files": "https://github.com/rabuchaim/geoip2fast/releases/latest",
17 | "Legacy v1.1.X DAT files": "https://github.com/rabuchaim/geoip2fast/releases/tag/LEGACY",
18 | },
19 | bugtrack_url='https://github.com/rabuchaim/geoip2fast/issues',
20 | license='MIT',
21 | keywords=['geoip','geoip2','geolite2','maxmind','geoip2fast','geolocation','geolocalization','geo ip','ipaddress','ip','geo','ipv4','ipv6','pure-python','purepython','pure python','geoiptofast','geoiptoofast','geoip2dat','mmdb','tools'],
22 | packages=['geoip2fast'],
23 | py_modules=['geoip2fast', 'geoip2dat'],
24 | package_dir = {'geoip2fast': 'geoip2fast'},
25 | include_package_data=True,
26 | zip_safe = False,
27 | package_data={
28 | 'geoip2fast': [
29 | 'CHANGELOG',
30 | 'geoip2fast.dat.gz',
31 | 'geoip2fast-ipv6.dat.gz',
32 | 'geoip2fast-asn.dat.gz',
33 | 'geoip2fast-asn-ipv6.dat.gz',
34 | 'tests/geoip2fast_test.py',
35 | 'tests/speed_test.py',
36 | 'tests/coverage_test.py',
37 | 'tests/compare_with_mmdb.py',
38 | 'tests/random_test.py',
39 | 'tests/geoipcli.py',
40 | ],
41 | },
42 | entry_points={
43 | 'console_scripts': [
44 | 'geoip2fast = geoip2fast.geoip2fast:main_function',
45 | 'geoip2dat = geoip2fast.geoip2dat:main_function'
46 | ]
47 | },
48 | python_requires=">=3.7",
49 | install_requires=[],
50 | classifiers=[
51 | 'Development Status :: 5 - Production/Stable',
52 | 'Topic :: Security',
53 | 'Topic :: Internet',
54 | 'Topic :: Internet :: Finger',
55 | 'Topic :: Scientific/Engineering',
56 | 'Topic :: System :: Monitoring',
57 | 'Topic :: System :: Networking',
58 | 'Topic :: System :: Systems Administration',
59 | 'Topic :: Software Development :: Libraries',
60 | 'Topic :: Software Development :: Libraries :: Python Modules',
61 | 'Topic :: Software Development :: Localization',
62 | 'Topic :: Utilities',
63 | 'Intended Audience :: Developers',
64 | 'Intended Audience :: Information Technology',
65 | 'Intended Audience :: System Administrators',
66 | 'Operating System :: MacOS',
67 | 'Operating System :: Microsoft :: Windows :: Windows 10',
68 | 'Operating System :: Microsoft :: Windows :: Windows 11',
69 | 'Operating System :: Unix',
70 | 'Operating System :: POSIX',
71 | 'Operating System :: POSIX :: Linux',
72 | 'Operating System :: POSIX :: BSD',
73 | 'Operating System :: POSIX :: BSD :: FreeBSD',
74 | 'Programming Language :: Python',
75 | 'Programming Language :: Python :: 3',
76 | 'Programming Language :: Python :: 3.7',
77 | 'Programming Language :: Python :: 3.8',
78 | 'Programming Language :: Python :: 3.9',
79 | 'Programming Language :: Python :: 3.10',
80 | 'Programming Language :: Python :: 3.11',
81 | 'Programming Language :: Python :: 3.12',
82 | 'Programming Language :: Python :: 3.13',
83 | 'Programming Language :: Python :: Implementation :: PyPy',
84 | 'License :: OSI Approved :: MIT License',
85 | ],
86 | long_description=codecs.open("README.md","r","utf-8").read(),
87 | long_description_content_type='text/markdown',
88 | )
89 |
--------------------------------------------------------------------------------