[Asterisk-code-review] utils.c: Fix ast set default eid for multiple platforms (asterisk[13])

Anonymous Coward asteriskteam at digium.com
Wed Oct 19 17:35:51 CDT 2016


Anonymous Coward #1000019 has submitted this change and it was merged. ( https://gerrit.asterisk.org/4116 )

Change subject: utils.c:  Fix ast_set_default_eid for multiple platforms
......................................................................


utils.c:  Fix ast_set_default_eid for multiple platforms

ast_set_default_eid was searching for ethX, emX, enoX, ensX and even
pciD#U interface names.  While this was a good attempt, it wasn't
inclusive enough to capture interfaces like enp6s0 or ens6d1, etc.

Rather than relying on interface names, we now simply find the first
interface returned by the OS that has a hardware address and that
address isn't all 0x00 or all 0xff.  The code IS different for BSD,
Solaris and Linux based on what method is available for enumerating
interfaces.

Tested on:
FreeBSD9
CentOS6
Ubuntu14
Fedora24

I was unable to test on Solaris at this time but the code for Solaris
is used elsewhere at Digium.

Change-Id: Iaa6db87ca78a9a375e47d70e043ae08c1448cb72
---
M main/utils.c
1 file changed, 203 insertions(+), 49 deletions(-)

Approvals:
  Anonymous Coward #1000019: Verified
  Matt Jordan: Looks good to me, approved
  Joshua Colp: Looks good to me, but someone else must approve



diff --git a/main/utils.c b/main/utils.c
index af0ee7f..03bead2 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -2478,73 +2478,227 @@
 	return os;
 }
 
+#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__Darwin__)
+#include <ifaddrs.h>
+#include <net/if_dl.h>
+
 void ast_set_default_eid(struct ast_eid *eid)
 {
-#if defined(SIOCGIFHWADDR) && defined(HAVE_STRUCT_IFREQ_IFR_IFRU_IFRU_HWADDR)
-	int s, x = 0;
+	struct ifaddrs *ifap, *ifaphead;
+	int rtnerr;
+	const struct sockaddr_dl *sdl;
+	int alen;
+	caddr_t ap;
 	char eid_str[20];
-	struct ifreq ifr;
-	static const unsigned int MAXIF = 10;
+	unsigned char empty_mac[6] = {0, 0, 0, 0, 0, 0};
+	unsigned char full_mac[6]  = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
 
-	s = socket(AF_INET, SOCK_STREAM, 0);
-	if (s < 0) {
+	rtnerr = getifaddrs(&ifaphead);
+	if (rtnerr) {
+		ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
+			"You will have to set it manually.\n");
 		return;
 	}
-	for (x = 0; x < MAXIF; x++) {
-		static const char *prefixes[] = { "eth", "em", "eno", "ens" };
-		unsigned int i;
 
-		for (i = 0; i < ARRAY_LEN(prefixes); i++) {
-			memset(&ifr, 0, sizeof(ifr));
-			snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", prefixes[i], x);
-			if (!ioctl(s, SIOCGIFHWADDR, &ifr)) {
-				break;
-			}
+	if (!ifaphead) {
+		ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
+			"You will have to set it manually.\n");
+		return;
+	}
+
+	for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) {
+		if (ifap->ifa_addr->sa_family != AF_LINK) {
+			continue;
 		}
 
-		if (i == ARRAY_LEN(prefixes)) {
-			/* Try pciX#[1..N] */
-			for (i = 0; i < MAXIF; i++) {
-				memset(&ifr, 0, sizeof(ifr));
-				snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "pci%d#%u", x, i);
-				if (!ioctl(s, SIOCGIFHWADDR, &ifr)) {
-					break;
-				}
-			}
-			if (i == MAXIF) {
-				continue;
-			}
+		sdl = (const struct sockaddr_dl *) ifap->ifa_addr;
+		ap = ((caddr_t) ((sdl)->sdl_data + (sdl)->sdl_nlen));
+		alen = sdl->sdl_alen;
+		if (alen != 6 || !(memcmp(ap, &empty_mac, 6) && memcmp(ap, &full_mac, 6))) {
+			continue;
 		}
 
-		memcpy(eid, ((unsigned char *)&ifr.ifr_hwaddr) + 2, sizeof(*eid));
-		ast_debug(1, "Seeding global EID '%s' from '%s' using 'siocgifhwaddr'\n", ast_eid_to_str(eid_str, sizeof(eid_str), eid), ifr.ifr_name);
+		memcpy(eid, ap, sizeof(*eid));
+		ast_debug(1, "Seeding global EID '%s'\n",
+				ast_eid_to_str(eid_str, sizeof(eid_str), eid));
+		freeifaddrs(ifaphead);
+		return;
+	}
+
+	ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
+		"You will have to set it manually.\n");
+	freeifaddrs(ifaphead);
+
+	return;
+}
+
+#elif defined(SOLARIS)
+#include <sys/sockio.h>
+#include <net/if_arp.h>
+
+void ast_set_default_eid(struct ast_eid *eid)
+{
+	int s;
+	int x;
+	int res = 0;
+	struct lifreq *ifr = NULL;
+	struct lifnum ifn;
+	struct lifconf ifc;
+	struct arpreq ar;
+	struct sockaddr_in *sa, *sa2;
+	char *buf = NULL;
+	char eid_str[20];
+	int bufsz;
+	unsigned char empty_mac[6] = {0, 0, 0, 0, 0, 0};
+	unsigned char full_mac[6]  = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+	s = socket(AF_INET, SOCK_STREAM, 0);
+	if (s <= 0) {
+		ast_log(LOG_WARNING, "Unable to open a socket for seeding global EID. "
+			" You will have to set it manually.\n");
+		return;
+	}
+
+	/* Get a count of interfaces on the machine */
+	ifn.lifn_family = AF_UNSPEC;
+	ifn.lifn_flags = 0;
+	ifn.lifn_count = 0;
+	if (ioctl(s, SIOCGLIFNUM, &ifn) < 0) {
+		ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
+			" You will have to set it manually.\n");
 		close(s);
 		return;
 	}
