]> git.meshlink.io Git - meshlink/blob - src/discovery.c
36d202bde9b192852370e0fc58c53fd9d95ae2b3
[meshlink] / src / discovery.c
1 #include "system.h"
2
3 #include <catta/core.h>
4 #include <catta/lookup.h>
5 #include <catta/publish.h>
6 #include <catta/log.h>
7 #include <catta/simple-watch.h>
8 #include <catta/malloc.h>
9 #include <catta/alternative.h>
10 #include <catta/error.h>
11
12 #if defined(__APPLE__) || defined(__unix) && !defined(__linux)
13 #include <net/route.h>
14 #elif defined(__linux)
15 #include <asm/types.h>
16 #include <net/if.h>
17 #include <linux/if_link.h>
18 #include <linux/netlink.h>
19 #include <linux/rtnetlink.h>
20 #endif
21
22 #include "mdns.h"
23 #include "meshlink_internal.h"
24 #include "event.h"
25 #include "discovery.h"
26 #include "sockaddr.h"
27 #include "logger.h"
28 #include "netutl.h"
29 #include "node.h"
30 #include "connection.h"
31 #include "utils.h"
32 #include "xalloc.h"
33
34 #define MESHLINK_MDNS_SERVICE_TYPE "_%s._tcp"
35 #define MESHLINK_MDNS_NAME_KEY "name"
36 #define MESHLINK_MDNS_FINGERPRINT_KEY "fingerprint"
37
38 static const sockaddr_t mdns_address_ipv4 = {
39         .in.sin_family = AF_INET,
40         .in.sin_addr.s_addr = 0xfb0000e0,
41         .in.sin_port = 0xe914,
42 };
43
44 static const sockaddr_t mdns_address_ipv6 = {
45         .in6.sin6_family = AF_INET6,
46         .in6.sin6_addr.s6_addr[0x0] = 0xfd,
47         .in6.sin6_addr.s6_addr[0x1] = 0x02,
48         .in6.sin6_addr.s6_addr[0xf] = 0xfb,
49         .in6.sin6_port = 0xe914,
50 };
51
52 static void generate_rand_string(meshlink_handle_t *mesh, char *buffer, size_t size) {
53         assert(size);
54
55         for(size_t i = 0; i < (size - 1); ++i) {
56                 buffer[i] = 'a' + prng(mesh, 'z' - 'a' + 1);
57         }
58
59         buffer[size - 1] = '\0';
60 }
61
62 static void discovery_entry_group_callback(CattaServer *server, CattaSEntryGroup *group, CattaEntryGroupState state, void *userdata) {
63         (void)server;
64         (void)group;
65         meshlink_handle_t *mesh = userdata;
66
67         assert(mesh);
68         assert(mesh->catta_server);
69         assert(mesh->catta_poll);
70
71         /* Called whenever the entry group state changes */
72         switch(state) {
73         case CATTA_ENTRY_GROUP_ESTABLISHED:
74                 /* The entry group has been established successfully */
75                 logger(mesh, MESHLINK_DEBUG, "Catta Service successfully established.\n");
76                 break;
77
78         case CATTA_ENTRY_GROUP_COLLISION:
79                 logger(mesh, MESHLINK_WARNING, "Catta Service collision.\n");
80                 // @TODO can we just set a new name and retry?
81                 break;
82
83         case CATTA_ENTRY_GROUP_FAILURE :
84                 /* Some kind of failure happened while we were registering our services */
85                 logger(mesh, MESHLINK_ERROR, "Catta Entry group failure: %s\n", catta_strerror(catta_server_errno(mesh->catta_server)));
86                 catta_simple_poll_quit(mesh->catta_poll);
87                 break;
88
89         case CATTA_ENTRY_GROUP_UNCOMMITED:
90         case CATTA_ENTRY_GROUP_REGISTERING:
91                 break;
92         }
93 }
94
95
96 static void discovery_create_services(meshlink_handle_t *mesh) {
97         char *fingerprint = NULL;
98         char *txt_name = NULL;
99         char *txt_fingerprint = NULL;
100
101         assert(mesh);
102         assert(mesh->name);
103         assert(mesh->myport);
104         assert(mesh->catta_server);
105         assert(mesh->catta_poll);
106         assert(mesh->catta_servicetype);
107         assert(mesh->self);
108
109         logger(mesh, MESHLINK_DEBUG, "Adding service\n");
110
111         /* If this is the first time we're called, let's create a new entry group */
112         if(!(mesh->catta_group = catta_s_entry_group_new(mesh->catta_server, discovery_entry_group_callback, mesh))) {
113                 logger(mesh, MESHLINK_ERROR, "catta_entry_group_new() failed: %s\n", catta_strerror(catta_server_errno(mesh->catta_server)));
114                 goto fail;
115         }
116
117         /* Create txt records */
118         fingerprint = meshlink_get_fingerprint(mesh, (meshlink_node_t *)mesh->self);
119         xasprintf(&txt_name, "%s=%s", MESHLINK_MDNS_NAME_KEY, mesh->name);
120         xasprintf(&txt_fingerprint, "%s=%s", MESHLINK_MDNS_FINGERPRINT_KEY, fingerprint);
121
122         /* Add the service */
123         int ret = 0;
124
125         if((ret = catta_server_add_service(mesh->catta_server, mesh->catta_group, CATTA_IF_UNSPEC, CATTA_PROTO_UNSPEC, 0, fingerprint, mesh->catta_servicetype, NULL, NULL, atoi(mesh->myport), txt_name, txt_fingerprint, NULL)) < 0) {
126                 logger(mesh, MESHLINK_ERROR, "Failed to add service: %s\n", catta_strerror(ret));
127                 goto fail;
128         }
129
130         /* Tell the server to register the service */
131         if((ret = catta_s_entry_group_commit(mesh->catta_group)) < 0) {
132                 logger(mesh, MESHLINK_ERROR, "Failed to commit entry_group: %s\n", catta_strerror(ret));
133                 goto fail;
134         }
135
136         goto done;
137
138 fail:
139         catta_simple_poll_quit(mesh->catta_poll);
140
141 done:
142         free(fingerprint);
143         free(txt_name);
144         free(txt_fingerprint);
145 }
146
147 static void discovery_server_callback(CattaServer *server, CattaServerState state, void *userdata) {
148         (void)server;
149         meshlink_handle_t *mesh = userdata;
150
151         assert(mesh);
152
153         switch(state) {
154         case CATTA_SERVER_RUNNING:
155
156                 /* The serve has startup successfully and registered its host
157                  * name on the network, so it's time to create our services */
158                 if(pthread_mutex_lock(&mesh->mutex) != 0) {
159                         abort();
160                 }
161
162                 if(!mesh->catta_group) {
163                         discovery_create_services(mesh);
164                 }
165
166                 pthread_mutex_unlock(&mesh->mutex);
167
168                 break;
169
170         case CATTA_SERVER_COLLISION: {
171                 /* A host name collision happened. Let's pick a new name for the server */
172                 char hostname[17];
173                 generate_rand_string(mesh, hostname, sizeof(hostname));
174
175                 if(pthread_mutex_lock(&mesh->mutex) != 0) {
176                         abort();
177                 }
178
179                 assert(mesh->catta_server);
180                 assert(mesh->catta_poll);
181
182                 int result = catta_server_set_host_name(mesh->catta_server, hostname);
183
184                 if(result < 0) {
185                         catta_simple_poll_quit(mesh->catta_poll);
186                 }
187
188                 pthread_mutex_unlock(&mesh->mutex);
189         }
190         break;
191
192         case CATTA_SERVER_REGISTERING:
193                 if(pthread_mutex_lock(&mesh->mutex) != 0) {
194                         abort();
195                 }
196
197                 /* Let's drop our registered services. When the server is back
198                  * in CATTA_SERVER_RUNNING state we will register them
199                  * again with the new host name. */
200                 if(mesh->catta_group) {
201                         catta_s_entry_group_reset(mesh->catta_group);
202                         mesh->catta_group = NULL;
203                 }
204
205                 pthread_mutex_unlock(&mesh->mutex);
206
207                 break;
208
209         case CATTA_SERVER_FAILURE:
210                 if(pthread_mutex_lock(&mesh->mutex) != 0) {
211                         abort();
212                 }
213
214                 assert(mesh->catta_server);
215                 assert(mesh->catta_poll);
216
217                 /* Terminate on failure */
218                 catta_simple_poll_quit(mesh->catta_poll);
219
220                 pthread_mutex_unlock(&mesh->mutex);
221                 break;
222
223         case CATTA_SERVER_INVALID:
224                 break;
225         }
226 }
227
228 static void discovery_resolve_callback(CattaSServiceResolver *resolver, CattaIfIndex interface_, CattaProtocol protocol, CattaResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const CattaAddress *address, uint16_t port, CattaStringList *txt, CattaLookupResultFlags flags, void *userdata) {
229         (void)interface_;
230         (void)protocol;
231         (void)flags;
232         (void)name;
233         (void)type;
234         (void)domain;
235         (void)host_name;
236
237         meshlink_handle_t *mesh = userdata;
238
239         assert(mesh);
240
241         if(event != CATTA_RESOLVER_FOUND) {
242                 catta_s_service_resolver_free(resolver);
243                 return;
244         }
245
246         // retrieve fingerprint
247         CattaStringList *node_name_li = catta_string_list_find(txt, MESHLINK_MDNS_NAME_KEY);
248         CattaStringList *node_fp_li = catta_string_list_find(txt, MESHLINK_MDNS_FINGERPRINT_KEY);
249
250         if(node_name_li && node_fp_li) {
251                 char *node_name = (char *)catta_string_list_get_text(node_name_li) + strlen(MESHLINK_MDNS_NAME_KEY);
252                 char *node_fp = (char *)catta_string_list_get_text(node_fp_li) + strlen(MESHLINK_MDNS_FINGERPRINT_KEY);
253
254                 if(node_name[0] == '=' && node_fp[0] == '=') {
255                         if(pthread_mutex_lock(&mesh->mutex) != 0) {
256                                 abort();
257                         }
258
259                         node_name += 1;
260
261                         meshlink_node_t *node = meshlink_get_node(mesh, node_name);
262
263                         if(node) {
264                                 logger(mesh, MESHLINK_INFO, "Node %s is part of the mesh network.\n", node->name);
265
266                                 sockaddr_t naddress;
267                                 memset(&naddress, 0, sizeof(naddress));
268
269                                 switch(address->proto) {
270                                 case CATTA_PROTO_INET: {
271                                         naddress.in.sin_family = AF_INET;
272                                         naddress.in.sin_port = htons(port);
273                                         naddress.in.sin_addr.s_addr = address->data.ipv4.address;
274                                 }
275                                 break;
276
277                                 case CATTA_PROTO_INET6: {
278                                         naddress.in6.sin6_family = AF_INET6;
279                                         naddress.in6.sin6_port = htons(port);
280                                         memcpy(naddress.in6.sin6_addr.s6_addr, address->data.ipv6.address, sizeof(naddress.in6.sin6_addr.s6_addr));
281                                 }
282                                 break;
283
284                                 default:
285                                         naddress.unknown.family = AF_UNKNOWN;
286                                         break;
287                                 }
288
289                                 if(naddress.unknown.family != AF_UNKNOWN) {
290                                         node_t *n = (node_t *)node;
291                                         connection_t *c = n->connection;
292
293                                         n->catta_address = naddress;
294                                         node_add_recent_address(mesh, n, &naddress);
295
296                                         if(c && c->outgoing && !c->status.active) {
297                                                 c->outgoing->timeout = 0;
298
299                                                 if(c->outgoing->ev.cb) {
300                                                         timeout_set(&mesh->loop, &c->outgoing->ev, &(struct timespec) {
301                                                                 0, 0
302                                                         });
303                                                 }
304
305                                                 c->last_ping_time = -3600;
306                                         }
307
308                                 } else {
309                                         logger(mesh, MESHLINK_WARNING, "Could not resolve node %s to a known address family type.\n", node->name);
310                                 }
311                         } else {
312                                 logger(mesh, MESHLINK_WARNING, "Node %s is not part of the mesh network.\n", node_name);
313                         }
314
315                         pthread_mutex_unlock(&mesh->mutex);
316                 }
317         }
318
319         catta_s_service_resolver_free(resolver);
320 }
321
322 static void discovery_browse_callback(CattaSServiceBrowser *browser, CattaIfIndex interface_, CattaProtocol protocol, CattaBrowserEvent event, const char *name, const char *type, const char *domain, CattaLookupResultFlags flags, void *userdata) {
323         (void)browser;
324         (void)flags;
325         meshlink_handle_t *mesh = userdata;
326
327         /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
328         switch(event) {
329         case CATTA_BROWSER_FAILURE:
330                 if(pthread_mutex_lock(&mesh->mutex) != 0) {
331                         abort();
332                 }
333
334                 catta_simple_poll_quit(mesh->catta_poll);
335                 pthread_mutex_unlock(&mesh->mutex);
336                 break;
337
338         case CATTA_BROWSER_NEW:
339                 if(pthread_mutex_lock(&mesh->mutex) != 0) {
340                         abort();
341                 }
342
343                 catta_s_service_resolver_new(mesh->catta_server, interface_, protocol, name, type, domain, CATTA_PROTO_UNSPEC, 0, discovery_resolve_callback, mesh);
344                 handle_network_change(mesh, ++mesh->catta_interfaces);
345                 pthread_mutex_unlock(&mesh->mutex);
346                 break;
347
348         case CATTA_BROWSER_REMOVE:
349                 if(pthread_mutex_lock(&mesh->mutex) != 0) {
350                         abort();
351                 }
352
353                 handle_network_change(mesh, --mesh->catta_interfaces);
354                 pthread_mutex_unlock(&mesh->mutex);
355                 break;
356
357         case CATTA_BROWSER_ALL_FOR_NOW:
358         case CATTA_BROWSER_CACHE_EXHAUSTED:
359                 break;
360         }
361 }
362
363 static void discovery_log_cb(CattaLogLevel level, const char *txt) {
364         meshlink_log_level_t mlevel = MESHLINK_CRITICAL;
365
366         switch(level) {
367         case CATTA_LOG_ERROR:
368                 mlevel = MESHLINK_ERROR;
369                 break;
370
371         case CATTA_LOG_WARN:
372                 mlevel = MESHLINK_WARNING;
373                 break;
374
375         case CATTA_LOG_NOTICE:
376         case CATTA_LOG_INFO:
377                 mlevel = MESHLINK_INFO;
378                 break;
379
380         case CATTA_LOG_DEBUG:
381         default:
382                 mlevel = MESHLINK_DEBUG;
383                 break;
384         }
385
386         logger(NULL, mlevel, "%s\n", txt);
387 }
388
389 static void *discovery_loop(void *userdata) {
390         bool status = false;
391         meshlink_handle_t *mesh = userdata;
392         assert(mesh);
393
394         if(pthread_mutex_lock(&mesh->discovery_mutex) != 0) {
395                 abort();
396         }
397
398 #if 1
399         // bypass Catta
400         pthread_cond_broadcast(&mesh->discovery_cond);
401         pthread_mutex_unlock(&mesh->discovery_mutex);
402         return NULL;
403 #endif
404
405         // handle catta logs
406         catta_set_log_function(discovery_log_cb);
407
408         // create service type string
409         char appname[strlen(mesh->appname) + 2];
410         strcpy(appname, mesh->appname);
411
412         for(char *p = appname; *p; p++) {
413                 if(!isalnum(*p) && *p != '_' && *p != '-') {
414                         *p = '_';
415                 }
416         }
417
418         if(!appname[1]) {
419                 appname[1] = '_';
420                 appname[2] = '\0';
421         }
422
423         size_t servicetype_strlen = sizeof(MESHLINK_MDNS_SERVICE_TYPE) + strlen(appname) + 1;
424         mesh->catta_servicetype = malloc(servicetype_strlen);
425
426         if(mesh->catta_servicetype == NULL) {
427                 logger(mesh, MESHLINK_ERROR, "Failed to allocate memory for service type string.\n");
428                 goto fail;
429         }
430
431         snprintf(mesh->catta_servicetype, servicetype_strlen, MESHLINK_MDNS_SERVICE_TYPE, appname);
432
433         // Allocate discovery loop object
434         if(!(mesh->catta_poll = catta_simple_poll_new())) {
435                 logger(mesh, MESHLINK_ERROR, "Failed to create discovery poll object.\n");
436                 goto fail;
437         }
438
439         // generate some unique host name (we actually do not care about it)
440         char hostname[17];
441         generate_rand_string(mesh, hostname, sizeof(hostname));
442
443         // Let's set the host name for this server.
444         CattaServerConfig config;
445         catta_server_config_init(&config);
446         config.host_name = catta_strdup(hostname);
447         config.publish_workstation = 0;
448         config.disallow_other_stacks = 0;
449         config.publish_hinfo = 0;
450         config.publish_addresses = 1;
451         config.publish_no_reverse = 1;
452         config.allow_point_to_point = 1;
453
454         /* Allocate a new server */
455         int error;
456         const CattaPoll *poller = catta_simple_poll_get(mesh->catta_poll);
457
458         if(!poller) {
459                 logger(mesh, MESHLINK_ERROR, "Failed to create discovery server: %s\n", catta_strerror(error));
460                 goto fail;
461         }
462
463         mesh->catta_server = catta_server_new(poller, &config, discovery_server_callback, mesh, &error);
464
465         /* Free the configuration data */
466         catta_server_config_free(&config);
467
468         /* Check whether creating the server object succeeded */
469         if(!mesh->catta_server) {
470                 logger(mesh, MESHLINK_ERROR, "Failed to create discovery server: %s\n", catta_strerror(error));
471                 goto fail;
472         }
473
474         // Create the service browser
475         if(!(mesh->catta_browser = catta_s_service_browser_new(mesh->catta_server, CATTA_IF_UNSPEC, CATTA_PROTO_UNSPEC, mesh->catta_servicetype, NULL, 0, discovery_browse_callback, mesh))) {
476                 logger(mesh, MESHLINK_ERROR, "Failed to create discovery service browser: %s\n", catta_strerror(catta_server_errno(mesh->catta_server)));
477                 goto fail;
478         }
479
480         status = true;
481
482 fail:
483
484         pthread_cond_broadcast(&mesh->discovery_cond);
485         pthread_mutex_unlock(&mesh->discovery_mutex);
486
487         if(status) {
488                 catta_simple_poll_loop(mesh->catta_poll);
489         }
490
491         if(mesh->catta_browser) {
492                 catta_s_service_browser_free(mesh->catta_browser);
493                 mesh->catta_browser = NULL;
494         }
495
496         if(mesh->catta_group) {
497                 catta_s_entry_group_reset(mesh->catta_group);
498                 catta_s_entry_group_free(mesh->catta_group);
499                 mesh->catta_group = NULL;
500         }
501
502         if(mesh->catta_server) {
503                 catta_server_free(mesh->catta_server);
504                 mesh->catta_server = NULL;
505         }
506
507         if(mesh->catta_poll) {
508                 catta_simple_poll_free(mesh->catta_poll);
509                 mesh->catta_poll = NULL;
510         }
511
512         if(mesh->catta_servicetype) {
513                 free(mesh->catta_servicetype);
514                 mesh->catta_servicetype = NULL;
515         }
516
517         return NULL;
518 }
519
520 typedef struct discovery_address {
521         int index;
522         bool up;
523         sockaddr_t address;
524 } discovery_address_t;
525
526 static int iface_compare(const void *va, const void *vb) {
527         const int *a = va;
528         const int *b = vb;
529         return *a - *b;
530 }
531
532 static int address_compare(const void *va, const void *vb) {
533         const discovery_address_t *a = va;
534         const discovery_address_t *b = vb;
535
536         if(a->index != b->index) {
537                 return a->index - b->index;
538         }
539
540         return sockaddrcmp_noport(&a->address, &b->address);
541 }
542
543 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) {
544 #ifdef IP_PKTINFO
545         struct iovec iov  = {
546                 .iov_base = data,
547                 .iov_len = len,
548         };
549
550         struct in_pktinfo pkti = {
551                 .ipi_ifindex = index,
552                 .ipi_addr = src->in.sin_addr,
553         };
554
555         union {
556                 char buf[CMSG_SPACE(sizeof(pkti))];
557                 struct cmsghdr align;
558         } u;
559
560         struct msghdr msg = {
561                 .msg_name = (struct sockaddr *) &dest->sa,
562                 .msg_namelen = SALEN(dest->sa),
563                 .msg_iov = &iov,
564                 .msg_iovlen = 1,
565                 .msg_control = u.buf,
566                 .msg_controllen = sizeof(u.buf),
567         };
568
569
570         struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
571         cmsg->cmsg_level = IPPROTO_IP;
572         cmsg->cmsg_type = IP_PKTINFO;
573         cmsg->cmsg_len = CMSG_LEN(sizeof(pkti));
574         memcpy(CMSG_DATA(cmsg), &pkti, sizeof(pkti));
575
576         // Send the packet
577         ssize_t result = sendmsg(fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL);
578 #else
579         // Send the packet
580         ssize_t result = sendto(fd, data, len, MSG_DONTWAIT | MSG_NOSIGNAL, &dest->sa, SALEN(dest->sa));
581 #endif
582
583         if(result <= 0) {
584                 logger(mesh, MESHLINK_ERROR, "Error sending multicast packet: %s", strerror(errno));
585         }
586 }
587
588 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) {
589 #ifdef IPV6_PKTINFO
590         struct iovec iov  = {
591                 .iov_base = data,
592                 .iov_len = len,
593         };
594
595         struct in6_pktinfo pkti = {
596                 .ipi6_ifindex = index,
597                 .ipi6_addr = src->in6.sin6_addr,
598         };
599
600         union {
601                 char buf[CMSG_SPACE(sizeof(pkti))];
602                 struct cmsghdr align;
603         } u;
604
605         memset(&u, 0, sizeof u);
606
607         struct msghdr msg = {
608                 .msg_name = (struct sockaddr *) &dest->sa,
609                 .msg_namelen = SALEN(dest->sa),
610                 .msg_iov = &iov,
611                 .msg_iovlen = 1,
612                 .msg_control = u.buf,
613                 .msg_controllen = CMSG_LEN(sizeof(pkti)),
614         };
615
616         struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
617         cmsg->cmsg_level = IPPROTO_IPV6;
618         cmsg->cmsg_type = IPV6_PKTINFO;
619         cmsg->cmsg_len = CMSG_LEN(sizeof(pkti));
620         memcpy(CMSG_DATA(cmsg), &pkti, sizeof(pkti));
621
622         // Send the packet
623         ssize_t result = sendmsg(fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL);
624 #else
625         // Send the packet
626         ssize_t result = sendto(fd, data, len, MSG_DONTWAIT | MSG_NOSIGNAL, &dest->sa, SALEN(dest->sa));
627 #endif
628
629         if(result <= 0) {
630                 logger(mesh, MESHLINK_ERROR, "Error sending multicast packet: %s", strerror(errno));
631         }
632 }
633
634 static void send_mdns_packet(meshlink_handle_t *mesh, const discovery_address_t *addr) {
635         char *host = NULL, *port = NULL;
636         sockaddr2str(&addr->address, &host, &port);
637         fprintf(stderr, "Sending on iface %d %s port %s\n", addr->index, host, port);
638         free(host);
639         free(port);
640
641         // Configure the socket to send the packet to the right interface
642         int fd;
643         uint8_t data[1024];
644         char *fingerprint = meshlink_get_fingerprint(mesh, (meshlink_node_t *)mesh->self);
645         const char *keys[] = {MESHLINK_MDNS_NAME_KEY, MESHLINK_MDNS_FINGERPRINT_KEY};
646         const char *values[] = {mesh->name, fingerprint};
647         size_t size = prepare_packet(data, sizeof data, fingerprint, mesh->appname, "tcp", atoi(mesh->myport), 2, keys, values);
648
649         switch(addr->address.sa.sa_family) {
650         case AF_INET:
651                 fd = mesh->discovery_sockets[0].fd;
652 #ifdef IP_MULTICAST_IF
653                 {
654                         struct ip_mreqn mreq = {
655                                 .imr_address = addr->address.in.sin_addr,
656                                 .imr_ifindex = addr->index,
657                         };
658
659                         if(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq)) != 0) {
660                                 logger(mesh, MESHLINK_ERROR, "Could not set outgoing multicast interface on IPv4 socket");
661                                 return;
662                         }
663                 }
664
665 #endif
666
667                 send_mdns_packet_ipv4(mesh, fd, addr->index, &addr->address, &mdns_address_ipv4, data, size);
668                 break;
669
670         case AF_INET6:
671                 fd = mesh->discovery_sockets[1].fd;
672 #ifdef IPV6_MULTICAST_IF
673
674                 if(setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &addr->index, sizeof(addr->index)) != 0) {
675                         logger(mesh, MESHLINK_ERROR, "Could not set outgoing multicast interface on IPv6 socket");
676                         return;
677                 }
678
679 #endif
680
681                 send_mdns_packet_ipv6(mesh, fd, addr->index, &addr->address, &mdns_address_ipv6, data, size);
682                 break;
683
684         default:
685                 break;
686         }
687 }
688
689 static void mdns_io_handler(event_loop_t *loop, void *data, int flags) {
690         (void)flags;
691         meshlink_handle_t *mesh = loop->data;
692         io_t *io = data;
693         uint8_t buf[1024];
694         sockaddr_t sa;
695         socklen_t sl = sizeof(sa);
696
697         ssize_t len = recvfrom(io->fd, buf, sizeof(buf), MSG_DONTWAIT, &sa.sa, &sl);
698
699         if(len == -1) {
700                 if(!sockwouldblock(errno)) {
701                         fprintf(stderr, "Error reading from discovery socket: %s\n", strerror(errno));
702                         logger(mesh, MESHLINK_ERROR, "Error reading from mDNS discovery socket: %s", strerror(errno));
703                         io_set(loop, io, 0);
704                 }
705
706                 return;
707         }
708
709         char *name = NULL;
710         uint16_t port = 0;
711         const char *keys[2] = {MESHLINK_MDNS_NAME_KEY, MESHLINK_MDNS_FINGERPRINT_KEY};
712         char *values[2] = {NULL, NULL};
713
714         if(parse_packet(buf, len, &name, mesh->appname, "tcp", &port, 2, keys, values)) {
715                 node_t *n = (node_t *)meshlink_get_node(mesh, values[0]);
716
717                 if(n) {
718                         logger(mesh, MESHLINK_INFO, "Node %s is part of the mesh network.\n", n->name);
719
720                         switch(sa.sa.sa_family) {
721                         case AF_INET:
722                                 sa.in.sin_port = port;
723                                 break;
724
725                         case AF_INET6:
726                                 sa.in6.sin6_port = port;
727                                 break;
728
729                         default:
730                                 logger(mesh, MESHLINK_WARNING, "Could not resolve node %s to a known address family type.\n", n->name);
731                                 sa.sa.sa_family = AF_UNKNOWN;
732                                 break;
733                         }
734
735                         if(sa.sa.sa_family != AF_UNKNOWN) {
736                                 n->catta_address = sa;
737                                 node_add_recent_address(mesh, n, &sa);
738
739                                 connection_t *c = n->connection;
740
741                                 if(c && c->outgoing && !c->status.active) {
742                                         c->outgoing->timeout = 0;
743
744                                         if(c->outgoing->ev.cb) {
745                                                 timeout_set(&mesh->loop, &c->outgoing->ev, &(struct timespec) {
746                                                         0, 0
747                                                 });
748                                         }
749
750                                         c->last_ping_time = -3600;
751                                 }
752                         }
753                 } else {
754                         logger(mesh, MESHLINK_WARNING, "Node %s is not part of the mesh network.\n", values[0]);
755                 }
756
757                 fprintf(stderr, "Got packet from %s port %u\n%s=%s\n%s=%s\n", name, port, keys[0], values[0], keys[1], values[1]);
758         }
759
760         free(name);
761
762         for(int i = 0; i < 2; i++) {
763                 free(values[i]);
764         }
765 }
766
767 static void iface_up(meshlink_handle_t *mesh, int index) {
768         int *p = bsearch(&index, mesh->discovery_ifaces, mesh->discovery_iface_count, sizeof(*p), iface_compare);
769
770         if(p) {
771                 return;
772         }
773
774         fprintf(stderr, "iface %d up\n", index);
775         mesh->discovery_ifaces = xrealloc(mesh->discovery_ifaces, ++mesh->discovery_iface_count * sizeof(*p));
776         mesh->discovery_ifaces[mesh->discovery_iface_count - 1] = index;
777         qsort(mesh->discovery_ifaces, mesh->discovery_iface_count, sizeof(*p), iface_compare);
778
779         // Add multicast membership
780         struct ip_mreqn mreq4 = {
781                 .imr_multiaddr = mdns_address_ipv4.in.sin_addr,
782                 .imr_ifindex = index,
783         };
784         setsockopt(mesh->discovery_sockets[0].fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq4, sizeof(mreq4));
785         setsockopt(mesh->discovery_sockets[0].fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq4, sizeof(mreq4));
786
787         struct ipv6_mreq mreq6 = {
788                 .ipv6mr_multiaddr = mdns_address_ipv6.in6.sin6_addr,
789                 .ipv6mr_interface = index,
790         };
791         setsockopt(mesh->discovery_sockets[1].fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6));
792         setsockopt(mesh->discovery_sockets[1].fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6));
793
794         // Send an announcement for all addresses associated with this interface
795         for(int i = 0; i < mesh->discovery_address_count; i++) {
796                 if(mesh->discovery_addresses[i].index == index) {
797                         send_mdns_packet(mesh, &mesh->discovery_addresses[i]);
798                 }
799         }
800
801         handle_network_change(mesh, true);
802 }
803
804 static void iface_down(meshlink_handle_t *const mesh, int index) {
805         int *p = bsearch(&index, mesh->discovery_ifaces, mesh->discovery_iface_count, sizeof(*p), iface_compare);
806
807         if(!p) {
808                 return;
809         }
810
811         // Drop multicast membership
812         struct ip_mreqn mreq4 = {
813                 .imr_multiaddr = mdns_address_ipv4.in.sin_addr,
814                 .imr_ifindex = index,
815         };
816         setsockopt(mesh->discovery_sockets[0].fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq4, sizeof(mreq4));
817
818         struct ipv6_mreq mreq6 = {
819                 .ipv6mr_multiaddr = mdns_address_ipv6.in6.sin6_addr,
820                 .ipv6mr_interface = index,
821         };
822         setsockopt(mesh->discovery_sockets[1].fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6));
823
824         fprintf(stderr, "iface %d down\n", index);
825         memmove(p, p + 1, (mesh->discovery_ifaces + --mesh->discovery_iface_count - p) * sizeof(*p));
826
827         handle_network_change(mesh, mesh->discovery_iface_count);
828 }
829
830 static void addr_add(meshlink_handle_t *mesh, const discovery_address_t *addr) {
831         discovery_address_t *p = bsearch(addr, mesh->discovery_addresses, mesh->discovery_address_count, sizeof(*p), address_compare);
832
833         if(p) {
834                 return;
835         }
836
837         bool up = bsearch(&addr->index, mesh->discovery_ifaces, mesh->discovery_iface_count, sizeof(int), iface_compare);
838         char *host = NULL, *port = NULL;
839         sockaddr2str(&addr->address, &host, &port);
840         fprintf(stderr, "address %d %s port %s up %d\n", addr->index, host, port, up);
841         free(host);
842         free(port);
843
844         mesh->discovery_addresses = xrealloc(mesh->discovery_addresses, ++mesh->discovery_address_count * sizeof(*p));
845         mesh->discovery_addresses[mesh->discovery_address_count - 1] = *addr;
846         mesh->discovery_addresses[mesh->discovery_address_count - 1].up = up;
847
848         if(up) {
849                 send_mdns_packet(mesh, &mesh->discovery_addresses[mesh->discovery_address_count - 1]);
850         }
851
852         qsort(mesh->discovery_addresses, mesh->discovery_address_count, sizeof(*p), address_compare);
853 }
854
855 static void addr_del(meshlink_handle_t *mesh, const discovery_address_t *addr) {
856         discovery_address_t *p = bsearch(addr, mesh->discovery_addresses, mesh->discovery_address_count, sizeof(*p), address_compare);
857
858         if(!p) {
859                 return;
860         }
861
862         char *host = NULL, *port = NULL;
863         sockaddr2str(&addr->address, &host, &port);
864         fprintf(stderr, "address %d %s port %s down\n", addr->index, host, port);
865         free(host);
866         free(port);
867
868         memmove(p, p + 1, (mesh->discovery_addresses + --mesh->discovery_address_count - p) * sizeof(*p));
869 }
870
871 #if defined(__linux)
872 static void netlink_getlink(int fd) {
873         static const struct {
874                 struct nlmsghdr nlm;
875                 struct ifinfomsg ifi;
876         } msg = {
877                 .nlm.nlmsg_len = NLMSG_LENGTH(sizeof(msg.ifi)),
878                 .nlm.nlmsg_type = RTM_GETLINK,
879                 .nlm.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
880                 .nlm.nlmsg_seq = 1,
881                 .ifi.ifi_family = AF_UNSPEC,
882         };
883         send(fd, &msg, msg.nlm.nlmsg_len, 0);
884 }
885
886 static void netlink_getaddr(int fd) {
887         static const struct {
888                 struct nlmsghdr nlm;
889                 struct ifaddrmsg ifa;
890         } msg = {
891                 .nlm.nlmsg_len = NLMSG_LENGTH(sizeof(msg.ifa)),
892                 .nlm.nlmsg_type = RTM_GETADDR,
893                 .nlm.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
894                 .nlm.nlmsg_seq = 2,
895                 .ifa.ifa_family = AF_UNSPEC,
896         };
897         send(fd, &msg, msg.nlm.nlmsg_len, 0);
898 }
899
900
901 static void netlink_parse_link(meshlink_handle_t *mesh, const struct nlmsghdr *nlm) {
902         const struct ifinfomsg *ifi = (const struct ifinfomsg *)(nlm + 1);
903
904         if(ifi->ifi_flags & IFF_UP && ifi->ifi_flags & IFF_MULTICAST) {
905                 iface_up(mesh, ifi->ifi_index);
906         } else {
907                 iface_down(mesh, ifi->ifi_index);
908         }
909 }
910
911 static void netlink_parse_addr(meshlink_handle_t *mesh, const struct nlmsghdr *nlm) {
912         const struct ifaddrmsg *ifa = (const struct ifaddrmsg *)(nlm + 1);
913         const uint8_t *ptr = (const uint8_t *)(ifa + 1);
914         size_t len = nlm->nlmsg_len - (ptr - (const uint8_t *)nlm);
915
916         while(len >= sizeof(struct rtattr)) {
917                 const struct rtattr *rta = (const struct rtattr *)ptr;
918
919                 if(rta->rta_len <= 0 || rta->rta_len > len) {
920                         break;
921                 }
922
923                 if(rta->rta_type == IFA_ADDRESS) {
924                         discovery_address_t addr  = {
925                                 .index = ifa->ifa_index,
926                         };
927
928                         if(rta->rta_len == 8) {
929                                 addr.address.sa.sa_family = AF_INET;
930                                 memcpy(&addr.address.in.sin_addr, ptr + 4, 4);
931                                 addr.address.in.sin_port = 5353;
932                         } else if(rta->rta_len == 20) {
933                                 addr.address.sa.sa_family = AF_INET6;
934                                 memcpy(&addr.address.in6.sin6_addr, ptr + 4, 16);
935                                 addr.address.in6.sin6_port = 5353;
936                                 addr.address.in6.sin6_scope_id = ifa->ifa_index;
937                         } else {
938                                 addr.address.sa.sa_family = AF_UNKNOWN;
939                         }
940
941                         if(addr.address.sa.sa_family != AF_UNKNOWN) {
942                                 if(nlm->nlmsg_type == RTM_NEWADDR) {
943                                         addr_add(mesh, &addr);
944                                 } else {
945                                         addr_del(mesh, &addr);
946                                 }
947                         }
948                 }
949
950                 unsigned short rta_len = (rta->rta_len + 3) & ~3;
951                 ptr += rta_len;
952                 len -= rta_len;
953         }
954 }
955
956 static void netlink_parse(meshlink_handle_t *mesh, const void *data, size_t len) {
957         const uint8_t *ptr = data;
958
959         while(len >= sizeof(struct nlmsghdr)) {
960                 const struct nlmsghdr *nlm = (const struct nlmsghdr *)ptr;
961
962                 if(nlm->nlmsg_len > len) {
963                         break;
964                 }
965
966                 switch(nlm->nlmsg_type) {
967                 case RTM_NEWLINK:
968                 case RTM_DELLINK:
969                         netlink_parse_link(mesh, nlm);
970                         break;
971
972                 case RTM_NEWADDR:
973                 case RTM_DELADDR:
974                         netlink_parse_addr(mesh, nlm);
975                 }
976
977                 ptr += nlm->nlmsg_len;
978                 len -= nlm->nlmsg_len;
979         }
980 }
981
982 static void netlink_io_handler(event_loop_t *loop, void *data, int flags) {
983         (void)flags;
984         static time_t prev_update;
985         meshlink_handle_t *mesh = data;
986
987         struct {
988                 struct nlmsghdr nlm;
989                 char data[16384];
990         } msg;
991
992         while(true) {
993                 ssize_t result = recv(mesh->pfroute_io.fd, &msg, sizeof(msg), MSG_DONTWAIT);
994
995                 if(result <= 0) {
996                         if(result == 0 || errno == EAGAIN || errno == EINTR) {
997                                 break;
998                         }
999
1000                         logger(mesh, MESHLINK_ERROR, "Reading from Netlink socket failed: %s\n", strerror(errno));
1001                         io_set(loop, &mesh->pfroute_io, 0);
1002                 }
1003
1004                 if((size_t)result < sizeof(msg.nlm)) {
1005                         logger(mesh, MESHLINK_ERROR, "Invalid Netlink message\n");
1006                         break;
1007                 }
1008
1009                 if(msg.nlm.nlmsg_type == NLMSG_DONE) {
1010                         if(msg.nlm.nlmsg_seq == 1) {
1011                                 // We just got the result of GETLINK, now send GETADDR.
1012                                 netlink_getaddr(mesh->pfroute_io.fd);
1013                         }
1014                 } else {
1015                         netlink_parse(mesh, &msg, result);
1016
1017                         if(loop->now.tv_sec > prev_update + 5) {
1018                                 prev_update = loop->now.tv_sec;
1019                                 handle_network_change(mesh, 1);
1020                         }
1021                 }
1022         }
1023 }
1024 #elif defined(RTM_NEWADDR)
1025 static void pfroute_io_handler(event_loop_t *loop, void *data, int flags) {
1026         (void)flags;
1027         static time_t prev_update;
1028         meshlink_handle_t *mesh = data;
1029
1030         struct {
1031                 struct rt_msghdr rtm;
1032                 char data[2048];
1033         } msg;
1034
1035         while(true) {
1036                 msg.rtm.rtm_version = 0;
1037                 ssize_t result = recv(mesh->pfroute_io.fd, &msg, sizeof(msg), MSG_DONTWAIT);
1038
1039                 if(result <= 0) {
1040                         if(result == 0 || errno == EAGAIN || errno == EINTR) {
1041                                 break;
1042                         }
1043
1044                         logger(mesh, MESHLINK_ERROR, "Reading from PFROUTE socket failed: %s\n", strerror(errno));
1045                         io_set(loop, &mesh->pfroute_io, 0);
1046                 }
1047
1048                 if(msg.rtm.rtm_version != RTM_VERSION) {
1049                         logger(mesh, MESHLINK_ERROR, "Invalid PFROUTE message version\n");
1050                         break;
1051                 }
1052
1053                 switch(msg.rtm.rtm_type) {
1054                 case RTM_IFINFO:
1055                 case RTM_NEWADDR:
1056                 case RTM_DELADDR:
1057                         if(loop->now.tv_sec > prev_update + 5) {
1058                                 prev_update = loop->now.tv_sec;
1059                                 handle_network_change(mesh, 1);
1060                         }
1061
1062                         break;
1063
1064                 default:
1065                         break;
1066                 }
1067         }
1068 }
1069 #endif
1070
1071 bool discovery_start(meshlink_handle_t *mesh) {
1072         logger(mesh, MESHLINK_DEBUG, "discovery_start called\n");
1073
1074         assert(mesh);
1075         assert(!mesh->catta_poll);
1076         assert(!mesh->catta_server);
1077         assert(!mesh->catta_browser);
1078         assert(!mesh->discovery_threadstarted);
1079         assert(!mesh->catta_servicetype);
1080
1081         if(pthread_mutex_lock(&mesh->discovery_mutex) != 0) {
1082                 abort();
1083         }
1084
1085         // Start the discovery thread
1086         if(pthread_create(&mesh->discovery_thread, NULL, discovery_loop, mesh) != 0) {
1087                 pthread_mutex_unlock(&mesh->discovery_mutex);
1088                 logger(mesh, MESHLINK_ERROR, "Could not start discovery thread: %s\n", strerror(errno));
1089                 memset(&mesh->discovery_thread, 0, sizeof(mesh)->discovery_thread);
1090                 return false;
1091         }
1092
1093         pthread_cond_wait(&mesh->discovery_cond, &mesh->discovery_mutex);
1094         pthread_mutex_unlock(&mesh->discovery_mutex);
1095
1096         mesh->discovery_threadstarted = true;
1097
1098         // Set up multicast sockets for mDNS
1099         static const int one = 1;
1100         static const int ttl = 255;
1101
1102         int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1103         sockaddr_t sa4 = {
1104                 .in.sin_family = AF_INET,
1105                 .in.sin_port = ntohs(5353),
1106         };
1107         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
1108         bind(fd, &sa4.sa, SALEN(sa4.sa));
1109         setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one));
1110         setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
1111         io_add(&mesh->loop, &mesh->discovery_sockets[0], mdns_io_handler, &mesh->discovery_sockets[0], fd, IO_READ);
1112
1113         sockaddr_t sa6 = {
1114                 .in6.sin6_family = AF_INET6,
1115                 .in6.sin6_port = ntohs(5353),
1116         };
1117         fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
1118         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
1119         setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
1120         bind(fd, &sa6.sa, SALEN(sa6.sa));
1121         setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &one, sizeof(one));
1122         setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl));
1123         io_add(&mesh->loop, &mesh->discovery_sockets[1], mdns_io_handler, &mesh->discovery_sockets[1], fd, IO_READ);
1124
1125 #if defined(__linux)
1126         int sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
1127
1128         if(sock != -1) {
1129                 struct sockaddr_nl sa;
1130                 memset(&sa, 0, sizeof(sa));
1131                 sa.nl_family = AF_NETLINK;
1132                 sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
1133
1134                 if(bind(sock, (struct sockaddr *)&sa, sizeof(sa)) != -1) {
1135                         io_add(&mesh->loop, &mesh->pfroute_io, netlink_io_handler, mesh, sock, IO_READ);
1136                         netlink_getlink(sock);
1137                 } else {
1138                         logger(mesh, MESHLINK_WARNING, "Could not bind AF_NETLINK socket: %s", strerror(errno));
1139                 }
1140         } else {
1141                 logger(mesh, MESHLINK_WARNING, "Could not open AF_NETLINK socket: %s", strerror(errno));
1142         }
1143
1144 #elif defined(RTM_NEWADDR)
1145         int sock = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
1146
1147         if(sock != -1) {
1148                 io_add(&mesh->loop, &mesh->pfroute_io, pfroute_io_handler, mesh, sock, IO_READ);
1149         } else {
1150                 logger(mesh, MESHLINK_WARNING, "Could not open PF_ROUTE socket: %s", strerror(errno));
1151         }
1152
1153 #endif
1154
1155         return true;
1156 }
1157
1158 void discovery_stop(meshlink_handle_t *mesh) {
1159         logger(mesh, MESHLINK_DEBUG, "discovery_stop called\n");
1160
1161         assert(mesh);
1162
1163         free(mesh->discovery_ifaces);
1164         free(mesh->discovery_addresses);
1165         mesh->discovery_iface_count = 0;
1166         mesh->discovery_address_count = 0;
1167
1168         if(mesh->pfroute_io.cb) {
1169                 close(mesh->pfroute_io.fd);
1170                 io_del(&mesh->loop, &mesh->pfroute_io);
1171         }
1172
1173         for(int i = 0; i < 2; i++) {
1174                 if(mesh->discovery_sockets[i].cb) {
1175                         close(mesh->discovery_sockets[i].fd);
1176                         io_del(&mesh->loop, &mesh->discovery_sockets[i]);
1177                 }
1178         }
1179
1180         // Shut down
1181         if(mesh->catta_poll) {
1182                 catta_simple_poll_quit(mesh->catta_poll);
1183         }
1184
1185         // Wait for the discovery thread to finish
1186         if(mesh->discovery_threadstarted == true) {
1187                 if(pthread_join(mesh->discovery_thread, NULL) != 0) {
1188                         abort();
1189                 }
1190
1191                 mesh->discovery_threadstarted = false;
1192         }
1193
1194         mesh->catta_interfaces = 0;
1195 }