Created
February 26, 2019 15:50
-
-
Save Mithrilwoodrat/e5d822bbb15e24ff41c422470289dc5d to your computer and use it in GitHub Desktop.
Linux netstat in python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# ref | |
# * https://gist.github.com/aleiphoenix/0e886336522c2f41412d | |
# * https://stackoverflow.com/questions/3319521/how-can-i-match-each-proc-net-tcp-entry-to-each-opened-socket | |
# * https://stackoverflow.com/questions/14667215/finding-a-process-id-given-a-socket-and-inode-in-python-3 | |
# read /proc/net/tcp get address port and inode. get pid by checking every sysbol link to this inode in every /proc/<PID>/fd | |
import re | |
import os | |
import sys | |
with open('/proc/net/tcp') as f: | |
lineno = 0 | |
sockets = [] | |
for line in f: | |
lineno += 1 | |
if lineno == 1: | |
continue | |
sockets.append(line.strip()) | |
columns = ("seq", "uid", "inode", "local", "remote", "timeout") | |
title = dict() | |
for c in columns: | |
title[c] = c | |
def split_every_n(data, n): | |
return [data[i:i+n] for i in range(0, len(data), n)] | |
def convert_linux_netaddr(address): | |
hex_addr, hex_port = address.split(':') | |
addr_list = split_every_n(hex_addr, 2) | |
addr_list.reverse() | |
addr = ".".join(map(lambda x: str(int(x, 16)), addr_list)) | |
port = str(int(hex_port, 16)) | |
return "{}:{}".format(addr, port) | |
def format_line(data): | |
#print data | |
return ("{seq:4s} {uid:5s} {local:25s} {remote:25s} " + | |
"{timeout:8s} {inode:8s} \n".format(**data)) | |
def find_pid(inode): | |
# get a list of all files and directories in /proc | |
procFiles = os.listdir("/proc/") | |
# remove the pid of the current python process | |
procFiles.remove(str(os.getpid())) | |
# set up a list object to store valid pids | |
pids = [] | |
for f in procFiles: | |
try: | |
# convert the filename to an integer and back, saving the result to a list | |
integer = int(f) | |
pids.append(str(integer)) | |
except ValueError: | |
# if the filename doesn't convert to an integer, it's not a pid, and we don't care about it | |
pass | |
for pid in pids: | |
# check the fd directory for socket information | |
fds = os.listdir("/proc/%s/fd/" % pid) | |
for fd in fds: | |
# save the pid for sockets matching our inode | |
if ('socket:[%s]' % inode) == os.readlink("/proc/%s/fd/%s" % (pid, fd)): | |
return pid | |
rv = [] | |
for info in sockets: | |
_ = re.split(r'\s+', info) | |
_tmp = { | |
'seq': _[0], | |
'local': convert_linux_netaddr(_[1]), | |
'remote': convert_linux_netaddr(_[2]), | |
'uid': _[7], | |
'timeout': _[8], | |
'inode': _[9], | |
'pid': find_pid(_[9]) | |
} | |
rv.append(_tmp) | |
if len(rv) > 0: | |
title = "{:4s} {:5s} {:25s} {:25s} {:8s} {:8s} \n".format(*title) | |
sys.stderr.write(title) | |
for _ in rv: | |
sys.stdout.write(str(_)+'\n') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment