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フィールド(彼らは16進表記であることに注意してください、特に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

@myroslavよろしいですか?このNode.jsスクリプトに対して機能します
cYrus

Fedora 22 64ビット上のFirefoxで開かれたTCP接続を使用して新しいスクリプトをテストしましたが、「アップタイム」の数値がまったく得られません。新しいソケットが開くと、「ランダムな」稼働時間、通常は「最も若い」ESTABLISHEDソケットの時間になります。
myroslav

@myroslavここでDebian(3.16.0-4-amd64)を使用していますが、報告されている時間は、実際にはソケットの作成に関して約3秒遅れていることです。たぶん...関わるいくつかのシステムに依存行動がある
サイラス

スクリプトの場合、「$ suptime 192:168:120:10 6379 Traceback(most recent call last):File "<string>"、line 1 in <module> socket.error:無効なIPアドレス文字列がinet_atonアドレスに渡されます一致しない」
オンドラŽižka17年

4

この質問は私にとっては役に立ちましたが、すべてのHEXを避けるlsof代わりに使用することがわかりましたnetstat

${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によるスクリプトは私のために働いたが、私はそれを少し修正しなければならなかった(16進アドレスの「L」を取り除き、ポートを4桁の16進にする):

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

ノート:

  • ニーズbcnetstat(によって提供net-toolsRHEL> = 7と同様のシステム)
  • ルートとして実行する必要があります
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.