> It is possible to get interface lists on earlier versions (and I hope
> still current versions) using the ioctl interfaces described in Stevens.
> See also ifconfig.c source from various versions of FreeBSD :-).

I think Garret suggested that the ioctl method was deprecated?

I wrote some code just to figure out how the sysctl stuff is packed
'cos it's not that obvoius - I've included it below incase it might
be of use to someone.

        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 [EMAIL PROTECTED]
with "unsubscribe freebsd-hackers" in the body of the message

Reply via email to