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