From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.71) id 1aTdDl-0004tH-TQ for mharc-grub-devel@gnu.org; Wed, 10 Feb 2016 17:26:49 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:34886) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aTdDi-0004qu-NZ for grub-devel@gnu.org; Wed, 10 Feb 2016 17:26:48 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aTdDe-0005gx-K7 for grub-devel@gnu.org; Wed, 10 Feb 2016 17:26:46 -0500 Received: from 66-220-144-178.intmgw.facebook.com ([66.220.144.178]:49436 helo=mx-out.facebook.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aTdDe-0005gi-Ba for grub-devel@gnu.org; Wed, 10 Feb 2016 17:26:42 -0500 Received: from facebook.com (2401:db00:2040:5012:face:0:9:0) by mx-out.facebook.com (10.102.107.97) with ESMTP id 0d121df2d03c11e5a74c0002c99331b0-5be9270 for ; Wed, 10 Feb 2016 13:20:04 -0800 Received: by devbig041.ash4.facebook.com (Postfix, from userid 8730) id 9145E4540A7E; Wed, 10 Feb 2016 13:21:10 -0800 (PST) From: Josef Bacik To: grub-devel@gnu.org, kernel-team@fb.com Subject: [PATCH 06/14] net: fix ipv6 routing Date: Wed, 10 Feb 2016 13:21:00 -0800 Message-Id: <1455139268-3241273-7-git-send-email-jbacik@fb.com> X-Mailer: git-send-email 1.8.1 In-Reply-To: <1455139268-3241273-1-git-send-email-jbacik@fb.com> References: <1455139268-3241273-1-git-send-email-jbacik@fb.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] [fuzzy] X-Received-From: 66.220.144.178 Cc: Josef Bacik X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: The development of GNU GRUB List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 10 Feb 2016 22:26:48 -0000 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 --- 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