summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2013-04-20 18:43:12 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2013-04-20 18:43:12 +0200
commit3fcb880682a02e1952eb710a5952a0d7f92f41e1 (patch)
treeab829de58a61a2e6b422979df2f352caf196f6bb
parentdaf3d6e8db9ef39b50dce040f864fb409bd7044a (diff)
downloadfastd-3fcb880682a02e1952eb710a5952a0d7f92f41e1.tar
fastd-3fcb880682a02e1952eb710a5952a0d7f92f41e1.zip
Greatly improve handling of hosts with multiple IP addresses
-rw-r--r--src/fastd.c145
-rw-r--r--src/fastd.h8
-rw-r--r--src/handshake.c26
-rw-r--r--src/handshake.h2
-rw-r--r--src/peer.c21
-rw-r--r--src/peer.h16
-rw-r--r--src/protocol_ec25519_fhmqvc.c102
7 files changed, 224 insertions, 96 deletions
diff --git a/src/fastd.c b/src/fastd.c
index d82589e..70bd99e 100644
--- a/src/fastd.c
+++ b/src/fastd.c
@@ -224,6 +224,19 @@ static int bind_socket(fastd_context_t *ctx, const fastd_bind_address_t *addr, b
fastd_setfd(ctx, fd, FD_CLOEXEC, 0);
fastd_setfl(ctx, fd, O_NONBLOCK, 0);
+ int one = 1;
+ if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one))) {
+ pr_error_errno(ctx, "setsockopt: unable to set IP_PKTINFO");
+ goto error;
+ }
+
+ if (af == AF_INET6) {
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one))) {
+ pr_error_errno(ctx, "setsockopt: unable to set IPV6_RECVPKTINFO");
+ goto error;
+ }
+ }
+
if (addr->bindtodev) {
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, addr->bindtodev, strlen(addr->bindtodev))) {
if (warn)
@@ -303,10 +316,14 @@ static bool bind_sockets(fastd_context_t *ctx) {
continue;
}
+ fastd_peer_address_t bound_addr = *ctx->socks[i].bound_addr;
+ if (!ctx->socks[i].addr->addr.sa.sa_family)
+ bound_addr.sa.sa_family = AF_UNSPEC;
+
if (ctx->socks[i].addr->bindtodev)
- pr_info(ctx, "successfully bound to %B on `%s'", ctx->socks[i].bound_addr, ctx->socks[i].addr->bindtodev);
+ pr_info(ctx, "successfully bound to %B on `%s'", &bound_addr, ctx->socks[i].addr->bindtodev);
else
- pr_info(ctx, "successfully bound to %B", ctx->socks[i].bound_addr);
+ pr_info(ctx, "successfully bound to %B", &bound_addr);
}
}
@@ -504,21 +521,21 @@ static size_t methods_min_decrypt_tail_space(fastd_context_t *ctx) {
return ret;
}
-static void fastd_send_type(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *address, uint8_t packet_type, fastd_buffer_t buffer) {
+static void fastd_send_type(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, uint8_t packet_type, fastd_buffer_t buffer) {
if (!sock)
exit_bug(ctx, "send: sock == NULL");
- struct msghdr msg;
- memset(&msg, 0, sizeof(msg));
+ struct msghdr msg = {};
+ char cbuf[1024] = {};
- switch (address->sa.sa_family) {
+ switch (remote_addr->sa.sa_family) {
case AF_INET:
- msg.msg_name = (void*)&address->in;
+ msg.msg_name = (void*)&remote_addr->in;
msg.msg_namelen = sizeof(struct sockaddr_in);
break;
case AF_INET6:
- msg.msg_name = (void*)&address->in6;
+ msg.msg_name = (void*)&remote_addr->in6;
msg.msg_namelen = sizeof(struct sockaddr_in6);
break;
@@ -534,6 +551,36 @@ static void fastd_send_type(fastd_context_t *ctx, const fastd_socket_t *sock, co
msg.msg_iov = iov;
msg.msg_iovlen = buffer.len ? 2 : 1;
+ if (local_addr && (local_addr->sa.sa_family == AF_INET || local_addr->sa.sa_family == AF_INET6)) {
+ msg.msg_control = cbuf;
+ msg.msg_controllen = sizeof(cbuf);
+
+ struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
+
+ if (local_addr->sa.sa_family == AF_INET) {
+ cmsg->cmsg_level = IPPROTO_IP;
+ cmsg->cmsg_type = IP_PKTINFO;
+
+ msg.msg_controllen = cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+
+ struct in_pktinfo *pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
+ pktinfo->ipi_addr = local_addr->in.sin_addr;
+ }
+ else {
+ cmsg->cmsg_level = IPPROTO_IPV6;
+ cmsg->cmsg_type = IPV6_PKTINFO;
+
+ msg.msg_controllen = cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+
+ struct in6_pktinfo *pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+
+ pktinfo->ipi6_addr = local_addr->in6.sin6_addr;
+
+ if (IN6_IS_ADDR_LINKLOCAL(&local_addr->in6.sin6_addr))
+ pktinfo->ipi6_ifindex = local_addr->in6.sin6_scope_id;
+ }
+ }
+
int ret;
do {
ret = sendmsg(sock->fd, &msg, 0);
@@ -545,12 +592,12 @@ static void fastd_send_type(fastd_context_t *ctx, const fastd_socket_t *sock, co
fastd_buffer_free(buffer);
}
-void fastd_send(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *address, fastd_buffer_t buffer) {
- fastd_send_type(ctx, sock, address, PACKET_DATA, buffer);
+void fastd_send(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_buffer_t buffer) {
+ fastd_send_type(ctx, sock, local_addr, remote_addr, PACKET_DATA, buffer);
}
-void fastd_send_handshake(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *address, fastd_buffer_t buffer) {
- fastd_send_type(ctx, sock, address, PACKET_HANDSHAKE, buffer);
+void fastd_send_handshake(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_buffer_t buffer) {
+ fastd_send_type(ctx, sock, local_addr, remote_addr, PACKET_HANDSHAKE, buffer);
}
void fastd_handle_receive(fastd_context_t *ctx, fastd_peer_t *peer, fastd_buffer_t buffer) {
@@ -739,7 +786,7 @@ static void send_handshake(fastd_context_t *ctx, fastd_peer_t *peer) {
pr_debug(ctx, "sending handshake to %P...", peer);
peer->last_handshake = ctx->now;
peer->last_handshake_address = peer->address;
- ctx->conf->protocol->handshake_init(ctx, peer->sock, &peer->address, peer);
+ ctx->conf->protocol->handshake_init(ctx, peer->sock, &peer->local_address, &peer->address, peer);
}
}
@@ -828,15 +875,65 @@ static void handle_socket(fastd_context_t *ctx, fastd_socket_t *sock) {
size_t max_len = PACKET_TYPE_LEN + methods_max_packet_size(ctx);
fastd_buffer_t buffer = fastd_buffer_alloc(ctx, max_len, methods_min_decrypt_head_space(ctx), methods_min_decrypt_tail_space(ctx));
uint8_t *packet_type;
+ fastd_peer_address_t local_addr = {};
fastd_peer_address_t recvaddr;
- socklen_t recvaddrlen = sizeof(recvaddr);
+ struct iovec buffer_vec = { .iov_base = buffer.data, .iov_len = buffer.len };
+ char cbuf[1024];
+
+ struct msghdr message = {
+ .msg_name = &recvaddr,
+ .msg_namelen = sizeof(recvaddr),
+ .msg_iov = &buffer_vec,
+ .msg_iovlen = 1,
+ .msg_control = cbuf,
+ .msg_controllen = sizeof(cbuf),
+ };
- ssize_t len = recvfrom(sock->fd, buffer.data, buffer.len, 0, (struct sockaddr*)&recvaddr, &recvaddrlen);
+ ssize_t len = recvmsg(sock->fd, &message, 0);
if (len <= 0) {
if (len < 0 && errno != EINTR)
- pr_warn(ctx, "recvfrom: %s", strerror(errno));
+ pr_warn_errno(ctx, "recvmsg");
+
+ fastd_buffer_free(buffer);
+ return;
+ }
+
+ struct cmsghdr *cmsg;
+ for (cmsg = CMSG_FIRSTHDR(&message); cmsg; cmsg = CMSG_NXTHDR(&message, cmsg)) {
+ if ((char*)cmsg + sizeof(*cmsg) > cbuf + sizeof(cbuf))
+ break;
+
+ if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
+ struct in_pktinfo *pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
+ if ((char*)pktinfo + sizeof(*pktinfo) > cbuf + sizeof(cbuf))
+ break;
+
+ local_addr.in.sin_family = AF_INET;
+ local_addr.in.sin_addr = pktinfo->ipi_addr;
+ local_addr.in.sin_port = fastd_peer_address_get_port(sock->bound_addr);
+
+ break;
+ }
+ if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
+ struct in6_pktinfo *pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+ if ((char*)pktinfo + sizeof(*pktinfo) > cbuf + sizeof(cbuf))
+ break;
+
+ local_addr.in6.sin6_family = AF_INET6;
+ local_addr.in6.sin6_addr = pktinfo->ipi6_addr;
+ local_addr.in6.sin6_port = fastd_peer_address_get_port(sock->bound_addr);
+
+ if (IN6_IS_ADDR_LINKLOCAL(&local_addr.in6.sin6_addr))
+ local_addr.in6.sin6_scope_id = pktinfo->ipi6_ifindex;
+
+ break;
+ }
+ }
+
+ if (!local_addr.sa.sa_family) {
+ pr_error(ctx, "received packet without packet info");
fastd_buffer_free(buffer);
return;
}
@@ -870,11 +967,17 @@ static void handle_socket(fastd_context_t *ctx, fastd_socket_t *sock) {
switch (*packet_type) {
case PACKET_DATA:
- ctx->conf->protocol->handle_recv(ctx, peer, buffer);
+ if (fastd_peer_is_established(peer) && fastd_peer_address_equal(&peer->local_address, &local_addr)) {
+ ctx->conf->protocol->handle_recv(ctx, peer, buffer);
+ }
+ else {
+ fastd_buffer_free(buffer);
+ ctx->conf->protocol->handshake_init(ctx, sock, &local_addr, &recvaddr, NULL);
+ }
break;
case PACKET_HANDSHAKE:
- fastd_handshake_handle(ctx, sock, &recvaddr, peer, buffer);
+ fastd_handshake_handle(ctx, sock, &local_addr, &recvaddr, peer, buffer);
break;
default:
@@ -887,11 +990,11 @@ static void handle_socket(fastd_context_t *ctx, fastd_socket_t *sock) {
switch (*packet_type) {
case PACKET_DATA:
fastd_buffer_free(buffer);
- ctx->conf->protocol->handshake_init(ctx, sock, &recvaddr, NULL);
+ ctx->conf->protocol->handshake_init(ctx, sock, &local_addr, &recvaddr, NULL);
break;
case PACKET_HANDSHAKE:
- fastd_handshake_handle(ctx, sock, &recvaddr, NULL, buffer);
+ fastd_handshake_handle(ctx, sock, &local_addr, &recvaddr, NULL, buffer);
break;
default:
@@ -933,7 +1036,7 @@ static void handle_resolv_returns(fastd_context_t *ctx) {
peer->last_resolve_return = ctx->now;
- if (fastd_peer_claim_address(ctx, peer, NULL, &resolve_return.addr)) {
+ if (fastd_peer_claim_address(ctx, peer, NULL, NULL, &resolve_return.addr)) {
send_handshake(ctx, peer);
}
else {
diff --git a/src/fastd.h b/src/fastd.h
index 9736e08..943b953 100644
--- a/src/fastd.h
+++ b/src/fastd.h
@@ -71,8 +71,8 @@ struct fastd_protocol {
bool (*peer_check)(fastd_context_t *ctx, fastd_peer_config_t *peer_conf);
bool (*peer_check_temporary)(fastd_context_t *ctx, fastd_peer_t *peer);
- void (*handshake_init)(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *address, fastd_peer_t *peer);
- void (*handshake_handle)(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *address, fastd_peer_t *peer, const fastd_handshake_t *handshake, const fastd_method_t *method);
+ void (*handshake_init)(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer);
+ void (*handshake_handle)(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, const fastd_handshake_t *handshake, const fastd_method_t *method);
void (*handle_recv)(fastd_context_t *ctx, fastd_peer_t *peer, fastd_buffer_t buffer);
void (*send)(fastd_context_t *ctx, fastd_peer_t *peer, fastd_buffer_t buffer);
@@ -308,8 +308,8 @@ struct fastd_string_stack {
};
-void fastd_send(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *address, fastd_buffer_t buffer);
-void fastd_send_handshake(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *address, fastd_buffer_t buffer);
+void fastd_send(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_buffer_t buffer);
+void fastd_send_handshake(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_buffer_t buffer);
void fastd_handle_receive(fastd_context_t *ctx, fastd_peer_t *peer, fastd_buffer_t buffer);
fastd_socket_t* fastd_socket_open(fastd_context_t *ctx, fastd_peer_t *peer, int af);
diff --git a/src/handshake.c b/src/handshake.c
index d28ebad..064cabf 100644
--- a/src/handshake.c
+++ b/src/handshake.c
@@ -180,9 +180,9 @@ static fastd_string_stack_t* parse_string_list(uint8_t *data, size_t len) {
return ret;
}
-void fastd_handshake_handle(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *address, fastd_peer_t *peer, fastd_buffer_t buffer) {
+void fastd_handshake_handle(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, fastd_buffer_t buffer) {
if (buffer.len < sizeof(fastd_packet_t)) {
- pr_warn(ctx, "received a short handshake from %I", address);
+ pr_warn(ctx, "received a short handshake from %I", remote_addr);
goto end_free;
}
@@ -211,7 +211,7 @@ void fastd_handshake_handle(fastd_context_t *ctx, fastd_socket_t *sock, const fa
}
if (handshake.records[RECORD_HANDSHAKE_TYPE].length != 1) {
- pr_debug(ctx, "received handshake without handshake type from %I", address);
+ pr_debug(ctx, "received handshake without handshake type from %I", remote_addr);
goto end_free;
}
@@ -220,7 +220,7 @@ void fastd_handshake_handle(fastd_context_t *ctx, fastd_socket_t *sock, const fa
if (handshake.records[RECORD_MTU].length == 2) {
if (AS_UINT16(handshake.records[RECORD_MTU]) != ctx->conf->mtu) {
pr_warn(ctx, "MTU configuration differs with peer %I: local MTU is %u, remote MTU is %u",
- address, ctx->conf->mtu, AS_UINT16(handshake.records[RECORD_MTU]));
+ remote_addr, ctx->conf->mtu, AS_UINT16(handshake.records[RECORD_MTU]));
}
}
@@ -304,15 +304,15 @@ void fastd_handshake_handle(fastd_context_t *ctx, fastd_socket_t *sock, const fa
fastd_handshake_add_uint8(ctx, &reply_buffer, RECORD_REPLY_CODE, reply_code);
fastd_handshake_add_uint8(ctx, &reply_buffer, RECORD_ERROR_DETAIL, error_detail);
- fastd_send_handshake(ctx, sock, address, reply_buffer);
+ fastd_send_handshake(ctx, sock, local_addr, remote_addr, reply_buffer);
}
else {
- ctx->conf->protocol->handshake_handle(ctx, sock, address, peer, &handshake, method);
+ ctx->conf->protocol->handshake_handle(ctx, sock, local_addr, remote_addr, peer, &handshake, method);
}
}
else {
if (handshake.records[RECORD_REPLY_CODE].length != 1) {
- pr_warn(ctx, "received handshake reply without reply code from %I", address);
+ pr_warn(ctx, "received handshake reply without reply code from %I", remote_addr);
goto end_free;
}
@@ -330,22 +330,22 @@ void fastd_handshake_handle(fastd_context_t *ctx, fastd_socket_t *sock, const fa
* It doesn't even make sense to send an error reply here.
*/
if (!method) {
- pr_warn(ctx, "Handshake with %I failed because an invalid method name was sent", address);
+ pr_warn(ctx, "Handshake with %I failed because an invalid method name was sent", remote_addr);
goto end_free;
}
- ctx->conf->protocol->handshake_handle(ctx, sock, address, peer, &handshake, method);
+ ctx->conf->protocol->handshake_handle(ctx, sock, local_addr, remote_addr, peer, &handshake, method);
}
else {
const char *error_field_str;
if (reply_code >= REPLY_MAX) {
- pr_warn(ctx, "Handshake with %I failed with unknown code %i", address, reply_code);
+ pr_warn(ctx, "Handshake with %I failed with unknown code %i", remote_addr, reply_code);
goto end_free;
}
if (handshake.records[RECORD_ERROR_DETAIL].length != 1) {
- pr_warn(ctx, "Handshake with %I failed with code %s", address, REPLY_TYPES[reply_code]);
+ pr_warn(ctx, "Handshake with %I failed with code %s", remote_addr, REPLY_TYPES[reply_code]);
goto end_free;
}
@@ -357,11 +357,11 @@ void fastd_handshake_handle(fastd_context_t *ctx, fastd_socket_t *sock, const fa
switch (reply_code) {
case REPLY_MANDATORY_MISSING:
- pr_warn(ctx, "Handshake with %I failed: mandatory field `%s' missing", address, error_field_str);
+ pr_warn(ctx, "Handshake with %I failed: mandatory field `%s' missing", remote_addr, error_field_str);
break;
case REPLY_UNACCEPTABLE_VALUE:
- pr_warn(ctx, "Handshake with %I failed: unacceptable value for field `%s'", address, error_field_str);
+ pr_warn(ctx, "Handshake with %I failed: unacceptable value for field `%s'", remote_addr, error_field_str);
break;
default: /* just to silence the warning */
diff --git a/src/handshake.h b/src/handshake.h
index 67a81fc..1c349da 100644
--- a/src/handshake.h
+++ b/src/handshake.h
@@ -71,7 +71,7 @@ struct fastd_handshake {
fastd_buffer_t fastd_handshake_new_init(fastd_context_t *ctx, size_t tail_space);
fastd_buffer_t fastd_handshake_new_reply(fastd_context_t *ctx, const fastd_handshake_t *handshake, const fastd_method_t *method, size_t tail_space);
-void fastd_handshake_handle(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *address, fastd_peer_t *peer, fastd_buffer_t buffer);
+void fastd_handshake_handle(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, fastd_buffer_t buffer);
static inline void fastd_handshake_add(fastd_context_t *ctx, fastd_buffer_t *buffer, fastd_handshake_record_type_t type, size_t len, const void *data) {
diff --git a/src/peer.c b/src/peer.c
index f4d62e3..14af83c 100644
--- a/src/peer.c
+++ b/src/peer.c
@@ -36,14 +36,14 @@ static inline void on_establish(fastd_context_t *ctx, const fastd_peer_t *peer)
if (!ctx->conf->on_establish)
return;
- fastd_shell_exec(ctx, ctx->conf->on_establish, ctx->conf->on_establish_dir, peer, peer->sock->bound_addr, &peer->address, NULL);
+ fastd_shell_exec(ctx, ctx->conf->on_establish, ctx->conf->on_establish_dir, peer, &peer->local_address, &peer->address, NULL);
}
static inline void on_disestablish(fastd_context_t *ctx, const fastd_peer_t *peer) {
if (!ctx->conf->on_disestablish)
return;
- fastd_shell_exec(ctx, ctx->conf->on_disestablish, ctx->conf->on_disestablish_dir, peer, peer->sock->bound_addr, &peer->address, NULL);
+ fastd_shell_exec(ctx, ctx->conf->on_disestablish, ctx->conf->on_disestablish_dir, peer, &peer->local_address, &peer->address, NULL);
}
static inline void free_socket(fastd_context_t *ctx, fastd_peer_t *peer) {
@@ -133,6 +133,8 @@ static void reset_peer(fastd_context_t *ctx, fastd_peer_t *peer) {
free_socket(ctx, peer);
+ memset(&peer->local_address, 0, sizeof(peer->local_address)),
+
ctx->conf->protocol->reset_peer_state(ctx, peer);
int i, deleted = 0;
@@ -275,6 +277,10 @@ bool fastd_peer_address_equal(const fastd_peer_address_t *addr1, const fastd_pee
return false;
if (addr1->in6.sin6_port != addr2->in6.sin6_port)
return false;
+ if (IN6_IS_ADDR_LINKLOCAL(&addr1->in6.sin6_addr)) {
+ if (addr1->in6.sin6_scope_id != addr2->in6.sin6_scope_id)
+ return false;
+ }
}
return true;
@@ -299,15 +305,15 @@ static inline void reset_peer_address(fastd_context_t *ctx, fastd_peer_t *peer)
memset(&peer->address, 0, sizeof(fastd_peer_address_t));
}
-bool fastd_peer_claim_address(fastd_context_t *ctx, fastd_peer_t *new_peer, fastd_socket_t *sock, const fastd_peer_address_t *addr) {
- if (addr->sa.sa_family == AF_UNSPEC) {
+bool fastd_peer_claim_address(fastd_context_t *ctx, fastd_peer_t *new_peer, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr) {
+ if (remote_addr->sa.sa_family == AF_UNSPEC) {
if (fastd_peer_is_established(new_peer))
fastd_peer_reset(ctx, new_peer);
}
else {
fastd_peer_t *peer;
for (peer = ctx->peers; peer; peer = peer->next) {
- if (!fastd_peer_address_equal(&peer->address, addr))
+ if (!fastd_peer_address_equal(&peer->address, remote_addr))
continue;
if (peer == new_peer)
@@ -323,12 +329,15 @@ bool fastd_peer_claim_address(fastd_context_t *ctx, fastd_peer_t *new_peer, fast
}
}
- new_peer->address = *addr;
+ new_peer->address = *remote_addr;
if (sock && sock->addr && sock != new_peer->sock) {
free_socket(ctx, new_peer);
new_peer->sock = sock;
}
+ if (local_addr)
+ new_peer->local_address = *local_addr;
+
return true;
}
diff --git a/src/peer.h b/src/peer.h
index dde19dd..4b57197 100644
--- a/src/peer.h
+++ b/src/peer.h
@@ -37,6 +37,7 @@ struct fastd_peer {
fastd_peer_group_t *group;
fastd_socket_t *sock;
+ fastd_peer_address_t local_address;
fastd_peer_address_t address;
bool established;
@@ -82,6 +83,19 @@ struct fastd_peer_eth_addr {
bool fastd_peer_address_equal(const fastd_peer_address_t *addr1, const fastd_peer_address_t *addr2);
void fastd_peer_address_simplify(fastd_peer_address_t *addr);
+static inline uint16_t fastd_peer_address_get_port(const fastd_peer_address_t *addr) {
+ switch (addr->sa.sa_family) {
+ case AF_INET:
+ return addr->in.sin_port;
+
+ case AF_INET6:
+ return addr->in6.sin6_port;
+
+ default:
+ return 0;
+ }
+}
+
fastd_peer_config_t* fastd_peer_config_new(fastd_context_t *ctx, fastd_config_t *conf);
void fastd_peer_config_free(fastd_peer_config_t *peer);
void fastd_peer_config_delete(fastd_context_t *ctx, fastd_config_t *conf);
@@ -96,7 +110,7 @@ bool fastd_peer_verify_temporary(fastd_context_t *ctx, fastd_peer_t *peer, const
void fastd_peer_enable_temporary(fastd_context_t *ctx, fastd_peer_t *peer);
void fastd_peer_set_established(fastd_context_t *ctx, fastd_peer_t *peer);
bool fastd_peer_may_connect(fastd_context_t *ctx, fastd_peer_t *peer);
-bool fastd_peer_claim_address(fastd_context_t *ctx, fastd_peer_t *peer, fastd_socket_t *sock, const fastd_peer_address_t *addr);
+bool fastd_peer_claim_address(fastd_context_t *ctx, fastd_peer_t *peer, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr);
void fastd_peer_reset_socket(fastd_context_t *ctx, fastd_peer_t *peer);
const fastd_eth_addr_t* fastd_get_source_address(const fastd_context_t *ctx, fastd_buffer_t buffer);
diff --git a/src/protocol_ec25519_fhmqvc.c b/src/protocol_ec25519_fhmqvc.c
index d0dad5b..662f3b8 100644
--- a/src/protocol_ec25519_fhmqvc.c
+++ b/src/protocol_ec25519_fhmqvc.c
@@ -260,7 +260,7 @@ static void maintenance(fastd_context_t *ctx) {
}
}
-static void protocol_handshake_init(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *address, fastd_peer_t *peer) {
+static void protocol_handshake_init(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer) {
maintenance(ctx);
fastd_buffer_t buffer = fastd_handshake_new_init(ctx, 3*(4+PUBLICKEYBYTES) /* sender key, receipient key, handshake key */);
@@ -270,16 +270,16 @@ static void protocol_handshake_init(fastd_context_t *ctx, const fastd_socket_t *
if (peer)
fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES, peer->protocol_config->public_key.p);
else
- pr_debug(ctx, "sending handshake to unknown peer %I", address);
+ pr_debug(ctx, "sending handshake to unknown peer %I", remote_addr);
fastd_handshake_add(ctx, &buffer, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES, ctx->protocol_state->handshake_key.public_key.p);
- fastd_send_handshake(ctx, sock, address, buffer);
+ fastd_send_handshake(ctx, sock, local_addr, remote_addr, buffer);
}
-static void respond_handshake(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *address, const fastd_peer_t *peer, const handshake_key_t *handshake_key, const ecc_int256_t *peer_handshake_key,
- const fastd_handshake_t *handshake, const fastd_method_t *method) {
- pr_debug(ctx, "responding handshake with %P[%I]...", peer, address);
+static void respond_handshake(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, const fastd_peer_t *peer,
+ const handshake_key_t *handshake_key, const ecc_int256_t *peer_handshake_key, const fastd_handshake_t *handshake, const fastd_method_t *method) {
+ pr_debug(ctx, "responding handshake with %P[%I]...", peer, remote_addr);
uint8_t hashinput[5*PUBLICKEYBYTES];
uint8_t hashbuf[HASHBYTES];
@@ -341,21 +341,22 @@ static void respond_handshake(fastd_context_t *ctx, const fastd_socket_t *sock,
fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES, peer_handshake_key->p);
fastd_handshake_add(ctx, &buffer, RECORD_T, HMACBYTES, hmacbuf);
- fastd_send_handshake(ctx, sock, address, buffer);
+ fastd_send_handshake(ctx, sock, local_addr, remote_addr, buffer);
}
-static bool establish(fastd_context_t *ctx, fastd_peer_t *peer, const fastd_method_t *method, fastd_socket_t *sock, const fastd_peer_address_t *address, bool initiator,
+static bool establish(fastd_context_t *ctx, fastd_peer_t *peer, const fastd_method_t *method, fastd_socket_t *sock,
+ const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, bool initiator,
const ecc_int256_t *A, const ecc_int256_t *B, const ecc_int256_t *X,
const ecc_int256_t *Y, const ecc_int256_t *sigma, uint64_t serial) {
uint8_t hashinput[5*PUBLICKEYBYTES];
uint8_t hash[HASHBYTES];
if (serial <= peer->protocol_state->last_serial) {
- pr_debug(ctx, "ignoring handshake from %P[%I] because of handshake key reuse", peer, address);
+ pr_debug(ctx, "ignoring handshake from %P[%I] because of handshake key reuse", peer, remote_addr);
return false;
}
- pr_verbose(ctx, "%I authorized as %P", address, peer);
+ pr_verbose(ctx, "%I authorized as %P", remote_addr, peer);
if (is_session_valid(ctx, &peer->protocol_state->session) && !is_session_valid(ctx, &peer->protocol_state->old_session)) {
if (peer->protocol_state->old_session.method)
@@ -383,8 +384,8 @@ static bool establish(fastd_context_t *ctx, fastd_peer_t *peer, const fastd_meth
fastd_peer_seen(ctx, peer);
- if (!fastd_peer_claim_address(ctx, peer, sock, address)) {
- pr_warn(ctx, "can't set address %I which is used by a fixed peer", address);
+ if (!fastd_peer_claim_address(ctx, peer, sock, local_addr, remote_addr)) {
+ pr_warn(ctx, "can't set address %I which is used by a fixed peer", remote_addr);
fastd_peer_reset(ctx, peer);
return false;
}
@@ -401,9 +402,9 @@ static bool establish(fastd_context_t *ctx, fastd_peer_t *peer, const fastd_meth
return true;
}
-static void finish_handshake(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *address, fastd_peer_t *peer, const handshake_key_t *handshake_key, const ecc_int256_t *peer_handshake_key,
+static void finish_handshake(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, const handshake_key_t *handshake_key, const ecc_int256_t *peer_handshake_key,
const fastd_handshake_t *handshake, const fastd_method_t *method) {
- pr_debug(ctx, "finishing handshake with %P[%I]...", peer, address);
+ pr_debug(ctx, "finishing handshake with %P[%I]...", peer, remote_addr);
uint8_t hashinput[5*PUBLICKEYBYTES];
uint8_t hashbuf[HASHBYTES];
@@ -456,7 +457,7 @@ static void finish_handshake(fastd_context_t *ctx, fastd_socket_t *sock, const f
memcpy(hashinput+PUBLICKEYBYTES, peer_handshake_key->p, PUBLICKEYBYTES);
if(crypto_auth_hmacsha256_verify(handshake->records[RECORD_T].data, hashinput, 2*PUBLICKEYBYTES, shared_handshake_key) != 0) {
- pr_warn(ctx, "received invalid protocol handshake response from %P[%I]", peer, address);
+ pr_warn(ctx, "received invalid protocol handshake response from %P[%I]", peer, remote_addr);
return;
}
@@ -464,7 +465,7 @@ static void finish_handshake(fastd_context_t *ctx, fastd_socket_t *sock, const f
memcpy(hashinput+PUBLICKEYBYTES, handshake_key->public_key.p, PUBLICKEYBYTES);
crypto_auth_hmacsha256(hmacbuf, hashinput, 2*PUBLICKEYBYTES, shared_handshake_key);
- if (!establish(ctx, peer, method, sock, address, true, &handshake_key->public_key, peer_handshake_key, &ctx->conf->protocol_config->public_key,
+ if (!establish(ctx, peer, method, sock, local_addr, remote_addr, true, &handshake_key->public_key, peer_handshake_key, &ctx->conf->protocol_config->public_key,
&peer->protocol_config->public_key, &sigma, handshake_key->serial))
return;
@@ -476,12 +477,13 @@ static void finish_handshake(fastd_context_t *ctx, fastd_socket_t *sock, const f
fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES, peer_handshake_key->p);
fastd_handshake_add(ctx, &buffer, RECORD_T, HMACBYTES, hmacbuf);
- fastd_send_handshake(ctx, sock, address, buffer);
+ fastd_send_handshake(ctx, sock, local_addr, remote_addr, buffer);
}
-static void handle_finish_handshake(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *address, fastd_peer_t *peer, const handshake_key_t *handshake_key, const ecc_int256_t *peer_handshake_key,
+static void handle_finish_handshake(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr,
+ fastd_peer_t *peer, const handshake_key_t *handshake_key, const ecc_int256_t *peer_handshake_key,
const fastd_handshake_t *handshake, const fastd_method_t *method) {
- pr_debug(ctx, "handling handshake finish with %P[%I]...", peer, address);
+ pr_debug(ctx, "handling handshake finish with %P[%I]...", peer, remote_addr);
uint8_t hashinput[5*PUBLICKEYBYTES];
uint8_t hashbuf[HASHBYTES];
@@ -533,11 +535,11 @@ static void handle_finish_handshake(fastd_context_t *ctx, fastd_socket_t *sock,
memcpy(hashinput+PUBLICKEYBYTES, peer_handshake_key->p, PUBLICKEYBYTES);
if(crypto_auth_hmacsha256_verify(handshake->records[RECORD_T].data, hashinput, 2*PUBLICKEYBYTES, shared_handshake_key) != 0) {
- pr_warn(ctx, "received invalid protocol handshake finish from %P[%I]", peer, address);
+ pr_warn(ctx, "received invalid protocol handshake finish from %P[%I]", peer, remote_addr);
return;
}
- establish(ctx, peer, method, sock, address, false, peer_handshake_key, &handshake_key->public_key, &peer->protocol_config->public_key,
+ establish(ctx, peer, method, sock, local_addr, remote_addr, false, peer_handshake_key, &handshake_key->public_key, &peer->protocol_config->public_key,
&ctx->conf->protocol_config->public_key, &sigma, handshake_key->serial);
}
@@ -636,7 +638,7 @@ static inline fastd_peer_t* add_temporary(fastd_context_t *ctx, fastd_socket_t *
return peer;
}
-static void protocol_handshake_handle(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *address, fastd_peer_t *peer, const fastd_handshake_t *handshake, const fastd_method_t *method) {
+static void protocol_handshake_handle(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, const fastd_handshake_t *handshake, const fastd_method_t *method) {
handshake_key_t *handshake_key;
char *peer_version_name = NULL;
bool temporary_added = false;
@@ -644,23 +646,23 @@ static void protocol_handshake_handle(fastd_context_t *ctx, fastd_socket_t *sock
maintenance(ctx);
if (!has_field(handshake, RECORD_SENDER_KEY, PUBLICKEYBYTES)) {
- pr_debug(ctx, "received handshake without sender key from %I", address);
+ pr_debug(ctx, "received handshake without sender key from %I", remote_addr);
return;
}
- peer = match_sender_key(ctx, sock, address, peer, handshake->records[RECORD_SENDER_KEY].data);
+ peer = match_sender_key(ctx, sock, remote_addr, peer, handshake->records[RECORD_SENDER_KEY].data);
if (!peer) {
switch (errno) {
case EAGAIN:
- pr_debug(ctx, "received handshake from %I, resolving host...", address);
+ pr_debug(ctx, "received handshake from %I, resolving host...", remote_addr);
return;
case EPERM:
- pr_debug(ctx, "ignoring handshake from %I (incorrect source address)", address);
+ pr_debug(ctx, "ignoring handshake from %I (incorrect source address)", remote_addr);
return;
case ENOENT:
- peer = add_temporary(ctx, sock, address, handshake->records[RECORD_SENDER_KEY].data);
+ peer = add_temporary(ctx, sock, remote_addr, handshake->records[RECORD_SENDER_KEY].data);
if (peer) {
temporary_added = true;
break;
@@ -674,65 +676,65 @@ static void protocol_handshake_handle(fastd_context_t *ctx, fastd_socket_t *sock
}
if (fastd_peer_is_temporary(peer) && !temporary_added) {
- if (!fastd_peer_verify_temporary(ctx, peer, sock->bound_addr, address)) {
- pr_debug(ctx, "ignoring handshake from %P[%I] (verification failed)", peer, address);
+ if (!fastd_peer_verify_temporary(ctx, peer, local_addr, remote_addr)) {
+ pr_debug(ctx, "ignoring handshake from %P[%I] (verification failed)", peer, remote_addr);
return;
}
}
if (!fastd_peer_may_connect(ctx, peer)) {
- pr_debug(ctx, "ignoring handshake from %P[%I] because of local constraints", peer, address);
+ pr_debug(ctx, "ignoring handshake from %P[%I] because of local constraints", peer, remote_addr);
return;
}
if (backoff(ctx, peer)) {
- pr_debug(ctx, "received repeated handshakes from %P[%I], ignoring", peer, address);
+ pr_debug(ctx, "received repeated handshakes from %P[%I], ignoring", peer, remote_addr);
return;
}
if (handshake->type > 1 && !has_field(handshake, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES)) {
- pr_debug(ctx, "received handshake reply without receipient key from %P[%I]", peer, address);
+ pr_debug(ctx, "received handshake reply without receipient key from %P[%I]", peer, remote_addr);
return;
}
else if(has_field(handshake, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES)) {
if (memcmp(ctx->conf->protocol_config->public_key.p, handshake->records[RECORD_RECEIPIENT_KEY].data, PUBLICKEYBYTES) != 0) {
- pr_debug(ctx, "received protocol handshake with wrong receipient key from %P[%I]", peer, address);
+ pr_debug(ctx, "received protocol handshake with wrong receipient key from %P[%I]", peer, remote_addr);
return;
}
}
if (!has_field(handshake, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES)) {
- pr_debug(ctx, "received handshake without sender handshake key from %P[%I]", peer, address);
+ pr_debug(ctx, "received handshake without sender handshake key from %P[%I]", peer, remote_addr);
return;
}
if (handshake->type > 1 && !has_field(handshake, RECORD_RECEIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES)) {
- pr_debug(ctx, "received handshake reply without receipient handshake key from %P[%I]", peer, address);
+ pr_debug(ctx, "received handshake reply without receipient handshake key from %P[%I]", peer, remote_addr);
return;
}
if (handshake->type > 1 && !has_field(handshake, RECORD_T, HMACBYTES)) {
- pr_debug(ctx, "received handshake reply without HMAC from %P[%I]", peer, address);
+ pr_debug(ctx, "received handshake reply without HMAC from %P[%I]", peer, remote_addr);
return;
}
switch(handshake->type) {
case 1:
if (timespec_diff(&ctx->now, &peer->last_handshake_response) < ctx->conf->min_handshake_interval*1000
- && fastd_peer_address_equal(address, &peer->last_handshake_response_address)) {
- pr_debug(ctx, "not responding repeated handshake from %P[%I]", peer, address);
+ && fastd_peer_address_equal(remote_addr, &peer->last_handshake_response_address)) {
+ pr_debug(ctx, "not responding repeated handshake from %P[%I]", peer, remote_addr);
return;
}
if (handshake->records[RECORD_VERSION_NAME].data)
peer_version_name = strndup(handshake->records[RECORD_VERSION_NAME].data, handshake->records[RECORD_VERSION_NAME].length);
- pr_verbose(ctx, "received handshake from %P[%I] using fastd %s", peer, address, peer_version_name);
+ pr_verbose(ctx, "received handshake from %P[%I] using fastd %s", peer, remote_addr, peer_version_name);
free(peer_version_name);
peer->last_handshake_response = ctx->now;
- peer->last_handshake_response_address = *address;
- respond_handshake(ctx, sock, address, peer, &ctx->protocol_state->handshake_key, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, handshake, method);
+ peer->last_handshake_response_address = *remote_addr;
+ respond_handshake(ctx, sock, local_addr, remote_addr, peer, &ctx->protocol_state->handshake_key, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, handshake, method);
break;
case 2:
@@ -743,17 +745,17 @@ static void protocol_handshake_handle(fastd_context_t *ctx, fastd_socket_t *sock
handshake_key = &ctx->protocol_state->prev_handshake_key;
}
else {
- pr_debug(ctx, "received handshake response with unexpected receipient handshake key from %P[%I]", peer, address);
+ pr_debug(ctx, "received handshake response with unexpected receipient handshake key from %P[%I]", peer, remote_addr);
return;
}
if (handshake->records[RECORD_VERSION_NAME].data)
peer_version_name = strndup(handshake->records[RECORD_VERSION_NAME].data, handshake->records[RECORD_VERSION_NAME].length);
-
- pr_verbose(ctx, "received handshake response from %P[%I] using fastd %s", peer, address, peer_version_name);
+
+ pr_verbose(ctx, "received handshake response from %P[%I] using fastd %s", peer, remote_addr, peer_version_name);
free(peer_version_name);
- finish_handshake(ctx, sock, address, peer, handshake_key, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, handshake, method);
+ finish_handshake(ctx, sock, local_addr, remote_addr, peer, handshake_key, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, handshake, method);
break;
case 3:
@@ -764,17 +766,17 @@ static void protocol_handshake_handle(fastd_context_t *ctx, fastd_socket_t *sock
handshake_key = &ctx->protocol_state->prev_handshake_key;
}
else {
- pr_debug(ctx, "received handshake response with unexpected receipient handshake key from %P[%I]", peer, address);
+ pr_debug(ctx, "received handshake response with unexpected receipient handshake key from %P[%I]", peer, remote_addr);
return;
}
- pr_debug(ctx, "received handshake finish from %P[%I]", peer, address);
+ pr_debug(ctx, "received handshake finish from %P[%I]", peer, remote_addr);
- handle_finish_handshake(ctx, sock, address, peer, handshake_key, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, handshake, method);
+ handle_finish_handshake(ctx, sock, local_addr, remote_addr, peer, handshake_key, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, handshake, method);
break;
default:
- pr_debug(ctx, "received handshake reply with unknown type %u from %P[%I]", handshake->type, peer, address);
+ pr_debug(ctx, "received handshake reply with unknown type %u from %P[%I]", handshake->type, peer, remote_addr);
}
}
@@ -845,7 +847,7 @@ static void session_send(fastd_context_t *ctx, fastd_peer_t *peer, fastd_buffer_
return;
}
- fastd_send(ctx, peer->sock, &peer->address, send_buffer);
+ fastd_send(ctx, peer->sock, &peer->local_address, &peer->address, send_buffer);
fastd_task_delete_peer_keepalives(ctx, peer);
fastd_task_schedule_keepalive(ctx, peer, ctx->conf->keepalive_interval*1000);