From 51271fea0fbd7bd63863ba05c399b4675dc5b4bf Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Mon, 13 Sep 2021 19:27:34 -0700 Subject: [PATCH] somewhat working parser --- jc/parsers/ping_s.py | 282 +++++++++++++++++++++---------------------- 1 file changed, 136 insertions(+), 146 deletions(-) diff --git a/jc/parsers/ping_s.py b/jc/parsers/ping_s.py index ad22d0ce..9b77d725 100644 --- a/jc/parsers/ping_s.py +++ b/jc/parsers/ping_s.py @@ -33,6 +33,7 @@ Examples: {example output} ... """ +import string import jc.utils @@ -87,176 +88,165 @@ def parse(data, raw=False, quiet=False): for line in data: try: - raw_output = {} + output_line = {} ping_responses = [] pattern = None footer = False - linedata = data.splitlines() - # check for PATTERN - if linedata[0].startswith('PATTERN: '): - pattern = linedata.pop(0).split(': ')[1] + if line.startswith('PATTERN: '): + pattern = line.strip().split(': ')[1] + continue - while not linedata[0].startswith('PING '): - linedata.pop(0) + if line.startswith('PING '): + ipv4 = True if 'bytes of data' in line else False - ipv4 = True if 'bytes of data' in linedata[0] else False + if ipv4 and line[5] not in string.digits: + hostname = True + elif ipv4 and line[5] in string.digits: + hostname = False + elif not ipv4 and ' (' in line: + hostname = True + else: + hostname = False - if ipv4 and linedata[0][5] not in string.digits: - hostname = True - elif ipv4 and linedata[0][5] in string.digits: - hostname = False - elif not ipv4 and ' (' in linedata[0]: - hostname = True - else: - hostname = False + if ipv4 and not hostname: + dst_ip, dta_byts = (2, 3) + elif ipv4 and hostname: + dst_ip, dta_byts = (2, 3) + elif not ipv4 and not hostname: + dst_ip, dta_byts = (2, 3) + else: + dst_ip, dta_byts = (3, 4) - for line in filter(None, linedata): - if line.startswith('PING '): - if ipv4 and not hostname: - dst_ip, dta_byts = (2, 3) - elif ipv4 and hostname: - dst_ip, dta_byts = (2, 3) - elif not ipv4 and not hostname: - dst_ip, dta_byts = (2, 3) - else: - dst_ip, dta_byts = (3, 4) + line = line.replace('(', ' ').replace(')', ' ') + output_line.update( + { + 'destination_ip': line.split()[dst_ip].lstrip('(').rstrip(')'), + 'data_bytes': line.split()[dta_byts], + 'pattern': pattern + } + ) + continue - line = line.replace('(', ' ').replace(')', ' ') - raw_output.update( - { - 'destination_ip': line.split()[dst_ip].lstrip('(').rstrip(')'), - 'data_bytes': line.split()[dta_byts], - 'pattern': pattern - } - ) - continue + if line.startswith('---'): + footer = True + # raw_output['destination'] = line.split()[1] + continue - if line.startswith('---'): - footer = True - raw_output['destination'] = line.split()[1] - continue - - if footer: - if 'packets transmitted' in line: - if ' duplicates,' in line: - raw_output.update( - { - 'packets_transmitted': line.split()[0], - 'packets_received': line.split()[3], - 'packet_loss_percent': line.split()[7].rstrip('%'), - 'duplicates': line.split()[5].lstrip('+'), - 'time_ms': line.split()[11].replace('ms', '') - } - ) - continue - else: - raw_output.update( - { - 'packets_transmitted': line.split()[0], - 'packets_received': line.split()[3], - 'packet_loss_percent': line.split()[5].rstrip('%'), - 'duplicates': '0', - 'time_ms': line.split()[9].replace('ms', '') - } - ) - continue - - else: - split_line = line.split(' = ')[1] - split_line = split_line.split('/') - raw_output.update( + if footer: + if 'packets transmitted' in line: + if ' duplicates,' in line: + output_line.update( { - 'round_trip_ms_min': split_line[0], - 'round_trip_ms_avg': split_line[1], - 'round_trip_ms_max': split_line[2], - 'round_trip_ms_stddev': split_line[3].split()[0] + 'packets_transmitted': line.split()[0], + 'packets_received': line.split()[3], + 'packet_loss_percent': line.split()[7].rstrip('%'), + 'duplicates': line.split()[5].lstrip('+'), + 'time_ms': line.split()[11].replace('ms', '') } ) + continue + else: + output_line.update( + { + 'packets_transmitted': line.split()[0], + 'packets_received': line.split()[3], + 'packet_loss_percent': line.split()[5].rstrip('%'), + 'duplicates': '0', + 'time_ms': line.split()[9].replace('ms', '') + } + ) + continue - # ping response lines else: - # request timeout - if 'no answer yet for icmp_seq=' in line: - timestamp = False - isequence = 5 + split_line = line.split(' = ')[1] + split_line = split_line.split('/') + output_line.update( + { + 'round_trip_ms_min': split_line[0], + 'round_trip_ms_avg': split_line[1], + 'round_trip_ms_max': split_line[2], + 'round_trip_ms_stddev': split_line[3].split()[0] + } + ) - # if timestamp option is specified, then shift icmp sequence field right by one + # ping response lines + else: + # request timeout + if 'no answer yet for icmp_seq=' in line: + timestamp = False + isequence = 5 + + # if timestamp option is specified, then shift icmp sequence field right by one + if line[0] == '[': + timestamp = True + isequence = 6 + + response = { + 'type': 'timeout', + 'timestamp': line.split()[0].lstrip('[').rstrip(']') if timestamp else None, + 'icmp_seq': line.replace('=', ' ').split()[isequence] + } + + output_line.update(response) + + if quiet: + output_line['_meta'] = {'success': True} + + if raw: + yield output_line + else: + yield _process(output_line) + + continue + + # normal responses + elif ' bytes from ' in line: + try: + line = line.replace('(', ' ').replace(')', ' ').replace('=', ' ') + + # positions of items depend on whether ipv4/ipv6 and/or ip/hostname is used + if ipv4 and not hostname: + bts, rip, iseq, t2l, tms = (0, 3, 5, 7, 9) + elif ipv4 and hostname: + bts, rip, iseq, t2l, tms = (0, 4, 7, 9, 11) + elif not ipv4 and not hostname: + bts, rip, iseq, t2l, tms = (0, 3, 5, 7, 9) + elif not ipv4 and hostname: + bts, rip, iseq, t2l, tms = (0, 4, 7, 9, 11) + + # if timestamp option is specified, then shift everything right by one + timestamp = False if line[0] == '[': timestamp = True - isequence = 6 + bts, rip, iseq, t2l, tms = (bts + 1, rip + 1, iseq + 1, t2l + 1, tms + 1) response = { - 'type': 'timeout', + 'type': 'reply', 'timestamp': line.split()[0].lstrip('[').rstrip(']') if timestamp else None, - 'icmp_seq': line.replace('=', ' ').split()[isequence] + 'bytes': line.split()[bts], + 'response_ip': line.split()[rip].rstrip(':'), + 'icmp_seq': line.split()[iseq], + 'ttl': line.split()[t2l], + 'time_ms': line.split()[tms], + 'duplicate': True if 'DUP!' in line else False + } + except Exception: + response = { + 'type': 'unparsable_line', + 'unparsed_line': line } - ping_responses.append(response) - continue - # normal responses - elif ' bytes from ' in line: - try: - line = line.replace('(', ' ').replace(')', ' ').replace('=', ' ') + output_line.update(response) - # positions of items depend on whether ipv4/ipv6 and/or ip/hostname is used - if ipv4 and not hostname: - bts, rip, iseq, t2l, tms = (0, 3, 5, 7, 9) - elif ipv4 and hostname: - bts, rip, iseq, t2l, tms = (0, 4, 7, 9, 11) - elif not ipv4 and not hostname: - bts, rip, iseq, t2l, tms = (0, 3, 5, 7, 9) - elif not ipv4 and hostname: - bts, rip, iseq, t2l, tms = (0, 4, 7, 9, 11) - - # if timestamp option is specified, then shift everything right by one - timestamp = False - if line[0] == '[': - timestamp = True - bts, rip, iseq, t2l, tms = (bts + 1, rip + 1, iseq + 1, t2l + 1, tms + 1) - - response = { - 'type': 'reply', - 'timestamp': line.split()[0].lstrip('[').rstrip(']') if timestamp else None, - 'bytes': line.split()[bts], - 'response_ip': line.split()[rip].rstrip(':'), - 'icmp_seq': line.split()[iseq], - 'ttl': line.split()[t2l], - 'time_ms': line.split()[tms], - 'duplicate': True if 'DUP!' in line else False - } - except Exception: - response = { - 'type': 'unparsable_line', - 'unparsed_line': line - } - - ping_responses.append(response) - continue - - raw_output['responses'] = ping_responses - - return raw_output - - if quiet: - output_line['_meta'] = {'success': True} - - if raw: - yield output_line - else: - yield _process(output_line) + if quiet: + output_line['_meta'] = {'success': True} + + if raw: + yield output_line + else: + yield _process(output_line) except Exception as e: - if not quiet: - e.args = (str(e) + '... Use the quiet option (-q) to ignore errors.',) - raise e - else: - yield { - '_meta': - { - 'success': False, - 'error': 'error parsing line', - 'line': line.strip() - } - } + yield jc.utils.stream_error(e, quiet, line)