Commit ae34fa90 authored by Dan Williams's avatar Dan Williams
Browse files

core: fix erroneous IPv6 routes by making route addition typesafe

Add two helper functions, one for IPv4 and one for IPv6, to ensure
that the core code benefits from compiler type checking when adding
routes.  Previously nm_netlink_route_add() took a void* which meant
we messed up adding IPv6 routes sometimes due to confusion over
what was supposed to be passed to it.  Also fixes what appears to
be a C&P error with add_ip6_route_to_gateway().

Reported by Tomáš Trnka <tomastrnka@gmx.com>
parent 0c83e6e3
......@@ -165,17 +165,25 @@ nm_netlink_route_new (int ifindex,
}
/**
* nm_netlink_route_add:
* _route_add:
* @route: the route to add
* @family: address family, either %AF_INET or %AF_INET6
* @dest: the route destination address, either a struct in_addr or a struct
* in6_addr depending on @family
* @dest_prefix: the CIDR prefix of @dest
* @gateway: the gateway through which to reach @dest, if any; given as a
* struct in_addr or struct in6_addr depending on @family
* @flags: flags to pass to rtnl_route_add(), eg %NLM_F_REPLACE
*
* Returns: zero if succeeded or the netlink error otherwise.
**/
int nm_netlink_route_add (struct rtnl_route * route,
int family,
const void * dest, /* in_addr or in6_addr */
int dest_prefix,
const void * gateway, /* in_addr or in6_addr */
int flags)
static int
_route_add (struct rtnl_route *route,
int family,
const void *dest, /* in_addr or in6_addr */
int dest_prefix,
const void *gateway, /* in_addr or in6_addr */
int flags)
{
struct nl_sock * sk;
struct nl_addr * dest_addr, * gw_addr;
......@@ -239,6 +247,50 @@ int nm_netlink_route_add (struct rtnl_route * route,
return err;
}
/**
* nm_netlink_route4_add:
* @route: the route to add
* @dest: the route destination address in network byte order
* @dest_prefix: the CIDR prefix of @dest
* @gateway: the gateway through which to reach @dest, if any, in network byte order
* @flags: flags to pass to rtnl_route_add(), eg %NLM_F_REPLACE
*
* Adds an IPv4 route with the given parameters.
*
* Returns: zero if succeeded or the netlink error otherwise.
**/
int
nm_netlink_route4_add (struct rtnl_route *route,
guint32 *dst,
int prefix,
guint32 *gw,
int flags)
{
return _route_add (route, AF_INET, dst, prefix, gw, flags);
}
/**
* nm_netlink_route6_add:
* @route: the route to add
* @dest: the route destination address
* @dest_prefix: the CIDR prefix of @dest
* @gateway: the gateway through which to reach @dest, if any
* @flags: flags to pass to rtnl_route_add(), eg %NLM_F_REPLACE
*
* Adds an IPv6 route with the given parameters.
*
* Returns: zero if succeeded or the netlink error otherwise.
**/
int
nm_netlink_route6_add (struct rtnl_route *route,
const struct in6_addr *dst,
int prefix,
const struct in6_addr *gw,
int flags)
{
return _route_add (route, AF_INET6, dst, prefix, gw, flags);
}
/**
* nm_netlink_route_delete:
* @route: the route to delete
......
......@@ -43,11 +43,16 @@ struct rtnl_route * nm_netlink_route_new (int ifindex,
int mss,
...) __attribute__((__sentinel__));
int nm_netlink_route_add (struct rtnl_route *route,
int family,
const void * dst, /* struct in_addr or struct in6_addr */
int nm_netlink_route4_add (struct rtnl_route *route,
guint32 *dst,
int prefix,
guint32 *gw,
int flags);
int nm_netlink_route6_add (struct rtnl_route *route,
const struct in6_addr *dst,
int prefix,
const void * gw, /* struct in_addr or struct in6_addr */
const struct in6_addr *gw,
int flags);
gboolean nm_netlink_route_delete (struct rtnl_route *route);
......
......@@ -115,7 +115,7 @@ nm_system_device_set_ip4_route (int ifindex,
g_return_val_if_fail (route != NULL, NULL);
/* Add the route */
err = nm_netlink_route_add(route, AF_INET, &ip4_dest, ip4_prefix, &ip4_gateway, 0);
err = nm_netlink_route4_add (route, &ip4_dest, ip4_prefix, &ip4_gateway, 0);
if (err == -NLE_OBJ_NOTFOUND && ip4_gateway) {
/* Gateway might be over a bridge; try adding a route to gateway first */
struct rtnl_route *route2;
......@@ -123,9 +123,9 @@ nm_system_device_set_ip4_route (int ifindex,
route2 = nm_netlink_route_new (ifindex, AF_INET, mss, NULL);
if (route2) {
/* Add route to gateway over bridge */
err = nm_netlink_route_add(route2, AF_INET, &ip4_gateway, 32, NULL, 0);
err = nm_netlink_route4_add (route2, &ip4_gateway, 32, NULL, 0);
if (!err) {
err = nm_netlink_route_add(route, AF_INET, &ip4_dest, ip4_prefix, &ip4_gateway, 0);
err = nm_netlink_route4_add (route, &ip4_dest, ip4_prefix, &ip4_gateway, 0);
if (err)
nm_netlink_route_delete (route2);
}
......@@ -486,18 +486,18 @@ nm_system_set_ip6_route (int ifindex,
g_return_val_if_fail (route != NULL, -1);
/* Add the route */
err = nm_netlink_route_add(route, AF_INET6, &ip6_dest, ip6_prefix, &ip6_gateway, 0);
err = nm_netlink_route6_add (route, ip6_dest, ip6_prefix, ip6_gateway, 0);
if (err == -NLE_OBJ_NOTFOUND && ip6_gateway) {
/* Gateway might be over a bridge; try adding a route to gateway first */
struct rtnl_route *route2;
route2 = nm_netlink_route_new (ifindex, AF_INET6, mss, NULL);
if (route2) {
err = nm_netlink_route_add(route, AF_INET6, &ip6_gateway, 128, NULL, 0);
err = nm_netlink_route6_add (route, ip6_gateway, 128, NULL, 0);
/* Add route to gateway over bridge */
if (!err) {
/* Try adding the route again */
err = nm_netlink_route_add(route, AF_INET6, &ip6_dest, ip6_prefix, &ip6_gateway, 0);
err = nm_netlink_route6_add (route, ip6_dest, ip6_prefix, ip6_gateway, 0);
if (err)
nm_netlink_route_delete (route2);
}
......@@ -825,7 +825,7 @@ add_ip4_route_to_gateway (int ifindex, guint32 gw, guint32 mss)
g_return_val_if_fail (route != NULL, NULL);
/* Add direct route to the gateway */
err = nm_netlink_route_add(route, AF_INET, &gw, 32, NULL, 0);
err = nm_netlink_route4_add (route, &gw, 32, NULL, 0);
if (err) {
char *iface = nm_netlink_index_to_iface (ifindex);
......@@ -849,7 +849,7 @@ replace_default_ip4_route (int ifindex, guint32 gw, guint32 mss)
struct rtnl_route *route = NULL;
struct nl_sock *nlh;
int err = -1;
int dst = 0;
guint32 dst = 0;
g_return_val_if_fail (ifindex > 0, -ENODEV);
......@@ -863,7 +863,7 @@ replace_default_ip4_route (int ifindex, guint32 gw, guint32 mss)
g_return_val_if_fail (route != NULL, -ENOMEM);
/* Add the new default route */
err = nm_netlink_route_add (route, AF_INET, &dst, 0, &gw, NLM_F_REPLACE);
err = nm_netlink_route4_add (route, &dst, 0, &gw, NLM_F_REPLACE);
if (err == -NLE_EXIST)
err = 0;
......@@ -1000,7 +1000,7 @@ add_ip6_route_to_gateway (int ifindex, const struct in6_addr *gw)
g_return_val_if_fail (route != NULL, NULL);
/* Add direct route to the gateway */
err = nm_netlink_route_add(route, AF_INET, gw, 128, NULL, 0);
err = nm_netlink_route6_add (route, gw, 128, NULL, 0);
if (err) {
char *iface = nm_netlink_index_to_iface (ifindex);
......@@ -1035,7 +1035,7 @@ replace_default_ip6_route (int ifindex, const struct in6_addr *gw)
g_return_val_if_fail (route != NULL, -ENOMEM);
/* Add the new default route */
err = nm_netlink_route_add (route, AF_INET6, NULL, 0, gw, NLM_F_REPLACE);
err = nm_netlink_route6_add (route, NULL, 0, gw, NLM_F_REPLACE);
if (err == -NLE_EXIST) {
/* FIXME: even though we use NLM_F_REPLACE the kernel won't replace
* the route if it's the same. Should try to remove it first, then
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment