Skip to content

Commit

Permalink
ipv6: addrconf: use stable address generator for ARPHRD_NONE
Browse files Browse the repository at this point in the history
Add a new address generator mode, using the stable address generator
with an automatically generated secret. This is intended as a default
address generator mode for device types with no EUI64 implementation.
The new generator is used for ARPHRD_NONE interfaces initially, adding
default IPv6 autoconf support to e.g. tun interfaces.

If the addrgenmode is set to 'random', either by default or manually,
and no stable secret is available, then a random secret is used as
input for the stable-privacy address generator.  The secret can be
read and modified like manually configured secrets, using the proc
interface.  Modifying the secret will change the addrgen mode to
'stable-privacy' to indicate that it operates on a known secret.

Existing behaviour of the 'stable-privacy' mode is kept unchanged. If
a known secret is available when the device is created, then the mode
will default to 'stable-privacy' as before.  The mode can be manually
set to 'random' but it will behave exactly like 'stable-privacy' in
this case. The secret will not change.

Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>
Cc: 吉藤英明 <hideaki.yoshifuji@miraclelinux.com>
Signed-off-by: Bjørn Mork <bjorn@mork.no>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
bmork authored and davem330 committed Dec 18, 2015
1 parent 8cb964d commit cc9da6c
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 6 deletions.
1 change: 1 addition & 0 deletions include/uapi/linux/if_link.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ enum in6_addr_gen_mode {
IN6_ADDR_GEN_MODE_EUI64,
IN6_ADDR_GEN_MODE_NONE,
IN6_ADDR_GEN_MODE_STABLE_PRIVACY,
IN6_ADDR_GEN_MODE_RANDOM,
};

/* Bridge section */
Expand Down
45 changes: 39 additions & 6 deletions net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -2319,6 +2319,12 @@ static void manage_tempaddrs(struct inet6_dev *idev,
}
}

static bool is_addr_mode_generate_stable(struct inet6_dev *idev)
{
return idev->addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY ||
idev->addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
}

void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
{
struct prefix_info *pinfo;
Expand Down Expand Up @@ -2432,8 +2438,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
in6_dev->token.s6_addr + 8, 8);
read_unlock_bh(&in6_dev->lock);
tokenized = true;
} else if (in6_dev->addr_gen_mode ==
IN6_ADDR_GEN_MODE_STABLE_PRIVACY &&
} else if (is_addr_mode_generate_stable(in6_dev) &&
!ipv6_generate_stable_address(&addr, 0,
in6_dev)) {
addr_flags |= IFA_F_STABLE_PRIVACY;
Expand Down Expand Up @@ -3033,6 +3038,17 @@ static int ipv6_generate_stable_address(struct in6_addr *address,
return 0;
}

static void ipv6_gen_mode_random_init(struct inet6_dev *idev)
{
struct ipv6_stable_secret *s = &idev->cnf.stable_secret;

if (s->initialized)
return;
s = &idev->cnf.stable_secret;
get_random_bytes(&s->secret, sizeof(s->secret));
s->initialized = true;
}

static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)
{
struct in6_addr addr;
Expand All @@ -3043,13 +3059,18 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)

ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0);

if (idev->addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
switch (idev->addr_gen_mode) {
case IN6_ADDR_GEN_MODE_RANDOM:
ipv6_gen_mode_random_init(idev);
/* fallthrough */
case IN6_ADDR_GEN_MODE_STABLE_PRIVACY:
if (!ipv6_generate_stable_address(&addr, 0, idev))
addrconf_add_linklocal(idev, &addr,
IFA_F_STABLE_PRIVACY);
else if (prefix_route)
addrconf_prefix_route(&addr, 64, idev->dev, 0, 0);
} else if (idev->addr_gen_mode == IN6_ADDR_GEN_MODE_EUI64) {
break;
case IN6_ADDR_GEN_MODE_EUI64:
/* addrconf_add_linklocal also adds a prefix_route and we
* only need to care about prefix routes if ipv6_generate_eui64
* couldn't generate one.
Expand All @@ -3058,6 +3079,11 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)
addrconf_add_linklocal(idev, &addr, 0);
else if (prefix_route)
addrconf_prefix_route(&addr, 64, idev->dev, 0, 0);
break;
case IN6_ADDR_GEN_MODE_NONE:
default:
/* will not add any link local address */
break;
}
}

Expand All @@ -3073,7 +3099,8 @@ static void addrconf_dev_config(struct net_device *dev)
(dev->type != ARPHRD_INFINIBAND) &&
(dev->type != ARPHRD_IEEE1394) &&
(dev->type != ARPHRD_TUNNEL6) &&
(dev->type != ARPHRD_6LOWPAN)) {
(dev->type != ARPHRD_6LOWPAN) &&
(dev->type != ARPHRD_NONE)) {
/* Alas, we support only Ethernet autoconfiguration. */
return;
}
Expand All @@ -3082,6 +3109,11 @@ static void addrconf_dev_config(struct net_device *dev)
if (IS_ERR(idev))
return;

/* this device type has no EUI support */
if (dev->type == ARPHRD_NONE &&
idev->addr_gen_mode == IN6_ADDR_GEN_MODE_EUI64)
idev->addr_gen_mode = IN6_ADDR_GEN_MODE_RANDOM;

addrconf_addr_gen(idev, false);
}

Expand Down Expand Up @@ -4926,7 +4958,8 @@ static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla)

if (mode != IN6_ADDR_GEN_MODE_EUI64 &&
mode != IN6_ADDR_GEN_MODE_NONE &&
mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY)
mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY &&
mode != IN6_ADDR_GEN_MODE_RANDOM)
return -EINVAL;

if (mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY &&
Expand Down

0 comments on commit cc9da6c

Please sign in to comment.