How can I determine the local machine's IP addresses from Perl? - perl

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?

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;

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: Sys::Hostname - works if it comes up with a resolvable hostname.
use Sys::Hostname;
use Socket;
my $addr = inet_ntoa((gethostbyname(hostname))[4]);
print "$addr\n";

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.

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.

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.

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.

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...

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

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.

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.

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.]+'

Related

Freebsd How to forward any classes IP?

I installed a FreeBSD 10.0 server(IP:10.1.2.3), and want to send packets to remote clients, with fake source ip, such as:
socket_sendto($socket $data, $length, 0, $ip, $port)
$data contains IP header, where i specify my "fake ip" here.
The questions is:
if i specify the IP to C class, everything goes well(below success):
10.1.2.4
10.1.3.5
if i specify the IP to B or A class, nothing send to destination(below failed):
10.2.1.2
11.1.2.3
So, how can i resolve the issue?
Btw i already modified sysctl.conf to :
net.inet.ip.forwarding=1
net.inet6.ip6.forwarding=1
net.inet.ip.fastforwarding=1
Sorry for poor English.
May be related to routing (netmasks). If Your server IP is 10.1.2.3/16, all IP adresses like 10.1.X.Y are directly reachable, but if You try to send to IP addresses outside this range, IP packet goes via routers. Properly configured router should not pass such fake packets. You should check defaultrouter setting in /etc/rc.conf. This defaultrouter may receive such fake packets, unless something else is blocking them on Your FreeBSD machine.
#Kestas is right, try the commands bellow:
1) Verify if you have route to the destination;
# netstat -ln
2) Test the connectivity:
# tracepath 10.2.1.2
3) Put on same network:
# ifconfig re0 10.2.1.1 / 255.0.0.0
GL !

ZeroMQ (0MQ) basic issue re connecting or binding to sockets

I'm using ZeroMQ on Windows, using C#, and am confused by a very basic networking question. I set up simplistic sample programs, one to PUBlish messages, the others use a SUB socket to receive them (the SUBscriber programs).
Works fine when both are on the same box. I used endpoint tcp://127.0.0.1:5000
As the next step, I put the SUBscriber program on a separate virtual machine (VM), to simulate using separate computers. I ran ipconfig to get it's IP address (on the guest os), 192.168.92.136
The host os has several network interfaces, one of which is the VMware Network Adapter VMnet1, with IP 192.168.92.1
On the host os, I ran the PUB program and connected the socket to 192.168.92.136, the IP address of the guest os.
On the guest os, I ran the SUB program and connected the socket to the IP of the host os. Did not work.
Then I changed the SUB program on the guest os to make it connect it to it's own IP address, ie that of the guest os - 192.168.92.136. Now it works!
Question: Why? I'm confused. But in a way it sort of makes sense: if that socket is for a service that attends to various clients that dynamically come and go, it doesn't know the IP address of each client. Therefore what the heck do you specify as the IP address for the SUB socket?! So connecting it to it's own host IP address does solve that concern. But the ZeroMQ Guide doesn't say this anywhere!
A related question is: if your host has multiple network interfaces, and each has it's own IP address, then if you connect your socket to some other host using the IP address of that other host - do you not need to specify which of those network interfaces you want to connect through? If so, how?
Incidentally, only one subscriber program seems to be able to connect at a time. The 2nd program to attempt to connect to it's SUB socket to the local IP address always gets a "Address is in use" error-message. I'm trying to make progress in small steps and learn this as I go.
Thanks for any help or advice.
James Hurst, JamesH at Designforge dot com

How to use the vSphere SDK for Perl with IPV6 hosts

I'm attempting to refactor old perl code to support some new IPV6-only hosts.
In testing the basic 'connect.pl' script, it fails with
Unsupported IP address format:
#/usr/lib/vmware-vcli/apps/general/connect.pl --url https://fe80::b6b5:2fff:fe5a:c5d8:443/sdk --username root --password pw
Unsupported IP address format
I also wrote a little test script to exercise Util::connect, and it fails in the same way.
Caveats:
I'm using VMware-vSphere-Perl-SDK-5.1.0-780721.
In my scenario, the ESXi hosts run IPV6 only, and the guests will run IPV4 only.
You have two issues here.
IPv6 literal addresses in a URL need to be in brackets.
Your link-local address is missing an interface identifier.
Specify the link-local address in brackets with the correct interface identifier. For example:
https://[fe80::b6b5:2fff:fe5a:c5d8%eth0]:443/sdk
The correct answer here is that, for unknown reasons, the API checks for link-local "fe80" addresses, and errors if it sees them.
connect.pl (which is sample code provided by VMware) works just fine with a global-scoped IPV6 address.

