llarp/net/net.hpp

Namespaces

Name
llarp
[crypto.hpp]
llarp::net

Classes

Name
class llarp::net::Platform
network platform (all methods virtual so it can be mocked by unit tests)

Functions

Name
bool operator==(const in_addr & a, const in_addr & b)
bool operator==(const in6_addr & a, const in6_addr & b)
bool operator==(const sockaddr_in & a, const sockaddr_in & b)
bool operator==(const sockaddr_in6 & a, const sockaddr_in6 & b)
bool operator==(const sockaddr & a, const sockaddr & b)
bool operator<(const in_addr & a, const in_addr & b)
bool operator<(const in6_addr & a, const in6_addr & b)
bool operator<(const sockaddr_in6 & a, const sockaddr_in6 & b)

Functions Documentation

function operator==

inline bool operator==(
    const in_addr & a,
    const in_addr & b
)

function operator==

inline bool operator==(
    const in6_addr & a,
    const in6_addr & b
)

function operator==

inline bool operator==(
    const sockaddr_in & a,
    const sockaddr_in & b
)

function operator==

inline bool operator==(
    const sockaddr_in6 & a,
    const sockaddr_in6 & b
)

function operator==

inline bool operator==(
    const sockaddr & a,
    const sockaddr & b
)

function operator<

inline bool operator<(
    const in_addr & a,
    const in_addr & b
)

function operator<

inline bool operator<(
    const in6_addr & a,
    const in6_addr & b
)

function operator<

inline bool operator<(
    const sockaddr_in6 & a,
    const sockaddr_in6 & b
)

Source code

#pragma once

#include "uint128.hpp"
#include "address_info.hpp"
#include "net_int.hpp"
#include "net.h"
#include "ip_range.hpp"
#include "sock_addr.hpp"
#include <llarp/util/mem.hpp>
#include <llarp/util/bits.hpp>

#include "interface_info.hpp"

#include <functional>
#include <cstdlib>  // for itoa
#include <vector>

// for addrinfo
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

#include <arpa/inet.h>

#include "bogon_ranges.hpp"

namespace llarp
{
  inline int
  cmp(const in_addr& a, const in_addr& b)
  {
    return memcmp(&a, &b, sizeof(in_addr));
  }

  inline int
  cmp(const in6_addr& a, const in6_addr& b)
  {
    return memcmp(&a, &b, sizeof(in6_addr));
  }

  namespace net
  {
    class Platform
    {
     public:
      Platform() = default;
      virtual ~Platform() = default;
      Platform(const Platform&) = delete;
      Platform(Platform&&) = delete;

      static const Platform*
      Default_ptr();

      virtual std::optional<SockAddr>
      AllInterfaces(SockAddr pubaddr) const = 0;

      inline SockAddr
      Wildcard(int af = AF_INET) const
      {
        if (af == AF_INET)
        {
          sockaddr_in addr{};
          addr.sin_family = AF_INET;
          addr.sin_addr.s_addr = htonl(INADDR_ANY);
          addr.sin_port = htons(0);
          return SockAddr{addr};
        }
        if (af == AF_INET6)
        {
          sockaddr_in6 addr6{};
          addr6.sin6_family = AF_INET6;
          addr6.sin6_port = htons(0);
          addr6.sin6_addr = IN6ADDR_ANY_INIT;
          return SockAddr{addr6};
        }
        throw std::invalid_argument{fmt::format("{} is not a valid address family", af)};
      }

      inline SockAddr
      WildcardWithPort(port_t port, int af = AF_INET) const
      {
        auto addr = Wildcard(af);
        addr.setPort(port);
        return addr;
      }

      virtual std::string
      LoopbackInterfaceName() const = 0;

      virtual bool
      HasInterfaceAddress(ipaddr_t ip) const = 0;

      inline bool
      IsLoopbackAddress(ipaddr_t ip) const
      {
        const IPRange loopback4 = IPRange::FromIPv4(127, 0, 0, 0, 8);
        const IPRange loopback6{
            net::ipv6addr_t::from_host(uint128_t{0UL, 1UL}), netmask_ipv6_bits(128)};
        return var::visit(
            [&loopback4, &loopback6](auto&& ip) {
              return loopback4.Contains(ip) or loopback6.Contains(ip);
            },
            ip);
      }

      inline bool
      IsWildcardAddress(ipaddr_t ip) const
      {
        return var::visit([](auto&& ip) { return not ip.n; }, ip);
      }

