2019-10-15 15:06:09 -07:00
|
|
|
"""jc - JSON CLI output utility netstat Parser
|
|
|
|
|
|
|
|
Usage:
|
2019-10-17 12:15:27 -07:00
|
|
|
Specify --netstat as the first argument if the piped input is coming from netstat
|
2019-10-15 15:06:09 -07:00
|
|
|
|
2019-10-17 12:15:27 -07:00
|
|
|
Supports -lnp netstat options
|
2019-10-15 15:06:09 -07:00
|
|
|
|
2019-10-17 12:15:27 -07:00
|
|
|
Limitations:
|
|
|
|
Only supports TCP and UDP
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
|
|
|
|
$ netstat -p | jc --netstat -p
|
|
|
|
{
|
|
|
|
"client": {
|
|
|
|
"tcp": {
|
|
|
|
"ipv4": [
|
|
|
|
{
|
|
|
|
"local_address": "localhost.localdo",
|
|
|
|
"local_port": "34480",
|
|
|
|
"foreign_address": "lb-192-30-255-113",
|
|
|
|
"foreign_port": "https",
|
|
|
|
"state": "ESTABLISHED",
|
2019-10-17 13:04:34 -07:00
|
|
|
"pid": 53550,
|
2019-10-17 12:15:27 -07:00
|
|
|
"program_name": "git-remote-ht",
|
|
|
|
"receive_q": 0,
|
|
|
|
"send_q": 0
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"local_address": "localhost.localdo",
|
|
|
|
"local_port": "34478",
|
|
|
|
"foreign_address": "lb-192-30-255-113",
|
|
|
|
"foreign_port": "https",
|
|
|
|
"state": "ESTABLISHED",
|
2019-10-17 13:04:34 -07:00
|
|
|
"pid": 53550,
|
2019-10-17 12:15:27 -07:00
|
|
|
"program_name": "git-remote-ht",
|
|
|
|
"receive_q": 0,
|
|
|
|
"send_q": 0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-10-17 08:03:56 -07:00
|
|
|
|
|
|
|
$ netstat -lp | jc --netstat -p
|
2019-10-17 12:15:27 -07:00
|
|
|
{
|
|
|
|
"server": {
|
|
|
|
"tcp": {
|
|
|
|
"ipv4": [
|
|
|
|
{
|
|
|
|
"local_address": "localhost",
|
|
|
|
"local_port": "smtp",
|
|
|
|
"foreign_address": "0.0.0.0",
|
|
|
|
"foreign_port": "*",
|
|
|
|
"state": "LISTEN",
|
2019-10-17 13:04:34 -07:00
|
|
|
"pid": 1594,
|
2019-10-17 12:15:27 -07:00
|
|
|
"program_name": "master",
|
|
|
|
"receive_q": 0,
|
|
|
|
"send_q": 0
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"local_address": "0.0.0.0",
|
|
|
|
"local_port": "ssh",
|
|
|
|
"foreign_address": "0.0.0.0",
|
|
|
|
"foreign_port": "*",
|
|
|
|
"state": "LISTEN",
|
2019-10-17 13:04:34 -07:00
|
|
|
"pid": 21918,
|
2019-10-17 12:15:27 -07:00
|
|
|
"program_name": "sshd",
|
|
|
|
"receive_q": 0,
|
|
|
|
"send_q": 0
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"ipv6": [
|
|
|
|
{
|
|
|
|
"local_address": "localhost",
|
|
|
|
"local_port": "smtp",
|
|
|
|
"foreign_address": "[::]",
|
|
|
|
"foreign_port": "*",
|
|
|
|
"state": "LISTEN",
|
2019-10-17 13:04:34 -07:00
|
|
|
"pid": 1594,
|
2019-10-17 12:15:27 -07:00
|
|
|
"program_name": "master",
|
|
|
|
"receive_q": 0,
|
|
|
|
"send_q": 0
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"local_address": "[::]",
|
|
|
|
"local_port": "ssh",
|
|
|
|
"foreign_address": "[::]",
|
|
|
|
"foreign_port": "*",
|
|
|
|
"state": "LISTEN",
|
2019-10-17 13:04:34 -07:00
|
|
|
"pid": 21918,
|
2019-10-17 12:15:27 -07:00
|
|
|
"program_name": "sshd",
|
|
|
|
"receive_q": 0,
|
|
|
|
"send_q": 0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"udp": {
|
|
|
|
"ipv4": [
|
|
|
|
{
|
|
|
|
"local_address": "0.0.0.0",
|
|
|
|
"local_port": "bootpc",
|
|
|
|
"foreign_address": "0.0.0.0",
|
|
|
|
"foreign_port": "*",
|
2019-10-17 13:04:34 -07:00
|
|
|
"pid": 13903,
|
2019-10-17 12:15:27 -07:00
|
|
|
"program_name": "dhclient",
|
|
|
|
"receive_q": 0,
|
|
|
|
"send_q": 0
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"local_address": "localhost",
|
|
|
|
"local_port": "323",
|
|
|
|
"foreign_address": "0.0.0.0",
|
|
|
|
"foreign_port": "*",
|
2019-10-17 13:04:34 -07:00
|
|
|
"pid": 30926,
|
2019-10-17 12:15:27 -07:00
|
|
|
"program_name": "chronyd",
|
|
|
|
"receive_q": 0,
|
|
|
|
"send_q": 0
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"ipv6": [
|
|
|
|
{
|
|
|
|
"local_address": "localhost",
|
|
|
|
"local_port": "323",
|
|
|
|
"foreign_address": "[::]",
|
|
|
|
"foreign_port": "*",
|
2019-10-17 13:04:34 -07:00
|
|
|
"pid": 30926,
|
2019-10-17 12:15:27 -07:00
|
|
|
"program_name": "chronyd",
|
|
|
|
"receive_q": 0,
|
|
|
|
"send_q": 0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-10-15 15:06:09 -07:00
|
|
|
"""
|
2019-10-17 12:07:01 -07:00
|
|
|
import string
|
2019-10-15 15:06:09 -07:00
|
|
|
|
2019-10-17 08:03:56 -07:00
|
|
|
output = {}
|
2019-10-15 15:06:09 -07:00
|
|
|
|
2019-10-17 08:03:56 -07:00
|
|
|
class state():
|
|
|
|
section = ''
|
|
|
|
session = ''
|
|
|
|
network = ''
|
|
|
|
|
|
|
|
client_tcp_ip4 = []
|
|
|
|
client_tcp_ip6 = []
|
|
|
|
client_udp_ip4 = []
|
|
|
|
client_udp_ip6 = []
|
2019-10-15 15:06:09 -07:00
|
|
|
|
2019-10-17 08:03:56 -07:00
|
|
|
server_tcp_ip4 = []
|
|
|
|
server_tcp_ip6 = []
|
|
|
|
server_udp_ip4 = []
|
|
|
|
server_udp_ip6 = []
|
|
|
|
|
|
|
|
def parse_line(entry):
|
|
|
|
parsed_line = entry.split()
|
|
|
|
output_line = {}
|
|
|
|
|
2019-10-17 12:07:01 -07:00
|
|
|
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]
|
|
|
|
|
2019-10-17 10:54:37 -07:00
|
|
|
if len(parsed_line) > 5:
|
2019-10-17 12:07:01 -07:00
|
|
|
|
|
|
|
if parsed_line[5][0] not in string.digits:
|
|
|
|
output_line['state'] = parsed_line[5]
|
|
|
|
|
|
|
|
if len(parsed_line) > 6:
|
2019-10-17 13:04:34 -07:00
|
|
|
output_line['pid'] = int(parsed_line[6].split('/')[0])
|
2019-10-17 12:07:01 -07:00
|
|
|
output_line['program_name'] = parsed_line[6].split('/')[1]
|
|
|
|
else:
|
2019-10-17 13:04:34 -07:00
|
|
|
output_line['pid'] = int(parsed_line[5].split('/')[0])
|
2019-10-17 12:07:01 -07:00
|
|
|
output_line['program_name'] = parsed_line[5].split('/')[1]
|
|
|
|
|
|
|
|
output_line['receive_q'] = int(parsed_line[1])
|
|
|
|
output_line['send_q'] = int(parsed_line[2])
|
2019-10-17 08:03:56 -07:00
|
|
|
|
|
|
|
return output_line
|
|
|
|
|
|
|
|
def parse(data):
|
2019-10-15 15:06:09 -07:00
|
|
|
cleandata = data.splitlines()
|
|
|
|
|
2019-10-17 08:03:56 -07:00
|
|
|
for line in cleandata:
|
2019-10-17 10:54:37 -07:00
|
|
|
|
2019-10-17 08:03:56 -07:00
|
|
|
if line.find('Active Internet connections (w/o servers)') == 0:
|
|
|
|
state.section = "client"
|
|
|
|
continue
|
|
|
|
|
|
|
|
if line.find('Active Internet connections (only servers)') == 0:
|
|
|
|
state.section = "server"
|
|
|
|
continue
|
|
|
|
|
|
|
|
if line.find('Proto') == 0:
|
|
|
|
continue
|
|
|
|
|
|
|
|
if line.find('Active UNIX') == 0:
|
|
|
|
break
|
|
|
|
|
2019-10-17 10:54:37 -07:00
|
|
|
if state.section == 'client':
|
2019-10-17 08:03:56 -07:00
|
|
|
if line.find('tcp') == 0:
|
|
|
|
state.session = 'tcp'
|
|
|
|
if line.find('p6') == 2:
|
|
|
|
state.network = 'ipv6'
|
|
|
|
else:
|
|
|
|
state.network = 'ipv4'
|
|
|
|
elif line.find('udp') == 0:
|
|
|
|
state.session = 'udp'
|
|
|
|
if line.find('p6') == 2:
|
|
|
|
state.network = 'ipv6'
|
|
|
|
else:
|
|
|
|
state.network = 'ipv4'
|
2019-10-17 10:54:37 -07:00
|
|
|
elif state.section == 'server':
|
2019-10-17 08:03:56 -07:00
|
|
|
if line.find('tcp') == 0:
|
|
|
|
state.session = 'tcp'
|
|
|
|
if line.find('p6') == 2:
|
|
|
|
state.network = 'ipv6'
|
|
|
|
else:
|
|
|
|
state.network = 'ipv4'
|
|
|
|
elif line.find('udp') == 0:
|
|
|
|
state.session = 'udp'
|
|
|
|
if line.find('p6') == 2:
|
|
|
|
state.network = 'ipv6'
|
|
|
|
else:
|
|
|
|
state.network = 'ipv4'
|
|
|
|
|
2019-10-17 09:05:49 -07:00
|
|
|
if state.section == 'client' and state.session == 'tcp' and state.network == 'ipv4':
|
2019-10-17 08:09:19 -07:00
|
|
|
state.client_tcp_ip4.append(parse_line(line))
|
2019-10-17 08:03:56 -07:00
|
|
|
|
2019-10-17 09:05:49 -07:00
|
|
|
if state.section == 'client' and state.session == 'tcp' and state.network == 'ipv6':
|
2019-10-17 08:09:19 -07:00
|
|
|
state.client_tcp_ip6.append(parse_line(line))
|
2019-10-17 08:03:56 -07:00
|
|
|
|
2019-10-17 09:05:49 -07:00
|
|
|
if state.section == 'client' and state.session == 'udp' and state.network == 'ipv4':
|
2019-10-17 08:09:19 -07:00
|
|
|
state.client_udp_ip4.append(parse_line(line))
|
2019-10-17 08:03:56 -07:00
|
|
|
|
2019-10-17 09:05:49 -07:00
|
|
|
if state.section == 'client' and state.session == 'udp' and state.network == 'ipv6':
|
2019-10-17 08:09:19 -07:00
|
|
|
state.client_udp_ip6.append(parse_line(line))
|
2019-10-17 08:03:56 -07:00
|
|
|
|
|
|
|
|
2019-10-17 09:05:49 -07:00
|
|
|
if state.section == 'server' and state.session == 'tcp' and state.network == 'ipv4':
|
2019-10-17 08:09:19 -07:00
|
|
|
state.server_tcp_ip4.append(parse_line(line))
|
2019-10-17 08:03:56 -07:00
|
|
|
|
2019-10-17 10:54:37 -07:00
|
|
|
if state.section == 'server' and state.session == 'tcp' and state.network == 'ipv6':
|
2019-10-17 08:09:19 -07:00
|
|
|
state.server_tcp_ip6.append(parse_line(line))
|
2019-10-17 08:03:56 -07:00
|
|
|
|
2019-10-17 10:54:37 -07:00
|
|
|
if state.section == 'server' and state.session == 'udp' and state.network == 'ipv4':
|
2019-10-17 08:09:19 -07:00
|
|
|
state.server_udp_ip4.append(parse_line(line))
|
2019-10-17 08:03:56 -07:00
|
|
|
|
2019-10-17 10:54:37 -07:00
|
|
|
if state.section == 'server' and state.session == 'udp' and state.network == 'ipv6':
|
2019-10-17 08:09:19 -07:00
|
|
|
state.server_udp_ip6.append(parse_line(line))
|
2019-10-17 08:03:56 -07:00
|
|
|
|
2019-10-17 10:54:37 -07:00
|
|
|
state.session = ''
|
|
|
|
state.network = ''
|
|
|
|
|
2019-10-17 09:05:49 -07:00
|
|
|
# build dictionary
|
|
|
|
if state.client_tcp_ip4:
|
|
|
|
if 'client' not in output:
|
|
|
|
output['client'] = {}
|
|
|
|
if 'tcp' not in output['client']:
|
|
|
|
output['client']['tcp'] = {}
|
|
|
|
output['client']['tcp']['ipv4'] = state.client_tcp_ip4
|
|
|
|
|
|
|
|
if state.client_tcp_ip6:
|
|
|
|
if 'client' not in output:
|
|
|
|
output['client'] = {}
|
|
|
|
if 'tcp' not in output['client']:
|
|
|
|
output['client']['tcp'] = {}
|
|
|
|
output['client']['tcp']['ipv6'] = state.client_tcp_ip6
|
|
|
|
|
|
|
|
if state.client_udp_ip4:
|
|
|
|
if 'client' not in output:
|
|
|
|
output['client'] = {}
|
|
|
|
if 'udp' not in output['client']:
|
|
|
|
output['client']['udp'] = {}
|
|
|
|
output['client']['udp']['ipv4'] = state.client_udp_ip4
|
|
|
|
|
|
|
|
if state.client_udp_ip6:
|
|
|
|
if 'client' not in output:
|
|
|
|
output['client'] = {}
|
|
|
|
if 'udp' not in output['client']:
|
|
|
|
output['client']['udp'] = {}
|
|
|
|
output['client']['udp']['ipv6'] = state.client_udp_ip6
|
|
|
|
|
|
|
|
|
|
|
|
if state.server_tcp_ip4:
|
|
|
|
if 'server' not in output:
|
|
|
|
output['server'] = {}
|
|
|
|
if 'tcp' not in output['server']:
|
|
|
|
output['server']['tcp'] = {}
|
|
|
|
output['server']['tcp']['ipv4'] = state.server_tcp_ip4
|
|
|
|
|
|
|
|
if state.server_tcp_ip6:
|
|
|
|
if 'server' not in output:
|
|
|
|
output['server'] = {}
|
|
|
|
if 'tcp' not in output['server']:
|
|
|
|
output['server']['tcp'] = {}
|
|
|
|
output['server']['tcp']['ipv6'] = state.server_tcp_ip6
|
|
|
|
|
|
|
|
if state.server_udp_ip4:
|
|
|
|
if 'server' not in output:
|
|
|
|
output['server'] = {}
|
|
|
|
if 'udp' not in output['server']:
|
|
|
|
output['server']['udp'] = {}
|
|
|
|
output['server']['udp']['ipv4'] = state.server_udp_ip4
|
|
|
|
|
|
|
|
if state.server_udp_ip6:
|
|
|
|
if 'server' not in output:
|
|
|
|
output['server'] = {}
|
|
|
|
if 'udp' not in output['server']:
|
|
|
|
output['server']['udp'] = {}
|
|
|
|
output['server']['udp']['ipv6'] = state.server_udp_ip6
|
2019-10-15 15:06:09 -07:00
|
|
|
|
|
|
|
return output
|