Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 11 Nov 1999 08:05:40 +0000
From:      David Malone <dwmalone@maths.tcd.ie>
To:        "Santhosh Kumar M [CEC-S]" <santoshm@wipinfo.soft.net>
Cc:        freebsd-hackers@FreeBSD.ORG
Subject:   Re: A Question
Message-ID:  <19991111080540.A58543@walton.maths.tcd.ie>
In-Reply-To: <Pine.SV4.3.93.991111112533.8773A-100000@tagore>
References:  <Pine.SV4.3.93.991111112533.8773A-100000@tagore>

next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, Nov 11, 1999 at 11:29:57AM +0530, Santhosh Kumar M [CEC-S] wrote:

> 	Can anyone give me the library call or system calls by which i can
> get all the IP address configured on a local system (Note: the system can
> be multihomed adapters). 

Here is a program I wrote to try to see how to find the addresses of
all the interfaces. It's based on rwhod and reading how the kernel
does it. I think I'm doing it the correct way, but it isn't pretty.

	David.

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <stdlib.h>
#include <err.h>
#include <stdio.h>
#include <string.h>

#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/*
 * This is an example of how to find info about the currently configured
 * interfaces.
 *
 * The code in rwhod and ifconfig if pretty hard to understand as it
 * doesn't really exploit the structure of what you're returned. We use
 * a sysctl to get the interface list, which returns a buffer with a
 * list of things each starting with:
 * 
 *         msglen
 *         version
 *         type
 * 
 * The generic type used to with this start in the kernel seems to be
 * "struct rt_msghdr". For this sysctl we call it returns a message of
 * type RTM_IFINFO followed by a list of RTM_NEWADDR for each interface.
 * This corrisponds to the interface and each of the configurations you
 * "put" on it with ifconfig.
 * 
 * The RTM_IFINFO message contains a struct if_msghdr followed by a
 * list of struct sockaddr. The RTM_NEWADDR contains a struct ifa_msghdr
 * followed by a list of struct sockaddr.
 * 
 * The struct sockaddr's sizes have been truncated to the nearest
 * power of two into which the data will fit. The struct sockaddr's
 * included depend on what is apropriate to this message. You can tell
 * which of RTAX_* sockaddr's have been included by looking at the set
 * bits of ifm_addrs or ifam_addrs, so you have to expand them out into
 * an array of struct sockaddr's of size RTAX_MAX.
 */

void unpack_addrs(struct sockaddr *packed,struct sockaddr *unpacked,int rti_addrs);
void print_addrs(struct sockaddr *unpacked,int rti_addrs);

int
main(int argc, char **argv)
{
	char *buf, *lim, *next; /* For sysctl */
	size_t needed;
	int mib[6];

	struct rt_msghdr *rtm; /* For decoding messages */
	struct if_msghdr *ifm;
	struct ifa_msghdr *ifam;

	struct sockaddr *packed_addr; /* For decoding addresses */
	struct sockaddr unpacked_addr[RTAX_MAX];

	mib[0] = CTL_NET;
	mib[1] = PF_ROUTE;
	mib[2] = 0;
	mib[3] = AF_INET;
	mib[4] = NET_RT_IFLIST;
	mib[5] = 0;

	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
		errx(1, "route-sysctl-estimate");
	if ((buf = malloc(needed)) == NULL)
		errx(1, "malloc");
	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
		errx(1, "actual retrieval of interface table");
	lim = buf + needed;

	for( next = buf; next < lim; next += rtm->rtm_msglen ) {
		rtm = (struct rt_msghdr *)next;

		switch( rtm->rtm_type ) {
		case RTM_IFINFO:
			ifm = (struct if_msghdr *)next;
			packed_addr = (struct sockaddr *)(next + sizeof(struct if_msghdr));
			printf("Found an interface.\n");
			if( ifm->ifm_flags & IFF_UP )
				printf("It is currently up.\n");
			if( ifm->ifm_addrs != 0 ) {
				printf("These addresses were available:\n");
				unpack_addrs(packed_addr,unpacked_addr,
				    ifm->ifm_addrs);
				print_addrs(unpacked_addr,ifm->ifm_addrs);
			} else
				printf("No addresses were available.\n");
			break;
		case RTM_NEWADDR:
			ifam = (struct ifa_msghdr *)next;
			packed_addr = (struct sockaddr *)(next + sizeof(struct ifa_msghdr));
			printf("Found extra addresses associated with interface.\n");
			unpack_addrs(packed_addr,unpacked_addr,
			    ifam->ifam_addrs);
			print_addrs(unpacked_addr,ifam->ifam_addrs);
			break;
		default:
			errx(1, "unexpected rtm type");
		}
	}

	exit(0);
}

#define ROUNDUP(a) \
        ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))

void
unpack_addrs(struct sockaddr *packed,struct sockaddr *unpacked,int rti_addrs)
{
	int i;

	for( i = 0; i < RTAX_MAX; i++ ) {
		bzero(&unpacked[i],sizeof(unpacked[i]));
		if( rti_addrs & (1<<i) ) {
			memcpy(&(unpacked[i]), packed, packed->sa_len);
			packed = (struct sockaddr *)(((char *)packed) + ROUNDUP(packed->sa_len));
		}
	}
}

void
print_addrs(struct sockaddr *unpacked,int rti_addrs)
{
	int i;

	for( i = 0; i < RTAX_MAX; i++ ) {
		if( (rti_addrs & (1<<i)) == 0 )
			continue;

		switch(i) {
		case RTAX_DST:
			printf("Destination address");
			break;
		case RTAX_GATEWAY:
			printf("Gateway address");
			break;
		case RTAX_NETMASK:
			printf("Netmask");
			break;
		case RTAX_GENMASK:
			printf("Cloning mask");
			break;
		case RTAX_IFP:
			printf("Interface name");
			break;
		case RTAX_IFA:
			printf("Interface address");
			break;
		case RTAX_AUTHOR:
			printf("Author of redirect");
			break;
		case RTAX_BRD:
			printf("Broadcast address");
			break;
		default:
			printf("Unknown type of address %d",i);
			break;
		}

		printf(": ");

		switch( unpacked[i].sa_family ) {
		case AF_INET:
			printf(inet_ntoa(((struct sockaddr_in *)&(unpacked[i]))->sin_addr));
			break;
		default:
			printf("address in family %d", unpacked[i].sa_family);
			break;
		}
		printf(".\n");
	}

}


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?19991111080540.A58543>