[RFC] CIFS: Make sure IPv6 host uses numeric scope
"\"Per Forlin <per.forlin" at axis.com
"\"Per Forlin <per.forlin" at axis.com
Mon Sep 19 12:59:29 UTC 2016
From: Per Förlin <perfn at axis.com>
Package: busybox
Version: master (1_25_0+)
Severity: medium
The purpose of this draft patch is to highlight an
issue concerning address scope in IPv6 and CIFS kernel implementation.
Without this patch the following command fails:
mount -t cifs //fe80::6a05:caff:fe3e:dbf5%eth0/test test
Based on this post
http://patchwork.sourceware.org/patch/1629/
it seems like this topic has been up for discussion before.
However it looks like the NI_NUMERICSCOPE flag for getnaminfo()
never made it to glibc.
getnameinfo() always returns the address scope using the
name representation but the CIFS kernel implementation
expects a numeric scope ID.
There are different ways to approach this.
1. Parse the host string manually and converting the scope
using if_nametoindex().
2. Convert the host address to binary and back again.
This patch uses alternative #2.
Re-create the host address using the numeric scope ID retrieved
by getaddrinfo().
---
include/libbb.h | 1 +
libbb/xconnect.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++------
util-linux/mount.c | 2 +-
3 files changed, 53 insertions(+), 7 deletions(-)
diff --git a/include/libbb.h b/include/libbb.h
index 3752df9..48e110a 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -688,6 +688,7 @@ char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa) FAST_FUNC RETU
/* inet_[ap]ton on steroids */
char* xmalloc_sockaddr2dotted(const struct sockaddr *sa) FAST_FUNC RETURNS_MALLOC;
char* xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa) FAST_FUNC RETURNS_MALLOC;
+char* xmalloc_sockaddr2dotted_noport_num(const struct sockaddr *sa) FAST_FUNC RETURNS_MALLOC;
// "old" (ipv4 only) API
// users: traceroute.c hostname.c - use _list_ of all IPs
struct hostent *xgethostbyname(const char *name) FAST_FUNC;
diff --git a/libbb/xconnect.c b/libbb/xconnect.c
index 6e78e63..5095c35 100644
--- a/libbb/xconnect.c
+++ b/libbb/xconnect.c
@@ -433,10 +433,45 @@ int FAST_FUNC xconnect_stream(const len_and_sockaddr *lsa)
return fd;
}
+/* Make sure the host is specified with a numeric scope.
+ * Numeric scope is required by the CIFS kernel implementation. */
+static int host_make_numeric_scope(char * host, int host_size) {
+ struct addrinfo *addr = NULL;
+ struct sockaddr_in6 *sin6;
+ int res = -1;
+
+ if (getaddrinfo(host, NULL, NULL, &addr) != 0)
+ goto out;
+
+ if (addr->ai_family != AF_INET6)
+ goto out;
+
+ sin6 = (struct sockaddr_in6 *)addr->ai_addr;
+ if (!sin6->sin6_scope_id) {
+ res = 0; /* no scope to be processed */
+ goto out;
+ }
+
+ if (inet_ntop(AF_INET6, &sin6->sin6_addr, host, host_size) != NULL) {
+ int len = strnlen(host, host_size);
+ if (snprintf(host + len, host_size - len,
+ "%%%u", sin6->sin6_scope_id) > 1)
+ res = 0;
+ }
+
+out:
+ if (res != 0)
+ bb_perror_msg("Failed to convert %s to numeric scope", host);
+
+ freeaddrinfo(addr);
+ return res;
+}
+
/* We hijack this constant to mean something else */
/* It doesn't hurt because we will add this bit anyway */
#define IGNORE_PORT NI_NUMERICSERV
-static char* FAST_FUNC sockaddr2str(const struct sockaddr *sa, int flags)
+static char* FAST_FUNC sockaddr2str(const struct sockaddr *sa, int flags,
+ int num_scope)
{
char host[128];
char serv[16];
@@ -464,6 +499,10 @@ static char* FAST_FUNC sockaddr2str(const struct sockaddr *sa, int flags)
/* do not resolve port# into service _name_ */
flags | NI_NUMERICSERV
);
+ if (num_scope && sa->sa_family == AF_INET6 &&
+ host_make_numeric_scope(host, sizeof(host)) != 0)
+ return NULL;
+
if (rc)
return NULL;
if (flags & IGNORE_PORT)
@@ -484,24 +523,30 @@ static char* FAST_FUNC sockaddr2str(const struct sockaddr *sa, int flags)
char* FAST_FUNC xmalloc_sockaddr2host(const struct sockaddr *sa)
{
- return sockaddr2str(sa, 0);
+ return sockaddr2str(sa, 0, false);
}
char* FAST_FUNC xmalloc_sockaddr2host_noport(const struct sockaddr *sa)
{
- return sockaddr2str(sa, IGNORE_PORT);
+ return sockaddr2str(sa, IGNORE_PORT, false);
}
char* FAST_FUNC xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa)
{
- return sockaddr2str(sa, NI_NAMEREQD | IGNORE_PORT);
+ return sockaddr2str(sa, NI_NAMEREQD | IGNORE_PORT, false);
}
char* FAST_FUNC xmalloc_sockaddr2dotted(const struct sockaddr *sa)
{
- return sockaddr2str(sa, NI_NUMERICHOST);
+ return sockaddr2str(sa, NI_NUMERICHOST, false);
}
char* FAST_FUNC xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa)
{
- return sockaddr2str(sa, NI_NUMERICHOST | IGNORE_PORT);
+ return sockaddr2str(sa, NI_NUMERICHOST | IGNORE_PORT, false);
+}
+
+char* FAST_FUNC xmalloc_sockaddr2dotted_noport_num(const struct sockaddr *sa)
+{
+ return sockaddr2str(sa, NI_NUMERICHOST | IGNORE_PORT,
+ true /* numeric scope */);
}
diff --git a/util-linux/mount.c b/util-linux/mount.c
index 13590ce..b87be90 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -1972,7 +1972,7 @@ static int singlemount(struct mntent *mp, int ignore_busy)
goto report_error;
// Insert "ip=..." option into options
- dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
+ dotted = xmalloc_sockaddr2dotted_noport_num(&lsa->u.sa);
if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
ip = xasprintf("ip=%s", dotted);
if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
--
2.1.4
More information about the busybox
mailing list