Cara menentukan koneksi soket waktu di Linux

24

Saya dapat memverifikasi bahwa koneksi sudah habis:

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

apakah ada cara untuk memeriksa berapa lama koneksi port tcp ini sudah terhubung (terhubung)?

(Tidak, saya tidak memiliki akses ke log aplikasi)

hidralisk
sumber

Jawaban:

23

Anda dapat mencoba yang berikut ini:

  1. dapatkan PID (katakanlah $pid) dari program dengan menambahkan -popsi ke netstat.

  2. mengidentifikasi baris yang tepat dalam /proc/net/tcpfile dengan melihat bidang local_addressdan / atau rem_address(perhatikan bahwa mereka dalam format hex, khususnya alamat IP diekspresikan dalam urutan bit-endian byte), juga pastikan bahwa stis 01(untuk ESTABLISHED);

  3. perhatikan inodebidang terkait (katakanlah $inode);

  4. cari itu di inodeantara deskriptor file di /proc/$pid/fddan akhirnya kueri waktu akses file dari tautan simbolik:

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

Itu adalah pekerjaan kasar ... inilah sebuah skrip (rintisan) untuk mengotomatiskan poin-poin di atas, ia membutuhkan alamat jarak jauh dan mencetak uptime soket dalam hitungan detik:

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 terima kasih kepada Alex untuk perbaikannya )

Contoh:

$ suptime 93.184.216.34 80
Thu Dec 24 16:22:58 CET 2015 (46.12s ago)
cYrus
sumber
1
Resep ini menampilkan usia proses yang menciptakan koneksi TCP, bukan koneksi itu sendiri.
myroslav
@ myroslav kamu yakin? Ia bekerja melawan skrip Node.js ini .
cYrus
Saya telah menguji skrip baru Anda dengan koneksi TCP yang dibuka oleh Firefox saya di Fedora 22 64-bit, dan saya jelas tidak mendapatkan angka "uptime". Ketika soket baru terbuka, itu menjadi "acak" uptime, biasanya waktu soket ESTABLISHED "termuda".
myroslav
@ myroslav Saya menggunakan Debian (3.16.0-4-amd64) di sini, satu-satunya hal yang saya perhatikan adalah waktu yang dilaporkan sebenarnya terlambat sekitar 3 detik sehubungan dengan pembuatan soket. Mungkin ada beberapa perilaku yang tergantung pada sistem yang terlibat ...
cYrus
Untuk skrip, "$ suptime 192: 168: 120: 10 6379 Traceback (panggilan terakhir terakhir): File" <string> ", baris 1, di <module> socket.error: string alamat IP ilegal yang diteruskan ke inet_aton Address tidak tidak cocok "
Ondra Žižka
4

Pertanyaan-pertanyaan ini sangat membantu saya, tetapi saya menemukan menggunakan lsofdaripada netstatmembiarkan saya menghindari semua hal HEX:

Untuk proses yang ${APP}dijalankan oleh pengguna ${USER}, berikut ini mengembalikan semua soket terbuka ke alamat 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

The lsofberisi PIDjuga, tapi saya tidak yakin bagaimana untuk mendapatkannya dan jumlah perangkat.

Ini diuji di Amazon Linux.

Raúl Cuza
sumber
3

Script oleh cYrus bekerja untuk saya tetapi saya harus memperbaikinya sedikit (untuk menghilangkan "L" di alamat hex dan untuk membuat port hex 4 digit):

--- 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")
Alex Vazquez Fente
sumber
1

Bagaimana tentang:

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

Anda juga dapat menyesuaikan perintah "ps" untuk mendapatkan pid dan memulai waktu dengan -o seperti:

lsof -t -i @ 192.168.2.110 | xargs ps --tidak ada header -o'pid, mulai '-p

Tentu saja ini mengasumsikan soket sudah dimulai ketika proses itu.

Pete
sumber
ini menunjukkan berapa lama proses yang membuka soket sudah habis. Jika ada proses yang berjalan sepanjang waktu dan ada terputusnya jaringan, nilai-nilai ini akan sangat berbeda. +1 untuk upaya
hidralisk
1

Terima kasih atas skrip yang dijaga dalam jawaban cYrus. Saya mempunyai masalah dengan itu mencetak duplikat, mungkin karena mungkin ada banyak koneksi dari PID yang berbeda ke alamat yang disediakan, jadi inilah versi saya yang ditingkatkan yang juga mencetak PID pada setiap jalur keluaran:

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
}

Catatan:

  • kebutuhan bc, netstat(disediakan oleh net-toolspada rhel> = 7 dan sistem serupa)
  • perlu dijalankan sebagai root
fholzer
sumber