grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 06/14] net: fix ipv6 routing


From: Josef Bacik
Subject: [PATCH 06/14] net: fix ipv6 routing
Date: Wed, 10 Feb 2016 13:21:00 -0800

ipv6 routing in grub2 is broken, we cannot talk to anything outside our local
network or anything that doesn't route in our global namespace.  This patch
fixes this by doing a couple of things

1) Read the router information off of the router advertisement.  If we have a
router lifetime we need to take the source address and create a route from it.

2) Changes the routing stuff slightly to allow you to specify a gateway _and_ an
interface.  Since the router advertisements come in on the link local address we
need to associate it with the global address on the card.  So when we are
processing the router advertisement, either use the SLAAC interface we create
and add the route to that interface, or loop through the global addresses we
currently have on our interface and associate it with one of those addresses.
We need to have a special case here for the default route so that it gets used,
we do this by setting the masksize to 0 to mean it encompasses all networks.
The routing code will automatically select the best route so if there is a
closer match we will use that.

With this patch I can now talk to ipv6 addresses outside of my local network.
Thanks,

Signed-off-by: Josef Bacik <address@hidden>
---
 grub-core/net/bootp.c                  |  2 +-
 grub-core/net/drivers/ieee1275/ofnet.c |  4 +--
 grub-core/net/icmp6.c                  | 63 +++++++++++++++++++++++++++++++++-
 grub-core/net/net.c                    | 40 ++++++++-------------
 include/grub/net.h                     | 25 +++++++++++++-
 5 files changed, 103 insertions(+), 31 deletions(-)

diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
index 37d1cfa..9fc47bd 100644
--- a/grub-core/net/bootp.c
+++ b/grub-core/net/bootp.c
@@ -83,7 +83,7 @@ parse_dhcp_vendor (const char *name, const void *vend, int 
limit, int *mask)
              grub_memcpy (&gw.ipv4, ptr, sizeof (gw.ipv4));
              rname = grub_xasprintf ("%s:default", name);
              if (rname)
-               grub_net_add_route_gw (rname, target, gw);
+               grub_net_add_route_gw (rname, target, gw, NULL);
              grub_free (rname);
            }
          break;
diff --git a/grub-core/net/drivers/ieee1275/ofnet.c 
b/grub-core/net/drivers/ieee1275/ofnet.c
index eff9085..6bd3b92 100644
--- a/grub-core/net/drivers/ieee1275/ofnet.c
+++ b/grub-core/net/drivers/ieee1275/ofnet.c
@@ -151,7 +151,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char 
*bootpath,
   grub_net_network_level_address_t client_addr, gateway_addr, subnet_mask;
   grub_net_link_level_address_t hw_addr;
   grub_net_interface_flags_t flags = 0;
-  struct grub_net_network_level_interface *inter;
+  struct grub_net_network_level_interface *inter = NULL;
 
   hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
 
@@ -221,7 +221,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char 
*bootpath,
       target.ipv4.masksize = 0;
       rname = grub_xasprintf ("%s:default", ((*card)->name));
       if (rname)
-        grub_net_add_route_gw (rname, target, gateway_addr);
+        grub_net_add_route_gw (rname, target, gateway_addr, inter);
       else
         return grub_errno;
     }
