Skip to content

Commit 2393667

Browse files
committed
Change the format of SCION-mapped IPv6 addresses
1 parent 7588085 commit 2393667

14 files changed

Lines changed: 502 additions & 149 deletions

File tree

‎Makefile‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ BUILD_DIR := $(SRC_ROOT)/build
77
PKG_DIR := $(SRC_ROOT)/out
88
PYTHONPATH := $(PYTHONPATH):$(SRC_ROOT)/python
99

10-
DOCKER_TAG := 0.0.5
10+
DOCKER_TAG := 0.1.0
1111
HOST_UID := $(shell id -u):$(shell id -g)
1212

1313
TEST_DATA=$(addsuffix .bin,$(basename $(shell find tests scitra/tests -name '*.py')))

‎cmake/version.cmake‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ set(SCION_C_SO_VERSION 0)
1111
set(INTERPOSER_VERSION 0.0.5)
1212
set(INTERPOSER_SO_VERSION 0)
1313

14-
set(SCITRA_TUN_VERSION 0.0.5)
14+
set(SCITRA_TUN_VERSION 0.1.0)
1515

16-
set(SCION2IP_VERSION 0.0.5)
16+
set(SCION2IP_VERSION 0.1.0)

‎docker/scitra-tun/README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ without requiring dependencies on the host except for Docker and the SCION Daemo
66

77
Building the image require the scitra-tun Debian packages in the build context:
88
```bash
9-
cp ../../out/scion++-tools_0.0.5-1_amd64.deb ./scitra-tun
10-
cp ../../out/scitra-tun_0.0.5-1_amd64.deb ./scitra-tun
9+
cp ../../out/scion++-tools_0.1.0-1_amd64.deb ./scitra-tun
10+
cp ../../out/scitra-tun_0.1.0-1_amd64.deb ./scitra-tun
1111
docker compose build
1212
```
1313

‎docker/scitra-tun/scitra-tun/Dockerfile‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ RUN apt-get update && apt-get -y upgrade
66

77
# Install deb package but ignore daemon dependency
88
COPY scion++-tools_5-1_amd64.deb /
9-
COPY scitra-tun_0.0.5-1_amd64.deb /
10-
RUN apt-get install -y /scion++-tools_0.0.5-1_amd64.deb /scitra-tun_0.0.5-1_amd64.deb
9+
COPY scitra-tun_0.1.0-1_amd64.deb /
10+
RUN apt-get install -y /scion++-tools_0.1.0-1_amd64.deb /scitra-tun_0.1.0-1_amd64.deb
1111

1212
ENTRYPOINT ["scitra-tun"]
1313
CMD ["lo", "127.0.0.1"]

‎include/scion/addr/generic_ip.hpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,10 @@ class IPAddress
210210
bool isScion() const { return is6() && ((m_hi >> 56) & 0xff) == 0xfc; }
211211

