Here's the output of netsat -tupn on my Debian Jessie server:

Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0          ESTABLISHED 26277/smbd      
tcp        0      0          ESTABLISHED 1400/nginx: worker 
tcp        0      0          ESTABLISHED 23039/smbd      
tcp        0      0          ESTABLISHED 1400/nginx: worker 
tcp        0      0         ESTABLISHED 23701/smbd      
tcp        0      0         ESTABLISHED 21535/smbd      
tcp        0      0         ESTABLISHED 21534/smbd      
tcp        0      0          ESTABLISHED 21470/smbd      
tcp        0      0          ESTABLISHED 1400/nginx: worker 
tcp        0      0           ESTABLISHED -               
tcp        0      0          ESTABLISHED 23111/sshd: redacted
tcp6       0      0         ESTABLISHED 31307/java      
tcp6       0      0       ESTABLISHED 31307/java      
tcp6       0      0         ESTABLISHED 31307/java 

PID 31307 is the CrashPlan backup engine, Java version 1.7.0_45. The two non-RFC1918 IPv4 addresses are CrashPlan's servers and is my computer running the client.

Why do the last three connections show as tcp6 even though they're IPv4 addresses?


This is happening because by default, AF_INET6 sockets will actually work for both IPv4 and IPv6. See section 3.7 - Compatibility with IPv4 Nodes of RFC 3493 - Basic Socket Interface Extensions for IPv6

Here is a short example of code that can produce this sort of situation:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define TEST_PORT 5555

#define xstr(s) str(s)
#define str(x) #x

int main (int argc, char **argv)
    int v6server;
    int v4client;
    int rc;

    struct sockaddr_in6 s6addr = {
        .sin6_family = AF_INET6,
        .sin6_flowinfo = 0,
        .sin6_port = htons(TEST_PORT),
        .sin6_addr = in6addr_any

    struct sockaddr_in c4addr = {
        .sin_family = AF_INET,
        .sin_port = htons(TEST_PORT),
        .sin_addr = inet_addr("")

    // Open an IPv6 listener
    v6server = socket(AF_INET6, SOCK_STREAM, 0);
    if (v6server < 0) perror("socket()");

    rc = bind(v6server, (struct sockaddr *)&s6addr, sizeof(s6addr));
    if (rc != 0) perror("bind()");

    rc = listen(v6server, 0);
    if (rc != 0) perror("listen()");

    // Connect to the listener with an IPv4 socket
    v4client = socket(AF_INET, SOCK_STREAM, 0);
    if (v4client < 0) perror("socket()");

    rc = connect(v4client, (struct sockaddr *)&c4addr, sizeof(c4addr));
    if (rc != 0) perror("connect()");

    // inspect open sockets
    system("netstat -tan | grep " xstr(TEST_PORT));


The output on my Ubuntu machine is:

$ make v4v6
cc     v4v6.c   -o v4v6
$ ./v4v6 
tcp        0      0          ESTABLISHED
tcp6       0      0 :::5555                 :::*                    LISTEN     
tcp6       0      0         ESTABLISHED
  • The tcp6 LISTEN entry is for the socket listening on port 5555. Note that it is an AF_INET6 socket, so it will accept both IPv4 and IPv6 incoming connections.
  • The tcp ESTABLISHED entry is the result of connecting an AF_INET4 socket to the listener (active connection).
  • The tcp6 ESTABLISHED entry is for the passive connection spawned from the listener socket. It shows up as tcp6, since it is spawned from a tcp6 listener; however it represents a connection from an IPv4.

Its worth noting the following:

  • This behavior is special to AF_INET6 sockets. AF_INET (IPv4) sockets simply cannot and will not deal with anything IPv6.
  • This behavior may be overridden with the IPV6_V6ONLY socket option. Setting this option will cause the socket to only handle IPv6 and not allow anything IPv4.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.