-	close(s);
-#else
-#if defined(ifa_broadaddr) && !defined(SOLARIS)
-	char eid_str[20];
-	struct ifaddrs *ifap;
 
-	if (getifaddrs(&ifap) == 0) {
-		struct ifaddrs *p;
-		for (p = ifap; p; p = p->ifa_next) {
-			if ((p->ifa_addr->sa_family == AF_LINK) && !(p->ifa_flags & IFF_LOOPBACK) && (p->ifa_flags & IFF_RUNNING)) {
-				struct sockaddr_dl* sdp = (struct sockaddr_dl*) p->ifa_addr;
-				memcpy(&(eid->eid), sdp->sdl_data + sdp->sdl_nlen, 6);
-				ast_debug(1, "Seeding global EID '%s' from '%s' using 'getifaddrs'\n", ast_eid_to_str(eid_str, sizeof(eid_str), eid), p->ifa_name);
-				freeifaddrs(ifap);
-				return;
-			}
-		}
-		freeifaddrs(ifap);
+	bufsz = ifn.lifn_count * sizeof(struct lifreq);
+	if (!(buf = ast_malloc(bufsz))) {
+		ast_log(LOG_WARNING, "Unable to allocate memory for seeding global EID. "
+			"You will have to set it manually.\n");
+		close(s);
+		return;
 	}
-#endif
-#endif
-	ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. You will have to set it manually.\n");
+	memset(buf, 0, bufsz);
+
+	/* Get a list of interfaces on the machine */
+	ifc.lifc_len = bufsz;
+	ifc.lifc_buf = buf;
+	ifc.lifc_family = AF_UNSPEC;
+	ifc.lifc_flags = 0;
+	if (ioctl(s, SIOCGLIFCONF, &ifc) < 0) {
+		ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
+			"You will have to set it manually.\n");
+		ast_free(buf);
+		close(s);
+		return;
+	}
+
+	for (ifr = (struct lifreq *)buf, x = 0; x < ifn.lifn_count; ifr++, x++) {
+		unsigned char *p;
+
+		sa = (struct sockaddr_in *)&(ifr->lifr_addr);
+		sa2 = (struct sockaddr_in *)&(ar.arp_pa);
+		*sa2 = *sa;
+
+		if(ioctl(s, SIOCGARP, &ar) >= 0) {
+			p = (unsigned char *)&(ar.arp_ha.sa_data);
+			if (!(memcmp(p, &empty_mac, 6) && memcmp(p, &full_mac, 6))) {
+				continue;
+			}
+
+			memcpy(eid, p, sizeof(*eid));
+			ast_debug(1, "Seeding global EID '%s'\n",
+				ast_eid_to_str(eid_str, sizeof(eid_str), eid));
+			ast_free(buf);
+			close(s);
+			return;
+		}
+	}
+
+	ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
+		"You will have to set it manually.\n");
+	ast_free(buf);
+	close(s);
+
+	return;
 }
 
