Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IO::Socket::INET does not bind UDP sockets to ephemeral ports #11809

Open
p5pRT opened this issue Dec 16, 2011 · 9 comments
Open

IO::Socket::INET does not bind UDP sockets to ephemeral ports #11809

p5pRT opened this issue Dec 16, 2011 · 9 comments

Comments

@p5pRT
Copy link

p5pRT commented Dec 16, 2011

Migrated from rt.perl.org#106370 (status was 'open')

Searchable as RT106370$

@p5pRT
Copy link
Author

p5pRT commented Dec 16, 2011

From imran.patel@gmail.com

Created by imran.patel@gmail.com

Perls' IO​::Socket​::INET core library module has a bug which prevents creating a
socket that is bound to an OS-selected ephemeral port.

The standard way to bind to an available port is to set the port to zero when
calling bind(). With IO​::Socket​::INET, you'd do something like​:

my @​socket_args = (
  Proto => 'udp',
  LocalPort => 0,
);
my $sock = IO​::Socket​::INET->new( @​socket_args ) or die "socket​: $@​";

Except this doesn't work. Here's the offending bit from IO/Socket/INET.pm​:

if($lport || ($laddr ne INADDR_ANY) || exists $arg->{Listen}) {
  $sock->bind($lport || 0, $laddr) or
  return _error($sock, $!, "$!");
}

In reality, $lport is undef instead of zero because of another bug, but it
doesn't matter either way. I verified that this if branch is not taken by using
the debugger.

The same thing is true for TCP. But since the Listen option is usually supplied
for TCP, it makes the if expression evaluate to true and the bind() happens by
accident.

I think the best workaround is to use the core Socket.pm module directly.

Perl Info

Flags:
    category=library
    severity=low

This perlbug was built using Perl v5.8.8 in the Red Hat build system.
It is being executed now by Perl v5.8.8 - Thu Jul  2 05:48:14 EDT 2009.

Site configuration information for perl v5.8.8:

Configured by Red Hat, Inc. at Thu Jul  2 05:48:14 EDT 2009.

Summary of my perl5 (revision 5 version 8 subversion 8) configuration:
  Platform:
    osname=linux, osvers=2.6.18-128.1.10.el5, archname=i386-linux-thread-multi
    uname='linux ls20-bc1-14.build.redhat.com 2.6.18-128.1.10.el5 #1 smp wed apr 29 13:53:08 edt 2009 i686 athlon i386 gnulinux '
    config_args='-des -Doptimize=-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=generic -fasynchronous-unwind-tables -Dversion=5.8.8 -Dmyhostname=localhost -Dperladmin=root@localhost -Dcc=gcc -Dcf_by=Red Hat, Inc. -Dinstallprefix=/usr -Dprefix=/usr -Darchname=i386-linux-thread-multi -Dvendorprefix=/usr -Dsiteprefix=/usr -Duseshrplib -Dusethreads -Duseithreads -Duselargefiles -Dd_dosuid -Dd_semctl_semun -Di_db -Ui_ndbm -Di_gdbm -Di_shadow -Di_syslog -Dman3ext=3pm -Duseperlio -Dinstallusrbinperl=n -Ubincompat5005 -Uversiononly -Dpager=/usr/bin/less -isr -Dd_gethostent_r_proto -Ud_endhostent_r_proto -Ud_sethostent_r_proto -Ud_endprotoent_r_proto -Ud_setprotoent_r_proto -Ud_endservent_r_proto -Ud_setservent_r_proto -Dinc_version_list=5.8.7 5.8.6 5.8.5 -Dscriptdir=/usr/bin'
    hint=recommended, useposix=true, d_sigaction=define
    usethreads=define use5005threads=undef useithreads=define usemultiplicity=define
    useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
    use64bitint=undef use64bitall=undef uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='gcc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -fno-strict-aliasing -pipe -Wdeclaration-after-statement -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm',
    optimize='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=generic -fasynchronous-unwind-tables',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -fno-strict-aliasing -pipe -Wdeclaration-after-statement -I/usr/local/include -I/usr/include/gdbm'
    ccversion='', gccversion='4.1.2 20080704 (Red Hat 4.1.2-44)', gccosandvers=''
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=4, prototype=define
  Linker and Libraries:
    ld='gcc', ldflags =' -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib
    libs=-lresolv -lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lpthread -lc
    perllibs=-lresolv -lnsl -ldl -lm -lcrypt -lutil -lpthread -lc
    libc=/lib/libc-2.5.so, so=so, useshrplib=true, libperl=libperl.so
    gnulibc_version='2.5'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E -Wl,-rpath,/usr/lib/perl5/5.8.8/i386-linux-thread-multi/CORE'
    cccdlflags='-fPIC', lddlflags='-shared -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=generic -fasynchronous-unwind-tables -L/usr/local/lib'

