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