--- libelwix/src/net.c	2013/06/03 14:00:26	1.3
+++ libelwix/src/net.c	2016/08/02 11:57:59	1.15.2.1
@@ -3,7 +3,7 @@
 *  by Michael Pounov <misho@elwix.org>
 *
 * $Author: misho $
-* $Id: net.c,v 1.3 2013/06/03 14:00:26 misho Exp $
+* $Id: net.c,v 1.15.2.1 2016/08/02 11:57:59 misho Exp $
 *
 **************************************************************************
 The ELWIX and AITNET software is distributed under the following
@@ -12,7 +12,7 @@ terms:
 All of the documentation and software included in the ELWIX and AITNET
 Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
 
-Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
+Copyright 2004 - 2016
 	by Michael Pounov <misho@elwix.org>.  All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,76 @@ SUCH DAMAGE.
 #include "global.h"
 
 
+#ifndef __linux__
+static char hexlist[] = "0123456789abcdef";
+
 /*
+ * e_link_ntoa() - String ethernet address from link address
+ *
+ * @sdl = link address
+ * return: =NULL error or !=NULL ethernet address, should be e_free()
+ */
+char *
+e_link_ntoa(const struct sockaddr_dl *sdl)
+{
+	static char obuf[64];
+	char *out = obuf;
+	int i;
+	u_char *in = (u_char*) LLADDR(sdl);
+	u_char *inlim = in + sdl->sdl_alen;
+	int firsttime = 1;
+
+	if (sdl->sdl_nlen) {
+		memcpy(obuf, sdl->sdl_data, sdl->sdl_nlen);
+		out += sdl->sdl_nlen;
+		if (sdl->sdl_alen)
+			*out++ = '!';
+	}
+
+	while (in < inlim) {
+		if (firsttime)
+			firsttime ^= firsttime;
+		else
+			*out++ = ':';
+
+		i = *in++;
+		if (i > 0xf) {
+			out[1] = hexlist[i & 0xf];
+			i >>= 4;
+		} else {
+			out[1] = hexlist[i];
+			i = 0;
+		}
+
+		out[0] = hexlist[i];
+		out += 2;
+	}
+
+	*out = 0;
+	return obuf;
+}
+
+/*
+ * e_link_addr() - String ethernet address to link address
+ *
+ * @mac = ethernet address
+ * @sdl = link address
+ * return: -1 error or 0 ok
+ */
+int
+e_link_addr(const char *mac, struct sockaddr_dl * __restrict sdl)
+{
+	if (!mac || !sdl)
+		return -1;
+	if (!sdl->sdl_len)
+		sdl->sdl_len = sizeof(struct sockaddr_dl);
+
+	link_addr(mac, sdl);
+	return 0;
+}
+#endif
+
+/*
  * e_ether_ntoa() - Convert ethernet address to string
  *
  * @n = ethernet address structure, like struct ether_addr
@@ -55,16 +124,16 @@ SUCH DAMAGE.
  * return: NULL error or !=NULL string a
  */
 char *
