]> git.proxmox.com Git - libhttp-daemon-perl.git/commitdiff
switch to IO::Socket::IP to add IPv6 support
authorFabian Grünbichler <f.gruenbichler@proxmox.com>
Wed, 27 Feb 2019 13:04:34 +0000 (14:04 +0100)
committerFabian Grünbichler <f.gruenbichler@proxmox.com>
Wed, 27 Feb 2019 13:23:43 +0000 (14:23 +0100)
by including patches shipped by Redhat/CentOS, as posted to upstream's
bug tracker.

Fixes: #667738
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
debian/changelog
debian/patches/0001-Add-IPv6-support.patch [new file with mode: 0644]
debian/patches/0002-Handle-undef-and-empty-LocalAddr.patch [new file with mode: 0644]
debian/patches/0003-Resolve-specific-socket-addresses-correctly.patch [new file with mode: 0644]
debian/patches/series [new file with mode: 0644]

index e182638259894702ae9536fa1d2dc052f4c17a07..0d11d539f08eaebad21e6c440c72539ecf96f370 100644 (file)
@@ -28,6 +28,9 @@ libhttp-daemon-perl (6.01-2) UNRELEASED; urgency=low
   * Update debhelper version support to 10 in d/compat & d/control
   * Add d/upstream/metadata
 