Locally applied patches:
    


@INC for perl v5.8.8:
    /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi
    /usr/lib/perl5/site_perl/5.8.8
    /usr/lib/perl5/site_perl/5.8.5
    /usr/lib/perl5/site_perl
    /usr/lib/perl5/vendor_perl/5.8.8/i386-linux-thread-multi
    /usr/lib/perl5/vendor_perl/5.8.8
    /usr/lib/perl5/vendor_perl/5.8.5
    /usr/lib/perl5/vendor_perl
    /usr/lib/perl5/5.8.8/i386-linux-thread-multi
    /usr/lib/perl5/5.8.8
    .


Environment for perl v5.8.8:
    HOME=/home/imranp
    LANG=en_US.UTF-8
    LANGUAGE (unset)
    LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib:/usr/lib/xorg:/usr/lib/xorg
    LOGDIR (unset)
    PATH=/usr/local/bin:/home/imranp/bin:/home/imranp/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/sbin:/usr/X11R6/bin:/usr/X11/bin:/usr/kerberos/bin
    PERL_BADLANG (unset)
    SHELL=/bin/zsh

@p5pRT
Copy link
Author

p5pRT commented Jan 7, 2012

From @jkeenan

On Thu Dec 15 16​:15​:45 2011, imran.patel@​gmail.com wrote​:

This is a bug report for perl from imran.patel@​gmail.com,
generated with the help of perlbug 1.35 running under perl v5.8.8.

Perls' IO​::Socket​::INET core library module has a bug which prevents
creating a
socket that is bound to an OS-selected ephemeral port.

The standard way to bind to an available port is to set the port to
zero when
calling bind(). With IO​::Socket​::INET, you'd do something like​:

my @​socket_args = (
Proto => 'udp',
LocalPort => 0,
);
my $sock = IO​::Socket​::INET->new( @​socket_args ) or die "socket​: $@​";

Except this doesn't work.

Can you be a bit more explicit as to what doesn't work?

Also, can you try this on a currently supported version of Perl (5.12 or
5.14)?

Here's the offending bit from
IO/Socket/INET.pm​:

if($lport || ($laddr ne INADDR_ANY) || exists $arg->{Listen}) {
$sock->bind($lport || 0, $laddr) or
return _error($sock, $!, "$!");
}

In reality, $lport is undef instead of zero because of another bug,
but it
doesn't matter either way. I verified that this if branch is not taken
by using
the debugger.

The same thing is true for TCP. But since the Listen option is usually
supplied
for TCP, it makes the if expression evaluate to true and the bind()
happens by
accident.

I think the best workaround is to use the core Socket.pm module
directly.

Thank you very much.
Jim Keenan

@p5pRT
Copy link
Author

p5pRT commented Jan 7, 2012

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Jan 7, 2012

From @ikegami

On Fri, Jan 6, 2012 at 7​:12 PM, James E Keenan via RT <
perlbug-followup@​perl.org> wrote​:

On Thu Dec 15 16​:15​:45 2011, imran.patel@​gmail.com wrote​:

This is a bug report for perl from imran.patel@​gmail.com,
generated with the help of perlbug 1.35 running under perl v5.8.8.

Perls' IO​::Socket​::INET core library module has a bug which prevents
creating a
socket that is bound to an OS-selected ephemeral port.