-e_ether_ntoa(const struct e_ether_addr *n, char * __restrict a, int len)
+e_ether_ntoa(const ether_addr_t * __restrict n, char * __restrict a, int len)
 {
 	if (!n || !a)
 		return NULL;
 
 	memset(a, 0, len);
-	if (snprintf(a, len, "%02x:%02x:%02x:%02x:%02x:%02x", 
-			n->ether_addr_octet[0], n->ether_addr_octet[1], 
-			n->ether_addr_octet[2], n->ether_addr_octet[3], 
-			n->ether_addr_octet[4], n->ether_addr_octet[5]) < 17)
+	if (snprintf(a, len, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", 
+			n->octet[0], n->octet[1], 
+			n->octet[2], n->octet[3], 
+			n->octet[4], n->octet[5]) < 17)
 		return NULL;
 
 	return a;
@@ -77,26 +146,24 @@ e_ether_ntoa(const struct e_ether_addr *n, char * __re
  * @e = ethernet address structure, like struct ether_addr
  * return: NULL error or !=NULL ethernet address structure
  */
-struct e_ether_addr *
-e_ether_aton(const char *a, struct e_ether_addr *e)
+ether_addr_t *
+e_ether_aton(const char *a, ether_addr_t * __restrict e)
 {                       
 	int i;
-	u_int o0, o1, o2, o3, o4, o5;
 
 	if (!a || !e)
 		return NULL;
 
-	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o0, &o1, &o2, &o3, &o4, &o5);
+	i = sscanf(a, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", 
+			&e->octet[0], 
+			&e->octet[1], 
+			&e->octet[2], 
+			&e->octet[3], 
+			&e->octet[4], 
+			&e->octet[5]);
 	if (i != 6)
 		return NULL;
 
-	e->ether_addr_octet[0] = o0;
-	e->ether_addr_octet[1] = o1;
-	e->ether_addr_octet[2] = o2;
-	e->ether_addr_octet[3] = o3;
-	e->ether_addr_octet[4] = o4;
-	e->ether_addr_octet[5] = o5;
-
 	return e;
 }
 
@@ -136,6 +203,9 @@ e_n2port(sockaddr_t * __restrict addr)
 const char *
 e_n2addr(sockaddr_t * __restrict addr, ait_val_t * __restrict val)
 {
+#ifndef __linux__
+	char *s;
+#endif
 	char str[INET6_ADDRSTRLEN] = { 0 };
 	const char *ret = NULL;
 
@@ -161,6 +231,15 @@ e_n2addr(sockaddr_t * __restrict addr, ait_val_t * __r
 		case AF_LOCAL:
 			ret = addr->sun.sun_path;
 			break;
+#ifndef __linux__
+		case AF_LINK:
+			if (!(s = e_link_ntoa(&addr->sdl))) {
+				LOGERR;
+				return ret;
+			} else
+				ret = s;
+			break;
+#endif
 		default:
 			elwix_SetErr(EPROTONOSUPPORT, "Unsuported address family %d", 
 					addr->sa.sa_family);
@@ -177,25 +256,22 @@ e_n2addr(sockaddr_t * __restrict addr, ait_val_t * __r
  * @psHost = Hostname
  * @port = Port
  * @addr = Network address structure
- * return: NULL error or !=NULL network structure
+ * return: 0 is error or >0 length of network structure
  */
-sockaddr_t *
+socklen_t 
 e_gethostbyname(const char *psHost, u_short port, sockaddr_t * __restrict addr)
 {
 	struct hostent *host = NULL;
 
 	if (!psHost || !addr)
-		return NULL;
+		return 0;
 
 	if (*psHost != '/') {
 		/* resolver */
-		if (!addr->sa.sa_family)
-			host = gethostbyname(psHost);
-		else
-			host = gethostbyname2(psHost, addr->sa.sa_family);
+		host = gethostbyname2(psHost, !strchr(psHost, ':') ? AF_INET : AF_INET6);
 		if (!host) {
 			elwix_SetErr(EINVAL, "Resolver #%d - %s", h_errno, hstrerror(h_errno));
-			return NULL;
+			return 0;
 		} else {
 			memset(addr, 0, sizeof(sockaddr_t));
 			addr->sa.sa_family = host->h_addrtype;
@@ -208,32 +284,66 @@ e_gethostbyname(const char *psHost, u_short port, sock
 
 	switch (addr->sa.sa_family) {
 		case AF_INET:
+#ifndef __linux__
 			addr->sin.sin_len = sizeof(struct sockaddr_in);
+#endif
 			addr->sin.sin_family = AF_INET;
 			addr->sin.sin_port = htons(port);
 			memcpy(&addr->sin.sin_addr, host->h_addr, sizeof addr->sin.sin_addr);
-			return addr;
+			return sizeof addr->sin;
 		case AF_INET6:
+#ifndef __linux__
 			addr->sin6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
 			addr->sin6.sin6_family = AF_INET6;
 			addr->sin6.sin6_port = htons(port);
 			memcpy(&addr->sin6.sin6_addr, host->h_addr, sizeof addr->sin6.sin6_addr);
-			return addr;
+			return sizeof addr->sin6;
 		case AF_LOCAL:
+#ifndef __linux__
 			addr->sun.sun_len = sizeof(struct sockaddr_un);
+#endif
 			addr->sun.sun_family = AF_LOCAL;
 			memset(addr->sun.sun_path, 0, sizeof addr->sun.sun_path);
 			snprintf(addr->sun.sun_path, sizeof addr->sun.sun_path, "%s-%hu", psHost, port);
-			return addr;
+			return sizeof addr->sun;
 		default:
 			elwix_SetErr(EPROTONOSUPPORT, "Unsuported address family %d", addr->sa.sa_family);
 			break;
 	}
 
-	return NULL;
+	return 0;
 }
 
 /*
+ * e_addrlen() - Get address length from network structure
+ *
+ * @addr = address
+ * return: 0 is error or >0 length of network structure
+ */
+socklen_t
+e_addrlen(const sockaddr_t *addr)
+{
+	if (!addr)
+		return 0;
+
+	switch (addr->sa.sa_family) {
+		case AF_INET:
+			return sizeof addr->sin;
+		case AF_INET6:
+			return sizeof addr->sin6;
+		case AF_LOCAL:
+			return sizeof addr->sun;
+#ifndef __linux__
+		case AF_LINK:
+			return sizeof addr->sdl;
+#endif
+	}
+
+	return E_SOCKADDR_MAX;
+}
+
+/*
  * e_addrcmp() - Compare network addresses
  *
  * @a = 1st address
@@ -260,9 +370,13 @@ e_addrcmp(sockaddr_t * __restrict a, sockaddr_t * __re
 				else
 					return memcmp(&a->sin6.sin6_addr, &b->sin6.sin6_addr, 
 							sizeof a->sin6.sin6_addr);
+#ifndef __linux__
 			case AF_LINK:
 				return memcmp(&a->sdl.sdl_data, &b->sdl.sdl_data, 
 						sizeof a->sdl.sdl_data);
+#endif
+			case AF_UNSPEC:
+				return memcmp(a, b, sizeof(sockaddr_t));
 		}
 
 	return (int) !!(a - b);
@@ -323,3 +437,262 @@ e_innet(netaddr_t * __restrict net, inaddr_t * __restr
 
 	return !!ret;
 }
+
+/*
+ * e_getnet() - Get network from string
+ *
+ * @net = Network string (format: <net[/cidr]>)
+ * return: NULL error or !=NULL network should be e_free()
+ */
+netaddr_t *
+e_getnet(const char *net)
+{
+	netaddr_t *n;
+	char *str, *wrk;
+	struct hostent *host;
+
+	n = e_malloc(sizeof(netaddr_t));
+	if (!n) {
+		LOGERR;
+		return NULL;
+	} else
+		memset(n, 0, sizeof(netaddr_t));
+	str = e_strdup(net);
+	if (!str) {
+		LOGERR;
+		e_free(n);
+		return NULL;
+	}
+	wrk = strchr(str, '/');
+	if (wrk)
+		*wrk++ = 0;
+
+	host = gethostbyname2(str, strchr(str, ':') ? AF_INET6 : AF_INET);
+	if (!host) {
+		elwix_SetErr(EINVAL, "Resolver #%d - %s", h_errno, hstrerror(h_errno));
+		e_free(str);
+		e_free(n);
+		return NULL;
+	}
+	switch (host->h_addrtype) {
+		case AF_INET:
+#ifndef __linux__
+			n->addr.sin.sin_len = sizeof(struct sockaddr_in);
+#endif
+			n->addr.sin.sin_family = host->h_addrtype;
+			memcpy(&n->addr.sin.sin_addr, host->h_addr, sizeof n->addr.sin.sin_addr);
+			if (wrk)
+				n->mask.in.s_addr = E_CIDRMASK(strtol(wrk, NULL, 10));
+			else
+				n->mask.in.s_addr = 0xFFFFFFFF;
+			break;
+		case AF_INET6:
+#ifndef __linux__
+			n->addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+			n->addr.sin6.sin6_family = host->h_addrtype;
+			memcpy(&n->addr.sin6.sin6_addr, host->h_addr, sizeof n->addr.sin6.sin6_addr);
+			/* TODO: should support ipv6 mask */
+			break;
+		default:
+			elwix_SetErr(EINVAL, "Unsupported family #%d", host->h_addrtype);
+			e_free(str);
+			e_free(n);
+			return NULL;
+	}
+
+	e_free(str);
+	return n;
+}
+
+/*
+ * e_ether_addr() - Get or set ethernet address from interface name
+ *
+ * @ifname = interface name
+ * @addr = if addr is !=NULL then set new ethernet address
+ * return: NULL error or !=NULL get current ethernet address should be e_free()
+ */
+ether_addr_t *
+e_ether_addr(const char *ifname, ether_addr_t * __restrict addr)
+{
+	ether_addr_t *a = NULL;
+	struct ifaddrs *p, *ifa = NULL;
+	struct ifreq req;
+	int s;
+	sockaddr_t sa = E_SOCKADDR_INIT;
+
+	memset(&req, 0, sizeof req);
+	if (!ifname)
+		return NULL;
+
+	getifaddrs(&ifa);
+	for (p = ifa; p && p->ifa_name; p = p->ifa_next) {
+#ifndef __linux__
+		if (p->ifa_name && !strcmp(p->ifa_name, ifname) && p->ifa_addr && 
+				p->ifa_addr->sa_family == AF_LINK) {
+			a = e_malloc(sizeof(ether_addr_t));
+			if (a)
+				memcpy(a, LLADDR((struct sockaddr_dl*) p->ifa_addr), 
+						sizeof(ether_addr_t));
+
+			/* should set mac address */
+			if (addr && (s = socket(AF_LOCAL, SOCK_DGRAM, 0)) > 0) {
+				strlcpy(req.ifr_name, ifname, sizeof req.ifr_name);
+				sa.sa.sa_family = AF_LINK;
+				sa.sa.sa_len = sizeof(ether_addr_t);
+				memcpy(sa.sa.sa_data, addr, sizeof(ether_addr_t));
+				req.ifr_ifru.ifru_addr = sa.sa;
+				ioctl(s, SIOCSIFLLADDR, &req);
+				close(s);
+			}
+			break;
+		}
+#else
+		if (p->ifa_name && !strcmp(p->ifa_name, ifname)) {
+			s = socket(AF_INET, SOCK_DGRAM, 0);
+			if (s == -1)
+				break;
+			strlcpy(req.ifr_name, ifname, sizeof req.ifr_name);
+			if (!ioctl(s, SIOCGIFHWADDR, &req)) {
+				a = e_malloc(sizeof(ether_addr_t));
+				if (a)
+					memcpy(a, req.ifr_addr.sa_data, sizeof(ether_addr_t));
+
+				/* should set mac address */
+				if (addr) {
+					memset(&req, 0, sizeof req);
+					strlcpy(req.ifr_name, ifname, sizeof req.ifr_name);
+					sa.sa.sa_family = ARPHRD_ETHER;
+					memcpy(sa.sa.sa_data, addr, sizeof(ether_addr_t));
+					req.ifr_hwaddr = sa.sa;
+					ioctl(s, SIOCSIFHWADDR, &req);
+				}
+			}
+			close(s);
+			break;
+		}
+#endif
+	}
+	freeifaddrs(ifa);
+
+	return a;
+}
+
+/*
+ * e_get1stiface() - Get first interface of host
+ *
+ * @szIface = interface string buffer
+ * @iflen = size of interface buffer
+ * return: -1 error or 0 ok
+ */
+int
+e_get1stiface(char *szIface, int iflen)
+{
+	struct ifaddrs *ifa;
+
+	if (!szIface || !iflen)
+		return -1;
+
+	getifaddrs(&ifa);
+	strlcpy(szIface, ifa->ifa_name, iflen);
+	freeifaddrs(ifa);
+	return 0;
+}
+
+#ifndef __linux__
+/*
+ * e_getifacebyname() - Get interface and make network structure
+ *
+ * @psIface = Interface, if =NULL first interface
+ * @addr = Network address structure
+ * return: NULL error or !=NULL network structure
+ */
+sockaddr_t *
+e_getifacebyname(const char *psIface, sockaddr_t * __restrict addr)
+{
+	char szIface[64] = { [0 ... 63] = 0 };
+	struct ifaddrs *p, *ifa = NULL;
+
+	if (!addr)
+		return NULL;
+
+	memset(addr, 0, sizeof(sockaddr_t));
+	getifaddrs(&ifa);
+	strlcpy(szIface, psIface ? psIface : ifa->ifa_name, sizeof szIface);
+	for (p = ifa; p && p->ifa_name; p = p->ifa_next)
+		if (p->ifa_name && !strcmp(p->ifa_name, szIface) && p->ifa_addr && 
+				p->ifa_addr->sa_family == AF_LINK) {
+			memcpy(&addr->sdl, p->ifa_addr, sizeof(struct sockaddr_dl));
+			break;
+		}
+	freeifaddrs(ifa);
+
+	return addr;
+}
+
+/*
+ * e_getlinkbyname() - Get host ethernet address and make network structure
+ *
+ * @psHost = Host ethernet address
+ * @addr = Network address structure
+ * return: NULL error or !=NULL network structure
+ */
+sockaddr_t *
+e_getlinkbyname(const char *psHost, sockaddr_t * __restrict addr)
+{
+	ait_val_t v;
+	sockaddr_t *a = addr;
+
+	if (!psHost || !addr)
+		return NULL;
+	else
+		memset(addr, 0, sizeof(sockaddr_t));
+
+	AIT_INIT_VAL2(&v, string);
+	if (!strchr(psHost, '.'))
+		AIT_SET_STR(&v, ":");
+	AIT_SET_STRCAT(&v, psHost);
+
+	addr->sdl.sdl_len = sizeof(struct sockaddr_dl);
+	if (e_link_addr(AIT_GET_STR(&v), &addr->sdl))
+		a = NULL;
+
+	AIT_FREE_VAL(&v);
+	return a;
+}
+
+/*
+ * e_getlinkbyether() - Get ethernet address and make network structure
+ *
+ * @mac = Ethernet address
+ * @idx = Interface index
+ * @type = Interface type
+ * @iface = Interface name
+ * @addr = Network address structure
+ * return: NULL error or !=NULL network structure
+ */
+sockaddr_t *
+e_getlinkbyether(const ether_addr_t * __restrict mac, u_short idx, u_char type, 
+		const char *iface, sockaddr_t * __restrict addr)
+{
+	sockaddr_t *a = addr;
+
+	if (!addr)
+		return NULL;
+	else
+		memset(addr, 0, sizeof(sockaddr_t));
+
+	addr->sdl.sdl_len = sizeof(struct sockaddr_dl);
+	addr->sdl.sdl_family = AF_LINK;
+	addr->sdl.sdl_index = idx;
+	addr->sdl.sdl_type = type;
+	if (iface && *iface) {
+		addr->sdl.sdl_nlen = strlen(iface);
+		memcpy(addr->sdl.sdl_data, iface, addr->sdl.sdl_nlen);
+	}
+	addr->sdl.sdl_alen = sizeof(ether_addr_t);
+	memcpy(LLADDR(&addr->sdl), mac, addr->sdl.sdl_alen);
+
+	return a;
+}
+#endif