Coverage Report

Created: 2026-01-16 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wpantund/src/util/TunnelIPv6Interface.cpp
Line
Count
Source
1
/*
2
 *
3
 * Copyright (c) 2016 Nest Labs, Inc.
4
 * All rights reserved.
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 *
18
 *    Description:
19
 *      This file contains the implementation for a C++ wrapper around the
20
 *      `tunnel.c`/`tunnel.h` interface.
21
 *
22
 */
23
24
#if HAVE_CONFIG_H
25
#include <config.h>
26
#endif
27
28
#include "assert-macros.h"
29
#include "TunnelIPv6Interface.h"
30
#include <syslog.h>
31
#include "IPv6Helpers.h"
32
33
#if __linux__
34
#include <asm/types.h>
35
#include <linux/if_link.h>
36
#include <sys/socket.h>
37
#include <linux/netlink.h>
38
#include <linux/rtnetlink.h>
39
#include <fcntl.h>
40
#include <ifaddrs.h>
41
#endif
42
43
#include <sys/select.h>
44
45
#ifndef O_NONBLOCK
46
#define O_NONBLOCK          O_NDELAY
47
#endif
48
49
namespace {
50
51
  const char* kMLDv2MulticastAddress= "ff02::16";
52
53
  const char *kFilterMulticastAddresses[] = {
54
      kMLDv2MulticastAddress,
55
      "ff02::01", //Link local all nodes
56
      "ff02::02", //Link local all routers
57
      "ff03::01", //realm local all nodes
58
      "ff03::02", //realm local all routers
59
      "ff03::fc", //realm local all mpl
60
  };
61
62
  struct MLDv2Header {
63
    uint8_t mType;
64
    uint8_t _rsv0;
65
    uint16_t mChecksum;
66
    uint16_t _rsv1;
67
    uint16_t mNumRecords;
68
  } __attribute__((packed));
69
70
  struct MLDv2Record {
71
    uint8_t mRecordType;
72
    uint8_t mAuxDataLen;
73
    uint16_t mNumSources;
74
    struct in6_addr mMulticastAddress;
75
    struct in6_addr mSourceAddresses[];
76
  } __attribute__((packed));
77
78
} // namespace
79
80
static bool
81
is_addr_multicast(const struct in6_addr &address)
82
0
{
83
0
  return (address.s6_addr[0] == 0xff);
84
0
}
85
86
TunnelIPv6Interface::TunnelIPv6Interface(const std::string& interface_name, int mtu):
87
#if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
88
13.9k
  UnixSocket(open("/dev/null",O_RDWR), true),
89
#else
90
  UnixSocket(tunnel_open(interface_name.c_str()), true),
91
#endif
92
13.9k
  mInterfaceName(interface_name),
93
13.9k
  mLastError(0),
94
13.9k
  mNetlinkFD(-1),
95
#if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
96
13.9k
  mNetifMgmtFD(-1),
97
#else
98
  mNetifMgmtFD(netif_mgmt_open()),
99
#endif
100
13.9k
  mMLDMonitorFD(-1),
101
13.9k
  mIsRunning(false),
102
13.9k
  mIsUp(false)
