Come determinare il tempo di attivazione della connessione socket su Linux


24

Posso verificare che la connessione sia attiva:

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

c'è un modo per verificare per quanto tempo questa connessione alla porta tcp è rimasta attiva (connessa)?

(No, non ho accesso ai registri delle app)

Risposte:


23

Puoi provare quanto segue:

  1. ottenere il PID (diciamo $pid) del programma aggiungendo l' -popzione a netstat.

  2. identificare la riga corretta nel /proc/net/tcpfile osservando i campi local_addresse / o rem_address(notare che sono in formato esadecimale, in particolare l'indirizzo IP è espresso in ordine di byte little-endian), inoltre assicurarsi che stsia 01(per ESTABLISHED);

  3. annotare il inodecampo associato (dire $inode);

  4. cercare quello inodetra i descrittori di file /proc/$pid/fde infine interrogare il tempo di accesso al file del collegamento simbolico:

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

Questo è un lavoro grugnito ... ecco uno script (stub) per automatizzare i punti di cui sopra, richiede l'indirizzo remoto e stampa il tempo di attività del socket in pochi secondi:

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")
}

(Modifica grazie ad Alex per le correzioni )

Esempio:

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

1
Questa ricetta mostra l'età del processo che ha creato la connessione TCP, non la connessione stessa.
miroslav

@myroslav sei sicuro? Funziona contro questa sceneggiatura Node.js .
cYrus

Avevo testato il tuo nuovo script con connessioni TCP aperte dal mio Firefox su Fedora 22 64-bit, e sicuramente non ricevo numeri "uptime". Quando si apre un nuovo socket, si ottengono tempi di attività "casuali", in genere il tempo del socket "più giovane" STABILITO.
miroslav,

@myroslav Sto usando Debian (3.16.0-4-amd64) qui, l'unica cosa che noto è che il tempo riportato è in realtà circa 3 secondi in ritardo rispetto alla creazione del socket. Forse ci sono alcuni comportamenti dipendenti dal sistema coinvolti ...
cYrus il

Per lo script, "$ suptime 192: 168: 120: 10 6379 Traceback (ultima chiamata più recente): file" <string> ", riga 1, in <module> socket.error: la stringa dell'indirizzo IP illegale passata all'indirizzo inet_aton non corrisponde "
Ondra Žižka,

4

Questa domanda mi è stata utile, ma ho scoperto che lsofinvece di netstatfarmi evitare tutte le cose HEX:

Per un processo ${APP}eseguito dall'utente ${USER}, quanto segue restituisce tutti i socket aperti all'indirizzo 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

Il lsofcontiene PIDanche, ma non sono sicuro di come ottenerlo e il numero del dispositivo.

Questo è stato testato su Amazon Linux.


3

Lo script di cYrus ha funzionato per me, ma ho dovuto risolverlo un po '(per sbarazzarmi di una "L" nell'indirizzo esadecimale e per rendere la porta un esagono di 4 cifre):

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

Che ne dite di:

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

Puoi anche personalizzare il comando "ps" per ottenere solo pid e ora di inizio con -o come:

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

Naturalmente questo presuppone che il socket sia stato avviato quando il processo era.


questo mostra per quanto tempo dura il processo che ha aperto il socket. Nel caso in cui vi sia un processo in esecuzione tutto il tempo e ci siano disconnessioni di rete, questi valori sarebbero molto diversi. +1 per sforzo
hidralisk il

1

Grazie per lo script mantenuto nella risposta di cYrus. Ho avuto problemi con la stampa di duplicati, probabilmente perché potrebbero esserci molte connessioni da diversi PID all'indirizzo fornito, quindi ecco la mia versione migliorata che stampa anche il PID su ogni linea di output:

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
}

Appunti:

  • esigenze bc, netstat(fornito da net-toolssu rhel> = 7 e sistemi simili)
  • deve essere eseguito come root
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.