What is the difference between 127.0.0.1 and localhost

Assuming the following is defined in .../hosts:
127.0.0.1 localhost
What, if any, are the actual differences between using 127.0.0.1 and localhost as the server name, especially when hitting processes running locally that are listening for connections?
Well, the most likely difference is that you still have to do an actual lookup of localhost somewhere.
If you use 127.0.0.1, then (intelligent) software will just turn that directly into an IP address and use it. Some implementations of gethostbyname will detect the dotted format (and presumably the equivalent IPv6 format) and not do a lookup at all.
Otherwise, the name has to be resolved. And there's no guarantee that your hosts file will actually be used for that resolution (first, or at all) so localhost may become a totally different IP address.
By that I mean that, on some systems, a local hosts file can be bypassed. The host.conf file controls this on Linux (and many other Unices).
Wikipedia sums this up well:
On modern computer systems, localhost as a hostname translates to an IPv4 address in the 127.0.0.0/8 (loopback) net block, usually 127.0.0.1, or ::1 in IPv6.
The only difference is that it would be looking up in the DNS for the system what localhost resolves to. This lookup is really, really quick. For instance, to get to stackoverflow.com you typed in that to the address bar (or used a bookmarklet that pointed here). Either way, you got here through a hostname. localhost provides a similar functionality.
some applications will treat "localhost" specially. the mysql client will treat localhost as a request to connect to the local unix domain socket instead of using tcp to connect to the server on 127.0.0.1. This may be faster, and may be in a different authentication zone.
I don't know of other apps that treat localhost differently than 127.0.0.1, but there probably are some.
Well, by IP is faster.
Basically, when you call by server name, it is converted to original IP.
But it would be difficult to memorize an IP, for this reason the domain name was created.
Personally I use http://localhost instead of http://127.0.0.1 or http://username.
There is nothing different. One is easier to remember than the other. Generally, you define a name to associate with an IP address. You don't have to specify localhost for 127.0.0.1, you could specify any name you want.

gethostbyname() only returns the address of local host on linux

I'm trying to portably (Windows & Linux) find all of the IP addresses of the local machine. The method I am using is to first call gethostname(), and then pass the result of that to gethostbyname(), which returns an array of ip addresses.
The problem is that on linux, the only address I get back is 127.0.0.1. This works on Windows, and I've seen a few people state that this will not work on Linux if your network was configured by DHCP (don't know if that's a true statement).
Is this not the correct way to do this on Linux?
It is not the correct way on unix/linux. The correct way involves ioctls to pull the necessary information.
struct ifreq ifc_buffer[MAX_NUM_IFREQ];
ioctl(s, SIOCGIFCONF, &ifc) # Interface list
num_ifreq = ifc.ifc_len / sizeof(struct ifreq);
for(cnt=0;cnt<num_ifreq;cnt++)
struct ifreq *ifr = &ifc.ifc_req[cnt]
ioctl(s, SIOCGIFADDR, ifr); # get ip address
There are also more modern methods involving:
if_nameindex()
Doing a SO search for if_nameindex and SIOCGIFCONF will yield a number of questions similar to this one.
This happens because on most distributions you have this in /etc/hosts:
127.0.0.1 localhost.localdomain localhost aiur
gethostbyname simply resolves the hostname (aiure in this example) to an address. If it finds it in /etc/hosts it's more than happy to give you that.
Back to the question. Unfortunately I don't believe you can get all the addresses of your machine in a portable way. You can do it in a Unix-portable way, like ifconfig does. Open a socket s and do an ioctl(..., SIOCGIFCONF, ...).
By the way, gethostbyname is obsolete if you believe kernel.org and deprecated if you believe MSDN.