summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2012-03-06 02:22:56 +0100
committerMatthias Schiffer <mschiffer@universe-factory.net>2012-03-06 02:22:56 +0100
commit7adeae186cdf0e986d7b965e5fc000687040ae9f (patch)
tree52925fe14b615c72155009f0f3037bdb26c2f05f
parentebd9d98fd7a2c08f57b1187a7b9efafbfbb63fe7 (diff)
downloadfastd-7adeae186cdf0e986d7b965e5fc000687040ae9f.tar
fastd-7adeae186cdf0e986d7b965e5fc000687040ae9f.zip
Implement tunneling over IPv6
-rw-r--r--src/fastd.c423
-rw-r--r--src/fastd.h46
-rw-r--r--src/peer.c51
-rw-r--r--src/peer.h21
4 files changed, 369 insertions, 172 deletions
diff --git a/src/fastd.c b/src/fastd.c
index f6635d3..fdd3f5c 100644
--- a/src/fastd.c
+++ b/src/fastd.c
@@ -80,27 +80,60 @@ static void init_tuntap(fastd_context *ctx) {
}
static void init_socket(fastd_context *ctx) {
- pr_debug(ctx, "Initializing UDP socket...");
+ if (ctx->conf->bind_addr_in.sin_family == AF_INET) {
+ pr_debug(ctx, "Initializing IPv4 socket...");
- if ((ctx->sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
- exit_errno(ctx, "socket");
+ if ((ctx->sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ exit_errno(ctx, "socket");
- struct sockaddr_in bindaddr;
- bindaddr.sin_family = AF_INET;
- bindaddr.sin_addr.s_addr = ctx->conf->bind_address;
- bindaddr.sin_port = ctx->conf->bind_port;
+ if (bind(ctx->sockfd, (struct sockaddr*)&ctx->conf->bind_addr_in, sizeof(struct sockaddr_in)))
+ exit_errno(ctx, "bind");
- if (bind(ctx->sockfd, (struct sockaddr*)&bindaddr, sizeof(struct sockaddr_in)))
- exit_errno(ctx, "bind");
+ pr_debug(ctx, "IPv4 socket initialized.");
+ }
+ else {
+ ctx->sockfd = -1;
+ }
+
+ if (ctx->conf->bind_addr_in6.sin6_family == AF_INET6) {
+ pr_debug(ctx, "Initializing IPv6 socket...");
+
+ if ((ctx->sock6fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ if (ctx->sockfd > 0)
+ warn_errno(ctx, "socket");
+ else
+ exit_errno(ctx, "socket");
+ }
+ else {
+ int val = 1;
+ if (setsockopt(ctx->sock6fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)))
+ exit_errno(ctx, "setsockopt");
- pr_debug(ctx, "UDP socket initialized.");
+ if (bind(ctx->sock6fd, (struct sockaddr*)&ctx->conf->bind_addr_in6, sizeof(struct sockaddr_in6)))
+ exit_errno(ctx, "bind");
+
+ pr_debug(ctx, "IPv6 socket initialized.");
+ }
+ }
+ else {
+ ctx->sock6fd = -1;
+ }
}
static void default_config(fastd_config *conf) {
conf->loglevel = LOG_DEBUG;
conf->ifname = NULL;
- conf->bind_address = htonl(INADDR_ANY);
- conf->bind_port = htons(1337);
+
+ memset(&conf->bind_addr_in, 0, sizeof(struct sockaddr_in));
+ conf->bind_addr_in.sin_family = AF_UNSPEC;
+ conf->bind_addr_in.sin_port = htons(1337);
+ conf->bind_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ memset(&conf->bind_addr_in6, 0, sizeof(struct sockaddr_in6));
+ conf->bind_addr_in6.sin6_family = AF_UNSPEC;
+ conf->bind_addr_in6.sin6_port = htons(1337);
+ conf->bind_addr_in6.sin6_addr = in6addr_any;
+
conf->mtu = 1500;
conf->protocol = PROTOCOL_ETHERNET;
conf->method = &fastd_method_null;
@@ -124,12 +157,13 @@ static void configure(fastd_context *ctx, fastd_config *conf, int argc, char *ar
int c;
int option_index = 0;
- struct in_addr addr;
long l;
char *charptr;
char *endptr;
char *addrstr;
+ bool v4_peers = false, v6_peers = false;
+
conf->n_floating = 0;
@@ -140,31 +174,55 @@ static void configure(fastd_context *ctx, fastd_config *conf, int argc, char *ar
break;
case 'b':
- charptr = strchr(optarg, ':');
- if (charptr) {
- addrstr = strndup(optarg, charptr-optarg);
- }
- else {
- addrstr = optarg;
- }
+ if (optarg[0] == '[') {
+ charptr = strchr(optarg, ']');
+ if (!charptr || (charptr[1] != ':' && charptr[1] != '\0'))
+ exit_error(ctx, "invalid bind address `%s'", optarg);
- if (strcmp(addrstr, "any") == 0) {
- addr.s_addr = htonl(INADDR_ANY);
+ addrstr = strndup(optarg+1, charptr-optarg-1);
+
+ if (charptr[1] == ':')
+ charptr++;
+ else
+ charptr = NULL;
}
- else if (inet_pton(AF_INET, addrstr, &addr) != 1) {
- exit_error(ctx, "invalid bind address `%s'", addrstr);
+ else {
+ charptr = strchr(optarg, ':');
+ if (charptr) {
+ addrstr = strndup(optarg, charptr-optarg);
+ }
+ else {
+ addrstr = strdup(optarg);
+ }
}
- conf->bind_address = addr.s_addr;
-
if (charptr) {
l = strtol(charptr+1, &endptr, 10);
if (*endptr || l > 65535)
exit_error(ctx, "invalid bind port `%s'", charptr+1);
- conf->bind_port = htons(l);
+ }
- free(addrstr);
+ if (strcmp(addrstr, "any") == 0) {
+ conf->bind_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
+ conf->bind_addr_in.sin_port = htons(l);
+
+ conf->bind_addr_in6.sin6_addr = in6addr_any;
+ conf->bind_addr_in6.sin6_port = htons(l);
+ }
+ else if (optarg[0] == '[') {
+ conf->bind_addr_in6.sin6_family = AF_INET6;
+ if (inet_pton(AF_INET6, addrstr, &conf->bind_addr_in6.sin6_addr) != 1)
+ exit_error(ctx, "invalid bind address `%s'", addrstr);
+ conf->bind_addr_in6.sin6_port = htons(l);
}
+ else {
+ conf->bind_addr_in.sin_family = AF_INET;
+ if (inet_pton(AF_INET, addrstr, &conf->bind_addr_in.sin_addr) != 1)
+ exit_error(ctx, "invalid bind address `%s'", addrstr);
+ conf->bind_addr_in.sin_port = htons(l);
+ }
+
+ free(addrstr);
break;
@@ -194,37 +252,58 @@ static void configure(fastd_context *ctx, fastd_config *conf, int argc, char *ar
*current_peer = malloc(sizeof(fastd_peer_config));
(*current_peer)->next = NULL;
- charptr = strchr(optarg, ':');
- if (charptr) {
- addrstr = strndup(optarg, charptr-optarg);
- }
- else {
- addrstr = optarg;
+ memset(&(*current_peer)->address, 0, sizeof(fastd_peer_address));
+ if (strcmp(optarg, "float") == 0) {
+ (*current_peer)->address.sa.sa_family = AF_UNSPEC;
+ conf->n_floating++;
+ continue;
}
- if (strcmp(addrstr, "any") == 0 || strcmp(addrstr, "float") == 0) {
- addr.s_addr = htonl(INADDR_ANY);
+ if (optarg[0] == '[') {
+ charptr = strchr(optarg, ']');
+ if (!charptr || (charptr[1] != ':' && charptr[1] != '\0'))
+ exit_error(ctx, "invalid peer address `%s'", optarg);
+
+ addrstr = strndup(optarg+1, charptr-optarg-1);
+
+ if (charptr[1] == ':')
+ charptr++;
+ else
+ charptr = NULL;
}
- else if (inet_pton(AF_INET, addrstr, &addr) != 1) {
- exit_error(ctx, "invalid bind address `%s'", addrstr);
+ else {
+ charptr = strchr(optarg, ':');
+ if (charptr)
+ addrstr = strndup(optarg, charptr-optarg);
+ else
+ addrstr = strdup(optarg);
}
- (*current_peer)->address = addr.s_addr;
-
if (charptr) {
l = strtol(charptr+1, &endptr, 10);
if (*endptr || l > 65535)
- exit_error(ctx, "invalid bind port `%s'", charptr+1);
- (*current_peer)->port = htons(l);
+ exit_error(ctx, "invalid peer port `%s'", charptr+1);
+ }
+ else {
+ l = 1337; /* default port */
+ }
- free(addrstr);
+ if (optarg[0] == '[') {
+ v6_peers = true;
+ (*current_peer)->address.in6.sin6_family = AF_INET6;
+ if (inet_pton(AF_INET6, addrstr, &(*current_peer)->address.in6.sin6_addr) != 1)
+ exit_error(ctx, "invalid peer address `%s'", addrstr);
+ (*current_peer)->address.in6.sin6_port = htons(l);
}
else {
- (*current_peer)->port = htons(1337); // Default port
+ v4_peers = true;
+ (*current_peer)->address.in.sin_family = AF_INET;
+ if (inet_pton(AF_INET, addrstr, &(*current_peer)->address.in.sin_addr) != 1)
+ exit_error(ctx, "invalid peer address `%s'", addrstr);
+ (*current_peer)->address.in.sin_port = htons(l);
}
- if (!(*current_peer)->address)
- conf->n_floating++;
+ free(addrstr);
current_peer = &(*current_peer)->next;
@@ -238,6 +317,17 @@ static void configure(fastd_context *ctx, fastd_config *conf, int argc, char *ar
}
}
+ if (conf->bind_addr_in.sin_family == AF_UNSPEC && conf->bind_addr_in6.sin6_family == AF_UNSPEC) {
+ conf->bind_addr_in.sin_family = AF_INET;
+ conf->bind_addr_in6.sin6_family = AF_INET6;
+ }
+ else if (v4_peers) {
+ conf->bind_addr_in.sin_family = AF_INET;
+ }
+ else if (v6_peers) {
+ conf->bind_addr_in6.sin6_family = AF_INET6;
+ }
+
bool ok = true;
if (conf->protocol == PROTOCOL_IP && (!conf->peers || conf->peers->next)) {
pr_error(ctx, "for protocol `ip' exactly one peer must be configured");
@@ -263,16 +353,26 @@ static void handle_tasks(fastd_context *ctx) {
switch (task->any.type) {
case TASK_SEND:
if (task->send.peer) {
+ int sockfd;
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
- struct sockaddr_in sendaddr;
- sendaddr.sin_family = AF_INET;
- sendaddr.sin_addr.s_addr = task->send.peer->address;
- sendaddr.sin_port = task->send.peer->port;
-
- msg.msg_name = &sendaddr;
- msg.msg_namelen = sizeof(sendaddr);
+ switch (task->send.peer->address.sa.sa_family) {
+ case AF_INET:
+ msg.msg_name = &task->send.peer->address.in;
+ msg.msg_namelen = sizeof(struct sockaddr_in);
+ sockfd = ctx->sockfd;
+ break;
+
+ case AF_INET6:
+ msg.msg_name = &task->send.peer->address.in6;
+ msg.msg_namelen = sizeof(struct sockaddr_in6);
+ sockfd = ctx->sock6fd;
+ break;
+
+ default:
+ exit_bug(ctx, "unsupported address family");
+ }
struct iovec iov[2] = {
{ .iov_base = &task->send.packet_type, .iov_len = 1 },
@@ -282,7 +382,7 @@ static void handle_tasks(fastd_context *ctx) {
msg.msg_iov = iov;
msg.msg_iovlen = task->send.buffer.len ? 2 : 1;
- sendmsg(ctx->sockfd, &msg, 0);
+ sendmsg(sockfd, &msg, 0);
}
fastd_buffer_free(task->send.buffer);
@@ -319,125 +419,158 @@ static void handle_tasks(fastd_context *ctx) {
}
}
-static void handle_input(fastd_context *ctx) {
- struct pollfd fds[2];
- fds[0].fd = ctx->tunfd;
- fds[0].events = POLLIN;
- fds[1].fd = ctx->sockfd;
- fds[1].events = POLLIN;
-
- int ret = poll(fds, 2, fastd_task_timeout(ctx));
- if (ret < 0)
- exit_errno(ctx, "poll");
+static void handle_tun(fastd_context *ctx) {
+ size_t max_len = fastd_max_packet_size(ctx);
+ fastd_buffer buffer = fastd_buffer_alloc(max_len, 0, 0);
- if (fds[0].revents & POLLIN) {
- size_t max_len = fastd_max_packet_size(ctx);
- fastd_buffer buffer = fastd_buffer_alloc(max_len, 0, 0);
+ ssize_t len = read(ctx->tunfd, buffer.data, max_len);
+ if (len < 0)
+ exit_errno(ctx, "read");
- ssize_t len = read(ctx->tunfd, buffer.data, max_len);
- if (len < 0)
- exit_errno(ctx, "read");
+ buffer.len = len;
- fastd_peer *peer = NULL;
+ fastd_peer *peer = NULL;
- if (ctx->conf->protocol == PROTOCOL_ETHERNET) {
- const fastd_eth_addr *dest_addr = fastd_get_dest_address(ctx, buffer);
- if (fastd_eth_addr_is_unicast(dest_addr)) {
- peer = fastd_peer_find_by_eth_addr(ctx, dest_addr);
+ if (ctx->conf->protocol == PROTOCOL_ETHERNET) {
+ const fastd_eth_addr *dest_addr = fastd_get_dest_address(ctx, buffer);
+ if (fastd_eth_addr_is_unicast(dest_addr)) {
+ peer = fastd_peer_find_by_eth_addr(ctx, dest_addr);
- if (peer == NULL) {
- fastd_buffer_free(buffer);
- return;
- }
+ if (peer == NULL) {
+ fastd_buffer_free(buffer);
+ return;
+ }
- if (peer->state == STATE_ESTABLISHED) {
- ctx->conf->method->send(ctx, peer, buffer);
- }
- else {
- fastd_buffer_free(buffer);
- }
+ if (peer->state == STATE_ESTABLISHED) {
+ ctx->conf->method->send(ctx, peer, buffer);
+ }
+ else {
+ fastd_buffer_free(buffer);
}
}
- if (peer == NULL) {
- for (peer = ctx->peers; peer; peer = peer->next) {
- if (peer->state == STATE_ESTABLISHED) {
- fastd_buffer send_buffer = fastd_buffer_alloc(len, 0, 0);
- memcpy(send_buffer.data, buffer.data, len);
- ctx->conf->method->send(ctx, peer, send_buffer);
- }
+ }
+ if (peer == NULL) {
+ for (peer = ctx->peers; peer; peer = peer->next) {
+ if (peer->state == STATE_ESTABLISHED) {
+ fastd_buffer send_buffer = fastd_buffer_alloc(len, 0, 0);
+ memcpy(send_buffer.data, buffer.data, len);
+ ctx->conf->method->send(ctx, peer, send_buffer);
}
-
- fastd_buffer_free(buffer);
}
+
+ fastd_buffer_free(buffer);
}
- if (fds[1].revents & POLLIN) {
- size_t max_len = ctx->conf->method->max_packet_size(ctx);
- fastd_buffer buffer = fastd_buffer_alloc(max_len, 0, 0);
+}
- uint8_t packet_type;
+static void handle_socket(fastd_context *ctx, int sockfd) {
+ size_t max_len = ctx->conf->method->max_packet_size(ctx);
+ fastd_buffer buffer = fastd_buffer_alloc(max_len, 0, 0);
- struct iovec iov[2] = {
- { .iov_base = &packet_type, .iov_len = 1 },
- { .iov_base = buffer.data, .iov_len = max_len }
- };
- struct sockaddr_in recvaddr;
+ uint8_t packet_type;
+
+ struct iovec iov[2] = {
+ { .iov_base = &packet_type, .iov_len = 1 },
+ { .iov_base = buffer.data, .iov_len = max_len }
+ };
+ fastd_peer_address recvaddr;
- struct msghdr msg;
- memset(&msg, 0, sizeof(msg));
+ struct msghdr msg;
+ memset(&msg, 0, sizeof(msg));
- msg.msg_name = &recvaddr;
- msg.msg_namelen = sizeof(recvaddr);
- msg.msg_iov = iov;
- msg.msg_iovlen = 2;
+ msg.msg_name = &recvaddr;
+ msg.msg_namelen = sizeof(recvaddr);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 2;
- ssize_t len = recvmsg(ctx->sockfd, &msg, 0);
- if (len < 0)
- pr_warn(ctx, "recvfrom: %s", strerror(errno));
+ ssize_t len = recvmsg(sockfd, &msg, 0);
+ if (len < 0)
+ pr_warn(ctx, "recvfrom: %s", strerror(errno));
- fastd_peer *peer;
- for (peer = ctx->peers; peer; peer = peer->next) {
- if (recvaddr.sin_addr.s_addr == peer->address && recvaddr.sin_port == peer->port)
- break;
- }
+ buffer.len = len - 1;
- if (peer) {
- switch (packet_type) {
- case PACKET_DATA:
- buffer.len = len - 1;
- ctx->conf->method->handle_recv(ctx, peer, buffer);
- break;
+ fastd_peer *peer;
+ for (peer = ctx->peers; peer; peer = peer->next) {
+ if (peer->address.sa.sa_family != recvaddr.sa.sa_family)
+ continue;
- case PACKET_HANDSHAKE:
- fastd_handshake_handle(ctx, peer, buffer);
- break;
+ if (recvaddr.sa.sa_family == AF_INET) {
+ if (peer->address.in.sin_addr.s_addr != recvaddr.in.sin_addr.s_addr)
+ continue;
+ if (peer->address.in.sin_port != recvaddr.in.sin_port)
+ continue;
- default:
- fastd_buffer_free(buffer);
- }
+ break;
}
- else if(ctx->conf->n_floating) {
- switch (packet_type) {
- case PACKET_DATA:
- fastd_buffer_free(buffer);
+ else if (recvaddr.sa.sa_family == AF_INET6) {
+ if (!IN6_ARE_ADDR_EQUAL(&peer->address.in6.sin6_addr, &recvaddr.in6.sin6_addr))
+ continue;
+ if (peer->address.in6.sin6_port != recvaddr.in6.sin6_port)
+ continue;
- peer = fastd_peer_add_temp(ctx, recvaddr.sin_addr.s_addr, recvaddr.sin_port);
- fastd_task_schedule_handshake(ctx, peer, 0);
- break;
+ break;
+ }
+ else {
+ exit_bug(ctx, "unsupported address family");
+ }
+ }
- case PACKET_HANDSHAKE:
- peer = fastd_peer_add_temp(ctx, recvaddr.sin_addr.s_addr, recvaddr.sin_port);
- fastd_handshake_handle(ctx, peer, buffer);
- break;
+ if (peer) {
+ switch (packet_type) {
+ case PACKET_DATA:
+ ctx->conf->method->handle_recv(ctx, peer, buffer);
+ break;
- default:
- fastd_buffer_free(buffer);
- }
+ case PACKET_HANDSHAKE:
+ fastd_handshake_handle(ctx, peer, buffer);
+ break;
+
+ default:
+ fastd_buffer_free(buffer);
}
- else {
- pr_debug(ctx, "received packet from unknown peer");
+ }
+ else if(ctx->conf->n_floating) {
+ switch (packet_type) {
+ case PACKET_DATA:
+ fastd_buffer_free(buffer);
+
+ peer = fastd_peer_add_temp(ctx, (fastd_peer_address*)&recvaddr);
+ fastd_task_schedule_handshake(ctx, peer, 0);
+ break;
+
+ case PACKET_HANDSHAKE:
+ peer = fastd_peer_add_temp(ctx, (fastd_peer_address*)&recvaddr);
+ fastd_handshake_handle(ctx, peer, buffer);
+ break;
+
+ default:
fastd_buffer_free(buffer);
}
}
+ else {
+ pr_debug(ctx, "received packet from unknown peer");
+ fastd_buffer_free(buffer);
+ }
+}
+
+static void handle_input(fastd_context *ctx) {
+ struct pollfd fds[3];
+ fds[0].fd = ctx->tunfd;
+ fds[0].events = POLLIN;
+ fds[1].fd = ctx->sockfd;
+ fds[1].events = POLLIN;
+ fds[2].fd = ctx->sock6fd;
+ fds[2].events = POLLIN;
+
+ int ret = poll(fds, 3, fastd_task_timeout(ctx));
+ if (ret < 0)
+ exit_errno(ctx, "poll");
+
+ if (fds[0].revents & POLLIN)
+ handle_tun(ctx);
+ if (fds[1].revents & POLLIN)
+ handle_socket(ctx, ctx->sockfd);
+ if (fds[2].revents & POLLIN)
+ handle_socket(ctx, ctx->sock6fd);
}
diff --git a/src/fastd.h b/src/fastd.h
index 04119a7..bd0d633 100644
--- a/src/fastd.h
+++ b/src/fastd.h
@@ -39,6 +39,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/uio.h>
+#include <sys/socket.h>
typedef enum _fastd_loglevel {
@@ -67,11 +68,16 @@ typedef enum _fastd_protocol {
PROTOCOL_IP,
} fastd_protocol;
+typedef union _fastd_peer_address {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+ struct sockaddr_in6 in6;
+} fastd_peer_address;
+
typedef struct _fastd_peer_config {
struct _fastd_peer_config *next;
- in_addr_t address;
- in_port_t port;
+ fastd_peer_address address;
} fastd_peer_config;
typedef enum _fastd_peer_state {
@@ -90,8 +96,7 @@ typedef struct _fastd_peer {
const fastd_peer_config *config;
- in_addr_t address;
- in_port_t port;
+ fastd_peer_address address;
fastd_peer_state state;
uint8_t last_req_id;
@@ -123,8 +128,8 @@ struct _fastd_config {
char *ifname;
- in_addr_t bind_address;
- in_port_t bind_port;
+ struct sockaddr_in bind_addr_in;
+ struct sockaddr_in6 bind_addr_in6;
uint16_t mtu;
fastd_protocol protocol;
@@ -143,6 +148,7 @@ struct _fastd_context {
int tunfd;
int sockfd;
+ int sock6fd;
size_t eth_addr_size;
size_t n_eth_addr;
@@ -150,19 +156,25 @@ struct _fastd_context {
};
-#define pr_log(context, level, prefix, args...) if ((context)->conf == NULL || (level) <= (context)->conf->loglevel) \
+#define pr_log(ctx, level, prefix, args...) if ((ctx)->conf == NULL || (level) <= (ctx)->conf->loglevel) \
do { fputs(prefix, stderr); fprintf(stderr, args); fputs("\n", stderr); } while(0)
-#define pr_fatal(context, args...) pr_log(context, LOG_FATAL, "Fatal: ", args)
-#define pr_error(context, args...) pr_log(context, LOG_ERROR, "Error: ", args)
-#define pr_warn(context, args...) pr_log(context, LOG_WARN, "Warning: ", args)
-#define pr_info(context, args...) pr_log(context, LOG_INFO, "", args)
-#define pr_debug(context, args...) pr_log(context, LOG_DEBUG, "DEBUG: ", args)
-
-#define exit_fatal(context, args...) do { pr_fatal(context, args); abort(); } while(0)
-#define exit_bug(context, message) exit_fatal(context, "BUG: %s", message)
-#define exit_error(context, args...) do { pr_error(context, args); exit(1); } while(0)
-#define exit_errno(context, message) exit_error(context, "%s: %s", message, strerror(errno))
+#define is_error(ctx) ((ctx)->conf == NULL || LOG_ERROR <= (ctx)->conf->loglevel)
+#define is_warn(ctx) ((ctx)->conf == NULL || LOG_WARN <= (ctx)->conf->loglevel)
+#define is_info(ctx) ((ctx)->conf == NULL || LOG_INFO <= (ctx)->conf->loglevel)
+#define is_debug(ctx) ((ctx)->conf == NULL || LOG_DEBUG <= (ctx)->conf->loglevel)
+
+#define pr_fatal(ctx, args...) pr_log(ctx, LOG_FATAL, "Fatal: ", args)
+#define pr_error(ctx, args...) pr_log(ctx, LOG_ERROR, "Error: ", args)
+#define pr_warn(ctx, args...) pr_log(ctx, LOG_WARN, "Warning: ", args)
+#define pr_info(ctx, args...) pr_log(ctx, LOG_INFO, "", args)
+#define pr_debug(ctx, args...) pr_log(ctx, LOG_DEBUG, "DEBUG: ", args)
+
+#define warn_errno(ctx, message) pr_warn(ctx, "%s: %s", message, strerror(errno))
+#define exit_fatal(ctx, args...) do { pr_fatal(ctx, args); abort(); } while(0)
+#define exit_bug(ctx, message) exit_fatal(ctx, "BUG: %s", message)
+#define exit_error(ctx, args...) do { pr_error(ctx, args); exit(1); } while(0)
+#define exit_errno(ctx, message) exit_error(ctx, "%s: %s", message, strerror(errno))
static inline fastd_buffer fastd_buffer_alloc(size_t len, size_t head_space, size_t tail_space) {
diff --git a/src/peer.c b/src/peer.c
index 93cb465..5cce906 100644
--- a/src/peer.c
+++ b/src/peer.c
@@ -65,29 +65,65 @@ fastd_peer* fastd_peer_add(fastd_context *ctx, fastd_peer_config *peer_conf) {
peer->config = peer_conf;
peer->address = peer_conf->address;
- peer->port = peer_conf->port;
peer->state = STATE_WAIT;
- pr_debug(ctx, "added peer %s:%u", inet_ntoa((struct in_addr){ .s_addr = peer->address }), ntohs(peer->port));
+ if (is_debug(ctx)) {
+ char buf[INET6_ADDRSTRLEN] = "";
- if (peer->address)
+ switch (peer->address.sa.sa_family) {
+ case AF_UNSPEC:
+ pr_debug(ctx, "added peer <floating>");
+ break;
+
+ case AF_INET:
+ if (inet_ntop(AF_INET, &peer->address.in.sin_addr, buf, sizeof(buf)))
+ pr_debug(ctx, "added peer %s:%u", buf, ntohs(peer->address.in.sin_port));
+ break;
+
+ case AF_INET6:
+ if (inet_ntop(AF_INET6, &peer->address.in6.sin6_addr, buf, sizeof(buf)))
+ pr_debug(ctx, "added peer [%s]:%u", buf, ntohs(peer->address.in6.sin6_port));
+ break;
+
+ default:
+ exit_bug(ctx, "unsupported address family");
+ }
+ }
+
+ if (!fastd_peer_is_floating(peer))
fastd_task_schedule_handshake(ctx, peer, 0);
return peer;
}
-fastd_peer* fastd_peer_add_temp(fastd_context *ctx, in_addr_t address, in_port_t port) {
+fastd_peer* fastd_peer_add_temp(fastd_context *ctx, const fastd_peer_address *address) {
fastd_peer *peer = add_peer(ctx);
if (!ctx->conf->n_floating)
exit_bug(ctx, "tried to add a temporary peer with no floating remotes defined");
peer->config = NULL;
- peer->address = address;
- peer->port = port;
+ peer->address = *address;
peer->state = STATE_TEMP;
- pr_debug(ctx, "added peer %s:%u (temporary)", inet_ntoa((struct in_addr){ .s_addr = peer->address }), ntohs(peer->port));
+ if (is_debug(ctx)) {
+ char buf[INET6_ADDRSTRLEN] = "";
+
+ switch (peer->address.sa.sa_family) {
+ case AF_INET:
+ if (inet_ntop(AF_INET, &peer->address.in.sin_addr, buf, sizeof(buf)))
+ pr_debug(ctx, "added peer %s:%u (temporary)", buf, ntohs(peer->address.in.sin_port));
+ break;
+
+ case AF_INET6:
+ if (inet_ntop(AF_INET6, &peer->address.in6.sin6_addr, buf, sizeof(buf)))
+ pr_debug(ctx, "added peer [%s]:%u (temporary)", buf, ntohs(peer->address.in6.sin6_port));
+ break;
+
+ default:
+ exit_bug(ctx, "unsupported address family");
+ }
+ }
return peer;
}
@@ -96,7 +132,6 @@ fastd_peer* fastd_peer_merge(fastd_context *ctx, fastd_peer *perm_peer, fastd_pe
pr_debug(ctx, "merging peers");
perm_peer->address = temp_peer->address;
- perm_peer->port = temp_peer->port;
perm_peer->state = fastd_peer_is_established(temp_peer) ? STATE_ESTABLISHED : STATE_WAIT;
int i;
diff --git a/src/peer.h b/src/peer.h
index cd3d1d9..38f13b2 100644
--- a/src/peer.h
+++ b/src/peer.h
@@ -35,13 +35,30 @@ const fastd_eth_addr* fastd_get_source_address(const fastd_context *ctx, fastd_b
const fastd_eth_addr* fastd_get_dest_address(const fastd_context *ctx, fastd_buffer buffer);
fastd_peer* fastd_peer_add(fastd_context *ctx, fastd_peer_config *conf);
-fastd_peer* fastd_peer_add_temp(fastd_context *ctx, in_addr_t address, in_port_t port);
+fastd_peer* fastd_peer_add_temp(fastd_context *ctx, const fastd_peer_address *address);
fastd_peer* fastd_peer_merge(fastd_context *ctx, fastd_peer *perm_peer, fastd_peer *temp_peer);
void fastd_peer_delete(fastd_context *ctx, fastd_peer *peer);
+static inline bool fastd_peer_config_is_floating(const fastd_peer_config *config) {
+ switch (config->address.sa.sa_family) {
+ case AF_UNSPEC:
+ return true;
+
+ case AF_INET:
+ return !config->address.in.sin_addr.s_addr;
+
+ case AF_INET6:
+ return IN6_IS_ADDR_UNSPECIFIED(&config->address.in6.sin6_addr);
+
+ default:
+ /* What is this? I don't even... */
+ return false;
+ }
+}
+
static inline bool fastd_peer_is_floating(fastd_peer *peer) {
- return (peer->config && !peer->config->address);
+ return (peer->config && fastd_peer_config_is_floating(peer->config));
}
static inline bool fastd_peer_is_temporary(fastd_peer *peer) {