diff options
author | Robert Ancell <robert.ancell@canonical.com> | 2014-11-12 12:14:06 +1300 |
---|---|---|
committer | Robert Ancell <robert.ancell@canonical.com> | 2014-11-12 12:14:06 +1300 |
commit | 705927dd0d9228894be57975d20c6968e10cb571 (patch) | |
tree | 420125d3a6a6fdd4e3c0694d823ced1a0419e338 /tests/src | |
parent | 98778683a05c3a27902309763ed27cb473ef6c05 (diff) | |
download | lightdm-705927dd0d9228894be57975d20c6968e10cb571.tar.gz |
Redirect bound socket ports so networking tests can be run non-root
Diffstat (limited to 'tests/src')
-rw-r--r-- | tests/src/libsystem.c | 184 | ||||
-rw-r--r-- | tests/src/vnc-client.c | 31 |
2 files changed, 186 insertions, 29 deletions
diff --git a/tests/src/libsystem.c b/tests/src/libsystem.c index 0510c9a5..88d9a61d 100644 --- a/tests/src/libsystem.c +++ b/tests/src/libsystem.c @@ -8,6 +8,8 @@ #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> +#include <sys/socket.h> +#include <netinet/in.h> #include <pwd.h> #include <unistd.h> #include <dirent.h> @@ -542,6 +544,188 @@ ioctl (int d, unsigned long request, ...) } } +static void +add_port_redirect (int requested_port, int redirected_port) +{ + GKeyFile *file; + gchar *path, *name, *data; + + file = g_key_file_new (); + path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), ".port-redirects", NULL); + g_key_file_load_from_file (file, path, G_KEY_FILE_NONE, NULL); + + name = g_strdup_printf ("%d", requested_port); + g_key_file_set_integer (file, name, "redirected", redirected_port); + g_free (name); + + data = g_key_file_to_data (file, NULL, NULL); + g_file_set_contents (path, data, -1, NULL); + g_free (data); + g_free (path); + + g_key_file_free (file); +} + +static int +find_port_redirect (int port) +{ + GKeyFile *file; + gchar *path, *name; + int redirected_port; + + file = g_key_file_new (); + path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), ".port-redirects", NULL); + g_key_file_load_from_file (file, path, G_KEY_FILE_NONE, NULL); + g_free (path); + + name = g_strdup_printf ("%d", port); + redirected_port = g_key_file_get_integer (file, name, "redirected", NULL); + g_free (name); + g_key_file_free (file); + + return redirected_port; +} + +int +bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + int port = 0, redirected_port = 0; + int (*_bind) (int sockfd, const struct sockaddr *addr, socklen_t addrlen); + const struct sockaddr *modified_addr = addr; + struct sockaddr_in temp_addr; + struct sockaddr_in6 temp_addr6; + int retval; + + _bind = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "bind"); + + switch (addr->sa_family) + { + case AF_INET: + port = ntohs (((const struct sockaddr_in *) addr)->sin_port); + redirected_port = find_port_redirect (port); + memcpy (&temp_addr, addr, sizeof (struct sockaddr_in)); + modified_addr = (struct sockaddr *) &temp_addr; + if (redirected_port != 0) + temp_addr.sin_port = htons (redirected_port); + else + temp_addr.sin_port = 0; + break; + case AF_INET6: + port = ntohs (((const struct sockaddr_in6 *) addr)->sin6_port); + redirected_port = find_port_redirect (port); + memcpy (&temp_addr6, addr, sizeof (struct sockaddr_in6)); + modified_addr = (struct sockaddr *) &temp_addr6; + if (redirected_port != 0) + temp_addr6.sin6_port = htons (redirected_port); + else + temp_addr6.sin6_port = 0; + break; + } + + retval = _bind (sockfd, modified_addr, addrlen); + + socklen_t temp_addr_len; + switch (addr->sa_family) + { + case AF_INET: + temp_addr_len = sizeof (temp_addr); + getsockname (sockfd, &temp_addr, &temp_addr_len); + if (redirected_port == 0) + { + redirected_port = ntohs (temp_addr.sin_port); + add_port_redirect (port, redirected_port); + } + break; + case AF_INET6: + temp_addr_len = sizeof (temp_addr6); + getsockname (sockfd, &temp_addr6, &temp_addr_len); + if (redirected_port == 0) + { + redirected_port = ntohs (temp_addr6.sin6_port); + add_port_redirect (port, redirected_port); + } + break; + } + + return retval; +} + +int +connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + int port, redirected_port; + const struct sockaddr *modified_addr = addr; + struct sockaddr_in temp_addr; + struct sockaddr_in6 temp_addr6; + int (*_connect) (int sockfd, const struct sockaddr *addr, socklen_t addrlen); + + _connect = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "connect"); + + switch (addr->sa_family) + { + case AF_INET: + port = ntohs (((const struct sockaddr_in *) addr)->sin_port); + redirected_port = find_port_redirect (port); + if (redirected_port != 0) + { + memcpy (&temp_addr, addr, sizeof (struct sockaddr_in)); + temp_addr.sin_port = htons (redirected_port); + modified_addr = (struct sockaddr *) &temp_addr; + } + break; + case AF_INET6: + port = ntohs (((const struct sockaddr_in6 *) addr)->sin6_port); + redirected_port = find_port_redirect (port); + if (redirected_port != 0) + { + memcpy (&temp_addr6, addr, sizeof (struct sockaddr_in6)); + temp_addr6.sin6_port = htons (redirected_port); + modified_addr = (struct sockaddr *) &temp_addr6; + } + break; + } + + return _connect (sockfd, modified_addr, addrlen); +} + +ssize_t +sendto (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) +{ + int port, redirected_port; + const struct sockaddr *modified_addr = dest_addr; + struct sockaddr_in temp_addr; + struct sockaddr_in6 temp_addr6; + ssize_t (*_sendto) (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); + + _sendto = (ssize_t (*)(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "sendto"); + + switch (dest_addr->sa_family) + { + case AF_INET: + port = ntohs (((const struct sockaddr_in *) dest_addr)->sin_port); + redirected_port = find_port_redirect (port); + if (redirected_port != 0) + { + memcpy (&temp_addr, dest_addr, sizeof (struct sockaddr_in)); + temp_addr.sin_port = htons (redirected_port); + modified_addr = (struct sockaddr *) &temp_addr; + } + break; + case AF_INET6: + port = ntohs (((const struct sockaddr_in6 *) dest_addr)->sin6_port); + redirected_port = find_port_redirect (port); + if (redirected_port != 0) + { + memcpy (&temp_addr6, dest_addr, sizeof (struct sockaddr_in6)); + temp_addr6.sin6_port = htons (redirected_port); + modified_addr = (struct sockaddr *) &temp_addr6; + } + break; + } + + return _sendto (sockfd, buf, len, flags, modified_addr, addrlen); +} + int close (int fd) { diff --git a/tests/src/vnc-client.c b/tests/src/vnc-client.c index b1917049..2fe0a017 100644 --- a/tests/src/vnc-client.c +++ b/tests/src/vnc-client.c @@ -12,9 +12,6 @@ static GKeyFile *config; int main (int argc, char **argv) { - gchar *server_address; - gchar *hostname, *c; - gint port; GError *error = NULL; GSocket *socket; GSocketConnectable *address; @@ -34,12 +31,7 @@ main (int argc, char **argv) config = g_key_file_new (); g_key_file_load_from_file (config, g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "script", NULL), G_KEY_FILE_NONE, NULL); - if (argc > 1) - server_address = g_strdup (argv[1]); - else - server_address = g_strdup (":0"); - - status_notify ("VNC-CLIENT CONNECT SERVER=%s", server_address); + status_notify ("VNC-CLIENT CONNECT"); socket = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, &error); if (error) @@ -48,26 +40,7 @@ main (int argc, char **argv) if (!socket) return EXIT_FAILURE; - hostname = g_strdup (server_address); - c = strchr (hostname, ':'); - if (c) - { - *c = '\0'; - gchar *port_string = c + 1; - if (g_str_has_prefix (port_string, ":")) - port = atoi (port_string + 1); - else - port = 5900 + atoi (port_string); - } - else - port = 5900; - if (strcmp (hostname, "") == 0) - { - g_free (hostname); - hostname = g_strdup ("localhost"); - } - - address = g_network_address_new (hostname, port); + address = g_network_address_new ("localhost", 5900); enumerator = g_socket_connectable_enumerate (address); result = FALSE; while (TRUE) |