910e62b5创建于 1月15日历史提交
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/address_tracker_linux_test_util.h"

#include <linux/if.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <stdint.h>
#include <string.h>

#include <array>
#include <vector>

#include "base/check_op.h"
#include "base/containers/span.h"
#include "base/logging.h"
#include "net/base/ip_address.h"

bool operator==(const struct ifaddrmsg& lhs, const struct ifaddrmsg& rhs) {
  return base::byte_span_from_ref(lhs) == base::byte_span_from_ref(rhs);
}

namespace net::test {

NetlinkMessage::NetlinkMessage(uint16_t type) : buffer_(NLMSG_HDRLEN) {
  header()->nlmsg_type = type;
  Align();
}

NetlinkMessage::~NetlinkMessage() = default;

void NetlinkMessage::AddPayload(base::span<const uint8_t> data) {
  CHECK_EQ(static_cast<size_t>(NLMSG_HDRLEN), buffer_.size())
      << "Payload must be added first";
  Append(data);
  Align();
}

void NetlinkMessage::AddAttribute(uint16_t type,
                                  base::span<const uint8_t> data) {
  struct nlattr attr;
  attr.nla_len = NLA_HDRLEN + data.size();
  attr.nla_type = type;
  Append(base::byte_span_from_ref(attr));
  Align();
  Append(data);
  Align();
}

void NetlinkMessage::AppendTo(NetlinkBuffer* output) const {
  CHECK_EQ(NLMSG_ALIGN(output->size()), output->size());
  output->insert(output->end(), buffer_.begin(), buffer_.end());
}

void NetlinkMessage::Append(base::span<const uint8_t> data) {
  buffer_.insert(buffer_.end(), data.begin(), data.end());
}

void NetlinkMessage::Align() {
  header()->nlmsg_len = buffer_.size();
  buffer_.resize(NLMSG_ALIGN(buffer_.size()));
  CHECK(NLMSG_OK(header(), buffer_.size()));
}

#define INFINITY_LIFE_TIME 0xFFFFFFFF

void MakeAddrMessageWithCacheInfo(uint16_t type,
                                  uint8_t flags,
                                  uint8_t family,
                                  int index,
                                  const IPAddress& address,
                                  const IPAddress& local,
                                  uint32_t preferred_lifetime,
                                  NetlinkBuffer* output) {
  NetlinkMessage nlmsg(type);
  ifaddrmsg msg = {};
  msg.ifa_family = family;
  msg.ifa_flags = flags;
  msg.ifa_index = index;
  nlmsg.AddPayload(base::byte_span_from_ref(msg));
  if (address.size()) {
    nlmsg.AddAttribute(IFA_ADDRESS, address.bytes().span());
  }
  if (local.size()) {
    nlmsg.AddAttribute(IFA_LOCAL, local.bytes().span());
  }
  ifa_cacheinfo cache_info = {};
  cache_info.ifa_prefered = preferred_lifetime;
  cache_info.ifa_valid = INFINITY_LIFE_TIME;
  nlmsg.AddAttribute(IFA_CACHEINFO, base::byte_span_from_ref(cache_info));
  nlmsg.AppendTo(output);
}

void MakeAddrMessage(uint16_t type,
                     uint8_t flags,
                     uint8_t family,
                     int index,
                     const IPAddress& address,
                     const IPAddress& local,
                     NetlinkBuffer* output) {
  MakeAddrMessageWithCacheInfo(type, flags, family, index, address, local,
                               INFINITY_LIFE_TIME, output);
}

void MakeLinkMessage(uint16_t type,
                     uint32_t flags,
                     uint32_t index,
                     NetlinkBuffer* output,
                     bool clear_output) {
  NetlinkMessage nlmsg(type);
  ifinfomsg msg = {};
  msg.ifi_index = index;
  msg.ifi_flags = flags;
  msg.ifi_change = 0xFFFFFFFF;
  nlmsg.AddPayload(base::byte_span_from_ref(msg));
  if (clear_output) {
    output->clear();
  }
  nlmsg.AppendTo(output);
}

// Creates a netlink message generated by wireless_send_event. These events
// should be ignored.
void MakeWirelessLinkMessage(uint16_t type,
                             uint32_t flags,
                             uint32_t index,
                             NetlinkBuffer* output,
                             bool clear_output) {
  NetlinkMessage nlmsg(type);
  ifinfomsg msg = {};
  msg.ifi_index = index;
  msg.ifi_flags = flags;
  msg.ifi_change = 0;
  nlmsg.AddPayload(base::byte_span_from_ref(msg));
  std::array<uint8_t, 8u> data = {};
  nlmsg.AddAttribute(IFLA_WIRELESS, data);
  if (clear_output) {
    output->clear();
  }
  nlmsg.AppendTo(output);
}

}  // namespace net::test