From 9fcf1eb9cb6172fba301412c48ddf73c3409f5d7 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 27 Jul 2022 10:42:35 -0700 Subject: [PATCH] initial ip-address parser --- jc/parsers/ip_address.py | 123 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 jc/parsers/ip_address.py diff --git a/jc/parsers/ip_address.py b/jc/parsers/ip_address.py new file mode 100644 index 00000000..7d16d76b --- /dev/null +++ b/jc/parsers/ip_address.py @@ -0,0 +1,123 @@ +"""jc - JSON Convert IP Address string parser + +Usage (cli): + + $ echo '192.168.1.1' | jc --ip-address + +Usage (module): + + import jc + result = jc.parse('ip_address', ip_address_string) + +Schema: + + [ + { + "ip_address": string, + "bar": boolean, + "baz": integer + } + ] + +Examples: + + $ ip_address | jc --ip_address -p + [] + + $ ip_address | jc --ip_address -p -r + [] +""" +from typing import List, Dict +import binascii +import ipaddress +import jc.utils + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = 'IP Address string parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'] + + +__version__ = info.version + + +def _process(proc_data: Dict) -> Dict: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (Dictionary) raw structured data to process + + Returns: + + Dictionary. Structured to conform to the schema. + """ + return proc_data + + +def _b2a(byte_string: bytes) -> str: + """Convert a byte string to a colon-delimited hex ascii string""" + # need try/except since seperator was only introduced in python 3.8. + # provides compatibility for python 3.6 and 3.7. + try: + return binascii.hexlify(byte_string, ':').decode('utf-8') + except TypeError: + hex_string = binascii.hexlify(byte_string).decode('utf-8') + colon_seperated = ':'.join(hex_string[i:i+2] for i in range(0, len(hex_string), 2)) + return colon_seperated + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> Dict: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + Dictionary. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: Dict = {} + + if jc.utils.has_data(data): + + interface = ipaddress.ip_interface(data.strip()) + + raw_output = { + 'version': int(interface.version), + 'ip': str(interface.ip), + 'ip_compressed': str(interface.compressed), + 'ip_exploded': str(interface.exploded), + 'ip_hex': _b2a(interface.packed), + 'dns_ptr': str(interface.reverse_pointer), + 'network': str(interface.network).split('/')[0], + 'netmask': str(interface.with_netmask).split('/')[1], + 'cidr_netmask': str(interface.with_prefixlen).split('/')[1], + 'hostmask': str(interface.with_hostmask).split('/')[1], + 'max_prefix_length': int(interface.max_prefixlen), + 'is_multicast': interface.is_multicast, + 'is_private': interface.is_private, + 'is_global': interface.is_global, + 'is_link_local': interface.is_link_local, + 'is_loopback': interface.is_loopback, + 'is_reserved': interface.is_reserved, + 'is_unspecified': interface.is_unspecified + } + + return raw_output if raw else _process(raw_output)