diff mbox series

[net-next,v2] ipv6: don't generate link-local addr in random or privacy mode

Message ID 20211116060959.32746-1-rocco.yue@mediatek.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series [net-next,v2] ipv6: don't generate link-local addr in random or privacy mode | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Single patches do not need cover letters
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 4757 this patch: 4757
netdev/cc_maintainers warning 3 maintainers not CCed: pbshelar@fb.com jonas@norrbonn.se thomas.karlsson@paneda.se
netdev/build_clang success Errors and warnings before: 863 this patch: 863
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 4914 this patch: 4914
netdev/checkpatch warning WARNING: line length of 82 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Rocco Yue Nov. 16, 2021, 6:09 a.m. UTC
In the 3GPP TS 29.061, here is a description as follows:
"In order to avoid any conflict between the link-local address
of the MS and that of the GGSN, the Interface-Identifier used by
the MS to build its link-local address shall be assigned by the
GGSN. The GGSN ensures the uniqueness of this Interface-Identifier.
The MT shall then enforce the use of this Interface-Identifier by
the TE"

In other words, in the cellular network, GGSN determines whether
to reply a solicited RA message by identifying the bottom 64 bits
of the source address of the received RS message. Therefore,
cellular network device's ipv6 link-local address should be set
as the format of fe80::(GGSN assigned IID).

To meet the above spec requirement, this patch adds two new
addr_gen_mode:

1) IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA, this mode is suitable
for cellular networks that support RFC7217. In this mode, the
kernel doesn't generate a link-local address for the cellular
NIC, and generates an ipv6 stable privacy global address after
receiving the RA message.

2) IN6_ADDR_GEN_MODE_RANDOM_NO_LLA, in this mode, the kernel
doesn't generate a link-local address for the cellular NIC,
and will use the bottom 64 bits of the link-local address(same
as the IID assigned by GGSN) to form an ipv6 global address
after receiveing the RA message.

Signed-off-by: Rocco Yue <rocco.yue@mediatek.com>
---
v1->v2: Add new addr_gen_mode instead of adding a separate sysctl.

v1 link:
https://patchwork.kernel.org/patch/12353465

---
 include/uapi/linux/if_link.h       |  2 ++
 net/ipv6/addrconf.c                | 22 ++++++++++++++++------
 tools/include/uapi/linux/if_link.h |  2 ++
 3 files changed, 20 insertions(+), 6 deletions(-)

Comments

David Ahern Nov. 16, 2021, 8:21 p.m. UTC | #1
On 11/15/21 11:09 PM, Rocco Yue wrote:
> In the 3GPP TS 29.061, here is a description as follows:
> "In order to avoid any conflict between the link-local address
> of the MS and that of the GGSN, the Interface-Identifier used by
> the MS to build its link-local address shall be assigned by the
> GGSN. The GGSN ensures the uniqueness of this Interface-Identifier.
> The MT shall then enforce the use of this Interface-Identifier by
> the TE"
> 
> In other words, in the cellular network, GGSN determines whether
> to reply a solicited RA message by identifying the bottom 64 bits
> of the source address of the received RS message. Therefore,
> cellular network device's ipv6 link-local address should be set
> as the format of fe80::(GGSN assigned IID).
> 
> To meet the above spec requirement, this patch adds two new
> addr_gen_mode:
> 
> 1) IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA, this mode is suitable
> for cellular networks that support RFC7217. In this mode, the
> kernel doesn't generate a link-local address for the cellular
> NIC, and generates an ipv6 stable privacy global address after
> receiving the RA message.
> 
> 2) IN6_ADDR_GEN_MODE_RANDOM_NO_LLA, in this mode, the kernel
> doesn't generate a link-local address for the cellular NIC,
> and will use the bottom 64 bits of the link-local address(same
> as the IID assigned by GGSN) to form an ipv6 global address
> after receiveing the RA message.
> 
> Signed-off-by: Rocco Yue <rocco.yue@mediatek.com>
> ---
> v1->v2: Add new addr_gen_mode instead of adding a separate sysctl.
> 
> v1 link:
> https://patchwork.kernel.org/patch/12353465
> 
> ---
>  include/uapi/linux/if_link.h       |  2 ++
>  net/ipv6/addrconf.c                | 22 ++++++++++++++++------
>  tools/include/uapi/linux/if_link.h |  2 ++
>  3 files changed, 20 insertions(+), 6 deletions(-)
> 

