Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : * Copyright (c) 2018 Google LLC.
5 : * Copyright (c) 2013-2018 Nest Labs, Inc.
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : /**
21 : * This file implements Inet::UDPEndPoint using sockets.
22 : */
23 :
24 : // Required to properly support underlying RFC3542-related fields to IPV6_PKTINFO
25 : // on Darwin.
26 : #define __APPLE_USE_RFC_3542
27 : #include <inet/UDPEndPointImplSockets.h>
28 :
29 : #include <lib/support/CodeUtils.h>
30 : #include <lib/support/SafeInt.h>
31 : #include <lib/support/logging/CHIPLogging.h>
32 :
33 : #if CHIP_SYSTEM_CONFIG_USE_POSIX_SOCKETS
34 : #if HAVE_SYS_SOCKET_H
35 : #include <sys/socket.h>
36 : #endif // HAVE_SYS_SOCKET_H
37 : #include <net/if.h>
38 : #include <netinet/in.h>
39 : #include <sys/ioctl.h>
40 : #endif // CHIP_SYSTEM_CONFIG_USE_POSIX_SOCKETS
41 :
42 : #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKETS
43 : #include <zephyr/net/socket.h>
44 : #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKETS
45 :
46 : #include <cerrno>
47 : #include <unistd.h>
48 : #include <utility>
49 :
50 : // SOCK_CLOEXEC not defined on all platforms, e.g. iOS/macOS:
51 : #ifndef SOCK_CLOEXEC
52 : #define SOCK_CLOEXEC 0
53 : #endif
54 :
55 : // On MbedOS, INADDR_ANY does not seem to exist...
56 : #ifndef INADDR_ANY
57 : #define INADDR_ANY 0
58 : #endif
59 :
60 : #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKET_EXTENSIONS
61 : #include "ZephyrSocket.h"
62 : #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKET_EXTENSIONS
63 :
64 : /*
65 : * Some systems define both IPV6_{ADD,DROP}_MEMBERSHIP and
66 : * IPV6_{JOIN,LEAVE}_GROUP while others only define
67 : * IPV6_{JOIN,LEAVE}_GROUP. Prefer the "_MEMBERSHIP" flavor for
68 : * parallelism with IPv4 and create the alias to the availabile
69 : * definitions.
70 : */
71 : #if defined(IPV6_ADD_MEMBERSHIP)
72 : #define INET_IPV6_ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP
73 : #elif defined(IPV6_JOIN_GROUP)
74 : #define INET_IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
75 : #elif !CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
76 : #error \
77 : "Neither IPV6_ADD_MEMBERSHIP nor IPV6_JOIN_GROUP are defined which are required for generalized IPv6 multicast group support."
78 : #endif // IPV6_ADD_MEMBERSHIP
79 :
80 : #if defined(IPV6_DROP_MEMBERSHIP)
81 : #define INET_IPV6_DROP_MEMBERSHIP IPV6_DROP_MEMBERSHIP
82 : #elif defined(IPV6_LEAVE_GROUP)
83 : #define INET_IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
84 : #elif !CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
85 : #error \
86 : "Neither IPV6_DROP_MEMBERSHIP nor IPV6_LEAVE_GROUP are defined which are required for generalized IPv6 multicast group support."
87 : #endif // IPV6_DROP_MEMBERSHIP
88 :
89 : namespace chip {
90 : namespace Inet {
91 :
92 : namespace {
93 :
94 33 : CHIP_ERROR IPv6Bind(int socket, const IPAddress & address, uint16_t port, InterfaceId interface)
95 : {
96 : struct sockaddr_in6 sa;
97 33 : memset(&sa, 0, sizeof(sa));
98 33 : sa.sin6_family = AF_INET6;
99 33 : sa.sin6_port = htons(port);
100 33 : sa.sin6_addr = address.ToIPv6();
101 33 : InterfaceId::PlatformType interfaceId = interface.GetPlatformInterface();
102 33 : if (!CanCastTo<decltype(sa.sin6_scope_id)>(interfaceId))
103 : {
104 0 : return CHIP_ERROR_INCORRECT_STATE;
105 : }
106 33 : sa.sin6_scope_id = static_cast<decltype(sa.sin6_scope_id)>(interfaceId);
107 :
108 33 : CHIP_ERROR status = CHIP_NO_ERROR;
109 :
110 : // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): Function called only with valid socket after GetSocket
111 33 : if (bind(socket, reinterpret_cast<const sockaddr *>(&sa), static_cast<unsigned>(sizeof(sa))) != 0)
112 : {
113 0 : status = CHIP_ERROR_POSIX(errno);
114 : }
115 : else
116 : {
117 : #ifdef IPV6_MULTICAST_IF
118 : // Instruct the kernel that any messages to multicast destinations should be
119 : // sent down the interface specified by the caller.
120 33 : setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_IF, &interfaceId, sizeof(interfaceId));
121 : #endif // defined(IPV6_MULTICAST_IF)
122 : }
123 :
124 : #ifdef IPV6_MULTICAST_HOPS
125 : // Instruct the kernel that any messages to multicast destinations should be
126 : // set with the configured hop limit value.
127 33 : int hops = INET_CONFIG_IP_MULTICAST_HOP_LIMIT;
128 33 : setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops));
129 : #endif // defined(IPV6_MULTICAST_HOPS)
130 :
131 33 : return status;
132 : }
133 :
134 : #if INET_CONFIG_ENABLE_IPV4
135 32 : CHIP_ERROR IPv4Bind(int socket, const IPAddress & address, uint16_t port)
136 : {
137 : struct sockaddr_in sa;
138 32 : memset(&sa, 0, sizeof(sa));
139 32 : sa.sin_family = AF_INET;
140 32 : sa.sin_port = htons(port);
141 32 : sa.sin_addr = address.ToIPv4();
142 :
143 32 : CHIP_ERROR status = CHIP_NO_ERROR;
144 :
145 : // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): Function called only with valid socket after GetSocket
146 32 : if (bind(socket, reinterpret_cast<const sockaddr *>(&sa), static_cast<unsigned>(sizeof(sa))) != 0)
147 : {
148 1 : status = CHIP_ERROR_POSIX(errno);
149 : }
150 : else
151 : {
152 : // Allow socket transmitting broadcast packets.
153 31 : constexpr int enable = 1;
154 31 : setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &enable, sizeof(enable));
155 :
156 : #ifdef IP_MULTICAST_IF
157 : // Instruct the kernel that any messages to multicast destinations should be
158 : // sent down the interface to which the specified IPv4 address is bound.
159 31 : setsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF, &sa, sizeof(sa));
160 : #endif // defined(IP_MULTICAST_IF)
161 : }
162 :
163 : #ifdef IP_MULTICAST_TTL
164 : // Instruct the kernel that any messages to multicast destinations should be
165 : // set with the configured hop limit value.
166 32 : constexpr int ttl = INET_CONFIG_IP_MULTICAST_HOP_LIMIT;
167 32 : setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
168 : #endif // defined(IP_MULTICAST_TTL)
169 :
170 32 : return status;
171 : }
172 : #endif // INET_CONFIG_ENABLE_IPV4
173 :
174 : } // anonymous namespace
175 :
176 : #if CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
177 : UDPEndPointImplSockets::MulticastGroupHandler UDPEndPointImplSockets::sMulticastGroupHandler;
178 : #endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
179 :
180 66 : CHIP_ERROR UDPEndPointImplSockets::BindImpl(IPAddressType addressType, const IPAddress & addr, uint16_t port, InterfaceId interface)
181 : {
182 : // Make sure we have the appropriate type of socket.
183 66 : ReturnErrorOnFailure(GetSocket(addressType));
184 :
185 65 : if (addressType == IPAddressType::kIPv6)
186 : {
187 33 : ReturnErrorOnFailure(IPv6Bind(mSocket, addr, port, interface));
188 : }
189 : #if INET_CONFIG_ENABLE_IPV4
190 32 : else if (addressType == IPAddressType::kIPv4)
191 : {
192 32 : ReturnErrorOnFailure(IPv4Bind(mSocket, addr, port));
193 : }
194 : #endif // INET_CONFIG_ENABLE_IPV4
195 : else
196 : {
197 0 : return INET_ERROR_WRONG_ADDRESS_TYPE;
198 : }
199 :
200 64 : mBoundPort = port;
201 64 : mBoundIntfId = interface;
202 :
203 : // If an ephemeral port was requested, retrieve the actual bound port.
204 64 : if (port == 0)
205 : {
206 : SockAddr boundAddr;
207 34 : socklen_t boundAddrLen = sizeof(boundAddr);
208 :
209 34 : if (getsockname(mSocket, &boundAddr.any, &boundAddrLen) == 0)
210 : {
211 34 : if (boundAddr.any.sa_family == AF_INET)
212 : {
213 17 : mBoundPort = ntohs(boundAddr.in.sin_port);
214 : }
215 17 : else if (boundAddr.any.sa_family == AF_INET6)
216 : {
217 17 : mBoundPort = ntohs(boundAddr.in6.sin6_port);
218 : }
219 : }
220 : }
221 :
222 64 : return CHIP_NO_ERROR;
223 : }
224 :
225 1 : CHIP_ERROR UDPEndPointImplSockets::BindInterfaceImpl(IPAddressType addressType, InterfaceId interfaceId)
226 : {
227 : // Make sure we have the appropriate type of socket.
228 1 : ReturnErrorOnFailure(GetSocket(addressType));
229 :
230 : #if HAVE_SO_BINDTODEVICE
231 1 : CHIP_ERROR status = CHIP_NO_ERROR;
232 :
233 1 : if (interfaceId.IsPresent())
234 : {
235 : // Start filtering on the passed interface.
236 : char interfaceName[IF_NAMESIZE];
237 1 : if (if_indextoname(interfaceId.GetPlatformInterface(), interfaceName) == nullptr)
238 : {
239 0 : status = CHIP_ERROR_POSIX(errno);
240 : }
241 1 : else if (setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, interfaceName, socklen_t(strlen(interfaceName))) == -1)
242 : {
243 0 : status = CHIP_ERROR_POSIX(errno);
244 : }
245 : }
246 : else
247 : {
248 : // Stop interface-based filtering.
249 0 : if (setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, "", 0) == -1)
250 : {
251 0 : status = CHIP_ERROR_POSIX(errno);
252 : }
253 : }
254 :
255 1 : if (status == CHIP_NO_ERROR)
256 : {
257 1 : mBoundIntfId = interfaceId;
258 : }
259 :
260 1 : return status;
261 : #else // !HAVE_SO_BINDTODEVICE
262 : return CHIP_ERROR_NOT_IMPLEMENTED;
263 : #endif // HAVE_SO_BINDTODEVICE
264 : }
265 :
266 43 : InterfaceId UDPEndPointImplSockets::GetBoundInterface() const
267 : {
268 43 : return mBoundIntfId;
269 : }
270 :
271 10 : uint16_t UDPEndPointImplSockets::GetBoundPort() const
272 : {
273 10 : return mBoundPort;
274 : }
275 :
276 64 : CHIP_ERROR UDPEndPointImplSockets::ListenImpl()
277 : {
278 : // Wait for ability to read on this endpoint.
279 64 : auto * layer = static_cast<System::LayerSockets *>(&GetSystemLayer());
280 64 : ReturnErrorOnFailure(layer->SetCallback(mWatch, HandlePendingIO, reinterpret_cast<intptr_t>(this)));
281 64 : return layer->RequestCallbackOnPendingRead(mWatch);
282 : }
283 :
284 46 : CHIP_ERROR UDPEndPointImplSockets::SendMsgImpl(const IPPacketInfo * aPktInfo, System::PacketBufferHandle && msg)
285 : {
286 : // Ensure packet buffer is not null
287 46 : VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
288 :
289 : // Make sure we have the appropriate type of socket based on the
290 : // destination address.
291 46 : ReturnErrorOnFailure(GetSocket(aPktInfo->DestAddress.Type()));
292 :
293 : // Ensure the destination address type is compatible with the endpoint address type.
294 46 : VerifyOrReturnError(mAddrType == aPktInfo->DestAddress.Type(), CHIP_ERROR_INVALID_ARGUMENT);
295 :
296 : // For now the entire message must fit within a single buffer.
297 46 : VerifyOrReturnError(!msg->HasChainedBuffer(), CHIP_ERROR_MESSAGE_TOO_LONG);
298 :
299 : struct iovec msgIOV;
300 46 : msgIOV.iov_base = msg->Start();
301 46 : msgIOV.iov_len = msg->DataLength();
302 :
303 : #if defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
304 : uint8_t controlData[256];
305 46 : memset(controlData, 0, sizeof(controlData));
306 : #endif // defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
307 :
308 : struct msghdr msgHeader;
309 46 : memset(&msgHeader, 0, sizeof(msgHeader));
310 46 : msgHeader.msg_iov = &msgIOV;
311 46 : msgHeader.msg_iovlen = 1;
312 :
313 : // Construct a sockaddr_in/sockaddr_in6 structure containing the destination information.
314 : SockAddr peerSockAddr;
315 46 : memset(&peerSockAddr, 0, sizeof(peerSockAddr));
316 46 : msgHeader.msg_name = &peerSockAddr;
317 46 : if (mAddrType == IPAddressType::kIPv6)
318 : {
319 23 : peerSockAddr.in6.sin6_family = AF_INET6;
320 23 : peerSockAddr.in6.sin6_port = htons(aPktInfo->DestPort);
321 23 : peerSockAddr.in6.sin6_addr = aPktInfo->DestAddress.ToIPv6();
322 23 : InterfaceId::PlatformType intfId = aPktInfo->Interface.GetPlatformInterface();
323 23 : VerifyOrReturnError(CanCastTo<decltype(peerSockAddr.in6.sin6_scope_id)>(intfId), CHIP_ERROR_INCORRECT_STATE);
324 23 : peerSockAddr.in6.sin6_scope_id = static_cast<decltype(peerSockAddr.in6.sin6_scope_id)>(intfId);
325 23 : msgHeader.msg_namelen = sizeof(sockaddr_in6);
326 : }
327 : #if INET_CONFIG_ENABLE_IPV4
328 : else
329 : {
330 23 : peerSockAddr.in.sin_family = AF_INET;
331 23 : peerSockAddr.in.sin_port = htons(aPktInfo->DestPort);
332 23 : peerSockAddr.in.sin_addr = aPktInfo->DestAddress.ToIPv4();
333 23 : msgHeader.msg_namelen = sizeof(sockaddr_in);
334 : }
335 : #endif // INET_CONFIG_ENABLE_IPV4
336 :
337 : // If the endpoint has been bound to a particular interface,
338 : // and the caller didn't supply a specific interface to send
339 : // on, use the bound interface. This appears to be necessary
340 : // for messages to multicast addresses, which under Linux
341 : // don't seem to get sent out the correct interface, despite
342 : // the socket being bound.
343 46 : InterfaceId intf = aPktInfo->Interface;
344 46 : if (!intf.IsPresent())
345 : {
346 4 : intf = mBoundIntfId;
347 : }
348 :
349 : #if INET_CONFIG_UDP_SOCKET_PKTINFO
350 : // If the packet should be sent over a specific interface, or with a specific source
351 : // address, construct an IP_PKTINFO/IPV6_PKTINFO "control message" to that effect
352 : // add add it to the message header. If the local OS doesn't support IP_PKTINFO/IPV6_PKTINFO
353 : // fail with an error.
354 46 : if (intf.IsPresent() || aPktInfo->SrcAddress.Type() != IPAddressType::kAny)
355 : {
356 : #if defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
357 42 : msgHeader.msg_control = controlData;
358 42 : msgHeader.msg_controllen = sizeof(controlData);
359 :
360 42 : struct cmsghdr * controlHdr = CMSG_FIRSTHDR(&msgHeader);
361 42 : InterfaceId::PlatformType intfId = intf.GetPlatformInterface();
362 :
363 : #if INET_CONFIG_ENABLE_IPV4
364 :
365 42 : if (mAddrType == IPAddressType::kIPv4)
366 : {
367 : #if defined(IP_PKTINFO)
368 21 : controlHdr->cmsg_level = IPPROTO_IP;
369 21 : controlHdr->cmsg_type = IP_PKTINFO;
370 21 : controlHdr->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
371 :
372 21 : auto * pktInfo = reinterpret_cast<struct in_pktinfo *> CMSG_DATA(controlHdr);
373 21 : if (!CanCastTo<decltype(pktInfo->ipi_ifindex)>(intfId))
374 : {
375 0 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
376 : }
377 :
378 21 : pktInfo->ipi_ifindex = static_cast<decltype(pktInfo->ipi_ifindex)>(intfId);
379 21 : pktInfo->ipi_spec_dst = aPktInfo->SrcAddress.ToIPv4();
380 :
381 21 : msgHeader.msg_controllen = CMSG_SPACE(sizeof(in_pktinfo));
382 : #else // !defined(IP_PKTINFO)
383 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
384 : #endif // !defined(IP_PKTINFO)
385 : }
386 :
387 : #endif // INET_CONFIG_ENABLE_IPV4
388 :
389 42 : if (mAddrType == IPAddressType::kIPv6)
390 : {
391 : #if defined(IPV6_PKTINFO)
392 21 : controlHdr->cmsg_level = IPPROTO_IPV6;
393 21 : controlHdr->cmsg_type = IPV6_PKTINFO;
394 21 : controlHdr->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
395 :
396 21 : auto * pktInfo = reinterpret_cast<struct in6_pktinfo *> CMSG_DATA(controlHdr);
397 21 : if (!CanCastTo<decltype(pktInfo->ipi6_ifindex)>(intfId))
398 : {
399 0 : return CHIP_ERROR_UNEXPECTED_EVENT;
400 : }
401 21 : pktInfo->ipi6_ifindex = static_cast<decltype(pktInfo->ipi6_ifindex)>(intfId);
402 21 : pktInfo->ipi6_addr = aPktInfo->SrcAddress.ToIPv6();
403 :
404 21 : msgHeader.msg_controllen = CMSG_SPACE(sizeof(in6_pktinfo));
405 : #else // !defined(IPV6_PKTINFO)
406 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
407 : #endif // !defined(IPV6_PKTINFO)
408 : }
409 :
410 : #else // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO))
411 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
412 : #endif // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO))
413 : }
414 : #endif // INET_CONFIG_UDP_SOCKET_PKTINFO
415 :
416 : // Send IP packet.
417 : // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): GetSocket calls ensure mSocket is valid
418 46 : const ssize_t lenSent = sendmsg(mSocket, &msgHeader, 0);
419 46 : if (lenSent == -1)
420 : {
421 0 : return CHIP_ERROR_POSIX(errno);
422 : }
423 :
424 46 : size_t len = static_cast<size_t>(lenSent);
425 :
426 46 : if (len != msg->DataLength())
427 : {
428 0 : return CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG;
429 : }
430 46 : return CHIP_NO_ERROR;
431 : }
432 :
433 65 : void UDPEndPointImplSockets::CloseImpl()
434 : {
435 65 : if (mSocket != kInvalidSocketFd)
436 : {
437 65 : static_cast<System::LayerSockets *>(&GetSystemLayer())->StopWatchingSocket(&mWatch);
438 65 : close(mSocket);
439 65 : mSocket = kInvalidSocketFd;
440 : }
441 65 : }
442 :
443 65 : void UDPEndPointImplSockets::Free()
444 : {
445 65 : Close();
446 65 : Release();
447 65 : }
448 :
449 113 : CHIP_ERROR UDPEndPointImplSockets::GetSocket(IPAddressType addressType)
450 : {
451 113 : if (mSocket == kInvalidSocketFd)
452 : {
453 66 : constexpr int type = (SOCK_DGRAM | SOCK_CLOEXEC);
454 66 : constexpr int protocol = 0;
455 :
456 66 : int family = PF_UNSPEC;
457 :
458 66 : switch (addressType)
459 : {
460 33 : case IPAddressType::kIPv6:
461 33 : family = PF_INET6;
462 33 : break;
463 :
464 : #if INET_CONFIG_ENABLE_IPV4
465 32 : case IPAddressType::kIPv4:
466 32 : family = PF_INET;
467 32 : break;
468 : #endif // INET_CONFIG_ENABLE_IPV4
469 :
470 1 : default:
471 1 : return INET_ERROR_WRONG_ADDRESS_TYPE;
472 : }
473 :
474 65 : mSocket = ::socket(family, type, protocol);
475 65 : if (mSocket == -1)
476 : {
477 0 : return CHIP_ERROR_POSIX(errno);
478 : }
479 65 : CHIP_ERROR err = static_cast<System::LayerSockets *>(&GetSystemLayer())->StartWatchingSocket(mSocket, &mWatch);
480 65 : if (err != CHIP_NO_ERROR)
481 : {
482 : // Our mWatch is not valid; make sure we never use it.
483 0 : close(mSocket);
484 0 : mSocket = kInvalidSocketFd;
485 0 : return err;
486 : }
487 :
488 65 : mAddrType = addressType;
489 :
490 : // NOTE WELL: the errors returned by setsockopt() here are not
491 : // returned as Inet layer CHIP_ERROR_POSIX(errno)
492 : // codes because they are normally expected to fail on some
493 : // platforms where the socket option code is defined in the
494 : // header files but not [yet] implemented. Certainly, there is
495 : // room to improve this by connecting the build configuration
496 : // logic up to check for implementations of these options and
497 : // to provide appropriate HAVE_xxxxx definitions accordingly.
498 :
499 65 : constexpr int one = 1;
500 65 : int res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
501 : static_cast<void>(res);
502 :
503 : #ifdef SO_REUSEPORT
504 65 : res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
505 65 : if (res != 0)
506 : {
507 0 : ChipLogError(Inet, "SO_REUSEPORT failed: %d", errno);
508 : }
509 : #endif // defined(SO_REUSEPORT)
510 :
511 : // If creating an IPv6 socket, tell the kernel that it will be
512 : // IPv6 only. This makes it posible to bind two sockets to
513 : // the same port, one for IPv4 and one for IPv6.
514 :
515 : #ifdef IPV6_V6ONLY
516 65 : if (addressType == IPAddressType::kIPv6)
517 : {
518 33 : res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
519 33 : if (res != 0)
520 : {
521 0 : ChipLogError(Inet, "IPV6_V6ONLY failed: %d", errno);
522 : }
523 : }
524 : #endif // defined(IPV6_V6ONLY)
525 :
526 : #if INET_CONFIG_ENABLE_IPV4
527 : #ifdef IP_PKTINFO
528 65 : if (addressType == IPAddressType::kIPv4)
529 : {
530 32 : res = setsockopt(mSocket, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
531 32 : if (res != 0)
532 : {
533 0 : ChipLogError(Inet, "IP_PKTINFO failed: %d", errno);
534 : }
535 : }
536 : #endif // defined(IP_PKTINFO)
537 : #endif // INET_CONFIG_ENABLE_IPV4
538 :
539 : #ifdef IPV6_RECVPKTINFO
540 65 : if (addressType == IPAddressType::kIPv6)
541 : {
542 33 : res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
543 33 : if (res != 0)
544 : {
545 0 : ChipLogError(Inet, "IPV6_PKTINFO failed: %d", errno);
546 : }
547 : }
548 : #endif // defined(IPV6_RECVPKTINFO)
549 :
550 : // On systems that support it, disable the delivery of SIGPIPE
551 : // signals when writing to a closed socket. This is mostly
552 : // needed on iOS which has the peculiar habit of sending
553 : // SIGPIPEs on unconnected UDP sockets.
554 : #ifdef SO_NOSIGPIPE
555 : {
556 : res = setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
557 : if (res != 0)
558 : {
559 : ChipLogError(Inet, "SO_NOSIGPIPE failed: %d", errno);
560 : }
561 : }
562 : #endif // defined(SO_NOSIGPIPE)
563 : }
564 47 : else if (mAddrType != addressType)
565 : {
566 0 : return CHIP_ERROR_INCORRECT_STATE;
567 : }
568 :
569 112 : return CHIP_NO_ERROR;
570 : }
571 :
572 : // static
573 14 : void UDPEndPointImplSockets::HandlePendingIO(System::SocketEvents events, intptr_t data)
574 : {
575 14 : reinterpret_cast<UDPEndPointImplSockets *>(data)->HandlePendingIO(events);
576 14 : }
577 :
578 14 : void UDPEndPointImplSockets::HandlePendingIO(System::SocketEvents events)
579 : {
580 14 : if (mState != State::kListening || OnMessageReceived == nullptr || !events.Has(System::SocketEventFlags::kRead))
581 : {
582 0 : return;
583 : }
584 :
585 14 : CHIP_ERROR lStatus = CHIP_NO_ERROR;
586 14 : IPPacketInfo lPacketInfo;
587 14 : System::PacketBufferHandle lBuffer;
588 :
589 14 : lPacketInfo.Clear();
590 14 : lPacketInfo.DestPort = mBoundPort;
591 14 : lPacketInfo.Interface = mBoundIntfId;
592 :
593 14 : lBuffer = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSizeWithoutReserve, 0);
594 :
595 14 : if (!lBuffer.IsNull())
596 : {
597 : struct iovec msgIOV;
598 : SockAddr lPeerSockAddr;
599 : uint8_t controlData[256];
600 : struct msghdr msgHeader;
601 :
602 14 : msgIOV.iov_base = lBuffer->Start();
603 14 : msgIOV.iov_len = lBuffer->AvailableDataLength();
604 :
605 14 : memset(&lPeerSockAddr, 0, sizeof(lPeerSockAddr));
606 :
607 14 : memset(&msgHeader, 0, sizeof(msgHeader));
608 :
609 14 : msgHeader.msg_name = &lPeerSockAddr;
610 14 : msgHeader.msg_namelen = sizeof(lPeerSockAddr);
611 14 : msgHeader.msg_iov = &msgIOV;
612 14 : msgHeader.msg_iovlen = 1;
613 14 : msgHeader.msg_control = controlData;
614 14 : msgHeader.msg_controllen = sizeof(controlData);
615 :
616 14 : ssize_t rcvLen = recvmsg(mSocket, &msgHeader, MSG_DONTWAIT);
617 :
618 14 : if (rcvLen == -1)
619 : {
620 0 : lStatus = CHIP_ERROR_POSIX(errno);
621 : }
622 14 : else if (lBuffer->AvailableDataLength() < static_cast<size_t>(rcvLen))
623 : {
624 0 : lStatus = CHIP_ERROR_INBOUND_MESSAGE_TOO_BIG;
625 : }
626 : else
627 : {
628 14 : lBuffer->SetDataLength(static_cast<uint16_t>(rcvLen));
629 :
630 14 : if (lPeerSockAddr.any.sa_family == AF_INET6)
631 : {
632 7 : lPacketInfo.SrcAddress = IPAddress(lPeerSockAddr.in6.sin6_addr);
633 7 : lPacketInfo.SrcPort = ntohs(lPeerSockAddr.in6.sin6_port);
634 : }
635 : #if INET_CONFIG_ENABLE_IPV4
636 7 : else if (lPeerSockAddr.any.sa_family == AF_INET)
637 : {
638 7 : lPacketInfo.SrcAddress = IPAddress(lPeerSockAddr.in.sin_addr);
639 7 : lPacketInfo.SrcPort = ntohs(lPeerSockAddr.in.sin_port);
640 : }
641 : #endif // INET_CONFIG_ENABLE_IPV4
642 : else
643 : {
644 0 : lStatus = CHIP_ERROR_INCORRECT_STATE;
645 : }
646 : }
647 :
648 14 : if (lStatus == CHIP_NO_ERROR)
649 : {
650 28 : for (struct cmsghdr * controlHdr = CMSG_FIRSTHDR(&msgHeader); controlHdr != nullptr;
651 14 : controlHdr = CMSG_NXTHDR(&msgHeader, controlHdr))
652 : {
653 : #if INET_CONFIG_ENABLE_IPV4
654 : #ifdef IP_PKTINFO
655 14 : if (controlHdr->cmsg_level == IPPROTO_IP && controlHdr->cmsg_type == IP_PKTINFO)
656 : {
657 7 : auto * inPktInfo = reinterpret_cast<struct in_pktinfo *> CMSG_DATA(controlHdr);
658 7 : if (!CanCastTo<InterfaceId::PlatformType>(inPktInfo->ipi_ifindex))
659 : {
660 0 : lStatus = CHIP_ERROR_INCORRECT_STATE;
661 0 : break;
662 : }
663 7 : lPacketInfo.Interface = InterfaceId(static_cast<InterfaceId::PlatformType>(inPktInfo->ipi_ifindex));
664 7 : lPacketInfo.DestAddress = IPAddress(inPktInfo->ipi_addr);
665 7 : continue;
666 7 : }
667 : #endif // defined(IP_PKTINFO)
668 : #endif // INET_CONFIG_ENABLE_IPV4
669 :
670 : #ifdef IPV6_PKTINFO
671 7 : if (controlHdr->cmsg_level == IPPROTO_IPV6 && controlHdr->cmsg_type == IPV6_PKTINFO)
672 : {
673 7 : auto * in6PktInfo = reinterpret_cast<struct in6_pktinfo *> CMSG_DATA(controlHdr);
674 7 : if (!CanCastTo<InterfaceId::PlatformType>(in6PktInfo->ipi6_ifindex))
675 : {
676 0 : lStatus = CHIP_ERROR_INCORRECT_STATE;
677 0 : break;
678 : }
679 7 : lPacketInfo.Interface = InterfaceId(static_cast<InterfaceId::PlatformType>(in6PktInfo->ipi6_ifindex));
680 7 : lPacketInfo.DestAddress = IPAddress(in6PktInfo->ipi6_addr);
681 7 : continue;
682 7 : }
683 : #endif // defined(IPV6_PKTINFO)
684 : }
685 : }
686 : }
687 : else
688 : {
689 0 : lStatus = CHIP_ERROR_NO_MEMORY;
690 : }
691 :
692 14 : if (lStatus == CHIP_NO_ERROR)
693 : {
694 14 : lBuffer.RightSize();
695 14 : OnMessageReceived(this, std::move(lBuffer), &lPacketInfo);
696 : }
697 : else
698 : {
699 0 : if (OnReceiveError != nullptr && lStatus != CHIP_ERROR_POSIX(EAGAIN))
700 : {
701 0 : OnReceiveError(this, lStatus, nullptr);
702 : }
703 : }
704 14 : }
705 :
706 : #ifdef IPV6_MULTICAST_LOOP
707 0 : static CHIP_ERROR SocketsSetMulticastLoopback(int aSocket, bool aLoopback, int aProtocol, int aOption)
708 : {
709 0 : const unsigned int lValue = static_cast<unsigned int>(aLoopback);
710 0 : if (setsockopt(aSocket, aProtocol, aOption, &lValue, sizeof(lValue)) != 0)
711 : {
712 0 : return CHIP_ERROR_POSIX(errno);
713 : }
714 :
715 0 : return CHIP_NO_ERROR;
716 : }
717 : #endif // IPV6_MULTICAST_LOOP
718 :
719 0 : static CHIP_ERROR SocketsSetMulticastLoopback(int aSocket, IPVersion aIPVersion, bool aLoopback)
720 : {
721 : #ifdef IPV6_MULTICAST_LOOP
722 : CHIP_ERROR lRetval;
723 :
724 0 : switch (aIPVersion)
725 : {
726 :
727 0 : case kIPVersion_6:
728 0 : lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
729 0 : break;
730 :
731 : #if INET_CONFIG_ENABLE_IPV4 && defined(IP_MULTICAST_LOOP)
732 0 : case kIPVersion_4:
733 0 : lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IP, IP_MULTICAST_LOOP);
734 0 : break;
735 : #endif // INET_CONFIG_ENABLE_IPV4 && defined(IP_MULTICAST_LOOP)
736 :
737 0 : default:
738 0 : lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
739 0 : break;
740 : }
741 :
742 0 : return (lRetval);
743 : #else // IPV6_MULTICAST_LOOP
744 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
745 : #endif // IPV6_MULTICAST_LOOP
746 : }
747 :
748 0 : CHIP_ERROR UDPEndPointImplSockets::SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback)
749 : {
750 0 : CHIP_ERROR lRetval = CHIP_ERROR_NOT_IMPLEMENTED;
751 :
752 0 : lRetval = SocketsSetMulticastLoopback(mSocket, aIPVersion, aLoopback);
753 0 : SuccessOrExit(lRetval);
754 :
755 0 : exit:
756 0 : return (lRetval);
757 : }
758 :
759 : #if INET_CONFIG_ENABLE_IPV4
760 :
761 14 : CHIP_ERROR UDPEndPointImplSockets::IPv4JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join)
762 : {
763 : in_addr interfaceAddr;
764 :
765 14 : if (aInterfaceId.IsPresent())
766 : {
767 : IPAddress lInterfaceAddress;
768 14 : bool lInterfaceAddressFound = false;
769 :
770 28 : for (InterfaceAddressIterator lAddressIterator; lAddressIterator.HasCurrent(); lAddressIterator.Next())
771 : {
772 : IPAddress lCurrentAddress;
773 42 : if ((lAddressIterator.GetInterfaceId() == aInterfaceId) &&
774 42 : (lAddressIterator.GetAddress(lCurrentAddress) == CHIP_NO_ERROR))
775 : {
776 14 : if (lCurrentAddress.IsIPv4())
777 : {
778 14 : lInterfaceAddressFound = true;
779 14 : lInterfaceAddress = lCurrentAddress;
780 14 : break;
781 : }
782 : }
783 14 : }
784 14 : VerifyOrReturnError(lInterfaceAddressFound, INET_ERROR_ADDRESS_NOT_FOUND);
785 :
786 14 : interfaceAddr = lInterfaceAddress.ToIPv4();
787 : }
788 : else
789 : {
790 0 : interfaceAddr.s_addr = htonl(INADDR_ANY);
791 : }
792 :
793 : #if INET_CONFIG_UDP_SOCKET_MREQN
794 : struct ip_mreqn lMulticastRequest;
795 : memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
796 : lMulticastRequest.imr_ifindex = aInterfaceId.GetPlatformInterface(); /* Network interface index */
797 : lMulticastRequest.imr_address = interfaceAddr; /* IP address of local interface */
798 : lMulticastRequest.imr_multiaddr = aAddress.ToIPv4(); /* IP multicast group address*/
799 :
800 : #else
801 :
802 : struct ip_mreq lMulticastRequest;
803 14 : memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
804 14 : lMulticastRequest.imr_interface = interfaceAddr;
805 14 : lMulticastRequest.imr_multiaddr = aAddress.ToIPv4();
806 :
807 : #endif
808 :
809 14 : const int command = join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
810 14 : if (setsockopt(mSocket, IPPROTO_IP, command, &lMulticastRequest, sizeof(lMulticastRequest)) != 0)
811 : {
812 0 : return CHIP_ERROR_POSIX(errno);
813 : }
814 14 : return CHIP_NO_ERROR;
815 : }
816 :
817 : #endif // INET_CONFIG_ENABLE_IPV4
818 :
819 14 : CHIP_ERROR UDPEndPointImplSockets::IPv6JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join)
820 : {
821 : #if CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
822 : if (sMulticastGroupHandler != nullptr)
823 : {
824 : return sMulticastGroupHandler(aInterfaceId, aAddress, join ? MulticastOperation::kJoin : MulticastOperation::kLeave);
825 : }
826 : #endif // CHIP_SYSTEM_CONFIG_USE_PLATFORM_MULTICAST_API
827 :
828 : #ifdef IPV6_MULTICAST_IMPLEMENTED
829 14 : if (!aInterfaceId.IsPresent())
830 : {
831 : // Do it on all the viable interfaces.
832 0 : bool interfaceFound = false;
833 :
834 0 : InterfaceIterator interfaceIt;
835 0 : while (interfaceIt.Next())
836 : {
837 0 : if (!interfaceIt.SupportsMulticast() || !interfaceIt.IsUp())
838 : {
839 0 : continue;
840 : }
841 :
842 0 : InterfaceId interfaceId = interfaceIt.GetInterfaceId();
843 :
844 : IPAddress ifAddr;
845 0 : if (interfaceId.GetLinkLocalAddr(&ifAddr) != CHIP_NO_ERROR)
846 : {
847 0 : continue;
848 : }
849 :
850 0 : if (ifAddr.Type() != IPAddressType::kIPv6)
851 : {
852 : // Not the right sort of interface.
853 0 : continue;
854 : }
855 :
856 0 : interfaceFound = true;
857 :
858 : char ifName[InterfaceId::kMaxIfNameLength];
859 0 : interfaceIt.GetInterfaceName(ifName, sizeof(ifName));
860 :
861 : // Ignore errors here, except for logging, because we expect some of
862 : // these interfaces to not work, and some (e.g. loopback) to always
863 : // work.
864 0 : CHIP_ERROR err = IPv6JoinLeaveMulticastGroupImpl(interfaceId, aAddress, join);
865 0 : if (err == CHIP_NO_ERROR)
866 : {
867 0 : ChipLogDetail(Inet, " %s multicast group on interface %s", (join ? "Joined" : "Left"), ifName);
868 : }
869 : else
870 : {
871 0 : ChipLogError(Inet, " Failed to %s multicast group on interface %s", (join ? "join" : "leave"), ifName);
872 : }
873 : }
874 :
875 0 : if (interfaceFound)
876 : {
877 : // Assume we're good.
878 0 : return CHIP_NO_ERROR;
879 : }
880 :
881 : // Else go ahead and try to work with the default interface.
882 0 : ChipLogError(Inet, "No valid IPv6 multicast interface found");
883 0 : }
884 :
885 14 : const InterfaceId::PlatformType lIfIndex = aInterfaceId.GetPlatformInterface();
886 :
887 : struct ipv6_mreq lMulticastRequest;
888 14 : memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
889 14 : VerifyOrReturnError(CanCastTo<decltype(lMulticastRequest.ipv6mr_interface)>(lIfIndex), CHIP_ERROR_UNEXPECTED_EVENT);
890 :
891 14 : lMulticastRequest.ipv6mr_interface = static_cast<decltype(lMulticastRequest.ipv6mr_interface)>(lIfIndex);
892 14 : lMulticastRequest.ipv6mr_multiaddr = aAddress.ToIPv6();
893 :
894 14 : const int command = join ? INET_IPV6_ADD_MEMBERSHIP : INET_IPV6_DROP_MEMBERSHIP;
895 14 : if (setsockopt(mSocket, IPPROTO_IPV6, command, &lMulticastRequest, sizeof(lMulticastRequest)) != 0)
896 : {
897 0 : return CHIP_ERROR_POSIX(errno);
898 : }
899 14 : return CHIP_NO_ERROR;
900 : #else
901 : return CHIP_ERROR_NOT_IMPLEMENTED;
902 : #endif
903 : }
904 :
905 : } // namespace Inet
906 : } // namespace chip
|