      virtual std::optional<std::string>
      GetBestNetIF(int af = AF_INET) const = 0;

      inline std::optional<SockAddr>
      MaybeInferPublicAddr(port_t default_port, int af = AF_INET) const
      {
        std::optional<SockAddr> maybe_addr;
        if (auto maybe_ifname = GetBestNetIF(af))
          maybe_addr = GetInterfaceAddr(*maybe_ifname, af);

        if (maybe_addr)
          maybe_addr->setPort(default_port);
        return maybe_addr;
      }

      virtual std::optional<IPRange>
      FindFreeRange() const = 0;

      virtual std::optional<std::string>
      FindFreeTun() const = 0;

      virtual std::optional<SockAddr>
      GetInterfaceAddr(std::string_view ifname, int af = AF_INET) const = 0;

      inline std::optional<net::ipv6addr_t>
      GetInterfaceIPv6Address(std::string_view ifname) const
      {
        if (auto maybe_addr = GetInterfaceAddr(ifname, AF_INET6))
          return maybe_addr->getIPv6();
        return std::nullopt;
      }

      inline bool
      IsBogon(const SockAddr& addr) const
      {
        return IsBogonIP(addr.getIPv6());
      }

      inline bool
      IsBogonRange(const IPRange& range) const
      {
        // special case for 0.0.0.0/0
        if (range.IsV4() and range.netmask_bits == netmask_ipv6_bits(96))
          return false;
        // special case for ::/0
        if (IsWildcardAddress(range.netmask_bits))
          return false;
        return IsBogonIP(range.addr) or IsBogonIP(range.HighestAddr());
      }

      inline bool
      IsBogonIP(const net::ipaddr_t& addr) const
      {
        return IsBogonIP(var::visit(
            [](auto&& ip) {
              if constexpr (std::is_same_v<net::ipv4addr_t, std::decay_t<decltype(ip)>>)
                return ExpandV4(ip);
              else
                return ip;
            },
            addr));
      }
      inline bool
      IsBogonIP(const net::ipv6addr_t& addr) const
      {
        if (not IPRange::V4MappedRange().Contains(addr))
        {
          for (const auto& v6_range : bogonRanges_v6)
          {
            if (v6_range.Contains(addr))
              return true;
          }
          return false;
        }
        const auto v4_addr = net::TruncateV6(addr);
        for (const auto& v4_range : bogonRanges_v4)
        {
          if (v4_range.Contains(v4_addr))
            return true;
        }
        return false;
      }

      virtual std::optional<int>
      GetInterfaceIndex(ipaddr_t ip) const = 0;

      virtual std::vector<InterfaceInfo>
      AllNetworkInterfaces() const = 0;
    };

  }  // namespace net

}  // namespace llarp

inline bool
operator==(const in_addr& a, const in_addr& b)
{
  return llarp::cmp(a, b) == 0;
}

inline bool
operator==(const in6_addr& a, const in6_addr& b)
{
  return llarp::cmp(a, b) == 0;
}

inline bool
operator==(const sockaddr_in& a, const sockaddr_in& b)
{
  return a.sin_port == b.sin_port and a.sin_addr.s_addr == b.sin_addr.s_addr;
}

inline bool
operator==(const sockaddr_in6& a, const sockaddr_in6& b)
{
  return a.sin6_port == b.sin6_port and a.sin6_addr == b.sin6_addr;
}

inline bool
operator==(const sockaddr& a, const sockaddr& b)
{
  if (a.sa_family != b.sa_family)
    return false;
  switch (a.sa_family)
  {
    case AF_INET:
      return reinterpret_cast<const sockaddr_in&>(a) == reinterpret_cast<const sockaddr_in&>(b);
    case AF_INET6:
      return reinterpret_cast<const sockaddr_in6&>(a) == reinterpret_cast<const sockaddr_in6&>(b);
    default:
      return false;
  }
}

inline bool
operator<(const in_addr& a, const in_addr& b)
{
  return llarp::cmp(a, b) < 0;
}

inline bool
operator<(const in6_addr& a, const in6_addr& b)
{
  return llarp::cmp(a, b) < 0;
}

inline bool
operator<(const sockaddr_in6& a, const sockaddr_in6& b)
{
  return std::tie(a.sin6_addr, a.sin6_port) < std::tie(b.sin6_addr, b.sin6_port);
}

Updated on 2026-01-10 at 22:49:45 +0000