Reviewed-by: David Ahern <dsahern@kernel.org>

you should add tests under tools/testing/selftests/net.
Jakub Kicinski Nov. 17, 2021, 3:34 a.m. UTC | #2
On Tue, 16 Nov 2021 13:21:12 -0700 David Ahern wrote:
> Reviewed-by: David Ahern <dsahern@kernel.org>
> 
> you should add tests under tools/testing/selftests/net.

Please keep David's review tag and repost with a selftest.
Lorenzo Colitti Nov. 17, 2021, 5:09 a.m. UTC | #3
On Tue, Nov 16, 2021 at 3:15 PM Rocco Yue <rocco.yue@mediatek.com> wrote:
>
> In the 3GPP TS 29.061, here is a description as follows:
> "In order to avoid any conflict between the link-local address
> of the MS and that of the GGSN, the Interface-Identifier used by
> the MS to build its link-local address shall be assigned by the
> GGSN.
> [...]
> 1) IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA, this mode is suitable
> for cellular networks that support RFC7217. In this mode, the
> kernel doesn't generate a link-local address for the cellular
> NIC, and generates an ipv6 stable privacy global address after
> receiving the RA message.


It sounds like this would violate RFC 4291 section 2.1 which says "All
interfaces are required to have at least one Link-Local unicast
address. It is also not what 3GPP requires. 3GPP *does* require a
link-local address. It just requires that that the bottom 64 bits of
that link-local address be assigned by the network, not randomly.

Given that the kernel already supports tokenized interface addresses,
a better option here would be to add new addrgen modes where the
link-local address is formed from the interface token (idev->token),
and the other addresses are formed randomly or via RFC7217. These
modes could be called IN6_ADDR_GEN_MODE_RANDOM_LL_TOKEN and
IN6_ADDR_GEN_MODE_STABLE_PRIVACY_LL_TOKEN. When setting up the
interface, userspace could set disable_ipv6 to 1, then set the
interface token and the address generation mode via RTM_SETLINK, then
set disable_ipv6 to 0 to start autoconf. The kernel would then form
the link-local address via the token (which comes from the network),
and then set the global addresses either randomly or via RFC 7217.
Rocco Yue Nov. 17, 2021, 7:17 a.m. UTC | #4
On Wed, 2021-11-17 at 13:09 +0800, Lorenzo Colitti wrote:
> On Tue, Nov 16, 2021 at 3:15 PM Rocco Yue <rocco.yue@mediatek.com>
> wrote:
>> 
>> In the 3GPP TS 29.061, here is a description as follows:
>> "In order to avoid any conflict between the link-local address
>> of the MS and that of the GGSN, the Interface-Identifier used by
>> the MS to build its link-local address shall be assigned by the
>> GGSN.
>> [...]
>> 1) IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA, this mode is suitable
>> for cellular networks that support RFC7217. In this mode, the
>> kernel doesn't generate a link-local address for the cellular
>> NIC, and generates an ipv6 stable privacy global address after
>> receiving the RA message.
> 
> 
> It sounds like this would violate RFC 4291 section 2.1 which says
> "All
> interfaces are required to have at least one Link-Local unicast
> address. It is also not what 3GPP requires. 3GPP *does* require a
> link-local address. It just requires that that the bottom 64 bits of
> that link-local address be assigned by the network, not randomly.
>

Hi Lorenzo,

