Index: include/asterisk/acl.h =================================================================== --- include/asterisk/acl.h (revision 99340) +++ include/asterisk/acl.h (working copy) @@ -45,6 +45,7 @@ int ast_get_ip_or_srv(struct sockaddr_in *sin, const char *value, const char *service); int ast_ouraddrfor(struct in_addr *them, struct in_addr *us); int ast_lookup_iface(char *iface, struct in_addr *address); +int ast_get_local_address(struct in_addr *ourip); struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original); int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr); int ast_str2tos(const char *value, unsigned int *tos); Index: main/acl.c =================================================================== --- main/acl.c (revision 99340) +++ main/acl.c (working copy) @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -53,6 +52,10 @@ #include #endif +#if defined(__linux__) +#include +#endif + /* netinet/ip.h may not define the following (See RFCs 791 and 1349) */ #if !defined(IPTOS_LOWCOST) #define IPTOS_LOWCOST 0x02 @@ -86,6 +89,136 @@ struct sockaddr_in ifru_addr; }; +static void score_address(const struct sockaddr_in *sin, struct in_addr *best_addr, int *best_score) +{ + const char *address; + int score; + + address = ast_inet_ntoa(sin->sin_addr); + + if (address[0] == '0') + score = -25; + else if (strncmp(address, "127", 3) == 0) + score = -20; + else if (strncmp(address, "10.", 3) == 0) + score = -5; + else if (strncmp(address, "172", 3) == 0) { + if (address[4] == '1' && address[5] >= '6') + score = -5; + else if (address[4] == '2') + score = -5; + else if (address[4] == '3' && address[5] <= '1') + score = -5; + else + score = 0; + } else if (strncmp(address, "192.168", 7) == 0) + score = -5; + else if (strncmp(address, "192.0.2.", 8) == 0) + score = -10; + else + score = 0; + + if (score > *best_score) { + *best_score = score; + memcpy(best_addr, &sin->sin_addr, sizeof(*best_addr)); + } +} + +int ast_get_local_address(struct in_addr *ourip) +{ + int s, res = -1; +#ifdef _SOLARIS + struct lifreq *ifr = NULL; + struct lifnum ifn; + struct lifconf ifc; + struct sockaddr_in *sa; + char *buf = NULL; + int bufsz, x; +#endif /* _SOLARIS */ +#if defined(_BSD) || defined(__linux__) + struct ifaddrs *ifap, *ifaphead; + int rtnerr; + const struct sockaddr_in *sin; +#endif /* defined(_BSD) || defined(_LINUX) */ + struct in_addr best_addr = { 0, }; + int best_score = -100; + +#if defined(_BSD) || defined(__linux__) + rtnerr = getifaddrs(&ifaphead); + if (rtnerr) { + perror(NULL); + return -1; + } +#endif /* BSD_OR_LINUX */ + + s = socket(AF_INET, SOCK_STREAM, 0); + + if (s > 0) { +#if defined(_BSD) || defined(__linux__) + for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) { + + if (ifap->ifa_addr->sa_family == AF_INET) { + sin = (const struct sockaddr_in *) ifap->ifa_addr; + score_address(sin, &best_addr, &best_score); + res = 0; + + if (best_score == 0) + break; + } + } +#endif /* _BSD */ + + /* There is no reason whatsoever that this shouldn't work on Linux or BSD also. */ +#ifdef _SOLARIS + /* Get a count of interfaces on the machine */ + ifn.lifn_family = AF_INET; + ifn.lifn_flags = 0; + ifn.lifn_count = 0; + if (ioctl(s, SIOCGLIFNUM, &ifn) < 0) { + close(s); + return -1; + } + + bufsz = ifn.lifn_count * sizeof(struct lifreq); + if (!(buf = malloc(bufsz))) { + close(s); + return -1; + } + memset(buf, 0, bufsz); + + /* Get a list of interfaces on the machine */ + ifc.lifc_len = bufsz; + ifc.lifc_buf = buf; + ifc.lifc_family = AF_INET; + ifc.lifc_flags = 0; + if (ioctl(s, SIOCGLIFCONF, &ifc) < 0) { + close(s); + free(buf); + return -1; + } + + for (ifr = (struct lifreq *)buf, x = 0; x < ifn.lifn_count; ifr++, x++) { + sa = (struct sockaddr_in *)&(ifr->lifr_addr); + score_address(sin, &best_addr, &best_score); + res = 0; + + if (best_score == 0) + break; + } + + free(buf); +#endif /* _SOLARIS */ + + close(s); + } +#if defined(_BSD) || defined(__linux__) + freeifaddrs(ifaphead); +#endif + + if (res == 0 && ourip) + memcpy(ourip, &best_addr, sizeof(*ourip)); + return res; +} /* Free HA structure */ void ast_free_ha(struct ast_ha *ha) { @@ -422,6 +555,6 @@ /* A.ROOT-SERVERS.NET. */ if (inet_aton("198.41.0.4", &saddr) && !ast_ouraddrfor(&saddr, ourip)) return 0; - return -1; + return ast_get_local_address(ourip); }