diff --git a/src/conf.h b/src/conf.h index f152bb35..dba795e1 100644 --- a/src/conf.h +++ b/src/conf.h @@ -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 { diff --git a/src/net.h b/src/net.h index 1e77d3d2..5d00b542 100644 --- a/src/net.h +++ b/src/net.h @@ -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); diff --git a/src/net_packet.c b/src/net_packet.c index c6d2e0dd..2ceff909 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -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)) diff --git a/src/net_setup.c b/src/net_setup.c index 91bd029e..4affdb94 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -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); diff --git a/src/net_socket.c b/src/net_socket.c index ed152ee3..50297d65 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -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);