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