103
13.9k
{
104
13.9k
  if (0 > mFDRead) {
105
0
    throw std::invalid_argument("Unable to open tunnel interface");
106
0
  }
107
108
#if !FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
109
  {
110
    char ActualInterfaceName[TUNNEL_MAX_INTERFACE_NAME_LEN] = "";
111
    int ret = 0;
112
    ret = tunnel_get_name(mFDRead, ActualInterfaceName, sizeof(ActualInterfaceName));
113
    if (ret) {
114
      syslog(LOG_WARNING,
115
           "TunnelIPv6Interface: Couldn't get tunnel name! errno=%d, %s",
116
           errno,
117
           strerror(errno));
118
    } else if (mInterfaceName != ActualInterfaceName) {
119
      syslog(LOG_WARNING,
120
           "TunnelIPv6Interface: Couldn't create tunnel named \"%s\", got \"%s\" instead!",
121
           mInterfaceName.c_str(),
122
           ActualInterfaceName);
123
      mInterfaceName = ActualInterfaceName;
124
    }
125
  }
126
127
  netif_mgmt_set_mtu(mNetifMgmtFD, mInterfaceName.c_str(), mtu);
128
129
  setup_signals();
130
  setup_mld_listener();
131
#endif
132
13.9k
}
133
134
TunnelIPv6Interface::~TunnelIPv6Interface()
135
13.9k
{
136
13.9k
  close(mNetlinkFD);
137
13.9k
  if (mMLDMonitorFD >= 0) {
138
0
    close(mMLDMonitorFD);
139
0
  }
140
13.9k
  netif_mgmt_close(mNetifMgmtFD);
141
13.9k
}
142
143
void
144
TunnelIPv6Interface::on_link_state_changed(bool isUp, bool isRunning)
145
0
{
146
0
  syslog(LOG_INFO, "TunnelIPv6Interface::on_link_state_changed() UP=%d RUNNING=%d", isUp, isRunning);
147
0
  if (isRunning != mIsRunning || isUp != mIsUp) {
148
0
    if (isRunning && !mIsRunning) {
149
0
      std::map<struct in6_addr, Entry>::iterator iter;
150
151
0
      for (iter = mUnicastAddresses.begin(); iter != mUnicastAddresses.end(); ++iter) {
152
0
        if (iter->second.mState != Entry::kWaitingToAdd) {
153
0
          continue;
154
0
        }
155
156
0
        syslog(LOG_INFO, "Adding address \"%s/%d\" to interface \"%s\"",
157
0
               in6_addr_to_string(iter->first).c_str(), iter->second.mPrefixLen,
158
0
               mInterfaceName.c_str());
159
160
0
        IGNORE_RETURN_VALUE(netif_mgmt_add_ipv6_address(mNetifMgmtFD, mInterfaceName.c_str(),
161
0
                            iter->first.s6_addr, iter->second.mPrefixLen));
162
0
        iter->second.mState = Entry::kWaitingForAddConfirm;
163
0
      }
164
165
0
      for (iter = mPendingMulticastAddresses.begin(); iter != mPendingMulticastAddresses.end(); ++iter) {
166
0
        if (iter->second.mState != Entry::kWaitingToAdd) {
167
0
          continue;
168
0
        }
169
170
0
        syslog(LOG_INFO, "Joining multicast address \"%s\" on interface \"%s\".",
171
0
               in6_addr_to_string(iter->first).c_str(), mInterfaceName.c_str());
172
173
0
        IGNORE_RETURN_VALUE(netif_mgmt_join_ipv6_multicast_address(mNetifMgmtFD, mInterfaceName.c_str(),
174
0
                            iter->first.s6_addr));
175
0
      }
176
0
      mPendingMulticastAddresses.clear();
177
0
    }
178
0
    mIsUp = isUp;
179
0
    mIsRunning = isRunning;
180
0
    mLinkStateChanged(isUp, isRunning);
181
0
  }
182
0
}
183
184
void
185
TunnelIPv6Interface::on_address_added(const struct in6_addr &address, uint8_t prefix_len)
186
0
{
187
0
  if (mUnicastAddresses.count(address)) {
188
0
    mUnicastAddresses.erase(address);
189
0
  }
190
191
0
  syslog(LOG_INFO, "TunnelIPv6Interface: \"%s/%d\" was added to \"%s\"", in6_addr_to_string(address).c_str(), prefix_len,
192
0
         get_interface_name().c_str());
193
194
0
  mUnicastAddressWasAdded(address, prefix_len);
195
0
}
196
197
void
198
TunnelIPv6Interface::on_multicast_address_joined(const struct in6_addr &address)
199
0
{
200
0
  if (mPendingMulticastAddresses.count(address)) {
201
0
    mPendingMulticastAddresses.erase(address);
202
0
  }
203
204
0
  syslog(LOG_INFO, "TunnelIPv6Interface: \"%s\" was added to \"%s\"", in6_addr_to_string(address).c_str(),
205
0
         get_interface_name().c_str());
206
207
0
  mMulticastAddressWasJoined(address);
208
0
}
209
210
void
211
TunnelIPv6Interface::on_address_removed(const struct in6_addr &address, uint8_t prefix_len)
212
0
{
213
  // Ignore "removed" signal if address is the list
214
  // meaning it was added earlier and we are still
215
  // waiting to confirm that it is added.
216
  // This is to address the case where before adding an
217
  // address on interface it may be first removed.
218
219
0
  if (!mUnicastAddresses.count(address)) {
220
0
    syslog(LOG_INFO, "TunnelIPv6Interface: \"%s/%d\" was removed from \"%s\"", in6_addr_to_string(address).c_str(), prefix_len,
221
0
           get_interface_name().c_str());
222
223
0
    mUnicastAddressWasRemoved(address, prefix_len);
224
0
  }
225
226
0
}
227
228
void
229
TunnelIPv6Interface::on_multicast_address_left(const struct in6_addr &address)
230
0
{
231
  // Ignore "removed" signal if address is the list
232
  // meaning it was added earlier and we are still
233
  // waiting to confirm that it is added.
234
  // This is to address the case where before adding an
235
  // address on interface it may be first removed.
236
237
0
  if (!mPendingMulticastAddresses.count(address)) {
238
0
    syslog(LOG_INFO, "TunnelIPv6Interface: \"%s\" was removed from \"%s\"", in6_addr_to_string(address).c_str(),
239
0
           get_interface_name().c_str());
240
241
0
    mMulticastAddressWasLeft(address);
242
0
  }
243
0
}
244
245
#if __linux__ // --------------------------------------------------------------
246
247
0
#define LCG32(x)    ((uint32_t)(x)*1664525+1013904223)
248
249
void
250
TunnelIPv6Interface::setup_signals(void)
251
0
{
252
0
  int status;
253
0
  int fd;
254
0
  struct sockaddr_nl la;
255
256
0
  fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
257
258
0
  require(fd != -1, bail);
259
260
0
  memset(&la, 0, sizeof(la));
261
0
  la.nl_family = AF_NETLINK;
262
0
  la.nl_pad = 0;
263
0
  la.nl_groups = RTMGRP_LINK | RTMGRP_IPV6_IFADDR;
264
265
  // We calculate the PID in a pseudo-random way based on the
266
  // address pointer and the actual process ID.
267
0
  la.nl_pid = LCG32(getpid()) ^ LCG32((uint32_t)reinterpret_cast<uintptr_t>(this));
268
269
0
  status = bind(fd, (struct sockaddr*) &la, sizeof(la));
270
271
0
  require(status != -1, bail);
272
273
  // Success!
274
0
  IGNORE_RETURN_VALUE(fcntl(fd, F_SETFL, O_NONBLOCK));
275
276
0
  mNetlinkFD = fd;
277
0
  fd = -1;
278
279
0
bail:
280
281
  // Cleanup (If necessary)
282
0
  if (fd > 0) {
283
0
    close(fd);
284
0
  }
285
286
0
  return;
287
0
}
288
289
void
290
TunnelIPv6Interface::setup_mld_listener(void)
291
0
{
292
0
  unsigned interfaceIndex = netif_mgmt_get_ifindex(mNetifMgmtFD, mInterfaceName.c_str());
293
0
  bool success = false;
294
0
  struct ipv6_mreq mreq6;
295
296
0
  mMLDMonitorFD = socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_ICMPV6);
