Commit ef2c7d7b authored by Nicolas Dichtel's avatar Nicolas Dichtel Committed by David S. Miller

ipv6: fix handling of blackhole and prohibit routes

When adding a blackhole or a prohibit route, they were handling like classic
routes. Moreover, it was only possible to add this kind of routes by specifying
an interface.

Bug already reported here:
  http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=498498

Before the patch:
  $ ip route add blackhole 2001::1/128
  RTNETLINK answers: No such device
  $ ip route add blackhole 2001::1/128 dev eth0
  $ ip -6 route | grep 2001
  2001::1 dev eth0  metric 1024

After:
  $ ip route add blackhole 2001::1/128
  $ ip -6 route | grep 2001
  blackhole 2001::1 dev lo  metric 1024  error -22

v2: wrong patch
v3: add a field fc_type in struct fib6_config to store RTN_* type
Signed-off-by: default avatarNicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d6b6d987
...@@ -37,6 +37,7 @@ struct fib6_config { ...@@ -37,6 +37,7 @@ struct fib6_config {
int fc_ifindex; int fc_ifindex;
u32 fc_flags; u32 fc_flags;
u32 fc_protocol; u32 fc_protocol;
u32 fc_type; /* only 8 bits are used */
struct in6_addr fc_dst; struct in6_addr fc_dst;
struct in6_addr fc_src; struct in6_addr fc_src;
......
...@@ -1463,8 +1463,18 @@ int ip6_route_add(struct fib6_config *cfg) ...@@ -1463,8 +1463,18 @@ int ip6_route_add(struct fib6_config *cfg)
} }
rt->dst.output = ip6_pkt_discard_out; rt->dst.output = ip6_pkt_discard_out;
rt->dst.input = ip6_pkt_discard; rt->dst.input = ip6_pkt_discard;
rt->dst.error = -ENETUNREACH;
rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP; rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
switch (cfg->fc_type) {
case RTN_BLACKHOLE:
rt->dst.error = -EINVAL;
break;
case RTN_PROHIBIT:
rt->dst.error = -EACCES;
break;
default:
rt->dst.error = -ENETUNREACH;
break;
}
goto install_route; goto install_route;
} }
...@@ -2261,8 +2271,11 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -2261,8 +2271,11 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
cfg->fc_src_len = rtm->rtm_src_len; cfg->fc_src_len = rtm->rtm_src_len;
cfg->fc_flags = RTF_UP; cfg->fc_flags = RTF_UP;
cfg->fc_protocol = rtm->rtm_protocol; cfg->fc_protocol = rtm->rtm_protocol;
cfg->fc_type = rtm->rtm_type;
if (rtm->rtm_type == RTN_UNREACHABLE) if (rtm->rtm_type == RTN_UNREACHABLE ||
rtm->rtm_type == RTN_BLACKHOLE ||
rtm->rtm_type == RTN_PROHIBIT)
cfg->fc_flags |= RTF_REJECT; cfg->fc_flags |= RTF_REJECT;
if (rtm->rtm_type == RTN_LOCAL) if (rtm->rtm_type == RTN_LOCAL)
...@@ -2391,8 +2404,19 @@ static int rt6_fill_node(struct net *net, ...@@ -2391,8 +2404,19 @@ static int rt6_fill_node(struct net *net,
rtm->rtm_table = table; rtm->rtm_table = table;
if (nla_put_u32(skb, RTA_TABLE, table)) if (nla_put_u32(skb, RTA_TABLE, table))
goto nla_put_failure; goto nla_put_failure;
if (rt->rt6i_flags & RTF_REJECT) if (rt->rt6i_flags & RTF_REJECT) {
switch (rt->dst.error) {
case -EINVAL:
rtm->rtm_type = RTN_BLACKHOLE;
break;
case -EACCES:
rtm->rtm_type = RTN_PROHIBIT;
break;
default:
rtm->rtm_type = RTN_UNREACHABLE; rtm->rtm_type = RTN_UNREACHABLE;
break;
}
}
else if (rt->rt6i_flags & RTF_LOCAL) else if (rt->rt6i_flags & RTF_LOCAL)
rtm->rtm_type = RTN_LOCAL; rtm->rtm_type = RTN_LOCAL;
else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK)) else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
......
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