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>