[PATCH] osmo-ggsn[master]: tun: Convert tun_ipv6_linklocal_get to be more generic

Pau Espin Pedrol gerrit-no-reply at lists.osmocom.org
Mon Oct 16 13:03:32 UTC 2017


Review at  https://gerrit.osmocom.org/4291

tun: Convert tun_ipv6_linklocal_get to be more generic

Add support for IPv4 and IPv6 global IPs. Also return the prefix length
of the IP address by using a in46_prefix.

Change-Id: I277af191dc611b6bbcb83479f4ae338083740322
---
M ggsn/ggsn.c
M lib/tun.c
M lib/tun.h
3 files changed, 55 insertions(+), 14 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/osmo-ggsn refs/changes/91/4291/1

diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c
index 29d8473..c04d32e 100644
--- a/ggsn/ggsn.c
+++ b/ggsn/ggsn.c
@@ -149,6 +149,7 @@
 /* actually start the APN with its current config */
 int apn_start(struct apn_ctx *apn)
 {
+	struct in46_prefix ipv6_tun_linklocal_ip;
 	if (apn->started)
 		return 0;
 
@@ -201,12 +202,13 @@
 		}
 
 		if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6)) {
-			if (tun_ipv6_linklocal_get(apn->tun.tun, &apn->v6_lladdr) < 0) {
+			if (tun_ip_local_get(apn->tun.tun, &ipv6_tun_linklocal_ip, IP_TYPE_IPv6_LINK) < 0) {
 				LOGPAPN(LOGL_ERROR, apn, "Cannot obtain IPv6 link-local address of "
 					"interface: %s\n", strerror(errno));
 				apn_stop(apn, false);
 				return -1;
 			}
+			apn->v6_lladdr = ipv6_tun_linklocal_ip.addr.v6;
 		}
 
 		/* set back-pointer from TUN device to APN */
diff --git a/lib/tun.c b/lib/tun.c
index 7662146..e8b55db 100644
--- a/lib/tun.c
+++ b/lib/tun.c
@@ -751,34 +751,63 @@
 
 #include <ifaddrs.h>
 
-/* obtain the link-local address of the tun device */
-int tun_ipv6_linklocal_get(const struct tun_t *tun, struct in6_addr *ia)
+/*! Obtain the local address of the tun device.
+ *  \param[in] tun Target device owning the IP
+ *  \param[out] prefix Structure to fill with an IPv4/6 and prefix length
+ *  \param[in] flags Specify which kind of IP to look for: IP_TYPE_IPv4, IP_TYPE_IPv6_LINK, IP_TYPE_IPv6_GLOBAL
+ *  \returns 0 if the IP was found and prefix structure was filled successfully, -1 othwerise
+ */
+int tun_ip_local_get(const struct tun_t *tun, struct in46_prefix *prefix, int flags)
 {
-	struct ifaddrs *ifaddr, *ifa;
 	static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
+	struct ifaddrs *ifaddr, *ifa;
+	struct in46_addr netmask;
+	bool is_ipv6_ll;
 
 	if (getifaddrs(&ifaddr) == -1) {
 		return -1;
 	}
 
 	for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
-		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ifa->ifa_addr;
 		if (ifa->ifa_addr == NULL)
-			continue;
-
-		if (ifa->ifa_addr->sa_family != AF_INET6)
 			continue;
 
 		if (strcmp(ifa->ifa_name, tun->devname))
 			continue;
 
-		if (memcmp(sin6->sin6_addr.s6_addr, ll_prefix, sizeof(ll_prefix)))
-			continue;
+		if (ifa->ifa_addr->sa_family == AF_INET && (flags & IP_TYPE_IPv4)) {
+			struct sockaddr_in *sin4 = (struct sockaddr_in *) ifa->ifa_addr;
+			struct sockaddr_in *netmask4 = (struct sockaddr_in *) ifa->ifa_netmask;
 
-		*ia = sin6->sin6_addr;
-		freeifaddrs(ifaddr);
-		return 0;
+			netmask.len = sizeof(netmask4->sin_addr);
+			netmask.v4 = netmask4->sin_addr;
+			prefix->addr.len = sizeof(sin4->sin_addr);
+			prefix->addr.v4 = sin4->sin_addr;
+			prefix->prefixlen = in46a_netmasklen(&netmask);
+			freeifaddrs(ifaddr);
+			return 0;
+		}
+
+		if (ifa->ifa_addr->sa_family == AF_INET6 && (flags & IP_TYPE_IPv6)) {
+			struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ifa->ifa_addr;
+			struct sockaddr_in6 *netmask6 = (struct sockaddr_in6 *) ifa->ifa_netmask;
+
+			is_ipv6_ll = !memcmp(sin6->sin6_addr.s6_addr, ll_prefix, sizeof(ll_prefix));
+			if ((flags & IP_TYPE_IPv6_GLOBAL) && is_ipv6_ll)
+				continue;
+			if ((flags & IP_TYPE_IPv6_LINK) && !is_ipv6_ll)
+				continue;
+
+			netmask.len = sizeof(netmask6->sin6_addr);
+			netmask.v6 = netmask6->sin6_addr;
+			prefix->addr.len = sizeof(sin6->sin6_addr);
+			prefix->addr.v6 = sin6->sin6_addr;
+			prefix->prefixlen = in46a_netmasklen(&netmask);
+			freeifaddrs(ifaddr);
+			return 0;
+		}
 	}
+
 	freeifaddrs(ifaddr);
 	return -1;
 }
diff --git a/lib/tun.h b/lib/tun.h
index f63be50..c50f907 100644
--- a/lib/tun.h
+++ b/lib/tun.h
@@ -23,6 +23,16 @@
 #define TUN_NLBUFSIZE   1024
 
 #include "config.h"
+
+/* ipv6 ip type flags for tun_ipv6_local_get() */
+enum {
+	IP_TYPE_IPv4 = 1,
+	IP_TYPE_IPv6_LINK = 2,
+	IP_TYPE_IPv6_GLOBAL = 4,
+};
+#define IP_TYPE_IPv6 (IP_TYPE_IPv6_LINK | IP_TYPE_IPv6_GLOBAL)
+
+
 #ifndef HAVE_IPHDR
 struct iphdr
   {
@@ -85,6 +95,6 @@
 
 extern int tun_runscript(struct tun_t *tun, char *script);
 
-int tun_ipv6_linklocal_get(const struct tun_t *tun, struct in6_addr *ia);
+int tun_ip_local_get(const struct tun_t *tun, struct in46_prefix *prefix, int flags);
 
 #endif /* !_TUN_H */

-- 
To view, visit https://gerrit.osmocom.org/4291
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I277af191dc611b6bbcb83479f4ae338083740322
Gerrit-PatchSet: 1
Gerrit-Project: osmo-ggsn
Gerrit-Branch: master
Gerrit-Owner: Pau Espin Pedrol <pespin at sysmocom.de>


More information about the gerrit-log mailing list