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