summaryrefslogtreecommitdiffstats
path: root/scripts/external_libs/netstat.py
blob: 8b4eaba0dea67f3d0b060cedf1ea87e85a1531e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#!/usr/bin/python

# based on http://voorloopnul.com/blog/a-python-netstat-in-less-than-100-lines-of-code/
# added caching of glob for x10 speedup (additional x2 by omitting pid)

import pwd
import os
import glob

PROC_TCP = "/proc/net/tcp"
STATE = {
        '01':'ESTABLISHED',
        '02':'SYN_SENT',
        '03':'SYN_RECV',
        '04':'FIN_WAIT1',
        '05':'FIN_WAIT2',
        '06':'TIME_WAIT',
        '07':'CLOSE',
        '08':'CLOSE_WAIT',
        '09':'LAST_ACK',
        '0A':'LISTEN',
        '0B':'CLOSING'
        }

def _load():
    ''' Read the table of tcp connections & remove header  '''
    with open(PROC_TCP,'r') as f:
        content = f.readlines()
        content.pop(0)
    return content

def _hex2dec(s, string = True):
    if string:
        return str(int(s,16))
    return int(s,16)

def _ip(s):
    ip = [(_hex2dec(s[6:8])),(_hex2dec(s[4:6])),(_hex2dec(s[2:4])),(_hex2dec(s[0:2]))]
    return '.'.join(ip)

def _remove_empty(array):
    return [x for x in array if x]

def _convert_ip_port(array):
    host,port = array.split(':')
    return _ip(host),_hex2dec(port, string = False)

def netstat(with_pid = True, search_local_port = None):
    '''
    Function to return a list with status of tcp connections at linux systems
    To get pid of all network process running on system, you must run this script
    as superuser
    '''

    pid_cache.clear()
    content=_load()
    result = []
    for line in content:
        line_array = _remove_empty(line.split(' '))     # Split lines and remove empty spaces.
        l_host,l_port = _convert_ip_port(line_array[1]) # Convert ipaddress and port from hex to decimal.
        if search_local_port and search_local_port != l_port:
            continue
        r_host,r_port = _convert_ip_port(line_array[2]) 
        tcp_id = line_array[0]
        state = STATE.get(line_array[3])
        uid = pwd.getpwuid(int(line_array[7]))[0]       # Get user from UID.
        inode = line_array[9]                           # Need the inode to get process pid.
        if with_pid:
            pid = _get_pid_of_inode(inode)                  # Get pid prom inode.
            try:                                            # try read the process name.
                exe = os.readlink('/proc/' + pid + '/exe')
            except:
                exe = None
        else:
            pid = exe = None
        result.append([tcp_id, uid, l_host, l_port, r_host, r_port, state, pid, exe])
    pid_cache.clear()
    return result

pid_cache = {}
def _get_pid_of_inode(inode):
    '''
    To retrieve the process pid, check every running process and look for one using
    the given inode.
    '''
    if not pid_cache:
        for fd in glob.glob('/proc/[0-9]*/fd/[0-9]*'):
            try:
                pid_cache[fd] = os.readlink(fd)
            except:
                pass
    inode = '[' + inode + ']'
    for key, val in pid_cache.items():
        if inode in val:
            return key.split('/')[2]
    return None

if __name__ == '__main__':
    for conn in netstat():
        print(conn)