Thanks for your reply. :-)

Disabling the kernel's automatic link-local address generation
doesn't mean that it violates RFC 4291, because an appropriate
link-local addr can be added to the cellulal NIC through ioctl.

In fact, the current kernel has similar precedents. For example,
when device type is ARPHRD_NONE, and its addr_gen_mode is NONE,
the kernel will never generate a link-local addr for such interface.

> Given that the kernel already supports tokenized interface addresses,
> a better option here would be to add new addrgen modes where the
> link-local address is formed from the interface token (idev->token),
> and the other addresses are formed randomly or via RFC7217. These
> modes could be called IN6_ADDR_GEN_MODE_RANDOM_LL_TOKEN and
> IN6_ADDR_GEN_MODE_STABLE_PRIVACY_LL_TOKEN. When setting up the
> interface, userspace could set disable_ipv6 to 1, then set the
> interface token and the address generation mode via RTM_SETLINK, then
> set disable_ipv6 to 0 to start autoconf. The kernel would then form
> the link-local address via the token (which comes from the network),
> and then set the global addresses either randomly or via RFC 7217.

The method you mentioned can also solve the current problem, but it
seems to introduce more logic: 
  (1) set the cellular interface addr_gen_mode to RANDOM_LL_TOKEN or PRIVACY_LL_TOKEN;
  (2) set the cellular interface up;
  (3) disable ipv6 first;
  (4) set token addr through netlink;
  (5) autoconf through the kernel;
  (6) kernel trigger send RS message;

For the current patch, it is simpler, the configure process as follows:
  (1) set the cellular NIC addr_gen_mode to RANDOM_NO_LLA or PRIVACY_NO_LLA;
  (2) set the cellular interface up;
  (3) configure the link-local addr for the NIC by ioctl;
  (4) kernel trigger send RS message;

I wonder to hear what you and David think.

Thanks,

Rocco
Lorenzo Colitti Nov. 17, 2021, 8:36 a.m. UTC | #5
On Wed, Nov 17, 2021 at 4:22 PM Rocco Yue <rocco.yue@mediatek.com> wrote:
> Disabling the kernel's automatic link-local address generation
> doesn't mean that it violates RFC 4291, because an appropriate
> link-local addr can be added to the cellulal NIC through ioctl.

Well, it would mean that the kernel requires additional work from
userspace to respect the RFC.

> The method you mentioned can also solve the current problem, but it
> seems to introduce more logic:
>   (1) set the cellular interface addr_gen_mode to RANDOM_LL_TOKEN or PRIVACY_LL_TOKEN;
>   (2) set the cellular interface up;
>   (3) disable ipv6 first;

I don't think you need to set the interface up to disable IPv6. Also I
think that if the interface is down autoconf won't run so you don't
actually need to do this.

>   (4) set token addr through netlink;

Can't 4 be the same as 3? The same netlink message can configure both
the addr_gen_mode and the token, no?

It seems to me that the following should work, and would be much simpler.

1. Bring the interface down. All addresses are deleted.
2. Send a netlink request to set addr_gen_mode RANDOM_LL_TOKEN or
PRIVACY_LL_TOKEN and set the token.
3. Bring the interface up. Autoconf runs. The link-local address is
generated from the token. An RS is sent. When the RA is received, the
global address is generated using RFC 7217 or randomly.

Cheers,
Lorenzo
Maciej Żenczykowski Nov. 17, 2021, 9:50 a.m. UTC | #6
> Can't 4 be the same as 3? The same netlink message can configure both
> the addr_gen_mode and the token, no?
>
> It seems to me that the following should work, and would be much simpler.
>
> 1. Bring the interface down. All addresses are deleted.
> 2. Send a netlink request to set addr_gen_mode RANDOM_LL_TOKEN or
> PRIVACY_LL_TOKEN and set the token.
> 3. Bring the interface up. Autoconf runs. The link-local address is
> generated from the token. An RS is sent. When the RA is received, the
> global address is generated using RFC 7217 or randomly.

