13

I was writing an utility to check /proc/net/tcp and tcp6 for active connections as its faster than parsing netstat output.

As I dont actually have ipv6 enabled I was mainly utilizing localhost as my reference point. Here is a copy of my /proc/net/tcp6

sl  local_address                         remote_address                        st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode
 0: 00000000000000000000000000000000:006F 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 19587 1 ffff880262630000 100 0 0 10 -1
 1: 00000000000000000000000000000000:0050 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 22011 1 ffff880261c887c0 100 0 0 10 -1
 2: 00000000000000000000000000000000:0016 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 21958 1 ffff880261c88000 100 0 0 10 -1
 3: 00000000000000000000000001000000:0277 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 28592 1 ffff88024eea0000 100 0 0 10 -1

Here is the matching netstat -6 -pant

Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp6       0      0 :::111                  :::*                    LISTEN      -                   
tcp6       0      0 :::80                   :::*                    LISTEN      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -                   
tcp6       0      0 ::1:631                 :::*                    LISTEN      -      

Entries 0-3 from tcp6 correspond with the ::'s (all ipv6), but entry 4 is supposedly the corresponding entry for ::1.

This is where I'm confused...

00000000000000000000000001000000 => 0000:0000:0000:0000:0000:0000:0100:0000 => ::100:0

When I run ::1 through some code to generate the full hex representation I get:

import binascii
import socket
print binascii.hexlify(socket.inet_pton(socket.AF_INET6, '::1'))
00000000000000000000000000000001

I can't programatically line these two values up, because they don't match (obviously). Why don't they match? Why does the kernel think ::100:0 is ::1?

gregswift
  • 265
  • 2
  • 8

3 Answers3

11

This is due to counterintuitive byte order in /proc/net/tcp6. The address is handled as four words consisting of four bytes each. In each of those four words the four bytes are written in reverse order.

2001:0db8       :: 0123:4567:89ab:cdef would thus come out as:
B80D 0120 00000000 6745 2301 EFCD AB89 (with spaces inserted for clarity).

This is probably due to endianness differences. Most PCs these days use IA32 or AMD64 which are using the opposite endianness from what IP was designed with. I don't have any other systems to test with to figure out if you can rely on /proc/net/tcp6 always looking like that. But I verified that it is the case on both IA32 and AMD64 architectures.

gregswift
  • 265
  • 2
  • 8
kasperd
  • 29,894
  • 16
  • 72
  • 122
  • Good answer but it might be better to provide more clarification. Your second sentence isn't quite as clear as it could be, i think the only reason it made sense was that someone else had just explained it to me differently. – gregswift May 01 '14 at 21:43
  • @gregswift since the OP never took action, maybe you could edit this yourself? This is a good answer to a good question and this bit of information would be valuable IMO. – André Chalella Jun 09 '15 at 12:14
  • @kasperd did edit it yesterday. I just reordered the example and added some formatting to hopefully provide any additional context – gregswift Jun 10 '15 at 15:19
3

Found this perl module intended for parsing /proc/net/tcp http://search.cpan.org/~salva/Linux-Proc-Net-TCP-0.05/lib/Linux/Proc/Net/TCP.pm It quotes the kernel documentation as shown below.

This document describes the interfaces /proc/net/tcp and
/proc/net/tcp6.  Note that these interfaces are deprecated in favor
of tcp_diag.

These /proc interfaces provide information about currently active TCP
connections, and are implemented by tcp4_seq_show() in
net/ipv4/tcp_ipv4.c and tcp6_seq_show() in net/ipv6/tcp_ipv6.c,
respectively.

It will first list all listening TCP sockets, and next list all
established TCP connections. A typical entry of /proc/net/tcp would
look like this (split up into 3 parts because of the length of the
line):

46: 010310AC:9C4C 030310AC:1770 01 
|      |      |      |      |   |--> connection state
|      |      |      |      |------> remote TCP port number
|      |      |      |-------------> remote IPv4 address
|      |      |--------------------> local TCP port number
|      |---------------------------> local IPv4 address
|----------------------------------> number of entry

00000150:00000000 01:00000019 00000000  
  |        |     |     |       |--> number of unrecovered RTO timeouts
  |        |     |     |----------> number of jiffies until timer expires
  |        |     |----------------> timer_active (see below)
  |        |----------------------> receive-queue
  |-------------------------------> transmit-queue

