/* 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; } }