Refactor of SLPD - moved most of the SLPD related code into slpd.{c,h}

This commit is contained in:
thorkill 2016-05-25 18:23:42 +02:00
parent 299b223bba
commit 11b8eb81b9
6 changed files with 239 additions and 177 deletions

View file

@ -87,6 +87,7 @@ tincd_SOURCES = \
rsa.h \
rsagen.h \
script.c script.h \
slpd.c slpd.h \
splay_tree.c splay_tree.h \
sptps.c sptps.h \
subnet.c subnet.h \

View file

@ -33,6 +33,7 @@
#include "net.h"
#include "netutl.h"
#include "protocol.h"
#include "slpd.h"
#include "subnet.h"
#include "xalloc.h"
@ -250,7 +251,6 @@ static void periodic_handler(void *data) {
nc++;
}
if(nc < 3) {
/* Not enough active connections, try to add one.
Choose a random node, if we don't have a connection to it,
@ -344,6 +344,9 @@ static void periodic_handler(void *data) {
}
}
// call SLPD periodic handler
periodic_slpd_handler();
end:
timeout_set(data, &(struct timeval){5, rand() % 100000});
}

View file

@ -44,6 +44,7 @@
#include "net.h"
#include "netutl.h"
#include "protocol.h"
#include "slpd.h"
#include "route.h"
#include "utils.h"
#include "xalloc.h"
@ -72,7 +73,6 @@ bool udp_discovery = true;
int udp_discovery_keepalive_interval = 10;
int udp_discovery_interval = 2;
int udp_discovery_timeout = 30;
extern int my_slpd_expire;
#define MAX_SEQNO 1073741824
@ -1525,89 +1525,6 @@ skip_harder:
send_mtu_info(myself, n, MTU);
}
static void handle_incoming_slpd_packet(listen_socket_t *ls, void *pkt, struct sockaddr_in6 *addr, size_t datalen) {
int mav, miv, port;
char nodename[MAXSIZE], fng[MAXSIZE];
char addrstr[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &addr->sin6_addr, addrstr, sizeof(addrstr));
int i = sscanf(pkt, "sLPD %d %d %s %d %86s", &mav, &miv, &nodename[0], &port, &fng[0]);
if (i != 5) {
logger(DEBUG_ALWAYS, LOG_ERR, "cant not parse packet... %d from %s", i, addrstr);
return;
}
fng[86] = '\00';
if (mav == 0 && miv <= 2) {
logger(DEBUG_TRAFFIC, LOG_ERR, "Got SLPD packet node:%s port:%d %d.%d <%s> from %s", nodename, port, mav, miv, fng, addrstr);
node_t *n = lookup_node(nodename);
if (!n) {
logger(DEBUG_ALWAYS, LOG_ERR, "unknown node: %s", nodename);
return;
}
if (n->slpd_address != NULL) {
if (now.tv_sec - n->slpd_active_since.tv_sec < my_slpd_expire) {
return;
} else {
logger(DEBUG_STATUS, LOG_INFO, "Expire SLPD for %s", n->name);
free_config(n->slpd_address);
n->slpd_address = NULL;
}
}
if (!n->ecdsa)
node_read_ecdsa_public_key(n);
char sig[64];
memset(&sig, 0x0, 64);
if (miv >= 2) {
if (b64decode(fng, &sig, 86) != 64) {
logger(DEBUG_ALWAYS, LOG_ERR, "b64decode() failed!");
return;
}
if (!ecdsa_verify(n->ecdsa, pkt, datalen-86-1, sig)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Signature verification for SLPD from <%s> failed!", addrstr);
return;
}
}
if (!strncmp(n->name, myself->name, strlen(myself->name))) {
logger(DEBUG_SCARY_THINGS, LOG_NOTICE, "Ignore SLPD for myself: %s", nodename);
return;
}
config_t *cfg = NULL;
if (!n->slpd_address) {
char iface_name[255] = { 0 };
char fullhost[255] = { 0 };
if_indextoname(addr->sin6_scope_id, iface_name);
cfg = new_config();
cfg->variable = xstrdup("Address");
snprintf(fullhost, 254, "%s%%%s %d", addrstr, iface_name, port);
cfg->value = xstrdup(fullhost);
cfg->file = NULL;
cfg->line = -1;
logger(DEBUG_ALWAYS, LOG_ERR, "Discovered %s on %s", nodename , fullhost);
n->slpd_address = cfg;
n->slpd_active_since = now;
n->status.has_address = true;
}
} else {
logger(DEBUG_ALWAYS, LOG_ERR, "Got SLPD packet with wrong version %d.%d", mav, miv);
}
return;
}
void handle_incoming_vpn_data(void *data, int flags) {
listen_socket_t *ls = data;

View file

@ -301,98 +301,6 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
return nfd;
} /* int setup_vpn_in_socket */
int setup_slpd_in_socket() {
int nfd;
char *my_slpd_port;
char *my_slpd_group;
struct addrinfo *res;
struct addrinfo hints;
struct ipv6_mreq group;
logger(DEBUG_ALWAYS, LOG_ERR, "Prepare SLPD mutlicast socket");
if(!get_config_string(lookup_config(config_tree, "SLPDPort"), &my_slpd_port))
my_slpd_port = xstrdup(DEFAULT_SLPD_PORT);
if(!get_config_string(lookup_config(config_tree, "SLPDGroup"), &my_slpd_group))
my_slpd_group = xstrdup(DEFAULT_SLPD_GROUP);
bzero(&hints, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
//hints.ai_flags = AI_PASSIVE;
int status;
if ((status = getaddrinfo(NULL, my_slpd_port, &hints, &res)) != 0 ) {
logger(DEBUG_ALWAYS, LOG_INFO, "getaddrinfo() error: [%s:%d]", strerror(errno), errno);
return -1;
}
nfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if(nfd < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can not create socket for SLPD %s", sockstrerror(sockerrno));
return -1;
}
#ifdef FD_CLOEXEC
fcntl(nfd, F_SETFD, FD_CLOEXEC);
#endif
#ifdef O_NONBLOCK
{
int flags = fcntl(nfd, F_GETFL);
if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
closesocket(nfd);
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "fcntl",
strerror(errno));
return -1;
}
}
#endif
int reuse = 1;
if(setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can not set SO_REUSEADDR for SLPD %s", sockstrerror(sockerrno));
closesocket(nfd);
return -1;
}
if (bind(nfd, res->ai_addr, res->ai_addrlen) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can not bind() socket for SLPD %s", sockstrerror(sockerrno));
closesocket(nfd);
return -1;
}
config_t *c_iface;
c_iface = lookup_config(config_tree, "SLPDInterface");
while(c_iface) {
struct sockaddr_in6 group_addr;
inet_pton(AF_INET6, my_slpd_group, &group_addr.sin6_addr);
group.ipv6mr_multiaddr = group_addr.sin6_addr;
group.ipv6mr_interface = if_nametoindex(c_iface->value);
if (setsockopt(nfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &group, sizeof(group)) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can not join group for SLPD %s", sockstrerror(sockerrno));
closesocket(nfd);
return -1;
}
logger(DEBUG_STATUS, LOG_INFO, "SLPD multicast group joined on %s ready", c_iface->value);
c_iface = lookup_config_next(config_tree, c_iface);
}
logger(DEBUG_STATUS, LOG_INFO, "SLPD socket ready (%d)", nfd);
return nfd;
} /* int setup_slpd_in_socket */
static void retry_outgoing_handler(void *data) {
setup_outgoing_connection(data);
}