1000        0 54165785 4 cd1e6040 25 4 27 3 -1
|          |    |     |    |     |  | |  | |--> slow start size threshold, 
|          |    |     |    |     |  | |  |      or -1 if the threshold
|          |    |     |    |     |  | |  |      is >= 0xFFFF
|          |    |     |    |     |  | |  |----> sending congestion window
|          |    |     |    |     |  | |-------> (ack.quick<<1)|ack.pingpong
|          |    |     |    |     |  |---------> Predicted tick of soft clock
|          |    |     |    |     |              (delayed ACK control data)
|          |    |     |    |     |------------> retransmit timeout
|          |    |     |    |------------------> location of socket in memory
|          |    |     |-----------------------> socket reference count
|          |    |-----------------------------> inode
|          |----------------------------------> unanswered 0-window probes
|---------------------------------------------> uid

timer_active:
0  no timer is pending
1  retransmit-timer is pending
2  another timer (e.g. delayed ack or keepalive) is pending
3  this is a socket in TIME_WAIT state. Not all fields will contain 
 data (or even exist)
4  zero window probe timer is pending
Sanxiago
  • 39
  • 1
1

Im parsing /proc/net/tcp, also /tcp6,/udp6 on Android and this are my simple methods for conversion, in Java. Thanks kasperd for guide me to this solution.

/**B80D01200000000067452301EFCDAB89 -> 2001:0db8:0000:0000:0123:4567:89ab:cdef
 * */
public static String toRegularHexa(String hexaIP){
    StringBuilder result = new StringBuilder();
    for(int i=0;i<hexaIP.length();i=i+8){
        String word = hexaIP.substring(i,i+8);
        for (int j = word.length() - 1; j >= 0; j = j - 2) {
            result.append(word.substring(j - 1, j + 1));
            result.append((j==5)?":":"");//in the middle
        }
        result.append(":");
    }
    return result.substring(0,result.length()-1).toString();
}
/**0100A8C0 -> 192.168.0.1*/
public static String hexa2decIPv4 (String hexa) {
    StringBuilder result = new StringBuilder();
    //reverse Little to Big
    for (int i = hexa.length() - 1; i >= 0; i = i - 2) {
        String wtf = hexa.substring(i - 1, i + 1);
        result.append(Integer.parseInt(wtf, 16));
        result.append(".");
    }
    //remove last ".";
    return result.substring(0,result.length()-1).toString();
}
/**0000000000000000FFFF00008370E736 -> 0.0.0.0.0.0.0.0.0.0.255.255.54.231.112.131
  0100A8C0 -> 192.168.0.1
*/
public static String hexa2decIP (String hexa) {
    StringBuilder result = new StringBuilder();
    if(hexa.length()==32){
        for(int i=0;i<hexa.length();i=i+8){
            result.append(hexa2decIPv4(hexa.substring(i, i + 8)));
            result.append(".");
        }
    }else {
        if(hexa.length()!=8){return "0.0.0.0";}
        return hexa2decIPv4(hexa);
    }
    //remove last ".";
    return result.substring(0,result.length()-1).toString();
}

/**Simple hexa to dec, for ports 
 * 01BB -> 403
 * */
public static String hexa2decPort(String hexa) {
    StringBuilder result = new StringBuilder();
    result.append(Integer.parseInt(hexa, 16));
    return result.toString();
}
  • Does this answer the question? – Andrew Schulman May 16 '15 at 11:12
  • Should I delete it? Maybe it helps somebody who will be doing ipv6 parsing in future or somebody can get better understanding looking at real code. – Jan Tancibok May 16 '15 at 14:13
  • Nobody in the target audience is likely to be doing any programming in Java or any other language. – Michael Hampton May 16 '15 at 14:32
  • 1
    @MichaelHampton That's an exaggeration. There are people who do both system administration and development. I am one of them. (Though it has been 9 years since I last did Java.) – kasperd May 16 '15 at 20:40
  • @kasperd The point is, people aren't going to think to come to [sf] for code samples. That's the _other_ site. :) – Michael Hampton May 16 '15 at 20:47
  • @MichaelHampton True. The majority of questions on SF are not looking for answers involving code samples. Code samples are better suited for other SE sites such as stackoverflow or codereview. – kasperd May 16 '15 at 20:52
  • I'm torn. I was codifying this in python when I ran across this issue. I didn't ask it as a coding question because what i needed was to understand the difference, I could then handle the code. Because of this I don't think having a code answer is such a bad idea. However, I am inclined to think that most admins won't be working this issue with java. – gregswift May 17 '15 at 17:22
  • 1
    The code example is fine, leave it there. I was benefited. – sivann Nov 07 '15 at 11:29
  • This code example provided more clarity to me than the accepted answer's english explanation. English really becomes awkward and unclear when getting across such concepts. – Aman Singh Sep 23 '20 at 13:27