diff --git a/grub-core/net/icmp6.c b/grub-core/net/icmp6.c
index 7953e68..2cbd95d 100644
--- a/grub-core/net/icmp6.c
+++ b/grub-core/net/icmp6.c
@@ -115,6 +115,7 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
                            grub_uint8_t ttl)
 {
   struct icmp_header *icmph;
+  struct grub_net_network_level_interface *orig_inf = inf;
   grub_err_t err;
   grub_uint16_t checksum;
 
@@ -345,14 +346,31 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
       {
        grub_uint8_t *ptr;
        struct option_header *ohdr;
+       struct router_adv *radv;
+       struct grub_net_network_level_interface *route_inf = NULL;
+       int default_route = 0;
        if (icmph->code)
          break;
+       radv = (struct router_adv *)nb->data;
        err = grub_netbuff_pull (nb, sizeof (struct router_adv));
        if (err)
          {
            grub_netbuff_free (nb);
            return err;
          }
+       if (grub_be_to_cpu16 (radv->router_lifetime) > 0)
+         {
+           struct grub_net_route *route;
+
+           FOR_NET_ROUTES (route)
+           {
+             if (!grub_memcmp (&route->gw, source, sizeof (route->gw)))
+               break;
+           }
+           if (route == NULL)
+             default_route = 1;
+         }
+
        for (ptr = (grub_uint8_t *) nb->data; ptr < nb->tail;
             ptr += ohdr->len * 8)
          {
@@ -413,7 +431,11 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
                    /* Update lease time if needed here once we have
                       lease times.  */
                    if (inf)
-                     continue;
+                     {
+                       if (!route_inf)
+                         route_inf = inf;
+                       continue;
+                     }
 
                    grub_dprintf ("net", "creating slaac\n");
 
@@ -429,12 +451,51 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
                      inf = grub_net_add_addr (name, 
                                               card, &addr,
                                               &slaac->address, 0);
+                     if (!route_inf)
+                       route_inf = inf;
                      grub_net_add_route (name, netaddr, inf);
                      grub_free (name);
                    }
                  }
              }
          }
+       if (default_route)
+         {
+           char *name;
+           grub_net_network_level_netaddress_t netaddr;
+           name = grub_xasprintf ("%s:ra:default6", card->name);
+           if (!name)
+             {
+               grub_errno = GRUB_ERR_NONE;
+               goto next;
+             }
+           /* Default routes take alll of the traffic, so make the mask huge */
+           netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
+           netaddr.ipv6.masksize = 0;
+           netaddr.ipv6.base[0] = 0;
+           netaddr.ipv6.base[1] = 0;
+
+           /* May not have gotten slaac info, find a global address on this
+             card.  */
+           if (route_inf == NULL)
+             {
+               FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
+               {
+                 if (inf->card == card && inf != orig_inf
+                     && inf->address.type == 
GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
+                     && grub_net_hwaddr_cmp(&inf->hwaddress,
+                                            &orig_inf->hwaddress) == 0)
+                   {
+                     route_inf = inf;
+                     break;
+                   }
+               }
+             }
+           if (route_inf != NULL)
+             grub_net_add_route_gw (name, netaddr, *source, route_inf);
+           grub_free (name);
+         }
+next:
        if (ptr != nb->tail)
          break;
       }
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
index 16bc4e7..f49631f 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -37,21 +37,6 @@ GRUB_MOD_LICENSE ("GPLv3+");
 
 char *grub_net_default_server;
 
-struct grub_net_route
-{
-  struct grub_net_route *next;
-  struct grub_net_route **prev;
-  grub_net_network_level_netaddress_t target;
-  char *name;
-  struct grub_net_network_level_protocol *prot;
-  int is_gateway;
-  union
-  {
-    struct grub_net_network_level_interface *interface;
-    grub_net_network_level_address_t gw;
-  };
-};
-
 struct grub_net_route *grub_net_routes = NULL;
 struct grub_net_network_level_interface *grub_net_network_level_interfaces = 
NULL;
 struct grub_net_card *grub_net_cards = NULL;
@@ -410,14 +395,6 @@ grub_cmd_ipv6_autoconf (struct grub_command *cmd 
__attribute__ ((unused)),
   return err;
 }
 
-static inline void
-grub_net_route_register (struct grub_net_route *route)
-{
-  grub_list_push (GRUB_AS_LIST_P (&grub_net_routes),
-                 GRUB_AS_LIST (route));
-}
-
-#define FOR_NET_ROUTES(var) for (var = grub_net_routes; var; var = var->next)
 
 static int
 parse_ip (const char *val, grub_uint32_t *ip, const char **rest)
