diff mbox series

[v2] net/9p/fd: support ipv6 for trans=tcp

Message ID 20250117214943.6368-2-joshuamurphy@posteo.net (mailing list archive)
State New
Headers show
Series [v2] net/9p/fd: support ipv6 for trans=tcp | expand

Commit Message

Joshua Murphy Jan. 17, 2025, 9:44 p.m. UTC
Allows specifying an IPv6 address when mounting a remote 9p file system.

Signed-off-by: Joshua Murphy <joshuamurphy@posteo.net>
---
v1 -> v2:
Simplified support using inet_pton_with_scope, initialized
sockaddr_storage variables to zero, and removed unneeded argument
from p9_bind_privport. 

 net/9p/trans_fd.c | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

Comments

Daniel Verkamp Jan. 17, 2025, 10:50 p.m. UTC | #1
On Fri, Jan 17, 2025 at 1:52 PM Joshua Murphy <joshuamurphy@posteo.net> wrote:
>
> Allows specifying an IPv6 address when mounting a remote 9p file system.
>
> Signed-off-by: Joshua Murphy <joshuamurphy@posteo.net>
> ---
[...]
> -       cl.sin_family = AF_INET;
> -       cl.sin_addr.s_addr = htonl(INADDR_ANY);
> +       stor.ss_family = sock->ops->family;
> +       inet_addr_is_any((struct sockaddr *) &stor);

It looks like inet_addr_is_any() checks the current sin_addr/sin6_addr
of a sockaddr, but does not change it, so this doesn't seem quite
right (its only effect is to return a bool, which is discarded here).

[...]
> -       if (addr == NULL || valid_ipaddr4(addr) < 0)
> -               return -EINVAL;
> +       sprintf(port_str, "%u", opts.port);
> +       err = inet_pton_with_scope(current->nsproxy->net_ns, AF_UNSPEC, addr,
> +                                  port_str, &stor);
> +       if (addr == NULL || err < 0) {

inet_pton_with_scope() appears to unconditionally dereference its
`src` parameter (`addr` in the call above), so the `addr == NULL`
check is too late.
Joshua Murphy Jan. 18, 2025, 1:23 a.m. UTC | #2
> It looks like inet_addr_is_any() checks the current sin_addr/sin6_addr
> of a sockaddr, but does not change it, so this doesn't seem quite
> right (its only effect is to return a bool, which is discarded here).

Huh, I’ll definitely fix that.
For some reason I must’ve thought it changed the addresses rather than
checking them.

> inet_pton_with_scope() appears to unconditionally dereference its
> `src` parameter (`addr` in the call above), so the `addr == NULL`
> check is too late.

I’ll put it in a separate check before the inet one.

Thanks,
Dominique Martinet Jan. 18, 2025, 7:27 a.m. UTC | #3
Joshua Murphy wrote on Fri, Jan 17, 2025 at 09:44:46PM +0000:
> Allows specifying an IPv6 address when mounting a remote 9p file system.

Thanks for the v2!

Daniel beat me to the important bits, just a couple more.

> -	if (addr == NULL || valid_ipaddr4(addr) < 0)

valid_ipaddr4 is no longer used so please also remove the function
definition just above as well

> -		return -EINVAL;
> +	sprintf(port_str, "%u", opts.port);

Oh, I hadn't realized this takes a string..

The previous string -> u16 conversion into opts.port happens in the same
file (parse_opts), and trans_opts is only used to print options in
/proc/mount later so can be made a char * as well, but that is code
cleanup that can (and probably should) be done in a separate patch.
Let's keep the sprintf here and I'll try to find time for that later
unless you want to do it.


Cheers,
Joshua Murphy Jan. 18, 2025, 6:54 p.m. UTC | #4
> Let's keep the sprintf here and I'll try to find time for that later
> unless you want to do it.

Doesn’t seem too crazy, so I’ll do it once this one is good.
diff mbox series

Patch

diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index 196060dc6..eaf72067e 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -11,6 +11,7 @@ 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/in.h>
+#include <linux/in6.h>
 #include <linux/module.h>
 #include <linux/net.h>
 #include <linux/ipv6.h>
@@ -973,45 +974,48 @@  static inline int valid_ipaddr4(const char *buf)
 
 static int p9_bind_privport(struct socket *sock)
 {
-	struct sockaddr_in cl;
+	struct sockaddr_storage stor = { 0 };
 	int port, err = -EINVAL;
 
-	memset(&cl, 0, sizeof(cl));
-	cl.sin_family = AF_INET;
-	cl.sin_addr.s_addr = htonl(INADDR_ANY);
+	stor.ss_family = sock->ops->family;
+	inet_addr_is_any((struct sockaddr *) &stor);
 	for (port = p9_ipport_resv_max; port >= p9_ipport_resv_min; port--) {
-		cl.sin_port = htons((ushort)port);
-		err = kernel_bind(sock, (struct sockaddr *)&cl, sizeof(cl));
+		if (stor.ss_family == AF_INET)
+			((struct sockaddr_in *) &stor)->sin_port = htons((ushort)port);
+		else
+			((struct sockaddr_in6 *) &stor)->sin6_port = htons((ushort)port);
+		err = kernel_bind(sock, (struct sockaddr *) &stor, sizeof(stor));
 		if (err != -EADDRINUSE)
 			break;
 	}
 	return err;
 }
 
-
 static int
 p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
 {
 	int err;
+	char port_str[6];
 	struct socket *csocket;
-	struct sockaddr_in sin_server;
+	struct sockaddr_storage stor = { 0 };
 	struct p9_fd_opts opts;
 
 	err = parse_opts(args, &opts);
 	if (err < 0)
 		return err;
 
-	if (addr == NULL || valid_ipaddr4(addr) < 0)
-		return -EINVAL;
+	sprintf(port_str, "%u", opts.port);
+	err = inet_pton_with_scope(current->nsproxy->net_ns, AF_UNSPEC, addr,
+				   port_str, &stor);
+	if (addr == NULL || err < 0) {
+		return err;
+	}
 
 	csocket = NULL;
 
 	client->trans_opts.tcp.port = opts.port;
 	client->trans_opts.tcp.privport = opts.privport;
-	sin_server.sin_family = AF_INET;
-	sin_server.sin_addr.s_addr = in_aton(addr);
-	sin_server.sin_port = htons(opts.port);
-	err = __sock_create(current->nsproxy->net_ns, PF_INET,
+	err = __sock_create(current->nsproxy->net_ns, stor.ss_family,
 			    SOCK_STREAM, IPPROTO_TCP, &csocket, 1);
 	if (err) {
 		pr_err("%s (%d): problem creating socket\n",
@@ -1030,8 +1034,8 @@  p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
 	}
 
 	err = READ_ONCE(csocket->ops)->connect(csocket,
-				    (struct sockaddr *)&sin_server,
-				    sizeof(struct sockaddr_in), 0);
+					       (struct sockaddr *) &stor,
+					       sizeof(stor), 0);
 	if (err < 0) {
 		pr_err("%s (%d): problem connecting socket to %s\n",
 		       __func__, task_pid_nr(current), addr);