diff options
author | David Ahern <dsahern@gmail.com> | 2019-04-16 20:31:43 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-04-18 02:19:07 -0400 |
commit | b8fb1ab46169ac016a8552a6455bb0bfc401f8e2 (patch) | |
tree | a7d8430a9044e9e3203915f401e68abfd6e30c31 | |
parent | cea29a70727e7885b3fdf0d266a57818652a89c1 (diff) |
net ipv6: Prevent neighbor add if protocol is disabled on device
Disabling IPv6 on an interface removes existing entries but nothing prevents
new entries from being manually added. To that end, add a new neigh_table
operation, allow_add, that is called on RTM_NEWNEIGH to see if neighbor
entries are allowed on a given device. If IPv6 is disabled on the device,
allow_add returns false and passes a message back to the user via extack.
$ echo 1 > /proc/sys/net/ipv6/conf/eth1/disable_ipv6
$ ip -6 neigh add fe80::4c88:bff:fe21:2704 dev eth1 lladdr de:ad:be:ef:01:01
Error: IPv6 is disabled on this device.
Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/neighbour.h | 2 | ||||
-rw-r--r-- | net/core/neighbour.c | 5 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 17 |
3 files changed, 24 insertions, 0 deletions
diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 3e5438bd0101..50a67bd6a434 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h | |||
@@ -205,6 +205,8 @@ struct neigh_table { | |||
205 | int (*pconstructor)(struct pneigh_entry *); | 205 | int (*pconstructor)(struct pneigh_entry *); |
206 | void (*pdestructor)(struct pneigh_entry *); | 206 | void (*pdestructor)(struct pneigh_entry *); |
207 | void (*proxy_redo)(struct sk_buff *skb); | 207 | void (*proxy_redo)(struct sk_buff *skb); |
208 | bool (*allow_add)(const struct net_device *dev, | ||
209 | struct netlink_ext_ack *extack); | ||
208 | char *id; | 210 | char *id; |
209 | struct neigh_parms parms; | 211 | struct neigh_parms parms; |
210 | struct list_head parms_list; | 212 | struct list_head parms_list; |
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 30f6fd8f68e0..997cfa8f99ba 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
@@ -1920,6 +1920,11 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1920 | goto out; | 1920 | goto out; |
1921 | } | 1921 | } |
1922 | 1922 | ||
1923 | if (tbl->allow_add && !tbl->allow_add(dev, extack)) { | ||
1924 | err = -EINVAL; | ||
1925 | goto out; | ||
1926 | } | ||
1927 | |||
1923 | neigh = neigh_lookup(tbl, dst, dev); | 1928 | neigh = neigh_lookup(tbl, dst, dev); |
1924 | if (neigh == NULL) { | 1929 | if (neigh == NULL) { |
1925 | bool exempt_from_gc; | 1930 | bool exempt_from_gc; |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 66c8b294e02b..4c8e2ea8bf19 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -77,6 +77,8 @@ static u32 ndisc_hash(const void *pkey, | |||
77 | const struct net_device *dev, | 77 | const struct net_device *dev, |
78 | __u32 *hash_rnd); | 78 | __u32 *hash_rnd); |
79 | static bool ndisc_key_eq(const struct neighbour *neigh, const void *pkey); | 79 | static bool ndisc_key_eq(const struct neighbour *neigh, const void *pkey); |
80 | static bool ndisc_allow_add(const struct net_device *dev, | ||
81 | struct netlink_ext_ack *extack); | ||
80 | static int ndisc_constructor(struct neighbour *neigh); | 82 | static int ndisc_constructor(struct neighbour *neigh); |
81 | static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); | 83 | static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); |
82 | static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb); | 84 | static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb); |
@@ -117,6 +119,7 @@ struct neigh_table nd_tbl = { | |||
117 | .pconstructor = pndisc_constructor, | 119 | .pconstructor = pndisc_constructor, |
118 | .pdestructor = pndisc_destructor, | 120 | .pdestructor = pndisc_destructor, |
119 | .proxy_redo = pndisc_redo, | 121 | .proxy_redo = pndisc_redo, |
122 | .allow_add = ndisc_allow_add, | ||
120 | .id = "ndisc_cache", | 123 | .id = "ndisc_cache", |
121 | .parms = { | 124 | .parms = { |
122 | .tbl = &nd_tbl, | 125 | .tbl = &nd_tbl, |
@@ -392,6 +395,20 @@ static void pndisc_destructor(struct pneigh_entry *n) | |||
392 | ipv6_dev_mc_dec(dev, &maddr); | 395 | ipv6_dev_mc_dec(dev, &maddr); |
393 | } | 396 | } |
394 | 397 | ||
398 | /* called with rtnl held */ | ||
399 | static bool ndisc_allow_add(const struct net_device *dev, | ||
400 | struct netlink_ext_ack *extack) | ||
401 | { | ||
402 | struct inet6_dev *idev = __in6_dev_get(dev); | ||
403 | |||
404 | if (!idev || idev->cnf.disable_ipv6) { | ||
405 | NL_SET_ERR_MSG(extack, "IPv6 is disabled on this device"); | ||
406 | return false; | ||
407 | } | ||
408 | |||
409 | return true; | ||
410 | } | ||
411 | |||
395 | static struct sk_buff *ndisc_alloc_skb(struct net_device *dev, | 412 | static struct sk_buff *ndisc_alloc_skb(struct net_device *dev, |
396 | int len) | 413 | int len) |
397 | { | 414 | { |