Advertisement
m4ly

Sockets uptime

Aug 16th, 2015
256
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 7.11 KB | None | 0 0
  1. #!/bin/bash
  2.  
  3. # Sockets uptime (SUP)
  4. # Author: Dawid Mocek ([email protected])
  5. # Require: python, ipv4 only
  6.  
  7. # SUP must be run as ROOT
  8.  
  9. # SUP does not take any args from the user - you need to modify some variables in this script
  10. # SUP shows times when socket was accessed, modified, changed and remote_addr, local_addr, inode created by a runinng process
  11. # SUP example output:
  12. #[root@my scripts]# ./socket_uptime.sh
  13. #           Local addr. Remote addr. Last access Last modify Last change       inode
  14. #         0.0.0.0:6789   0.0.0.0:*         52m      17662m      17662m        9920
  15. #    10.202.30.12:9991   0.0.0.0:*         52m      17662m      17662m        8863
  16. #    10.202.30.12:9999   0.0.0.0:*         52m      17662m      17662m        9926
  17. #    10.202.30.12:8080   0.0.0.0:*         52m      17662m      17662m        8862
  18. #       0.0.0.0:60720   0.0.0.0:*         52m      17662m      17662m        9921
  19. #       0.0.0.0:52820   0.0.0.0:*         52m      17662m      17662m        9918
  20. #    10.202.32.12:4447   0.0.0.0:*         52m      17662m      17662m        9927
  21. #    10.202.32.12:8080  10.255.24.13:40186         52m      17662m      17662m     8652595
  22.  
  23.  
  24. # The only variables you need to modify here are:
  25. #       PID - __runinng__ processs id
  26. #       TCP_STATE - tcp state you wish or "ALL" of them. Read more: man netstat
  27. #       TIME_FORMAT
  28.  
  29.  
  30.  
  31. # Process pid
  32. PID="1104"
  33.  
  34. # Possible values for TCP_STATE are: TIME_WAIT CLOSE_WAIT FIN_WAIT ESTABLISHED SYN_RCVD(man netstat) or just  ALL
  35. TCP_STATE="ALL"
  36.  
  37. # Possible values for TIME_FORMAT are: DAYS HOURS MINUTES SECONDS
  38. TIME_FORMAT="HOURS"
  39.  
  40.  
  41. # Disable file expansion cos netstat outputs wildcards(*)
  42. set -f
  43.  
  44. LANG=C
  45. LC_NUMERIC=C
  46. LC_COLLATE=C
  47. NOW=""
  48.  
  49. # Converts port number (int) to hex
  50. function port_to_hex() {
  51.     p=${1:?Port number}
  52.     # wilcard(*) case: netstat -tlnuap eg.:
  53.     # [...]
  54.     # tcp        0      0 0.0.0.0:6789                0.0.0.0:*                   LISTEN      1104/java
  55.     if [ "$p" == "*" ]; then
  56.         printf '%04X' 0
  57.     else
  58.         printf '%04X' $p
  59.     fi
  60. }
  61.  
  62. # HEX IP addr is printed backwards using: cat /proc/net/tcp
  63. # so we need to pack it into raw socket struct to convert
  64. function ipv4_to_hex() {
  65.     ip=${1:?IPv4 address}
  66.     echo $(python -c "
  67. import socket, struct;
  68. print hex(struct.unpack('<L',socket.inet_aton('$ip'))[0])[2:].upper().zfill(8)")
  69. }
  70.  
  71. # Returns file descriptor inode
  72. function get_fd_inode {
  73.     remote_hex_ip=${1:?Remote hex IPv4}
  74.     remote_hex_port=${2:?Remote hex port number}
  75.     local_hex_ip=${3:?Local hex IPv4}
  76.     local_hex_port=${4:?Local hex port number}
  77.  
  78.     awk '$2 == "'$local_hex_ip:$local_hex_port'" && $3 == "'$remote_hex_ip:$remote_hex_port'" {print $10}' /proc/net/tcp
  79. }
  80.  
  81. # Returns last time access, last time read and last time modified
  82. # %(X|Y|Z) corresponds to EPOCH time
  83. function inode_time {
  84.     pid=${1:?PID}
  85.     inode=${2:?i-node}
  86.     find "/proc/$pid/fd" -lname "socket:\[$inode\]" -exec stat -c "%X %Y %Z"  {} \;
  87. }
  88.  
  89.  
  90. function change_output_time_format() {
  91.     tmp=${1:?Time}
  92.     if [ "$tmp" -eq "0" ]; then
  93.         echo "<1"
  94.     else
  95.         echo "$tmp"
  96.     fi
  97. }
  98.  
  99. function socket_uptime() {
  100.     pid=${1:?PID}
  101.     inode=${2:?i-node}
  102.     format=${3:?Format DAYS | HOURS | SECONDS}
  103.  
  104.     # Get time
  105.     time=$(inode_time $pid $inode)
  106.  
  107.     if [ "x$time" != "x" ]; then
  108.         tmp2=($time)
  109.  
  110.         # Defaults to: seconds
  111.         divisor=1
  112.         ext="s"
  113.         if [[ $format == "SECONDS" ]]; then
  114.             divisor=1
  115.             ext="s"
  116.         elif [[ $format == "MINUTES" ]]; then
  117.             divisor=60
  118.             ext="m"
  119.         elif [[ $format == "HOURS" ]]; then
  120.             divisor=3600
  121.             ext="h"
  122.         elif [[ $format == "DAYS" ]]; then
  123.             divisor=86400
  124.             ext="d"
  125.         fi
  126.  
  127.         last_access=$(( ($NOW - ${tmp2[0]}) / $divisor ))
  128.         last_modify=$(( ($NOW - ${tmp2[1]}) / $divisor ))
  129.         last_change=$(( ($NOW - ${tmp2[2]}) / $divisor ))
  130.  
  131.         last_access=$(change_output_time_format $last_access)
  132.         last_modify=$(change_output_time_format $last_modify)
  133.         last_change=$(change_output_time_format $last_change)
  134.  
  135.         echo "$last_access$ext $last_modify$ext $last_change$ext"
  136.     else
  137.         echo "N/A N/A N/A"
  138.     fi
  139. }
  140.  
  141.  
  142. # Main program #
  143.  
  144. # Hash array storing ip in hex format
  145. declare -A HEX_IP_CACHE
  146.  
  147. # Get current date in epoch format - it's a lot time faster than runing `date` command every function call in a loop in main_program
  148. NOW=$(date -d 'now' +%s)
  149.  
  150. HEADER=0
  151.  
  152. # Check if PID exists
  153. if [[ $(kill -s 0 $PID > /dev/null 2>&1) -eq "0" ]]; then
  154.  
  155.     # Set flag if user choose all tcp states
  156.     IS_ALL="false"
  157.     if [[ "$TCP_STATE" == "ALL" ]]; then
  158.         IS_ALL="true"
  159.     fi
  160.  
  161.     netstat -tulnap | awk -v is_all=$IS_ALL '{ if (is_all == "true" && $7 ~ /^'"$PID"'/) { print $4, $5; } else if ($6 == "'"$TCP_STATE"'" && $7 ~ /^'"$PID"'/) { print $4, $5; } }' | while read line; do
  162.         # To array
  163.         tmp=($line)
  164.  
  165.         local_addr=${tmp[0]}
  166.         remote_addr=${tmp[1]}
  167.  
  168.         # Replace ":" from netstat output
  169.         local_addr=("${local_addr/:/ }")
  170.         remote_addr=("${remote_addr/:/ }")
  171.  
  172.         # To array
  173.         local_addr=($local_addr)
  174.         remote_addr=($remote_addr)
  175.  
  176.         # Assign local ports and ipv4 numbers
  177.         local_ip=${local_addr[0]}
  178.         local_port=${local_addr[1]}
  179.  
  180.         # Assign remote ports and ipv4 numbers
  181.         remote_ip="${remote_addr[0]}"
  182.         remote_port="${remote_addr[1]}"
  183.  
  184.         # Convert port number to hex
  185.         local_hex_port=$(port_to_hex $local_port)
  186.         remote_hex_port=$(port_to_hex $remote_port)
  187.  
  188.         local_hex_ip=""
  189.         remote_hex_ip=""
  190.  
  191.  
  192.         # Convert ipv4 to hex or use cache(a lot time faster than coverting it again using python)
  193.         if  test "${HEX_IP_CACHE[$local_addr]+isset}"; then
  194.             local_hex_ip=${HEX_IP_CACHE[$local_ip]}
  195.         else
  196.             local_hex_ip=$(ipv4_to_hex $local_ip)
  197.             HEX_IP_CACHE[$local_ip]=$local_hex_ip
  198.         fi
  199.  
  200.         if  test "${HEX_IP_CACHE[$remote_addr]+isset}"; then
  201.             remote_hex_ip=${HEX_IP_CACHE[$remote_ip]}
  202.         else
  203.             remote_hex_ip=$(ipv4_to_hex $remote_ip)
  204.             HEX_IP_CACHE[$remote_ip]=$remote_hex_ip
  205.         fi
  206.  
  207.  
  208.  
  209.         # Get fd inode
  210.         inode=$(get_fd_inode $remote_hex_ip $remote_hex_port $local_hex_ip $local_hex_port)
  211.  
  212.         # Stats() this fd(socket)
  213.         sup=($(socket_uptime $PID $inode $TIME_FORMAT))
  214.         last_access=${sup[0]}
  215.         last_modify=${sup[1]}
  216.         last_change=${sup[2]}
  217.  
  218.         if [ $HEADER -eq 0 ]; then
  219.             printf "%22s %11s %11s %11s %11s %11s \n" "Local addr." "Remote addr." "Last access" "Last modify" "Last change" "inode"
  220.             HEADER=1
  221.         fi
  222.         local_addr="$local_ip:$local_port"
  223.         local_addr_size=${#local_addr}
  224.  
  225.         remote_addr="$remote_ip:$remote_port"
  226.         remote_addr_size=${#remote_addr}
  227.  
  228.         printf "%22s %11s %11s %11s %11s %11s \n" "$local_addr" "$remote_addr" "$last_access" "$last_modify" "$last_change" "$inode"
  229.     done
  230. fi
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement