diff --git a/src/ipv4.c b/src/ipv4.c
index 01e34af69d29d0fa76868db4259b19c2d476982e..99d73081ff57a8c2260fe04aa712fa3c764e6459 100644
--- a/src/ipv4.c
+++ b/src/ipv4.c
@@ -107,8 +107,12 @@ static inline void route_destroy(struct rtentry *route)
 /*
  * Finds system IP route to a destination.
  *
- * The passed route must have dest and mask set. If the route is found, the
- * function fills the gtw and iface properties.
+ * The passed route must have dest and mask set. If the route is found,
+ * the function searches for a match in the routing table and returns
+ * that one. Note that dest and mask contain the network address and
+ * the mask of the corresponding routing table entry after calling.
+ * After calling ipv4_get_route it might be necessary to set dest
+ * and mask again to the desired values for further processing.
  */
 static int ipv4_get_route(struct rtentry *route)
 {
@@ -116,9 +120,22 @@ static int ipv4_get_route(struct rtentry *route)
 	char buffer[0x1000];
 	char *start, *line;
 	char *saveptr1 = NULL, *saveptr2 = NULL;
+	uint32_t rtdest, rtmask, rtgtw;
+	int rtfound = 0;
 
 	log_debug("ip route show %s\n", ipv4_show_route(route));
 
+	// store what we are looking for
+	rtdest = route_dest(route).s_addr;
+	rtmask = route_mask(route).s_addr;
+	rtgtw = route_gtw(route).s_addr;
+
+
+	// initialize the output record
+	route_dest(route).s_addr = inet_addr("0.0.0.0");
+	route_mask(route).s_addr = inet_addr("0.0.0.0");
+	route_gtw(route).s_addr = inet_addr("0.0.0.0");
+
 #ifdef __APPLE__
 	FILE *fp;
 	int len = sizeof(buffer) - 1;
@@ -144,8 +161,20 @@ static int ipv4_get_route(struct rtentry *route)
 
 	unsigned short flag_table[256] = { 0 };
 
-	// fill the table now (I'm still looking for a more elagant way to do this),
-	// also, not all flags might be allowed in the context of ipv4
+	/*
+	 * Fill the flag_table now. Unfortunately it is not easy
+	 * to do this in a more elegant way. The problem here
+	 * is that these are already preprocessor macros and
+	 * we can't use them as arguments for another macro which
+	 * would include the #ifdef statements.
+	 *
+	 * Also, not all flags might be allowed in the context
+	 * of ipv4, and the code depends on which ones are
+	 * actually implemented on the target platform, which
+	 * might also be varying between OSX versions.
+	 *
+	 */
+
 #ifdef RTF_PROTO1     // Protocol specific routing flag #1
 	flag_table['1'] = RTF_PROTO1 & USHRT_MAX;
 #endif
@@ -243,7 +272,7 @@ static int ipv4_get_route(struct rtentry *route)
 	start++;
 
 #ifdef __APPLE__
-	// Skip 3 more line
+	// Skip 3 more lines on Mac OSX
 	start = index(start, '\n');
 	start = index(++start, '\n');
 	start = index(++start, '\n');
@@ -273,6 +302,10 @@ static int ipv4_get_route(struct rtentry *route)
 		mask = UINT32_MAX;
 		// "Destination"
 		tmpstr = strtok_r(line, " ", &saveptr2);
+		if (strncmp(tmpstr, "Internet6", 9) == 0) {
+			// we have arrived at the end of ipv4 output
+			goto end;
+		}
 		log_debug("- Destination: %s\n", tmpstr);
 		// replace literal "default" route by IPV4 numbers-and-dots notation
 		if (strncmp(tmpstr, "default", 7) == 0) {
@@ -359,29 +392,89 @@ static int ipv4_get_route(struct rtentry *route)
 		window = strtol(strtok_r(NULL, "\t", &saveptr2), NULL, 16);
 		irtt = strtol(strtok_r(NULL, "\t", &saveptr2), NULL, 16);
 #endif
+		/*
+		 * Now that we have parsed a routing entry, check if it
+		 * matches the current argument to the function call.
+		 * In rtentry we have integer representation, i.e.
+		 * the most significant byte corresponds to the last
+		 * number of dotted-number representation and vice versa.
+		 * In this representation ( address & mask ) is the network
+		 * address.
+		 * The routing algorithm does the following:
+		 * First, check if the network address we are looking for
+		 * falls into the network for the current route.
+		 * Therefore, calculate the network address for both, the
+		 * current route and for the destination we are searching.
+		 * If the destination is a smaller network (for instance a
+		 * single host), we have to mask again with the netmask of
+		 * the routing entry that we are checking in order to obtain
+		 * the network address in the context of the current route.
+		 * If both network addresses match, we have found a candidate
+		 * for a route.
+		 * However, there might be another route for a smaller network,
+		 * therefore repeat this and only store the resulting route
+		 * when the mask is at least as large as the one we may
+		 * have already found in a previous iteration (a larger
+		 * netmask corresponds to a smaller network in this
+		 * representation, and has a higher prority by default).
+		 * Also, only consider routing entries for which the
+		 * netmask is not larger than the netmask used in the
+		 * argument when calling the function - so that we can
+		 * distinguish between different routing entries for subnets
+		 * of different size but with the same network address.
+		 * For routing entries with the same destination and
+		 * the same netmask the metric can be used for adjusting
+		 * the priority (this is not supported on mac).
+		 * If the metric is larger than one found for this network
+		 * size, skip the current route (smaller numbers denote
+		 * less hops and therefore have a higher priority).
+		 */
+
+		if (((dest & mask) == (rtdest & rtmask & mask))
+		    && (mask >= route_mask(route).s_addr)
+		    && (mask <= rtmask)) {
+#ifndef __APPLE__
+			if (((mask == route_mask(route).s_addr)
+			     && (metric <= route->rt_metric))
+			    || (rtfound == 0)
+			    || (mask > route_mask(route).s_addr)) {
+#endif
+				rtfound = 1;
+				// Requested route has been found
+				route_dest(route).s_addr = dest;
+				route_mask(route).s_addr = mask;
+				route_gtw(route).s_addr = gtw;
+				route->rt_flags = flags;
+
+				strncpy(route_iface(route), iface,
+				        ROUTE_IFACE_LEN - 1);
 
-		if (dest == route_dest(route).s_addr &&
-		    mask == route_mask(route).s_addr) {
-			// Requested route has been found
-			route_gtw(route).s_addr = gtw;
-			route->rt_flags = flags;
 #ifndef __APPLE__
-			// we do not have these values from Mac OS X netstat,
-			// so stay with defaults denoted by values of 0
-			route->rt_metric = metric;
-			route->rt_mtu = mtu;
-			route->rt_window = window;
-			route->rt_irtt = irtt;
+				// we do not have these values from Mac OS X netstat,
+				// so stay with defaults denoted by values of 0
+				route->rt_metric = metric;
+				route->rt_mtu = mtu;
+				route->rt_window = window;
+				route->rt_irtt = irtt;
+			}
 #endif
-			strncpy(route_iface(route), iface,
-			        ROUTE_IFACE_LEN - 1);
-			return 0;
 		}
 		line = strtok_r(NULL, "\n", &saveptr1);
 	}
-	log_debug("Route not found.\n");
+#ifdef __APPLE__
+end:
+#endif
+	if (rtfound==0) {
+		// should not occur anymore unless there is no default route
+		log_debug("Route not found.\n");
+		// at least restore input values
+		route_dest(route).s_addr = rtdest;
+		route_mask(route).s_addr = rtmask;
+		route_gtw(route).s_addr = rtgtw;
+		return ERR_IPV4_NO_SUCH_ROUTE;
+	}
 
-	return ERR_IPV4_NO_SUCH_ROUTE;
+	return 0;
 }
 
 static int ipv4_set_route(struct rtentry *route)
@@ -485,11 +578,16 @@ int ipv4_protect_tunnel_route(struct tunnel *tunnel)
 	}
 
 
