1 /*
2 * Copyright (c) 2024, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #define OTBR_LOG_TAG "NETIF"
30
31 #include "netif.hpp"
32
33 #include <arpa/inet.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <ifaddrs.h>
37 #include <net/if.h>
38 #include <net/if_arp.h>
39 #include <netinet/in.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <sys/ioctl.h>
43 #include <sys/socket.h>
44 #include <unistd.h>
45
46 #include <algorithm>
47
48 #include "common/code_utils.hpp"
49 #include "common/logging.hpp"
50 #include "common/types.hpp"
51 #include "utils/socket_utils.hpp"
52
53 namespace otbr {
54
Ip6Send(const uint8_t * aData,uint16_t aLength)55 otbrError Netif::Dependencies::Ip6Send(const uint8_t *aData, uint16_t aLength)
56 {
57 OTBR_UNUSED_VARIABLE(aData);
58 OTBR_UNUSED_VARIABLE(aLength);
59
60 return OTBR_ERROR_NONE;
61 }
62
Ip6MulAddrUpdateSubscription(const otIp6Address & aAddress,bool aIsAdd)63 otbrError Netif::Dependencies::Ip6MulAddrUpdateSubscription(const otIp6Address &aAddress, bool aIsAdd)
64 {
65 OTBR_UNUSED_VARIABLE(aAddress);
66 OTBR_UNUSED_VARIABLE(aIsAdd);
67
68 return OTBR_ERROR_NONE;
69 }
70
71 OT_TOOL_PACKED_BEGIN
72 struct Mldv2Header
73 {
74 uint8_t mType;
75 uint8_t _rsv0;
76 uint16_t mChecksum;
77 uint16_t _rsv1;
78 uint16_t mNumRecords;
79 } OT_TOOL_PACKED_END;
80
81 OT_TOOL_PACKED_BEGIN
82 struct Mldv2Record
83 {
84 uint8_t mRecordType;
85 uint8_t mAuxDataLen;
86 uint16_t mNumSources;
87 struct in6_addr mMulticastAddress;
88 } OT_TOOL_PACKED_END;
89
90 enum
91 {
92 kIcmpv6Mldv2Type = 143,
93 kIcmpv6Mldv2ModeIsIncludeType = 1,
94 kIcmpv6Mldv2ModeIsExcludeType = 2,
95 kIcmpv6Mldv2RecordChangeToIncludeType = 3,
96 kIcmpv6Mldv2RecordChangeToExcludeType = 4,
97 };
98
Netif(Dependencies & aDependencies)99 Netif::Netif(Dependencies &aDependencies)
100 : mTunFd(-1)
101 , mIpFd(-1)
102 , mNetlinkFd(-1)
103 , mMldFd(-1)
104 , mNetlinkSequence(0)
105 , mNetifIndex(0)
106 , mDeps(aDependencies)
107 {
108 }
109
Init(const std::string & aInterfaceName)110 otbrError Netif::Init(const std::string &aInterfaceName)
111 {
112 otbrError error = OTBR_ERROR_NONE;
113
114 mIpFd = SocketWithCloseExec(AF_INET6, SOCK_DGRAM, IPPROTO_IP, kSocketNonBlock);
115 VerifyOrExit(mIpFd >= 0, error = OTBR_ERROR_ERRNO);
116
117 SuccessOrExit(error = CreateTunDevice(aInterfaceName));
118 SuccessOrExit(error = InitNetlink());
119
120 mNetifIndex = if_nametoindex(mNetifName.c_str());
121 VerifyOrExit(mNetifIndex > 0, error = OTBR_ERROR_INVALID_STATE);
122
123 SuccessOrExit(error = InitMldListener());
124
125 PlatformSpecificInit();
126
127 exit:
128 if (error != OTBR_ERROR_NONE)
129 {
130 Clear();
131 }
132 return error;
133 }
134
Deinit(void)135 void Netif::Deinit(void)
136 {
137 Clear();
138 }
139
Process(const MainloopContext * aContext)140 void Netif::Process(const MainloopContext *aContext)
141 {
142 if (FD_ISSET(mTunFd, &aContext->mErrorFdSet))
143 {
144 close(mTunFd);
145 DieNow("Error on Tun Fd!");
146 }
147
148 if (FD_ISSET(mMldFd, &aContext->mErrorFdSet))
149 {
150 close(mMldFd);
151 DieNow("Error on MLD Fd!");
152 }
153
154 if (FD_ISSET(mTunFd, &aContext->mReadFdSet))
155 {
156 ProcessIp6Send();
157 }
158
159 if (FD_ISSET(mMldFd, &aContext->mReadFdSet))
160 {
161 ProcessMldEvent();
162 }
163 }
164
UpdateFdSet(MainloopContext * aContext)165 void Netif::UpdateFdSet(MainloopContext *aContext)
166 {
167 assert(aContext != nullptr);
168 assert(mTunFd >= 0);
169 assert(mIpFd >= 0);
170 assert(mMldFd >= 0);
171
172 aContext->AddFdToSet(mTunFd, MainloopContext::kErrorFdSet | MainloopContext::kReadFdSet);
173 aContext->AddFdToSet(mMldFd, MainloopContext::kErrorFdSet | MainloopContext::kReadFdSet);
174 }
175
UpdateIp6UnicastAddresses(const std::vector<Ip6AddressInfo> & aAddrInfos)176 void Netif::UpdateIp6UnicastAddresses(const std::vector<Ip6AddressInfo> &aAddrInfos)
177 {
178 // Remove stale addresses
179 for (const Ip6AddressInfo &addrInfo : mIp6UnicastAddresses)
180 {
181 if (std::find(aAddrInfos.begin(), aAddrInfos.end(), addrInfo) == aAddrInfos.end())
182 {
183 otbrLogInfo("Remove address: %s", Ip6Address(addrInfo.mAddress).ToString().c_str());
184 // TODO: Verify success of the addition or deletion in Netlink response.
185 ProcessUnicastAddressChange(addrInfo, false);
186 }
187 }
188
189 // Add new addresses
190 for (const Ip6AddressInfo &addrInfo : aAddrInfos)
191 {
192 if (std::find(mIp6UnicastAddresses.begin(), mIp6UnicastAddresses.end(), addrInfo) == mIp6UnicastAddresses.end())
193 {
194 otbrLogInfo("Add address: %s", Ip6Address(addrInfo.mAddress).ToString().c_str());
195 // TODO: Verify success of the addition or deletion in Netlink response.
196 ProcessUnicastAddressChange(addrInfo, true);
197 }
198 }
199
200 mIp6UnicastAddresses.assign(aAddrInfos.begin(), aAddrInfos.end());
201 }
202
UpdateIp6MulticastAddresses(const std::vector<Ip6Address> & aAddrs)203 otbrError Netif::UpdateIp6MulticastAddresses(const std::vector<Ip6Address> &aAddrs)
204 {
205 otbrError error = OTBR_ERROR_NONE;
206
207 // Remove stale addresses
208 for (const Ip6Address &address : mIp6MulticastAddresses)
209 {
210 if (std::find(aAddrs.begin(), aAddrs.end(), address) == aAddrs.end())
211 {
212 otbrLogInfo("Remove address: %s", Ip6Address(address).ToString().c_str());
213 SuccessOrExit(error = ProcessMulticastAddressChange(address, /* aIsAdded */ false));
214 }
215 }
216
217 // Add new addresses
218 for (const Ip6Address &address : aAddrs)
219 {
220 if (std::find(mIp6MulticastAddresses.begin(), mIp6MulticastAddresses.end(), address) ==
221 mIp6MulticastAddresses.end())
222 {
223 otbrLogInfo("Add address: %s", Ip6Address(address).ToString().c_str());
224 SuccessOrExit(error = ProcessMulticastAddressChange(address, /* aIsAdded */ true));
225 }
226 }
227
228 mIp6MulticastAddresses.assign(aAddrs.begin(), aAddrs.end());
229
230 exit:
231 if (error != OTBR_ERROR_NONE)
232 {
233 mIp6MulticastAddresses.clear();
234 }
235 return error;
236 }
237
ProcessMulticastAddressChange(const Ip6Address & aAddress,bool aIsAdded)238 otbrError Netif::ProcessMulticastAddressChange(const Ip6Address &aAddress, bool aIsAdded)
239 {
240 struct ipv6_mreq mreq;
241 otbrError error = OTBR_ERROR_NONE;
242 int err;
243
244 VerifyOrExit(mIpFd >= 0, error = OTBR_ERROR_INVALID_STATE);
245 memcpy(&mreq.ipv6mr_multiaddr, &aAddress, sizeof(mreq.ipv6mr_multiaddr));
246 mreq.ipv6mr_interface = mNetifIndex;
247
248 err = setsockopt(mIpFd, IPPROTO_IPV6, (aIsAdded ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP), &mreq, sizeof(mreq));
249
250 if (err != 0)
251 {
252 otbrLogWarning("%s failure (%d)", aIsAdded ? "IPV6_JOIN_GROUP" : "IPV6_LEAVE_GROUP", errno);
253 ExitNow(error = OTBR_ERROR_ERRNO);
254 }
255
256 otbrLogInfo("%s multicast address %s", aIsAdded ? "Added" : "Removed", Ip6Address(aAddress).ToString().c_str());
257
258 exit:
259 return error;
260 }
261
SetNetifState(bool aState)262 void Netif::SetNetifState(bool aState)
263 {
264 otbrError error = OTBR_ERROR_NONE;
265 struct ifreq ifr;
266 bool ifState = false;
267
268 VerifyOrExit(mIpFd >= 0);
269 memset(&ifr, 0, sizeof(ifr));
270 strncpy(ifr.ifr_name, mNetifName.c_str(), IFNAMSIZ - 1);
271 VerifyOrExit(ioctl(mIpFd, SIOCGIFFLAGS, &ifr) == 0, error = OTBR_ERROR_ERRNO);
272
273 ifState = ((ifr.ifr_flags & IFF_UP) == IFF_UP) ? true : false;
274
275 otbrLogInfo("Changing interface state to %s%s.", aState ? "up" : "down",
276 (ifState == aState) ? " (already done, ignoring)" : "");
277
278 if (ifState != aState)
279 {
280 ifr.ifr_flags = aState ? (ifr.ifr_flags | IFF_UP) : (ifr.ifr_flags & ~IFF_UP);
281 VerifyOrExit(ioctl(mIpFd, SIOCSIFFLAGS, &ifr) == 0, error = OTBR_ERROR_ERRNO);
282 }
283
284 exit:
285 if (error != OTBR_ERROR_NONE)
286 {
287 otbrLogWarning("Failed to update state %s", otbrErrorString(error));
288 }
289 }
290
Ip6Receive(const uint8_t * aBuf,uint16_t aLen)291 void Netif::Ip6Receive(const uint8_t *aBuf, uint16_t aLen)
292 {
293 otbrError error = OTBR_ERROR_NONE;
294
295 VerifyOrExit(aLen <= kIp6Mtu, error = OTBR_ERROR_DROPPED);
296 VerifyOrExit(mTunFd > 0, error = OTBR_ERROR_INVALID_STATE);
297
298 otbrLogInfo("Packet from NCP (%u bytes)", aLen);
299 VerifyOrExit(write(mTunFd, aBuf, aLen) == aLen, error = OTBR_ERROR_ERRNO);
300
301 exit:
302 if (error != OTBR_ERROR_NONE)
303 {
304 otbrLogWarning("Failed to receive, error:%s", otbrErrorString(error));
305 }
306 }
307
ProcessIp6Send(void)308 void Netif::ProcessIp6Send(void)
309 {
310 ssize_t rval;
311 uint8_t packet[kIp6Mtu];
312 otbrError error = OTBR_ERROR_NONE;
313
314 rval = read(mTunFd, packet, sizeof(packet));
315 VerifyOrExit(rval > 0, error = OTBR_ERROR_ERRNO);
316
317 otbrLogInfo("Send packet (%hu bytes)", static_cast<uint16_t>(rval));
318
319 error = mDeps.Ip6Send(packet, rval);
320 exit:
321 if (error == OTBR_ERROR_ERRNO)
322 {
323 otbrLogInfo("Error reading from Tun Fd: %s", strerror(errno));
324 }
325 }
326
Clear(void)327 void Netif::Clear(void)
328 {
329 if (mTunFd != -1)
330 {
331 close(mTunFd);
332 mTunFd = -1;
333 }
334
335 if (mIpFd != -1)
336 {
337 close(mIpFd);
338 mIpFd = -1;
339 }
340
341 if (mNetlinkFd != -1)
342 {
343 close(mNetlinkFd);
344 mNetlinkFd = -1;
345 }
346
347 if (mMldFd != -1)
348 {
349 close(mMldFd);
350 mMldFd = -1;
351 }
352
353 mNetifIndex = 0;
354 mIp6UnicastAddresses.clear();
355 mIp6MulticastAddresses.clear();
356 }
357
358 static const otIp6Address kMldv2MulticastAddress = {
359 {{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16}}};
360 static const otIp6Address kAllRouterLocalMulticastAddress = {
361 {{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}}};
362
IsMulAddrFiltered(const otIp6Address & aAddr)363 static bool IsMulAddrFiltered(const otIp6Address &aAddr)
364 {
365 return Ip6Address(aAddr) == Ip6Address(kMldv2MulticastAddress) ||
366 Ip6Address(aAddr) == Ip6Address(kAllRouterLocalMulticastAddress);
367 }
368
InitMldListener(void)369 otbrError Netif::InitMldListener(void)
370 {
371 otbrError error = OTBR_ERROR_NONE;
372 struct ipv6_mreq mreq6;
373
374 mMldFd = SocketWithCloseExec(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, kSocketNonBlock);
375 VerifyOrExit(mMldFd != -1, error = OTBR_ERROR_ERRNO);
376
377 mreq6.ipv6mr_interface = mNetifIndex;
378 memcpy(&mreq6.ipv6mr_multiaddr, kMldv2MulticastAddress.mFields.m8, sizeof(kMldv2MulticastAddress.mFields.m8));
379
380 VerifyOrExit(setsockopt(mMldFd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6)) == 0,
381 error = OTBR_ERROR_ERRNO);
382 #ifdef __linux__
383 VerifyOrExit(setsockopt(mMldFd, SOL_SOCKET, SO_BINDTODEVICE, mNetifName.c_str(),
384 static_cast<socklen_t>(mNetifName.length())) == 0,
385 error = OTBR_ERROR_ERRNO);
386 #endif
387
388 exit:
389 return error;
390 }
391
ProcessMldEvent(void)392 void Netif::ProcessMldEvent(void)
393 {
394 const size_t kMaxMldEvent = 8192;
395 uint8_t buffer[kMaxMldEvent];
396 ssize_t bufferLen = -1;
397 struct sockaddr_in6 srcAddr;
398 socklen_t addrLen = sizeof(srcAddr);
399 bool fromSelf = false;
400 Mldv2Header *hdr = reinterpret_cast<Mldv2Header *>(buffer);
401 size_t offset;
402 uint8_t type;
403 struct ifaddrs *ifAddrs = nullptr;
404 char addressString[INET6_ADDRSTRLEN + 1];
405
406 bufferLen = recvfrom(mMldFd, buffer, sizeof(buffer), 0, reinterpret_cast<sockaddr *>(&srcAddr), &addrLen);
407 VerifyOrExit(bufferLen > 0);
408
409 type = buffer[0];
410 VerifyOrExit(type == kIcmpv6Mldv2Type && bufferLen >= static_cast<ssize_t>(sizeof(Mldv2Header)));
411
412 // Check whether it is sent by self
413 VerifyOrExit(getifaddrs(&ifAddrs) == 0);
414 for (struct ifaddrs *ifAddr = ifAddrs; ifAddr != nullptr; ifAddr = ifAddr->ifa_next)
415 {
416 if (ifAddr->ifa_addr != nullptr && ifAddr->ifa_addr->sa_family == AF_INET6 &&
417 strncmp(mNetifName.c_str(), ifAddr->ifa_name, IFNAMSIZ) == 0)
418 {
419 struct sockaddr_in6 *addr6 = reinterpret_cast<struct sockaddr_in6 *>(ifAddr->ifa_addr);
420
421 if (memcmp(&addr6->sin6_addr, &srcAddr.sin6_addr, sizeof(in6_addr)) == 0)
422 {
423 fromSelf = true;
424 break;
425 }
426 }
427 }
428 VerifyOrExit(fromSelf);
429
430 hdr = reinterpret_cast<Mldv2Header *>(buffer);
431 offset = sizeof(Mldv2Header);
432
433 for (size_t i = 0; i < ntohs(hdr->mNumRecords) && offset < static_cast<size_t>(bufferLen); i++)
434 {
435 if (static_cast<size_t>(bufferLen) >= (sizeof(Mldv2Record) + offset))
436 {
437 Mldv2Record *record = reinterpret_cast<Mldv2Record *>(&buffer[offset]);
438
439 otbrError error = OTBR_ERROR_DROPPED;
440 otIp6Address address;
441
442 memcpy(&address, &record->mMulticastAddress, sizeof(address));
443 if (IsMulAddrFiltered(address))
444 {
445 continue;
446 }
447
448 inet_ntop(AF_INET6, &record->mMulticastAddress, addressString, sizeof(addressString));
449
450 switch (record->mRecordType)
451 {
452 case kIcmpv6Mldv2ModeIsIncludeType:
453 case kIcmpv6Mldv2ModeIsExcludeType:
454 error = OTBR_ERROR_NONE;
455 break;
456 ///< Only update subscription on NCP when the target multicast address is not in `mIp6MulticastAddresses`.
457 ///< This indicates that this is the first time the multicast address subscription needs to be updated.
458 case kIcmpv6Mldv2RecordChangeToIncludeType:
459 if (record->mNumSources == 0)
460 {
461 if (std::find(mIp6MulticastAddresses.begin(), mIp6MulticastAddresses.end(), Ip6Address(address)) !=
462 mIp6MulticastAddresses.end())
463 {
464 error = mDeps.Ip6MulAddrUpdateSubscription(address, /* isAdd */ false);
465 }
466 else
467 {
468 error = OTBR_ERROR_NONE;
469 }
470 }
471 break;
472 case kIcmpv6Mldv2RecordChangeToExcludeType:
473 if (std::find(mIp6MulticastAddresses.begin(), mIp6MulticastAddresses.end(), Ip6Address(address)) ==
474 mIp6MulticastAddresses.end())
475 {
476 error = mDeps.Ip6MulAddrUpdateSubscription(address, /* isAdd */ true);
477 }
478 else
479 {
480 error = OTBR_ERROR_NONE;
481 }
482 break;
483 }
484
485 offset += sizeof(Mldv2Record) + sizeof(in6_addr) * ntohs(record->mNumSources);
486
487 if (error != OTBR_ERROR_NONE)
488 {
489 otbrLogWarning("Failed to Update multicast subscription: %s", otbrErrorString(error));
490 }
491 }
492 }
493
494 exit:
495 if (ifAddrs)
496 {
497 freeifaddrs(ifAddrs);
498 }
499 }
500
501 } // namespace otbr
502