By Brian Fitzgerald
Question
$ netstat -ntl | grep :1521 tcp6 0 0 :::1521 :::* LISTEN
Q: Does the netstat output shown here mean that the listener accepts only IPv6 connections?
A: No. By default, a Linux listener uses a dual stack socket.
Oracle listener trace
Here is an strace of the Oracle TNS listener socket binding.
32649 socket(AF_INET6, SOCK_STREAM, IPPROTO_IP) = 8
32649 setsockopt(8, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
32649 bind(8, {sa_family=AF_INET6, sin6_port=htons(1521), inet_pton(AF_INET6, "::", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0
32649 listen(8, 128)
In the bind call, notice that the socket address family is AF_INET6, and the IP address shown is “::”, meaning listen on all IP addresses on the local host. The netstat output looks like this:
[grid@ip-172-32-10-34 ~]$ netstat -ntl | grep :1521 tcp6 0 0 :::1521 :::* LISTEN
However, the listener will accept either IPv4 or IPv6. You can check this by testing IPv4 and IPv6 one at a time:
[ec2-user@ip-172-32-10-34 ~]$ nc -v -4 localhost 1521 < /dev/null Ncat: Version 7.50 ( https://nmap.org/ncat ) Ncat: Connected to 127.0.0.1:1521. Ncat: 0 bytes sent, 0 bytes received in 0.02 seconds. [ec2-user@ip-172-32-10-34 ~]$ nc -v -6 localhost 1521 < /dev/null Ncat: Version 7.50 ( https://nmap.org/ncat ) Ncat: Connected to ::1:1521. Ncat: 0 bytes sent, 0 bytes received in 0.03 seconds.
The connect calls were:
connect(3, {sa_family=AF_INET, sin_port=htons(1521), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
connect(3, {sa_family=AF_INET6, sin6_port=htons(1521), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = -1 EINPROGRESS (Operation now in progress)
You can compare the single-stack Oracle listener to other listeners that use separate sockets.
Linux sshd trace
By comparison, here is a trace of the sshd listener socket bindings.
1142 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
1142 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
1142 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
1142 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
1142 bind(3, {sa_family=AF_INET, sin_port=htons(22), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
1142 listen(3, 128) = 0
...
1142 socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP) = 4
1142 fcntl(4, F_GETFL) = 0x2 (flags O_RDWR)
1142 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0
1142 setsockopt(4, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
1142 setsockopt(4, SOL_IPV6, IPV6_V6ONLY, [1], 4) = 0
1142 bind(4, {sa_family=AF_INET6, sin6_port=htons(22), inet_pton(AF_INET6, "::", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0
1142 listen(4, 128)
Notice that for socket 3, the address family is AF_INET and the listener IP address is given as “0.0.0.0”, again meaning listen on all IP addresses. Examining socket 4 trace carefully, we see that before the bind call, socket option IPV6_V6ONLY is set. The netstat output looks like this:
[ec2-user@ip-172-32-10-34 ~]$ netstat -ntl | grep :22 tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN tcp6 0 0 :::22 :::* LISTEN
netstat displays one output line per socket. sshd has two listener sockets, one for IPv4 and a separate IPv6 socket.
IPv6-only listener
You can demonstrate an IPv6-only listener:
[ec2-user@ip-172-32-10-34 ~]$ nc -6 -l 6666
[ec2-user@ip-172-32-10-34 ~]$ netstat -ntl | grep :6666 tcp6 0 0 :::6666 :::* LISTEN
An IPv4 connection fails:
[ec2-user@ip-172-32-10-34 ~]$ nc -4 localhost 6666 Ncat: Connection refused.
The nc utility makes two connection attempts:
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(6666), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
...
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 4
fcntl(4, F_GETFL) = 0x2 (flags O_RDWR)
fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0
connect(4, {sa_family=AF_INET, sin_port=htons(6666), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
IPv4-only listener
Likewise, you can demonstrate an IPv4-only listener.
[ec2-user@ip-172-32-10-34 ~]$ nc -4 -l 4444
Netstat:
[ec2-user@ip-172-32-10-34 ~]$ netstat -ntl | grep :4444 tcp 0 0 0.0.0.0:4444 0.0.0.0:* LISTEN
IPv6 connection fails:
[ec2-user@ip-172-32-10-34 ~]$ nc -6 localhost 4444 Ncat: Connection refused.
The connect call:
connect(3, {sa_family=AF_INET6, sin6_port=htons(4444), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = -1 EINPROGRESS (Operation now in progress)
Conclusion
In the netstat output,
[ec2-user@ip-172-32-10-34 ~]$ netstat -ntl | grep :1521 tcp6 0 0 :::1521 :::* LISTEN
The lack of a line such as
tcp 0 0 0.0.0.0:1521 0.0.0.0:* LISTEN
does not mean that the listener does not accept IPv4 connections. It could mean that the listener implements a dual stack socket.
