Host routes are added for nameservers whenever the nameservers for a service are updated. The ensures that nameservers are always reachable as long as a service is online, even if the default route changes.
In particular, this fixes problems with the DNS proxy when the
nameservers are not on a local subnet. Since nameservers are added,
to the resolver before the default route is set up, the DNS proxy
would fail to connect to the nameservers as they were not yet
reachable.
---
include/inet.h | 3 +-
include/ipconfig.h | 2 +
src/connection.c | 8 ++--
src/connman.h | 1 +
src/inet.c | 62 ++++++------------------------------
src/ipconfig.c | 50 +++++++++++++++++++++++++++++
src/service.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++-
7 files changed, 155 insertions(+), 60 deletions(-)
diff --git a/include/inet.h b/include/inet.h
index b5bf8a5..207410a 100644
--- a/include/inet.h
+++ b/include/inet.h
@@ -44,8 +44,7 @@ connman_bool_t connman_inet_is_cfg80211(int index);
int connman_inet_set_address(int index, struct connman_ipaddress *ipaddress);
int connman_inet_clear_address(int index);
-int connman_inet_add_host_route_vpn(int index, const char *gateway, const char
*host);
-int connman_inet_add_host_route(int index, const char *host);
+int connman_inet_add_host_route(int index, const char *host, const char
*gateway);
int connman_inet_del_host_route(int index, const char *host);
int connman_inet_set_gateway_address(int index, const char *gateway);
int connman_inet_clear_gateway_address(int index, const char *gateway);
diff --git a/include/ipconfig.h b/include/ipconfig.h
index 0b70252..8e8e045 100644
--- a/include/ipconfig.h
+++ b/include/ipconfig.h
@@ -71,6 +71,8 @@ struct connman_ipconfig_ops {
void (*lower_down) (struct connman_ipconfig *ipconfig);
void (*ip_bound) (struct connman_ipconfig *ipconfig);
void (*ip_release) (struct connman_ipconfig *ipconfig);
+ void (*new_gateway) (struct connman_ipconfig *ipconfig);
+ void (*del_gateway) (struct connman_ipconfig *ipconfig);
};
struct connman_ipconfig *connman_ipconfig_create(int index);
diff --git a/src/connection.c b/src/connection.c
index 154076b..82648d6 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -157,7 +157,7 @@ static void set_default_gateway(struct gateway_data *data)
goto done;
}
- connman_inet_add_host_route(element->index, data->gateway);
+ connman_inet_add_host_route(element->index, data->gateway, NULL);
if (connman_inet_set_gateway_address(element->index, data->gateway) < 0)
return;
@@ -301,9 +301,9 @@ static int connection_probe(struct connman_element *element)
}
if (new_gateway->vpn == TRUE) {
- connman_inet_add_host_route_vpn(active_gateway->index,
- active_gateway->gateway,
- new_gateway->gateway);
+ connman_inet_add_host_route(active_gateway->index,
+ new_gateway->gateway,
+ active_gateway->gateway);
}
if (new_gateway->order >= active_gateway->order) {
diff --git a/src/connman.h b/src/connman.h
index 1fdada3..991d1ba 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -221,6 +221,7 @@ void __connman_ipconfig_foreach(void (*function) (int
index, void *user_data),
unsigned short __connman_ipconfig_get_type(int index);
unsigned int __connman_ipconfig_get_flags(int index);
const char *__connman_ipconfig_get_gateway(int index);
+connman_bool_t __connman_ipconfig_is_host_on_local_network(struct
connman_ipconfig *ipconfig, const char *host);
void __connman_ipconfig_set_index(struct connman_ipconfig *ipconfig, int
index);
int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig);
diff --git a/src/inet.c b/src/inet.c
index 980bd48..aa56c10 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -612,63 +612,15 @@ int connman_inet_clear_address(int index)
return 0;
}
-int connman_inet_add_host_route_vpn(int index, const char *gateway, const char
*host)
+int connman_inet_add_host_route(int index, const char *host,
+ const char *gateway)
{
struct ifreq ifr;
struct rtentry rt;
struct sockaddr_in addr;
int sk, err;
- sk = socket(PF_INET, SOCK_DGRAM, 0);
- if (sk < 0)
- return -1;
-
- memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_ifindex = 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 | 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_ANY;
- 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("Adding host route failed (%s)",
- strerror(errno));
-
- close(sk);
-
- return err;
-}
-
-int connman_inet_add_host_route(int index, const char *host)
-{
- struct ifreq ifr;
- struct rtentry rt;
- struct sockaddr_in addr;
- int sk, err;
+ DBG("index %u host %s gateway %s", index, host, gateway);
sk = socket(PF_INET, SOCK_DGRAM, 0);
if (sk < 0)
@@ -687,6 +639,9 @@ int connman_inet_add_host_route(int index, const char *host)
memset(&rt, 0, sizeof(rt));
rt.rt_flags = RTF_UP | RTF_HOST;
+ if (gateway != NULL)
+ rt.rt_flags = rt.rt_flags | RTF_GATEWAY;
+
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(host);
@@ -694,7 +649,10 @@ int connman_inet_add_host_route(int index, const char
*host)
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = INADDR_ANY;
+ if (gateway != NULL)
+ addr.sin_addr.s_addr = inet_addr(gateway);
+ else
+ addr.sin_addr.s_addr = INADDR_ANY;
memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
memset(&addr, 0, sizeof(addr));
diff --git a/src/ipconfig.c b/src/ipconfig.c
index 51c4619..b4271d2 100644
--- a/src/ipconfig.c
+++ b/src/ipconfig.c
@@ -624,6 +624,7 @@ void __connman_ipconfig_newroute(int index, unsigned char
scope,
if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
GSList *list;
+ GList *list2;
g_free(ipdevice->gateway);
ipdevice->gateway = g_strdup(gateway);
@@ -640,6 +641,20 @@ void __connman_ipconfig_newroute(int index, unsigned char
scope,
g_free(ipaddress->gateway);
ipaddress->gateway = g_strdup(gateway);
}
+
+ for (list2 = g_list_first(ipconfig_list); list2;
+ list2 =
g_list_next(list2)) {
+ struct connman_ipconfig *ipconfig = list2->data;
+
+ if (index != ipconfig->index)
+ continue;
+
+ if (ipconfig->ops == NULL)
+ continue;
+
+ if (ipconfig->ops->new_gateway)
+ ipconfig->ops->new_gateway(ipconfig);
+ }
}
connman_info("%s {add} route %s gw %s scope %u <%s>",
@@ -660,6 +675,7 @@ void __connman_ipconfig_delroute(int index, unsigned char
scope,
if (scope == 0 && g_strcmp0(dst, "0.0.0.0") == 0) {
GSList *list;
+ GList *list2;
g_free(ipdevice->gateway);
ipdevice->gateway = NULL;
@@ -676,6 +692,20 @@ void __connman_ipconfig_delroute(int index, unsigned char
scope,
g_free(ipaddress->gateway);
ipaddress->gateway = NULL;
}
+
+ for (list2 = g_list_first(ipconfig_list); list2;
+ list2 =
g_list_next(list2)) {
+ struct connman_ipconfig *ipconfig = list2->data;
+
+ if (index != ipconfig->index)
+ continue;
+
+ if (ipconfig->ops == NULL)
+ continue;
+
+ if (ipconfig->ops->del_gateway)
+ ipconfig->ops->del_gateway(ipconfig);
+ }
}
connman_info("%s {del} route %s gw %s scope %u <%s>",
@@ -734,6 +764,26 @@ const char *__connman_ipconfig_get_gateway(int index)
return ipdevice->gateway;
}
+connman_bool_t __connman_ipconfig_is_host_on_local_network(
+ struct connman_ipconfig *ipconfig, const char *host)
+{
+ struct in_addr host_addr, local_addr;
+ in_addr_t netmask, host_network_addr, local_network_addr;
+
+ if (ipconfig->system == NULL)
+ return FALSE;
+
+ netmask = 0xffffffff << (32 - ipconfig->system->prefixlen);
+
+ inet_aton(host, &host_addr);
+ host_network_addr = host_addr.s_addr & netmask;
+
+ inet_aton(ipconfig->system->local, &local_addr);
+ local_network_addr = local_addr.s_addr & netmask;
+
+ return (host_network_addr == local_network_addr);
+}
+
void __connman_ipconfig_set_index(struct connman_ipconfig *ipconfig, int index)
{
ipconfig->index = index;
diff --git a/src/service.c b/src/service.c
index fd694e8..f795ee1 100644
--- a/src/service.c
+++ b/src/service.c
@@ -298,6 +298,56 @@ static connman_bool_t is_connected(const struct
connman_service *service)
return FALSE;
}
+static int add_nameserver_host_route(struct connman_service *service,
+ const char *nameserver)
+{
+ int index;
+ const char *gateway;
+
+ DBG("service %p nameserver %s", service, nameserver);
+
+ index = connman_network_get_index(service->network);
+ gateway = __connman_ipconfig_get_gateway(index);
+
+ DBG("gateway %s", gateway);
+
+ if (__connman_ipconfig_is_host_on_local_network(
+ service->ipconfig, nameserver)) {
+ DBG("adding host route for nameserver %s with no gateway",
+ nameserver);
+ return connman_inet_add_host_route(index, nameserver, NULL);
+ }
+
+ if (gateway != NULL) {
+ DBG("adding host route for nameserver %s with gateway %s",
+ nameserver, gateway);
+ return connman_inet_add_host_route(index, nameserver, gateway);
+ }
+
+ DBG("not adding host route for nameserver %s (gateway not known)",
+ nameserver);
+ return -1;
+}
+
+static void del_all_nameserver_host_routes(struct connman_service *service)
+{
+ int index, i;
+ const char *gateway;
+
+ DBG("service %p", service);
+
+ index = connman_network_get_index(service->network);
+ gateway = __connman_ipconfig_get_gateway(index);
+
+ if (service->nameservers != NULL)
+ for (i = 0; service->nameservers[i]; i++)
+ connman_inet_del_host_route(index,
+ service->nameservers[i]);
+
+ else if (service->nameserver != NULL)
+ connman_inet_del_host_route(index, service->nameserver);
+}
+
static void update_nameservers(struct connman_service *service)
{
const char *ifname = connman_ipconfig_get_ifname(service->ipconfig);
@@ -314,6 +364,7 @@ static void update_nameservers(struct connman_service
*service)
case CONNMAN_SERVICE_STATE_FAILURE:
case CONNMAN_SERVICE_STATE_DISCONNECT:
connman_resolver_remove_all(ifname);
+ del_all_nameserver_host_routes(service);
return;
case CONNMAN_SERVICE_STATE_READY:
case CONNMAN_SERVICE_STATE_LOGIN:
@@ -322,15 +373,20 @@ static void update_nameservers(struct connman_service
*service)
}
connman_resolver_remove_all(ifname);
+ del_all_nameserver_host_routes(service);
if (service->nameservers != NULL) {
int i;
- for (i = 0; service->nameservers[i]; i++)
+ for (i = 0; service->nameservers[i]; i++) {
+ add_nameserver_host_route(service,
service->nameservers[i]);
connman_resolver_append(ifname, NULL,
service->nameservers[i]);
- } else if (service->nameserver != NULL)
+ }
+ } else if (service->nameserver != NULL) {
+ add_nameserver_host_route(service, service->nameserver);
connman_resolver_append(ifname, NULL, service->nameserver);
+ }
}
void __connman_service_append_nameserver(struct connman_service *service,
@@ -2665,6 +2721,33 @@ static void service_ip_release(struct connman_ipconfig
*ipconfig)
settings_changed(service);
}
+static void service_new_gateway(struct connman_ipconfig *ipconfig)
+{
+ struct connman_service *service = connman_ipconfig_get_data(ipconfig);
+
+ connman_info("%s new gateway", connman_ipconfig_get_ifname(ipconfig));
+
+ /* Refresh nameservers so that nameserver host routes requiring a
+ * gateway are correctly installed.
+ */
+ update_nameservers(service);
+}
+
+static void service_del_gateway(struct connman_ipconfig *ipconfig)
+{
+ struct connman_service *service = connman_ipconfig_get_data(ipconfig);
+
+ connman_info("%s del gateway", connman_ipconfig_get_ifname(ipconfig));
+
+ /* FIXME: We probably don't need to do this. Nameserver host routes
+ * should have been removed when the service went into
+ * CONNMAN_SERVICE_STATE_DISCONNECT.
+ */
+
+ /* Ensure nameserver host routes are removed. */
+ update_nameservers(service);
+}
+
static const struct connman_ipconfig_ops service_ops = {
.up = service_up,
.down = service_down,
@@ -2672,6 +2755,8 @@ static const struct connman_ipconfig_ops service_ops = {
.lower_down = service_lower_down,
.ip_bound = service_ip_bound,
.ip_release = service_ip_release,
+ .new_gateway = service_new_gateway,
+ .del_gateway = service_del_gateway,
};
static void setup_ipconfig(struct connman_service *service, int index)
--
1.7.0.4
signature.asc
Description: Digital signature
_______________________________________________ connman mailing list [email protected] http://lists.connman.net/listinfo/connman
