master
cpp 163 lines 4.67 KB
Raw
1 // Copyright (C) Microsoft Corporation. All rights reserved.
2 #include <iostream>
3 #include <regex>
4 #include "address.h"
5 #include "Syscall.h"
6
7 Address::Address(short family, size_t prefixLength, const std::string& address, IpPrefixOrigin prefixOrigin, IpSuffixOrigin suffixOrigin, int preferredLifetime) :
8 m_family(family), m_prefixLength(prefixLength), m_address(address), m_prefixOrigin(prefixOrigin), m_suffixOrigin(suffixOrigin)
9 {
10 // We cannot plumb temporary addresses (identified by RA prefix and random suffix) in Linux.
11 // In order for Linux to prefer temporary addresses over public addresses during source address
12 // selection, we instead mark public addresses as deprecated and plumb temporary addresses as
13 // public preferred addresses.
14 if (preferredLifetime == 0 || (prefixOrigin == IpPrefixOrigin::RouterAdvertisement && suffixOrigin == IpSuffixOrigin::LinkLayerAddress))
15 {
16 m_preferredLifetime = 0;
17 }
18 else
19 {
20 m_preferredLifetime = 0xFFFFFFFF;
21 }
22 }
23
24 Address::Address(short family, size_t prefixLength, const std::string& address) :
25 Address(family, prefixLength, address, IpPrefixOrigin::Manual, IpSuffixOrigin::Manual, 0xFFFFFFFF)
26 {
27 }
28
29 bool Address::operator==(const Address& other) const
30 {
31 return m_family == other.Family() && m_address == other.Addr() && m_prefixLength == other.PrefixLength();
32 }
33
34 bool Address::operator!=(const Address& other) const
35 {
36 return !(*this == other);
37 }
38
39 std::ostream& operator<<(std::ostream& out, const Address& address)
40 {
41 return out << address.Addr() << "/" << address.PrefixLength();
42 }
43
44 Address Address::FromBytes(int family, int prefixLength, const void* ptr)
45 {
46 static_assert(INET6_ADDRSTRLEN > INET_ADDRSTRLEN);
47
48 std::string addressString(INET6_ADDRSTRLEN, '\0');
49
50 if (inet_ntop(family, ptr, addressString.data(), addressString.size()) == nullptr)
51 {
52 throw RuntimeErrorWithSourceLocation(std::format("inet_ntop failed, {}", errno));
53 }
54
55 return {family, static_cast<size_t>(prefixLength), addressString.c_str()};
56 }
57
58 void Address::ConvertToBytes(void* ptr) const
59 {
60 Syscall(inet_pton, m_family, m_address.c_str(), ptr);
61 }
62
63 Address Address::FromPrefixString(int family, const std::string& prefix)
64 {
65 const std::regex exp(R"((.*)\/((\d){1,3}))");
66 std::smatch match;
67 if (!std::regex_search(prefix.begin(), prefix.end(), match, exp) || match.size() != 4)
68 {
69 throw RuntimeErrorWithSourceLocation(std::format("Failed to parse prefix: {}", prefix));
70 }
71
72 in6_addr tmpAddr;
73 int err = inet_pton(family, match.str(1).c_str(), &tmpAddr);
74 if (err != 1)
75 {
76 throw RuntimeErrorWithSourceLocation(std::format(
77 "Parsed invalid address ({}) from prefix: {} and family: {} with error {} and errno {}", match.str(1), prefix, family, err, errno));
78 }
79
80 return Address{family, std::stoul(match.str(2)), match.str(1)};
81 }
82
83 Address Address::FromBinary(int family, int prefixLength, const void* data)
84 {
85 std::string addr(INET6_ADDRSTRLEN, '\0');
86 if (inet_ntop(family, data, addr.data(), addr.size()) == nullptr)
87 {
88 throw RuntimeErrorWithSourceLocation(
89 std::format("inet_ntop failed for family {} prefixLength {} with errno {}", family, prefixLength, errno));
90 }
91
92 addr.resize(strlen(addr.c_str()));
93
94 return {family, static_cast<size_t>(prefixLength), addr};
95 }
96
97 short Address::Family() const noexcept
98 {
99 return m_family;
100 }
101
102 size_t Address::PrefixLength() const noexcept
103 {
104 return m_prefixLength;
105 }
106
107 const std::string Address::Addr() const noexcept
108 {
109 return m_address;
110 }
111
112 int Address::Flags() const noexcept
113 {
114 // Note: the below is only useful if the kernel ever supports plumbing temporary addresses
115 int flags = 0;
116 if (m_prefixOrigin == IpPrefixOrigin::RouterAdvertisement && m_suffixOrigin == IpSuffixOrigin::Random)
117 {
118 flags |= IFA_F_TEMPORARY;
119 }
120
121 return flags;
122 }
123
124 int Address::Scope() const noexcept
125 {
126 if (m_prefixOrigin == IpPrefixOrigin::WellKnown && m_suffixOrigin == IpSuffixOrigin::LinkLayerAddress)
127 {
128 return RT_SCOPE_LINK;
129 }
130
131 return RT_SCOPE_UNIVERSE;
132 }
133
134 int Address::PreferredLifetime() const noexcept
135 {
136 return m_preferredLifetime;
137 }
138
139 bool Address::IsIpv4() const noexcept
140 {
141 return m_family == AF_INET;
142 }
143
144 bool Address::IsLinkLocal() const
145 {
146 if (m_family == AF_INET)
147 {
148 return (ntohl(AsBytes<in_addr>().s_addr) & 0xFFFF0000) == 0xA9FE0000;
149 }
150
151 if (m_family == AF_INET6)
152 {
153 const auto bytes = AsBytes<in6_addr>();
154 return bytes.s6_addr[0] == 0xFE && (bytes.s6_addr[1] & 0xC0) == 0x80;
155 }
156
157 return false;
158 }
159
160 bool Address::IsPrefixRouteAutogenerationDisabled() const noexcept
161 {
162 return m_disableAutogeneratedPrefixRoute;
163 }