1 /*
2 * Copyright (c) 2024, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "mdns_socket.hpp"
30
31 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
32
33 #include <arpa/inet.h>
34 #include <errno.h>
35 #include <net/if.h>
36 #include <netinet/in.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/socket.h>
41 #include <sys/types.h>
42 #include <unistd.h>
43
44 #include "ip6_utils.hpp"
45 #include "platform-posix.h"
46 #include "common/code_utils.hpp"
47
otPlatMdnsSetListeningEnabled(otInstance * aInstance,bool aEnable,uint32_t aInfraIfIndex)48 extern "C" otError otPlatMdnsSetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex)
49 {
50 return ot::Posix::MdnsSocket::Get().SetListeningEnabled(aInstance, aEnable, aInfraIfIndex);
51 }
52
otPlatMdnsSendMulticast(otInstance * aInstance,otMessage * aMessage,uint32_t aInfraIfIndex)53 extern "C" void otPlatMdnsSendMulticast(otInstance *aInstance, otMessage *aMessage, uint32_t aInfraIfIndex)
54 {
55 OT_UNUSED_VARIABLE(aInstance);
56 return ot::Posix::MdnsSocket::Get().SendMulticast(aMessage, aInfraIfIndex);
57 }
58
otPlatMdnsSendUnicast(otInstance * aInstance,otMessage * aMessage,const otPlatMdnsAddressInfo * aAddress)59 extern "C" void otPlatMdnsSendUnicast(otInstance *aInstance, otMessage *aMessage, const otPlatMdnsAddressInfo *aAddress)
60 {
61 OT_UNUSED_VARIABLE(aInstance);
62 return ot::Posix::MdnsSocket::Get().SendUnicast(aMessage, aAddress);
63 }
64
65 namespace ot {
66 namespace Posix {
67
68 using namespace ot::Posix::Ip6Utils;
69
70 const char MdnsSocket::kLogModuleName[] = "MdnsSocket";
71
Get(void)72 MdnsSocket &MdnsSocket::Get(void)
73 {
74 static MdnsSocket sInstance;
75
76 return sInstance;
77 }
78
Init(void)79 void MdnsSocket::Init(void)
80 {
81 mEnabled = false;
82 mInfraIfIndex = 0;
83 mFd6 = -1;
84 mFd4 = -1;
85 mPendingIp6Tx = 0;
86 mPendingIp4Tx = 0;
87
88 // mDNS multicast IPv6 address "ff02::fb"
89 memset(&mMulticastIp6Address, 0, sizeof(otIp6Address));
90 mMulticastIp6Address.mFields.m8[0] = 0xff;
91 mMulticastIp6Address.mFields.m8[1] = 0x02;
92 mMulticastIp6Address.mFields.m8[15] = 0xfb;
93
94 // mDNS multicast IPv4 address "224.0.0.251"
95 memset(&mMulticastIp4Address, 0, sizeof(otIp4Address));
96 mMulticastIp4Address.mFields.m8[0] = 224;
97 mMulticastIp4Address.mFields.m8[3] = 251;
98
99 memset(&mTxQueue, 0, sizeof(mTxQueue));
100 }
101
SetUp(void)102 void MdnsSocket::SetUp(void)
103 {
104 otMessageQueueInit(&mTxQueue);
105 Mainloop::Manager::Get().Add(*this);
106 }
107
TearDown(void)108 void MdnsSocket::TearDown(void)
109 {
110 Mainloop::Manager::Get().Remove(*this);
111
112 if (mEnabled)
113 {
114 ClearTxQueue();
115 mEnabled = false;
116 }
117 }
118
Deinit(void)119 void MdnsSocket::Deinit(void)
120 {
121 CloseIp4Socket();
122 CloseIp6Socket();
123 }
124
Update(otSysMainloopContext & aContext)125 void MdnsSocket::Update(otSysMainloopContext &aContext)
126 {
127 VerifyOrExit(mEnabled);
128
129 FD_SET(mFd6, &aContext.mReadFdSet);
130 FD_SET(mFd4, &aContext.mReadFdSet);
131
132 if (mPendingIp6Tx > 0)
133 {
134 FD_SET(mFd6, &aContext.mWriteFdSet);
135 }
136
137 if (mPendingIp4Tx > 0)
138 {
139 FD_SET(mFd4, &aContext.mWriteFdSet);
140 }
141
142 if (aContext.mMaxFd < mFd6)
143 {
144 aContext.mMaxFd = mFd6;
145 }
146
147 if (aContext.mMaxFd < mFd4)
148 {
149 aContext.mMaxFd = mFd4;
150 }
151
152 exit:
153 return;
154 }
155
Process(const otSysMainloopContext & aContext)156 void MdnsSocket::Process(const otSysMainloopContext &aContext)
157 {
158 VerifyOrExit(mEnabled);
159
160 if (FD_ISSET(mFd6, &aContext.mWriteFdSet))
161 {
162 SendQueuedMessages(kIp6Msg);
163 }
164
165 if (FD_ISSET(mFd4, &aContext.mWriteFdSet))
166 {
167 SendQueuedMessages(kIp4Msg);
168 }
169
170 if (FD_ISSET(mFd6, &aContext.mReadFdSet))
171 {
172 ReceiveMessage(kIp6Msg);
173 }
174
175 if (FD_ISSET(mFd4, &aContext.mReadFdSet))
176 {
177 ReceiveMessage(kIp4Msg);
178 }
179
180 exit:
181 return;
182 }
183
SetListeningEnabled(otInstance * aInstance,bool aEnable,uint32_t aInfraIfIndex)184 otError MdnsSocket::SetListeningEnabled(otInstance *aInstance, bool aEnable, uint32_t aInfraIfIndex)
185 {
186 otError error = OT_ERROR_NONE;
187
188 VerifyOrExit(aEnable != mEnabled);
189 mInstance = aInstance;
190
191 if (aEnable)
192 {
193 error = Enable(aInfraIfIndex);
194 }
195 else
196 {
197 Disable(aInfraIfIndex);
198 }
199
200 exit:
201 return error;
202 }
203
Enable(uint32_t aInfraIfIndex)204 otError MdnsSocket::Enable(uint32_t aInfraIfIndex)
205 {
206 otError error;
207
208 SuccessOrExit(error = OpenIp4Socket(aInfraIfIndex));
209 SuccessOrExit(error = JoinOrLeaveIp4MulticastGroup(/* aJoin */ true, aInfraIfIndex));
210
211 SuccessOrExit(error = OpenIp6Socket(aInfraIfIndex));
212 SuccessOrExit(error = JoinOrLeaveIp6MulticastGroup(/* aJoin */ true, aInfraIfIndex));
213
214 mEnabled = true;
215 mInfraIfIndex = aInfraIfIndex;
216
217 LogInfo("Enabled");
218
219 exit:
220 if (error != OT_ERROR_NONE)
221 {
222 CloseIp4Socket();
223 CloseIp6Socket();
224 }
225
226 return error;
227 }
228
Disable(uint32_t aInfraIfIndex)229 void MdnsSocket::Disable(uint32_t aInfraIfIndex)
230 {
231 ClearTxQueue();
232
233 IgnoreError(JoinOrLeaveIp4MulticastGroup(/* aJoin */ false, aInfraIfIndex));
234 IgnoreError(JoinOrLeaveIp6MulticastGroup(/* aJoin */ false, aInfraIfIndex));
235 CloseIp4Socket();
236 CloseIp6Socket();
237
238 mEnabled = false;
239
240 LogInfo("Disabled");
241 }
242
SendMulticast(otMessage * aMessage,uint32_t aInfraIfIndex)243 void MdnsSocket::SendMulticast(otMessage *aMessage, uint32_t aInfraIfIndex)
244 {
245 Metadata metadata;
246 uint16_t length;
247
248 VerifyOrExit(mEnabled);
249 VerifyOrExit(aInfraIfIndex == mInfraIfIndex);
250
251 length = otMessageGetLength(aMessage);
252
253 if (length > kMaxMessageLength)
254 {
255 LogWarn("Multicast msg length %u is longer than max %u", length, kMaxMessageLength);
256 ExitNow();
257 }
258
259 metadata.mIp6Address = mMulticastIp6Address;
260 metadata.mIp6Port = kMdnsPort;
261 metadata.mIp4Address = mMulticastIp4Address;
262 metadata.mIp4Port = kMdnsPort;
263
264 SuccessOrExit(otMessageAppend(aMessage, &metadata, sizeof(Metadata)));
265
266 mPendingIp4Tx++;
267 mPendingIp6Tx++;
268
269 otMessageQueueEnqueue(&mTxQueue, aMessage);
270 aMessage = NULL;
271
272 exit:
273 if (aMessage != NULL)
274 {
275 otMessageFree(aMessage);
276 }
277 }
278
SendUnicast(otMessage * aMessage,const otPlatMdnsAddressInfo * aAddress)279 void MdnsSocket::SendUnicast(otMessage *aMessage, const otPlatMdnsAddressInfo *aAddress)
280 {
281 bool isIp4 = false;
282 Metadata metadata;
283 uint16_t length;
284
285 VerifyOrExit(mEnabled);
286 VerifyOrExit(aAddress->mInfraIfIndex == mInfraIfIndex);
287
288 length = otMessageGetLength(aMessage);
289
290 if (length > kMaxMessageLength)
291 {
292 LogWarn("Unicast msg length %u is longer than max %u", length, kMaxMessageLength);
293 ExitNow();
294 }
295
296 memset(&metadata, 0, sizeof(Metadata));
297
298 if (otIp4FromIp4MappedIp6Address(&aAddress->mAddress, &metadata.mIp4Address) == OT_ERROR_NONE)
299 {
300 isIp4 = true;
301 metadata.mIp4Port = aAddress->mPort;
302 metadata.mIp6Port = 0;
303 }
304 else
305 {
306 metadata.mIp6Address = aAddress->mAddress;
307 metadata.mIp4Port = 0;
308 metadata.mIp6Port = aAddress->mPort;
309 }
310
311 SuccessOrExit(otMessageAppend(aMessage, &metadata, sizeof(Metadata)));
312
313 if (isIp4)
314 {
315 mPendingIp4Tx++;
316 }
317 else
318 {
319 mPendingIp6Tx++;
320 }
321
322 otMessageQueueEnqueue(&mTxQueue, aMessage);
323 aMessage = NULL;
324
325 exit:
326 if (aMessage != NULL)
327 {
328 otMessageFree(aMessage);
329 }
330 }
331
ClearTxQueue(void)332 void MdnsSocket::ClearTxQueue(void)
333 {
334 otMessage *message;
335
336 while ((message = otMessageQueueGetHead(&mTxQueue)) != NULL)
337 {
338 otMessageQueueDequeue(&mTxQueue, message);
339 otMessageFree(message);
340 }
341
342 mPendingIp4Tx = 0;
343 mPendingIp6Tx = 0;
344 }
345
SendQueuedMessages(MsgType aMsgType)346 void MdnsSocket::SendQueuedMessages(MsgType aMsgType)
347 {
348 switch (aMsgType)
349 {
350 case kIp6Msg:
351 VerifyOrExit(mPendingIp6Tx > 0);
352 break;
353 case kIp4Msg:
354 VerifyOrExit(mPendingIp4Tx > 0);
355 break;
356 }
357
358 for (otMessage *message = otMessageQueueGetHead(&mTxQueue); message != NULL;
359 message = otMessageQueueGetNext(&mTxQueue, message))
360 {
361 bool isTxPending = false;
362 uint16_t length;
363 uint16_t offset;
364 int bytesSent;
365 Metadata metadata;
366 uint8_t buffer[kMaxMessageLength];
367 struct sockaddr_in6 addr6;
368 struct sockaddr_in addr;
369
370 length = otMessageGetLength(message);
371
372 offset = length - sizeof(Metadata);
373 length -= sizeof(Metadata);
374
375 otMessageRead(message, offset, &metadata, sizeof(Metadata));
376
377 switch (aMsgType)
378 {
379 case kIp6Msg:
380 isTxPending = (metadata.mIp6Port != 0);
381 break;
382 case kIp4Msg:
383 isTxPending = (metadata.mIp4Port != 0);
384 break;
385 }
386
387 if (!isTxPending)
388 {
389 continue;
390 }
391
392 otMessageRead(message, 0, buffer, length);
393
394 switch (aMsgType)
395 {
396 case kIp6Msg:
397 memset(&addr6, 0, sizeof(addr6));
398 addr6.sin6_family = AF_INET6;
399 addr6.sin6_port = htons(metadata.mIp6Port);
400 CopyIp6AddressTo(metadata.mIp6Address, &addr6.sin6_addr);
401 bytesSent = sendto(mFd6, buffer, length, 0, reinterpret_cast<struct sockaddr *>(&addr6), sizeof(addr6));
402 VerifyOrExit(bytesSent == length);
403 metadata.mIp6Port = 0;
404 mPendingIp6Tx--;
405 break;
406
407 case kIp4Msg:
408 memset(&addr, 0, sizeof(addr));
409 addr.sin_family = AF_INET;
410 addr.sin_port = htons(metadata.mIp4Port);
411 memcpy(&addr.sin_addr.s_addr, &metadata.mIp4Address, sizeof(otIp4Address));
412 bytesSent = sendto(mFd4, buffer, length, 0, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr));
413 VerifyOrExit(bytesSent == length);
414 metadata.mIp4Port = 0;
415 mPendingIp4Tx--;
416 break;
417 }
418
419 if (metadata.CanFreeMessage())
420 {
421 otMessageQueueDequeue(&mTxQueue, message);
422 otMessageFree(message);
423 }
424 else
425 {
426 otMessageWrite(message, offset, &metadata, sizeof(Metadata));
427 }
428 }
429
430 exit:
431 return;
432 }
433
ReceiveMessage(MsgType aMsgType)434 void MdnsSocket::ReceiveMessage(MsgType aMsgType)
435 {
436 otMessage *message = nullptr;
437 uint8_t buffer[kMaxMessageLength];
438 otPlatMdnsAddressInfo addrInfo;
439 uint16_t length = 0;
440 struct sockaddr_in6 sockaddr6;
441 struct sockaddr_in sockaddr;
442 socklen_t len = sizeof(sockaddr6);
443 ssize_t rval;
444
445 memset(&addrInfo, 0, sizeof(addrInfo));
446
447 switch (aMsgType)
448 {
449 case kIp6Msg:
450 len = sizeof(sockaddr6);
451 memset(&sockaddr6, 0, sizeof(sockaddr6));
452 rval = recvfrom(mFd6, reinterpret_cast<char *>(&buffer), sizeof(buffer), 0,
453 reinterpret_cast<struct sockaddr *>(&sockaddr6), &len);
454 VerifyOrExit(rval >= 0, LogCrit("recvfrom() for IPv6 socket failed, errno: %s", strerror(errno)));
455 length = static_cast<uint16_t>(rval);
456 ReadIp6AddressFrom(&sockaddr6.sin6_addr, addrInfo.mAddress);
457 break;
458
459 case kIp4Msg:
460 len = sizeof(sockaddr);
461 memset(&sockaddr, 0, sizeof(sockaddr));
462 rval = recvfrom(mFd4, reinterpret_cast<char *>(&buffer), sizeof(buffer), 0,
463 reinterpret_cast<struct sockaddr *>(&sockaddr), &len);
464 VerifyOrExit(rval >= 0, LogCrit("recvfrom() for IPv4 socket failed, errno: %s", strerror(errno)));
465 length = static_cast<uint16_t>(rval);
466 otIp4ToIp4MappedIp6Address((otIp4Address *)(&sockaddr.sin_addr.s_addr), &addrInfo.mAddress);
467 break;
468 }
469
470 VerifyOrExit(length > 0);
471
472 message = otIp6NewMessage(mInstance, nullptr);
473 VerifyOrExit(message != nullptr);
474 SuccessOrExit(otMessageAppend(message, buffer, length));
475
476 addrInfo.mPort = kMdnsPort;
477 addrInfo.mInfraIfIndex = mInfraIfIndex;
478
479 otPlatMdnsHandleReceive(mInstance, message, /* aInUnicast */ false, &addrInfo);
480 message = nullptr;
481
482 exit:
483 if (message != nullptr)
484 {
485 otMessageFree(message);
486 }
487 }
488
489 //---------------------------------------------------------------------------------------------------------------------
490 // Socket helpers
491
OpenIp4Socket(uint32_t aInfraIfIndex)492 otError MdnsSocket::OpenIp4Socket(uint32_t aInfraIfIndex)
493 {
494 otError error = OT_ERROR_FAILED;
495 struct sockaddr_in addr;
496 int fd;
497
498 fd = socket(AF_INET, SOCK_DGRAM, 0);
499 VerifyOrExit(fd >= 0, LogCrit("Failed to create IPv4 socket"));
500
501 #ifdef __linux__
502 {
503 char nameBuffer[IF_NAMESIZE];
504 const char *ifname;
505
506 ifname = if_indextoname(aInfraIfIndex, nameBuffer);
507 VerifyOrExit(ifname != NULL, LogCrit("if_indextoname() failed"));
508
509 error = SetSocketOptionValue(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname), "SO_BINDTODEVICE");
510 SuccessOrExit(error);
511 }
512 #else
513 {
514 int ifindex = static_cast<int>(aInfraIfIndex);
515
516 SuccessOrExit(error = SetSocketOption<int>(fd, IPPROTO_IP, IP_BOUND_IF, ifindex, "IP_BOUND_IF"));
517 }
518 #endif
519
520 SuccessOrExit(error = SetSocketOption<uint8_t>(fd, IPPROTO_IP, IP_MULTICAST_TTL, 255, "IP_MULTICAST_TTL"));
521 SuccessOrExit(error = SetSocketOption<int>(fd, IPPROTO_IP, IP_TTL, 255, "IP_TTL"));
522 SuccessOrExit(error = SetSocketOption<uint8_t>(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 1, "IP_MULTICAST_LOOP"));
523 SuccessOrExit(error = SetReuseAddrPortOptions(fd));
524
525 {
526 struct ip_mreqn mreqn;
527
528 memset(&mreqn, 0, sizeof(mreqn));
529 mreqn.imr_multiaddr.s_addr = inet_addr("224.0.0.251");
530 mreqn.imr_ifindex = aInfraIfIndex;
531
532 SuccessOrExit(
533 error = SetSocketOptionValue(fd, IPPROTO_IP, IP_MULTICAST_IF, &mreqn, sizeof(mreqn), "IP_MULTICAST_IF"));
534 }
535
536 memset(&addr, 0, sizeof(addr));
537 addr.sin_family = AF_INET;
538 addr.sin_addr.s_addr = htonl(INADDR_ANY);
539 addr.sin_port = htons(kMdnsPort);
540
541 if (bind(fd, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)) < 0)
542 {
543 LogCrit("bind() to mDNS port for IPv4 socket failed, errno: %s", strerror(errno));
544 error = OT_ERROR_FAILED;
545 ExitNow();
546 }
547
548 mFd4 = fd;
549
550 LogInfo("Successfully opened IPv4 socket");
551
552 exit:
553 return error;
554 }
555
JoinOrLeaveIp4MulticastGroup(bool aJoin,uint32_t aInfraIfIndex)556 otError MdnsSocket::JoinOrLeaveIp4MulticastGroup(bool aJoin, uint32_t aInfraIfIndex)
557 {
558 struct ip_mreqn mreqn;
559
560 memset(&mreqn, 0, sizeof(mreqn));
561 memcpy(&mreqn.imr_multiaddr.s_addr, &mMulticastIp4Address, sizeof(otIp4Address));
562 mreqn.imr_ifindex = aInfraIfIndex;
563
564 if (aJoin)
565 {
566 // Suggested workaround for netif not dropping
567 // a previous multicast membership.
568 setsockopt(mFd4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
569 }
570
571 return SetSocketOption(mFd4, IPPROTO_IP, aJoin ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, mreqn,
572 "IP_ADD/DROP_MEMBERSHIP");
573 }
574
CloseIp4Socket(void)575 void MdnsSocket::CloseIp4Socket(void)
576 {
577 if (mFd4 >= 0)
578 {
579 close(mFd4);
580 mFd4 = -1;
581 }
582 }
583
OpenIp6Socket(uint32_t aInfraIfIndex)584 otError MdnsSocket::OpenIp6Socket(uint32_t aInfraIfIndex)
585 {
586 otError error = OT_ERROR_FAILED;
587 struct sockaddr_in6 addr6;
588 int fd;
589 int ifindex = static_cast<int>(aInfraIfIndex);
590
591 fd = socket(AF_INET6, SOCK_DGRAM, 0);
592 VerifyOrExit(fd >= 0, LogCrit("Failed to create IPv4 socket"));
593
594 #ifdef __linux__
595 {
596 char nameBuffer[IF_NAMESIZE];
597 const char *ifname;
598
599 ifname = if_indextoname(aInfraIfIndex, nameBuffer);
600 VerifyOrExit(ifname != NULL, LogCrit("if_indextoname() failed"));
601
602 error = SetSocketOptionValue(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname), "SO_BINDTODEVICE");
603 SuccessOrExit(error);
604 }
605 #else
606 {
607 SuccessOrExit(error = SetSocketOption<int>(fd, IPPROTO_IPV6, IPV6_BOUND_IF, ifindex, "IPV6_BOUND_IF"));
608 }
609 #endif
610
611 SuccessOrExit(error = SetSocketOption<int>(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 255, "IPV6_MULTICAST_HOPS"));
612 SuccessOrExit(error = SetSocketOption<int>(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 255, "IPV6_UNICAST_HOPS"));
613 SuccessOrExit(error = SetSocketOption<int>(fd, IPPROTO_IPV6, IPV6_V6ONLY, 1, "IPV6_V6ONLY"));
614 SuccessOrExit(error = SetSocketOption<int>(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, ifindex, "IPV6_MULTICAST_IF"));
615 SuccessOrExit(error = SetSocketOption<int>(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 1, "IPV6_MULTICAST_LOOP"));
616 SuccessOrExit(error = SetReuseAddrPortOptions(fd));
617
618 memset(&addr6, 0, sizeof(addr6));
619 addr6.sin6_family = AF_INET6;
620 addr6.sin6_port = htons(kMdnsPort);
621
622 if (bind(fd, reinterpret_cast<struct sockaddr *>(&addr6), sizeof(addr6)) < 0)
623 {
624 LogCrit("bind() to mDNS port for IPv6 socket failed, errno: %s", strerror(errno));
625 error = OT_ERROR_FAILED;
626 ExitNow();
627 }
628
629 mFd6 = fd;
630
631 LogInfo("Successfully opened IPv6 socket");
632
633 exit:
634 return error;
635 }
636
637 #ifndef IPV6_ADD_MEMBERSHIP
638 #ifdef IPV6_JOIN_GROUP
639 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
640 #endif
641 #endif
642
643 #ifndef IPV6_DROP_MEMBERSHIP
644 #ifdef IPV6_LEAVE_GROUP
645 #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
646 #endif
647 #endif
648
JoinOrLeaveIp6MulticastGroup(bool aJoin,uint32_t aInfraIfIndex)649 otError MdnsSocket::JoinOrLeaveIp6MulticastGroup(bool aJoin, uint32_t aInfraIfIndex)
650 {
651 struct ipv6_mreq mreq6;
652
653 memset(&mreq6, 0, sizeof(mreq6));
654 Ip6Utils::CopyIp6AddressTo(mMulticastIp6Address, &mreq6.ipv6mr_multiaddr);
655
656 mreq6.ipv6mr_interface = static_cast<int>(aInfraIfIndex);
657
658 if (aJoin)
659 {
660 // Suggested workaround for netif not dropping
661 // a previous multicast membership.
662 setsockopt(mFd6, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6));
663 }
664
665 return SetSocketOptionValue(mFd6, IPPROTO_IPV6, aJoin ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq6,
666 sizeof(mreq6), "IP6_ADD/DROP_MEMBERSHIP");
667 }
668
CloseIp6Socket(void)669 void MdnsSocket::CloseIp6Socket(void)
670 {
671 if (mFd6 >= 0)
672 {
673 close(mFd6);
674 mFd6 = -1;
675 }
676 }
677
SetReuseAddrPortOptions(int aFd)678 otError MdnsSocket::SetReuseAddrPortOptions(int aFd)
679 {
680 otError error;
681
682 SuccessOrExit(error = SetSocketOption<int>(aFd, SOL_SOCKET, SO_REUSEADDR, 1, "SO_REUSEADDR"));
683 SuccessOrExit(error = SetSocketOption<int>(aFd, SOL_SOCKET, SO_REUSEPORT, 1, "SO_REUSEPORT"));
684
685 exit:
686 return error;
687 }
688
SetSocketOptionValue(int aFd,int aLevel,int aOption,const void * aValue,uint32_t aValueLength,const char * aOptionName)689 otError MdnsSocket::SetSocketOptionValue(int aFd,
690 int aLevel,
691 int aOption,
692 const void *aValue,
693 uint32_t aValueLength,
694 const char *aOptionName)
695 {
696 otError error = OT_ERROR_NONE;
697
698 if (setsockopt(aFd, aLevel, aOption, aValue, aValueLength) != 0)
699 {
700 error = OT_ERROR_FAILED;
701 LogCrit("Failed to setsockopt(%s) - errno: %s", aOptionName, strerror(errno));
702 }
703
704 return error;
705 }
706
707 } // namespace Posix
708 } // namespace ot
709
710 #endif // OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE
711