Skip to content

Commit

Permalink
Release 2.76: use SOCK_DGRAM for icmp under linux,
Browse files Browse the repository at this point in the history
when not root. also for icmpv6.
By Owen DeLong GH #33
  • Loading branch information
Reini Urban committed Dec 5, 2024
1 parent 95b8136 commit 52ff7bf
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 30 deletions.
4 changes: 4 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
CHANGES
-------
2.76 2024-12-05 13:12:08 rurban
Features
- use SOCK_DRGAM for ICMP under linux, which requires no root.
(Owen DeLong GH #33)
2.75 2022-09-01 12:44:03 rurban
Minor
- Modernized the synopsis (PR #31)
Expand Down
44 changes: 23 additions & 21 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ NAME
SYNOPSIS
use Net::Ping;

$p = Net::Ping->new();
my $p = Net::Ping->new();
print "$host is alive.\n" if $p->ping($host);
$p->close();

$p = Net::Ping->new("icmp");
my $p = Net::Ping->new("icmp");
$p->bind($my_addr); # Specify source interface of pings
foreach $host (@host_array)
foreach my $host (@host_array)
{
print "$host is ";
print "NOT " unless $p->ping($host, 2);
Expand All @@ -19,11 +19,11 @@ SYNOPSIS
}
$p->close();

$p = Net::Ping->new("icmpv6");
$ip = "[fd00:dead:beef::4e]";
my $p = Net::Ping->new("icmpv6");
my $ip = "[fd00:dead:beef::4e]";
print "$ip is alive.\n" if $p->ping($ip);

$p = Net::Ping->new("tcp", 2);
my $p = Net::Ping->new("tcp", 2);
# Try connecting to the www port instead of the echo port
$p->port_number(scalar(getservbyname("http", "tcp")));
while ($stop_time > time())
Expand All @@ -35,19 +35,19 @@ SYNOPSIS
undef($p);

# Like tcp protocol, but with many hosts
$p = Net::Ping->new("syn");
my $p = Net::Ping->new("syn");
$p->port_number(getservbyname("http", "tcp"));
foreach $host (@host_array) {
foreach my $host (@host_array) {
$p->ping($host);
}
while (($host,$rtt,$ip) = $p->ack) {
while (my ($host, $rtt, $ip) = $p->ack) {
print "HOST: $host [$ip] ACKed in $rtt seconds.\n";
}

# High precision syntax (requires Time::HiRes)
$p = Net::Ping->new();
my $p = Net::Ping->new();
$p->hires();
($ret, $duration, $ip) = $p->ping($host, 5.5);
my ($ret, $duration, $ip) = $p->ping($host, 5.5);
printf("$host [ip: $ip] is alive (packet return time: %.2f ms)\n",
1000 * $duration)
if $ret;
Expand Down Expand Up @@ -280,9 +280,9 @@ DESCRIPTION
tcp socket. It's only necessary to do this if you want to provide a
different timeout when creating the connection, or remove the
overhead of establishing the connection from the first ping. If you
don't call "open()", the connection is automatically opened the
first time "ping()" is called. This call simply does nothing if you
are using any protocol other than stream.
don't call open(), the connection is automatically opened the first
time ping() is called. This call simply does nothing if you are
using any protocol other than stream.

The $host argument can be omitted when specifying the "host" option
to new().
Expand All @@ -308,18 +308,20 @@ DESCRIPTION

$p->nack( $failed_ack_host );
The reason that "host $failed_ack_host" did not receive a valid ACK.
Useful to find out why when "ack($fail_ack_host)" returns a false
Useful to find out why when ack($fail_ack_host) returns a false
value.

$p->ack_unfork($host)
The variant called by "ack" with the "syn" protocol and $syn_forking
enabled.

$p->ping_icmp([$host, $timeout, $family])
The "ping" method used with the icmp protocol.
The "ping" method used with the icmp protocol. Under Linux under a
non-root account this uses now SOCK_DGRAM.

$p->ping_icmpv6([$host, $timeout, $family])
The "ping" method used with the icmpv6 protocol.
The "ping" method used with the icmpv6 protocol. Under Linux under a
non-root account this uses now SOCK_DGRAM.

$p->ping_stream([$host, $timeout, $family])
The "ping" method used with the stream protocol.
Expand Down Expand Up @@ -373,10 +375,10 @@ DESCRIPTION
function returns the value of the port that "ping" will connect to.

$p->mselect
A "select()" wrapper that compensates for platform peculiarities.
A select() wrapper that compensates for platform peculiarities.

$p->ntop
Platform abstraction over "inet_ntop()"
Platform abstraction over inet_ntop()

$p->checksum($msg)
Do a checksum on the message. Basically sum all of the short words
Expand All @@ -387,8 +389,8 @@ DESCRIPTION

pingecho($host [, $timeout]);
To provide backward compatibility with the previous version of
Net::Ping, a "pingecho()" subroutine is available with the same
functionality as before. "pingecho()" uses the tcp protocol. The
Net::Ping, a pingecho() subroutine is available with the same
functionality as before. pingecho() uses the tcp protocol. The
return values and parameters are the same as described for the
"ping" method. This subroutine is obsolete and may be removed in a
future version of Net::Ping.
Expand Down
33 changes: 25 additions & 8 deletions lib/Net/Ping.pm
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use Time::HiRes;
@ISA = qw(Exporter);
@EXPORT = qw(pingecho);
@EXPORT_OK = qw(wakeonlan);
$VERSION = "2.75";
$VERSION = "2.76";

# Globals

Expand Down Expand Up @@ -227,13 +227,18 @@ sub new
}
elsif ($self->{proto} eq "icmp")
{
croak("icmp ping requires root privilege") if !_isroot();
croak("icmp ping requires root privilege") if !_isroot() and $^O ne "linux";
$self->{proto_num} = eval { (getprotobyname('icmp'))[2] } ||
croak("Can't get icmp protocol by name");
$self->{pid} = $$ & 0xffff; # Save lower 16 bits of pid
$self->{fh} = FileHandle->new();
socket($self->{fh}, PF_INET, SOCK_RAW, $self->{proto_num}) ||
croak("icmp socket error - $!");
if ($^O eq "linux" and !_isroot()) {
socket($self->{fh}, PF_INET, SOCK_DGRAM, $self->{proto_num}) ||
croak("icmp socket error - $!");
} else {
socket($self->{fh}, PF_INET, SOCK_RAW, $self->{proto_num}) ||
croak("icmp socket error - $!");
}
$self->_setopts();
if ($self->{'ttl'}) {
setsockopt($self->{fh}, IPPROTO_IP, IP_TTL, pack("I*", $self->{'ttl'}))
Expand All @@ -250,8 +255,13 @@ sub new
croak("Can't get ipv6-icmp protocol by name"); # 58
$self->{pid} = $$ & 0xffff; # Save lower 16 bits of pid
$self->{fh} = FileHandle->new();
socket($self->{fh}, $AF_INET6, SOCK_RAW, $self->{proto_num}) ||
croak("icmp socket error - $!");
if ($^O eq 'linux' and !_isroot()) {
socket($self->{fh}, $AF_INET6, SOCK_DGRAM, $self->{proto_num}) ||
croak("icmp socket error - $!");
} else {
socket($self->{fh}, $AF_INET6, SOCK_RAW, $self->{proto_num}) ||
croak("icmp socket error - $!");
}
$self->_setopts();
if ($self->{'gateway'}) {
my $g = $self->{gateway};
Expand Down Expand Up @@ -715,8 +725,13 @@ sub ping_icmp
$timeout = $self->{timeout} if !defined $timeout and $self->{timeout};
$timestamp_msg = $self->{message_type} && $self->{message_type} eq 'timestamp' ? 1 : 0;

socket($self->{fh}, $ip->{family}, SOCK_RAW, $self->{proto_num}) ||
croak("icmp socket error - $!");
if ($^O eq 'linux' and !_isroot()) {
socket($self->{fh}, $ip->{family}, SOCK_DGRAM, $self->{proto_num}) ||
croak("icmp socket error - $!");
} else {
socket($self->{fh}, $ip->{family}, SOCK_RAW, $self->{proto_num}) ||
croak("icmp socket error - $!");
}

if (defined $self->{local_addr} &&
!CORE::bind($self->{fh}, _pack_sockaddr_in(0, $self->{local_addr}))) {
Expand Down Expand Up @@ -2366,11 +2381,13 @@ enabled.
X<ping_icmp>
The L</ping> method used with the icmp protocol.
Under Linux under a non-root account this uses now SOCK_DGRAM.
=item $p->ping_icmpv6([$host, $timeout, $family])
X<ping_icmpv6>
The L</ping> method used with the icmpv6 protocol.
Under Linux under a non-root account this uses now SOCK_DGRAM.
=item $p->ping_stream([$host, $timeout, $family])
X<ping_stream>
Expand Down
2 changes: 1 addition & 1 deletion t/500_ping_icmp.t
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ if (!Net::Ping::_isroot()) {

SKIP: {
skip "icmp ping requires root privileges.", 2
if !Net::Ping::_isroot() or $^O eq 'MSWin32';
if ($^O ne 'Linux' and !Net::Ping::_isroot()) or $^O eq 'MSWin32';
my $p = new Net::Ping "icmp";
is($p->message_type(), 'echo', "default icmp message type is 'echo'");
# message_type fails on wrong message type
Expand Down

0 comments on commit 52ff7bf

Please sign in to comment.