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?

1 Answer 1


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.
  • 1
    Perfect answer!!
    – Vijay S B
    Nov 23, 2021 at 16:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .