2929
3030namespace scion {
3131
32+ // / \brief Prefix of all SCION-mapped IPv6 addresses
3233constexpr 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.
93164inline 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
0 commit comments