Browse code

Fix IPv4 default gateway with multiple route tables

Current default gateway selection for zero destination address just
dumps and parses all the routing tables. If any of non-main table
with default route comes first, wrong default gateway can be picked.
Since adding/removing routes currently handles only main table,
let's stick to RT_TABLE_MAIN while selecting default route too.

v2: keep gateway address unchanged on lookup error
v3: reduce ammout of gateway address copying

Reported-by: Donald Sharp <donaldsharp72@gmail.com>
Signed-off-by: Vladislav Grishenko <themiron@yandex-team.ru>
Acked-by: Antonio Quartulli <antonio@openvpn.net>
Message-Id: <20210416120708.1532-1-themiron@yandex-team.ru>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg22130.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
(cherry picked from commit c7f95891a4a0aabb64e7d4f3200525c1a2fcf433)

Vladislav Grishenko authored on 2021/04/16 21:07:07
Showing 1 changed files
... ...
@@ -426,6 +426,7 @@ typedef struct {
426 426
     inet_address_t gw;
427 427
     char iface[IFNAMSIZ];
428 428
     bool default_only;
429
+    unsigned int table;
429 430
 } route_res_t;
430 431
 
431 432
 static int
... ...
@@ -435,7 +436,8 @@ sitnl_route_save(struct nlmsghdr *n, void *arg)
435 435
     struct rtmsg *r = NLMSG_DATA(n);
436 436
     struct rtattr *rta = RTM_RTA(r);
437 437
     int len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r));
438
-    unsigned int ifindex = 0;
438
+    unsigned int table, ifindex = 0;
439
+    void *gw = NULL;
439 440
 
440 441
     /* filter-out non-zero dst prefixes */
441 442
     if (res->default_only && r->rtm_dst_len != 0)
... ...
@@ -443,6 +445,9 @@ sitnl_route_save(struct nlmsghdr *n, void *arg)
443 443
         return 1;
444 444
     }
445 445
 
446
+    /* route table, ignored with RTA_TABLE */
447
+    table = r->rtm_table;
448
+
446 449
     while (RTA_OK(rta, len))
447 450
     {
448 451
         switch (rta->rta_type)
... ...
@@ -458,13 +463,24 @@ sitnl_route_save(struct nlmsghdr *n, void *arg)
458 458
 
459 459
             /* GW for the route */
460 460
             case RTA_GATEWAY:
461
-                memcpy(&res->gw, RTA_DATA(rta), res->addr_size);
461
+                gw = RTA_DATA(rta);
462
+                break;
463
+
464
+            /* route table */
465
+            case RTA_TABLE:
466
+                table = *(unsigned int *)RTA_DATA(rta);
462 467
                 break;
463 468
         }
464 469
 
465 470
         rta = RTA_NEXT(rta, len);
466 471
     }
467 472
 
473
+    /* filter out any route not coming from the selected table */
474
+    if (res->table && res->table != table)
475
+    {
476
+        return 1;
477
+    }
478
+
468 479
     if (!if_indextoname(ifindex, res->iface))
469 480
     {
470 481
         msg(M_WARN | M_ERRNO, "%s: rtnl: can't get ifname for index %d",
... ...
@@ -472,6 +488,11 @@ sitnl_route_save(struct nlmsghdr *n, void *arg)
472 472
         return -1;
473 473
     }
474 474
 
475
+    if (gw)
476
+    {
477
+        memcpy(&res->gw, gw, res->addr_size);
478
+    }
479
+
475 480
     return 0;
476 481
 }
477 482
 
... ...
@@ -507,6 +528,7 @@ sitnl_route_best_gw(sa_family_t af_family, const inet_address_t *dst,
507 507
             {
508 508
                 req.n.nlmsg_flags |= NLM_F_DUMP;
509 509
                 res.default_only = true;
510
+                res.table = RT_TABLE_MAIN;
510 511
             }
511 512
             else
512 513
             {