297
0
  mreq6.ipv6mr_interface = interfaceIndex;
298
0
  inet_pton(AF_INET6, kMLDv2MulticastAddress, &mreq6.ipv6mr_multiaddr);
299
300
0
  require(setsockopt(mMLDMonitorFD, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6)) == 0, bail);
301
0
  require(setsockopt(mMLDMonitorFD, SOL_SOCKET, SO_BINDTODEVICE, mInterfaceName.c_str(), mInterfaceName.size()) == 0, bail);
302
303
0
  success = true;
304
305
0
bail:
306
0
  if (!success) {
307
0
    if (mMLDMonitorFD >= 0) {
308
0
      close(mMLDMonitorFD);
309
0
    }
310
0
    syslog(LOG_ERR, "listen to MLD messages on interface failed\n");
311
0
  }
312
0
  return;
313
0
}
314
315
int
316
TunnelIPv6Interface::process(void)
317
2.90M
{
318
2.90M
  processNetlinkFD();
319
2.90M
  processMLDMonitorFD();
320
321
2.90M
  return nl::UnixSocket::process();
322
2.90M
}
323
324
void
325
TunnelIPv6Interface::processNetlinkFD(void)
326
2.90M
{
327
2.90M
  uint8_t buffer[4096];
328
2.90M
  ssize_t buffer_len(-1);
329
330
2.90M
  if (mNetlinkFD >= 0) {
331
0
    buffer_len = recv(mNetlinkFD, buffer, sizeof(buffer), 0);
332
0
  }
333
334
2.90M
  if (buffer_len > 0) {
335
0
    struct nlmsghdr *nlp;
336
0
    struct rtmsg *rtp;
337
0
    int rta_len;
338
0
    struct rtattr *rta;
339
340
0
    nlp = (struct nlmsghdr *)buffer;
341
0
    for (;NLMSG_OK(nlp, buffer_len); nlp=NLMSG_NEXT(nlp, buffer_len))
342
0
    {
343
0
      char ifnamebuf[IF_NAMESIZE];
344
0
      if (nlp->nlmsg_type == RTM_NEWADDR || nlp->nlmsg_type == RTM_DELADDR) {
345
0
        struct ifaddrmsg *ifaddr = (struct ifaddrmsg *)NLMSG_DATA(nlp);
346
0
        const char *ifname = if_indextoname(ifaddr->ifa_index, ifnamebuf);
347
0
        struct in6_addr addr;
348
349
0
        if ((ifname == NULL) || (get_interface_name() != ifname)) {
350
0
          continue;
351
0
        }
352
353
        // get RTNETLINK message header
354
        // get start of attributes
355
0
        rta = (struct rtattr *) IFA_RTA(ifaddr);
356
357
        // get length of attributes
358
0
        rta_len = IFA_PAYLOAD(nlp);
359
360
0
        for(;RTA_OK(rta, rta_len); rta = RTA_NEXT(rta, rta_len)) {
361
0
          switch(rta->rta_type) {
362
0
          case IFA_ADDRESS:
363
0
          case IFA_LOCAL:
364
0
          case IFA_BROADCAST:
365
0
          case IFA_ANYCAST:
366
0
            memcpy(addr.s6_addr, RTA_DATA(rta), sizeof(addr));
367
368
0
            if (nlp->nlmsg_type == RTM_NEWADDR) {
369
0
              on_address_added(addr, ifaddr->ifa_prefixlen);
370
0
            } else if (nlp->nlmsg_type == RTM_DELADDR) {
371
0
              on_address_removed(addr, ifaddr->ifa_prefixlen);
372
0
            }
373
0
            break;
374
0
          default:
375
0
            break;
376
0
          }
377
0
        }
378
0
      } else if (nlp->nlmsg_type == RTM_NEWLINK || nlp->nlmsg_type == RTM_DELLINK) {
379
0
        struct ifinfomsg *ifinfo = (struct ifinfomsg *)NLMSG_DATA(nlp);
380
0
        const char *ifname = if_indextoname(ifinfo->ifi_index, ifnamebuf);
381
0
        bool isUp, isRunning;
382
383
0
        if ((ifname == NULL) || (get_interface_name() != ifname)) {
384
0
          continue;
385
0
        }
386
387
0
        isUp = ((ifinfo->ifi_flags & IFF_UP) == IFF_UP);
388
0
        isRunning = ((ifinfo->ifi_flags & IFF_RUNNING) == IFF_RUNNING);
389
390
0
        on_link_state_changed(isUp, isRunning);
391
0
      }
392
0
    }
393
0
  }
394
2.90M
}
395
396
static bool IsMulticastAddressFiltered(const struct in6_addr& addr_to_check) 
397
0
{
398
0
  bool found = false;
399
400
0
  for (size_t i = 0; i < sizeof(kFilterMulticastAddresses) /
401
0
                             sizeof(kFilterMulticastAddresses[0]);
402
0
       i++) {
403
0
      struct in6_addr addr; 
404
405
0
      inet_pton(AF_INET6, kFilterMulticastAddresses[i], &addr);
406
0
      if (memcmp(&addr, &addr_to_check, sizeof(addr)) == 0) {
407
0
        found = true;
408
0
        break;
409
0
      }
410
0
  }
411
412
0
  return found;
413
0
}
414
415
void
416
TunnelIPv6Interface::processMLDMonitorFD(void)
417
2.90M
{
418
2.90M
  uint8_t buffer[4096];
419
2.90M
  ssize_t bufferLen(-1);
420
2.90M
  struct sockaddr_in6 srcAddr;
421
2.90M
  socklen_t addrLen;
422
2.90M
  bool fromSelf = false;
423
2.90M
  MLDv2Header* hdr = reinterpret_cast<MLDv2Header *>(buffer);
424
2.90M
  ssize_t offset;
425
2.90M
  uint8_t type;
426
2.90M
  struct ifaddrs *ifAddrs = NULL;
427
428
2.90M
  if (mNetlinkFD >= 0) {
429
0
    bufferLen = recvfrom(mMLDMonitorFD, buffer, sizeof(buffer), 0, reinterpret_cast<sockaddr *>(&srcAddr), &addrLen);
430
0
  }
431
2.90M
  require_quiet(bufferLen > 0, bail);
432
433
0
  type = buffer[0];
434
0
  require_quiet(type == kICMPv6MLDv2Type && bufferLen >= sizeof(MLDv2Header), bail);
435
436
  // Check whether it is sent by self
437
0
  require(getifaddrs(&ifAddrs) == 0, bail);
438
0
  for (struct ifaddrs* ifAddr = ifAddrs; ifAddr != NULL; ifAddr = ifAddr->ifa_next) {
439
0
    if (ifAddr->ifa_addr != NULL && ifAddr->ifa_addr->sa_family == AF_INET6 &&
440
0
        mInterfaceName == std::string(ifAddr->ifa_name)) {
441
0
      struct sockaddr_in6 *addr6 = reinterpret_cast<struct sockaddr_in6 *>(ifAddr->ifa_addr);
442
443
0
      if (memcmp(&addr6->sin6_addr, &srcAddr.sin6_addr, sizeof(in6_addr)) == 0) {
444
0
        fromSelf = true;
445
0
        break;
446
0
      }
447
0
    }
448
0
  }
449
0
  require_quiet(fromSelf, bail);
450
451
0
  hdr = reinterpret_cast<MLDv2Header *>(buffer);
452
0
  offset = sizeof(MLDv2Header);
453
454
0
  for (size_t i = 0; i < ntohs(hdr->mNumRecords) && offset < bufferLen; i++) {
455
0
    if (bufferLen - offset >= sizeof(MLDv2Record)) {
456
0
      MLDv2Record *record = reinterpret_cast<MLDv2Record *>(&buffer[offset]);
457
458
0
      if (!IsMulticastAddressFiltered(record->mMulticastAddress)) {
459
0
        if (record->mRecordType == kICMPv6MLDv2RecordChangeToIncludeType) {
460
0
          on_multicast_address_joined(record->mMulticastAddress);
461
0
        } else if (record->mRecordType == kICMPv6MLDv2RecordChangeToExcludeType) {
462
0
          on_multicast_address_left(record->mMulticastAddress);
463
0
        }
464
0
      }
465
466
0
      offset += sizeof(MLDv2Record) + sizeof(in6_addr) * ntohs(record->mNumSources);
467
0
    }
468
0
  }
469
470
2.90M
bail:
471
2.90M
  if (ifAddrs) {
472
0
    freeifaddrs(ifAddrs);
473
0
  }
474
475
2.90M
  return;
476
0
}
477
478
#else // ----------------------------------------------------------------------
479
480
void
481
TunnelIPv6Interface::setup_signals(void)
482
{
483
  // Unknown platform.
484
}
485
486
int
487
TunnelIPv6Interface::process(void)
488
{
489
  return nl::UnixSocket::process();
490
}
491
492
void
493
TunnelIPv6Interface::processNetlinkFD(void)
494
{
495
}
496
497
void
498
TunnelIPv6Interface::processMLDMonitorFD(void)
499
{
500
}
501
502
#endif // ---------------------------------------------------------------------
503
504
int
505
TunnelIPv6Interface::update_fd_set(fd_set *read_fd_set, fd_set *write_fd_set, fd_set *error_fd_set, int *max_fd, cms_t *timeout)
506
5.85M
{
507
5.85M
  if (read_fd_set) {
508
2.92M
    if (mNetlinkFD >= 0)  {
509
0
      FD_SET(mNetlinkFD, read_fd_set);
510
0
    }
511
512
2.92M
    if (mMLDMonitorFD >= 0) {
513
0
      FD_SET(mMLDMonitorFD, read_fd_set);
514
0
    }
515
516
2.92M
    if ((max_fd != NULL)) {
517
2.92M
      *max_fd = std::max(*max_fd, mNetlinkFD);
518
2.92M
      *max_fd = std::max(*max_fd, mMLDMonitorFD);
519
2.92M
    }
520
2.92M
  }
521
522
5.85M
  return nl::UnixSocket::update_fd_set(read_fd_set, write_fd_set, error_fd_set, max_fd, timeout);
523
5.85M
}
524
525
const std::string&
526
TunnelIPv6Interface::get_interface_name(void)
527
0
{
528
0
  return mInterfaceName;
529
0
}
530
531
int
532
TunnelIPv6Interface::get_last_error(void)
533
0
{
534
0
  return mLastError;
535
0
}
536
537
bool
538
TunnelIPv6Interface::is_up(void)
539
0
{
540
0
  return netif_mgmt_is_up(mNetifMgmtFD, mInterfaceName.c_str());
541
0
}
542
543
bool
544
TunnelIPv6Interface::is_running(void)
545
7.45k
{
546
7.45k
  return netif_mgmt_is_running(mNetifMgmtFD, mInterfaceName.c_str());
547
7.45k
}
548
549
bool
550
TunnelIPv6Interface::is_online(void)
551
31.8k
{
552
31.8k
  static const int online_flags = IFF_UP | IFF_RUNNING;
553
31.8k
  return (netif_mgmt_get_flags(mNetifMgmtFD, mInterfaceName.c_str()) & online_flags) == online_flags;
554
31.8k
}
555
556
int
557
TunnelIPv6Interface::set_up(bool isUp)
558
0
{
559
0
  int ret = 0;
560
0
  bool old = is_up();
561
562
0
  if (isUp != old) {
563
0
    if (isUp) {
564
0
      syslog(LOG_INFO, "Bringing interface %s up. . .", mInterfaceName.c_str());
565
0
    } else {
566
0
      syslog(LOG_INFO, "Taking interface %s down. . .", mInterfaceName.c_str());
567
0
    }
568
569
0
    ret = netif_mgmt_set_up(mNetifMgmtFD, mInterfaceName.c_str(), isUp);
570
571
0
    require_action(ret == 0, bail, mLastError = errno);
572
0
  }
573
574
0
bail:
575
0
  return ret;
576
0
}
577
578
int
579
TunnelIPv6Interface::set_running(bool isRunning)
580
7.45k
{
581
7.45k
  int ret = 0;
582
7.45k
  bool old = is_running();
583
584
7.45k
  if (isRunning != old) {
585
2.35k
    if (isRunning) {
586
2.35k
      syslog(LOG_INFO, "Bringing interface %s online. . .", mInterfaceName.c_str());
587
2.35k
    } else {
588
0
      syslog(LOG_INFO, "Taking interface %s offline. . .", mInterfaceName.c_str());
589
0
    }
590
591
2.35k
    ret = netif_mgmt_set_running(mNetifMgmtFD, mInterfaceName.c_str(), isRunning);
592
593
2.35k
    mLastError = errno;
594
595
2.35k
    require_action(ret == 0, bail, mLastError = errno);
596
597
2.35k
  }
598
599
7.45k
bail:
600
7.45k
  return ret;
601
7.45k
}
602
603
604
int
605
TunnelIPv6Interface::set_online(bool online)
606
7.45k
{
607
7.45k
  return set_running(online);
608
7.45k
}
609
610
void
611
TunnelIPv6Interface::reset(void)
612
2.99k
{
613
2.99k
  syslog(LOG_INFO, "Resetting interface %s. . .", mInterfaceName.c_str());
614
2.99k
  set_online(false);
615
2.99k
}
616
617
618
bool
619
TunnelIPv6Interface::add_address(const struct in6_addr *addr, int prefixlen)
620
13.7k
{
621
13.7k
  bool ret = false;
622
623
13.7k
  require_action(!IN6_IS_ADDR_UNSPECIFIED(addr), bail, mLastError = EINVAL);
624
625
13.6k
  if (mUnicastAddresses.count(*addr)) {
626
0
    ret = true;
627
0
    goto bail;
628
0
  }
629
630
13.6k
  if (is_online()) {
631
0
    syslog(LOG_INFO, "Adding address \"%s/%d\" to interface \"%s\"",
632
0
           in6_addr_to_string(*addr).c_str(), prefixlen, mInterfaceName.c_str());
633
634
0
    require_noerr_action(
635
0
      netif_mgmt_add_ipv6_address(mNetifMgmtFD, mInterfaceName.c_str(), addr->s6_addr, prefixlen),
636
0
      bail,
637
0
      mLastError = errno
638
0
    );
639
0
    mUnicastAddresses[*addr] = Entry(Entry::kWaitingForAddConfirm, prefixlen);
640
13.6k
  } else {
641
13.6k
    mUnicastAddresses[*addr] = Entry(Entry::kWaitingToAdd, prefixlen);
642
13.6k
  }
643
644
13.6k
  ret = true;
645
646
13.7k
bail:
647
13.7k
  return ret;
648
13.6k
}
649
650
bool
651
TunnelIPv6Interface::remove_address(const struct in6_addr *addr, int prefixlen)
652
11.5k
{
653
11.5k
  bool ret = false;
654
655
11.5k
  require_action(!IN6_IS_ADDR_UNSPECIFIED(addr), bail, mLastError = EINVAL);
656
657
11.4k
  if (mUnicastAddresses.count(*addr)) {
658
11.4k
    mUnicastAddresses.erase(*addr);
659
11.4k
  }
660
661
11.4k
  if (netif_mgmt_remove_ipv6_address(mNetifMgmtFD, mInterfaceName.c_str(), addr->s6_addr) != 0) {
662
11.4k
    mLastError = errno;
663
11.4k
    goto bail;
664
11.4k
  }
665
666
0
  syslog(LOG_INFO,"Removing address \"%s\" from interface \"%s\"",
667
0
         in6_addr_to_string(*addr).c_str(), mInterfaceName.c_str());
668
0
  ret = true;
669
670
11.5k
bail:
671
11.5k
  return ret;
672
0
}
673
674
bool
675
TunnelIPv6Interface::join_multicast_address(const struct in6_addr *addr)
676
18.2k
{
677
18.2k
  bool ret = false;
678
679
18.2k
  require_action(!IN6_IS_ADDR_UNSPECIFIED(addr), bail, mLastError = EINVAL);
680
681
18.2k
  if (is_online()) {
682
0
    if (netif_mgmt_join_ipv6_multicast_address(mNetifMgmtFD, mInterfaceName.c_str(), addr->s6_addr) != 0) {
683
0
      mLastError = errno;
684
0
      goto bail;
685
0
    }
686
687
0
    syslog(LOG_INFO, "Joining multicast address \"%s\" on interface \"%s\".",
688
0
           in6_addr_to_string(*addr).c_str(), mInterfaceName.c_str());
689
18.2k
  } else {
690
18.2k
    mPendingMulticastAddresses[*addr] = Entry(Entry::kWaitingToAdd);
691
18.2k
  }
692
693
18.2k
  ret = true;
694
695
18.2k
bail:
696
18.2k
  return ret;
697
18.2k
}
698
699
bool
700
TunnelIPv6Interface::leave_multicast_address(const struct in6_addr *addr)
701
3.42k
{
702
3.42k
  bool ret = false;
703
704
3.42k
  require_action(!IN6_IS_ADDR_UNSPECIFIED(addr), bail, mLastError = EINVAL);
705
706
3.42k
  if (mPendingMulticastAddresses.count(*addr)) {
707
3.42k
    mPendingMulticastAddresses.erase(*addr);
708
3.42k
  }
709
710
3.42k
  if (netif_mgmt_leave_ipv6_multicast_address(mNetifMgmtFD, mInterfaceName.c_str(), addr->s6_addr) != 0) {
711
3.42k
    mLastError = errno;
712
3.42k
    goto bail;
713
3.42k
  }
714
715
0
  syslog(LOG_INFO, "Leaving multicast address \"%s\" on interface \"%s\".",
716
0
         in6_addr_to_string(*addr).c_str(), mInterfaceName.c_str());
717
0
  ret = true;
718
719
3.42k
bail:
720
3.42k
  return ret;
721
0
}
722
723
724
bool
725
TunnelIPv6Interface::add_route(const struct in6_addr *route, int prefixlen, uint32_t metric)
726
13.8k
{
727
13.8k
  bool ret = false;
728
729
13.8k
  if (netif_mgmt_add_ipv6_route(mNetifMgmtFD, mInterfaceName.c_str(), route->s6_addr, prefixlen, metric) != 0) {
730
13.8k
    mLastError = errno;
731
13.8k
    goto bail;
732
13.8k
  }
733
0
  syslog(LOG_INFO, "Adding route prefix \"%s/%d\" on interface \"%s\".",
734
0
         in6_addr_to_string(*route).c_str(), prefixlen, mInterfaceName.c_str());
735
736
0
  ret = true;
737
738
13.8k
bail:
739
13.8k
  return ret;
740
0
}
741
742
bool
743
TunnelIPv6Interface::remove_route(const struct in6_addr *route, int prefixlen, uint32_t metric)
744
11.3k
{
745
11.3k
  bool ret = false;
746
747
11.3k
  if (netif_mgmt_remove_ipv6_route(mNetifMgmtFD, mInterfaceName.c_str(), route->s6_addr, prefixlen, metric) != 0) {
748
11.3k
    mLastError = errno;
749
11.3k
    goto bail;
750
11.3k
  }
751
752
0
  syslog(LOG_INFO, "Removing route prefix \"%s/%d\" on interface \"%s\".",
753
0
         in6_addr_to_string(*route).c_str(), prefixlen, mInterfaceName.c_str());
754
755
0
  ret = true;
756
757
11.3k
bail:
758
11.3k
  return ret;
759
0
}
760
761
ssize_t
762
TunnelIPv6Interface::read(void* data, size_t len)
763
0
{
764
0
  ssize_t ret = nl::UnixSocket::read(data, len);
765
0
  uint8_t *data_bytes = static_cast<uint8_t*>(data);
766
767
  // Remove any subheader, if present.
768
0
  if ((ret >= 4) && (data_bytes[0] == 0) && (data_bytes[1] == 0)) {
769
0
    ret -= 4;
770
0
    memmove(data, static_cast<const void*>(data_bytes + 4), ret);
771
0
  }
772
773
0
  return ret;
774
0
}
775
776
ssize_t
777
TunnelIPv6Interface::write(const void* data, size_t len)
778
13.2k
{
779
#ifdef __APPLE__
780
  const uint8_t* const data_bytes = static_cast<const uint8_t*>(data);
781
782
  if ((data_bytes[0] != 0) || (data_bytes[0] != 0)) {
783
    // The utun interface on OS X needs this header.
784
    // Linux seems to be able to infer the type of the packet
785
    // with no problems.
786
    uint8_t packet[len + 4];
787
    packet[0] = 0;
788
    packet[1] = 0;
789
    packet[2] = (PF_INET6 << 8) & 0xFF;
790
    packet[3] = (PF_INET6 << 0) & 0xFF;
791
    memcpy(static_cast<void*>(packet + 4), data, len);
792
    ssize_t ret = nl::UnixSocket::write(packet, len + 4);
793
    return (ret >= 4)?(ret - 4):(-1);
794
  }
795
#endif
796
13.2k
  return nl::UnixSocket::write(data, len);
797
13.2k
}