@@ -524,6 +501,8 @@ match_net (const grub_net_network_level_netaddress_t *net,
     case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
       {
        grub_uint64_t mask[2];
+       if (net->ipv6.masksize == 0)
+         return 1;
        if (net->ipv6.masksize <= 64)
          {
            mask[0] = 0xffffffffffffffffULL << (64 - net->ipv6.masksize);
@@ -687,7 +666,14 @@ grub_net_route_address (grub_net_network_level_address_t 
addr,
          return GRUB_ERR_NONE;
        }
       if (depth == 0)
-       *gateway = bestroute->gw;
+       {
+         *gateway = bestroute->gw;
+         if (bestroute->interface != NULL)
+           {
+             *interf = bestroute->interface;
+             return GRUB_ERR_NONE;
+           }
+       }
       curtarget = bestroute->gw;
     }
 
@@ -1109,7 +1095,8 @@ grub_net_add_route (const char *name,
 grub_err_t
 grub_net_add_route_gw (const char *name,
                       grub_net_network_level_netaddress_t target,
-                      grub_net_network_level_address_t gw)
+                      grub_net_network_level_address_t gw,
+                      struct grub_net_network_level_interface *inter)
 {
   struct grub_net_route *route;
 
@@ -1127,6 +1114,7 @@ grub_net_add_route_gw (const char *name,
   route->target = target;
   route->is_gateway = 1;
   route->gw = gw;
+  route->interface = inter;
 
   grub_net_route_register (route);
 
@@ -1152,7 +1140,7 @@ grub_cmd_addroute (struct grub_command *cmd __attribute__ 
((unused)),
       err = grub_net_resolve_address (args[3], &gw);
       if (err)
        return err;
-      return grub_net_add_route_gw (args[0], target, gw);
+      return grub_net_add_route_gw (args[0], target, gw, NULL);
     }
   else
     {
diff --git a/include/grub/net.h b/include/grub/net.h
index fa3d286..b5d4546 100644
--- a/include/grub/net.h
+++ b/include/grub/net.h
@@ -192,6 +192,18 @@ typedef struct grub_net_network_level_netaddress
   };
 } grub_net_network_level_netaddress_t;
 
+struct grub_net_route
+{
+  struct grub_net_route *next;
+  struct grub_net_route **prev;
+  grub_net_network_level_netaddress_t target;
+  char *name;
+  struct grub_net_network_level_protocol *prot;
+  int is_gateway;
+  struct grub_net_network_level_interface *interface;
+  grub_net_network_level_address_t gw;
+};
+
 #define FOR_PACKETS(cont,var) for (var = (cont).first; var; var = var->next)
 
 static inline grub_err_t
@@ -368,6 +380,16 @@ grub_net_card_unregister (struct grub_net_card *card);
 #define FOR_NET_CARDS_SAFE(var, next) for (var = grub_net_cards, next = (var ? 
var->next : 0); var; var = next, next = (var ? var->next : 0))
 
 
+extern struct grub_net_route *grub_net_routes;
+
+static inline void
+grub_net_route_register (struct grub_net_route *route)
+{
+  grub_list_push (GRUB_AS_LIST_P (&grub_net_routes),
+                 GRUB_AS_LIST (route));
+}
+
+#define FOR_NET_ROUTES(var) for (var = grub_net_routes; var; var = var->next)
 struct grub_net_session *
 grub_net_open_tcp (char *address, grub_uint16_t port);
 
@@ -393,7 +415,8 @@ grub_net_add_route (const char *name,
 grub_err_t
 grub_net_add_route_gw (const char *name,
                       grub_net_network_level_netaddress_t target,
-                      grub_net_network_level_address_t gw);
+                      grub_net_network_level_address_t gw,
+                      struct grub_net_network_level_interface *inter);
 
 
 #define GRUB_NET_BOOTP_MAC_ADDR_LEN    16
-- 
1.8.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]