SLPD rewrite for IPv6 - IPv4 has been dropped
After first tests it came out, that RoadWarriors with multiple active Interfaces hat problems with receiving on/ and sending SLPD packets to specific interfaces. Here the solution: - Define SLPDInterface in your tinc.conf (multiple definitions are allowed) On those interfaces tincd will send and receive SLPD packetes - You have to have IPv6 support on - link-local addresses configured - tincd must listen on IPv6 on your SLPDInterfaces - Define SLPDGroup to something like ff02::42:1 - Define SLPDPort for your group - Define SLPDInterval to some sane number of seconds (0 is default, meaning SLPD is disabled, 30 seconds should be enough for average users) SLPDGroup and SLPDPort should be unique for your network. Fingerprinting, message signing is yet to be implemented. Discovered address should also expire periodically.
This commit is contained in:
parent
057ccb8da6
commit
43ed440176
5 changed files with 119 additions and 61 deletions
|
@ -25,7 +25,7 @@
|
|||
#include "splay_tree.h"
|
||||
#include "subnet.h"
|
||||
|
||||
#define DEFAULT_SLPD_GROUP "224.0.42.23"
|
||||
#define DEFAULT_SLPD_GROUP "ff02::42:1"
|
||||
#define DEFAULT_SLPD_PORT "1655"
|
||||
|
||||
typedef struct config_t {
|
||||
|
|
|
@ -217,10 +217,10 @@ extern bool read_ecdsa_public_key(struct connection_t *);
|
|||
extern bool read_rsa_public_key(struct connection_t *);
|
||||
extern void handle_device_data(void *, int);
|
||||
extern void handle_meta_connection_data(struct connection_t *);
|
||||
extern void send_slpd_broadcast(void);
|
||||
extern void send_slpd_broadcast(char *);
|
||||
extern void regenerate_key(void);
|
||||
extern void update_edge_weight(void);
|
||||
extern int setup_slpd_in_socket(void);
|
||||
extern int setup_slpd_in_socket();
|
||||
extern void purge(void);
|
||||
extern void retry(void);
|
||||
extern int reload_configuration(void);
|
||||
|
|
|
@ -1515,20 +1515,23 @@ skip_harder:
|
|||
send_mtu_info(myself, n, MTU);
|
||||
}
|
||||
|
||||
static void handle_incoming_slpd_packet(listen_socket_t *ls, void *pkt, sockaddr_t *addr) {
|
||||
static void handle_incoming_slpd_packet(listen_socket_t *ls, void *pkt, struct sockaddr_in6 *addr) {
|
||||
|
||||
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 %s", &mav, &miv, &nodename[0], &port, &fng[0]);
|
||||
if (i != 5) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "cant not parse packet... %d",i);
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "cant not parse packet... %d from %s", i, addrstr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mav == 0 && miv == 1) {
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR, "Got SLPD packet node:%s port:%d %d.%d <%s> from %s", nodename, port, mav, miv, fng, inet_ntoa(addr->in.sin_addr));
|
||||
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) {
|
||||
|
@ -1543,14 +1546,19 @@ static void handle_incoming_slpd_packet(listen_socket_t *ls, void *pkt, sockaddr
|
|||
|
||||
config_t *cfg = NULL;
|
||||
if (!n->slpd_address) {
|
||||
char iface_name[255];
|
||||
char fullhost[255];
|
||||
|
||||
if_indextoname(addr->sin6_scope_id, &iface_name);
|
||||
|
||||
cfg = new_config();
|
||||
cfg->variable = xstrdup("Address");
|
||||
cfg->value = xstrdup(inet_ntoa(addr->in.sin_addr));
|
||||
snprintf(&fullhost, 254, "%s%%%s", addrstr, iface_name);
|
||||
cfg->value = xstrdup(fullhost);
|
||||
cfg->file = NULL;
|
||||
cfg->line = -1;
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Discovered %s on %s", nodename, inet_ntoa(addr->in.sin_addr));
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Discovered %s on %s", nodename , fullhost);
|
||||
n->slpd_address = cfg;
|
||||
n->status.has_address = true;
|
||||
}
|
||||
|
@ -1625,12 +1633,10 @@ void handle_incoming_slpd_data(void *data, int flags) {
|
|||
listen_socket_t *ls = data;
|
||||
|
||||
char pkt[MAXSIZE];
|
||||
sockaddr_t addr = {};
|
||||
socklen_t addrlen = sizeof addr;
|
||||
struct sockaddr_in6 addr;
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
|
||||
logger(DEBUG_SCARY_THINGS, LOG_INFO, "Receiving SLPD packet");
|
||||
|
||||
size_t len = recvfrom(ls->udp.fd, (void *)&pkt, MAXSIZE, 0, &addr.sa, &addrlen);
|
||||
size_t len = recvfrom(ls->udp.fd, pkt, MAXSIZE, 0, (struct sockaddr *)&addr, &addrlen);
|
||||
|
||||
if(len <= 0 || len > MAXSIZE) {
|
||||
if(!sockwouldblock(sockerrno))
|
||||
|
|
|
@ -319,7 +319,15 @@ static timeout_t edgeupdate_timeout;
|
|||
static timeout_t slpdupdate_timeout;
|
||||
|
||||
static void slpdupdate_handler(void *data) {
|
||||
send_slpd_broadcast();
|
||||
config_t *c_iface;
|
||||
c_iface = lookup_config(config_tree, "SLPDInterface");
|
||||
|
||||
while(c_iface) {
|
||||
logger(DEBUG_STATUS, LOG_NOTICE, "Sending SLPD out on %s", c_iface->value);
|
||||
send_slpd_broadcast(c_iface->value);
|
||||
c_iface = lookup_config_next(config_tree, c_iface);
|
||||
}
|
||||
|
||||
timeout_set(data, &(struct timeval){slpdinterval + (rand() % 10), rand() % 100000});
|
||||
}
|
||||
|
||||
|
@ -333,50 +341,72 @@ static void edgeupdate_handler(void *data) {
|
|||
timeout_set(data, &(struct timeval){edgeupdateinterval + (rand() % 10), rand() % 100000});
|
||||
}
|
||||
|
||||
void send_slpd_broadcast(void) {
|
||||
void send_slpd_broadcast(char *iface) {
|
||||
int sd;
|
||||
struct sockaddr_in address;
|
||||
char slpd_msg[MAXSIZE] = "";
|
||||
char *iface;
|
||||
struct in_addr lif;
|
||||
struct ifreq ifr;
|
||||
int fd;
|
||||
struct addrinfo *mcast_addr;
|
||||
struct addrinfo hints;
|
||||
sockaddr_t r;
|
||||
|
||||
sd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (sd < 0) {
|
||||
char slpd_msg[MAXSIZE] = "";
|
||||
|
||||
/* Check if interface is up */
|
||||
struct ifreq ifr;
|
||||
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strcpy(ifr.ifr_name, iface);
|
||||
if (ioctl(sd, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "ioctl() on %s error: [%s:%d]", iface, strerror(errno), errno);
|
||||
}
|
||||
close(sd);
|
||||
// Requested interface is down
|
||||
if (!(ifr.ifr_flags & IFF_UP) || !(ifr.ifr_flags & IFF_RUNNING))
|
||||
return;
|
||||
|
||||
bzero(&hints, sizeof(hints));
|
||||
hints.ai_family = AF_INET6;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME;
|
||||
|
||||
int status;
|
||||
if ((status = getaddrinfo(my_slpd_group, my_slpd_port, &hints, &mcast_addr)) != 0 ) {
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "getaddrinfo() error: [%s:%d]", strerror(errno), errno);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((sd = socket(mcast_addr->ai_family, mcast_addr->ai_socktype, 0)) < 0 ) {
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "socket() error: [%s:%d]", strerror(errno), errno);
|
||||
freeaddrinfo(&mcast_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
int on = 1;
|
||||
if (setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "setsockopt() IPV6_V6ONLY failed [%s:%d]", strerror(errno), errno);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Send SLPD only on this Interface */
|
||||
if(get_config_string (lookup_config (config_tree, "SLPDInterface"), &iface)) {
|
||||
fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
strncpy(ifr.ifr_name, iface, IFNAMSIZ-1);
|
||||
ioctl(fd, SIOCGIFADDR, &ifr);
|
||||
close(fd);
|
||||
|
||||
/* display result */
|
||||
logger(DEBUG_SCARY_THINGS, LOG_ERR, "%s has the ip: %s\n", iface,
|
||||
inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
|
||||
|
||||
lif.s_addr = inet_addr(inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
|
||||
if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, (char *)&lif, sizeof(lif)) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "can not bind multicast to %s\n", iface);
|
||||
return;
|
||||
}
|
||||
unsigned int ifindex;
|
||||
ifindex = if_nametoindex(iface);
|
||||
if(setsockopt (sd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) != 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "setsockopt() IPV6_MULTICAST_IF failed [%s:%d]", strerror(errno), errno);
|
||||
freeaddrinfo(&mcast_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
memset (&address, 0, sizeof (address));
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = inet_addr (DEFAULT_SLPD_GROUP);
|
||||
address.sin_port = htons(atoi(my_slpd_port));
|
||||
unsigned int reuse = 1;
|
||||
if(setsockopt (sd, IPPROTO_IPV6, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) != 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "setsockopt() SO_REUSEADDR failed: [%s:%d]", strerror(errno), errno);
|
||||
freeaddrinfo(&mcast_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(slpd_msg, MAXSIZE, "sLPD 0 1 %s %d none ", myname, atoi(myport));
|
||||
slpd_msg[MAXSIZE-1] = '\00';
|
||||
//ecdsa_sign(myself->sptps.mykey, msg, strlen(msg), sig);
|
||||
|
||||
if (sendto( sd, slpd_msg, strlen(slpd_msg), 0, (struct sockaddr *) &address, sizeof (address)) < 0) {
|
||||
if (sendto(sd, slpd_msg, strlen(slpd_msg), 0, mcast_addr->ai_addr, mcast_addr->ai_addrlen) != strlen(slpd_msg) ) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "SLPD send() error: [%s:%d]", strerror(errno), errno);
|
||||
}
|
||||
close(sd);
|
||||
|
@ -1136,6 +1166,7 @@ static bool setup_myself(void) {
|
|||
int slpd_fd = setup_slpd_in_socket();
|
||||
if (slpd_fd < 0) {
|
||||
close(slpd_fd);
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Listening on multicast group failed");
|
||||
} else {
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Listening on multicast group");
|
||||
io_add(&listen_socket[listen_sockets].udp, handle_incoming_slpd_data, &listen_socket[listen_sockets], slpd_fd, IO_READ);
|
||||
|
|
|
@ -302,13 +302,17 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
|
|||
} /* int setup_vpn_in_socket */
|
||||
|
||||
|
||||
int setup_slpd_in_socket(void) {
|
||||
int setup_slpd_in_socket() {
|
||||
int nfd;
|
||||
char *my_slpd_port;
|
||||
char *my_slpd_group;
|
||||
struct sockaddr_in lsock;
|
||||
struct ip_mreq group;
|
||||
struct ip_mreq mreq;
|
||||
|
||||
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);
|
||||
|
@ -316,7 +320,19 @@ int setup_slpd_in_socket(void) {
|
|||
if(!get_config_string(lookup_config(config_tree, "SLPDGroup"), &my_slpd_group))
|
||||
my_slpd_group = xstrdup(DEFAULT_SLPD_GROUP);
|
||||
|
||||
nfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
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));
|
||||
|
@ -347,24 +363,29 @@ int setup_slpd_in_socket(void) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
memset((char *) &lsock, 0, sizeof(lsock));
|
||||
lsock.sin_family = AF_INET;
|
||||
lsock.sin_port = htons(atoi(my_slpd_port));
|
||||
lsock.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
if(bind(nfd, (struct sockaddr*)&lsock, sizeof(lsock)) < 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
group.imr_multiaddr.s_addr = inet_addr(my_slpd_group);
|
||||
group.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
config_t *c_iface;
|
||||
c_iface = lookup_config(config_tree, "SLPDInterface");
|
||||
|
||||
if(setsockopt(nfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can not join group for SLPD %s", sockstrerror(sockerrno));
|
||||
closesocket(nfd);
|
||||
return -1;
|
||||
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 (%d)", c_iface->value);
|
||||
c_iface = lookup_config_next(config_tree, c_iface);
|
||||
}
|
||||
|
||||
logger(DEBUG_STATUS, LOG_INFO, "SLPD socket ready (%d)", nfd);
|
||||
|
|
Loading…
Reference in a new issue