Sophie

Sophie

distrib > Mandriva > 2007.0 > i586 > by-pkgid > 0515fa6c685498be6300af197b2935dd > files > 10

cipe-1.4.5-20mdk.src.rpm

/* This function currently only supports IPv4.  Someone who knows
 * more about multi-protocol socket stuff should take a look at this.
 * 
 * (But does it make any sense to support other 
 * protocols?  Maybe IPv6...
 */

#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>

static char *search_routing_table(const char *to)
{
    struct ifaddrlist *first_if;
    FILE *fp;
    char buf[1024];
    char ifname[128];
    unsigned int route_dest;
    unsigned int mask;
    char best_name[128];
    unsigned int best_mask;
    unsigned int dest_addr;
    unsigned int convs;
    int fd;
    struct ifreq ifr;
    struct sockaddr_in * addrp;
    struct hostent *he = gethostbyname(to);
    if (!he) {
	fprintf (stderr, "gethostbyname: %s\n", hstrerror(h_errno));
	return NULL;
    }
    dest_addr = inet_addr(*he->h_addr_list);

    fp = fopen("/proc/net/route", "r");
    if (fp == NULL) {
	return NULL;
    }

    /* Skip the first line (the column headings) */
    if (fgets(buf, sizeof(buf), fp) == NULL) {
	fclose(fp);
	return NULL;
    }

    best_name[0] = '\0';
    best_mask = 0;

    while (fgets(buf, sizeof(buf), fp) != NULL) {
	/* Field 1: interface name
	 * Field 2: dest addr
	 * Field 8: genmask 
	 */
	convs = sscanf(buf, "%s %x %*s %*s %*s %*s %*s %x", 
		       ifname, &route_dest, &mask);
	if (convs != 3) {
	    /* format error .... */
	    fclose(fp);
	    return NULL;
	}

	if ((dest_addr & mask) == route_dest) {
	    /* This routing entry applies to
	     * our destination addr
	     */
	    if ((mask > best_mask) || (best_mask == 0)) {
		/* And it is more specific than any
		 * previous match (or is the first match)
		 */
		best_mask = mask;
		strncpy(best_name, ifname, sizeof(best_name));
	    }
	}
    }
    fclose(fp);

    fd = socket(AF_INET, SOCK_DGRAM, 0);
    strncpy(ifr.ifr_name, best_name, sizeof(ifr.ifr_name));
    if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
	fprintf (stderr, "ioctl (%s): %s\n", best_name, strerror(errno));
	return NULL;
    }

    addrp = (struct sockaddr_in *) &ifr.ifr_addr;
    return inet_ntoa(addrp->sin_addr);
}

int main (int argc, char **argv)
{
    char *address;
    if (argc < 2) {
	fprintf (stderr, "usage: %s [address]\n", argv[0]);
	return -1;
    }
    address = search_routing_table (argv[1]);
    if (address) {
	printf ("%s\n", address);
	return 0;
    } else {
	return -1;
    }
}