开发者

Identifying listening ports using Python

In translating some scripts from bash, I am encountering many uses of netstat -an to find if one of our services is listening. While I know I can just use subprocess.call or other even popen I would rather use a pythonic solution so I am not leveraging the unix environment we are operating in.

From what I have read the socket module should have something but I haven't seen anything that checks for lis开发者_JAVA百科tening ports. It could be me not understanding a simple trick, but so far I know how to connect to a socket, and write something that lets me know when that connection failed. But not necessarily have I found something that specifically checks the port to see if its listening.

Any ideas?


How about trying to connect...

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = s.connect_ex(('127.0.0.1', 3306))

if result == 0:
    print('socket is open')
s.close()


I know this question is old, but i write this for begginners. If you want identifying listening ports on your system, you can use the code below.

from socket import *

Port = 0 #First port.
while Port <= 65535: #Port 65535 is last port you can access.
    try:
        try:
            Socket = socket(AF_INET, SOCK_STREAM, 0) #Create a socket.
        except:
            print("Error: Can't open socket!\n")    
            break #If can't open socket, exit the loop.
        Socket.connect(("127.0.0.1", Port)) #Try connect the port. If port is not listening, throws ConnectionRefusedError. 
        Connected = True
    except ConnectionRefusedError:
        Connected = False       
    finally:
        if(Connected and Port != Socket.getsockname()[1]): #If connected,
            print("{}:{} Open \n".format("127.0.0.1", Port)) #print port.
        Port = Port + 1 #Increase port.
        Socket.close() #Close socket.


On Linux we can use strace to see that netstat -ln is reading and parsing various values from the /proc filesystem.

$ strace netstat -ln 2>&1| grep '/proc'
open("/proc/net/tcp", O_RDONLY)         = 3
open("/proc/net/tcp6", O_RDONLY)        = 3
open("/proc/net/udp", O_RDONLY)         = 3
open("/proc/net/udp6", O_RDONLY)        = 3
open("/proc/net/raw", O_RDONLY)         = 3
open("/proc/net/raw6", O_RDONLY)        = 3
open("/proc/net/unix", O_RDONLY)        = 3
open("/proc/net/ipx/socket", O_RDONLY)  = -1 ENOENT (No such file or directory)
open("/proc/net/ipx", O_RDONLY)         = -1 ENOENT (No such file or directory)
open("/proc/net/ax25", O_RDONLY)        = -1 ENOENT (No such file or directory)
open("/proc/net/x25", O_RDONLY)         = -1 ENOENT (No such file or directory)
open("/proc/net/x25", O_RDONLY)         = -1 ENOENT (No such file or directory)
open("/proc/net/nr", O_RDONLY)          = -1 ENOENT (No such file or directory)

So you can just read those files from Python and extract the data you need.

$ cat /proc/net/tcp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode
   0: 00000000:0050 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 8190 1 00000000 300 0 0 2 -1
   1: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 6458 1 00000000 300 0 0 2 -1
   2: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 10425 1 00000000 300 0 0 2 -1
   3: 8D0BA8C0:8801 689255D1:01BB 01 00000000:00000000 00:00000000 00000000  1000        0 1680975 1 00000000 24 4 16 6 -1
   4: 8D0BA8C0:D142 97E67D4A:01BB 06 00000000:00000000 03:000012E8 00000000     0        0 0 3 00000000
   5: 8D0BA8C0:D1A1 96E67D4A:01BB 01 00000000:00000000 00:00000000 00000000  1000        0 1672130 1 00000000 24 4 18 5 -1
   6: 8D0BA8C0:D148 97E67D4A:01BB 01 00000000:00000000 00:00000000 00000000  1000        0 1679875 1 00000000 24 4 20 5 -1

The listening sockets will have remote address 00000000:0000

The address:port pairs are in hex. See: * How can i match each /proc/net/tcp entry to each opened socket?

You could cross reference with /proc//fd. For example, sshd is running on my laptop.

$ cat /var/run/sshd.pid
522

$ sudo ls -l /proc/522/fd
total 0
lrwx------ 1 root root 64 2011-09-15 21:32 0 -> /dev/null
lrwx------ 1 root root 64 2011-09-15 21:32 1 -> /dev/null
lrwx------ 1 root root 64 2011-09-15 21:32 2 -> /dev/null
lrwx------ 1 root root 64 2011-09-15 21:32 3 -> socket:[6456]
lrwx------ 1 root root 64 2011-09-15 21:32 4 -> socket:[6458]

Socket 6456 corresponds to inode 6458 listed in the second row of /proc/net/tcp.

So you can get all this information from proc, but you may end up reinventing netstat -lntp


import psutil
connections = psutil.net_connections()

Reference: https://stackoverflow.com/a/6244270


You could either try connecting to the port in question, or emulate netstat.