-	// Set the default route as the route to the tunnel gateway
-	char *iface = route_iface(gtw_rt);
-	memcpy(gtw_rt, def_rt, sizeof(*gtw_rt));
-	route_iface(gtw_rt) = iface;
-	strncpy(route_iface(gtw_rt), route_iface(def_rt), ROUTE_IFACE_LEN - 1);
+	// Set the up a route to the tunnel gateway
+	route_dest(gtw_rt).s_addr = tunnel->config->gateway_ip.s_addr;
+	route_mask(gtw_rt).s_addr = inet_addr("255.255.255.255");
+	ret = ipv4_get_route(gtw_rt);
+	if (ret != 0) {
+		log_warn("Could not get route to gateway (%s).\n",
+		         err_ipv4_str(ret));
+		log_warn("Protecting tunnel route has failed. But this can be working except for some cases.\n");
+		goto err_destroy;
+	}
 	route_dest(gtw_rt).s_addr = tunnel->config->gateway_ip.s_addr;
 	route_mask(gtw_rt).s_addr = inet_addr("255.255.255.255");
 	gtw_rt->rt_flags |= RTF_HOST;
@@ -497,6 +595,7 @@ int ipv4_protect_tunnel_route(struct tunnel *tunnel)
 
 	tunnel->ipv4.route_to_vpn_is_added = 1;
 	log_debug("Setting route to vpn server...\n");
+	log_debug("ip route show %s\n", ipv4_show_route(gtw_rt));
 	ret = ipv4_set_route(gtw_rt);
 	if (ret == ERR_IPV4_SEE_ERRNO && errno == EEXIST) {
 		log_warn("Route to vpn server exists already.\n");