VPN need to add the VPN host to active network gateway then add
default gateway as VPN network.
---
diff --git a/src/connection.c b/src/connection.c
index cfe4828..27f5f8b 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -41,6 +41,9 @@ struct gateway_data {
struct connman_element *element;
unsigned int order;
gboolean active;
+ /* VPN extra data */
+ gboolean vpn;
+ char *vpn_ip;
};
static GSList *gateway_list = NULL;
@@ -66,7 +69,10 @@ static struct gateway_data *find_gateway(int index, const
char *gateway)
return NULL;
}
-static int set_route(struct connman_element *element, const char *gateway)
+
+static int add_vpn_host(struct connman_element *element,
+ const char *gateway,
+ const char *host)
{
struct ifreq ifr;
struct rtentry rt;
@@ -86,9 +92,144 @@ static int set_route(struct connman_element *element, const
char *gateway)
close(sk);
return -1;
}
+ DBG("ifname %s", ifr.ifr_name);
+
+ memset(&rt, 0, sizeof(rt));
+ rt.rt_flags = RTF_UP | RTF_HOST | RTF_GATEWAY;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr(host);
+ memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr(gateway);
+ memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_NONE;
+ memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
+
+ rt.rt_dev = ifr.ifr_name;
+
+ err = ioctl(sk, SIOCADDRT, &rt);
+ if (err < 0)
+ connman_error("Setting default route1 failed (%s)",
+ strerror(errno));
+
+ close(sk);
+
+ return err;
+}
+
+static int del_vpn_host(const char *host)
+{
+ struct rtentry rt;
+ struct sockaddr_in addr;
+ int sk, err;
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return -1;
+
+ memset(&rt, 0, sizeof(rt));
+ rt.rt_flags = RTF_UP | RTF_HOST;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr(host);
+ memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
+
+ err = ioctl(sk, SIOCDELRT, &rt);
+ if (err < 0)
+ connman_error("Setting default route1 failed (%s)",
+ strerror(errno));
+
+ close(sk);
+
+ return err;
+}
+
+
+static int set_vpn_route(struct connman_element *element, const char *gateway)
+{
+ struct ifreq ifr;
+ struct rtentry rt;
+ struct sockaddr_in addr;
+ int sk, err;
+
+ DBG("set_rout1: element %p", element);
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = element->index;
+
+ if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+ close(sk);
+ return -1;
+ }
DBG("ifname %s", ifr.ifr_name);
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = element->index;
+
+ memset(&rt, 0, sizeof(rt));
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr(gateway);
+ memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
+
+ err = ioctl(sk, SIOCADDRT, &rt);
+ if (err < 0)
+ connman_error("Setting default route1 failed (%s)",
+ strerror(errno));
+
+ close(sk);
+
+ return err;
+}
+
+
+static int set_route(struct connman_element *element, const char *gateway)
+{
+ struct ifreq ifr;
+ struct rtentry rt;
+ struct sockaddr_in addr;
+ int sk, err;
+
+ DBG("element %p", element);
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = element->index;
+
+ if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+ close(sk);
+ return -1;
+ }
+ DBG("ifname %s", ifr.ifr_name);
+
memset(&rt, 0, sizeof(rt));
rt.rt_flags = RTF_UP | RTF_HOST;
@@ -113,7 +254,6 @@ static int set_route(struct connman_element *element, const
char *gateway)
if (err < 0)
connman_error("Setting host gateway route failed (%s)",
strerror(errno));
-
memset(&rt, 0, sizeof(rt));
rt.rt_flags = RTF_UP | RTF_GATEWAY;
@@ -193,6 +333,19 @@ static int del_route(struct connman_element *element,
const char *gateway)
return err;
}
+static int del_route_all(struct gateway_data *data)
+{
+ int err = 0;
+
+ if (data->vpn) {
+ del_vpn_host(data->gateway);
+ err = del_route(data->element, data->vpn_ip);
+ } else
+ err = del_route(data->element, data->gateway);
+
+ return err;
+}
+
static DBusConnection *connection;
static void emit_default_signal(struct connman_element *element)
@@ -247,6 +400,8 @@ static struct gateway_data *add_gateway(int index, const
char *gateway)
data->gateway = g_strdup(gateway);
data->active = FALSE;
data->element = NULL;
+ data->vpn_ip = NULL;
+ data->vpn = FALSE;
__connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION,
find_element, data);
@@ -279,6 +434,12 @@ static void set_default_gateway(struct gateway_data *data)
DBG("gateway %s", data->gateway);
+ if (data->vpn == TRUE) {
+
+ set_vpn_route(element, data->vpn_ip);
+ /* vpn gateway going away no changes in services */
+ return;
+ }
if (set_route(element, data->gateway) < 0)
return;
@@ -311,9 +472,11 @@ static void remove_gateway(struct gateway_data *data)
gateway_list = g_slist_remove(gateway_list, data);
if (data->active == TRUE)
- del_route(data->element, data->gateway);
+ del_route_all(data);
g_free(data->gateway);
+ if (data->vpn_ip != NULL)
+ g_free(data->vpn_ip);
g_free(data);
}
@@ -520,6 +683,7 @@ static int connection_probe(struct connman_element *element)
{
struct connman_service *service = NULL;
const char *gateway = NULL;
+ const char *vpn_ip = NULL;
struct gateway_data *active_gateway = NULL;
struct gateway_data *new_gateway = NULL;
@@ -534,6 +698,9 @@ static int connection_probe(struct connman_element *element)
connman_element_get_value(element,
CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
+ connman_element_get_value(element,
+ CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &vpn_ip);
+
DBG("gateway %s", gateway);
if (register_interface(element) < 0)
@@ -552,13 +719,29 @@ static int connection_probe(struct connman_element
*element)
active_gateway = find_active_gateway();
new_gateway = add_gateway(element->index, gateway);
+ if (service == NULL) {
+ new_gateway->vpn = TRUE;
+ new_gateway->vpn_ip = g_strdup(vpn_ip);
+ /* make sure vpn gateway are at higher priority */
+ new_gateway->order = 10;
+ } else
+ new_gateway->vpn = FALSE;
+
if (active_gateway == NULL) {
set_default_gateway(new_gateway);
return 0;
}
+
+ if (new_gateway->vpn == TRUE) {
+ add_vpn_host(active_gateway->element,
+ active_gateway->gateway,
+ new_gateway->gateway);
+
+ }
+
if (new_gateway->order >= active_gateway->order) {
- del_route(active_gateway->element, active_gateway->gateway);
+ del_route_all(active_gateway);
return 0;
}
@@ -570,6 +753,7 @@ static void connection_remove(struct connman_element
*element)
struct connman_service *service;
const char *gateway = NULL;
struct gateway_data *data = NULL;
+ gboolean set_default = FALSE;
DBG("element %p name %s", element, element->name);
@@ -594,7 +778,23 @@ static void connection_remove(struct connman_element
*element)
if (data == NULL)
return;
+ set_default = data->vpn;
+
+ if (data->vpn == TRUE)
+ del_vpn_host(data->gateway);
+
remove_gateway(data);
+
+ /* with vpn this will be called after the network was deleted,
+ * we need to call set_default here because we will not recieve any
+ * gateway delete notification.
+ */
+ if (set_default) {
+ del_vpn_host(data->gateway);
+ data = find_default_gateway();
+ if (data != NULL)
+ set_default_gateway(data);
+ }
}
static struct connman_driver connection_driver = {
@@ -651,6 +851,10 @@ static void update_order(void)
struct gateway_data *data = list->data;
struct connman_service *service;
+ /* vpn gataway is not attached to a service. */
+ if (data->vpn)
+ continue;
+
service = __connman_element_get_service(data->element);
data->order = __connman_service_get_order(service);
}
@@ -667,7 +871,7 @@ gboolean __connman_connection_update_gateway(void)
default_gateway = find_default_gateway();
if (active_gateway && active_gateway != default_gateway) {
- del_route(active_gateway->element, active_gateway->gateway);
+ del_route_all(active_gateway);
updated = TRUE;
}
_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman