1 /*
2  *  Copyright (c) 2016, 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 /**
30  * @file
31  *   This file implements UDP/IPv6 sockets.
32  */
33 
34 #include "udp6.hpp"
35 
36 #include <stdio.h>
37 
38 #include <openthread/platform/udp.h>
39 
40 #include "common/code_utils.hpp"
41 #include "common/encoding.hpp"
42 #include "common/instance.hpp"
43 #include "common/locator_getters.hpp"
44 #include "net/checksum.hpp"
45 #include "net/ip6.hpp"
46 
47 namespace ot {
48 namespace Ip6 {
49 
Matches(const MessageInfo & aMessageInfo) const50 bool Udp::SocketHandle::Matches(const MessageInfo &aMessageInfo) const
51 {
52     bool matches = false;
53 
54     VerifyOrExit(GetSockName().mPort == aMessageInfo.GetSockPort());
55 
56     VerifyOrExit(aMessageInfo.GetSockAddr().IsMulticast() || GetSockName().GetAddress().IsUnspecified() ||
57                  GetSockName().GetAddress() == aMessageInfo.GetSockAddr());
58 
59     // Verify source if connected socket
60     if (GetPeerName().mPort != 0)
61     {
62         VerifyOrExit(GetPeerName().mPort == aMessageInfo.GetPeerPort());
63 
64         VerifyOrExit(GetPeerName().GetAddress().IsUnspecified() ||
65                      GetPeerName().GetAddress() == aMessageInfo.GetPeerAddr());
66     }
67 
68     matches = true;
69 
70 exit:
71     return matches;
72 }
73 
Socket(Instance & aInstance)74 Udp::Socket::Socket(Instance &aInstance)
75     : InstanceLocator(aInstance)
76 {
77     Clear();
78 }
79 
NewMessage(uint16_t aReserved,const Message::Settings & aSettings)80 Message *Udp::Socket::NewMessage(uint16_t aReserved, const Message::Settings &aSettings)
81 {
82     return Get<Udp>().NewMessage(aReserved, aSettings);
83 }
84 
Open(otUdpReceive aHandler,void * aContext)85 Error Udp::Socket::Open(otUdpReceive aHandler, void *aContext)
86 {
87     return Get<Udp>().Open(*this, aHandler, aContext);
88 }
89 
IsOpen(void) const90 bool Udp::Socket::IsOpen(void) const
91 {
92     return Get<Udp>().IsOpen(*this);
93 }
94 
Bind(const SockAddr & aSockAddr,otNetifIdentifier aNetifIdentifier)95 Error Udp::Socket::Bind(const SockAddr &aSockAddr, otNetifIdentifier aNetifIdentifier)
96 {
97     return Get<Udp>().Bind(*this, aSockAddr, aNetifIdentifier);
98 }
99 
Bind(uint16_t aPort,otNetifIdentifier aNetifIdentifier)100 Error Udp::Socket::Bind(uint16_t aPort, otNetifIdentifier aNetifIdentifier)
101 {
102     return Bind(SockAddr(aPort), aNetifIdentifier);
103 }
104 
Connect(const SockAddr & aSockAddr)105 Error Udp::Socket::Connect(const SockAddr &aSockAddr)
106 {
107     return Get<Udp>().Connect(*this, aSockAddr);
108 }
109 
Connect(uint16_t aPort)110 Error Udp::Socket::Connect(uint16_t aPort)
111 {
112     return Connect(SockAddr(aPort));
113 }
114 
Close(void)115 Error Udp::Socket::Close(void)
116 {
117     return Get<Udp>().Close(*this);
118 }
119 
SendTo(Message & aMessage,const MessageInfo & aMessageInfo)120 Error Udp::Socket::SendTo(Message &aMessage, const MessageInfo &aMessageInfo)
121 {
122     return Get<Udp>().SendTo(*this, aMessage, aMessageInfo);
123 }
124 
125 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
JoinNetifMulticastGroup(otNetifIdentifier aNetifIdentifier,const Address & aAddress)126 Error Udp::Socket::JoinNetifMulticastGroup(otNetifIdentifier aNetifIdentifier, const Address &aAddress)
127 {
128     OT_UNUSED_VARIABLE(aNetifIdentifier);
129     OT_UNUSED_VARIABLE(aAddress);
130 
131     Error error = kErrorNotImplemented;
132 
133     VerifyOrExit(aAddress.IsMulticast(), error = kErrorInvalidArgs);
134 
135 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
136     error = otPlatUdpJoinMulticastGroup(this, aNetifIdentifier, &aAddress);
137 #endif
138 
139 exit:
140     return error;
141 }
142 
LeaveNetifMulticastGroup(otNetifIdentifier aNetifIdentifier,const Address & aAddress)143 Error Udp::Socket::LeaveNetifMulticastGroup(otNetifIdentifier aNetifIdentifier, const Address &aAddress)
144 {
145     OT_UNUSED_VARIABLE(aNetifIdentifier);
146     OT_UNUSED_VARIABLE(aAddress);
147 
148     Error error = kErrorNotImplemented;
149 
150     VerifyOrExit(aAddress.IsMulticast(), error = kErrorInvalidArgs);
151 
152 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
153     error = otPlatUdpLeaveMulticastGroup(this, aNetifIdentifier, &aAddress);
154 #endif
155 
156 exit:
157     return error;
158 }
159 #endif
160 
Udp(Instance & aInstance)161 Udp::Udp(Instance &aInstance)
162     : InstanceLocator(aInstance)
163     , mEphemeralPort(kDynamicPortMin)
164 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
165     , mPrevBackboneSockets(nullptr)
166 #endif
167 #if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE
168     , mUdpForwarderContext(nullptr)
169     , mUdpForwarder(nullptr)
170 #endif
171 {
172 }
173 
AddReceiver(Receiver & aReceiver)174 Error Udp::AddReceiver(Receiver &aReceiver)
175 {
176     return mReceivers.Add(aReceiver);
177 }
178 
RemoveReceiver(Receiver & aReceiver)179 Error Udp::RemoveReceiver(Receiver &aReceiver)
180 {
181     Error error;
182 
183     SuccessOrExit(error = mReceivers.Remove(aReceiver));
184     aReceiver.SetNext(nullptr);
185 
186 exit:
187     return error;
188 }
189 
Open(SocketHandle & aSocket,otUdpReceive aHandler,void * aContext)190 Error Udp::Open(SocketHandle &aSocket, otUdpReceive aHandler, void *aContext)
191 {
192     Error error = kErrorNone;
193 
194     OT_ASSERT(!IsOpen(aSocket));
195 
196     aSocket.GetSockName().Clear();
197     aSocket.GetPeerName().Clear();
198     aSocket.mHandler = aHandler;
199     aSocket.mContext = aContext;
200 
201 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
202     error = otPlatUdpSocket(&aSocket);
203 #endif
204     SuccessOrExit(error);
205 
206     AddSocket(aSocket);
207 
208 exit:
209     return error;
210 }
211 
Bind(SocketHandle & aSocket,const SockAddr & aSockAddr,otNetifIdentifier aNetifIdentifier)212 Error Udp::Bind(SocketHandle &aSocket, const SockAddr &aSockAddr, otNetifIdentifier aNetifIdentifier)
213 {
214     OT_UNUSED_VARIABLE(aNetifIdentifier);
215 
216     Error error = kErrorNone;
217 
218 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
219     SuccessOrExit(error = otPlatUdpBindToNetif(&aSocket, aNetifIdentifier));
220 #endif
221 
222 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
223     if (aNetifIdentifier == OT_NETIF_BACKBONE)
224     {
225         SetBackboneSocket(aSocket);
226     }
227 #endif
228 
229     VerifyOrExit(aSockAddr.GetAddress().IsUnspecified() || Get<ThreadNetif>().HasUnicastAddress(aSockAddr.GetAddress()),
230                  error = kErrorInvalidArgs);
231 
232     aSocket.mSockName = aSockAddr;
233 
234     if (!aSocket.IsBound())
235     {
236         do
237         {
238             aSocket.mSockName.mPort = GetEphemeralPort();
239 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
240             error = otPlatUdpBind(&aSocket);
241 #endif
242         } while (error != kErrorNone);
243     }
244 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
245     else if (ShouldUsePlatformUdp(aSocket))
246     {
247         error = otPlatUdpBind(&aSocket);
248     }
249 #endif
250 
251 exit:
252     return error;
253 }
254 
255 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
SetBackboneSocket(SocketHandle & aSocket)256 void Udp::SetBackboneSocket(SocketHandle &aSocket)
257 {
258     RemoveSocket(aSocket);
259 
260     if (mPrevBackboneSockets != nullptr)
261     {
262         mSockets.PushAfter(aSocket, *mPrevBackboneSockets);
263     }
264     else
265     {
266         mSockets.Push(aSocket);
267     }
268 }
269 
GetBackboneSockets(void) const270 const Udp::SocketHandle *Udp::GetBackboneSockets(void) const
271 {
272     return mPrevBackboneSockets != nullptr ? mPrevBackboneSockets->GetNext() : mSockets.GetHead();
273 }
274 
IsBackboneSocket(const SocketHandle & aSocket) const275 bool Udp::IsBackboneSocket(const SocketHandle &aSocket) const
276 {
277     bool retval = false;
278 
279     for (const SocketHandle *sock = GetBackboneSockets(); sock != nullptr; sock = sock->GetNext())
280     {
281         if (sock == &aSocket)
282         {
283             ExitNow(retval = true);
284         }
285     }
286 
287 exit:
288     return retval;
289 }
290 #endif
291 
Connect(SocketHandle & aSocket,const SockAddr & aSockAddr)292 Error Udp::Connect(SocketHandle &aSocket, const SockAddr &aSockAddr)
293 {
294     Error error = kErrorNone;
295 
296     aSocket.mPeerName = aSockAddr;
297 
298     if (!aSocket.IsBound())
299     {
300         SuccessOrExit(error = Bind(aSocket, aSocket.GetSockName(), OT_NETIF_THREAD));
301     }
302 
303 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
304     if (ShouldUsePlatformUdp(aSocket))
305     {
306         error = otPlatUdpConnect(&aSocket);
307     }
308 #endif
309 
310 exit:
311     return error;
312 }
313 
Close(SocketHandle & aSocket)314 Error Udp::Close(SocketHandle &aSocket)
315 {
316     Error error = kErrorNone;
317 
318     VerifyOrExit(IsOpen(aSocket));
319 
320 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
321     error = otPlatUdpClose(&aSocket);
322 #endif
323     SuccessOrExit(error);
324 
325     RemoveSocket(aSocket);
326     aSocket.GetSockName().Clear();
327     aSocket.GetPeerName().Clear();
328 
329 exit:
330     return error;
331 }
332 
SendTo(SocketHandle & aSocket,Message & aMessage,const MessageInfo & aMessageInfo)333 Error Udp::SendTo(SocketHandle &aSocket, Message &aMessage, const MessageInfo &aMessageInfo)
334 {
335     Error       error = kErrorNone;
336     MessageInfo messageInfoLocal;
337 
338     VerifyOrExit((aMessageInfo.GetSockPort() == 0) || (aSocket.GetSockName().mPort == aMessageInfo.GetSockPort()),
339                  error = kErrorInvalidArgs);
340 
341     messageInfoLocal = aMessageInfo;
342 
343     if (messageInfoLocal.GetPeerAddr().IsUnspecified())
344     {
345         VerifyOrExit(!aSocket.GetPeerName().GetAddress().IsUnspecified(), error = kErrorInvalidArgs);
346 
347         messageInfoLocal.SetPeerAddr(aSocket.GetPeerName().GetAddress());
348     }
349 
350     if (messageInfoLocal.mPeerPort == 0)
351     {
352         VerifyOrExit(aSocket.GetPeerName().mPort != 0, error = kErrorInvalidArgs);
353         messageInfoLocal.mPeerPort = aSocket.GetPeerName().mPort;
354     }
355 
356     if (messageInfoLocal.GetSockAddr().IsUnspecified())
357     {
358         messageInfoLocal.SetSockAddr(aSocket.GetSockName().GetAddress());
359     }
360 
361     if (!aSocket.IsBound())
362     {
363         SuccessOrExit(error = Bind(aSocket, aSocket.GetSockName(), OT_NETIF_THREAD));
364     }
365 
366     messageInfoLocal.SetSockPort(aSocket.GetSockName().mPort);
367 
368 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
369     if (ShouldUsePlatformUdp(aSocket))
370     {
371         SuccessOrExit(error = otPlatUdpSend(&aSocket, &aMessage, &messageInfoLocal));
372     }
373     else
374 #endif
375     {
376         SuccessOrExit(error = SendDatagram(aMessage, messageInfoLocal, kProtoUdp));
377     }
378 
379 exit:
380     return error;
381 }
382 
IsPortReserved(uint16_t aPort)383 bool Udp::IsPortReserved(uint16_t aPort)
384 {
385     return aPort == Tmf::kUdpPort || (kSrpServerPortMin <= aPort && aPort <= kSrpServerPortMax);
386 }
387 
AddSocket(SocketHandle & aSocket)388 void Udp::AddSocket(SocketHandle &aSocket)
389 {
390     SuccessOrExit(mSockets.Add(aSocket));
391 
392 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
393     if (mPrevBackboneSockets == nullptr)
394     {
395         mPrevBackboneSockets = &aSocket;
396     }
397 #endif
398 exit:
399     return;
400 }
401 
RemoveSocket(SocketHandle & aSocket)402 void Udp::RemoveSocket(SocketHandle &aSocket)
403 {
404     SocketHandle *prev;
405 
406     SuccessOrExit(mSockets.Find(aSocket, prev));
407 
408     mSockets.PopAfter(prev);
409     aSocket.SetNext(nullptr);
410 
411 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
412     if (&aSocket == mPrevBackboneSockets)
413     {
414         mPrevBackboneSockets = prev;
415     }
416 #endif
417 
418 exit:
419     return;
420 }
421 
GetEphemeralPort(void)422 uint16_t Udp::GetEphemeralPort(void)
423 {
424     do
425     {
426         if (mEphemeralPort < kDynamicPortMax)
427         {
428             mEphemeralPort++;
429         }
430         else
431         {
432             mEphemeralPort = kDynamicPortMin;
433         }
434     } while (IsPortReserved(mEphemeralPort));
435 
436     return mEphemeralPort;
437 }
438 
NewMessage(uint16_t aReserved,const Message::Settings & aSettings)439 Message *Udp::NewMessage(uint16_t aReserved, const Message::Settings &aSettings)
440 {
441     return Get<Ip6>().NewMessage(sizeof(Header) + aReserved, aSettings);
442 }
443 
SendDatagram(Message & aMessage,MessageInfo & aMessageInfo,uint8_t aIpProto)444 Error Udp::SendDatagram(Message &aMessage, MessageInfo &aMessageInfo, uint8_t aIpProto)
445 {
446     Error error = kErrorNone;
447 
448 #if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE
449     if (aMessageInfo.IsHostInterface())
450     {
451         VerifyOrExit(mUdpForwarder != nullptr, error = kErrorNoRoute);
452         mUdpForwarder(&aMessage, aMessageInfo.mPeerPort, &aMessageInfo.GetPeerAddr(), aMessageInfo.mSockPort,
453                       mUdpForwarderContext);
454         // message is consumed by the callback
455     }
456     else
457 #endif
458     {
459         Header udpHeader;
460 
461         udpHeader.SetSourcePort(aMessageInfo.mSockPort);
462         udpHeader.SetDestinationPort(aMessageInfo.mPeerPort);
463         udpHeader.SetLength(sizeof(udpHeader) + aMessage.GetLength());
464         udpHeader.SetChecksum(0);
465 
466         SuccessOrExit(error = aMessage.Prepend(udpHeader));
467         aMessage.SetOffset(0);
468 
469         error = Get<Ip6>().SendDatagram(aMessage, aMessageInfo, aIpProto);
470     }
471 
472 exit:
473     return error;
474 }
475 
HandleMessage(Message & aMessage,MessageInfo & aMessageInfo)476 Error Udp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo)
477 {
478     Error  error = kErrorNone;
479     Header udpHeader;
480 
481     SuccessOrExit(error = aMessage.Read(aMessage.GetOffset(), udpHeader));
482 
483 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
484     SuccessOrExit(error = Checksum::VerifyMessageChecksum(aMessage, aMessageInfo, kProtoUdp));
485 #endif
486 
487     aMessage.MoveOffset(sizeof(udpHeader));
488     aMessageInfo.mPeerPort = udpHeader.GetSourcePort();
489     aMessageInfo.mSockPort = udpHeader.GetDestinationPort();
490 
491 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
492     VerifyOrExit(!ShouldUsePlatformUdp(aMessageInfo.mSockPort) || IsPortInUse(aMessageInfo.mSockPort));
493 #endif
494 
495     for (Receiver &receiver : mReceivers)
496     {
497         VerifyOrExit(!receiver.HandleMessage(aMessage, aMessageInfo));
498     }
499 
500     HandlePayload(aMessage, aMessageInfo);
501 
502 exit:
503     return error;
504 }
505 
HandlePayload(Message & aMessage,MessageInfo & aMessageInfo)506 void Udp::HandlePayload(Message &aMessage, MessageInfo &aMessageInfo)
507 {
508     SocketHandle *socket;
509     SocketHandle *prev;
510 
511 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
512     {
513         const SocketHandle *socketsBegin, *socketsEnd;
514 
515         if (!aMessageInfo.IsHostInterface())
516         {
517             socketsBegin = mSockets.GetHead();
518             socketsEnd   = GetBackboneSockets();
519         }
520         else
521         {
522             socketsBegin = GetBackboneSockets();
523             socketsEnd   = nullptr;
524         }
525 
526         socket = mSockets.FindMatching(socketsBegin, socketsEnd, aMessageInfo, prev);
527     }
528 #else
529     socket = mSockets.FindMatching(aMessageInfo, prev);
530 #endif
531 
532     VerifyOrExit(socket != nullptr);
533 
534     aMessage.RemoveHeader(aMessage.GetOffset());
535     OT_ASSERT(aMessage.GetOffset() == 0);
536     socket->HandleUdpReceive(aMessage, aMessageInfo);
537 
538 exit:
539     return;
540 }
541 
IsPortInUse(uint16_t aPort) const542 bool Udp::IsPortInUse(uint16_t aPort) const
543 {
544     bool found = false;
545 
546     for (const SocketHandle &socket : mSockets)
547     {
548         if (socket.GetSockName().GetPort() == aPort)
549         {
550             found = true;
551             break;
552         }
553     }
554 
555     return found;
556 }
557 
ShouldUsePlatformUdp(uint16_t aPort) const558 bool Udp::ShouldUsePlatformUdp(uint16_t aPort) const
559 {
560     return (aPort != Mle::kUdpPort && aPort != Tmf::kUdpPort
561 #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE && !OPENTHREAD_CONFIG_DNSSD_SERVER_BIND_UNSPECIFIED_NETIF
562             && aPort != Dns::ServiceDiscovery::Server::kPort
563 #endif
564 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
565             && aPort != Get<MeshCoP::BorderAgent>().GetUdpProxyPort()
566 #endif
567 #if OPENTHREAD_FTD
568             && aPort != Get<MeshCoP::JoinerRouter>().GetJoinerUdpPort()
569 #endif
570     );
571 }
572 
573 #if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
ShouldUsePlatformUdp(const Udp::SocketHandle & aSocket) const574 bool Udp::ShouldUsePlatformUdp(const Udp::SocketHandle &aSocket) const
575 {
576     return (ShouldUsePlatformUdp(aSocket.mSockName.mPort)
577 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
578             || IsBackboneSocket(aSocket)
579 #endif
580     );
581 }
582 #endif // OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
583 
584 } // namespace Ip6
585 } // namespace ot
586