aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2017-10-12 17:56:55 +0200
committerPau Espin Pedrol <pespin@sysmocom.de>2017-10-13 11:08:54 +0200
commitf9108cc53168b72bc35152b93a647e6c69f8a8c0 (patch)
treedf640bc3f8505b7416d20fae332220fc6e51689d
parent40d8c08b8959aba92816a64573fefb18b7c4fd85 (diff)
WIP
-rw-r--r--ggsn/ggsn.c27
-rw-r--r--lib/in46_addr.c52
-rw-r--r--lib/in46_addr.h3
-rw-r--r--lib/ippool.c4
-rw-r--r--lib/ippool.h8
-rw-r--r--lib/tun.c44
-rw-r--r--lib/tun.h9
7 files changed, 121 insertions, 26 deletions
diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c
index 4f90599..a9c319d 100644
--- a/ggsn/ggsn.c
+++ b/ggsn/ggsn.c
@@ -1,13 +1,13 @@
-/*
+/*
* OsmoGGSN - Gateway GPRS Support Node
* Copyright (C) 2002, 2003, 2004 Mondru AB.
* Copyright (C) 2017 by Harald Welte <laforge@gnumonks.org>
- *
+ *
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
- *
+ *
*/
/* ggsn.c
@@ -149,8 +149,8 @@ int apn_stop(struct apn_ctx *apn, bool force)
/* actually start the APN with its current config */
int apn_start(struct apn_ctx *apn)
{
- int ipv4_blacklist_size = 0;
- int ipv6_blacklist_size = 0;
+ int ipv4_blacklist_size = 0, ipv6_blacklist_size = 0;
+ struct in46_prefix ipv4_tun_ip, ipv6_tun_ip;
int ippool_flags = IPPOOL_NONETWORK | IPPOOL_NOBROADCAST;
if (apn->started)
@@ -183,7 +183,6 @@ int apn_start(struct apn_ctx *apn)
apn_stop(apn, false);
return -1;
}
- ipv4_blacklist_size++;
}
if (apn->v6.cfg.ifconfig_prefix.addr.len) {
@@ -197,7 +196,6 @@ int apn_start(struct apn_ctx *apn)
apn_stop(apn, false);
return -1;
}
- ipv6_blacklist_size++;
}
if (apn->tun.cfg.ipup_script) {
@@ -207,12 +205,13 @@ int apn_start(struct apn_ctx *apn)
}
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_ipv6_linklocal_get(apn->tun.tun, &ipv6_tun_ip) < 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_ip.addr.v6;
}
/* set back-pointer from TUN device to APN */
@@ -235,9 +234,13 @@ int apn_start(struct apn_ctx *apn)
if (apn->v4.cfg.dynamic_prefix.addr.len) {
LOGPAPN(LOGL_INFO, apn, "Creating IPv4 pool %s\n",
in46p_ntoa(&apn->v4.cfg.dynamic_prefix));
+ if(tun_ipv4_local_get(apn->tun.tun, &ipv4_tun_ip) == 0)
+ ipv4_blacklist_size = 1;
+ LOGPAPN(LOGL_INFO, apn, "Blacklist IPv4 tun IP %s\n",
+ in46p_ntoa(&ipv4_tun_ip));
if (ippool_new(&apn->v4.pool, &apn->v4.cfg.dynamic_prefix,
&apn->v4.cfg.static_prefix, ippool_flags,
- &apn->v4.cfg.ifconfig_prefix, ipv4_blacklist_size)) {
+ &ipv4_tun_ip, ipv4_blacklist_size)) {
LOGPAPN(LOGL_ERROR, apn, "Failed to create IPv4 pool\n");
apn_stop(apn, false);
return -1;
@@ -248,9 +251,13 @@ int apn_start(struct apn_ctx *apn)
if (apn->v6.cfg.dynamic_prefix.addr.len) {
LOGPAPN(LOGL_INFO, apn, "Creating IPv6 pool %s\n",
in46p_ntoa(&apn->v6.cfg.dynamic_prefix));
+ if(tun_ipv6_linklocal_get(apn->tun.tun, &ipv6_tun_ip) == 0)
+ ipv6_blacklist_size = 1;
+ LOGPAPN(LOGL_INFO, apn, "Blacklist IPv6 tun IP %s\n",
+ in46p_ntoa(&ipv4_tun_ip));
if (ippool_new(&apn->v6.pool, &apn->v6.cfg.dynamic_prefix,
&apn->v6.cfg.static_prefix, ippool_flags,
- &apn->v6.cfg.ifconfig_prefix, ipv6_blacklist_size)) {
+ &ipv6_tun_ip, ipv6_blacklist_size)) {
LOGPAPN(LOGL_ERROR, apn, "Failed to create IPv6 pool\n");
apn_stop(apn, false);
return -1;
diff --git a/lib/in46_addr.c b/lib/in46_addr.c
index f78a40b..c1d6c42 100644
--- a/lib/in46_addr.c
+++ b/lib/in46_addr.c
@@ -6,7 +6,7 @@
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
- *
+ *
*/
#include "../lib/in46_addr.h"
@@ -195,6 +195,56 @@ int in46a_within_mask(const struct in46_addr *addr, const struct in46_addr *net,
}
}
+unsigned int netmask_ipv4_prefixlen(const struct in_addr *netmask)
+{
+ struct in_addr tmp = *netmask;
+ int neg_prefix = 0;
+ if(tmp.s_addr == 0)
+ return 32;
+ while ((tmp.s_addr & 0x01) == 0 ) {
+ neg_prefix++;
+ tmp.s_addr = tmp.s_addr >> 1;
+ }
+ return 32 - neg_prefix;
+}
+
+unsigned int netmask_ipv6_prefixlen(const struct in6_addr *netmask)
+{
+
+ #if defined(__linux__)
+ #define ADDRFIELD(i) s6_addr32[i]
+ #else
+ #define ADDRFIELD(i) __u6_addr.__u6_addr32[i]
+ #endif
+
+ struct in6_addr tmp = *netmask;
+ int neg_prefix = 0;
+ for (int i = 0; i < 4; i++) {
+ if(tmp.ADDRFIELD(i) == 0)
+ continue;
+ while ((tmp.ADDRFIELD(i) & 0x01) == 0 ) {
+ neg_prefix++;
+ tmp.ADDRFIELD(i) = tmp.ADDRFIELD(i) >> 1;
+ }
+ }
+ #undef ADDRFIELD
+
+ return 128 - neg_prefix;
+}
+
+unsigned int in46a_prefixlen(const struct in46_addr *netmask)
+{
+ switch (netmask->len) {
+ case 4:
+ return netmask_ipv4_prefixlen(&netmask->v4);
+ case 16:
+ return netmask_ipv6_prefixlen(&netmask->v6);
+ default:
+ OSMO_ASSERT(0);
+ return 0;
+ }
+}
+
/*! Convert given PDP End User Address to in46_addr
* \returns 0 on success; negative on error */
int in46a_to_eua(const struct in46_addr *src, struct ul66_t *eua)
diff --git a/lib/in46_addr.h b/lib/in46_addr.h
index ce2df14..109a933 100644
--- a/lib/in46_addr.h
+++ b/lib/in46_addr.h
@@ -27,6 +27,9 @@ extern const char *in46p_ntoa(const struct in46_prefix *in46p);
extern int in46a_equal(const struct in46_addr *a, const struct in46_addr *b);
extern int in46a_prefix_equal(const struct in46_addr *a, const struct in46_addr *b);
extern int in46a_within_mask(const struct in46_addr *addr, const struct in46_addr *net, size_t prefixlen);
+extern unsigned int netmask_ipv4_prefixlen(const struct in_addr *netmask);
+extern unsigned int netmask_ipv6_prefixlen(const struct in6_addr *netmask);
+extern unsigned int in46a_prefixlen(const struct in46_addr *netmask);
int in46a_to_eua(const struct in46_addr *src, struct ul66_t *eua);
int in46a_from_eua(const struct ul66_t *eua, struct in46_addr *dst);
diff --git a/lib/ippool.c b/lib/ippool.c
index 2a41e58..55133ce 100644
--- a/lib/ippool.c
+++ b/lib/ippool.c
@@ -7,7 +7,7 @@
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
- *
+ *
*/
#include <sys/types.h>
@@ -384,7 +384,7 @@ int ippool_newip(struct ippool_t *this, struct ippoolm_t **member,
uint32_t hash;
/* If static:
- * Look in dynaddr.
+ * Look in dynaddr.
* If found remove from firstdyn/lastdyn linked list.
* Else allocate from stataddr.
* Remove from firststat/laststat linked list.
diff --git a/lib/ippool.h b/lib/ippool.h
index 704b887..04a86b8 100644
--- a/lib/ippool.h
+++ b/lib/ippool.h
@@ -1,12 +1,12 @@
-/*
+/*
* IP address pool functions.
* Copyright (C) 2003, 2004 Mondru AB.
- *
+ *
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
- *
+ *
*/
#ifndef _IPPOOL_H
@@ -23,7 +23,7 @@
When initialising a new address pool it should be possible to pass
a string of CIDR format networks: "10.0.0.0/24 10.15.0.0/20" would
translate to 256 addresses starting at 10.0.0.0 and 1024 addresses
- starting at 10.15.0.0.
+ starting at 10.15.0.0.
The above also applies to IPv6 which can be specified as described
in RFC2373.
diff --git a/lib/tun.c b/lib/tun.c
index 35d371e..14d5d4d 100644
--- a/lib/tun.c
+++ b/lib/tun.c
@@ -1,13 +1,13 @@
-/*
+/*
* TUN interface functions.
* Copyright (C) 2002, 2003, 2004 Mondru AB.
* Copyright (C) 2017 by Harald Welte <laforge@gnumonks.org>
- *
+ *
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
- *
+ *
*/
/*
@@ -751,8 +751,39 @@ int tun_runscript(struct tun_t *tun, char *script)
#include <ifaddrs.h>
+/* obtain the local address of the tun device */
+int tun_ipv4_local_get(const struct tun_t *tun, struct in46_prefix *prefix)
+{
+ struct ifaddrs *ifaddr, *ifa;
+
+ if (getifaddrs(&ifaddr) == -1) {
+ return -1;
+ }
+
+ for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+ struct sockaddr_in *sin4 = (struct sockaddr_in *) ifa->ifa_addr;
+ struct sockaddr_in *netmask4 = (struct sockaddr_in *) ifa->ifa_netmask;
+ if (ifa->ifa_addr == NULL)
+ continue;
+
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+
+ if (strcmp(ifa->ifa_name, tun->devname))
+ continue;
+
+ prefix->addr.len = sizeof(sin4->sin_addr);
+ prefix->addr.v4 = sin4->sin_addr;
+ prefix->prefixlen = netmask_ipv4_prefixlen(&netmask4->sin_addr);
+ freeifaddrs(ifaddr);
+ return 0;
+ }
+ freeifaddrs(ifaddr);
+ return -1;
+}
+
/* obtain the link-local address of the tun device */
-int tun_ipv6_linklocal_get(const struct tun_t *tun, struct in6_addr *ia)
+int tun_ipv6_linklocal_get(const struct tun_t *tun, struct in46_prefix *prefix)
{
struct ifaddrs *ifaddr, *ifa;
static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
@@ -763,6 +794,7 @@ int tun_ipv6_linklocal_get(const struct tun_t *tun, struct in6_addr *ia)
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) ifa->ifa_addr;
+ struct sockaddr_in6 *netmask6 = (struct sockaddr_in6 *) ifa->ifa_netmask;
if (ifa->ifa_addr == NULL)
continue;
@@ -775,7 +807,9 @@ int tun_ipv6_linklocal_get(const struct tun_t *tun, struct in6_addr *ia)
if (memcmp(sin6->sin6_addr.s6_addr, ll_prefix, sizeof(ll_prefix)))
continue;
- *ia = sin6->sin6_addr;
+ prefix->addr.len = sizeof(sin6->sin6_addr);
+ prefix->addr.v6 = sin6->sin6_addr;
+ prefix->prefixlen = netmask_ipv6_prefixlen(&netmask6->sin6_addr);
freeifaddrs(ifaddr);
return 0;
}
diff --git a/lib/tun.h b/lib/tun.h
index 95fff26..114c471 100644
--- a/lib/tun.h
+++ b/lib/tun.h
@@ -1,13 +1,13 @@
-/*
+/*
* TUN interface functions.
* Copyright (C) 2002, 2003 Mondru AB.
* Copyright (C) 2017 by Harald Welte <laforge@gnumonks.org>
- *
+ *
* The contents of this file may be used under the terms of the GNU
* General Public License Version 2, provided that the above copyright
* notice and this permission notice is included in all copies or
* substantial portions of the software.
- *
+ *
*/
#ifndef _TUN_H
@@ -85,6 +85,7 @@ extern int tun_set_cb_ind(struct tun_t *this,
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_ipv4_local_get(const struct tun_t *tun, struct in46_prefix *prefix);
+int tun_ipv6_linklocal_get(const struct tun_t *tun, struct in46_prefix *prefix);
#endif /* !_TUN_H */