How can I determine the local machine's IP add

2020-06-15 03:36发布

问题:

Is there a clean and OS independent way to determine the local machine's IP addresses from Perl?

So far I have found the following solutions:

  • parse the output of ifconfig and ipconfig (hard, different windows versions have different ipconfig outputs)

  • establish a network connection to a well-known IP and examine the socket's local IP address (won't work if I can't establish a connection and will determine only one IP address)

Any better suggestion?

回答1:

Net::Address::IP::Local looks promising.

use Net::Address::IP::Local;

# Get the local system's IP address that is "en route" to "the internet":
my $address      = Net::Address::IP::Local->public;


回答2:

You also have some other options, including your solution to "establish a network connection to a well-known IP and examine the socket's local IP address".

In that case (establishing network connection) however, that article points out that:

there is no such thing as a host's IP address.
Network interfaces have IP addresses, not hosts, and a single network interface can have many (virtual) IP addresses. The operating system's routing subsystem decides which network interface and IP address to use to connect to a remote machine.

If your machine only has one external network interface, and this interface only has one IP address then this IP address is commonly called the machine's address, but that is inaccurate.
For example, if the machine is connected to a VPN via a virtual interface it will use this interface's IP address to connect to another machine on the VPN, not the external IP address

Amongst the other solutions: uses "Sys::Hostname"
(Works if Sys::Hostname comes up with a resolvable hostname)

use Sys::Hostname;
use Socket;
my($addr)=inet_ntoa((gethostbyname(hostname))[4]);
print "$addr\n";


回答3:

In my case, I need a solution without any non-core dependencies. I came up with this after studying the code in Net::Address::IP::Local:

#!/usr/bin/env perl

use strict;
use warnings;

use IO::Socket::INET;

my $local_ip_address = get_local_ip_address();

print "$local_ip_address\n";

# This idea was stolen from Net::Address::IP::Local::connected_to()
sub get_local_ip_address {
    my $socket = IO::Socket::INET->new(
        Proto       => 'udp',
        PeerAddr    => '198.41.0.4', # a.root-servers.net
        PeerPort    => '53', # DNS
    );

    # A side-effect of making a socket connection is that our IP address
    # is available from the 'sockhost' method
    my $local_ip_address = $socket->sockhost;

    return $local_ip_address;
}

get_local_ip_address() should return the same string as Net::Address::IP::Local->public_ipv4.

If desired, you can change the PeerAddr attribute (in the arguments to the constructor for IO::Socket::INET) to a local DNS server.



回答4:

To retrieve the IP address of all interfaces, use IO::Interface::Simple:

perl -MIO::Interface::Simple '-Esay $_->address for grep { $_->is_running && defined $_->address } IO::Interface::Simple->interfaces'

If you are not interested in 127.0.0.1 (loopback) you can filter on $_->is_loopback.



回答5:

Perldoc has an answer to this question in its FAQ ("perlfaq9") - using different modules (which are parts of the Standard Library) or even a built-in function.



回答6:

I've had good success with IO::Interface on Linux and Solaris, and I think it even worked on AIX but I can't recall for sure. Poking around on search.cpan.org, rt.cpan.org and ActiveState's various sites, it looks like IO::Interface may be experiencing build problems on Windows. I guess the only way to know if it's available is to search for io-interface in PPM.



回答7:

use WMI?

Example of extracting IP addresses (in Powershell, but it's pretty clear what's happening)

Example of accessing WMI from Perl (not the same WMI functions, but again the process is reasonably clear)

EDIT: after a search on Google codesearch for Networkadapterconfiguration and language "perl":

Example looks like pretty much what you need

EDIT2: In fact the OCS code seems to contain code for most platforms to do this, so while there may be no one set of code that does this, you may be able to re-use their ideas. It's GPL'd, though.

For example, here's the Solaris code. Other bits cover BSD, Linux, MacOS...



回答8:

getting a network interface's IP address in Perl without additional modules usage and 'ifconfig' output parsing



回答9:

Net::Address::IP::Local works fine, but since the original poster asks for all the local addresses, I think this one is better:

http://www.perlmonks.org/?node_id=166951

It worked fine for me with ActivePerl for Windows XP.



回答10:

for windows I use

foreach (split(/\r?\n/,`netstat -r`))
{
  next unless /^\s+0.0.0.0/;
  @S = split(/\s+/); 
  # $S[3] = Default Gateway
  # $S[4] = Main IP
}

The first line starting 0.0.0.0 is the default gateway. There maybe multiple gateways. Lines starting 255.255.255.255 are also useful. netstat -r and route print are the same.

Can be adapted for OSX, Linux not so helpful.



回答11:

I have used a combination of these Linux commands so no dependancy on any perl module.

hostname -i
hostname -I
ls /sys/class/net
ip -f inet addr show eth0| grep -Po 'inet \K[\d.]+'