]> git.meshlink.io Git - meshlink/blob - src/discovery.c
31dc63b616ad73682f0a2a2452a8a545ada96b7a
[meshlink] / src / discovery.c
1 #define __APPLE_USE_RFC_3542
2 #include "system.h"
3
4 #if defined(__APPLE__) || defined(__unix) && !defined(__linux)
5 #include <net/if.h>
6 #include <net/route.h>
7 #include <netinet/in.h>
8 #elif defined(__linux)
9 #include <asm/types.h>
10 #include <net/if.h>
11 #include <linux/if_link.h>
12 #include <linux/netlink.h>
13 #include <linux/rtnetlink.h>
14 #endif
15
16 #include "mdns.h"
17 #include "meshlink_internal.h"
18 #include "event.h"
19 #include "discovery.h"
20 #include "sockaddr.h"
21 #include "logger.h"
22 #include "netutl.h"
23 #include "node.h"
24 #include "connection.h"
25 #include "utils.h"
26 #include "xalloc.h"
27
28 #define MESHLINK_MDNS_SERVICE_TYPE "_%s._tcp"
29 #define MESHLINK_MDNS_NAME_KEY "name"
30 #define MESHLINK_MDNS_FINGERPRINT_KEY "fingerprint"
31
32 #ifndef MSG_NOSIGNAL
33 #define MSG_NOSIGNAL 0
34 #endif
35
36 #ifndef IPV6_ADD_MEMBERSHIP
37 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
38 #endif
39
40 #ifndef IPV6_DROP_MEMBERSHIP
41 #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
42 #endif
43
44 static const sockaddr_t mdns_address_ipv4 = {
45         .in.sin_family = AF_INET,
46         .in.sin_addr.s_addr = 0xfb0000e0,
47         .in.sin_port = 0xe914,
48 };
49
50 static const sockaddr_t mdns_address_ipv6 = {
51         .in6.sin6_family = AF_INET6,
52         .in6.sin6_addr.s6_addr[0x0] = 0xfd,
53         .in6.sin6_addr.s6_addr[0x1] = 0x02,
54         .in6.sin6_addr.s6_addr[0xf] = 0xfb,
55         .in6.sin6_port = 0xe914,
56 };
57
58 typedef struct discovery_address {
59         int index;
60         bool up;
61         sockaddr_t address;
62 } discovery_address_t;
63
64 static int iface_compare(const void *va, const void *vb) {
65         const int *a = va;
66         const int *b = vb;
67         return *a - *b;
68 }
69
70 static int address_compare(const void *va, const void *vb) {
71         const discovery_address_t *a = va;
72         const discovery_address_t *b = vb;
73
74         if(a->index != b->index) {
75                 return a->index - b->index;
76         }
77
78         return sockaddrcmp_noport(&a->address, &b->address);
79 }
80
81 static void send_mdns_packet_ipv4(meshlink_handle_t *mesh, int fd, int index, const sockaddr_t *src, const sockaddr_t *dest, void *data, size_t len) {
82 #ifdef IP_PKTINFO
83         struct iovec iov  = {
84                 .iov_base = data,
85                 .iov_len = len,
86         };
87
88         struct in_pktinfo pkti = {
89                 .ipi_ifindex = index,
90                 .ipi_addr = src->in.sin_addr,
91         };
92
93         union {
94                 char buf[CMSG_SPACE(sizeof(pkti))];
95                 struct cmsghdr align;
96         } u;
97
98         struct msghdr msg = {
99                 .msg_name = (struct sockaddr *) &dest->sa,
100                 .msg_namelen = SALEN(dest->sa),
101                 .msg_iov = &iov,
102                 .msg_iovlen = 1,
103                 .msg_control = u.buf,
104                 .msg_controllen = sizeof(u.buf),
105         };
106
107
108         struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
109         cmsg->cmsg_level = IPPROTO_IP;
110         cmsg->cmsg_type = IP_PKTINFO;
111         cmsg->cmsg_len = CMSG_LEN(sizeof(pkti));
112         memcpy(CMSG_DATA(cmsg), &pkti, sizeof(pkti));
113
114         // Send the packet
115         ssize_t result = sendmsg(fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL);
116 #else
117         (void)index;
118         (void)src;
119
120         // Send the packet
121         ssize_t result = sendto(fd, data, len, MSG_DONTWAIT | MSG_NOSIGNAL, &dest->sa, SALEN(dest->sa));
122 #endif
123
124         if(result <= 0) {
125                 logger(mesh, MESHLINK_ERROR, "Error sending multicast packet: %s", strerror(errno));
126         }
127 }
128
129 static void send_mdns_packet_ipv6(meshlink_handle_t *mesh, int fd, int index, const sockaddr_t *src, const sockaddr_t *dest, void *data, size_t len) {
130 #ifdef IPV6_PKTINFO
131         struct iovec iov  = {
132                 .iov_base = data,
133                 .iov_len = len,
134         };
135
136         struct in6_pktinfo pkti = {
137                 .ipi6_ifindex = index,
138                 .ipi6_addr = src->in6.sin6_addr,
139         };
140
141         union {
142                 char buf[CMSG_SPACE(sizeof(pkti))];
143                 struct cmsghdr align;
144         } u;
145
146         memset(&u, 0, sizeof u);
147
148         struct msghdr msg = {
149                 .msg_name = (struct sockaddr *) &dest->sa,
150                 .msg_namelen = SALEN(dest->sa),
151                 .msg_iov = &iov,
152                 .msg_iovlen = 1,
153                 .msg_control = u.buf,
154                 .msg_controllen = CMSG_LEN(sizeof(pkti)),
155         };
156
157         struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
158         cmsg->cmsg_level = IPPROTO_IPV6;
159         cmsg->cmsg_type = IPV6_PKTINFO;
160         cmsg->cmsg_len = CMSG_LEN(sizeof(pkti));
161         memcpy(CMSG_DATA(cmsg), &pkti, sizeof(pkti));
162
163         // Send the packet
164         ssize_t result = sendmsg(fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL);
165 #else
166         (void)index;
167         (void)src;
168
169         // Send the packet
170         ssize_t result = sendto(fd, data, len, MSG_DONTWAIT | MSG_NOSIGNAL, &dest->sa, SALEN(dest->sa));
171 #endif
172
173         if(result <= 0) {
174                 logger(mesh, MESHLINK_ERROR, "Error sending multicast packet: %s", strerror(errno));
175         }
176 }
177
178 static void send_mdns_packet(meshlink_handle_t *mesh, const discovery_address_t *addr) {
179         // Configure the socket to send the packet to the right interface
180         int fd;
181         uint8_t request[1024], response[1024];
182         char *fingerprint = meshlink_get_fingerprint(mesh, (meshlink_node_t *)mesh->self);
183         const char *keys[] = {MESHLINK_MDNS_NAME_KEY, MESHLINK_MDNS_FINGERPRINT_KEY};
184         const char *values[] = {mesh->name, fingerprint};
185         size_t request_size = prepare_request(request, sizeof request, mesh->appname, "tcp");
186         size_t response_size = prepare_response(response, sizeof response, fingerprint, mesh->appname, "tcp", atoi(mesh->myport), 2, keys, values);
187         free(fingerprint);
188
189         switch(addr->address.sa.sa_family) {
190         case AF_INET:
191                 fd = mesh->discovery.sockets[0].fd;
192 #ifdef IP_MULTICAST_IF
193                 {
194                         struct ip_mreqn mreq = {
195                                 .imr_address = addr->address.in.sin_addr,
196                                 .imr_ifindex = addr->index,
197                         };
198
199                         if(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq)) != 0) {
200                                 logger(mesh, MESHLINK_ERROR, "Could not set outgoing multicast interface on IPv4 socket");
201                                 return;
202                         }
203                 }
204
205 #endif
206
207                 send_mdns_packet_ipv4(mesh, fd, addr->index, &addr->address, &mdns_address_ipv4, request, request_size);
208                 send_mdns_packet_ipv4(mesh, fd, addr->index, &addr->address, &mdns_address_ipv4, response, response_size);
209                 break;
210
211         case AF_INET6:
212                 fd = mesh->discovery.sockets[1].fd;
213 #ifdef IPV6_MULTICAST_IF
214
215                 if(setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &addr->index, sizeof(addr->index)) != 0) {
216                         logger(mesh, MESHLINK_ERROR, "Could not set outgoing multicast interface on IPv6 socket");
217                         return;
218                 }
219
220 #endif
221
222                 send_mdns_packet_ipv6(mesh, fd, addr->index, &addr->address, &mdns_address_ipv6, request, request_size);
223                 send_mdns_packet_ipv6(mesh, fd, addr->index, &addr->address, &mdns_address_ipv6, response, response_size);
224                 break;
225
226         default:
227                 break;
228         }
229 }
230
231 static void mdns_io_handler(event_loop_t *loop, void *data, int flags) {
232         (void)flags;
233         meshlink_handle_t *mesh = loop->data;
234         io_t *io = data;
235         uint8_t buf[1024];
236         sockaddr_t sa;
237         socklen_t sl = sizeof(sa);
238
239         ssize_t len = recvfrom(io->fd, buf, sizeof(buf), MSG_DONTWAIT, &sa.sa, &sl);
240
241         if(len == -1) {
242                 if(!sockwouldblock(errno)) {
243                         logger(mesh, MESHLINK_ERROR, "Error reading from mDNS discovery socket: %s", strerror(errno));
244                         io_set(loop, io, 0);
245                 }
246
247                 return;
248         }
249
250         char *name = NULL;
251         uint16_t port = 0;
252         const char *keys[2] = {MESHLINK_MDNS_NAME_KEY, MESHLINK_MDNS_FINGERPRINT_KEY};
253         char *values[2] = {NULL, NULL};
254
255         if(parse_response(buf, len, &name, mesh->appname, "tcp", &port, 2, keys, values)) {
256                 node_t *n = (node_t *)meshlink_get_node(mesh, values[0]);
257
258                 if(n) {
259                         if(n != mesh->self) {
260                                 logger(mesh, MESHLINK_INFO, "Node %s discovered on the local network.\n", n->name);
261                         }
262
263                         switch(sa.sa.sa_family) {
264                         case AF_INET:
265                                 sa.in.sin_port = htons(port);
266                                 break;
267
268                         case AF_INET6:
269                                 sa.in6.sin6_port = htons(port);
270                                 break;
271
272                         default:
273                                 logger(mesh, MESHLINK_WARNING, "Could not resolve node %s to a known address family type.\n", n->name);
274                                 sa.sa.sa_family = AF_UNKNOWN;
275                                 break;
276                         }
277
278                         if(sa.sa.sa_family != AF_UNKNOWN) {
279                                 n->catta_address = sa;
280                                 n->last_connect_try = 0;
281                                 node_add_recent_address(mesh, n, &sa);
282
283                                 if(n->connection) {
284                                         n->connection->last_ping_time = -3600;
285                                 }
286
287                                 for list_each(outgoing_t, outgoing, mesh->outgoings) {
288                                         if(outgoing->node != n) {
289                                                 continue;
290                                         }
291
292                                         outgoing->timeout = 0;
293
294                                         if(outgoing->ev.cb) {
295                                                 timeout_set(&mesh->loop, &outgoing->ev, &(struct timespec) {
296                                                         0, 0
297                                                 });
298                                         }
299                                 }
300                         }
301                 }
302         } else if(parse_request(buf, len, mesh->appname, "tcp")) {
303                 // Send a unicast response back
304                 char *fingerprint = meshlink_get_fingerprint(mesh, (meshlink_node_t *)mesh->self);
305                 const char *response_values[] = {mesh->name, fingerprint};
306                 size_t size = prepare_response(buf, sizeof(buf), fingerprint, mesh->appname, "tcp", atoi(mesh->myport), 2, keys, response_values);
307                 sendto(io->fd, buf, size, MSG_DONTWAIT | MSG_NOSIGNAL, &sa.sa, sl);
308                 free(fingerprint);
309         }
310
311         free(name);
312
313         for(int i = 0; i < 2; i++) {
314                 free(values[i]);
315         }
316 }
317
318 static void iface_up(meshlink_handle_t *mesh, int index) {
319         int *p = bsearch(&index, mesh->discovery.ifaces, mesh->discovery.iface_count, sizeof(*p), iface_compare);
320
321         if(p) {
322                 return;
323         }
324
325         mesh->discovery.ifaces = xrealloc(mesh->discovery.ifaces, ++mesh->discovery.iface_count * sizeof(*p));
326         mesh->discovery.ifaces[mesh->discovery.iface_count - 1] = index;
327         qsort(mesh->discovery.ifaces, mesh->discovery.iface_count, sizeof(*p), iface_compare);
328
329         // Add multicast membership
330         struct ip_mreqn mreq4 = {
331                 .imr_multiaddr = mdns_address_ipv4.in.sin_addr,
332                 .imr_ifindex = index,
333         };
334         setsockopt(mesh->discovery.sockets[0].fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq4, sizeof(mreq4));
335         setsockopt(mesh->discovery.sockets[0].fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq4, sizeof(mreq4));
336
337         struct ipv6_mreq mreq6 = {
338                 .ipv6mr_multiaddr = mdns_address_ipv6.in6.sin6_addr,
339                 .ipv6mr_interface = index,
340         };
341         setsockopt(mesh->discovery.sockets[1].fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6));
342         setsockopt(mesh->discovery.sockets[1].fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6));
343
344         // Send an announcement for all addresses associated with this interface
345         for(int i = 0; i < mesh->discovery.address_count; i++) {
346                 if(mesh->discovery.addresses[i].index == index) {
347                         send_mdns_packet(mesh, &mesh->discovery.addresses[i]);
348                 }
349         }
350
351         handle_network_change(mesh, true);
352 }
353
354 static void iface_down(meshlink_handle_t *const mesh, int index) {
355         int *p = bsearch(&index, mesh->discovery.ifaces, mesh->discovery.iface_count, sizeof(*p), iface_compare);
356
357         if(!p) {
358                 return;
359         }
360
361         // Drop multicast membership
362         struct ip_mreqn mreq4 = {
363                 .imr_multiaddr = mdns_address_ipv4.in.sin_addr,
364                 .imr_ifindex = index,
365         };
366         setsockopt(mesh->discovery.sockets[0].fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq4, sizeof(mreq4));
367
368         struct ipv6_mreq mreq6 = {
369                 .ipv6mr_multiaddr = mdns_address_ipv6.in6.sin6_addr,
370                 .ipv6mr_interface = index,
371         };
372         setsockopt(mesh->discovery.sockets[1].fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6));
373
374         memmove(p, p + 1, (mesh->discovery.ifaces + --mesh->discovery.iface_count - p) * sizeof(*p));
375
376         handle_network_change(mesh, mesh->discovery.iface_count);
377 }
378
379 static void addr_add(meshlink_handle_t *mesh, const discovery_address_t *addr) {
380         discovery_address_t *p = bsearch(addr, mesh->discovery.addresses, mesh->discovery.address_count, sizeof(*p), address_compare);
381
382         if(p) {
383                 return;
384         }
385
386         bool up = bsearch(&addr->index, mesh->discovery.ifaces, mesh->discovery.iface_count, sizeof(int), iface_compare);
387
388         mesh->discovery.addresses = xrealloc(mesh->discovery.addresses, ++mesh->discovery.address_count * sizeof(*p));
389         mesh->discovery.addresses[mesh->discovery.address_count - 1] = *addr;
390         mesh->discovery.addresses[mesh->discovery.address_count - 1].up = up;
391
392         if(up) {
393                 send_mdns_packet(mesh, &mesh->discovery.addresses[mesh->discovery.address_count - 1]);
394         }
395
396         qsort(mesh->discovery.addresses, mesh->discovery.address_count, sizeof(*p), address_compare);
397 }
398
399 static void addr_del(meshlink_handle_t *mesh, const discovery_address_t *addr) {
400         discovery_address_t *p = bsearch(addr, mesh->discovery.addresses, mesh->discovery.address_count, sizeof(*p), address_compare);
401
402         if(!p) {
403                 return;
404         }
405
406         memmove(p, p + 1, (mesh->discovery.addresses + --mesh->discovery.address_count - p) * sizeof(*p));
407 }
408
409 #if defined(__linux)
410 static void netlink_getlink(int fd) {
411         static const struct {
412                 struct nlmsghdr nlm;
413                 struct ifinfomsg ifi;
414         } msg = {
415                 .nlm.nlmsg_len = NLMSG_LENGTH(sizeof(msg.ifi)),
416                 .nlm.nlmsg_type = RTM_GETLINK,
417                 .nlm.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
418                 .nlm.nlmsg_seq = 1,
419                 .ifi.ifi_family = AF_UNSPEC,
420         };
421         send(fd, &msg, msg.nlm.nlmsg_len, 0);
422 }
423
424 static void netlink_getaddr(int fd) {
425         static const struct {
426                 struct nlmsghdr nlm;
427                 struct ifaddrmsg ifa;
428         } msg = {
429                 .nlm.nlmsg_len = NLMSG_LENGTH(sizeof(msg.ifa)),
430                 .nlm.nlmsg_type = RTM_GETADDR,
431                 .nlm.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
432                 .nlm.nlmsg_seq = 2,
433                 .ifa.ifa_family = AF_UNSPEC,
434         };
435         send(fd, &msg, msg.nlm.nlmsg_len, 0);
436 }
437
438 static void netlink_parse_link(meshlink_handle_t *mesh, const struct nlmsghdr *nlm) {
439         const struct ifinfomsg *ifi = (const struct ifinfomsg *)(nlm + 1);
440
441         if(ifi->ifi_flags & IFF_UP && ifi->ifi_flags & IFF_MULTICAST) {
442                 iface_up(mesh, ifi->ifi_index);
443         } else {
444                 iface_down(mesh, ifi->ifi_index);
445         }
446 }
447
448 static void netlink_parse_addr(meshlink_handle_t *mesh, const struct nlmsghdr *nlm) {
449         const struct ifaddrmsg *ifa = (const struct ifaddrmsg *)(nlm + 1);
450         const uint8_t *ptr = (const uint8_t *)(ifa + 1);
451         size_t len = nlm->nlmsg_len - (ptr - (const uint8_t *)nlm);
452
453         while(len >= sizeof(struct rtattr)) {
454                 const struct rtattr *rta = (const struct rtattr *)ptr;
455
456                 if(rta->rta_len <= 0 || rta->rta_len > len) {
457                         break;
458                 }
459
460                 if(rta->rta_type == IFA_ADDRESS) {
461                         discovery_address_t addr  = {
462                                 .index = ifa->ifa_index,
463                         };
464
465                         if(rta->rta_len == 8) {
466                                 addr.address.sa.sa_family = AF_INET;
467                                 memcpy(&addr.address.in.sin_addr, ptr + 4, 4);
468                                 addr.address.in.sin_port = ntohs(5353);
469                         } else if(rta->rta_len == 20) {
470                                 addr.address.sa.sa_family = AF_INET6;
471                                 memcpy(&addr.address.in6.sin6_addr, ptr + 4, 16);
472                                 addr.address.in6.sin6_port = ntohs(5353);
473                                 addr.address.in6.sin6_scope_id = ifa->ifa_index;
474                         } else {
475                                 addr.address.sa.sa_family = AF_UNKNOWN;
476                         }
477
478                         if(addr.address.sa.sa_family != AF_UNKNOWN) {
479                                 if(nlm->nlmsg_type == RTM_NEWADDR) {
480                                         addr_add(mesh, &addr);
481                                 } else {
482                                         addr_del(mesh, &addr);
483                                 }
484                         }
485                 }
486
487                 unsigned short rta_len = (rta->rta_len + 3) & ~3;
488                 ptr += rta_len;
489                 len -= rta_len;
490         }
491 }
492
493 static void netlink_parse(meshlink_handle_t *mesh, const void *data, size_t len) {
494         const uint8_t *ptr = data;
495
496         while(len >= sizeof(struct nlmsghdr)) {
497                 const struct nlmsghdr *nlm = (const struct nlmsghdr *)ptr;
498
499                 if(nlm->nlmsg_len > len) {
500                         break;
501                 }
502
503                 switch(nlm->nlmsg_type) {
504                 case RTM_NEWLINK:
505                 case RTM_DELLINK:
506                         netlink_parse_link(mesh, nlm);
507                         break;
508
509                 case RTM_NEWADDR:
510                 case RTM_DELADDR:
511                         netlink_parse_addr(mesh, nlm);
512                 }
513
514                 ptr += nlm->nlmsg_len;
515                 len -= nlm->nlmsg_len;
516         }
517 }
518
519 static void netlink_io_handler(event_loop_t *loop, void *data, int flags) {
520         (void)flags;
521         (void)data;
522         static time_t prev_update;
523         meshlink_handle_t *mesh = loop->data;
524
525         struct {
526                 struct nlmsghdr nlm;
527                 char data[16384];
528         } msg;
529
530         while(true) {
531                 ssize_t result = recv(mesh->discovery.pfroute_io.fd, &msg, sizeof(msg), MSG_DONTWAIT);
532
533                 if(result <= 0) {
534                         if(result == 0 || errno == EAGAIN || errno == EINTR) {
535                                 break;
536                         }
537
538                         logger(mesh, MESHLINK_ERROR, "Reading from Netlink socket failed: %s\n", strerror(errno));
539                         io_set(loop, &mesh->discovery.pfroute_io, 0);
540                 }
541
542                 if((size_t)result < sizeof(msg.nlm)) {
543                         logger(mesh, MESHLINK_ERROR, "Invalid Netlink message\n");
544                         break;
545                 }
546
547                 if(msg.nlm.nlmsg_type == NLMSG_DONE) {
548                         if(msg.nlm.nlmsg_seq == 1) {
549                                 // We just got the result of GETLINK, now send GETADDR.
550                                 netlink_getaddr(mesh->discovery.pfroute_io.fd);
551                         }
552                 } else {
553                         netlink_parse(mesh, &msg, result);
554
555                         if(loop->now.tv_sec > prev_update + 5) {
556                                 prev_update = loop->now.tv_sec;
557                                 handle_network_change(mesh, 1);
558                         }
559                 }
560         }
561 }
562 #elif defined(RTM_NEWADDR)
563 static void pfroute_parse_iface(meshlink_handle_t *mesh, const struct rt_msghdr *rtm) {
564         const struct if_msghdr *ifm = (const struct if_msghdr *)rtm;
565
566         if(ifm->ifm_flags & IFF_UP && ifm->ifm_flags & IFF_MULTICAST && !(ifm->ifm_flags & IFF_LOOPBACK)) {
567                 iface_up(mesh, ifm->ifm_index);
568         } else {
569                 iface_down(mesh, ifm->ifm_index);
570         }
571 }
572
573 static void pfroute_parse_addr(meshlink_handle_t *mesh, const struct rt_msghdr *rtm) {
574         const struct ifa_msghdr *ifam = (const struct ifa_msghdr *)rtm;
575         const char *p = (const char *)(ifam + 1);
576
577         for(unsigned int i = 1; i; i <<= 1) {
578                 if(!(ifam->ifam_addrs & i)) {
579                         continue;
580                 }
581
582                 const sockaddr_t *sa = (const sockaddr_t *)p;
583
584                 if(i == RTA_IFA) {
585                         discovery_address_t addr = {
586                                 .index = ifam->ifam_index,
587                         };
588
589                         if(sa->sa.sa_family == AF_INET) {
590                                 addr.address.in = sa->in;
591                                 addr.address.in.sin_port = ntohs(5353);
592                         } else if(sa->sa.sa_family == AF_INET6) {
593                                 addr.address.in6 = sa->in6;
594                                 addr.address.in6.sin6_port = ntohs(5353);
595                         } else {
596                                 addr.address.sa.sa_family = AF_UNKNOWN;
597                         }
598
599                         if(addr.address.sa.sa_family != AF_UNKNOWN) {
600                                 if(ifam->ifam_type == RTM_NEWADDR) {
601                                         addr_add(mesh, &addr);
602                                 } else {
603                                         addr_del(mesh, &addr);
604                                 }
605                         }
606
607                         break;
608                 }
609
610                 size_t len = (sa->sa.sa_len + 3) & ~3;
611                 p += len;
612         }
613 }
614
615 static void pfroute_io_handler(event_loop_t *loop, void *data, int flags) {
616         (void)flags;
617         (void)data;
618         meshlink_handle_t *mesh = loop->data;
619
620         struct {
621                 struct rt_msghdr rtm;
622                 char data[2048];
623         } msg;
624
625         while(true) {
626                 msg.rtm.rtm_version = 0;
627                 ssize_t result = recv(mesh->discovery.pfroute_io.fd, &msg, sizeof(msg), MSG_DONTWAIT);
628
629                 if(result <= 0) {
630                         if(result == 0 || errno == EAGAIN || errno == EINTR) {
631                                 break;
632                         }
633
634                         logger(mesh, MESHLINK_ERROR, "Reading from PFROUTE socket failed: %s\n", strerror(errno));
635                         io_set(loop, &mesh->discovery.pfroute_io, 0);
636                 }
637
638                 if(msg.rtm.rtm_version != RTM_VERSION) {
639                         logger(mesh, MESHLINK_ERROR, "Invalid PFROUTE message version\n");
640                         break;
641                 }
642
643                 switch(msg.rtm.rtm_type) {
644                 case RTM_IFINFO:
645                         pfroute_parse_iface(mesh, &msg.rtm);
646                         break;
647
648                 case RTM_NEWADDR:
649                 case RTM_DELADDR:
650                         pfroute_parse_addr(mesh, &msg.rtm);
651                         break;
652
653                 default:
654                         break;
655                 }
656         }
657 }
658 #endif
659
660 bool discovery_start(meshlink_handle_t *mesh) {
661         logger(mesh, MESHLINK_DEBUG, "discovery_start called\n");
662
663         assert(mesh);
664
665         // Set up multicast sockets for mDNS
666         static const int one = 1;
667         static const int ttl = 255;
668         static const uint8_t one8 = 1;
669         static const uint8_t ttl8 = 255;
670
671         int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
672
673         if(fd == -1) {
674                 logger(mesh, MESHLINK_ERROR, "Error creating IPv4 socket: %s", strerror(errno));
675         }
676
677         sockaddr_t sa4 = {
678                 .in.sin_family = AF_INET,
679                 .in.sin_port = ntohs(5353),
680         };
681         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
682         setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
683         setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one8, sizeof(one8));
684         setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl8, sizeof(ttl8));
685
686         if(bind(fd, &sa4.sa, SALEN(sa4.sa)) == -1) {
687                 logger(mesh, MESHLINK_ERROR, "Error binding to IPv4 multicast socket: %s", strerror(errno));
688         } else {
689                 io_add(&mesh->loop, &mesh->discovery.sockets[0], mdns_io_handler, &mesh->discovery.sockets[0], fd, IO_READ);
690         }
691
692         sockaddr_t sa6 = {
693                 .in6.sin6_family = AF_INET6,
694                 .in6.sin6_port = ntohs(5353),
695         };
696         fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
697
698         if(fd == -1) {
699                 logger(mesh, MESHLINK_ERROR, "Error creating IPv6 socket: %s", strerror(errno));
700         }
701
702         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
703         setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
704         setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
705         setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &one, sizeof(one));
706         setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl));
707         setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
708
709         if(bind(fd, &sa6.sa, SALEN(sa6.sa)) == -1) {
710                 logger(mesh, MESHLINK_ERROR, "Error binding to IPv4 multicast socket: %s", strerror(errno));
711         } else {
712                 io_add(&mesh->loop, &mesh->discovery.sockets[1], mdns_io_handler, &mesh->discovery.sockets[1], fd, IO_READ);
713         }
714
715 #if defined(__linux)
716         int sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
717
718         if(sock != -1) {
719                 struct sockaddr_nl sa;
720                 memset(&sa, 0, sizeof(sa));
721                 sa.nl_family = AF_NETLINK;
722                 sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
723
724                 if(bind(sock, (struct sockaddr *)&sa, sizeof(sa)) != -1) {
725                         io_add(&mesh->loop, &mesh->discovery.pfroute_io, netlink_io_handler, NULL, sock, IO_READ);
726                         netlink_getlink(sock);
727                 } else {
728                         logger(mesh, MESHLINK_WARNING, "Could not bind AF_NETLINK socket: %s", strerror(errno));
729                 }
730         } else {
731                 logger(mesh, MESHLINK_WARNING, "Could not open AF_NETLINK socket: %s", strerror(errno));
732         }
733
734 #elif defined(RTM_NEWADDR)
735         int sock = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
736
737         if(sock != -1) {
738                 io_add(&mesh->loop, &mesh->discovery.pfroute_io, pfroute_io_handler, NULL, sock, IO_READ);
739         } else {
740                 logger(mesh, MESHLINK_WARNING, "Could not open PF_ROUTE socket: %s", strerror(errno));
741         }
742
743         struct ifaddrs *ifa = NULL;
744
745         if(getifaddrs(&ifa) == -1) {
746                 logger(mesh, MESHLINK_ERROR, "Could not get list of interface addresses: %s", strerror(errno));
747                 return true;
748         }
749
750         for(struct ifaddrs *ifap = ifa; ifap; ifap = ifap->ifa_next) {
751                 if(!ifap->ifa_name) {
752                         continue;
753                 }
754
755                 int index = if_nametoindex(ifap->ifa_name);
756
757                 if(ifap->ifa_flags & IFF_UP && ifap->ifa_flags & IFF_MULTICAST && !(ifap->ifa_flags & IFF_LOOPBACK)) {
758                         iface_up(mesh, index);
759                 }
760
761                 if(!ifap->ifa_addr) {
762                         continue;
763                 }
764
765                 discovery_address_t addr  = {
766                         .index = index,
767                 };
768
769                 sockaddr_t *sa = (sockaddr_t *)ifap->ifa_addr;
770
771                 if(sa->sa.sa_family == AF_INET) {
772                         memcpy(&addr.address.in, &sa->in, sizeof(sa->in));
773                         addr.address.in.sin_port = ntohs(5353);
774                 } else if(sa->sa.sa_family == AF_INET6) {
775                         memcpy(&addr.address.in6, &sa->in6, sizeof(sa->in6));
776                         addr.address.in6.sin6_port = ntohs(5353);
777                 } else {
778                         addr.address.sa.sa_family = AF_UNKNOWN;
779                 }
780
781                 if(addr.address.sa.sa_family != AF_UNKNOWN) {
782                         addr_add(mesh, &addr);
783                 }
784         }
785
786         freeifaddrs(ifa);
787
788 #endif
789
790         return true;
791 }
792
793 void discovery_stop(meshlink_handle_t *mesh) {
794         logger(mesh, MESHLINK_DEBUG, "discovery_stop called\n");
795
796         assert(mesh);
797
798         free(mesh->discovery.ifaces);
799         free(mesh->discovery.addresses);
800         mesh->discovery.ifaces = NULL;
801         mesh->discovery.addresses = NULL;
802         mesh->discovery.iface_count = 0;
803         mesh->discovery.address_count = 0;
804
805         if(mesh->discovery.pfroute_io.cb) {
806                 close(mesh->discovery.pfroute_io.fd);
807                 io_del(&mesh->loop, &mesh->discovery.pfroute_io);
808         }
809
810         for(int i = 0; i < 2; i++) {
811                 if(mesh->discovery.sockets[i].cb) {
812                         close(mesh->discovery.sockets[i].fd);
813                         io_del(&mesh->loop, &mesh->discovery.sockets[i]);
814                 }
815         }
816 }
817
818 void discovery_refresh(meshlink_handle_t *mesh) {
819         for(int i = 0; i < mesh->discovery.address_count; i++) {
820                 if(mesh->discovery.addresses[i].up) {
821                         send_mdns_packet(mesh, &mesh->discovery.addresses[i]);
822                 }
823         }
824 }