Doing the latter will be OS-specific. On Linux you can examine /proc/net/tcp. It looks like this:

  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode                                                     
   0: 00000000:C809 00000000:0000 0A 00000000:00000000 00:00000000 00000000   117        0 8381 1 ffff8802f22a8000 300 0 0 2 -1                      
   1: 00000000:16CC 00000000:0000 0A 00000000:00000000 00:00000000 00000000  1026        0 14336 1 ffff8802f2249440 300 0 0 2 -1                     
   2: 00000000:006F 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 7876 1 ffff8802f2248000 300 0 0 2 -1                      
   3: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 8163 1 ffff8802f3578000 300 0 0 2 -1                      
   4: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 981582 1 ffff8800d7a53600 300 0 0 2 -1                    
   5: 00000000:0019 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 9129 1 ffff8802edc886c0 300 0 0 2 -1                      
   6: 00000000:021A 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 9016 1 ffff8802edc88000 300 0 0 2 -1                      
   7: 00000000:2B1C 00000000:0000 0A 00000000:00000000 00:00000000 00000000  1026        0 783709 1 ffff8803119cca40 300 0 0 2 -1                    
   8: 00000000:977C 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 24292 1 ffff8802f224e540 300 0 0 2 -1                     

You're looking for lines that have 0A in the st ("status") column. The numbers after the colon in local_address -- C809, 16CC etc -- are TCP port numbers (in hex) on which there are listening processes.


I know I am several years late, but non of the existing answers are good enough.

I was Google searching for a good, elegant solution for exactly the same problem and non of the answers already posted seemed good enough, instead I have found solutions of my own and I want to post them here to help future readers who get redirected here by Google.

Most operating systems have an executable named netstat, that can be used to capture listening ports, in this example I am using Windows 10 and Python 3.9.6 x64, but this is written Python so you can easily adapt it for your own use case.

Using plain netstat will be very slow, because of all the name-resolving, using netstat -n will be exponentially faster because it doesn't waste time resolving the names.

In Python 3.9.6, use subproces.run() to run os calls, and use capture_output=True to capture stdout, then use .stdout property of resultant process to get output, the result is in binary form, use .decode() to get string.

Then the output should look like this:


Active Connections

  Proto  Local Address          Foreign Address        State
  TCP    10.70.0.6:1134         40.83.240.146:443      ESTABLISHED
  TCP    10.70.0.6:1283         117.18.232.200:443     CLOSE_WAIT
  TCP    10.70.0.6:1609         198.252.206.25:443     ESTABLISHED
  TCP    10.70.0.6:1621         198.252.206.25:443     ESTABLISHED
  TCP    10.70.0.6:1691         74.125.24.102:443      ESTABLISHED
  TCP    10.70.0.6:1727         142.251.10.94:443      ESTABLISHED
  TCP    10.70.0.6:1728         142.251.10.100:443     TIME_WAIT
  TCP    10.70.0.6:1731         172.217.194.119:443    TIME_WAIT
  TCP    10.70.0.6:1735         74.125.24.113:443      ESTABLISHED
  TCP    10.70.0.6:1787         104.244.42.130:443     ESTABLISHED
  TCP    10.70.0.6:1796         151.101.1.69:443       ESTABLISHED
  TCP    10.70.0.6:1797         151.101.196.193:443    ESTABLISHED
  TCP    10.70.0.6:1799         74.125.130.132:443     ESTABLISHED
  TCP    10.70.0.6:1800         198.252.206.25:443     ESTABLISHED
  TCP    10.70.0.6:1805         3.209.45.230:443       TIME_WAIT
  TCP    10.70.0.6:1806         3.219.6.82:443         TIME_WAIT
  TCP    10.70.0.6:1807         3.211.239.214:443      TIME_WAIT
  TCP    10.70.0.6:1816         140.82.113.26:443      ESTABLISHED
  TCP    127.0.0.1:1053         127.0.0.1:1055         ESTABLISHED
  TCP    127.0.0.1:1055         127.0.0.1:1053         ESTABLISHED
  TCP    127.0.0.1:1057         127.0.0.1:1058         ESTABLISHED
  TCP    127.0.0.1:1058         127.0.0.1:1057         ESTABLISHED
  TCP    127.0.0.1:1061         127.0.0.1:1062         ESTABLISHED
  TCP    127.0.0.1:1062         127.0.0.1:1061         ESTABLISHED
  TCP    127.0.0.1:1763         127.0.0.1:1764         ESTABLISHED
  TCP    127.0.0.1:1764         127.0.0.1:1763         ESTABLISHED
  TCP    127.0.0.1:1766         127.0.0.1:1767         ESTABLISHED
  TCP    127.0.0.1:1767         127.0.0.1:1766         ESTABLISHED
  TCP    127.0.0.1:1810         127.0.0.1:2015         ESTABLISHED
  TCP    127.0.0.1:1811         127.0.0.1:2015         ESTABLISHED
  TCP    127.0.0.1:1820         127.0.0.1:1821         ESTABLISHED
  TCP    127.0.0.1:1821         127.0.0.1:1820         ESTABLISHED
  TCP    127.0.0.1:1829         127.0.0.1:9614         SYN_SENT
  TCP    127.0.0.1:2015         127.0.0.1:1810         ESTABLISHED
  TCP    127.0.0.1:2015         127.0.0.1:1811         ESTABLISHED
  TCP    127.0.0.1:14845        127.0.0.1:14846        ESTABLISHED
  TCP    127.0.0.1:14846        127.0.0.1:14845        ESTABLISHED
  TCP    127.0.0.1:15004        127.0.0.1:15005        ESTABLISHED
  TCP    127.0.0.1:15005        127.0.0.1:15004        ESTABLISHED
  TCP    127.0.0.1:15013        127.0.0.1:15014        ESTABLISHED
  TCP    127.0.0.1:15014        127.0.0.1:15013        ESTABLISHED
  TCP    127.0.0.1:16976        127.0.0.1:16977        ESTABLISHED
  TCP    127.0.0.1:16977        127.0.0.1:16976        ESTABLISHED
  TCP    127.0.0.1:19278        127.0.0.1:19279        ESTABLISHED
  TCP    127.0.0.1:19279        127.0.0.1:19278        ESTABLISHED
  TCP    127.0.0.1:19280        127.0.0.1:19281        ESTABLISHED
  TCP    127.0.0.1:19281        127.0.0.1:19280        ESTABLISHED
  TCP    127.0.0.1:20695        127.0.0.1:21385        ESTABLISHED
  TCP    127.0.0.1:21385        127.0.0.1:20695        ESTABLISHED
  TCP    127.0.0.1:23460        127.0.0.1:23461        ESTABLISHED
  TCP    127.0.0.1:23461        127.0.0.1:23460        ESTABLISHED
  TCP    127.0.0.1:23462        127.0.0.1:23463        ESTABLISHED
  TCP    127.0.0.1:23463        127.0.0.1:23462        ESTABLISHED
  TCP    127.0.0.1:28343        127.0.0.1:28344        ESTABLISHED
  TCP    127.0.0.1:28344        127.0.0.1:28343        ESTABLISHED
  TCP    127.0.0.1:30307        127.0.0.1:30308        ESTABLISHED
  TCP    127.0.0.1:30308        127.0.0.1:30307        ESTABLISHED
  TCP    127.0.0.1:30311        127.0.0.1:30312        ESTABLISHED
  TCP    127.0.0.1:30312        127.0.0.1:30311        ESTABLISHED
  TCP    127.0.0.1:30313        127.0.0.1:30314        ESTABLISHED
  TCP    127.0.0.1:30314        127.0.0.1:30313        ESTABLISHED
  TCP    127.0.0.1:30316        127.0.0.1:30317        ESTABLISHED
  TCP    127.0.0.1:30317        127.0.0.1:30316        ESTABLISHED
  TCP    127.0.0.1:30319        127.0.0.1:30320        ESTABLISHED
  TCP    127.0.0.1:30320        127.0.0.1:30319        ESTABLISHED
  TCP    127.0.0.1:30584        127.0.0.1:30585        ESTABLISHED
  TCP    127.0.0.1:30585        127.0.0.1:30584        ESTABLISHED
  TCP    127.0.0.1:30623        127.0.0.1:30624        ESTABLISHED
  TCP    127.0.0.1:30624        127.0.0.1:30623        ESTABLISHED
  TCP    127.0.0.1:49669        127.0.0.1:49670        ESTABLISHED
  TCP    127.0.0.1:49670        127.0.0.1:49669        ESTABLISHED
  TCP    127.0.0.1:49690        127.0.0.1:49692        ESTABLISHED
  TCP    127.0.0.1:49692        127.0.0.1:49690        ESTABLISHED
  TCP    [::1]:3306             [::1]:23468            ESTABLISHED
  TCP    [::1]:3306             [::1]:23469            ESTABLISHED
  TCP    [::1]:23468            [::1]:3306             ESTABLISHED
  TCP    [::1]:23469            [::1]:3306             ESTABLISHED

Use splitlines() to get separate lines, then use list slicing to get the contents of the actual table, here we use index 4, then using regex splitting to split on whitespace characters, then use index to get the local address value, then finally use string split on colons and indexing to get the ports.

The code:

import psutil
import re
import subprocess

def get_active_ports():
    process = subprocess.run(['netstat', '-n'], capture_output=True)
    report = process.stdout.decode().splitlines()
    ports = set()
    for i in report[4:]:
        ports.add(re.split(':(?!.*:)', re.split('\s+', i)[2])[1])
    return ports

Or in one-liner:

set([re.split(':(?!.*:)', re.split('\s+', i)[2])[1] for i in subprocess.run(['netstat', '-n'], capture_output=True).stdout.decode().splitlines()[4:]])

Performance:

In [119]: %timeit set([re.split(':(?!.*:)', re.split('\s+', i)[2])[1] for i in subprocess.run(['netstat', '-n'], capture_output=True).stdout.decode().splitlines()[4:]])
11.4 ms ± 315 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Or, alternatively, psutil has a .net_connections() method, you can just get the ports from it.

Just use set comprehension to grab the output:

set(i.laddr.port for i in psutil.net_connections())

This approach is tremendously faster than the previous one:

In [103]: %timeit set(i.laddr.port for i in psutil.net_connections())
893 µs ± 13.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