--- Ident.pm.orig Sun Dec 14 08:08:02 2014 +++ Ident.pm Sat Sep 5 09:14:17 2015 @@ -2,6 +2,7 @@ use strict; use Socket; +use Socket::GetAddrInfo qw( getaddrinfo getnameinfo :constants ); use Fcntl; use FileHandle; use Carp; @@ -50,12 +51,6 @@ print STDDBG "Debugging turned to level $DEBUG\n"; } -# protocol number for tcp. -my $tcpproto = ( getprotobyname('tcp') )[2] || 6; - -# get identd port (default to 113). -my $identport = ( getservbyname( 'ident', 'tcp' ) )[2] || 113; - # what to use to make nonblocking sockets my $NONBLOCK = eval "&$Config{o_nonblock}"; @@ -146,49 +141,81 @@ my ( $class, $localaddr, $remoteaddr, $timeout ) = @_; my $self = {}; - print STDDBG "Net::Ident::newFromInAddr localaddr=", sub { inet_ntoa( $_[1] ) . ":$_[0]" } - ->( sockaddr_in($localaddr) ), ", remoteaddr=", sub { inet_ntoa( $_[1] ) . ":$_[0]" } - ->( sockaddr_in($remoteaddr) ), ", timeout=", defined $timeout ? $timeout : "", "\n" - if $DEBUG > 1; + if ($DEBUG > 1) { + my ($err, $lip, $lport, $rip, $rport); + ($err, $lip, $lport) = getnameinfo($localaddr, NI_NUMERICHOST|NI_NUMERICSERV, 0); + ($err, $rip, $rport) = getnameinfo($remoteaddr, NI_NUMERICHOST|NI_NUMERICSERV, 0); + printf STDDBG "Net::Ident::newFromInAddr localaddr=%s port %s remoteaddr=%s port %s defined timeout=%s\n", + $lip, $lport, $rip, $rport, defined $timeout ? $timeout : ""; + } eval { # unpack addresses and store in - my ( $localip, $remoteip ); - ( $self->{localport}, $localip ) = sockaddr_in($localaddr); - ( $self->{remoteport}, $remoteip ) = sockaddr_in($remoteaddr); + my($family, $err, $localip, $remoteip, @res); + $family = sockaddr_family($localaddr); + if ($family != sockaddr_family($remoteaddr)) { + die "= local and remote address family mismatch\n"; + } - # create a local binding port. We cannot bind to INADDR_ANY, it has - # to be bind (bound?) to the same IP address as the connection we're - # interested in on machines with multiple IP addresses - my $localbind = sockaddr_in( 0, $localip ); + ($err, $localip, $self->{localport}) = getnameinfo($localaddr, + NI_NUMERICHOST | NI_NUMERICSERV); + if ($err) { + die "= local getnameinfo failed: $err\n"; + } + ($err, $remoteip, $self->{remoteport}) = getnameinfo($remoteaddr, + NI_NUMERICHOST | NI_NUMERICSERV); + if ($err) { + die "= remote getnameinfo failed: $err\n"; + } + # store max time $self->{maxtime} = defined($timeout) ? time + $timeout : undef; - # create a remote connect point - my $identbind = sockaddr_in( $identport, $remoteip ); + # create a local binding port. + ($err, @res) = getaddrinfo($localip, 0, { + flags => AI_PASSIVE|AI_NUMERICHOST, + family => $family, + socktype => SOCK_STREAM + }); + if ($err) { + die "= local getaddrinfo failed: $err\n"; + } - # create a new FileHandle - $self->{fh} = new FileHandle; + for my $ai ( @res ) { + my $fh = new FileHandle; + socket($fh, $ai->{family}, $ai->{socktype}, $ai->{protocol}) + or next; - # create a stream socket. - socket( $self->{fh}, PF_INET, SOCK_STREAM, $tcpproto ) - or die "= socket failed: $!\n"; + # bind it to the same IP number as the local end of THESOCK + bind($fh, $ai->{addr}) + or next; - # bind it to the same IP number as the local end of THESOCK - bind( $self->{fh}, $localbind ) or die "= bind failed: $!\n"; + # make it a non-blocking socket + fcntl($fh, F_SETFL, $NONBLOCK) or die "= fcntl failed: $!\n"; - # make it a non-blocking socket - if ( $^O ne 'MSWin32' ) { - fcntl( $self->{fh}, F_SETFL, $NONBLOCK ) or die "= fcntl failed: $!\n"; + $self->{fh} = $fh; + last; } + if (!defined($self->{fh})) { + die "= unable to bind to $localaddr: $!\n"; + } - # connect it to the remote identd port, this can return EINPROGRESS. - # for some reason, reading $! twice doesn't work as it should - connect( $self->{fh}, $identbind ) - or $!{EINPROGRESS} - or die "= connect failed: $!\n"; - $self->{fh}->blocking(0) if $^O eq 'MSWin32'; + # create a remote connect point + ($err, @res) = getaddrinfo($remoteip, 'ident', { + flags => AI_NUMERICHOST, + family => $family, + socktype => SOCK_STREAM + }); + if ($err) { + die "= remote getaddrinfo failed: $err\n"; + } + + for my $ai ( @res ) { + connect($self->{fh}, $ai->{addr}) or $!{EINPROGRESS} or + die "= connect failed: $!\n"; + last; + } }; if ( $@ =~ /^= (.*)/ ) { @@ -504,10 +531,13 @@ sub lookupFromInAddr ($$;$) { my ( $localaddr, $remoteaddr, $timeout ) = @_; - print STDDBG "Net::Ident::lookupFromInAddr localaddr=", sub { inet_ntoa( $_[1] ) . ":$_[0]" } - ->( sockaddr_in($localaddr) ), ", remoteaddr=", sub { inet_ntoa( $_[1] ) . ":$_[0]" } - ->( sockaddr_in($remoteaddr) ), ", timeout=", defined $timeout ? $timeout : "", "\n" - if $DEBUG > 1; + if ($DEBUG > 1) { + my ($err, $lip, $lport, $rip, $rport); + ($err, $lip, $lport) = getnameinfo($localaddr, NI_NUMERICHOST|NI_NUMERICSERV); + ($err, $rip, $rport) = getnameinfo($remoteaddr, NI_NUMERICHOST|NI_NUMERICSERV); + printf STDDBG "Net::Ident::lookupFromInAddr localaddr=%s port %s, remoteaddr=%s port %s, timeout=%s\n", + $lip, $lport, $rip, $rport, defined $timeout ? $timeout : ""; + } Net::Ident->newFromInAddr( $localaddr, $remoteaddr, $timeout )->username; }