Unix sockets

From Christoph's Personal Wiki
Revision as of 22:09, 20 January 2022 by Christoph (Talk | contribs) (Socket status)

Jump to: navigation, search

Socket status

The kernel exports information about open network sockets. The relevant /proc/net/ files for IPv4 are: tcp, udp, and raw. All three files have identical syntax. The first line provides labels for each of the columns in the output. Each following line represents one open socket. Results from $(cat /proc/net/tcp) are shown here.

The data presented in each output column is:

sl 
The number of the line in the output listing.
local_address 
The local IP address and port number for the socket. The IP address is displayed as a little-endian four-byte hexadecimal number; that is, the least significant byte is listed first, so one needs to reverse the order of the bytes to convert it to an IP address. The port number is a simple two-byte hexadecimal number.
rem_address 
The remote IP address and port number for the socket. Encoding is the same as for the local_address.
st 
The socket status.
tx_queue / rx_queue 
The size of the transmit and receive queues.
tr / tm->when : The <code>tr field indicates whether a timer is active for this socket. A value of zero indicates the timer is not active. The tm->when field indicates the time remaining (in jiffies) before timeout occurs.
retrnsmt 
Unused.
uid 
The ID of the user that owns the socket. This is the same ID found in the /etc/passwd file.
time-out 
Unused.
inode 
A cryptic-looking number that identifies the socket to the Linux virtual filesystem.

IP addresses in /proc/net/

In the files offered by the /proc/net/ directory, IP addresses are often represented as little-endian four-byte hexadecimal numbers. These are easy to convert into the more usual dotted-decimal notation.

For example, to convert the remote address and port of line 16 of the /proc/net/tcp output shown in this column, one would do the following:

  1. Take the rem_address field:
    0100007F:0017
  2. Reverse the ordering of the bytes in the IP address part:
    7F000001:0017
  3. Separate the bytes of the address for readability:
    7F 00 00 01 : 0017
  4. Perform a simple hexadecimal-to-decimal conversion on each:
    127 0 0 1 : 23

It is a telnet connection to localhost. Simple enough.

  • Get a list of local IP addresses and ports listening via UDP:
$ netstat -planu | awk '/^udp / {print $4}'
  • Get the same info via the /proc filesystem:
$ for h in $(awk 'NR>1{print $2}' /proc/net/udp); do
    printf "%s:%d\n" $(printf "%d." $(echo ${h%:*}|sed 's/../0x& /g'|tr ' ' '\n'|tac)|sed 's/\.$/\n/') 0x${h#*:};
  done
$ ip_addr=$(echo 0F01A8C0 | sed -e 's/\(..\)\(..\)\(..\)\(..\)/echo $((0x\4)).$(echo $((0x\3))).$(echo $((0x\2))).$(echo $((0x\1)))/e')
  • Nice, but, let's do this in pure awk:
$ awk 'NR>1{split($2, addr, ":"); for(i=0;i<4;i++){
    printf("%d.",strtonum("0x" substr(addr[1],2*i+1,2)))}; print ":" strtonum("0x" addr[2]);}' /proc/net/udp
  • Almost. Just need to reverse the dotted decimals.
$ echo 0F01A8C0 | awk '{str = sprintf("0x%s", $0); ip = strtonum(str); \
    printf ("%d.%d.%d.%d\t",rshift(and(ip,0x000000ff),00),
                            rshift(and(ip,0x0000ff00),08),
                            rshift(and(ip,0x00ff0000),16),
                            rshift(and(ip,0xff000000),24))}'
  • Final, pure awk:
$ awk 'NR>1 {
       split($2, a, ":");
       patsplit(a[1],h,/.{2}/);
       for(i=4;i>0;i--){
         h[i]=strtonum("0x" h[i]);
       };
       printf("%d.%d.%d.%d:%d\n",h[4],h[3],h[2],h[1],strtonum("0x" a[2]));
     }' /proc/net/udp

External links