From 87f81d15f29f980375669bb63b91d517c8c63c6d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Jun 2016 23:19:06 +0200 Subject: [PATCH 1/2] respondd: delay replies to multicast packages to avoid flooding the server --- net/respondd/src/respondd.c | 44 ++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/net/respondd/src/respondd.c b/net/respondd/src/respondd.c index e3242da..71f9fcc 100644 --- a/net/respondd/src/respondd.c +++ b/net/respondd/src/respondd.c @@ -48,6 +48,8 @@ #include #include +#define MULTICAST_MAX_DELAY (1*1000*1000) // 1 second + struct provider_list { struct provider_list *next; @@ -320,19 +322,33 @@ static struct json_object * handle_request(char *request, bool *compress) { } } - static void serve(int sock) { char input[256]; + char control[256]; const char *output = NULL; ssize_t input_bytes, output_bytes; struct sockaddr_in6 addr; + struct in6_addr destaddr; + struct cmsghdr *cmsg; socklen_t addrlen = sizeof(addr); bool compress; - input_bytes = recvfrom(sock, input, sizeof(input)-1, 0, (struct sockaddr *)&addr, &addrlen); + struct iovec iv = { + .iov_base = input, + .iov_len = sizeof(input)-1, + }; + struct msghdr mh = { + .msg_name = &addr, + .msg_namelen = sizeof(addr), + .msg_iov = &iv, + .msg_iovlen = 1, + .msg_control = control, + .msg_controllen = sizeof(control), + }; + input_bytes = recvmsg(sock, &mh, 0); if (input_bytes < 0) { - perror("recvfrom failed"); + perror("recvmsg failed"); exit(EXIT_FAILURE); } @@ -342,6 +358,19 @@ static void serve(int sock) { if (!result) return; + // Determine destination address + for (cmsg = CMSG_FIRSTHDR(&mh); cmsg != NULL; cmsg = CMSG_NXTHDR(&mh, cmsg)) + { + // ignore the control headers that don't match what we want + if (cmsg->cmsg_level != IPPROTO_IPV6 || cmsg->cmsg_type != IPV6_PKTINFO) + continue; + struct in6_pktinfo *pi = CMSG_DATA(cmsg); + destaddr = pi->ipi6_addr; + break; + } + // Now "cmsg != NULL" tests whether we found the destination address at all. + const bool is_multicast = (cmsg != NULL) && destaddr.s6_addr[0] == 0xFF; + const char *str = json_object_to_json_string_ext(result, JSON_C_TO_STRING_PLAIN); if (compress) { @@ -361,6 +390,10 @@ static void serve(int sock) { } if (output) { + if (is_multicast) { + // Wait some random amount of time to avoid spamming the multicast sender from all sides at once. + usleep(rand() % MULTICAST_MAX_DELAY); + } if (sendto(sock, output, output_bytes, 0, (struct sockaddr *)&addr, addrlen) < 0) perror("sendto failed"); } @@ -376,6 +409,7 @@ int main(int argc, char **argv) { struct sockaddr_in6 server_addr = {}; struct in6_addr mgroup_addr; + srand(time(NULL)); sock = socket(PF_INET6, SOCK_DGRAM, 0); if (sock < 0) { @@ -387,6 +421,10 @@ int main(int argc, char **argv) { perror("can't set socket to IPv6 only"); exit(EXIT_FAILURE); } + if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one))) { + perror("can't set socket to deliver IPV6_PKTINFO control message"); + exit(EXIT_FAILURE); + } server_addr.sin6_family = AF_INET6; server_addr.sin6_addr = in6addr_any; From 11be23d2e2f6bc55eedc120143383a700f8e9f16 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Jun 2016 08:46:42 +0200 Subject: [PATCH 2/2] use IN6_IS_ADDR_MULTICAST to check for multicast address --- net/respondd/src/respondd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/respondd/src/respondd.c b/net/respondd/src/respondd.c index 71f9fcc..1c3231b 100644 --- a/net/respondd/src/respondd.c +++ b/net/respondd/src/respondd.c @@ -369,7 +369,7 @@ static void serve(int sock) { break; } // Now "cmsg != NULL" tests whether we found the destination address at all. - const bool is_multicast = (cmsg != NULL) && destaddr.s6_addr[0] == 0xFF; + const bool is_multicast = (cmsg != NULL) && IN6_IS_ADDR_MULTICAST(&destaddr); const char *str = json_object_to_json_string_ext(result, JSON_C_TO_STRING_PLAIN);