This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
Pau Espin Pedrol gerrit-no-reply at lists.osmocom.orgPau Espin Pedrol has submitted this change and it was merged. Change subject: tun: Convert tun_ipv6_linklocal_get to be more generic ...................................................................... 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, 67 insertions(+), 15 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c index 29d8473..ff760cf 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, 1, IP_TYPE_IPv6_LINK) < 1) { 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..6bcc13b 100644 --- a/lib/tun.c +++ b/lib/tun.c @@ -751,34 +751,73 @@ #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_list List of prefix structures to fill with each IPv4/6 and prefix length found. + * \param[in] prefix_size Amount of elements allowed to be fill in the prefix_list array. + * \param[in] flags Specify which kind of IP to look for: IP_TYPE_IPv4, IP_TYPE_IPv6_LINK, IP_TYPE_IPv6_NONLINK + * \returns The number of ips found following the criteria specified by flags, -1 on error. + * + * This function will fill prefix_list with up to prefix_size IPs following the + * criteria specified by flags parameter. It returns the number of IPs matching + * the criteria. As a result, the number returned can be bigger than + * prefix_size. It can be used with prefix_size=0 to get an estimate of the size + * needed for prefix_list. + */ +int tun_ip_local_get(const struct tun_t *tun, struct in46_prefix *prefix_list, size_t prefix_size, 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; + size_t count = 0; + 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; + if (count < prefix_size) { + netmask.len = sizeof(netmask4->sin_addr); + netmask.v4 = netmask4->sin_addr; + prefix_list[count].addr.len = sizeof(sin4->sin_addr); + prefix_list[count].addr.v4 = sin4->sin_addr; + prefix_list[count].prefixlen = in46a_netmasklen(&netmask); + } + count++; + } + + 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_NONLINK) && is_ipv6_ll) + continue; + if ((flags & IP_TYPE_IPv6_LINK) && !is_ipv6_ll) + continue; + + if (count < prefix_size) { + netmask.len = sizeof(netmask6->sin6_addr); + netmask.v6 = netmask6->sin6_addr; + prefix_list[count].addr.len = sizeof(sin6->sin6_addr); + prefix_list[count].addr.v6 = sin6->sin6_addr; + prefix_list[count].prefixlen = in46a_netmasklen(&netmask); + } + count++; + } } + freeifaddrs(ifaddr); - return -1; + return count; } diff --git a/lib/tun.h b/lib/tun.h index f63be50..0b960e5 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_NONLINK = 4, +}; +#define IP_TYPE_IPv6 (IP_TYPE_IPv6_LINK | IP_TYPE_IPv6_NONLINK) + + #ifndef HAVE_IPHDR struct iphdr { @@ -85,6 +95,7 @@ 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_list, + size_t prefix_size, int flags); #endif /* !_TUN_H */ -- To view, visit https://gerrit.osmocom.org/4291 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I277af191dc611b6bbcb83479f4ae338083740322 Gerrit-PatchSet: 2 Gerrit-Project: osmo-ggsn Gerrit-Branch: master Gerrit-Owner: Pau Espin Pedrol <pespin at sysmocom.de> Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: Pau Espin Pedrol <pespin at sysmocom.de>