+  [ Fabian Grünbichler ]
+  * switch to IO::Socket::IP to add IPv6 support (Closes: #667738)
+
  -- Salvatore Bonaccorso <carnil@debian.org>  Sun, 06 Jan 2013 22:02:15 +0100
 
 libhttp-daemon-perl (6.01-1) unstable; urgency=low
diff --git a/debian/patches/0001-Add-IPv6-support.patch b/debian/patches/0001-Add-IPv6-support.patch
new file mode 100644 (file)
index 0000000..7e04c66
--- /dev/null
@@ -0,0 +1,303 @@
+From: =?utf-8?q?Petr_P=C3=ADsa=C5=99?= <ppisar@redhat.com>
+Date: Mon, 16 Jan 2017 16:13:08 +0100
+Subject: Add IPv6 support
+MIME-Version: 1.0
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+This patch ports the code from IO::Socket::INET to IO::Socket::IP in
+order to support IPv6.
+
+CPAN RT #91699, #71395.
+
+Signed-off-by: Petr Písař <ppisar@redhat.com>
+
+Bug: https://rt.cpan.org/Public/Bug/Display.html?id=91699
+---
+ README             | 24 ++++++++++++------------
+ Makefile.PL        |  1 +
+ lib/HTTP/Daemon.pm | 43 ++++++++++++++++++++++++++++---------------
+ t/chunked.t        | 34 +++++++++++++++++++++++-----------
+ 4 files changed, 64 insertions(+), 38 deletions(-)
+
+diff --git a/README b/README
+index be5a20a..ddb3b6e 100644
+--- a/README
++++ b/README
+@@ -24,12 +24,12 @@ SYNOPSIS
+ DESCRIPTION
+     Instances of the `HTTP::Daemon' class are HTTP/1.1 servers that listen
+     on a socket for incoming requests. The `HTTP::Daemon' is a subclass of
+-    `IO::Socket::INET', so you can perform socket operations directly on it
++    `IO::Socket::IP', so you can perform socket operations directly on it
+     too.
+     The accept() method will return when a connection from a client is
+     available. The returned value will be an `HTTP::Daemon::ClientConn'
+-    object which is another `IO::Socket::INET' subclass. Calling the
++    object which is another `IO::Socket::IP' subclass. Calling the
+     get_request() method on this object will read data from the client and
+     return an `HTTP::Request' object. The ClientConn object also provide
+     methods to send back various responses.
+@@ -40,13 +40,13 @@ DESCRIPTION
+     responses that conform to the HTTP/1.1 protocol.
+     The following methods of `HTTP::Daemon' are new (or enhanced) relative
+-    to the `IO::Socket::INET' base class:
++    to the `IO::Socket::IP' base class:
+     $d = HTTP::Daemon->new
+     $d = HTTP::Daemon->new( %opts )
+         The constructor method takes the same arguments as the
+-        `IO::Socket::INET' constructor, but unlike its base class it can
+-        also be called without any arguments. The daemon will then set up a
++        `IO::Socket::IP' constructor, but unlike its base class it can also
++        be called without any arguments. The daemon will then set up a
+         listen queue of 5 connections and allocate some random port number.
+         A server that wants to bind to some specific address on the standard
+@@ -57,8 +57,8 @@ DESCRIPTION
+                    LocalPort => 80,
+                );
+-        See IO::Socket::INET for a description of other arguments that can
+-        be used configure the daemon during construction.
++        See IO::Socket::IP for a description of other arguments that can be
++        used configure the daemon during construction.
+     $c = $d->accept
+     $c = $d->accept( $pkg )
+@@ -71,7 +71,7 @@ DESCRIPTION
+         The accept method will return `undef' if timeouts have been enabled
+         and no connection is made within the given time. The timeout()
+-        method is described in IO::Socket.
++        method is described in IO::Socket::IP.
+         In list context both the client object and the peer address will be
+         returned; see the description of the accept method IO::Socket for
+@@ -89,9 +89,9 @@ DESCRIPTION
+         The default is the string "libwww-perl-daemon/#.##" where "#.##" is
+         replaced with the version number of this module.
+-    The `HTTP::Daemon::ClientConn' is a `IO::Socket::INET' subclass.
+-    Instances of this class are returned by the accept() method of
+-    `HTTP::Daemon'. The following methods are provided:
++    The `HTTP::Daemon::ClientConn' is a `IO::Socket::IP' subclass. Instances
++    of this class are returned by the accept() method of `HTTP::Daemon'. The
++    following methods are provided:
+     $c->get_request
+     $c->get_request( $headers_only )
+@@ -227,7 +227,7 @@ DESCRIPTION
+ SEE ALSO
+     RFC 2616
+-    IO::Socket::INET, IO::Socket
++    IO::Socket::IP, IO::Socket
+ COPYRIGHT
+     Copyright 1996-2003, Gisle Aas
+diff --git a/Makefile.PL b/Makefile.PL
+index 09c7e86..85d5712 100644
+--- a/Makefile.PL
++++ b/Makefile.PL
+@@ -14,6 +14,7 @@ WriteMakefile(
+     PREREQ_PM => {
+       'Sys::Hostname' => 0,
+       'IO::Socket' => 0,
++      'IO::Socket::IP' => 0,
+       'HTTP::Request' => 6,
+       'HTTP::Response' => 6,
+       'HTTP::Status' => 6,
+diff --git a/lib/HTTP/Daemon.pm b/lib/HTTP/Daemon.pm
+index 27a7bf4..0e22b77 100644
+--- a/lib/HTTP/Daemon.pm
++++ b/lib/HTTP/Daemon.pm
+@@ -5,8 +5,10 @@ use vars qw($VERSION @ISA $PROTO $DEBUG);
+ $VERSION = "6.01";
+-use IO::Socket qw(AF_INET INADDR_ANY INADDR_LOOPBACK inet_ntoa);
+-@ISA=qw(IO::Socket::INET);
++use Socket qw(AF_INET AF_INET6 INADDR_ANY IN6ADDR_ANY
++          INADDR_LOOPBACK IN6ADDR_LOOPBACK inet_ntop sockaddr_family);
++use IO::Socket::IP;
++@ISA=qw(IO::Socket::IP);
+ $PROTO = "HTTP/1.1";
+@@ -40,15 +42,26 @@ sub url
+     my $self = shift;
+     my $url = $self->_default_scheme . "://";
+     my $addr = $self->sockaddr;
+-    if (!$addr || $addr eq INADDR_ANY) {
++    if (!$addr || $addr eq INADDR_ANY || $addr eq IN6ADDR_ANY) {
+       require Sys::Hostname;
+       $url .= lc Sys::Hostname::hostname();
+     }
+     elsif ($addr eq INADDR_LOOPBACK) {
+-      $url .= inet_ntoa($addr);
++      $url .= inet_ntop(AF_INET, $addr);
++    }
++    elsif ($addr eq IN6ADDR_LOOPBACK) {
++      $url .= '[' . inet_ntop(AF_INET6, $addr) . ']';
+     }
+     else {
+-      $url .= gethostbyaddr($addr, AF_INET) || inet_ntoa($addr);
++      my $host = $addr->sockhostname;
++        if (!defined $host) {
++          if (sockaddr_family($addr) eq AF_INET6) {
++              $host = '[' . inet_ntop(AF_INET6, $addr) . ']';
++          } else {
++              $host = inet_ntop(AF_INET6, $addr);
++          }
++      }
++      $url .= $host;
+     }
+     my $port = $self->sockport;
+     $url .= ":$port" if $port != $self->_default_port;
+@@ -77,8 +90,8 @@ sub product_tokens
+ package HTTP::Daemon::ClientConn;
+ use vars qw(@ISA $DEBUG);
+-use IO::Socket ();
+-@ISA=qw(IO::Socket::INET);
++use IO::Socket::IP ();
++@ISA=qw(IO::Socket::IP);
+ *DEBUG = \$HTTP::Daemon::DEBUG;
+ use HTTP::Request  ();
+@@ -645,12 +658,12 @@ HTTP::Daemon - a simple http server class
+ Instances of the C<HTTP::Daemon> class are HTTP/1.1 servers that
+ listen on a socket for incoming requests. The C<HTTP::Daemon> is a
+-subclass of C<IO::Socket::INET>, so you can perform socket operations
++subclass of C<IO::Socket::IP>, so you can perform socket operations
+ directly on it too.
+ The accept() method will return when a connection from a client is
+ available.  The returned value will be an C<HTTP::Daemon::ClientConn>
+-object which is another C<IO::Socket::INET> subclass.  Calling the
++object which is another C<IO::Socket::IP> subclass.  Calling the
+ get_request() method on this object will read data from the client and
+ return an C<HTTP::Request> object.  The ClientConn object also provide
+ methods to send back various responses.
+@@ -661,7 +674,7 @@ desirable.  Also note that the user is responsible for generating
+ responses that conform to the HTTP/1.1 protocol.
+ The following methods of C<HTTP::Daemon> are new (or enhanced) relative
+-to the C<IO::Socket::INET> base class:
++to the C<IO::Socket::IP> base class:
+ =over 4
+@@ -670,7 +683,7 @@ to the C<IO::Socket::INET> base class:
+ =item $d = HTTP::Daemon->new( %opts )
+ The constructor method takes the same arguments as the
+-C<IO::Socket::INET> constructor, but unlike its base class it can also
++C<IO::Socket::IP> constructor, but unlike its base class it can also
+ be called without any arguments.  The daemon will then set up a listen
+ queue of 5 connections and allocate some random port number.
+@@ -682,7 +695,7 @@ HTTP port will be constructed like this:
+            LocalPort => 80,
+        );
+-See L<IO::Socket::INET> for a description of other arguments that can
++See L<IO::Socket::IP> for a description of other arguments that can
+ be used configure the daemon during construction.
+ =item $c = $d->accept
+@@ -699,7 +712,7 @@ class a subclass of C<HTTP::Daemon::ClientConn>.
+ The accept method will return C<undef> if timeouts have been enabled
+ and no connection is made within the given time.  The timeout() method
+-is described in L<IO::Socket>.
++is described in L<IO::Socket::IP>.
+ In list context both the client object and the peer address will be
+ returned; see the description of the accept method L<IO::Socket> for
+@@ -721,7 +734,7 @@ replaced with the version number of this module.
+ =back
+-The C<HTTP::Daemon::ClientConn> is a C<IO::Socket::INET>
++The C<HTTP::Daemon::ClientConn> is a C<IO::Socket::IP>
+ subclass. Instances of this class are returned by the accept() method
+ of C<HTTP::Daemon>.  The following methods are provided:
+@@ -895,7 +908,7 @@ Return a reference to the corresponding C<HTTP::Daemon> object.
+ RFC 2616
+-L<IO::Socket::INET>, L<IO::Socket>
++L<IO::Socket::IP>, L<IO::Socket>
+ =head1 COPYRIGHT
+diff --git a/t/chunked.t b/t/chunked.t
+index e11799f..c274b11 100644
+--- a/t/chunked.t
++++ b/t/chunked.t
+@@ -95,18 +95,30 @@ my $can_fork = $Config{d_fork} ||
+ my $tests = @TESTS;
+ my $tport = 8333;
+-my $tsock = IO::Socket::INET->new(LocalAddr => '0.0.0.0',
+-                                  LocalPort => $tport,
+-                                  Listen    => 1,
+-                                  ReuseAddr => 1);
++my @addresses = (
++    { server => '::', client => '::1' },
++    { server => '0.0.0.0', client => '127.0.0.1' }
++);
++my $family;
++for my $id (0..$#addresses) {
++    my $tsock = IO::Socket::IP->new(LocalAddr => $addresses[$id]->{server},
++                                    LocalPort => $tport,
++                                    Listen    => 1,
++                                    ReuseAddr => 1);
++    if ($tsock) {
++        close $tsock;
++        $family = $id;
++        last;
++    }
++}
++
+ if (!$can_fork) {
+   plan skip_all => "This system cannot fork";
+ }
+-elsif (!$tsock) {
+-  plan skip_all => "Cannot listen on 0.0.0.0:$tport";
++elsif (!defined $family) {
++  plan skip_all => "Cannot listen on unspecifed address and port $tport";
+ }
+ else {
+-  close $tsock;
+   plan tests => $tests;
+ }
+@@ -132,9 +144,9 @@ if ($pid = fork) {
+       open my $fh, "| socket localhost $tport" or die;
+       print $fh $test;
+     }
+-    use IO::Socket::INET;
+-    my $sock = IO::Socket::INET->new(
+-                                     PeerAddr => "127.0.0.1",
++    use IO::Socket::IP;
++    my $sock = IO::Socket::IP->new(
++                                     PeerAddr => $addresses[$family]->{client},
+                                      PeerPort => $tport,
+                                     ) or die;
+     if (0) {
+@@ -158,7 +170,7 @@ if ($pid = fork) {
+ } else {
+   die "cannot fork: $!" unless defined $pid;
+   my $d = HTTP::Daemon->new(
+-                            LocalAddr => '0.0.0.0',
++                            LocalAddr => $addresses[$family]->{server},
+                             LocalPort => $tport,
+                             ReuseAddr => 1,
+                            ) or die;
diff --git a/debian/patches/0002-Handle-undef-and-empty-LocalAddr.patch b/debian/patches/0002-Handle-undef-and-empty-LocalAddr.patch
new file mode 100644 (file)
index 0000000..7af1f9b
--- /dev/null
@@ -0,0 +1,46 @@
+From: =?utf-8?q?Petr_P=C3=ADsa=C5=99?= <ppisar@redhat.com>
+Date: Mon, 18 Sep 2017 15:21:16 +0200
+Subject: Handle undef and empty LocalAddr
+MIME-Version: 1.0
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+IO::Socket::INET interprets undefined and empty string LocalAddr
+arguments as an unspecified address while IO::Socket::IP returns an
+error. This seems to be one of the differences between the two
+Socket implementations. Recent IO::Socket::IP (0.39) accepts undefined
+value, but still bail outs on an empty string.
+
+To improve compatibility, this patch adds a special handling for these
+two values to be accepted as an unspecified value. Though this should
+be corrected on IO::Socket:IP side probably.
+
+CPAN RT#91699
+CPAN RT#123069
+
+Signed-off-by: Petr Písař <ppisar@redhat.com>
+
+Bug: https://rt.cpan.org/Public/Bug/Display.html?id=91699
+---
+ lib/HTTP/Daemon.pm | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/lib/HTTP/Daemon.pm b/lib/HTTP/Daemon.pm
+index 0e22b77..1e9d48e 100644
+--- a/lib/HTTP/Daemon.pm
++++ b/lib/HTTP/Daemon.pm
+@@ -18,6 +18,14 @@ sub new
+     my($class, %args) = @_;
+     $args{Listen} ||= 5;
+     $args{Proto}  ||= 'tcp';
++    # Handle undefined or empty local address the same way as
++    # IO::Socket::INET -- use unspecified address
++    for my $key (qw(LocalAddr LocalHost)) {
++        if (exists $args{$key} &&
++            (!defined($args{$key}) || $args{$key} eq '')) {
++            delete $args{$key};
++        }
++    }
+     return $class->SUPER::new(%args);
+ }
diff --git a/debian/patches/0003-Resolve-specific-socket-addresses-correctly.patch b/debian/patches/0003-Resolve-specific-socket-addresses-correctly.patch
new file mode 100644 (file)
index 0000000..4833437
--- /dev/null
@@ -0,0 +1,53 @@
+From: =?utf-8?q?Petr_P=C3=ADsa=C5=99?= <ppisar@redhat.com>
+Date: Wed, 23 May 2018 17:31:42 +0200
+Subject: Resolve specific socket addresses correctly
+MIME-Version: 1.0
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+Previous code did not formatted specific (not 0.0.0.0 or ::)
+correctly:
+
+$ perl -MHTTP::Daemon -e '$d=HTTP::Daemon->new(LocalAddr=>q{127.0.0.2}) or die; print $d->url, qq{\n}'
+Can't call method "sockhostname" without a package or object reference at /usr/share/perl5/vendor_perl/HTTP/Daemon.pm line 64.
+
+This patch also fixes formatting numerical IPv6 addresses. It seems
+that IO::Socket::IP::sockhostname() formats unresolvable addresses too.
+
+Signed-off-by: Petr Písař <ppisar@redhat.com>
+
+Bug: https://rt.cpan.org/Public/Bug/Display.html?id=125242
+---
+ lib/HTTP/Daemon.pm | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+diff --git a/lib/HTTP/Daemon.pm b/lib/HTTP/Daemon.pm
+index 1e9d48e..216c73f 100644
+--- a/lib/HTTP/Daemon.pm
++++ b/lib/HTTP/Daemon.pm
+@@ -61,12 +61,23 @@ sub url
+       $url .= '[' . inet_ntop(AF_INET6, $addr) . ']';
+     }
+     else {
+-      my $host = $addr->sockhostname;
++      my $host = $self->sockhostname;
++      # sockhostname() seems to return a stringified IP address if not
++      # resolvable, then quote it for a port separator and an IPv6 zone separator.
++      # But be paranoid for a case when it already contains a bracket.
++      if (defined $host and $host =~ /:/) {
++          if ($host =~ /[\[\]]/) {
++              $host = undef;
++          } else {
++              $host =~ s/%/%25/g;
++              $host  = '[' . $host . ']';
++          }
++      }
+         if (!defined $host) {
+           if (sockaddr_family($addr) eq AF_INET6) {
+               $host = '[' . inet_ntop(AF_INET6, $addr) . ']';
+           } else {
+-              $host = inet_ntop(AF_INET6, $addr);
++              $host = inet_ntop(AF_INET, $addr);
+           }
+       }
+       $url .= $host;
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644 (file)
index 0000000..989b1e2
--- /dev/null
@@ -0,0 +1,3 @@
+0001-Add-IPv6-support.patch
+0002-Handle-undef-and-empty-LocalAddr.patch
+0003-Resolve-specific-socket-addresses-correctly.patch