212212
/// \brief Tell whether this is a SCION-IPv4-mapped IPv6 address.
213-
bool isScion4() const { return isScion() && (m_hi & 0xff'fffful) == 0 && (m_lo >> 32) == 0xffffull; }
213+
bool isScion4() const;
214214

215215
/// \brief Tell whether this is a SCION-IPv6-mapped IPv6 address.
216-
bool isScion6() const { return isScion() && ((m_hi & 0xff'fffful) != 0 || (m_lo >> 32) != 0xffffull); }
216+
bool isScion6() const;
217217

218218
/// \brief Unmaps IPv4-mapped IPv6 addresses to regular IPv4. Returns a copy
219219
/// of the address if it is not a 4-in-6 address.

‎include/scion/addr/mapping.hpp‎

Lines changed: 93 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,96 @@
2929

3030
namespace scion {
3131

32+
/// \brief Prefix of all SCION-mapped IPv6 addresses
3233
constexpr std::uint64_t SCION_IP_PREFIX = 0xfcull << 56;
3334

35+
/// \brief Types/formats of SCION-mapped IPv6 addresses.
36+
enum class ScionIPv6Class
37+
{
38+
/// Not a SCION-mapped IPv6 address
39+
INVALID = 0,
40+
/// 19-bit BGP ASN with IPv4 host address
41+
BGP_IPV4 = 1,
42+
/// 19-bit BGP ASN with 24-bit local prefix and 64-bit interface ID
43+
BGP_IPV6 = 2,
44+
/// 19-bit BGP ASN with 24-bit local prefix and no host address
45+
BGP_WILDCARD = 3,
46+
/// Wildcard ASN
47+
WILDCARD_ASN = 4,
48+
/// 32-bit SCION ASN between 2:0:0 and 2:ffff:ffff with IPv4 host address
49+
PUBLIC_SCION_IPV4 = 13,
50+
/// 32-bit SCION ASN between 2:0:0 and 2:ffff:ffff with 8-bit local prefix
51+
/// and 64-bit interface ID
52+
PUBLIC_SCION_IPV6 = 14,
53+
/// 32-bit SCION ASN between 2:0:0 and 2:ffff:ffff with no host address
54+
PUBLIC_SCION_WILDCARD = 15,
55+
/// Reserved SCION-mapped IPv6 address
56+
RESERVED = 255,
57+
};
58+
59+
/// \brief Returns what type of SCION-mapped IPv6 address `ip` is, or INVALID
60+
/// if `ip` is not a SCION-mapped IPv6 address.
61+
inline ScionIPv6Class classifyScionMappedIP(const generic::IPAddress& ip)
62+
{
63+
auto [prefix, iid] = ip.getIPv6();
64+
if ((prefix & (0xffull << 56)) != SCION_IP_PREFIX)
65+
return ScionIPv6Class::INVALID;
66+
67+
auto flags = ((prefix >> 40) & 0xf);
68+
if ((flags & 0x8) == 0) {
69+
auto asn = ((prefix >> 24) & 0xfffff);
70+
if (asn == 0) return ScionIPv6Class::WILDCARD_ASN;
71+
if ((prefix & ~(~0 << 24)) == 0) {
72+
if (iid == 0)
73+
return ScionIPv6Class::BGP_WILDCARD;
74+
else if ((iid >> 32) == 0xffff)
75+
return ScionIPv6Class::BGP_IPV4;
76+
}
77+
return ScionIPv6Class::BGP_IPV6;
78+
} else if (flags == 0xe) {
79+
if ((prefix & ~(~0 << 8)) == 0) {
80+
if (iid == 0)
81+
return ScionIPv6Class::PUBLIC_SCION_WILDCARD;
82+
else if ((iid >> 32) == 0xffff)
83+
return ScionIPv6Class::PUBLIC_SCION_IPV4;
84+
}
85+
return ScionIPv6Class::PUBLIC_SCION_IPV6;
86+
} else {
87+
return ScionIPv6Class::RESERVED;
88+
}
89+
}
90+
3491
/// \brief Extracts the ISD-ASN from a SCION-mapped IPv6 address.
35-
inline IsdAsn unmapIsdAsn(const generic::IPAddress& ip)
92+
/// \param ip Input address.
93+
/// \param localPrefix If not NULL, localPrefix is set to the AS-local routing
94+
/// prefix extracted from the IPv6 address. The length of this prefix depends
95+
/// on the specific address.
96+
/// \return The extracted ISD-ASN or any empty optional, if the address format
97+
/// is of a reserved type.
98+
inline std::optional<IsdAsn> unmapIsdAsn(
99+
const generic::IPAddress& ip, std::uint32_t* localPrefix = nullptr)
36100
{
37101
auto [hi, lo] = ip.getIPv6();
38-
std::uint_fast16_t isd = ((hi >> 44) & 0xfffull);
39-
std::uint64_t asn = ((hi >> 24) & 0xfffff);
40-
if (asn & (1ull << 19)) asn = 0x2'0000'0000ull | (asn & 0x7ffffull);
102+
std::uint_fast16_t isd = ((hi >> 44) & 0xfff);
103+
std::uint64_t asn = 0;
104+
auto flags = ((hi >> 40) & 0xf);
105+
if ((flags & 0x8) == 0) {
106+
asn = ((hi >> 24) & 0xfffff);
107+
if (localPrefix) *localPrefix = hi & ~(~0 << 24);
108+
} else if (flags == 0xe) {
109+
asn = (2ull << 32) | ((hi >> 8) & 0xffff'ffff);
110+
if (localPrefix) *localPrefix = hi & ~(~0 << 8);
111+
} else {
112+
return std::nullopt; // reserved address
113+
}
41114
return IsdAsn(Isd(isd), Asn(asn));
42115
}
43116

44117
/// \brief Statically map a full SCION address to an IPv6 address if such a
45118
/// mapping is reversible without any additional information.
46119
///
47120
/// The mapping is only possible iff the ISD is smaller than 2^12, and the ASN
48-
/// is either a BGP ASN < 2^19 or a SCION ASN in the range [2:0:0, 2:7:ffff].
121+
/// is either a BGP ASN < 2^19 or a SCION ASN in the range [2:0:0, 2:ffff:ffff].
49122
/// Since the static mapping must be reversible without additional information
50123
/// about the network, the host part must either be an IPv4 address or an IPv6
51124
/// address that already is the SCION-mapped IPv6 itself.
@@ -62,7 +135,7 @@ inline Maybe<generic::IPAddress> mapToIPv6(const ScIPAddress& addr)
62135
} else if (!host.isScion()) {
63136
// can't map IPv6 without loosing parts of the address
64137
return Error(ErrorCode::InvalidArgument);
65-
} else if (unmapIsdAsn(host) != addr.isdAsn()) {
138+
} else if (auto isdAsn = unmapIsdAsn(host); !isdAsn || *isdAsn != addr.isdAsn()) {
66139
// host part is mapped address, but not the right one
67140
return Error(ErrorCode::InvalidArgument);
68141
} else {
@@ -74,36 +147,35 @@ inline Maybe<generic::IPAddress> mapToIPv6(const ScIPAddress& addr)
74147
if (!(isd < (1 << 12))) return Error(ErrorCode::InvalidArgument);
75148

76149
std::uint64_t asn = addr.isdAsn().asn();
77-
std::uint64_t encodedAsn = 0;
150+
std::uint64_t prefix = 0;
78151
if (asn < (1ull << 19)) {
79-
encodedAsn = asn;
80-
} else if (0x2'0000'0000ull <= asn && asn <= 0x2'0007'ffffull) {
81-
encodedAsn = (1ull << 19) | (asn & 0x7ffffull);
152+
prefix = SCION_IP_PREFIX | (isd << 44) | (asn << 24);
153+
} else if (0x2'0000'0000ull <= asn && asn <= 0x2'ffff'ffffull) {
154+
prefix = SCION_IP_PREFIX | (isd << 44) | (0xeull << 40) | ((asn & 0xffff'ffff) << 8);
82155
} else {
83156
return Error(ErrorCode::InvalidArgument);
84157
}
85-
86-
std::uint64_t hi = SCION_IP_PREFIX | (isd << 44) | (encodedAsn << 24);
87-
std::uint64_t lo = 0xffffull << 32 | host.getIPv4();
88-
return generic::IPAddress::MakeIPv6(hi, lo);
158+
return generic::IPAddress::MakeIPv6(prefix, (0xffffull << 32) | host.getIPv4());
89159
}
90160

91161
/// \brief The inverse of mapToIPv6(). Fails with ErrorCode::InvalidArgument
92-
/// if `ip` is not a SCION-mapped IPv6.
162+
/// if `ip` is not a SCION-mapped IPv6. Fails with ErrorCode::NotImplemented
163+
/// if `ip` is a SCION-mapped IPv6 if a reserved format.
93164
inline Maybe<ScIPAddress> unmapFromIPv6(const generic::IPAddress& ip)
94165
{
95166
using generic::IPAddress;
96-
auto [prefix, interface] = ip.getIPv6();
167+
auto [prefix, iid] = ip.getIPv6();
97168
if ((prefix & (0xffull << 56)) != SCION_IP_PREFIX)
98169
return Error(ErrorCode::InvalidArgument); // not the right prefix
99170

100-
auto isdAsn = unmapIsdAsn(ip);
101-
auto localPrefix = prefix & 0xff'ffff;
171+
std::uint32_t localPrefix = 0;
172+
auto isdAsn = unmapIsdAsn(ip, &localPrefix);
173+
if (!isdAsn) return Error(ErrorCode::NotImplemented); // reserved address
102174

103-
if (localPrefix == 0 && (interface >> 32) == 0xffffllu) { // IPv4 host
104-
return ScIPAddress(isdAsn, IPAddress::MakeIPv4(interface & 0xffff'ffffull));
175+
if (localPrefix == 0 && iid != 0 && (iid >> 32) == 0xffff) { // IPv4 host
176+
return ScIPAddress(*isdAsn, IPAddress::MakeIPv4((std::uint32_t)iid));
105177
} else { // IPv6 host
106-
return ScIPAddress(isdAsn, ip);
178+
return ScIPAddress(*isdAsn, ip);
107179
}
108180
}
109181

‎integration-tests/examples/traceroute.py‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def test_traceroute(self):
4040
self.assertEqual(len(lines), 6)
4141
self.assertEqual(lines[0], "Bound to 1-ff00:0:111,127.0.0.1:32767")
4242
self.assertEqual(lines[1], "Using path: 1-ff00:0:111 41>1 1-ff00:0:110 2>1 1-ff00:0:112")
43-
self.assertRegex(lines[2], r"1 1-ff00:0:111 IfID=41 \d\.\d+ms")
44-
self.assertRegex(lines[3], r"2 1-ff00:0:110 IfID=1 \d\.\d+ms")
45-
self.assertRegex(lines[4], r"4 1-ff00:0:110 IfID=2 \d\.\d+ms")
46-
self.assertRegex(lines[5], r"7 1-ff00:0:112 IfID=1 \d\.\d+ms")
43+
self.assertRegex(lines[2], r"1 1-ff00:0:111 IfID=41 \d(\.\d+)?ms")
44+
self.assertRegex(lines[3], r"2 1-ff00:0:110 IfID=1 \d(\.\d+)?ms")
45+
self.assertRegex(lines[4], r"4 1-ff00:0:110 IfID=2 \d(\.\d+)?ms")
46+
self.assertRegex(lines[5], r"7 1-ff00:0:112 IfID=1 \d(\.\d+)?ms")

‎interposer/tests/test_get_name_info.cpp‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ TEST(GetNameInfoTest, ShortBuffer)
117117
using namespace scion;
118118

119119
sockaddr_in6 addr = EndpointTraits<sockaddr_in6>::fromHostPort(
120-
unwrap(ScIPAddress::Parse("4095-2:7:ffff,fcff:ffff:ffaa:aabb:1234:5678:9abc:def0")
120+
unwrap(ScIPAddress::Parse("4095-2:ffff:ffff,fcff:feff:ffff:ff00:1234:5678:9abc:def0")
121121
.and_then(mapToIPv6)
122122
.and_then([] (const scion::generic::IPAddress& x) {
123123
return generic::toUnderlay<in6_addr>(x);
@@ -135,7 +135,7 @@ TEST(GetNameInfoTest, ShortBuffer)
135135
res = interposer_getnameinfo(reinterpret_cast<sockaddr*>(&addr), sizeof(addr),
136136
host.data(), host.size(), nullptr, 0, 0);
137137
ASSERT_EQ(res, 0);
138-
EXPECT_STREQ(host.data(), "4095-2:7:ffff,fcff:ffff:ffaa:aabb:1234:5678:9abc:def0");
138+
EXPECT_STREQ(host.data(), "4095-2:ffff:ffff,fcff:feff:ffff:ff00:1234:5678:9abc:def0");
139139
}
140140

141141
TEST(InetPtoNTest, NativeScion)
@@ -186,7 +186,7 @@ TEST(InetNtoPTest, MappedScion)
186186
using namespace scion;
187187

188188
in6_addr addr = unwrap(
189-
ScIPAddress::Parse("4095-2:7:ffff,fcff:ffff:ffaa:aabb:1234:5678:9abc:def0")
189+
ScIPAddress::Parse("4095-2:ffff:ffff,fcff:feff:ffff:ff00:1234:5678:9abc:def0")
190190
.and_then(mapToIPv6)
191191
.and_then([] (const scion::generic::IPAddress& x) {
192192
return generic::toUnderlay<in6_addr>(x);
@@ -202,5 +202,5 @@ TEST(InetNtoPTest, MappedScion)
202202

203203
res = interposer_inet_ntop(AF_INET6, &addr, host.data(), host.size());
204204
EXPECT_EQ(res, host.data());
205-
EXPECT_STREQ(host.data(), "4095-2:7:ffff,fcff:ffff:ffaa:aabb:1234:5678:9abc:def0");
205+
EXPECT_STREQ(host.data(), "4095-2:ffff:ffff,fcff:feff:ffff:ff00:1234:5678:9abc:def0");
206206
}

0 commit comments

Comments
 (0)