Определение прослушивающих портов с использованием Python

При переводе некоторых сценариев из bash я сталкиваюсь со многими случаями использования netstat -an, чтобы определить, прослушивает ли один из наших сервисов. Хотя я знаю, что могу просто использовать subprocess.call или другой даже popen, я бы предпочел использовать pythonic решение, поэтому я не использую среду unix, в которой мы работаем.

Из того, что я прочитал, у модуля сокета должно быть что-то, но я не видел ничего, что проверяет прослушивание портов. Может быть, я не понимаю простой трюк, но до сих пор я знаю, как подключиться к сокету, и написать что-то, что позволяет мне знать, когда это соединение не удалось. Но не обязательно я нашел что-то, что специально проверяет порт, чтобы узнать, прослушивает ли он.

Есть идеи?

6 ответов

Решение

Как насчет попытки подключиться...

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()

Я знаю, что этот вопрос старый, но я пишу это для начинающих. Если вы хотите определить порты прослушивания в вашей системе, вы можете использовать код ниже.

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.
import psutil
connections = psutil.net_connections()

Ссылка: /questions/13071081/kak-mne-poluchit-dostup-k-dannyim-netstat-v-python/13071100#13071100

В Linux мы можем использовать strace, чтобы увидеть, что netstat -ln читает и анализирует различные значения из файловой системы / proc.

$ 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)

Таким образом, вы можете просто прочитать эти файлы из Python и извлечь необходимые данные.

$ 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

Сокеты прослушивания будут иметь удаленный адрес 00000000:0000

Адрес: пары портов указаны в шестнадцатеричном формате. Смотрите: * Как мне сопоставить каждую запись / proc / net / tcp с каждым открытым сокетом?

Вы можете сделать перекрестную ссылку с /proc//fd. Например, sshd работает на моем ноутбуке.

$ 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]

Сокет 6456 соответствует индексу 6458, указанному во втором ряду / proc / net / tcp.

Таким образом, вы можете получить всю эту информацию из proc, но в итоге вы можете заново изобретать netstat -lntp

Вы можете попробовать подключиться к рассматриваемому порту или эмулировать netstat,

Последнее будет зависеть от ОС. На Linux вы можете изучить /proc/net/tcp, Это выглядит так:

  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                     

Вы ищете строки, которые имеют 0A в st ("статус") столбец. Числа после двоеточия в local_address - C809, 16CC etc - номера портов TCP (в шестнадцатеричном формате), на которых происходят прослушивающие процессы.

Я знаю, что опаздываю на несколько лет, но ни один из существующих ответов недостаточно хорош.

Я искал в Google хорошее, элегантное решение для той же проблемы, и ни один из уже опубликованных ответов не казался достаточно хорошим, вместо этого я нашел собственные решения и хочу опубликовать их здесь, чтобы помочь будущим читателям, которые будут перенаправлены сюда Google.

В большинстве операционных систем есть исполняемый файл с именем, который можно использовать для захвата портов прослушивания, в этом примере я использую Windows 10 и Python 3.9.6 x64, но это написано на Python, поэтому вы можете легко адаптировать его для своего собственного варианта использования.

Использование простого netstat будет очень медленным из-за разрешения имен с использованием netstat -n будет экспоненциально быстрее, потому что не тратит время на разрешение имен.

В Python 3.9.6 используйте subproces.run() для запуска вызовов ОС и использовать capture_output=True для захвата stdout, затем используйте .stdout свойство результирующего процесса для получения вывода, результат в двоичной форме, используйте .decode() получить строку.

Тогда результат должен выглядеть так:

      
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

Использовать splitlines() чтобы получить отдельные строки, затем используйте нарезку списка, чтобы получить содержимое фактической таблицы, здесь мы используем индекс 4, затем используем разделение регулярных выражений для разделения на пробельные символы, затем используйте индекс для получения значения локального адреса, затем, наконец, используйте разделение строк на двоеточия и индексация для получения портов.

Код:

      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

Или однострочным:

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

Представление:

      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)

Или, альтернативно, psutil имеет .net_connections() метод, вы можете просто получить от него порты.

Просто используйте понимание набора, чтобы получить результат:

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

Этот подход намного быстрее, чем предыдущий:

      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)
Другие вопросы по тегам