# Copyright (c) 2013-2020 Philip Hane # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # CLI python script interface for ipwhois.utils lookups. import argparse from collections import OrderedDict import json from ipwhois.utils import (ipv4_lstrip_zeros, calculate_cidr, get_countries, ipv4_is_defined, ipv6_is_defined, ipv4_generate_random, ipv6_generate_random, unique_everseen, unique_addresses) # CLI ANSI rendering ANSI = { 'end': '\033[0m', 'b': '\033[1m', 'ul': '\033[4m', 'red': '\033[31m', 'green': '\033[32m', 'yellow': '\033[33m', 'cyan': '\033[36m' } # Setup the arg parser. parser = argparse.ArgumentParser( description='ipwhois utilities CLI interface' ) parser.add_argument( '--ipv4_lstrip_zeros', type=str, nargs=1, metavar='"IP ADDRESS"', help='Strip leading zeros in each octet of an IPv4 address.' ) parser.add_argument( '--calculate_cidr', type=str, nargs=2, metavar='"IP ADDRESS"', help='Calculate a CIDR range(s) from a start and end IP address.' ) parser.add_argument( '--get_countries', action='store_true', help='Output a dictionary containing ISO_3166-1 country codes to names.' ) parser.add_argument( '--get_country', type=str, nargs=1, metavar='"COUNTRY CODE"', help='Output the ISO_3166-1 name for a country code.' ) parser.add_argument( '--ipv4_is_defined', type=str, nargs=1, metavar='"IP ADDRESS"', help='Check if an IPv4 address is defined (in a reserved address range).' ) parser.add_argument( '--ipv6_is_defined', type=str, nargs=1, metavar='"IP ADDRESS"', help='Check if an IPv6 address is defined (in a reserved address range).' ) parser.add_argument( '--ipv4_generate_random', type=int, nargs=1, metavar='TOTAL', help='Generate random, unique IPv4 addresses that are not defined (can be ' 'looked up using ipwhois).' ) parser.add_argument( '--ipv6_generate_random', type=int, nargs=1, metavar='TOTAL', help='Generate random, unique IPv6 addresses that are not defined (can be ' 'looked up using ipwhois).' ) parser.add_argument( '--unique_everseen', type=json.loads, nargs=1, metavar='"ITERABLE"', help='List unique elements from input iterable, preserving the order.' ) parser.add_argument( '--unique_addresses', type=str, nargs=1, metavar='"FILE PATH"', help='Search an input file, extracting, counting, and summarizing ' 'IPv4/IPv6 addresses/networks.' ) # Output options group = parser.add_argument_group('Output options') group.add_argument( '--colorize', action='store_true', help='If set, colorizes the output using ANSI. Should work in most ' 'platform consoles.' ) # Get the args script_args = parser.parse_args() if script_args.ipv4_lstrip_zeros: print(ipv4_lstrip_zeros(address=script_args.ipv4_lstrip_zeros[0])) elif script_args.calculate_cidr: try: result = calculate_cidr( start_address=script_args.calculate_cidr[0], end_address=script_args.calculate_cidr[1] ) print('{0}Found {1} CIDR blocks for ({2}, {3}){4}:\n{5}'.format( ANSI['green'] if script_args.colorize else '', len(result), script_args.calculate_cidr[0], script_args.calculate_cidr[1], ANSI['end'] if script_args.colorize else '', '\n'.join(result) )) except Exception as e: print('{0}Error{1}: {2}'.format(ANSI['red'], ANSI['end'], str(e))) elif script_args.get_countries: try: result = get_countries() print('{0}Found {1} countries{2}:\n{3}'.format( ANSI['green'] if script_args.colorize else '', len(result), ANSI['end'] if script_args.colorize else '', '\n'.join(['{0}: {1}'.format(k, v) for k, v in ( OrderedDict(sorted(result.items())).iteritems())]) )) except Exception as e: print('{0}Error{1}: {2}'.format(ANSI['red'], ANSI['end'], str(e))) elif script_args.get_country: try: countries = get_countries() result = countries[script_args.get_country[0].upper()] print('{0}Match found for country code ({1}){2}:\n{3}'.format( ANSI['green'] if script_args.colorize else '', script_args.get_country[0], ANSI['end'] if script_args.colorize else '', result )) except Exception as e: print('{0}Error{1}: {2}'.format(ANSI['red'], ANSI['end'], str(e))) elif script_args.ipv4_is_defined: try: result = ipv4_is_defined(address=script_args.ipv4_is_defined[0]) if result[0]: print('{0}{1} is defined{2}:\n{3}'.format( ANSI['green'] if script_args.colorize else '', script_args.ipv4_is_defined[0], ANSI['end'] if script_args.colorize else '', 'Name: {0}\nRFC: {1}'.format(result[1], result[2]) )) else: print('{0}{1} is not defined{2}'.format( ANSI['yellow'] if script_args.colorize else '', script_args.ipv4_is_defined[0], ANSI['end'] if script_args.colorize else '' )) except Exception as e: print('{0}Error{1}: {2}'.format(ANSI['red'], ANSI['end'], str(e))) elif script_args.ipv6_is_defined: try: result = ipv6_is_defined(address=script_args.ipv6_is_defined[0]) if result[0]: print('{0}{1} is defined{2}:\n{3}'.format( ANSI['green'] if script_args.colorize else '', script_args.ipv6_is_defined[0], ANSI['end'] if script_args.colorize else '', 'Name: {0}\nRFC: {1}'.format(result[1], result[2]) )) else: print('{0}{1} is not defined{2}'.format( ANSI['yellow'] if script_args.colorize else '', script_args.ipv6_is_defined[0], ANSI['end'] if script_args.colorize else '' )) except Exception as e: print('{0}Error{1}: {2}'.format(ANSI['red'], ANSI['end'], str(e))) elif script_args.ipv4_generate_random: try: result = ipv4_generate_random(total=script_args.ipv4_generate_random[0]) for random_ip in result: print(random_ip) except Exception as e: print('{0}Error{1}: {2}'.format(ANSI['red'], ANSI['end'], str(e))) elif script_args.ipv6_generate_random: try: result = ipv6_generate_random(total=script_args.ipv6_generate_random[0]) for random_ip in result: print(random_ip) except Exception as e: print('{0}Error{1}: {2}'.format(ANSI['red'], ANSI['end'], str(e))) elif script_args.unique_everseen: try: result = list(unique_everseen(iterable=script_args.unique_everseen[0])) print('{0}Unique everseen{1}:\n{2}'.format( ANSI['green'] if script_args.colorize else '', ANSI['end'] if script_args.colorize else '', result )) except Exception as e: print('{0}Error{1}: {2}'.format(ANSI['red'], ANSI['end'], str(e))) elif script_args.unique_addresses: try: result = unique_addresses(file_path=script_args.unique_addresses[0]) tmp = [] for k, v in sorted(result.items(), key=lambda kv: int(kv[1]['count']), reverse=True): tmp.append('{0}{1}{2}: Count: {3}, Ports: {4}'.format( ANSI['b'] if script_args.colorize else '', k, ANSI['end'] if script_args.colorize else '', v['count'], json.dumps(v['ports']) )) print('{0}Found {1} unique addresses{2}:\n{3}'.format( ANSI['green'] if script_args.colorize else '', len(result), ANSI['end'] if script_args.colorize else '', '\n'.join(tmp) )) except Exception as e: print('{0}Error{1}: {2}'.format(ANSI['red'], ANSI['end'], str(e)))