The standard way to bind to an available port is to set the port to
zero when
calling bind(). With IO​::Socket​::INET, you'd do something like​:

my @​socket_args = (
Proto => 'udp',
LocalPort => 0,
);
my $sock = IO​::Socket​::INET-&gt;new( @​socket_args ) or die "socket​: $@​";

Except this doesn't work.

Can you be a bit more explicit as to what doesn't work?

He wants bind() to be called, and it isn't. So the real question is​: Why
does he want bind() to be called?

Maybe one can't query the socket to find out which port it's bound to until
bind() is called or a connection is established? That would be a problem
for server sockets (which would explain why bind() is explicitly called
when Listen is provided).

Also, can you try this on a currently supported version of Perl (5.12 or

5.14)?

The statement in question is still present unchanged in the latest
distribution of IO (1.25).

- Eric

@p5pRT
Copy link
Author

p5pRT commented Jan 8, 2012

From imran.patel@gmail.com

my @​socket_args = (
    Proto => 'udp',
    LocalPort => 0,
);
my $sock = IO​::Socket​::INET-&gt;new( @​socket_args ) or die "socket​: $@​";

Except this doesn't work.

Can you be a bit more explicit as to what doesn't work?
The UDP socket won't bind to an ephemeral port.

Also, can you try this on a currently supported version of Perl (5.12 or
5.14)?
Ok, will do.

Imran

@p5pRT
Copy link
Author

p5pRT commented Mar 24, 2012

From @jkeenan

On Sun Jan 08 14​:57​:13 2012, imran.patel@​gmail.com wrote​:

my @​socket_args = (
� � Proto => 'udp',
� � LocalPort => 0,
);
my $sock = IO​::Socket​::INET-&gt;new( @​socket_args ) or die "socket​: $@​";

Except this doesn't work.

Can you be a bit more explicit as to what doesn't work?
The UDP socket won't bind to an ephemeral port.

Also, can you try this on a currently supported version of Perl (5.12 or
5.14)?
Ok, will do.

Have you had any opportunity to try this on a supported version of Perl?

Thank you very much.
Jim Keenan

@p5pRT
Copy link
Author

p5pRT commented Mar 24, 2012

From imran.patel@gmail.com

No I haven't had access to anything more modern than 5.8.8. Do you want me
to provide a test case?

Imran

On Fri, Mar 23, 2012 at 6​:29 PM, James E Keenan via RT <
perlbug-followup@​perl.org> wrote​:

On Sun Jan 08 14​:57​:13 2012, imran.patel@​gmail.com wrote​:

my @​socket_args = (
� � Proto => 'udp',
� � LocalPort => 0,
);
my $sock = IO​::Socket​::INET-&gt;new( @​socket_args ) or die "socket​: $@​";

Except this doesn't work.

Can you be a bit more explicit as to what doesn't work?
The UDP socket won't bind to an ephemeral port.

Also, can you try this on a currently supported version of Perl (5.12
or
5.14)?
Ok, will do.

Have you had any opportunity to try this on a supported version of Perl?

Thank you very much.
Jim Keenan

@richardleach
Copy link
Contributor

This behaviour is unchanged in the version of IO::Socket::INET bundled with v5.28.1.

However, IO::Socket::IP exhibits the behaviour that the op wanted.

use IO::Socket::IP;
my @socket_args = (
  Proto => 'udp',
  LocalPort => 0,
);
my $sock = IO::Socket::IP->new( @socket_args ) or die "socket​: $@​";
print $sock->sockport."\n";

e.g.

root@debian:~/PerlExperiments# perl socky.pl
48185
root@debian:~/PerlExperiments# perl socky.pl
33403
root@debian:~/PerlExperiments# perl socky.pl
58575
root@debian:~/PerlExperiments# perl socky.pl
35671

Is there therefore still a perceived need to keep this ticket open with the intention of changing the longstanding behaviour of IO::Socket::INET?

@xsawyerx
Copy link
Member

IO::Socket::IP is available with core, so that does give a good way out without jumping to CPAN. But that doesn't mean we should fix this. Can the same approach that IO::Socket::IP takes be used for this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants