Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a function for retrieving location and provider info by IP address. #12

Merged
merged 22 commits into from
Jul 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/scripts/recon/ip_info/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import sys
from pathlib import Path

__root_dir = Path(__file__).parents[4]
sys.path.append(str(__root_dir))
11 changes: 11 additions & 0 deletions src/scripts/recon/ip_info/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from pprint import pprint
from sys import argv

from src.core.utils.module import run_module
from .module import Runner

result = run_module(
Runner, args=argv, arg_name="ip", arg_default="8.8.8.8"
)

pprint(result)
65 changes: 65 additions & 0 deletions src/scripts/recon/ip_info/module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env python3

import ipaddress

import requests

from src.core.base.recon import ReconRunner, PossibleKeys
from src.core.utils.response import ScriptResponse
from src.core.utils.validators import validate_kwargs


class Runner(ReconRunner):
def __init__(self, logger: str = __name__) -> None:
super(Runner, self).__init__(logger)
self.__BASE_URL = "http://ip-api.com/json/{query}?fields=18411513"

@validate_kwargs(PossibleKeys.KEYS)
def run(self, *args, **kwargs) -> ScriptResponse.success or ScriptResponse.error:
# fmt: off
response = self.__get_ip_info(kwargs.get("ip"))

try:
msg = (
"Query successful!"
if response["status"] == "success"
else "Query failed!"
)
# we don't need duplicate status, let's get rid of it
response.pop("status", None)
return ScriptResponse.success(result=response, message=msg)
except TypeError as type_err:
return ScriptResponse.error(message=f"Error occurred while trying to get data: {str(type_err)}")
# fmt: on

def __get_ip_info(self, ip: str) -> dict or str:
"""
A function for retrieving location and provider info by IP address. You can get the following information:
- continent name
- country name
- region/state name
- city name
- district name
- zip code
- latitude
- longitude
- timezone
- ISP name
- organization name
- AS number and organization, separated by space (RIR). Empty for IP blocks not being announced in BGP
tables.
- hosting, colocated or data center.

:param ip: the IP address you want to know about.
:return: string with error message in case of error or a dict with information about IP address.
"""

try:
validated_ip = str(ipaddress.ip_address(ip))
except ValueError:
return "Invalid IP address!"

try:
return requests.get(self.__BASE_URL.format(query=validated_ip)).json()
except Exception as err_unexp:
return "Unexpected error occurred: {}".format(str(err_unexp))
5 changes: 5 additions & 0 deletions src/scripts/recon/ip_info/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
certifi==2020.6.20
chardet==3.0.4
idna==2.10
requests==2.24.0
urllib3==1.25.9
59 changes: 59 additions & 0 deletions src/scripts/recon/ip_info/test_module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env python3

from unittest import TestCase
from .module import Runner


class DefaultValues:
# Set Google DNS Resolver as the default host to test
HOST_IP = "8.8.8.8"
HOST_CITY = "Ashburn"


class IPInfoTest(TestCase):
def setUp(self) -> None:
"""
Setup before each test function.

:return: None
"""

self.runner = Runner()

def test_invalid_ip(self) -> None:
"""
This test function tests the case where the user entered an invalid IP (it can't be converted to a valid IP).

:return: None
"""

res = self.runner.run(ip="abcde")

self.assertEqual(res.get("status"), "error")

def test_valid_ip_regular_format(self) -> None:
"""
This test function tests the case where the user entered a valid ip in regular format.
This IP was found here: https://ip-api.com/docs/api:json

:return: None
"""

res = self.runner.run(ip=DefaultValues.HOST_IP)

self.assertEqual(res.get("status"), "success")
self.assertEqual(res.get("result").get("city"), DefaultValues.HOST_CITY)

def test_valid_ip_dec_format(self) -> None:
"""
This test function tests the case where the user entered a valid ip in decimal format.
This IP was found here: https://ip-api.com/docs/api:json

:return: None
"""

# this IP is the same as IP in previous test function.
res = self.runner.run(ip=134744072)

self.assertEqual(res.get("status"), "success")
self.assertEqual(res.get("result").get("city"), DefaultValues.HOST_CITY)