204
src/slpd.c Normal file
View file

@ -0,0 +1,204 @@
/*
slpd.c -- Simple Local Peer Discovery
Copyright (C) 2016 Rafal Lesniak
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "slpd.h"
extern int my_slpd_expire;
void periodic_slpd_handler(void) {
// expire SLPD addresses
for splay_each(node_t, n, node_tree) {
if (!n->slpd_address)
continue;
if ((now.tv_sec - n->slpd_active_since.tv_sec) >= my_slpd_expire) {
logger(DEBUG_STATUS, LOG_INFO, "Expire SLPD for %s", n->name);
free_config(n->slpd_address);
n->slpd_address = NULL;
}
}
}
int setup_slpd_in_socket(void) {
int nfd;
char *my_slpd_port;
char *my_slpd_group;
struct addrinfo *res;
struct addrinfo hints;
struct ipv6_mreq group;
logger(DEBUG_ALWAYS, LOG_ERR, "Prepare SLPD mutlicast socket");
if(!get_config_string(lookup_config(config_tree, "SLPDPort"), &my_slpd_port))
my_slpd_port = xstrdup(DEFAULT_SLPD_PORT);
if(!get_config_string(lookup_config(config_tree, "SLPDGroup"), &my_slpd_group))
my_slpd_group = xstrdup(DEFAULT_SLPD_GROUP);
bzero(&hints, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
int status;
if ((status = getaddrinfo(NULL, my_slpd_port, &hints, &res)) != 0 ) {
logger(DEBUG_ALWAYS, LOG_INFO, "getaddrinfo() error: [%s:%d]", strerror(errno), errno);
return -1;
}
nfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if(nfd < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can not create socket for SLPD %s", sockstrerror(sockerrno));
return -1;
}
#ifdef FD_CLOEXEC
fcntl(nfd, F_SETFD, FD_CLOEXEC);
#endif
#ifdef O_NONBLOCK
{
int flags = fcntl(nfd, F_GETFL);
if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
closesocket(nfd);
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "fcntl",
strerror(errno));
return -1;
}
}
#endif
int reuse = 1;
if(setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can not set SO_REUSEADDR for SLPD %s", sockstrerror(sockerrno));
closesocket(nfd);
return -1;
}
if (bind(nfd, res->ai_addr, res->ai_addrlen) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can not bind() socket for SLPD %s", sockstrerror(sockerrno));
closesocket(nfd);
return -1;
}
config_t *c_iface;
c_iface = lookup_config(config_tree, "SLPDInterface");
while(c_iface) {
struct sockaddr_in6 group_addr;
inet_pton(AF_INET6, my_slpd_group, &group_addr.sin6_addr);
group.ipv6mr_multiaddr = group_addr.sin6_addr;
group.ipv6mr_interface = if_nametoindex(c_iface->value);
if (setsockopt(nfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &group, sizeof(group)) < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Can not join group for SLPD %s", sockstrerror(sockerrno));
closesocket(nfd);
return -1;
}
logger(DEBUG_STATUS, LOG_INFO, "SLPD multicast group joined on %s ready", c_iface->value);
c_iface = lookup_config_next(config_tree, c_iface);
}
logger(DEBUG_STATUS, LOG_INFO, "SLPD socket ready (%d)", nfd);
return nfd;
} /* int setup_slpd_in_socket */
void handle_incoming_slpd_packet(listen_socket_t *ls, void *pkt, struct sockaddr_in6 *addr, size_t datalen) {
unsigned int mav, miv, port;
char nodename[MAXSIZE], fng[MAXSIZE];
char addrstr[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &addr->sin6_addr, addrstr, sizeof(addrstr));
int i = sscanf(pkt, "sLPD %d %d %s %d %86s", &mav, &miv, &nodename[0], &port, &fng[0]);
if (i != 5) {
logger(DEBUG_ALWAYS, LOG_ERR, "can not parse packet... %d from %s", i, addrstr);
return;
}
fng[86] = '\00';
if (mav == 0 && miv <= 2) {
logger(DEBUG_TRAFFIC, LOG_ERR, "Got SLPD packet node:%s port:%d %d.%d <%s> from %s", nodename, port, mav, miv, fng, addrstr);
node_t *n = lookup_node(nodename);
if (!n) {
logger(DEBUG_ALWAYS, LOG_ERR, "unknown node: %s", nodename);
return;
}
// Address is still known we do not check if it changed
if (n->slpd_address != NULL)
return;
if (!n->ecdsa)
node_read_ecdsa_public_key(n);
char sig[64];
memset(&sig, 0x0, 64);
if (miv >= 2) {
if (b64decode(fng, &sig, 86) != 64) {
logger(DEBUG_ALWAYS, LOG_ERR, "b64decode() failed!");
return;
}
if (!ecdsa_verify(n->ecdsa, pkt, datalen-86-1, sig)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Signature verification for SLPD from <%s> failed!", addrstr);
return;
}
}
if (!strncmp(n->name, myself->name, strlen(myself->name))) {
logger(DEBUG_SCARY_THINGS, LOG_NOTICE, "Ignore SLPD for myself: %s", nodename);
return;
}
config_t *cfg = NULL;
if (!n->slpd_address) {
char iface_name[255] = { 0 };
char fullhost[255] = { 0 };
if_indextoname(addr->sin6_scope_id, iface_name);
cfg = new_config();
cfg->variable = xstrdup("Address");
snprintf(fullhost, 254, "%s%%%s %d", addrstr, iface_name, port);
cfg->value = xstrdup(fullhost);
cfg->file = NULL;
cfg->line = -1;
logger(DEBUG_ALWAYS, LOG_ERR, "Discovered %s on %s", nodename , fullhost);
n->slpd_address = cfg;
n->slpd_active_since = now;
n->status.has_address = true;
}
} else {
logger(DEBUG_ALWAYS, LOG_ERR, "Got SLPD packet with wrong version %d.%d", mav, miv);
}
return;
}

29
src/slpd.h Normal file
View file

@ -0,0 +1,29 @@
/*
slpd.h -- Simple Local Peer Discovery
Copyright (C) 2016 Rafal Lesniak
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "system.h"
#include "conf.h"
#include "logger.h"
#include "utils.h"
#include "xalloc.h"
void periodic_slpd_handler(void);
int setup_slpd_in_socket(void);
void handle_incoming_slpd_packet(listen_socket_t *, void *, struct sockaddr_in6 *, size_t);