5151
5252/**
5353 * {@code AddressSelectingDnsResolver} wraps a delegate {@link DnsResolver}
54- * and applies RFC 6724 destination address selection rules (RFC 6724 §6)
55- * to the returned addresses. It can also enforce or bias a protocol family preference.
54+ * and applies destination address selection rules (scope, precedence, label matching,
55+ * longest-prefix) to the returned addresses. It can also enforce or bias a protocol
56+ * family preference.
5657 *
5758 * <p>The canonical hostname lookup is delegated unchanged.</p>
5859 *
5960 * <p>
60- * {@link ProtocolFamilyPreference#DEFAULT} keeps the RFC 6724 sorted order intact (no family bias).
61+ * {@link ProtocolFamilyPreference#DEFAULT} keeps the sorted order intact (no family bias).
6162 * {@link ProtocolFamilyPreference#INTERLEAVE} interleaves IPv6 and IPv4 addresses (v6, v4, v6, …),
62- * preserving the relative order within each family as produced by RFC 6724 sorting.
63+ * preserving the relative order within each family as produced by destination address sorting.
6364 * </p>
6465 *
6566 * @since 5.7
@@ -88,7 +89,7 @@ interface SourceAddressResolver {
8889 private final SourceAddressResolver sourceAddressResolver ;
8990
9091 /**
91- * Creates a new resolver that applies RFC 6724 ordering with no family bias (DEFAULT).
92+ * Creates a new resolver that applies destination address ordering with no family bias (DEFAULT).
9293 *
9394 * @param delegate underlying resolver to use.
9495 */
@@ -97,7 +98,7 @@ public AddressSelectingDnsResolver(final DnsResolver delegate) {
9798 }
9899
99100 /**
100- * Creates a new resolver that applies RFC 6724 ordering and a specific protocol family preference.
101+ * Creates a new resolver that applies destination address ordering and a specific protocol family preference.
101102 *
102103 * @param delegate underlying resolver to use.
103104 * @param familyPreference family preference to apply (e.g. PREFER_IPV6, IPV4_ONLY).
@@ -129,13 +130,6 @@ public InetAddress[] resolve(final String host) throws UnknownHostException {
129130 return null ;
130131 }
131132
132- if (resolved .length <= 1 ) {
133- if (LOG .isDebugEnabled ()) {
134- LOG .debug ("resolved '{}' -> {}" , host , fmt (resolved ));
135- }
136- return resolved ;
137- }
138-
139133 if (LOG .isTraceEnabled ()) {
140134 LOG .trace ("resolving host '{}' via delegate {}" , host , delegate .getClass ().getName ());
141135 LOG .trace ("familyPreference={}" , familyPreference );
@@ -151,8 +145,15 @@ public InetAddress[] resolve(final String host) throws UnknownHostException {
151145 return null ;
152146 }
153147
154- final List <InetAddress > rfcSorted = sortByRfc6724 (candidates );
155- final List <InetAddress > ordered = applyFamilyPreference (rfcSorted , familyPreference );
148+ if (candidates .size () == 1 ) {
149+ if (LOG .isDebugEnabled ()) {
150+ LOG .debug ("resolved '{}' -> {}" , host , fmt (candidates ));
151+ }
152+ return candidates .toArray (new InetAddress [0 ]);
153+ }
154+
155+ final List <InetAddress > sorted = sortByDestinationAddressSelection (candidates );
156+ final List <InetAddress > ordered = applyFamilyPreference (sorted , familyPreference );
156157
157158 if (LOG .isDebugEnabled ()) {
158159 LOG .debug ("resolved '{}' -> {}" , host , fmt (ordered ));
@@ -161,6 +162,17 @@ public InetAddress[] resolve(final String host) throws UnknownHostException {
161162 return ordered .toArray (new InetAddress [0 ]);
162163 }
163164
165+ @ Override
166+ public List <InetSocketAddress > resolve (final String host , final int port ) throws UnknownHostException {
167+ final InetAddress [] addresses = resolve (host );
168+ if (addresses == null || addresses .length == 0 ) {
169+ throw new UnknownHostException (host );
170+ }
171+ return Arrays .stream (addresses )
172+ .map (a -> new InetSocketAddress (a , port ))
173+ .collect (Collectors .toList ());
174+ }
175+
164176 @ Override
165177 public String resolveCanonicalHostname (final String host ) throws UnknownHostException {
166178 if (LOG .isTraceEnabled ()) {
@@ -203,15 +215,15 @@ private static boolean shouldInclude(final ProtocolFamilyPreference pref, final
203215 }
204216
205217
206- // --- RFC 6724 helpers ---
218+ // --- Destination address selection helpers ---
207219
208- private List <InetAddress > sortByRfc6724 (final List <InetAddress > addrs ) {
220+ private List <InetAddress > sortByDestinationAddressSelection (final List <InetAddress > addrs ) {
209221 if (addrs .size () < 2 ) {
210222 return addrs ;
211223 }
212224
213225 if (LOG .isTraceEnabled ()) {
214- LOG .trace ("RFC6724 input candidates: {}" , fmt (addrs ));
226+ LOG .trace ("address-selection input candidates: {}" , fmt (addrs ));
215227 }
216228
217229 final List <Info > infos = new ArrayList <>(addrs .size ());
@@ -222,21 +234,21 @@ private List<InetAddress> sortByRfc6724(final List<InetAddress> addrs) {
222234
223235 if (LOG .isTraceEnabled ()) {
224236 for (final Info info : infos ) {
225- LOG .trace ("RFC6724 candidate dst={} src={} dst[scope={},prec={},label={}] src[scope={},prec={},label={}]" ,
237+ LOG .trace ("address-selection candidate dst={} src={} dst[scope={},prec={},label={}] src[scope={},prec={},label={}]" ,
226238 addr (info .dst ), addr (info .src ),
227239 info .dstAttr .scope , info .dstAttr .precedence , info .dstAttr .label ,
228240 info .srcAttr .scope , info .srcAttr .precedence , info .srcAttr .label );
229241 }
230242 }
231243
232- infos .sort (RFC6724_COMPARATOR );
244+ infos .sort (DESTINATION_ADDRESS_COMPARATOR );
233245
234246 final List <InetAddress > out = infos .stream ()
235247 .map (info -> info .dst )
236248 .collect (Collectors .toList ());
237249
238250 if (LOG .isTraceEnabled ()) {
239- LOG .trace ("RFC6724 output order: {}" , fmt (out ));
251+ LOG .trace ("address-selection output order: {}" , fmt (out ));
240252 }
241253
242254 return out ;
@@ -247,27 +259,27 @@ private InetAddress inferSourceAddress(final InetSocketAddress destination) {
247259 return sourceAddressResolver .resolveSource (destination );
248260 } catch (final SocketException ex ) {
249261 if (LOG .isTraceEnabled ()) {
250- LOG .trace ("RFC6724 could not infer source address for {}: {}" , destination , ex .toString ());
262+ LOG .trace ("address-selection could not infer source address for {}: {}" , destination , ex .toString ());
251263 }
252264 return null ;
253265 }
254266 }
255267
256268 private static List <InetAddress > applyFamilyPreference (
257- final List <InetAddress > rfcSorted ,
269+ final List <InetAddress > sorted ,
258270 final ProtocolFamilyPreference pref ) {
259271
260- if (rfcSorted .size () <= 1 ) {
261- return rfcSorted ;
272+ if (sorted .size () <= 1 ) {
273+ return sorted ;
262274 }
263275
264276 switch (pref ) {
265277 case PREFER_IPV6 :
266278 case PREFER_IPV4 : {
267279 final boolean preferV6 = pref == ProtocolFamilyPreference .PREFER_IPV6 ;
268280
269- // Stable: preserves the RFC6724 order within each family.
270- final List <InetAddress > out = rfcSorted .stream ()
281+ // Stable: preserves the destination-sorted order within each family.
282+ final List <InetAddress > out = sorted .stream ()
271283 .sorted (Comparator .comparingInt (a -> ((a instanceof Inet6Address ) == preferV6 ) ? 0 : 1 ))
272284 .collect (Collectors .toList ());
273285
@@ -277,7 +289,7 @@ private static List<InetAddress> applyFamilyPreference(
277289 return out ;
278290 }
279291 case INTERLEAVE : {
280- final List <InetAddress > out = interleaveFamilies (rfcSorted );
292+ final List <InetAddress > out = interleaveFamilies (sorted );
281293 if (LOG .isTraceEnabled ()) {
282294 LOG .trace ("Family preference {} applied. Output: {}" , pref , fmt (out ));
283295 }
@@ -286,21 +298,21 @@ private static List<InetAddress> applyFamilyPreference(
286298 case IPV4_ONLY :
287299 case IPV6_ONLY : {
288300 // already filtered earlier
289- return rfcSorted ;
301+ return sorted ;
290302 }
291303 case DEFAULT :
292304 default : {
293- // No family bias. Keep RFC 6724 order intact.
294- return rfcSorted ;
305+ // No family bias. Keep destination-sorted order intact.
306+ return sorted ;
295307 }
296308 }
297309 }
298310
299- private static List <InetAddress > interleaveFamilies (final List <InetAddress > rfcSorted ) {
311+ private static List <InetAddress > interleaveFamilies (final List <InetAddress > sorted ) {
300312 final List <InetAddress > v6 = new ArrayList <>();
301313 final List <InetAddress > v4 = new ArrayList <>();
302314
303- for (final InetAddress a : rfcSorted ) {
315+ for (final InetAddress a : sorted ) {
304316 if (a instanceof Inet6Address ) {
305317 v6 .add (a );
306318 } else {
@@ -309,14 +321,14 @@ private static List<InetAddress> interleaveFamilies(final List<InetAddress> rfcS
309321 }
310322
311323 if (v6 .isEmpty () || v4 .isEmpty ()) {
312- return rfcSorted ;
324+ return sorted ;
313325 }
314326
315- final boolean startWithV6 = rfcSorted .get (0 ) instanceof Inet6Address ;
327+ final boolean startWithV6 = sorted .get (0 ) instanceof Inet6Address ;
316328 final List <InetAddress > first = startWithV6 ? v6 : v4 ;
317329 final List <InetAddress > second = startWithV6 ? v4 : v6 ;
318330
319- final List <InetAddress > out = new ArrayList <>(rfcSorted .size ());
331+ final List <InetAddress > out = new ArrayList <>(sorted .size ());
320332 final Iterator <InetAddress > it1 = first .iterator ();
321333 final Iterator <InetAddress > it2 = second .iterator ();
322334 while (it1 .hasNext () || it2 .hasNext ()) {
@@ -330,7 +342,7 @@ private static List<InetAddress> interleaveFamilies(final List<InetAddress> rfcS
330342 return out ;
331343 }
332344
333- // --- RFC 6724 score structs ---
345+ // --- Address selection score structs ---
334346
335347 private static final class Info {
336348 final InetAddress dst ;
@@ -418,7 +430,7 @@ static Scope classifyScope(final InetAddress ip) {
418430 }
419431 if (ip .isMulticastAddress ()) {
420432 if (ip instanceof Inet6Address ) {
421- // RFC 6724 §3.1 and RFC 4291 : low 4 bits of second byte encode scope for IPv6 multicast .
433+ // IPv6 multicast : low 4 bits of second byte encode scope.
422434 // Not all nibble values map to a known Scope constant; treat unknown values as GLOBAL.
423435 final int nibble = ip .getAddress ()[1 ] & 0x0f ;
424436 try {
@@ -517,7 +529,7 @@ private static PolicyEntry classify(final InetAddress ip) {
517529 return new PolicyEntry (null , 40 , 1 );
518530 }
519531
520- private static final Comparator <Info > RFC6724_COMPARATOR = (a , b ) -> {
532+ private static final Comparator <Info > DESTINATION_ADDRESS_COMPARATOR = (a , b ) -> {
521533 final InetAddress aDst = a .dst ;
522534 final InetAddress bDst = b .dst ;
523535 final InetAddress aSrc = a .src ;
@@ -530,7 +542,7 @@ private static PolicyEntry classify(final InetAddress ip) {
530542 final int preferA = -1 ;
531543 final int preferB = 1 ;
532544
533- // RFC 6724 §6: destination address selection rules.
545+ // Destination address selection rules.
534546 //
535547 // Rules 3, 4 and 7 are not implementable with standard JDK APIs:
536548 // Rule 3 (Avoid deprecated source addresses) — InetAddress exposes no deprecation state.
@@ -588,7 +600,7 @@ private static PolicyEntry classify(final InetAddress ip) {
588600 return preferB ;
589601 }
590602
591- // Rule 9: Longest matching prefix (IPv6 only, per RFC 6724 §6 ).
603+ // Rule 9: Longest matching prefix (IPv6 only).
592604 if (aDst instanceof Inet6Address && bDst instanceof Inet6Address ) {
593605 final int commonA = commonPrefixLen (aSrc , aDst );
594606 final int commonB = commonPrefixLen (bSrc , bDst );
0 commit comments