summaryrefslogtreecommitdiff
path: root/vpn/vpn-ipconfig.c
diff options
context:
space:
mode:
authorJukka Rissanen <jukka.rissanen@linux.intel.com>2012-11-12 14:07:21 +0200
committerPatrik Flykt <patrik.flykt@linux.intel.com>2012-11-23 12:58:50 +0200
commit4ba04eb6172f898402e0aa66f0dc8f564a12279f (patch)
tree7a67e489ea3de6f65e65d6034b2a0951db709cd0 /vpn/vpn-ipconfig.c
parenta426464354273a5586612b6577288e3662e3f8ac (diff)
downloadconnman-4ba04eb6172f898402e0aa66f0dc8f564a12279f.tar.gz
connman-4ba04eb6172f898402e0aa66f0dc8f564a12279f.tar.bz2
connman-4ba04eb6172f898402e0aa66f0dc8f564a12279f.zip
vpn: New vpn daemon that handles vpn connections and clients
Diffstat (limited to 'vpn/vpn-ipconfig.c')
-rw-r--r--vpn/vpn-ipconfig.c450
1 files changed, 450 insertions, 0 deletions
diff --git a/vpn/vpn-ipconfig.c b/vpn/vpn-ipconfig.c
new file mode 100644
index 00000000..cb5167f0
--- /dev/null
+++ b/vpn/vpn-ipconfig.c
@@ -0,0 +1,450 @@
+/*
+ *
+ * ConnMan VPN daemon
+ *
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <linux/if_link.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <arpa/inet.h>
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP 0x10000
+#endif
+
+#include <gdbus.h>
+
+#include "../src/connman.h"
+
+#include "vpn.h"
+
+struct vpn_ipconfig {
+ int refcount;
+ int index;
+ int family;
+ connman_bool_t enabled;
+ struct connman_ipaddress *address;
+ struct connman_ipaddress *system;
+};
+
+struct vpn_ipdevice {
+ int index;
+ char *ifname;
+ unsigned short type;
+ unsigned int flags;
+ char *address;
+ uint16_t mtu;
+
+ GSList *address_list;
+ char *ipv4_gateway;
+ char *ipv6_gateway;
+
+ char *pac;
+};
+
+static GHashTable *ipdevice_hash = NULL;
+
+unsigned char __vpn_ipconfig_netmask_prefix_len(const char *netmask)
+{
+ unsigned char bits;
+ in_addr_t mask;
+ in_addr_t host;
+
+ if (netmask == NULL)
+ return 32;
+
+ mask = inet_network(netmask);
+ host = ~mask;
+
+ /* a valid netmask must be 2^n - 1 */
+ if ((host & (host + 1)) != 0)
+ return -1;
+
+ bits = 0;
+ for (; mask; mask <<= 1)
+ ++bits;
+
+ return bits;
+}
+
+const char *__vpn_ipconfig_get_peer(struct vpn_ipconfig *ipconfig)
+{
+ if (ipconfig->address == NULL)
+ return NULL;
+
+ return ipconfig->address->peer;
+}
+
+unsigned short __vpn_ipconfig_get_type_from_index(int index)
+{
+ struct vpn_ipdevice *ipdevice;
+
+ ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
+ if (ipdevice == NULL)
+ return ARPHRD_VOID;
+
+ return ipdevice->type;
+}
+
+unsigned int __vpn_ipconfig_get_flags_from_index(int index)
+{
+ struct vpn_ipdevice *ipdevice;
+
+ ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
+ if (ipdevice == NULL)
+ return 0;
+
+ return ipdevice->flags;
+}
+
+void __vpn_ipconfig_foreach(void (*function) (int index,
+ void *user_data), void *user_data)
+{
+ GList *list, *keys;
+
+ keys = g_hash_table_get_keys(ipdevice_hash);
+ if (keys == NULL)
+ return;
+
+ for (list = g_list_first(keys); list; list = g_list_next(list)) {
+ int index = GPOINTER_TO_INT(list->data);
+
+ function(index, user_data);
+ }
+
+ g_list_free(keys);
+}
+
+void __vpn_ipconfig_set_local(struct vpn_ipconfig *ipconfig,
+ const char *address)
+{
+ if (ipconfig->address == NULL)
+ return;
+
+ g_free(ipconfig->address->local);
+ ipconfig->address->local = g_strdup(address);
+}
+
+const char *__vpn_ipconfig_get_local(struct vpn_ipconfig *ipconfig)
+{
+ if (ipconfig->address == NULL)
+ return NULL;
+
+ return ipconfig->address->local;
+}
+
+void __vpn_ipconfig_set_peer(struct vpn_ipconfig *ipconfig,
+ const char *address)
+{
+ if (ipconfig->address == NULL)
+ return;
+
+ g_free(ipconfig->address->peer);
+ ipconfig->address->peer = g_strdup(address);
+}
+
+void __vpn_ipconfig_set_broadcast(struct vpn_ipconfig *ipconfig,
+ const char *broadcast)
+{
+ if (ipconfig->address == NULL)
+ return;
+
+ g_free(ipconfig->address->broadcast);
+ ipconfig->address->broadcast = g_strdup(broadcast);
+}
+
+void __vpn_ipconfig_set_gateway(struct vpn_ipconfig *ipconfig,
+ const char *gateway)
+{
+ DBG("");
+
+ if (ipconfig->address == NULL)
+ return;
+ g_free(ipconfig->address->gateway);
+ ipconfig->address->gateway = g_strdup(gateway);
+}
+
+const char *
+__vpn_ipconfig_get_gateway(struct vpn_ipconfig *ipconfig)
+{
+ if (ipconfig->address == NULL)
+ return NULL;
+
+ return ipconfig->address->gateway;
+}
+
+void __vpn_ipconfig_set_prefixlen(struct vpn_ipconfig *ipconfig,
+ unsigned char prefixlen)
+{
+ if (ipconfig->address == NULL)
+ return;
+
+ ipconfig->address->prefixlen = prefixlen;
+}
+
+unsigned char
+__vpn_ipconfig_get_prefixlen(struct vpn_ipconfig *ipconfig)
+{
+ if (ipconfig->address == NULL)
+ return 0;
+
+ return ipconfig->address->prefixlen;
+}
+
+int __vpn_ipconfig_address_add(struct vpn_ipconfig *ipconfig, int family)
+{
+ DBG("ipconfig %p family %d", ipconfig, family);
+
+ if (ipconfig == NULL)
+ return -EINVAL;
+
+ if (family == AF_INET)
+ return connman_inet_set_address(ipconfig->index,
+ ipconfig->address);
+ else if (family == AF_INET6)
+ return connman_inet_set_ipv6_address(ipconfig->index,
+ ipconfig->address);
+
+ return 0;
+}
+
+int __vpn_ipconfig_gateway_add(struct vpn_ipconfig *ipconfig, int family)
+{
+ DBG("ipconfig %p family %d", ipconfig, family);
+
+ if (ipconfig == NULL || ipconfig->address == NULL)
+ return -EINVAL;
+
+ DBG("family %d gw %s peer %s", family,
+ ipconfig->address->gateway, ipconfig->address->peer);
+
+ if (family == AF_INET)
+ connman_inet_add_host_route(ipconfig->index,
+ ipconfig->address->gateway,
+ ipconfig->address->peer);
+ else if (family == AF_INET6)
+ connman_inet_add_ipv6_host_route(ipconfig->index,
+ ipconfig->address->gateway,
+ ipconfig->address->peer);
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct vpn_ipconfig *create_ipv6config(int index)
+{
+ struct vpn_ipconfig *ipv6config;
+
+ DBG("index %d", index);
+
+ ipv6config = g_try_new0(struct vpn_ipconfig, 1);
+ if (ipv6config == NULL)
+ return NULL;
+
+ ipv6config->refcount = 1;
+
+ ipv6config->index = index;
+ ipv6config->enabled = FALSE;
+ ipv6config->family = AF_INET6;
+
+ ipv6config->address = connman_ipaddress_alloc(AF_INET6);
+ if (ipv6config->address == NULL) {
+ g_free(ipv6config);
+ return NULL;
+ }
+
+ ipv6config->system = connman_ipaddress_alloc(AF_INET6);
+
+ DBG("ipconfig %p", ipv6config);
+
+ return ipv6config;
+}
+
+struct vpn_ipconfig *__vpn_ipconfig_create(int index, int family)
+{
+ struct vpn_ipconfig *ipconfig;
+
+ if (family == AF_INET6)
+ return create_ipv6config(index);
+
+ DBG("index %d", index);
+
+ ipconfig = g_try_new0(struct vpn_ipconfig, 1);
+ if (ipconfig == NULL)
+ return NULL;
+
+ ipconfig->refcount = 1;
+
+ ipconfig->index = index;
+ ipconfig->enabled = FALSE;
+ ipconfig->family = family;
+
+ ipconfig->address = connman_ipaddress_alloc(AF_INET);
+ if (ipconfig->address == NULL) {
+ g_free(ipconfig);
+ return NULL;
+ }
+
+ ipconfig->system = connman_ipaddress_alloc(AF_INET);
+
+ DBG("ipconfig %p", ipconfig);
+
+ return ipconfig;
+}
+
+void __vpn_ipconfig_set_index(struct vpn_ipconfig *ipconfig, int index)
+{
+ ipconfig->index = index;
+}
+
+static const char *type2str(unsigned short type)
+{
+ switch (type) {
+ case ARPHRD_ETHER:
+ return "ETHER";
+ case ARPHRD_LOOPBACK:
+ return "LOOPBACK";
+ case ARPHRD_PPP:
+ return "PPP";
+ case ARPHRD_NONE:
+ return "NONE";
+ case ARPHRD_VOID:
+ return "VOID";
+ }
+
+ return "";
+}
+
+void __vpn_ipconfig_newlink(int index, unsigned short type,
+ unsigned int flags,
+ const char *address,
+ unsigned short mtu,
+ struct rtnl_link_stats *stats)
+{
+ struct vpn_ipdevice *ipdevice;
+ GString *str;
+
+ if (type == ARPHRD_LOOPBACK)
+ return;
+
+ ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
+ if (ipdevice != NULL)
+ goto update;
+
+ ipdevice = g_try_new0(struct vpn_ipdevice, 1);
+ if (ipdevice == NULL)
+ return;
+
+ ipdevice->index = index;
+ ipdevice->ifname = connman_inet_ifname(index);
+ ipdevice->type = type;
+
+ ipdevice->address = g_strdup(address);
+
+ g_hash_table_insert(ipdevice_hash, GINT_TO_POINTER(index), ipdevice);
+
+ connman_info("%s {create} index %d type %d <%s>", ipdevice->ifname,
+ index, type, type2str(type));
+
+update:
+ ipdevice->mtu = mtu;
+
+ if (flags == ipdevice->flags)
+ return;
+
+ ipdevice->flags = flags;
+
+ str = g_string_new(NULL);
+ if (str == NULL)
+ return;
+
+ if (flags & IFF_UP)
+ g_string_append(str, "UP");
+ else
+ g_string_append(str, "DOWN");
+
+ if (flags & IFF_RUNNING)
+ g_string_append(str, ",RUNNING");
+
+ if (flags & IFF_LOWER_UP)
+ g_string_append(str, ",LOWER_UP");
+
+ connman_info("%s {update} flags %u <%s>", ipdevice->ifname,
+ flags, str->str);
+
+ g_string_free(str, TRUE);
+}
+
+void __vpn_ipconfig_dellink(int index, struct rtnl_link_stats *stats)
+{
+ struct vpn_ipdevice *ipdevice;
+
+ DBG("index %d", index);
+
+ ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
+ if (ipdevice == NULL)
+ return;
+
+ g_hash_table_remove(ipdevice_hash, GINT_TO_POINTER(index));
+}
+
+static void free_ipdevice(gpointer data)
+{
+ struct vpn_ipdevice *ipdevice = data;
+
+ connman_info("%s {remove} index %d", ipdevice->ifname,
+ ipdevice->index);
+
+ g_free(ipdevice->ipv4_gateway);
+ g_free(ipdevice->ipv6_gateway);
+ g_free(ipdevice->pac);
+
+ g_free(ipdevice->address);
+
+ g_free(ipdevice->ifname);
+ g_free(ipdevice);
+}
+
+int __vpn_ipconfig_init(void)
+{
+ DBG("");
+
+ ipdevice_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, free_ipdevice);
+
+ return 0;
+}
+
+void __vpn_ipconfig_cleanup(void)
+{
+ DBG("");
+
+ g_hash_table_destroy(ipdevice_hash);
+ ipdevice_hash = NULL;
+}