So ermitteln Sie die Socket-Betriebszeit unter Linux


24

Ich kann überprüfen, ob die Verbindung besteht:

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

Gibt es eine Möglichkeit zu überprüfen, wie lange diese TCP-Port-Verbindung aktiv war (verbunden)?

(Nein, ich habe keinen Zugriff auf App-Protokolle.)

Antworten:


23

Sie können Folgendes versuchen:

  1. Rufen Sie die PID $piddes Programms ab, indem Sie die -pOption zu hinzufügen netstat.

  2. die richtige Zeile in der Identifizierung /proc/net/tcpDatei , indem Sie auf den local_addressund / oder rem_addressFeldern (beachten Sie, dass sie in Hex - Format sind, insbesondere die IP - Adresse im Little-Endian - Byte - Reihenfolge ausgedrückt), auch sicherstellen, dass das stist 01(für ESTABLISHED);

  3. beachte das zugehörige inodeFeld (sprich $inode);

  4. Suchen Sie danach inodeunter den Dateideskriptoren in /proc/$pid/fdund fragen Sie schließlich die Dateizugriffszeit des symbolischen Links ab:

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

Das ist eine Grunzarbeit ... hier ist ein Skript (Stub), um die obigen Punkte zu automatisieren. Es erfordert die Remote-Adresse und gibt die Socket-Betriebszeit in Sekunden aus:

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

(Edit danke an Alex für die Korrekturen )

Beispiel:

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

1
In diesem Rezept wird das Alter des Prozesses angezeigt, der die TCP-Verbindung erstellt hat, nicht die Verbindung selbst.
Myroslav

@myroslav bist du sicher? Es funktioniert gegen dieses Node.js-Skript .
CYRUS

Ich habe Ihr neues Skript mit TCP-Verbindungen getestet, die von meinem Firefox auf Fedora 22 64-Bit geöffnet wurden, und ich erhalte definitiv keine "Verfügbarkeits" -Zahlen. Wenn ein neuer Socket geöffnet wird, wird die Betriebszeit "zufällig" festgelegt, normalerweise die Zeit des "jüngsten" eingerichteten Sockets.
Myroslav

@myroslav Ich verwende hier Debian (3.16.0-4-amd64), das einzige, was ich bemerke, ist, dass die angegebene Zeit in Bezug auf die Socket-Erstellung tatsächlich etwa 3 Sekunden zu spät ist. Vielleicht sind einige systemabhängige Verhaltensweisen involviert ...
cYrus

Für das Skript "$ suptime 192: 168: 120: 10 6379 Traceback (letzter Aufruf zuletzt): Datei" <string> ", Zeile 1, in <module> socket.error: Unzulässige IP-Adresszeichenfolge, die an inet_aton Address übergeben wird nicht übereinstimmen "
Ondra Žižka

4

Diese Frage war hilfreich für mich, aber ich habe festgestellt, dass ich das gesamte HEX-Zeug vermeiden muss , lsofanstatt es zu verwenden netstat:

Bei einem ${APP}vom Benutzer ausgeführten Prozess werden ${USER}alle offenen Sockets an die IP-Adresse $ {IP} zurückgegeben:

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

Das lsofenthält das PIDauch, aber ich bin mir nicht sicher, wie ich es bekomme und die Gerätenummer.

Dies wurde unter Amazon Linux getestet.


3

Das Skript von cYrus funktionierte für mich, aber ich musste es ein wenig korrigieren (um ein "L" in der Hex-Adresse loszuwerden und einen 4-stelligen Hex-Port zu erstellen):

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

Wie wäre es mit:

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

Sie können den Befehl "ps" auch so anpassen, dass nur pid abgerufen wird und die Zeit mit -o beginnt, z. B .:

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

Dies setzt natürlich voraus, dass der Socket gestartet wurde, als der Prozess ausgeführt wurde.


Dies zeigt, wie lange der Prozess, der den Socket geöffnet hat, noch läuft. Wenn ein Prozess ständig ausgeführt wird und die Verbindung zum Netzwerk unterbrochen wird, sind diese Werte sehr unterschiedlich. +1 für Mühe
Hidralisk

1

Danke für das Skript, das in der Antwort von cYrus enthalten ist. Ich hatte Probleme beim Drucken von Duplikaten, wahrscheinlich, weil es viele Verbindungen von verschiedenen PIDs zu der angegebenen Adresse gibt. Deshalb ist hier meine verbesserte Version, die auch die PID auf jeder Ausgabezeile druckt:

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
}

Anmerkungen:

  • Bedürfnisse bc, netstat(bereitgestellt von net-toolson rhel> = 7 und ähnlichen Systemen)
  • muss als root ausgeführt werden
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.