Refactor of SLPD - moved most of the SLPD related code into slpd.{c,h}
This commit is contained in:
parent
299b223bba
commit
11b8eb81b9
6 changed files with 239 additions and 177 deletions
|
@ -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 \
|
||||
|
|
|
@ -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});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
204
src/slpd.c
Normal 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
29
src/slpd.h
Normal 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);
|
Loading…
Reference in a new issue