Re: kernel bug? listening on same port with IPv4 and IPv6

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 08/01/2023 16:14, Sjoerd Mullender wrote:
On 07/01/2023 01.38, Gordon Messmer wrote:
On 2023-01-06 06:17, Sjoerd Mullender wrote:
I have a program that is supposed to listen to the same port on both IPv4 and IPv6 sockets.  In the past, what it did, was basically: create new socket for IPv6, set option IPV6_V6ONLY to off, bind, listen; then create a new socket for IPv4, and also bind and listen.


Do you have sample code that demonstrates this process?

I'm confused by your description, because setting IPV6_V6ONLY to 0 with setsockopt should result in a socket that's bound to a port that accepts both IPv4 and IPv6 connections.  You shouldn't have ever been able to bind to that port in IPv4 in the past.

See the attached program.  Can be compiled without any extra options.

This program creates an IPv6 listening socket and tells it to also do IPv4.  Then it executes "netstat -anp | grep <pid>" to show what it did.
After that it tries to create an IPv4 listening socket for the port that was assigned in the first round and if successful again executes netstat.  If not successful, it will tell why.

When trying to bind to the wildcard address (specify "all" on the command line), the behavior is very different from when specifying "localhost".

Run as
$ ./a.out all 0
$ ./a.out localhost 0

and see the difference in behavior.  When using "all", the second round (IPv4) says that bind returns 1 unexpectedly, and the port is also unexpected.  When using "localhost", both IPv6 and IPv4 succeed and listen to the same port, but using two different sockets internally.

The behavior for the "all" case is different with the older kernel 6.0.15-300.fc37.x86_64 where bind will say "Address already in use".

I made a small change like this:

                        snprintf(command, sizeof(command), "netstat -tanp | grep ' %d/'", (int) getpid());
                        system(command);
                        snprintf(command, sizeof(command), "lsof -p %d", (int) getpid());
                        system(command);

and here:

                        default:
                                fprintf(stderr, "bind: unexpected return: %d\n", e);
                                perror("bind");
                                break;

I netstat line is not going to return false matches and lsof is a 2nd way to see what is bound.

THis works as you expected:

$ ./a.out localhost 0
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
tcp6       0      0 ::1:41787               :::*                    LISTEN      36315/./a.out        
COMMAND   PID  USER   FD      TYPE DEVICE SIZE/OFF    NODE NAME
a.out   36315 barry  cwd       DIR   0,37     2644  877499 /home/barry/Downloads
a.out   36315 barry  rtd       DIR   0,33      184     256 /
a.out   36315 barry  txt       REG   0,37    25968 3258908 /home/barry/Downloads/a.out
a.out   36315 barry  mem       REG   0,31          3258908 /home/barry/Downloads/a.out (path dev=0,37)
a.out   36315 barry  mem       REG   0,31          3693988 /usr/lib64/libc.so.6 (path dev=0,33)
a.out   36315 barry  mem       REG   0,31          3693985 /usr/lib64/ld-linux-x86-64.so.2 (path dev=0,33)
a.out   36315 barry    0u      CHR  136,5      0t0       8 /dev/pts/5
a.out   36315 barry    1u      CHR  136,5      0t0       8 /dev/pts/5
a.out   36315 barry    2u      CHR  136,5      0t0       8 /dev/pts/5
a.out   36315 barry    3u     IPv6 565528      0t0     TCP localhost:41787 (LISTEN)
a.out   36315 barry   66r  a_inode   0,14        0    3098 inotify
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
tcp        0      0 127.0.0.1:41787         0.0.0.0:*               LISTEN      36315/./a.out        
tcp6       0      0 ::1:41787               :::*                    LISTEN      36315/./a.out        
COMMAND   PID  USER   FD      TYPE DEVICE SIZE/OFF    NODE NAME
a.out   36315 barry  cwd       DIR   0,37     2644  877499 /home/barry/Downloads
a.out   36315 barry  rtd       DIR   0,33      184     256 /
a.out   36315 barry  txt       REG   0,37    25968 3258908 /home/barry/Downloads/a.out
a.out   36315 barry  mem       REG   0,31          3258908 /home/barry/Downloads/a.out (path dev=0,37)
a.out   36315 barry  mem       REG   0,31          3693988 /usr/lib64/libc.so.6 (path dev=0,33)
a.out   36315 barry  mem       REG   0,31          3693985 /usr/lib64/ld-linux-x86-64.so.2 (path dev=0,33)
a.out   36315 barry    0u      CHR  136,5      0t0       8 /dev/pts/5
a.out   36315 barry    1u      CHR  136,5      0t0       8 /dev/pts/5
a.out   36315 barry    2u      CHR  136,5      0t0       8 /dev/pts/5
a.out   36315 barry    3u     IPv6 565528      0t0     TCP localhost:41787 (LISTEN)
a.out   36315 barry    4u     IPv4 565531      0t0     TCP localhost:41787 (LISTEN)
a.out   36315 barry   66r  a_inode   0,14        0    3098 inotify

