Як визначити час підключення сокета до Linux


24

Я можу переконатися, що з'єднання налаштовано:

$ netstat -tn | grep "192.168.2.110"
tcp  0  0 192.168.2.100:10444  192.168.2.110:52639  ESTABLISHED

чи є спосіб перевірити, як довго було підключено (підключено) цей порт tcp?

(Ні, у мене немає доступу до журналів додатків)

Відповіді:


23

Ви можете спробувати наступне:

  1. отримати PID (скажімо $pid) програми, додавши -pопцію до netstat.

  2. визначте належний рядок у /proc/net/tcpфайлі, переглянувши поля local_addressта / або rem_address(зауважте, що вони у шістнадцятковому форматі, зокрема IP-адреса виражається у порядку малобайкового байту), а також переконайтесь, що stце 01(для ESTABLISHED);

  3. відзначте пов’язане inodeполе (скажімо $inode);

  4. шукайте це inodeсеред дескрипторів файлів /proc/$pid/fdі, нарешті, запитуйте час доступу до символічного посилання:

    find /proc/$pid/fd -lname "socket:\[$inode\]" -printf %t
    

Це бурхлива робота ... ось сценарій (заглушка) для автоматизації вищезазначених пунктів, для цього потрібна віддалена адреса і він друкує час роботи сокета за лічені секунди:

function suptime() {
    local addr=${1:?Specify the remote IPv4 address}
    local port=${2:?Specify the remote port number}
    # convert the provided address to hex format
    local hex_addr=$(python -c "import socket, struct; print(hex(struct.unpack('<L', socket.inet_aton('$addr'))[0])[2:10].upper().zfill(8))")
    local hex_port=$(python -c "print(hex($port)[2:].upper().zfill(4))")
    # get the PID of the owner process
    local pid=$(netstat -ntp 2>/dev/null | awk '$6 == "ESTABLISHED" && $5 == "'$addr:$port'"{sub("/.*", "", $7); print $7}')
    [ -z "$pid" ] && { echo 'Address does not match' 2>&1; return 1; }
    # get the inode of the socket
    local inode=$(awk '$4 == "01" && $3 == "'$hex_addr:$hex_port'" {print $10}' /proc/net/tcp)
    [ -z "$inode" ] && { echo 'Cannot lookup the socket' 2>&1; return 1; }
    # query the inode status change time
    local timestamp=$(find /proc/$pid/fd -lname "socket:\[$inode\]" -printf %T@)
    [ -z "$timestamp" ] && { echo 'Cannot fetch the timestamp' 2>&1; return 1; }
    # compute the time difference
    LANG=C printf '%s (%.2fs ago)\n' "$(date -d @$timestamp)" $(bc <<<"$(date +%s.%N) - $timestamp")
}

(Редагувати завдяки Алексу за виправлення )

Приклад:

$ suptime 93.184.216.34 80
Thu Dec 24 16:22:58 CET 2015 (46.12s ago)

1
Цей рецепт відображає вік процесу, який створив TCP-з'єднання, а не саме з'єднання.
мирослав

@myroslav ви впевнені? Він працює проти цього сценарію Node.js .
cYrus

Я перевірив ваш новий сценарій на TCP-з'єднаннях, відкритих моїм Firefox на Fedora 22 64-розрядному, і я напевно не отримую "безрезультатного" числа. Коли нова розетка відкривається, вона отримує "випадковий" час роботи, як правило, час "наймолодшого" Встановленого сокета.
мирослав

@myroslav Я тут використовую Debian (3.16.0-4-amd64). Єдине, що я помічаю, це те, що повідомлений час фактично затримується на 3 секунди стосовно створення сокета. Можливо, пов’язані якісь системні форми поведінки ...
cYrus

Для сценарію "$ suptime 192: 168: 120: 10 6379 Traceback (останній дзвінок останній): Файл" <string> ", рядок 1, в <module> socket.error: незаконні рядки IP-адреси передані до inet_aton Адреса не збігається "
Ondra Žižka

4

Ці питання мені були корисні, але я знайшов використання lsofзамість того, netstatщоб дозволити мені уникати всіх HEX-матеріалів:

