Listing all IP addresses on an multihomed system


#1

Hi all,

I’m wondering if there’s a way to list all IP addresses on a
multihomed system using Ruby’s Socket API. I actually want this for
the sys-host library (at http://www.rubyforge.org/projects/sysutils).
It’s C, but I figure I can reverse engineer the Ruby code back to C.

Here’s the equivalent of what I’m currently doing (in C):

#include <unistd.h>
#include <netdb.h>
#include <stdio.h>
#include <arpa/inet.h>

#define BUF 256

int main(){
struct hostent* h;
char hostname[BUF];
char ip[BUF];

if(gethostname(hostname, BUF) != 0){
printf(“gethostbyname failed\n”);
return -1;
}

printf(“Hostname: %s\n”, hostname);

h = gethostbyname(hostname);

if(!h){
printf(“gethostbyname failed\n”);
return -1;
}

while(*h->h_addr_list){
printf(“Addr: %s\n”, inet_ntop(h->h_addrtype, *h->h_addr_list,
ip, BUF));
*h->h_addr_list++;
}

return 0;
}

But, at least one user has reported that he has eth0 configured with a
LAN IP and eth1 that has 5 attached IP addresses. The above code
doesn’t pick them up.

Is there a pure Ruby solution? Is it just a matter of
Socket.getaddrinfo(Socket.gethostname, 80)? Or, does anyone happen to
know the C solution?

Thanks,

Dan


#2

On 7/18/07, Daniel B. removed_email_address@domain.invalid wrote:

#include <unistd.h>

  printf("gethostbyname failed\n");

}

Dan

Since you’re obviously using Linux, how about just parsing the output of
ethtool?


#3

On 7/18/07, Francis C. removed_email_address@domain.invalid wrote:

char ip[BUF];
if(!h){
return 0;
Thanks,

Dan

Since you’re obviously using Linux, how about just parsing the output of
ethtool?

Eh? No, the C code above works just fine on Solaris (with -lsocket and
-lnsl added). Besides, I need the code to be as cross platform as
possible (for Unix flavors, that is - I use a different approach on MS
Windows). So, parsing system calls is out of the question.

Regards,

Dan


#4

In article removed_email_address@domain.invalid,
Daniel B. removed_email_address@domain.invalid writes:

I’m wondering if there’s a way to list all IP addresses on a
multihomed system using Ruby’s Socket API. I actually want this for
the sys-host library (at http://www.rubyforge.org/projects/sysutils).
It’s C, but I figure I can reverse engineer the Ruby code back to C.

[ extraneous program based on gethostbyname elided]

But, at least one user has reported that he has eth0 configured with a
LAN IP and eth1 that has 5 attached IP addresses. The above code
doesn’t pick them up.

As your user has reported, your C-based program does not do what
you desire. gethostbyname (and its friends) can only deal with
DNS-based information. Information about multi-hosting is not
stored in the DNS. In fact, it is actually system dependent and is
only stored in the local kernel’s network tables.

Most UNIX and Linux systems provide a mechanism to access this
information via some variant of the ioctl(2) call with command
SIOCGIFCONF. BSDi and FreeBSD have a set of subroutines (originally
based on the ioctl) called getifaddrs. MS Windows WinSock2 uses
the command SIO_GET_INTERFACE_LIST with the WSAIoctl procedure.
You will need to look in the documentation for your system (and
probably do a net search for programming examples) to see how it
works.

Is there a pure Ruby solution? Is it just a matter of
Socket.getaddrinfo(Socket.gethostname, 80)? Or, does anyone happen to
know the C solution?

I’m fairly certain that this could be done in ruby via IO.ioctl
and pack/unpack on UNIX/Linux, but I’m also fairly certain that
this would be a real PITA. I don’t have any familiarity with the
Win32-specific solutions.

Dan

Good luck, - dmw

Notes:

  • DNS = Domain Name System
  • The ioctl commands evolve over time and over various systems.
    The ones I note there may well be deprecated, obsolete, and/or
    non-existent on your system.

#5

On 7/18/07, Daniel B. removed_email_address@domain.invalid wrote:

But, at least one user has reported that he has eth0 configured with
a

LAN IP and eth1 that has 5 attached IP addresses. The above code
doesn’t pick them up.

Sorry, it’s the “eth0” and “eth1” that made me think you were doing this
for
Linux.


#6

On Jul 18, 2:10 pm, removed_email_address@domain.invalid (Douglas Wells) wrote:

But, at least one user has reported that he has eth0 configured with a
information via some variant of the ioctl(2) call with command
SIOCGIFCONF. BSDi and FreeBSD have a set of subroutines (originally
based on the ioctl) called getifaddrs. MS Windows WinSock2 uses
the command SIO_GET_INTERFACE_LIST with the WSAIoctl procedure.
You will need to look in the documentation for your system (and
probably do a net search for programming examples) to see how it
works.

Indeed, there’s an example in Stevens’ “Unix Network Programming, Vol.
1” staring at me now. :slight_smile: Many thanks for the lead. I should be ok from
here (I hope).

I’ll see if I can come up with a pure Ruby solution and post it here
eventually.

Regards,

Dan


#7

Douglas Wells wrote:

Most UNIX and Linux systems provide a mechanism to access this

associated with an interface name, however.
It also appears that you can use sysctl() + NET_RT_IFLIST. It’s easier,
but less portable. I’ll probably just suck it up and use the more
portable version.

Regards,

Dan


#8

In article removed_email_address@domain.invalid,
Daniel B. removed_email_address@domain.invalid writes:

1" staring at me now. :slight_smile: Many thanks for the lead. I should be ok from
here (I hope).

I’ll see if I can come up with a pure Ruby solution and post it here
eventually.

Dan

Please let us know if you do. I managed to find time to take a
slightly deeper look, and the problem that I found is that SIOCGIFCONF
requires that you place an actual virtual address in the additional
argument to ioctl. I doubt that there is a “pure Ruby” way of
doing that. You’ll can probably do ok getting the addresses
associated with an interface name, however.

  • dmw