Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F2020084
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
39 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/libtap/libtap.c b/libtap/libtap.c
index b4071eff..46c6dd27 100644
--- a/libtap/libtap.c
+++ b/libtap/libtap.c
@@ -1,848 +1,862 @@
#include "config.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/if_tun.h>
#include <net/ethernet.h>
#include <netinet/ether.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <limits.h>
+#include <stdio.h>
-#include "utils.h"
#include "libtap.h"
#include "libtap_private.h"
STATIC int tap_init = 0;
STATIC struct tap_config tap_cfg;
STATIC pthread_mutex_t tap_mutex = PTHREAD_MUTEX_INITIALIZER;
/* forward declarations */
-STATIC int tap_execute_shell(const char *command);
-static int tap_exec_updown(const knet_tap_t knet_tap, const char *action);
+STATIC int tap_execute_shell(const char *command, char **error_string);
+static int tap_exec_updown(const knet_tap_t knet_tap, const char *action, char **error_string);
static int tap_set_down(knet_tap_t knet_tap);
static int tap_read_pipe(int fd, char **file, size_t *length);
static int tap_check(const knet_tap_t knet_tap);
static void tap_close(knet_tap_t knet_tap);
static void tap_close_cfg(void);
static int tap_get_mtu(const knet_tap_t knet_tap);
static int tap_get_mac(const knet_tap_t knet_tap, char **ether_addr);
static int tap_set_down(knet_tap_t knet_tap);
static char *tap_get_v4_broadcast(const char *ip_addr, const char *prefix);
static int tap_set_ip(knet_tap_t knet_tap, const char *command,
- const char *ip_addr, const char *prefix);
+ const char *ip_addr, const char *prefix,
+ char **error_string);
static int tap_find_ip(knet_tap_t knet_tap,
const char *ip_addr, const char *prefix,
struct tap_ip **tap_ip, struct tap_ip **tap_ip_prev);
static int tap_read_pipe(int fd, char **file, size_t *length)
{
char buf[4096];
int n;
int done = 0;
*file = NULL;
*length = 0;
memset(buf, 0, sizeof(buf));
while (!done) {
n = read(fd, buf, sizeof(buf));
if (n < 0) {
if (errno == EINTR)
continue;
if (*file)
free(*file);
return n;
}
if (n == 0 && (!*length))
return 0;
if (n == 0)
done = 1;
if (*file)
*file = realloc(*file, (*length) + n + done);
else
*file = malloc(n + done);
if (!*file)
return -1;
memcpy((*file) + (*length), buf, n);
*length += (done + n);
}
/* Null terminator */
(*file)[(*length) - 1] = 0;
return 0;
}
-STATIC int tap_execute_shell(const char *command)
+STATIC int tap_execute_shell(const char *command, char **error_string)
{
pid_t pid;
int status, err = 0;
int fd[2];
- char *data = NULL;
size_t size = 0;
- if (command == NULL) {
+ if ((command == NULL) || (!error_string)) {
errno = EINVAL;
return -1;
}
+ *error_string = NULL;
+
err = pipe(fd);
if (err)
goto out_clean;
pid = fork();
if (pid < 0) {
err = pid;
goto out_clean;
}
if (pid) { /* parent */
close(fd[1]);
- err = tap_read_pipe(fd[0], &data, &size);
+ err = tap_read_pipe(fd[0], error_string, &size);
if (err)
goto out_clean;
waitpid(pid, &status, 0);
if (!WIFEXITED(status)) {
- log_error("shell: child did not terminate normally");
err = -1;
goto out_clean;
}
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
- log_error("shell: child returned %d", WEXITSTATUS(status));
- err = -1;
+ err = WEXITSTATUS(status);
goto out_clean;
}
} else { /* child */
close(0);
close(1);
close(2);
close(fd[0]);
- if(dup2(fd[1], 1) < 0)
- log_error("Unable to redirect stdout");
- if(dup2(fd[1], 2) < 0)
- log_error("Unable to redirect stderr");
+ dup2(fd[1], 1);
+ dup2(fd[1], 2);
close(fd[1]);
execlp("/bin/sh", "/bin/sh", "-c", command, NULL);
exit(EXIT_FAILURE);
}
out_clean:
close(fd[0]);
close(fd[1]);
- if ((size) && (err)) {
- log_error("%s", data);
- free(data);
- }
-
return err;
}
-static int tap_exec_updown(const knet_tap_t knet_tap, const char *action)
+static int tap_exec_updown(const knet_tap_t knet_tap, const char *action, char **error_string)
{
char command[PATH_MAX];
if (!knet_tap->hasupdown)
return 0;
memset(command, 0, PATH_MAX);
snprintf(command, PATH_MAX, "%s%s/%s", knet_tap->updownpath, action, knet_tap->ifname);
- return tap_execute_shell(command);
+ return tap_execute_shell(command, error_string);
}
static int tap_check(const knet_tap_t knet_tap)
{
knet_tap_t temp = tap_cfg.tap_head;
if (!knet_tap)
return 0;
while (temp != NULL) {
if (knet_tap == temp)
return 1;
temp = temp->next;
}
return 0;
}
static void tap_close(knet_tap_t knet_tap)
{
if (!knet_tap)
return;
if (knet_tap->knet_tap_fd)
close(knet_tap->knet_tap_fd);
free(knet_tap);
return;
}
static void tap_close_cfg(void)
{
if (tap_cfg.tap_head == NULL) {
close(tap_cfg.tap_sockfd);
tap_init = 0;
}
}
static int tap_get_mtu(const knet_tap_t knet_tap)
{
int err;
err = ioctl(tap_cfg.tap_sockfd, SIOCGIFMTU, &knet_tap->ifr);
if (err)
goto out_clean;
err = knet_tap->ifr.ifr_mtu;
out_clean:
return err;
}
static int tap_get_mac(const knet_tap_t knet_tap, char **ether_addr)
{
int err;
char mac[MAX_MAC_CHAR];
err = ioctl(tap_cfg.tap_sockfd, SIOCGIFHWADDR, &knet_tap->ifr);
if (err)
goto out_clean;
ether_ntoa_r((struct ether_addr *)knet_tap->ifr.ifr_hwaddr.sa_data, mac);
*ether_addr = strdup(mac);
if (!*ether_addr)
err = -1;
out_clean:
return err;
}
knet_tap_t knet_tap_find(char *dev, size_t dev_size)
{
knet_tap_t knet_tap;
if (dev == NULL) {
errno = EINVAL;
return NULL;
}
if (dev_size < IFNAMSIZ) {
errno = EINVAL;
return NULL;
}
if (strlen(dev) > IFNAMSIZ) {
errno = E2BIG;
return NULL;
}
pthread_mutex_lock(&tap_mutex);
knet_tap = tap_cfg.tap_head;
while (knet_tap != NULL) {
if (!strcmp(dev, knet_tap->ifname))
break;
knet_tap = knet_tap->next;
}
pthread_mutex_unlock(&tap_mutex);
return knet_tap;
}
knet_tap_t knet_tap_open(char *dev, size_t dev_size, const char *updownpath)
{
knet_tap_t knet_tap;
char *temp_mac = NULL;
if (dev == NULL) {
errno = EINVAL;
return NULL;
}
if (dev_size < IFNAMSIZ) {
errno = EINVAL;
return NULL;
}
if (strlen(dev) > IFNAMSIZ) {
errno = E2BIG;
return NULL;
}
if (updownpath) {
/* only absolute paths */
if (updownpath[0] != '/') {
errno = EINVAL;
return NULL;
}
/* 14: 2 for /, 1 for \0 + 11 (post-down.d) */
if (strlen(updownpath) >= (PATH_MAX - (strlen(dev) + 14))) {
errno = E2BIG;
return NULL;
}
}
pthread_mutex_lock(&tap_mutex);
knet_tap = malloc(sizeof(struct tap_iface));
if (!knet_tap)
return NULL;
memset(knet_tap, 0, sizeof(struct tap_iface));
if ((knet_tap->knet_tap_fd = open("/dev/net/tun", O_RDWR)) < 0)
goto out_error;
strncpy(knet_tap->ifname, dev, IFNAMSIZ);
knet_tap->ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
if (ioctl(knet_tap->knet_tap_fd, TUNSETIFF, &knet_tap->ifr) < 0)
goto out_error;
if ((strlen(dev) > 0) && (strcmp(dev, knet_tap->ifname) != 0)) {
errno = EBUSY;
goto out_error;
}
strcpy(dev, knet_tap->ifname);
if (!tap_init) {
tap_cfg.tap_head = NULL;
tap_cfg.tap_sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (tap_cfg.tap_sockfd < 0)
goto out_error;
tap_init = 1;
}
if (ioctl(tap_cfg.tap_sockfd, SIOGIFINDEX, &knet_tap->ifr) < 0)
goto out_error;
knet_tap->default_mtu = tap_get_mtu(knet_tap);
if (knet_tap->default_mtu < 0)
goto out_error;
if (tap_get_mac(knet_tap, &temp_mac) < 0)
goto out_error;
strncpy(knet_tap->default_mac, temp_mac, 18);
free(temp_mac);
if (updownpath) {
int len = strlen(updownpath);
strcpy(knet_tap->updownpath, updownpath);
if (knet_tap->updownpath[len-1] != '/') {
knet_tap->updownpath[len] = '/';
}
knet_tap->hasupdown = 1;
}
knet_tap->next = tap_cfg.tap_head;
tap_cfg.tap_head = knet_tap;
pthread_mutex_unlock(&tap_mutex);
return knet_tap;
out_error:
tap_close(knet_tap);
tap_close_cfg();
pthread_mutex_unlock(&tap_mutex);
return NULL;
}
int knet_tap_close(knet_tap_t knet_tap)
{
int err = 0;
knet_tap_t temp = tap_cfg.tap_head;
knet_tap_t prev = tap_cfg.tap_head;
struct tap_ip *tap_ip, *tap_ip_next;
+ char *error_string = NULL;
pthread_mutex_lock(&tap_mutex);
if (!tap_check(knet_tap)) {
errno = EINVAL;
err = -1;
goto out_clean;
}
while ((temp) && (temp != knet_tap)) {
prev = temp;
temp = temp->next;
}
if (knet_tap == prev) {
tap_cfg.tap_head = knet_tap->next;
} else {
prev->next = knet_tap->next;
}
tap_set_down(knet_tap);
tap_ip = knet_tap->tap_ip;
while (tap_ip) {
tap_ip_next = tap_ip->next;
- tap_set_ip(knet_tap, "del", tap_ip->ip_addr, tap_ip->prefix);
+ tap_set_ip(knet_tap, "del", tap_ip->ip_addr, tap_ip->prefix, &error_string);
+ if (error_string)
+ free(error_string);
free(tap_ip);
tap_ip = tap_ip_next;
}
tap_close(knet_tap);
tap_close_cfg();
out_clean:
pthread_mutex_unlock(&tap_mutex);
return err;
}
int knet_tap_get_mtu(const knet_tap_t knet_tap)
{
int err;
pthread_mutex_lock(&tap_mutex);
if (!tap_check(knet_tap)) {
errno = EINVAL;
err = -1;
goto out_clean;
}
err = tap_get_mtu(knet_tap);
out_clean:
pthread_mutex_unlock(&tap_mutex);
return err;
}
int knet_tap_set_mtu(knet_tap_t knet_tap, const int mtu)
{
int err, oldmtu;
pthread_mutex_lock(&tap_mutex);
if (!tap_check(knet_tap)) {
errno = EINVAL;
err = -1;
goto out_clean;
}
oldmtu = knet_tap->ifr.ifr_mtu;
knet_tap->ifr.ifr_mtu = mtu;
err = ioctl(tap_cfg.tap_sockfd, SIOCSIFMTU, &knet_tap->ifr);
if (err)
knet_tap->ifr.ifr_mtu = oldmtu;
out_clean:
pthread_mutex_unlock(&tap_mutex);
return err;
}
int knet_tap_reset_mtu(knet_tap_t knet_tap)
{
return knet_tap_set_mtu(knet_tap, knet_tap->default_mtu);
}
int knet_tap_get_mac(const knet_tap_t knet_tap, char **ether_addr)
{
int err;
pthread_mutex_lock(&tap_mutex);
if ((!tap_check(knet_tap)) || (!ether_addr)) {
errno = EINVAL;
err = -1;
goto out_clean;
}
err = tap_get_mac(knet_tap, ether_addr);
out_clean:
pthread_mutex_unlock(&tap_mutex);
return err;
}
int knet_tap_set_mac(knet_tap_t knet_tap, const char *ether_addr)
{
struct ether_addr oldmac;
int err;
pthread_mutex_lock(&tap_mutex);
if ((!tap_check(knet_tap)) || (!ether_addr)) {
errno = EINVAL;
err = -1;
goto out_clean;
}
memcpy(&oldmac, knet_tap->ifr.ifr_hwaddr.sa_data, ETH_ALEN);
memcpy(knet_tap->ifr.ifr_hwaddr.sa_data, ether_aton(ether_addr), ETH_ALEN);
err = ioctl(tap_cfg.tap_sockfd, SIOCSIFHWADDR, &knet_tap->ifr);
if (err)
memcpy(knet_tap->ifr.ifr_hwaddr.sa_data, &oldmac, ETH_ALEN);
out_clean:
pthread_mutex_unlock(&tap_mutex);
return err;
}
int knet_tap_reset_mac(knet_tap_t knet_tap)
{
return knet_tap_set_mac(knet_tap, knet_tap->default_mac);
}
int knet_tap_set_up(knet_tap_t knet_tap)
{
int err = 0;
short int oldflags;
+ char *error_string = NULL;
pthread_mutex_lock(&tap_mutex);
if (!tap_check(knet_tap)) {
errno = EINVAL;
err = -1;
goto out_clean;
}
if (knet_tap->up)
goto out_clean;
- tap_exec_updown(knet_tap, "pre-up.d");
+ tap_exec_updown(knet_tap, "pre-up.d", &error_string);
+ if (error_string)
+ free(error_string);
oldflags = knet_tap->ifr.ifr_flags;
knet_tap->ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
err=ioctl(tap_cfg.tap_sockfd, SIOCSIFFLAGS, &knet_tap->ifr);
if (err)
knet_tap->ifr.ifr_flags = oldflags;
- tap_exec_updown(knet_tap, "up.d");
+ tap_exec_updown(knet_tap, "up.d", &error_string);
+ if (error_string)
+ free(error_string);
knet_tap->up = 1;
out_clean:
pthread_mutex_unlock(&tap_mutex);
return err;
}
static int tap_set_down(knet_tap_t knet_tap)
{
int err = 0;
short int oldflags;
+ char *error_string = NULL;
if (!knet_tap->up)
goto out_clean;
- tap_exec_updown(knet_tap, "down.d");
+ tap_exec_updown(knet_tap, "down.d", &error_string);
+ if (error_string)
+ free(error_string);
oldflags = knet_tap->ifr.ifr_flags;
knet_tap->ifr.ifr_flags &= ~IFF_UP;
err=ioctl(tap_cfg.tap_sockfd, SIOCSIFFLAGS, &knet_tap->ifr);
if (err) {
knet_tap->ifr.ifr_flags = oldflags;
goto out_clean;
}
- tap_exec_updown(knet_tap, "post-down.d");
+ tap_exec_updown(knet_tap, "post-down.d", &error_string);
+ if (error_string)
+ free(error_string);
knet_tap->up = 0;
out_clean:
return err;
}
int knet_tap_set_down(knet_tap_t knet_tap)
{
int err = 0;
pthread_mutex_lock(&tap_mutex);
if (!tap_check(knet_tap)) {
errno = EINVAL;
err = -1;
goto out_clean;
}
err=tap_set_down(knet_tap);
out_clean:
pthread_mutex_unlock(&tap_mutex);
return err;
}
static char *tap_get_v4_broadcast(const char *ip_addr, const char *prefix)
{
int prefix_len;
struct in_addr mask;
struct in_addr broadcast;
struct in_addr address;
prefix_len = atoi(prefix);
if ((prefix_len > 32) || (prefix_len < 0))
return NULL;
if (inet_pton(AF_INET, ip_addr, &address) <= 0)
return NULL;
mask.s_addr = htonl(~((1 << (32 - prefix_len)) - 1));
memset(&broadcast, 0, sizeof(broadcast));
broadcast.s_addr = (address.s_addr & mask.s_addr) | ~mask.s_addr;
return strdup(inet_ntoa(broadcast));
}
static int tap_set_ip(knet_tap_t knet_tap, const char *command,
- const char *ip_addr, const char *prefix)
+ const char *ip_addr, const char *prefix,
+ char **error_string)
{
char *broadcast = NULL;
char cmdline[4096];
if (!strchr(ip_addr, ':')) {
broadcast = tap_get_v4_broadcast(ip_addr, prefix);
if (!broadcast) {
errno = EINVAL;
return -1;
}
}
memset(cmdline, 0, sizeof(cmdline));
if (broadcast) {
snprintf(cmdline, sizeof(cmdline)-1,
"ip addr %s %s/%s dev %s broadcast %s",
command, ip_addr, prefix,
knet_tap->ifname, broadcast);
free(broadcast);
} else {
snprintf(cmdline, sizeof(cmdline)-1,
"ip addr %s %s/%s dev %s",
command, ip_addr, prefix,
knet_tap->ifname);
}
- return tap_execute_shell(cmdline);
+ return tap_execute_shell(cmdline, error_string);
}
static int tap_find_ip(knet_tap_t knet_tap,
const char *ip_addr, const char *prefix,
struct tap_ip **tap_ip, struct tap_ip **tap_ip_prev)
{
struct tap_ip *local_tap_ip, *local_tap_ip_prev;
int found = 0;
local_tap_ip = local_tap_ip_prev = knet_tap->tap_ip;
while(local_tap_ip) {
if ((!strcmp(local_tap_ip->ip_addr, ip_addr)) && (!strcmp(local_tap_ip->prefix, prefix))) {
found = 1;
break;
}
local_tap_ip_prev = local_tap_ip;
local_tap_ip = local_tap_ip->next;
}
if (found) {
*tap_ip = local_tap_ip;
*tap_ip_prev = local_tap_ip_prev;
}
return found;
}
int knet_tap_add_ip(knet_tap_t knet_tap, const char *ip_addr, const char *prefix)
{
int err = 0, found;
struct tap_ip *tap_ip = NULL, *tap_ip_prev = NULL;
+ char *error_string = NULL;
pthread_mutex_lock(&tap_mutex);
if ((!tap_check(knet_tap)) || (!ip_addr) || (!prefix)) {
errno = EINVAL;
err = -1;
goto out_clean;
}
found = tap_find_ip(knet_tap, ip_addr, prefix, &tap_ip, &tap_ip_prev);
if (found)
goto out_clean;
tap_ip = malloc(sizeof(struct tap_ip));
if (!tap_ip) {
err = -1 ;
goto out_clean;
}
memset(tap_ip, 0, sizeof(struct tap_ip));
strncpy(tap_ip->ip_addr, ip_addr, MAX_IP_CHAR);
strncpy(tap_ip->prefix, prefix, MAX_PREFIX_CHAR);
- err = tap_set_ip(knet_tap, "add", ip_addr, prefix);
+ err = tap_set_ip(knet_tap, "add", ip_addr, prefix, &error_string);
+ if (error_string)
+ free(error_string);
+
if (err) {
free(tap_ip);
goto out_clean;
}
tap_ip->next = knet_tap->tap_ip;
knet_tap->tap_ip = tap_ip;
out_clean:
pthread_mutex_unlock(&tap_mutex);
return err;
}
int knet_tap_del_ip(knet_tap_t knet_tap, const char *ip_addr, const char *prefix)
{
int err = 0, found;
struct tap_ip *tap_ip = NULL, *tap_ip_prev = NULL;
+ char *error_string = NULL;
pthread_mutex_lock(&tap_mutex);
if ((!tap_check(knet_tap)) || (!ip_addr) || (!prefix)) {
errno = EINVAL;
err = -1;
goto out_clean;
}
found = tap_find_ip(knet_tap, ip_addr, prefix, &tap_ip, &tap_ip_prev);
if (!found)
goto out_clean;
- err = tap_set_ip(knet_tap, "del", ip_addr, prefix);
+ err = tap_set_ip(knet_tap, "del", ip_addr, prefix, &error_string);
+ if (error_string)
+ free(error_string);
if (!err) {
if (tap_ip == tap_ip_prev) {
knet_tap->tap_ip = tap_ip->next;
} else {
tap_ip_prev->next = tap_ip->next;
}
free(tap_ip);
}
out_clean:
pthread_mutex_unlock(&tap_mutex);
return err;
}
int knet_tap_get_fd(const knet_tap_t knet_tap)
{
int fd;
pthread_mutex_lock(&tap_mutex);
if (!tap_check(knet_tap)) {
errno = EINVAL;
fd = -1;
goto out_clean;
}
fd = knet_tap->knet_tap_fd;
out_clean:
pthread_mutex_unlock(&tap_mutex);
return fd;
}
const char *knet_tap_get_name(const knet_tap_t knet_tap)
{
char *name = NULL;
pthread_mutex_lock(&tap_mutex);
if (!tap_check(knet_tap)) {
errno = EINVAL;
goto out_clean;
}
name = knet_tap->ifname;
out_clean:
pthread_mutex_unlock(&tap_mutex);
return name;
}
int knet_tap_get_ips(const knet_tap_t knet_tap, char **ip_addr_list, int *entries)
{
int err = 0;
int found = 0;
char *ip_list = NULL;
int size = 0, offset = 0, len;
struct tap_ip *tap_ip = knet_tap->tap_ip;
pthread_mutex_lock(&tap_mutex);
while (tap_ip) {
found++;
tap_ip = tap_ip->next;
}
size = found * (MAX_IP_CHAR + MAX_PREFIX_CHAR + 2);
ip_list = malloc(size);
if (!ip_list) {
err = -1;
goto out_clean;
}
memset(ip_list, 0, size);
tap_ip = knet_tap->tap_ip;
while (tap_ip) {
len = strlen(tap_ip->ip_addr);
memcpy(ip_list + offset, tap_ip->ip_addr, len);
offset = offset + len + 1;
len = strlen(tap_ip->prefix);
memcpy(ip_list + offset, tap_ip->prefix, len);
offset = offset + len + 1;
tap_ip = tap_ip->next;
}
*ip_addr_list = ip_list;
*entries = found;
out_clean:
pthread_mutex_unlock(&tap_mutex);
return err;
}
diff --git a/libtap/libtap_private.h b/libtap/libtap_private.h
index 762d8965..bd780fb6 100644
--- a/libtap/libtap_private.h
+++ b/libtap/libtap_private.h
@@ -1,35 +1,41 @@
#ifndef __LIBTAP_PRIVATE_H__
#define __LIBTAP_PRIVATE_H__
#include <net/if.h>
#include <limits.h>
+#ifndef TEST
+#define STATIC static
+#else
+#define STATIC
+#endif
+
#define MAX_IP_CHAR 128
#define MAX_PREFIX_CHAR 4
#define MAX_MAC_CHAR 18
struct tap_ip {
char ip_addr[MAX_IP_CHAR];
char prefix[MAX_PREFIX_CHAR];
struct tap_ip *next;
};
struct tap_iface {
struct ifreq ifr;
int knet_tap_fd;
char default_mac[MAX_MAC_CHAR];
int default_mtu;
char updownpath[PATH_MAX];
int hasupdown;
int up;
struct tap_ip *tap_ip;
struct tap_iface *next;
};
#define ifname ifr.ifr_name
struct tap_config {
struct tap_iface *tap_head;
int tap_sockfd;
};
#endif
diff --git a/tests/tap_test.c b/tests/tap_test.c
index 2233f512..3de67ebc 100644
--- a/tests/tap_test.c
+++ b/tests/tap_test.c
@@ -1,793 +1,869 @@
#include "config.h"
#include <string.h>
#include <errno.h>
#include <net/if.h>
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/ether.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include "libtap.h"
#include "libtap_private.h"
#include "utils.h"
extern struct tap_config tap_cfg;
-extern int tap_execute_shell(const char *command);
+extern int tap_execute_shell(const char *command, char **error_string);
static int is_if_in_system(char *name)
{
struct ifaddrs *ifap = NULL;
struct ifaddrs *ifa;
int found = 0;
if (getifaddrs(&ifap) < 0) {
log_error("Unable to get interface list.");
return -1;
}
ifa = ifap;
while (ifa) {
if (!strncmp(name, ifa->ifa_name, IFNAMSIZ)) {
found = 1;
break;
}
ifa=ifa->ifa_next;
}
freeifaddrs(ifap);
return found;
}
static int test_iface(char *name, size_t size, const char *updownpath)
{
knet_tap_t knet_tap;
knet_tap=knet_tap_open(name, size, updownpath);
if (!knet_tap) {
if (tap_cfg.tap_sockfd < 0)
log_error("Unable to open knet_socket");
log_error("Unable to open knet.");
return -1;
}
log_info("Created interface: %s", name);
if (is_if_in_system(name) > 0) {
log_info("Found interface %s on the system", name);
} else {
log_info("Unable to find interface %s on the system", name);
}
if (!knet_tap_find(name, size)) {
log_info("Unable to find interface %s in tap db", name);
} else {
log_info("Found interface %s in tap db", name);
}
knet_tap_close(knet_tap);
if (is_if_in_system(name) == 0)
log_info("Successfully removed interface %s from the system", name);
return 0;
}
static int check_knet_tap_open_close(void)
{
char device_name[2*IFNAMSIZ];
char fakepath[PATH_MAX];
size_t size = IFNAMSIZ;
memset(device_name, 0, sizeof(device_name));
log_info("Creating random tap interface:");
if (test_iface(device_name, size, NULL) < 0) {
log_error("Unable to create random interface");
return -1;
}
log_info("Creating kronostest tap interface:");
strncpy(device_name, "kronostest", IFNAMSIZ);
if (test_iface(device_name, size, NULL) < 0) {
log_error("Unable to create kronosnet interface");
return -1;
}
log_info("Testing ERROR conditions");
log_info("Testing dev == NULL");
errno=0;
if ((test_iface(NULL, size, NULL) >= 0) || (errno != EINVAL)) {
log_error("Something is wrong in knet_tap_open sanity checks");
return -1;
}
log_info("Testing size < IFNAMSIZ");
errno=0;
if ((test_iface(device_name, 1, NULL) >= 0) || (errno != EINVAL)) {
log_error("Something is wrong in knet_tap_open sanity checks");
return -1;
}
log_info("Testing device_name size > IFNAMSIZ");
errno=0;
strcpy(device_name, "abcdefghilmnopqrstuvwz");
if ((test_iface(device_name, IFNAMSIZ, NULL) >= 0) || (errno != E2BIG)) {
log_error("Something is wrong in knet_tap_open sanity checks");
return -1;
}
log_info("Testing updown path != abs");
errno=0;
strcpy(device_name, "kronostest");
if ((test_iface(device_name, IFNAMSIZ, "foo") >= 0) || (errno != EINVAL)) {
log_error("Something is wrong in knet_tap_open sanity checks");
return -1;
}
memset(fakepath, '/', PATH_MAX - 2);
fakepath[PATH_MAX-1] = 0;
log_info("Testing updown path > PATH_MAX");
errno=0;
strcpy(device_name, "kronostest");
if ((test_iface(device_name, IFNAMSIZ, fakepath) >= 0) || (errno != E2BIG)) {
log_error("Something is wrong in knet_tap_open sanity checks");
return -1;
}
return 0;
}
static int check_knet_multi_eth(void)
{
char device_name1[IFNAMSIZ];
char device_name2[IFNAMSIZ];
size_t size = IFNAMSIZ;
int err=0;
knet_tap_t knet_tap1 = NULL;
knet_tap_t knet_tap2 = NULL;
log_info("Testing multiple knet interface instances");
memset(device_name1, 0, size);
memset(device_name2, 0, size);
strncpy(device_name1, "kronostest1", size);
strncpy(device_name2, "kronostest2", size);
knet_tap1 = knet_tap_open(device_name1, size, NULL);
if (!knet_tap1) {
log_error("Unable to init %s.", device_name1);
err = -1;
goto out_clean;
}
if (is_if_in_system(device_name1) > 0) {
log_info("Found interface %s on the system", device_name1);
} else {
log_info("Unable to find interface %s on the system", device_name1);
}
knet_tap2 = knet_tap_open(device_name2, size, NULL);
if (!knet_tap2) {
log_error("Unable to init %s.", device_name2);
err = -1;
goto out_clean;
}
if (is_if_in_system(device_name2) > 0) {
log_info("Found interface %s on the system", device_name2);
} else {
log_info("Unable to find interface %s on the system", device_name2);
}
if (knet_tap1)
knet_tap_close(knet_tap1);
if (knet_tap2)
knet_tap_close(knet_tap2);
log_info("Testing error conditions");
log_info("Open same device twice");
knet_tap1 = knet_tap_open(device_name1, size, NULL);
if (!knet_tap1) {
log_error("Unable to init %s.", device_name1);
err = -1;
goto out_clean;
}
if (is_if_in_system(device_name1) > 0) {
log_info("Found interface %s on the system", device_name1);
} else {
log_info("Unable to find interface %s on the system", device_name1);
}
knet_tap2 = knet_tap_open(device_name1, size, NULL);
if (knet_tap2) {
log_error("We were able to init 2 interfaces with the same name!");
err = -1;
goto out_clean;
}
out_clean:
if (knet_tap1)
knet_tap_close(knet_tap1);
if (knet_tap2)
knet_tap_close(knet_tap2);
return err;
}
static int check_knet_mtu(void)
{
char device_name[IFNAMSIZ];
size_t size = IFNAMSIZ;
int err=0;
knet_tap_t knet_tap;
int current_mtu = 0;
int expected_mtu = 1500;
log_info("Testing get/set MTU");
memset(device_name, 0, size);
strncpy(device_name, "kronostest", size);
knet_tap = knet_tap_open(device_name, size, NULL);
if (!knet_tap) {
log_error("Unable to init %s.", device_name);
return -1;
}
log_info("Comparing default MTU");
current_mtu = knet_tap_get_mtu(knet_tap);
if (current_mtu < 0) {
log_error("Unable to get MTU");
err = -1;
goto out_clean;
}
if (current_mtu != expected_mtu) {
log_error("current mtu [%d] does not match expected default [%d]", current_mtu, expected_mtu);
err = -1;
goto out_clean;
}
log_info("Setting MTU to 9000");
expected_mtu = 9000;
if (knet_tap_set_mtu(knet_tap, expected_mtu) < 0) {
log_error("Unable to set MTU to %d.", expected_mtu);
err = -1;
goto out_clean;
}
current_mtu = knet_tap_get_mtu(knet_tap);
if (current_mtu < 0) {
log_error("Unable to get MTU");
err = -1;
goto out_clean;
}
if (current_mtu != expected_mtu) {
log_error("current mtu [%d] does not match expected value [%d]", current_mtu, expected_mtu);
err = -1;
goto out_clean;
}
log_info("Testing ERROR conditions");
log_info("Passing empty struct to get_mtu");
if (knet_tap_get_mtu(NULL) > 0) {
log_error("Something is wrong in knet_tap_get_mtu sanity checks");
err = -1;
goto out_clean;
}
log_info("Passing empty struct to set_mtu");
if (knet_tap_set_mtu(NULL, 1500) == 0) {
log_error("Something is wrong in knet_tap_set_mtu sanity checks");
err = -1;
goto out_clean;
}
out_clean:
knet_tap_close(knet_tap);
return err;
}
static int check_knet_mac(void)
{
char device_name[IFNAMSIZ];
size_t size = IFNAMSIZ;
int err=0;
knet_tap_t knet_tap;
char *current_mac = NULL, *temp_mac = NULL, *err_mac = NULL;
struct ether_addr *cur_mac, *tmp_mac;
log_info("Testing get/set MAC");
memset(device_name, 0, size);
strncpy(device_name, "kronostest", size);
knet_tap = knet_tap_open(device_name, size, NULL);
if (!knet_tap) {
log_error("Unable to init %s.", device_name);
return -1;
}
log_info("Get current MAC");
if (knet_tap_get_mac(knet_tap, ¤t_mac) < 0) {
log_error("Unable to get current MAC address.");
err = -1;
goto out_clean;
}
log_info("Current MAC: %s", current_mac);
log_info("Setting MAC: 00:01:01:01:01:01");
if (knet_tap_set_mac(knet_tap, "00:01:01:01:01:01") < 0) {
log_error("Unable to set current MAC address.");
err = -1;
goto out_clean;
}
if (knet_tap_get_mac(knet_tap, &temp_mac) < 0) {
log_error("Unable to get current MAC address.");
err = -1;
goto out_clean;
}
log_info("Current MAC: %s", temp_mac);
cur_mac = ether_aton(current_mac);
tmp_mac = ether_aton(temp_mac);
log_info("Comparing MAC addresses");
if (memcmp(cur_mac, tmp_mac, sizeof(struct ether_addr))) {
log_error("Mac addresses are not the same?!");
err = -1;
goto out_clean;
}
log_info("Testing ERROR conditions");
log_info("Pass NULL to get_mac (pass1)");
errno = 0;
if ((knet_tap_get_mac(NULL, &err_mac) >= 0) || (errno != EINVAL)) {
log_error("Something is wrong in knet_tap_get_mac sanity checks");
err = -1;
goto out_clean;
}
log_info("Pass NULL to get_mac (pass2)");
errno = 0;
if ((knet_tap_get_mac(knet_tap, NULL) >= 0) || (errno != EINVAL)) {
log_error("Something is wrong in knet_tap_get_mac sanity checks");
err = -1;
goto out_clean;
}
log_info("Pass NULL to set_mac (pass1)");
errno = 0;
if ((knet_tap_set_mac(knet_tap, NULL) >= 0) || (errno != EINVAL)) {
log_error("Something is wrong in knet_tap_set_mac sanity checks");
err = -1;
goto out_clean;
}
log_info("Pass NULL to set_mac (pass2)");
errno = 0;
if ((knet_tap_set_mac(NULL, err_mac) >= 0) || (errno != EINVAL)) {
log_error("Something is wrong in knet_tap_set_mac sanity checks");
err = -1;
goto out_clean;
}
out_clean:
if (err_mac) {
log_error("Something managed to set err_mac!");
err = -1;
free(err_mac);
}
if (current_mac)
free(current_mac);
if (temp_mac)
free(temp_mac);
knet_tap_close(knet_tap);
return err;
}
static int check_tap_execute_shell(void)
{
int err = 0;
char command[4096];
+ char *error_string = NULL;
memset(command, 0, sizeof(command));
log_info("Testing tap_execute_shell");
log_info("command /bin/true");
- if (tap_execute_shell("/bin/true") < 0) {
+ err = tap_execute_shell("/bin/true", &error_string);
+ if (error_string) {
+ log_error("Error string: %s", error_string);
+ free(error_string);
+ error_string = NULL;
+ }
+ if (err < 0) {
log_error("Unable to execute /bin/true ?!?!");
- err = -1;
goto out_clean;
}
log_info("Testing ERROR conditions");
log_info("command /bin/false");
- if (!tap_execute_shell("/bin/false")) {
+ err = tap_execute_shell("/bin/false", &error_string);
+ if (error_string) {
+ log_error("Error string: %s", error_string);
+ free(error_string);
+ error_string = NULL;
+ }
+ if (!err) {
log_error("Can we really execute /bin/false successfully?!?!");
err = -1;
goto out_clean;
}
log_info("command that outputs to stdout (enforcing redirect)");
- if (!tap_execute_shell("/bin/grep -h 2>&1")) {
+
+ err = tap_execute_shell("/bin/grep -h 2>&1", &error_string);
+ if (error_string) {
+ log_error("Error string: %s", error_string);
+ free(error_string);
+ error_string = NULL;
+ }
+ if (!err) {
log_error("Can we really execute /bin/grep -h successfully?!?");
err = -1;
goto out_clean;
}
log_info("command that outputs to stderr");
- if (!tap_execute_shell("/bin/grep -h")) {
+ err = tap_execute_shell("/bin/grep -h", &error_string);
+ if (error_string) {
+ log_error("Error string: %s", error_string);
+ free(error_string);
+ error_string = NULL;
+ }
+ if (!err) {
log_error("Can we really execute /bin/grep -h successfully?!?");
err = -1;
goto out_clean;
}
log_info("empty command");
- if (!tap_execute_shell(NULL)) {
+ err = tap_execute_shell(NULL, &error_string);
+ if (error_string) {
+ log_error("Error string: %s", error_string);
+ free(error_string);
+ error_string = NULL;
+ }
+ if (!err) {
log_error("Can we really execute (nil) successfully?!?!");
err = -1;
goto out_clean;
}
+ log_info("empty error");
+ err = tap_execute_shell("/bin/true", NULL);
+ if (!err) {
+ log_error("Check EINVAL filter for no error_string!");
+ err = -1;
+ goto out_clean;
+ }
+
+ err = 0;
+
out_clean:
return err;
}
static int check_knet_up_down(void)
{
char device_name[IFNAMSIZ];
size_t size = IFNAMSIZ;
int err=0;
knet_tap_t knet_tap;
+ char *error_string = NULL;
log_info("Testing interface up/down");
memset(device_name, 0, size);
strncpy(device_name, "kronostest", size);
knet_tap = knet_tap_open(device_name, size, NULL);
if (!knet_tap) {
log_error("Unable to init %s.", device_name);
return -1;
}
log_info("Put the interface up");
if (knet_tap_set_up(knet_tap) < 0) {
log_error("Unable to set interface up");
err = -1;
goto out_clean;
}
- if (tap_execute_shell("ip addr show dev kronostest | grep -q UP") < 0) {
+
+ err = tap_execute_shell("ip addr show dev kronostest | grep -q UP", &error_string);
+ if (error_string) {
+ log_error("Error string: %s", error_string);
+ free(error_string);
+ error_string = NULL;
+ }
+ if (err < 0) {
log_error("Unable to verify inteface UP");
err = -1;
goto out_clean;
}
log_info("Put the interface down");
if (knet_tap_set_down(knet_tap) < 0) {
log_error("Unable to put the interface down");
err = -1;
goto out_clean;
}
- log_info("A shell error here is NORMAL");
-
- if (!tap_execute_shell("ifconfig kronostest | grep -q UP")) {
+ err = tap_execute_shell("ifconfig kronostest | grep -q UP", &error_string);
+ if (error_string) {
+ log_error("Error string: %s", error_string);
+ free(error_string);
+ error_string = NULL;
+ }
+ if (!err) {
log_error("Unable to verify inteface DOWN");
err = -1;
goto out_clean;
}
knet_tap_close(knet_tap);
log_info("Testing interface pre-up/up/down/post-down (exec errors)");
knet_tap = knet_tap_open(device_name, size, ABSBUILDDIR "/tap_updown_bad");
if (!knet_tap) {
log_error("Unable to init %s.", device_name);
return -1;
}
log_info("Put the interface up");
if (knet_tap_set_up(knet_tap) < 0) {
log_error("Unable to set interface up");
err = -1;
goto out_clean;
}
log_info("Put the interface down");
if (knet_tap_set_down(knet_tap) < 0) {
log_error("Unable to put the interface down");
err = -1;
goto out_clean;
}
knet_tap_close(knet_tap);
log_info("Testing interface pre-up/up/down/post-down");
knet_tap = knet_tap_open(device_name, size, ABSBUILDDIR "/tap_updown_good");
if (!knet_tap) {
log_error("Unable to init %s.", device_name);
return -1;
}
log_info("Put the interface up");
if (knet_tap_set_up(knet_tap) < 0) {
log_error("Unable to set interface up");
err = -1;
goto out_clean;
}
log_info("Put the interface down");
if (knet_tap_set_down(knet_tap) < 0) {
log_error("Unable to put the interface down");
err = -1;
goto out_clean;
}
knet_tap_close(knet_tap);
log_info("Test ERROR conditions");
log_info("Pass NULL to set_up");
errno = 0;
if ((knet_tap_set_up(NULL) >= 0) || (errno != EINVAL)) {
log_error("Something is wrong in knet_tap_set_up sanity checks");
err = -1;
goto out_clean;
}
log_info("Pass NULL to set_down");
errno = 0;
if ((knet_tap_set_down(NULL) >= 0) || (errno != EINVAL)) {
log_error("Something is wrong in knet_tap_set_down sanity checks");
err = -1;
goto out_clean;
}
out_clean:
knet_tap_close(knet_tap);
return err;
}
static int check_knet_close_leak(void)
{
char device_name[IFNAMSIZ];
size_t size = IFNAMSIZ;
int err=0;
knet_tap_t knet_tap;
log_info("Testing close leak (needs valgrind)");
memset(device_name, 0, size);
strncpy(device_name, "kronostest", size);
knet_tap = knet_tap_open(device_name, size, NULL);
if (!knet_tap) {
log_error("Unable to init %s.", device_name);
return -1;
}
log_info("Adding ip: 192.168.168.168/24");
if (knet_tap_add_ip(knet_tap, "192.168.168.168", "24") < 0) {
log_error("Unable to assign IP address");
err=-1;
goto out_clean;
}
log_info("Adding ip: 192.168.169.169/24");
if (knet_tap_add_ip(knet_tap, "192.168.169.169", "24") < 0) {
log_error("Unable to assign IP address");
err=-1;
goto out_clean;
}
out_clean:
knet_tap_close(knet_tap);
return err;
}
static int check_knet_set_del_ip(void)
{
char device_name[IFNAMSIZ];
size_t size = IFNAMSIZ;
int err=0;
knet_tap_t knet_tap;
char *ip_list = NULL;
int ip_list_entries = 0, i, offset = 0;
+ char *error_string = NULL;
log_info("Testing interface add/remove ip");
memset(device_name, 0, size);
strncpy(device_name, "kronostest", size);
knet_tap = knet_tap_open(device_name, size, NULL);
if (!knet_tap) {
log_error("Unable to init %s.", device_name);
return -1;
}
log_info("Adding ip: 192.168.168.168/24");
if (knet_tap_add_ip(knet_tap, "192.168.168.168", "24") < 0) {
log_error("Unable to assign IP address");
err=-1;
goto out_clean;
}
log_info("Adding ip: 192.168.169.169/24");
if (knet_tap_add_ip(knet_tap, "192.168.169.169", "24") < 0) {
log_error("Unable to assign IP address");
err=-1;
goto out_clean;
}
log_info("Adding duplicate ip: 192.168.168.168/24");
if (knet_tap_add_ip(knet_tap, "192.168.168.168", "24") < 0) {
log_error("Unable to find IP address in libtap db");
err=-1;
goto out_clean;
}
log_info("Checking ip: 192.168.168.168/24");
- if (tap_execute_shell("ip addr show dev kronostest | grep -q 192.168.168.168/24")) {
+ err = tap_execute_shell("ip addr show dev kronostest | grep -q 192.168.168.168/24", &error_string);
+ if (error_string) {
+ log_error("Error string: %s", error_string);
+ free(error_string);
+ error_string = NULL;
+ }
+ if (err) {
log_error("Unable to verify IP address");
err=-1;
goto out_clean;
}
log_info("Get ip list from libtap:");
if (knet_tap_get_ips(knet_tap, &ip_list, &ip_list_entries) < 0) {
log_error("Not enough mem?");
err=-1;
goto out_clean;
}
if (ip_list_entries != 2) {
log_error("Didn't get enough ip back from libtap?");
err=-1;
goto out_clean;
}
for (i = 1; i <= ip_list_entries; i++) {
log_info("Found IP %s %s in libtap db", ip_list + offset, ip_list + offset + strlen(ip_list + offset) + 1);
offset = offset + strlen(ip_list) + 1;
offset = offset + strlen(ip_list + offset) + 1;
}
free(ip_list);
log_info("Deleting ip: 192.168.168.168/24");
if (knet_tap_del_ip(knet_tap, "192.168.168.168", "24") < 0) {
log_error("Unable to delete IP address");
err=-1;
goto out_clean;
}
log_info("Deleting ip: 192.168.169.169/24");
if (knet_tap_del_ip(knet_tap, "192.168.169.169", "24") < 0) {
log_error("Unable to delete IP address");
err=-1;
goto out_clean;
}
log_info("Deleting again ip: 192.168.168.168/24");
if (knet_tap_del_ip(knet_tap, "192.168.168.168", "24") < 0) {
log_error("Unable to delete IP address");
err=-1;
goto out_clean;
}
- log_info("A shell error here is NORMAL");
- if (!tap_execute_shell("ip addr show dev kronostest | grep -q 192.168.168.168/24")) {
+ err = tap_execute_shell("ip addr show dev kronostest | grep -q 192.168.168.168/24", &error_string);
+ if (error_string) {
+ log_error("Error string: %s", error_string);
+ free(error_string);
+ error_string = NULL;
+ }
+ if (!err) {
log_error("Unable to verify IP address");
err=-1;
goto out_clean;
}
log_info("Adding ip: 3ffe::1/64");
if (knet_tap_add_ip(knet_tap, "3ffe::1", "64") < 0) {
log_error("Unable to assign IP address");
err=-1;
goto out_clean;
}
- if (tap_execute_shell("ip addr show dev kronostest | grep -q 3ffe::1/64")) {
+ err = tap_execute_shell("ip addr show dev kronostest | grep -q 3ffe::1/64", &error_string);
+ if (error_string) {
+ log_error("Error string: %s", error_string);
+ free(error_string);
+ error_string = NULL;
+ }
+ if (err) {
log_error("Unable to verify IP address");
err=-1;
goto out_clean;
}
log_info("Deleting ip: 3ffe::1/64");
if (knet_tap_del_ip(knet_tap, "3ffe::1", "64") < 0) {
log_error("Unable to delete IP address");
err=-1;
goto out_clean;
}
- log_info("A shell error here is NORMAL");
- if (!tap_execute_shell("ip addr show dev kronostest | grep -q 3ffe::1/64")) {
+ err = tap_execute_shell("ip addr show dev kronostest | grep -q 3ffe::1/64", &error_string);
+ if (error_string) {
+ log_error("Error string: %s", error_string);
+ free(error_string);
+ error_string = NULL;
+ }
+ if (!err) {
log_error("Unable to verify IP address");
err=-1;
goto out_clean;
}
out_clean:
knet_tap_close(knet_tap);
return err;
}
int main(void)
{
if (check_knet_tap_open_close() < 0)
return -1;
if (check_knet_multi_eth() < 0)
return -1;
if (check_knet_mtu() < 0)
return -1;
if (check_knet_mac() < 0)
return -1;
if (check_tap_execute_shell() < 0)
return -1;
if (check_knet_up_down() < 0)
return -1;
if (check_knet_set_del_ip() < 0)
return -1;
if (check_knet_close_leak() < 0)
return -1;
return 0;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Dec 23, 12:27 PM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1128340
Default Alt Text
(39 KB)
Attached To
Mode
rK kronosnet
Attached
Detach File
Event Timeline
Log In to Comment