From bdfa95912398b2630fcb13e866f4013747fd0975 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Thu, 7 Nov 2019 08:07:43 -0800 Subject: [PATCH] fix compatibility code --- jc/parsers/arp.py | 4 +- jc/parsers/df.py | 4 +- jc/parsers/dig.py | 10 +- jc/parsers/env.py | 10 +- jc/parsers/free.py | 10 +- jc/parsers/history.py | 8 +- jc/parsers/ifconfig.py | 10 +- jc/parsers/iptables.py | 10 +- jc/parsers/jobs.py | 10 +- jc/parsers/ls.py | 10 +- jc/parsers/lsblk.py | 10 +- jc/parsers/lsmod.py | 10 +- jc/parsers/lsof.py | 10 +- jc/parsers/mount.py | 10 +- jc/parsers/netstat.py | 257 ++++++++++++++++++----------------------- jc/parsers/ps.py | 10 +- jc/parsers/route.py | 10 +- jc/parsers/uname.py | 10 +- jc/parsers/uptime.py | 10 +- jc/parsers/w.py | 10 +- 20 files changed, 215 insertions(+), 218 deletions(-) diff --git a/jc/parsers/arp.py b/jc/parsers/arp.py index 62bb18c9..6e2191cc 100644 --- a/jc/parsers/arp.py +++ b/jc/parsers/arp.py @@ -78,7 +78,7 @@ $ arp -a | jc --arp -p -r } ] """ -from jc.utils import * +import jc.utils def process(proc_data): @@ -108,7 +108,7 @@ def parse(data, raw=False, quiet=False): compatible = ['linux', 'aix', 'freebsd'] if not quiet: - compatibility(__name__, compatible) + jc.utils.compatibility(__name__, compatible) # code adapted from Conor Heine at: # https://gist.github.com/cahna/43a1a3ff4d075bcd71f9d7120037a501 diff --git a/jc/parsers/df.py b/jc/parsers/df.py index 1d7ca89a..ab460779 100644 --- a/jc/parsers/df.py +++ b/jc/parsers/df.py @@ -63,7 +63,7 @@ $ df | jc --df -p -r ... ] """ -from jc.utils import * +import jc.utils def process(proc_data): @@ -112,7 +112,7 @@ def parse(data, raw=False, quiet=False): compatible = ['linux'] if not quiet: - compatibility(__name__, compatible) + jc.utils.compatibility(__name__, compatible) cleandata = data.splitlines() fix_headers = cleandata[0].lower().replace('avail ', 'available ') diff --git a/jc/parsers/dig.py b/jc/parsers/dig.py index ee28e44b..7827fbfc 100644 --- a/jc/parsers/dig.py +++ b/jc/parsers/dig.py @@ -148,7 +148,7 @@ $ dig -x 1.1.1.1 | jc --dig -p } ] """ -import jc +import jc.utils def process(proc_data): @@ -311,10 +311,12 @@ def parse_answer(answer): 'data': answer_data} -def parse(data, raw=False): +def parse(data, raw=False, quiet=False): # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']) + compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) raw_output = [] cleandata = data.splitlines() diff --git a/jc/parsers/env.py b/jc/parsers/env.py index 9f6df058..28a0dca7 100644 --- a/jc/parsers/env.py +++ b/jc/parsers/env.py @@ -43,7 +43,7 @@ $ env | jc --env -p -r "_": "/usr/bin/env" } """ -import jc +import jc.utils def process(proc_data): @@ -67,10 +67,12 @@ def process(proc_data): return processed -def parse(data, raw=False): +def parse(data, raw=False, quiet=False): # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']) + compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) raw_output = {} diff --git a/jc/parsers/free.py b/jc/parsers/free.py index bf3c8505..adce04e5 100644 --- a/jc/parsers/free.py +++ b/jc/parsers/free.py @@ -43,7 +43,7 @@ $ free | jc --free -p -r } ] """ -import jc +import jc.utils def process(proc_data): @@ -74,10 +74,12 @@ def process(proc_data): return proc_data -def parse(data, raw=False): +def parse(data, raw=False, quiet=False): # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux']) + compatible = ['linux'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) # code adapted from Conor Heine at: # https://gist.github.com/cahna/43a1a3ff4d075bcd71f9d7120037a501 diff --git a/jc/parsers/history.py b/jc/parsers/history.py index fa78f839..76c3a4ba 100644 --- a/jc/parsers/history.py +++ b/jc/parsers/history.py @@ -59,10 +59,12 @@ def process(proc_data): return processed -def parse(data, raw=False): +def parse(data, raw=False, quiet=False): # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']) + compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) raw_output = {} diff --git a/jc/parsers/ifconfig.py b/jc/parsers/ifconfig.py index 4e0dc476..4516cfd5 100644 --- a/jc/parsers/ifconfig.py +++ b/jc/parsers/ifconfig.py @@ -120,7 +120,7 @@ $ ifconfig | jc --ifconfig -p -r } ] """ -import jc +import jc.utils from ifconfigparser import IfconfigParser @@ -170,10 +170,12 @@ def process(proc_data): return proc_data -def parse(data, raw=False): +def parse(data, raw=False, quiet=False): # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux', 'aix', 'freebsd']) + compatible = ['linux', 'aix', 'freebsd'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) raw_output = [] diff --git a/jc/parsers/iptables.py b/jc/parsers/iptables.py index 94c4569d..fb643374 100644 --- a/jc/parsers/iptables.py +++ b/jc/parsers/iptables.py @@ -125,7 +125,7 @@ $ sudo iptables --line-numbers -v -L -t nat | jc --iptables -p -r ... ] """ -import jc +import jc.utils def process(proc_data): @@ -193,10 +193,12 @@ def process(proc_data): return proc_data -def parse(data, raw=False): +def parse(data, raw=False, quiet=False): # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux']) + compatible = ['linux'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) raw_output = [] chain = {} diff --git a/jc/parsers/jobs.py b/jc/parsers/jobs.py index 542c2230..0a5e3a1c 100644 --- a/jc/parsers/jobs.py +++ b/jc/parsers/jobs.py @@ -68,7 +68,7 @@ $ jobs -l | jc --jobs -p -r ] """ import string -import jc +import jc.utils def process(proc_data): @@ -96,10 +96,12 @@ def process(proc_data): return proc_data -def parse(data, raw=False): +def parse(data, raw=False, quiet=False): # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']) + compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) raw_output = [] diff --git a/jc/parsers/ls.py b/jc/parsers/ls.py index 4d52a617..bff95ae4 100644 --- a/jc/parsers/ls.py +++ b/jc/parsers/ls.py @@ -135,7 +135,7 @@ $ ls -l /usr/bin | jc --ls | jq '.[] | select(.size > 50000000)' } """ import re -import jc +import jc.utils def process(proc_data): @@ -165,10 +165,12 @@ def process(proc_data): return proc_data -def parse(data, raw=False): +def parse(data, raw=False, quiet=False): # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']) + compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) raw_output = [] diff --git a/jc/parsers/lsblk.py b/jc/parsers/lsblk.py index 4f172f1f..dac13faf 100644 --- a/jc/parsers/lsblk.py +++ b/jc/parsers/lsblk.py @@ -148,7 +148,7 @@ $ lsblk -o +STATE | jc --lsblk -p -r ] """ import string -import jc +import jc.utils def process(proc_data): @@ -219,10 +219,12 @@ def process(proc_data): return proc_data -def parse(data, raw=False): +def parse(data, raw=False, quiet=False): # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux']) + compatible = ['linux'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) raw_output = [] linedata = data.splitlines() diff --git a/jc/parsers/lsmod.py b/jc/parsers/lsmod.py index c34befcb..3264183b 100644 --- a/jc/parsers/lsmod.py +++ b/jc/parsers/lsmod.py @@ -97,7 +97,7 @@ $ lsmod | jc --lsmod -p -r ... ] """ -import jc +import jc.utils def process(proc_data): @@ -127,10 +127,12 @@ def process(proc_data): return proc_data -def parse(data, raw=False): +def parse(data, raw=False, quiet=False): # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux']) + compatible = ['linux'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) # code adapted from Conor Heine at: # https://gist.github.com/cahna/43a1a3ff4d075bcd71f9d7120037a501 diff --git a/jc/parsers/lsof.py b/jc/parsers/lsof.py index 7d3dcdf5..27689990 100644 --- a/jc/parsers/lsof.py +++ b/jc/parsers/lsof.py @@ -88,7 +88,7 @@ $ sudo lsof | jc --lsof -p -r ] """ import string -import jc +import jc.utils def process(proc_data): @@ -121,10 +121,12 @@ def process(proc_data): return proc_data -def parse(data, raw=False): +def parse(data, raw=False, quiet=False): # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux']) + compatible = ['linux'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) raw_output = [] diff --git a/jc/parsers/mount.py b/jc/parsers/mount.py index 177af886..001165ad 100644 --- a/jc/parsers/mount.py +++ b/jc/parsers/mount.py @@ -47,7 +47,7 @@ $ mount | jc --mount -p ... ] """ -import jc +import jc.utils def process(proc_data): @@ -68,10 +68,12 @@ def process(proc_data): return proc_data -def parse(data, raw=False): +def parse(data, raw=False, quiet=False): # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux']) + compatible = ['linux'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) raw_output = [] diff --git a/jc/parsers/netstat.py b/jc/parsers/netstat.py index 6891c393..9dc104bd 100644 --- a/jc/parsers/netstat.py +++ b/jc/parsers/netstat.py @@ -3,175 +3,138 @@ Usage: Specify --netstat as the first argument if the piped input is coming from netstat - Supports -lnp netstat options - Limitations: - Only supports TCP and UDP - -Examples: - -$ netstat -p | jc --netstat -p -[ - { - "transport_protocol": "tcp", - "network_protocol": "ipv4", - "local_address": "localhost.localdo", - "local_port": "34480", - "foreign_address": "lb-192-30-255-113", - "foreign_port": "https", - "state": "ESTABLISHED", - "pid": "53550", - "program_name": "git-remote-ht", - "receive_q": "0", - "send_q": "0" - }, - { - "transport_protocol": "tcp", - "network_protocol": "ipv4", - "local_address": "localhost.localdo", - "local_port": "34478", - "foreign_address": "lb-192-30-255-113", - "foreign_port": "https", - "state": "ESTABLISHED", - "pid": "53550", - "program_name": "git-remote-ht", - "receive_q": "0", - "send_q": "0" - } -] - -$ sudo netstat -lpn | jc --netstat -p -[ - { - "transport_protocol": "tcp", - "network_protocol": "ipv4", - "local_address": "127.0.0.1", - "local_port": "25", - "foreign_address": "0.0.0.0", - "foreign_port": "*", - "state": "LISTEN", - "pid": "1584", - "program_name": "master", - "receive_q": "0", - "send_q": "0" - }, - { - "transport_protocol": "tcp", - "network_protocol": "ipv4", - "local_address": "0.0.0.0", - "local_port": "22", - "foreign_address": "0.0.0.0", - "foreign_port": "*", - "state": "LISTEN", - "pid": "1213", - "program_name": "sshd", - "receive_q": "0", - "send_q": "0" - }, - { - "transport_protocol": "tcp", - "network_protocol": "ipv6", - "local_address": "::1", - "local_port": "25", - "foreign_address": "::", - "foreign_port": "*", - "state": "LISTEN", - "pid": "1584", - "program_name": "master", - "receive_q": "0", - "send_q": "0" - }, - { - "transport_protocol": "udp", - "network_protocol": "ipv4", - "local_address": "0.0.0.0", - "local_port": "68", - "foreign_address": "0.0.0.0", - "foreign_port": "*", - "pid": "19177", - "program_name": "dhclient", - "receive_q": "0", - "send_q": "0" - }, - ... -] + -Z option may rarely cause incorrect parsing of the program_name, security_context, and path + for lines with spaces in the program_name """ import string -import jc +import jc.utils -def parse_line(entry): - # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux']) +def process(proc_data): + '''schema: + [ + { + "proto": "tcp", + "recv_q": "0", + "send_q": "0", + "local_address": "0.0.0.0:22", + "foreign_address": "0.0.0.0:*", + "state": "LISTEN", + "program_name": "1219/sshd", + "security_context": "system_u:system_r:sshd_t:s0-s0:c0.c1023 ", + "refcnt": "2", + "flags": "ACC", + "type": "STREAM", + "inode": "20782", + "path": "/var/run/NetworkManager/private-dhcp", + "kind": "network" + } + ] + ''' + return proc_data - output_line = {} - if entry.find('tcp') == 0: - output_line['transport_protocol'] = 'tcp' +def normalize_headers(header): + header = header.lower() + header = header.replace('local address', 'local_address') + header = header.replace('foreign address', 'foreign_address') + header = header.replace('pid/program name', 'program_name') + header = header.replace('security context', 'security_context') + header = header.replace('i-node', 'inode') + header = header.replace('-', '_') - if entry.find('p6') == 2: - output_line['network_protocol'] = 'ipv6' + return header - else: - output_line['network_protocol'] = 'ipv4' - elif entry.find('udp') == 0: - output_line['transport_protocol'] = 'udp' +def parse_network(headers, entry): + # Count words in header + # if len of line is one less than len of header, then insert None in field 5 + entry = entry.split(maxsplit=len(headers) - 1) - if entry.find('p6') == 2: - output_line['network_protocol'] = 'ipv6' + if len(entry) == len(headers) - 1: + entry.insert(5, None) - else: - output_line['network_protocol'] = 'ipv4' - else: - return - - parsed_line = entry.split() - - output_line['local_address'] = parsed_line[3].rsplit(':', 1)[0] - output_line['local_port'] = parsed_line[3].rsplit(':', 1)[-1] - output_line['foreign_address'] = parsed_line[4].rsplit(':', 1)[0] - output_line['foreign_port'] = parsed_line[4].rsplit(':', 1)[-1] - - if len(parsed_line) > 5: - - if parsed_line[5][0] not in string.digits and parsed_line[5][0] != '-': - output_line['state'] = parsed_line[5] - - if len(parsed_line) > 6 and parsed_line[6][0] in string.digits: - output_line['pid'] = parsed_line[6].split('/')[0] - output_line['program_name'] = parsed_line[6].split('/')[1] - else: - if parsed_line[5][0] in string.digits: - output_line['pid'] = parsed_line[5].split('/')[0] - output_line['program_name'] = parsed_line[5].split('/')[1] - - output_line['receive_q'] = parsed_line[1] - output_line['send_q'] = parsed_line[2] + output_line = dict(zip(headers, entry)) + output_line['kind'] = 'network' return output_line -def parse(data): - output = [] +def parse_socket(header_text, headers, entry): + # get the column # of first letter of "state" + # for each line check column # to see if state column is populated + # remove [ and ] from each line + output_line = {} + state_col = header_text.find('state') + + entry = entry.replace('[ ]', '---') + entry = entry.replace('[', ' ').replace(']', ' ') + entry_list = entry.split(maxsplit=len(headers) - 1) + if entry[state_col] in string.whitespace: + entry_list.insert(4, None) + + output_line = dict(zip(headers, entry_list)) + output_line['kind'] = 'socket' + + return output_line + + +def parse_post(raw_data): + + # post process to split pid and program name and ip addresses and ports + + return raw_data + + +def parse(data, raw=False, quiet=False): + # compatible options: linux, darwin, cygwin, win32, aix, freebsd + compatible = ['linux'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) + cleandata = data.splitlines() + raw_output = [] + + network = False + socket = False + headers = '' for line in cleandata: - if line.find('Active Internet connections (w/o servers)') == 0: - continue - - if line.find('Active Internet connections (only servers)') == 0: - continue - - if line.find('Proto') == 0: + if line.find('Active Internet') == 0: + network_list = [] + network = True + socket = False continue if line.find('Active UNIX') == 0: - break + socket_list = [] + network = False + socket = True + continue - output.append(parse_line(line)) + if line.find('Proto') == 0: + header_text = normalize_headers(line) + headers = header_text.split() + continue - clean_output = list(filter(None, output)) - return clean_output + if network: + network_list.append(parse_network(headers, line)) + continue + + if socket: + socket_list.append(parse_socket(header_text, headers, line)) + continue + + for item in [network_list, socket_list]: + for entry in item: + raw_output.append(entry) + + raw_output = parse_post(raw_output) + + if raw: + return raw_output + else: + return process(raw_output) diff --git a/jc/parsers/ps.py b/jc/parsers/ps.py index 059de253..2daef3e7 100644 --- a/jc/parsers/ps.py +++ b/jc/parsers/ps.py @@ -65,13 +65,15 @@ $ ps -ef | jc --ps -p ... ] """ -import jc +import jc.utils -def parse(data): +def parse(data, raw=False, quiet=False): # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']) + compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) # code adapted from Conor Heine at: # https://gist.github.com/cahna/43a1a3ff4d075bcd71f9d7120037a501 diff --git a/jc/parsers/route.py b/jc/parsers/route.py index a6ecc7b3..4aa39a04 100644 --- a/jc/parsers/route.py +++ b/jc/parsers/route.py @@ -40,13 +40,15 @@ $ route | jc --route -p } ] """ -import jc +import jc.utils -def parse(data): +def parse(data, raw=False, quiet=False): # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux', 'aix', 'freebsd']) + compatible = ['linux', 'aix', 'freebsd'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) # code adapted from Conor Heine at: # https://gist.github.com/cahna/43a1a3ff4d075bcd71f9d7120037a501 diff --git a/jc/parsers/uname.py b/jc/parsers/uname.py index 6b2e22b4..fa6549ac 100644 --- a/jc/parsers/uname.py +++ b/jc/parsers/uname.py @@ -20,13 +20,15 @@ $ uname -a | jc --uname -p "kernel_version": "#74-Ubuntu SMP Tue Sep 17 17:06:04 UTC 2019" } """ -import jc +import jc.utils -def parse(data): +def parse(data, raw=False, quiet=False): # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux']) + compatible = ['linux'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) output = {} parsed_line = data.split(maxsplit=3) diff --git a/jc/parsers/uptime.py b/jc/parsers/uptime.py index 823ba41c..75c3f199 100644 --- a/jc/parsers/uptime.py +++ b/jc/parsers/uptime.py @@ -15,13 +15,15 @@ $ uptime | jc --uptime -p "load_15m": "1.91" } """ -import jc +import jc.utils -def parse(data): +def parse(data, raw=False, quiet=False): # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']) + compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) output = {} diff --git a/jc/parsers/w.py b/jc/parsers/w.py index 37982198..1d408d36 100644 --- a/jc/parsers/w.py +++ b/jc/parsers/w.py @@ -29,13 +29,15 @@ $ w | jc --w -p } ] """ -import jc +import jc.utils -def parse(data): +def parse(data, raw=False, quiet=False): # compatible options: linux, darwin, cygwin, win32, aix, freebsd - jc.jc.compatibility(__name__, - ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']) + compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd'] + + if not quiet: + jc.utils.compatibility(__name__, compatible) # code adapted from Conor Heine at: # https://gist.github.com/cahna/43a1a3ff4d075bcd71f9d7120037a501