Could you simply manually add an ipv6 link local address to the
interface while it is down (ip -6 addr add fe80::..../64 dev X), then
bring the interface up (ip link set dev X up)...
All that would need to happen is the automatic link local generation
would need to be suppressed if there's already a link local ip
configured - which sounds like a good idea anyway, since why have two?
(btw. even a manually added link local ip will get deleted when the
interface gets brought back down)
diff mbox series

Patch

diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index eebd3894fe89..9c5695744c7d 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -428,6 +428,8 @@  enum in6_addr_gen_mode {
 	IN6_ADDR_GEN_MODE_NONE,
 	IN6_ADDR_GEN_MODE_STABLE_PRIVACY,
 	IN6_ADDR_GEN_MODE_RANDOM,
+	IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA,
+	IN6_ADDR_GEN_MODE_RANDOM_NO_LLA,
 };
 
 /* Bridge section */
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 3445f8017430..0045de10f4b5 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -392,7 +392,8 @@  static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
 	timer_setup(&ndev->rs_timer, addrconf_rs_timer, 0);
 	memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf));
 
-	if (ndev->cnf.stable_secret.initialized)
+	if (ndev->cnf.stable_secret.initialized &&
+	    ndev->cnf.addr_gen_mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA)
 		ndev->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
 
 	ndev->cnf.mtu6 = dev->mtu;
@@ -2578,7 +2579,8 @@  static void manage_tempaddrs(struct inet6_dev *idev,
 static bool is_addr_mode_generate_stable(struct inet6_dev *idev)
 {
 	return idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY ||
-	       idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
+	       idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM ||
+	       idev->cnf.addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA;
 }
 
 int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
@@ -3331,6 +3333,8 @@  static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)
 					      0, 0, GFP_KERNEL);
 		break;
 	case IN6_ADDR_GEN_MODE_NONE:
+	case IN6_ADDR_GEN_MODE_RANDOM_NO_LLA:
+	case IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA:
 	default:
 		/* will not add any link local address */
 		break;
@@ -5798,7 +5802,9 @@  static int check_addr_gen_mode(int mode)
 	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_RANDOM)
+	    mode != IN6_ADDR_GEN_MODE_RANDOM &&
+	    mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA &&
+	    mode != IN6_ADDR_GEN_MODE_RANDOM_NO_LLA)
 		return -EINVAL;
 	return 1;
 }
@@ -6428,15 +6434,19 @@  static int addrconf_sysctl_stable_secret(struct ctl_table *ctl, int write,
 		for_each_netdev(net, dev) {
 			struct inet6_dev *idev = __in6_dev_get(dev);
 
-			if (idev) {
+			if (idev && idev->cnf.addr_gen_mode !=
+			    IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA) {
 				idev->cnf.addr_gen_mode =
 					IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
 			}
 		}
 	} else {
 		struct inet6_dev *idev = ctl->extra1;
-
-		idev->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
+		if (idev->cnf.addr_gen_mode !=
+		    IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA) {
+			idev->cnf.addr_gen_mode =
+				IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
+		}
 	}
 
 out:
diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h
index b3610fdd1fee..fb69137aea89 100644
--- a/tools/include/uapi/linux/if_link.h
+++ b/tools/include/uapi/linux/if_link.h
@@ -241,6 +241,8 @@  enum in6_addr_gen_mode {
 	IN6_ADDR_GEN_MODE_NONE,
 	IN6_ADDR_GEN_MODE_STABLE_PRIVACY,
 	IN6_ADDR_GEN_MODE_RANDOM,
+	IN6_ADDR_GEN_MODE_STABLE_PRIVACY_NO_LLA,
+	IN6_ADDR_GEN_MODE_RANDOM_NO_LLA,
 };
 
 /* Bridge section */