Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 9 Jan 2001 14:07:52 +0000
From:      David Malone <dwmalone@maths.tcd.ie>
To:        Graham Wheeler <gram@cequrux.com>
Cc:        freebsd-hackers@freebsd.org, markster@marko.net
Subject:   Re: Size of struct ifreq/returned buffer of SIOCGIFCONF
Message-ID:  <20010109140752.A52761@walton.maths.tcd.ie>
In-Reply-To: <3A5AE617.E8644889@cequrux.com>; from gram@cequrux.com on Tue, Jan 09, 2001 at 12:21:11PM %2B0200
References:  <3A5AE617.E8644889@cequrux.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Tue, Jan 09, 2001 at 12:21:11PM +0200, Graham Wheeler wrote:

> I am attempting to port the cheops network mapping/diagnostic program
> from Linux to FreeBSD (see www.marko.net/cheops). One of the first snags
> I have hit comes in using SIOCGIFCONF to queries the network interface
> names and addresses.

Could you use getifaddrs() for this? It would probably provide the
info you need in a easier to digest form. If not, the code below
might be useful. It gets a list of interface properties using
sysctl(), but I believe the info is packed in the same way as it
is for SIOCGIFCONF.

(I wrote the code to figure out how the process worked, I think it
is correct, but you never know).

	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?20010109140752.A52761>