lib: qemu: rbd: Properly escape IPv6 addresses.

Each ':' character in the address must be escaped from qemu.

Thanks: Jonathan Wright
This commit is contained in:
Richard W.M. Jones
2019-04-01 16:36:15 +01:00
parent f79129b8dc
commit e047cc4da8
5 changed files with 62 additions and 26 deletions

View File

@@ -47,6 +47,7 @@ extern char *guestfs_int_concat_strings (char *const *);
extern char **guestfs_int_copy_string_list (char *const *);
extern char *guestfs_int_join_strings (const char *sep, char *const *);
extern char **guestfs_int_split_string (char sep, const char *);
extern char *guestfs_int_replace_string (const char *str, const char *s1, const char *s2);
extern char *guestfs_int_exit_status_to_string (int status, const char *cmd_name, char *buffer, size_t buflen);
extern int guestfs_int_random_string (char *ret, size_t len);
extern char *guestfs_int_drive_name (size_t index, char *ret);

View File

@@ -214,6 +214,53 @@ guestfs_int_split_string (char sep, const char *str)
return ret;
}
/**
* Replace every instance of C<s1> appearing in C<str> with C<s2>. A
* newly allocated string is returned which must be freed by the
* caller. If allocation fails this can return C<NULL>.
*
* For example:
*
* replace_string ("abcabb", "ab", "a");
*
* would return C<"acab">.
*/
char *
guestfs_int_replace_string (const char *str, const char *s1, const char *s2)
{
const size_t len = strlen (str), s1len = strlen (s1), s2len = strlen (s2);
size_t i, n;
char *ret;
/* Count the size of the final string. */
n = 0;
for (i = 0; i < len; ++i) {
if (strncmp (&str[i], s1, s1len) == 0)
n += s2len;
else
n++;
}
ret = malloc (n+1);
if (ret == NULL)
return NULL;
n = 0;
for (i = 0; i < len; ++i) {
if (strncmp (&str[i], s1, s1len) == 0) {
strcpy (&ret[n], s2);
n += s2len;
}
else {
ret[n] = str[i];
n++;
}
}
ret[n] = '\0';
return ret;
}
/**
* Translate a wait/system exit status into a printable string.
*/

View File

@@ -903,37 +903,24 @@ guestfs_int_drive_source_qemu_param (guestfs_h *g,
}
case drive_protocol_rbd: {
CLEANUP_FREE_STRING_LIST char **hosts = NULL;
CLEANUP_FREE char *mon_host = NULL, *username = NULL, *secret = NULL;
const char *auth;
size_t n = 0;
size_t i, j;
size_t i;
/* Build the list of all the mon hosts. */
hosts = safe_calloc (g, src->nr_servers + 1, sizeof (char *));
/* build the list of all the mon hosts */
for (i = 0; i < src->nr_servers; i++) {
n += strlen (src->servers[i].u.hostname);
n += 8; /* for slashes, colons, & port numbers */
}
n++; /* for \0 */
mon_host = safe_malloc (g, n);
n = 0;
for (i = 0; i < src->nr_servers; i++) {
CLEANUP_FREE char *port = NULL;
CLEANUP_FREE char *escaped_host;
for (j = 0; j < strlen (src->servers[i].u.hostname); j++)
mon_host[n++] = src->servers[i].u.hostname[j];
mon_host[n++] = '\\';
mon_host[n++] = ':';
port = safe_asprintf (g, "%d", src->servers[i].port);
for (j = 0; j < strlen (port); j++)
mon_host[n++] = port[j];
/* join each host with \; */
if (i != src->nr_servers - 1) {
mon_host[n++] = '\\';
mon_host[n++] = ';';
}
escaped_host =
guestfs_int_replace_string (src->servers[i].u.hostname, ":", "\\:");
if (escaped_host == NULL) g->abort_cb ();
hosts[i] =
safe_asprintf (g, "%s\\:%d", escaped_host, src->servers[i].port);
}
mon_host[n] = '\0';
mon_host = guestfs_int_join_strings ("\\;", hosts);
if (src->username)
username = safe_asprintf (g, ":id=%s", src->username);

View File

@@ -56,7 +56,7 @@ rm -f "$DEBUG_QEMU_FILE"
$guestfish -d ceph1 run ||:
check_output
grep -sq -- '-drive file=rbd:abc-def/ghi-jkl:mon_host=1.2.3.4\\:1234\\;1.2.3.5\\:1235\\;1.2.3.6\\:1236:auth_supported=none,' "$DEBUG_QEMU_FILE" || fail ceph1
grep -sq -- '-drive file=rbd:abc-def/ghi-jkl:mon_host=1.2.3.4\\:1234\\;1.2.3.5\\:1235\\;1.2.3.6\\:1236\\;\[fe80\\:\\:1\]\\:1237:auth_supported=none,' "$DEBUG_QEMU_FILE" || fail ceph1
rm "$DEBUG_QEMU_FILE"
$guestfish -d ceph2 run ||:

View File

@@ -35,6 +35,7 @@
<host name='1.2.3.4' port='1234'/>
<host name='1.2.3.5' port='1235'/>
<host name='1.2.3.6' port='1236'/>
<host name='[fe80::1]' port='1237'/>
</source>
<target dev='vda' bus='virtio'/>
</disk>