Browse code

Use lowest metric interface when multiple interfaces match a route

Currently a route addition using IPAPI or service is skipped if the
route gateway is reachable by multiple interfaces. This changes that
to use the interface with lowest metric. Implemented by

(i) Do not over-write the return value with TUN_ADAPTER_INDEX_INVALID in
windows_route_find_if_index() if multiple interfaces match a route.
(ii) Select the interface with lowest metric in adapter_index_of_ip()
instead of the first one found when multiple interfaces match.

Reported by Jan Just Keijser <janjust@nikhef.nl>

Signed-off-by: Selva Nair <selva.nair@gmail.com>
Tested-by: Jan Just Keijser <janjust@nikhef.nl>

Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <1516815105-17882-1-git-send-email-selva.nair@gmail.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg16347.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>

Selva Nair authored on 2018/01/25 02:31:45
Showing 2 changed files
... ...
@@ -2780,7 +2780,6 @@ windows_route_find_if_index(const struct route_ipv4 *r, const struct tuntap *tt)
2780 2780
         msg(M_WARN, "Warning: route gateway is ambiguous: %s (%d matches)",
2781 2781
             print_in_addr_t(r->gateway, 0, &gc),
2782 2782
             count);
2783
-        ret = TUN_ADAPTER_INDEX_INVALID;
2784 2783
     }
2785 2784
 
2786 2785
     dmsg(D_ROUTE_DEBUG, "DEBUG: route find if: on_tun=%d count=%d index=%d",
... ...
@@ -45,6 +45,7 @@
45 45
 #include "manage.h"
46 46
 #include "route.h"
47 47
 #include "win32.h"
48
+#include "block_dns.h"
48 49
 
49 50
 #include "memdbg.h"
50 51
 
... ...
@@ -4480,6 +4481,7 @@ adapter_index_of_ip(const IP_ADAPTER_INFO *list,
4480 4480
     struct gc_arena gc = gc_new();
4481 4481
     DWORD ret = TUN_ADAPTER_INDEX_INVALID;
4482 4482
     in_addr_t highest_netmask = 0;
4483
+    int lowest_metric = INT_MAX;
4483 4484
     bool first = true;
4484 4485
 
4485 4486
     if (count)
... ...
@@ -4493,9 +4495,14 @@ adapter_index_of_ip(const IP_ADAPTER_INFO *list,
4493 4493
 
4494 4494
         if (is_ip_in_adapter_subnet(list, ip, &hn))
4495 4495
         {
4496
+            int metric = get_interface_metric(list->Index, AF_INET, NULL);
4496 4497
             if (first || hn > highest_netmask)
4497 4498
             {
4498 4499
                 highest_netmask = hn;
4500
+                if (metric >= 0)
4501
+                {
4502
+                    lowest_metric = metric;
4503
+                }
4499 4504
                 if (count)
4500 4505
                 {
4501 4506
                     *count = 1;
... ...
@@ -4509,16 +4516,22 @@ adapter_index_of_ip(const IP_ADAPTER_INFO *list,
4509 4509
                 {
4510 4510
                     ++*count;
4511 4511
                 }
4512
+                if (metric >= 0 && metric < lowest_metric)
4513
+                {
4514
+                    ret = list->Index;
4515
+                    lowest_metric = metric;
4516
+                }
4512 4517
             }
4513 4518
         }
4514 4519
         list = list->Next;
4515 4520
     }
4516 4521
 
4517
-    dmsg(D_ROUTE_DEBUG, "DEBUG: IP Locate: ip=%s nm=%s index=%d count=%d",
4522
+    dmsg(D_ROUTE_DEBUG, "DEBUG: IP Locate: ip=%s nm=%s index=%d count=%d metric=%d",
4518 4523
          print_in_addr_t(ip, 0, &gc),
4519 4524
          print_in_addr_t(highest_netmask, 0, &gc),
4520 4525
          (int)ret,
4521
-         count ? *count : -1);
4526
+         count ? *count : -1,
4527
+         lowest_metric);
4522 4528
 
4523 4529
     if (ret == TUN_ADAPTER_INDEX_INVALID && count)
4524 4530
     {