+#else
+void ast_set_default_eid(struct ast_eid *eid)
+{
+	int s;
+	int i;
+	struct ifreq *ifr;
+	struct ifreq *ifrp;
+	struct ifconf ifc;
+	char *buf = NULL;
+	char eid_str[20];
+	int bufsz, num_interfaces;
+	unsigned char empty_mac[6] = {0, 0, 0, 0, 0, 0};
+	unsigned char full_mac[6]  = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+	s = socket(AF_INET, SOCK_STREAM, 0);
+	if (s <= 0) {
+		ast_log(LOG_WARNING, "Unable to open socket for seeding global EID. "
+			"You will have to set it manually.\n");
+		return;
+	}
+
+	ifc.ifc_len = 0;
+	ifc.ifc_buf = NULL;
+	if (ioctl(s, SIOCGIFCONF, &ifc) || ifc.ifc_len <= 0) {
+		ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
+			"You will have to set it manually.\n");
+		close(s);
+		return;
+	}
+	bufsz = ifc.ifc_len;
+
+	if (!(buf = ast_malloc(bufsz))) {
+		ast_log(LOG_WARNING, "Unable to allocate memory for seeding global EID. "
+			"You will have to set it manually.\n");
+		close(s);
+		return;
+	}
+
+	ifc.ifc_buf = buf;
+	if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
+		ast_log(LOG_WARNING, "Unable to retrieve ethernet interfaces for seeding global EID. "
+			"You will have to set it manually.\n");
+		ast_free(buf);
+		close(s);
+		return;
+	}
+
+	ifrp = ifc.ifc_req;
+	num_interfaces = ifc.ifc_len / sizeof(*ifr);
+
+	for (i = 0; i < num_interfaces; i++) {
+		ifr = &ifrp[i];
+		if (!ioctl(s, SIOCGIFHWADDR, ifr)) {
+			unsigned char *hwaddr = (unsigned char *) ifr->ifr_hwaddr.sa_data;
+
+			if (!(memcmp(hwaddr, &empty_mac, 6) && memcmp(hwaddr, &full_mac, 6))) {
+				continue;
+			}
+
+			memcpy(eid, hwaddr, sizeof(*eid));
+			ast_debug(1, "Seeding global EID '%s' from '%s' using 'siocgifhwaddr'\n",
+				ast_eid_to_str(eid_str, sizeof(eid_str), eid), ifr->ifr_name);
+			ast_free(buf);
+			close(s);
+			return;
+		}
+	}
+
+	ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. "
+		"You will have to set it manually.\n");
+	ast_free(buf);
+	close(s);
+
+	return;
+}
+#endif /* LINUX */
+
 int ast_str_to_eid(struct ast_eid *eid, const char *s)
 {
 	unsigned int eid_int[6];

-- 
To view, visit https://gerrit.asterisk.org/4116
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Iaa6db87ca78a9a375e47d70e043ae08c1448cb72
Gerrit-PatchSet: 2
Gerrit-Project: asterisk
Gerrit-Branch: 13
Gerrit-Owner: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Anonymous Coward #1000019
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Matt Jordan <mjordan at digium.com>



More information about the asterisk-code-review mailing list