But this does not:

$ ./a.out all 0
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
tcp6       0      0 :::42243                :::*                    LISTEN      36396/./a.out        
COMMAND   PID  USER   FD      TYPE DEVICE SIZE/OFF    NODE NAME
a.out   36396 barry  cwd       DIR   0,37     2644  877499 /home/barry/Downloads
a.out   36396 barry  rtd       DIR   0,33      184     256 /
a.out   36396 barry  txt       REG   0,37    25968 3258908 /home/barry/Downloads/a.out
a.out   36396 barry  mem       REG   0,31          3258908 /home/barry/Downloads/a.out (path dev=0,37)
a.out   36396 barry  mem       REG   0,31          3693988 /usr/lib64/libc.so.6 (path dev=0,33)
a.out   36396 barry  mem       REG   0,31          3693985 /usr/lib64/ld-linux-x86-64.so.2 (path dev=0,33)
a.out   36396 barry    0u      CHR  136,5      0t0       8 /dev/pts/5
a.out   36396 barry    1u      CHR  136,5      0t0       8 /dev/pts/5
a.out   36396 barry    2u      CHR  136,5      0t0       8 /dev/pts/5
a.out   36396 barry    3u     IPv6 565577      0t0     TCP *:42243 (LISTEN)
a.out   36396 barry   66r  a_inode   0,14        0    3098 inotify
bind: unexpected return: 1
bind: Success
bound to unexpected port 0, expected 42243

And strace shows this for the bad bind:

socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 4
bind(4, {sa_family=AF_INET, sin_port=htons(43925), sin_addr=inet_addr("0.0.0.0")}, 16) = 1

That bind() return 1 looks like a bug, that is not a documented return value.

I think you are right and its a regression.
I'm running the code with kernel 6.0.16-300.fc37.x86_64

Barry



_______________________________________________
users mailing list -- users@xxxxxxxxxxxxxxxxxxxxxxx
To unsubscribe send an email to users-leave@xxxxxxxxxxxxxxxxxxxxxxx
Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: https://lists.fedoraproject.org/archives/list/users@xxxxxxxxxxxxxxxxxxxxxxx
Do not reply to spam, report it: https://pagure.io/fedora-infrastructure/new_issue
_______________________________________________
users mailing list -- users@xxxxxxxxxxxxxxxxxxxxxxx
To unsubscribe send an email to users-leave@xxxxxxxxxxxxxxxxxxxxxxx
Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: https://lists.fedoraproject.org/archives/list/users@xxxxxxxxxxxxxxxxxxxxxxx
Do not reply to spam, report it: https://pagure.io/fedora-infrastructure/new_issue
[Index of Archives]     [Older Fedora Users]     [Fedora Announce]     [Fedora Package Announce]     [EPEL Announce]     [EPEL Devel]     [Fedora Magazine]     [Fedora Summer Coding]     [Fedora Laptop]     [Fedora Cloud]     [Fedora Advisory Board]     [Fedora Education]     [Fedora Security]     [Fedora Scitech]     [Fedora Robotics]     [Fedora Infrastructure]     [Fedora Websites]     [Anaconda Devel]     [Fedora Devel Java]     [Fedora Desktop]     [Fedora Fonts]     [Fedora Marketing]     [Fedora Management Tools]     [Fedora Mentors]     [Fedora Package Review]     [Fedora R Devel]     [Fedora PHP Devel]     [Kickstart]     [Fedora Music]     [Fedora Packaging]     [Fedora SELinux]     [Fedora Legal]     [Fedora Kernel]     [Fedora OCaml]     [Coolkey]     [Virtualization Tools]     [ET Management Tools]     [Yum Users]     [Yosemite News]     [Gnome Users]     [KDE Users]     [Fedora Art]     [Fedora Docs]     [Fedora Sparc]     [Libvirt Users]     [Fedora ARM]

  Powered by Linux