Для процесу, ${APP}керованого користувачем ${USER}, наступне повертає всі відкриті сокети до IP-адреси $ {IP}:

PEEID=$(sudo pgrep -u ${USER} ${APP}) && for i in `sudo lsof -anP -i -u logstash | grep ${IP} | awk '{print $6}'` ; do echo "${device} time" ; sudo find /proc/${PEEID}/fd -lname "socket:\[${device}\]" -printf %t 2> /dev/null  ; echo  ;  done

lsofМістить PIDзанадто, але я не знаю , як отримати його і номер пристрою.

Це було протестовано на Amazon Linux.


3

Сценарій cYrus працював на мене, але мені довелося трохи його виправити (щоб позбутися "L" у шістнадцятковій адресі та зробити порт чотиризначним шістнадцятковим):

--- suptime.orig    2015-08-20 15:46:12.896652464 +0200
+++ suptime 2015-08-20 15:47:48.560074728 +0200
@@ -7,8 +7,8 @@
     hex_addr=$(python -c "
 import socket, struct;
 print hex(struct.unpack('<L',
-socket.inet_aton('$addr'))[0])[2:].upper().zfill(8)")
-    hex_port=$(python -c "print hex($port)[2:].upper()")
+socket.inet_aton('$addr'))[0])[2:10].upper().zfill(8)")
+    hex_port=$(python -c "print hex($port)[2:].upper().zfill(4)")
     inode=$(awk '$3 == "'$hex_addr:$hex_port'" {print $10}' /proc/net/tcp)
     time=$(find /proc/$pid/fd -lname "socket:\[$inode\]" -printf %A@)
     LANG=C printf '%.2fs' $(bc <<<"$(date +%s.%N) - $time")

1

Як щодо:

lsof -t -i @ 192.168.2.110 | xargs ps -fp

Ви також можете налаштувати команду "ps", щоб просто отримати pid та час початку з -o, наприклад:

lsof -t -i @ 192.168.2.110 | xargs ps --no-headers -o'pid, start '-p

Звичайно, це передбачає, що розетка була запущена, коли процес був.


це показує, як довго триває процес, який відкрив сокет. У випадку, якщо є процес, який працює весь час і є відключення мережі, ці значення будуть дуже різними. +1 за зусилля
hidralisk

1

Дякую за сценарій, який підтримується у відповіді cYrus. У мене виникли проблеми з друком дублікатів, ймовірно, тому що може бути багато підключень від різних PID до вказаної адреси, тому ось моя вдосконалена версія, яка також друкує PID на кожному вихідному рядку:

function suptime() {
    local addr=${1:?Specify the remote IPv4 address}
    local port=${2:?Specify the remote port number}

    # convert the provided address to hex format
    local hex_addr=$(python -c "import socket, struct; print(hex(struct.unpack('<L', socket.inet_aton('$addr'))[0])[2:10].upper().zfill(8))")
    local hex_port=$(python -c "print(hex($port)[2:].upper().zfill(4))")

    # get the inode of the socket
    local inodes=$(awk '$4 == "01" && $3 == "'$hex_addr:$hex_port'" {print $10}' /proc/net/tcp)
    [ -z "$inodes" ] && { echo 'Cannot lookup the socket(s)' 2>&1; return 1; }

    # get file descriptors
    for inode in $inodes; do
        # get inode's file descriptor details
        local fdinfo=( $(find /proc/[0-9]*/fd -lname "socket:\[$inode\]" -printf "%p %T@") )
        [ -z "$fdinfo" ] && { echo 'Cannot find file descriptor' 2>&1; return 1; }

        # extract pid
        local fdpath=${fdinfo[0]}
        local pid=${fdpath#/proc/}
        pid=${pid%%/*}

        # extract timestamp
        local timestamp=${fdinfo[1]}

        # compute the time difference
        LANG=C printf 'PID: %s; Age: %s (%.2fs ago)\n' "$pid" "$(date -d @$timestamp)" $(bc <<<"$(date +%s.%N) - $timestamp")
    done
}

Примітки:

  • потреби bc, netstat(надається net-toolsна RHEL> = 7 і аналогічних систем)
  • потрібно запускати як root
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.