Skip to content

Commit 739daa7

Browse files
committed
Filter special purpose IPs (RFC 6890) in externalAddresses()
Update `InetAddressFilter.externalAddresses()` to filter special purpose IP addresses as defined by RFC 6890. As a byproduct of this commit to additional factory methods (`specialPurpose()` and `multicast()`) have also been introduced. Closes gh-50668
1 parent f98f063 commit 739daa7

2 files changed

Lines changed: 243 additions & 2 deletions

File tree

module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/InetAddressFilter.java

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,12 +185,16 @@ default InetAddressFilter negate() {
185185

186186
/**
187187
* Return a filter that will match external (non-private) IP addresses. External
188-
* addresses are all non-{@link #internalAddresses() internal addresses}
188+
* addresses are all {@link #routable() routable} addresses that are not:
189+
* <ul>
190+
* <li>{@link #multicast() multicast}</li>
191+
* <li>{@link #specialPurpose() special purpose}</li>
192+
* </ul>
189193
* @return a filter for external IP addresses
190194
* @see #internalAddresses()
191195
*/
192196
static InetAddressFilter externalAddresses() {
193-
return routable().andNot(InternalInetAddressFilter.instance);
197+
return routable().andNot(multicast(), specialPurpose());
194198
}
195199

196200
/**
@@ -224,6 +228,27 @@ static InetAddressFilter routable() {
224228
};
225229
}
226230

231+
/**
232+
* Returns a filter that will match all multicast addresses.
233+
* @return a filter for multicast IP addresses
234+
*/
235+
static InetAddressFilter multicast() {
236+
return InetAddress::isMulticastAddress;
237+
}
238+
239+
/**
240+
* Returns a filter that will match special purpose IP addresses as defined by
241+
* <a href="https://www.rfc-editor.org/info/rfc6890">RFC 6890</a>.
242+
* @return a filter for this network
243+
*/
244+
static InetAddressFilter specialPurpose() {
245+
return of("0.0.0.0/8", "100.64.0.0/10", "127.0.0.0/8", "169.254.0.0/16", "192.0.0.0/24", "192.0.0.0/29",
246+
"192.0.2.0/24", "192.88.99.0/24", "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4",
247+
"255.255.255.255/32", "::1/128", "::/128", "64:ff9b::/96", "100::/64", "2001::/23", "2001::/32",
248+
"2001:2::/48", "2001:db8::/32", "2001:10::/28", "2002::/16", "fc00::/7", "fe80::/10")
249+
.or(InternalInetAddressFilter.instance);
250+
}
251+
227252
/**
228253
* Return a filter that is the negation of all the given addresses.
229254
* @param addresses the addresses to negate in any form supported by

module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/InetAddressFilterTests.java

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,65 @@ void ipv6NonRoutable() {
327327
assertThat(filter).doesNotMatch("::");
328328
}
329329

330+
@Test
331+
void ipv4CurrentLocalThisNetwork() {
332+
InetAddressFilter filter = InetAddressFilter.externalAddresses();
333+
assertThat(filter).doesNotMatch("0.0.0.4");
334+
}
335+
336+
@Test
337+
void ipv4Subnet() {
338+
InetAddressFilter filter = InetAddressFilter.externalAddresses();
339+
assertThat(filter).doesNotMatch("169.254.0.1");
340+
assertThat(filter).doesNotMatch("255.255.255.255");
341+
}
342+
343+
@Test
344+
void ipv4Documentation() {
345+
InetAddressFilter filter = InetAddressFilter.externalAddresses();
346+
assertThat(filter).doesNotMatch("192.0.2.1");
347+
assertThat(filter).doesNotMatch("203.0.113.1");
348+
}
349+
350+
@Test
351+
void ipv4Multicast() {
352+
InetAddressFilter filter = InetAddressFilter.externalAddresses();
353+
assertThat(filter).doesNotMatch("224.0.0.1");
354+
}
355+
356+
@Test
357+
void ipv4ReservedForFutureUse() {
358+
InetAddressFilter filter = InetAddressFilter.externalAddresses();
359+
assertThat(filter).doesNotMatch("240.0.0.1");
360+
}
361+
362+
@Test
363+
void ipv4SharedAddressSpace() {
364+
InetAddressFilter filter = InetAddressFilter.externalAddresses();
365+
assertThat(filter).doesNotMatch("100.64.0.1");
366+
assertThat(filter).doesNotMatch("100.127.255.254");
367+
}
368+
369+
@Test
370+
void ipv4PerformanceBenchmarking() {
371+
InetAddressFilter filter = InetAddressFilter.externalAddresses();
372+
assertThat(filter).doesNotMatch("198.18.0.1");
373+
assertThat(filter).doesNotMatch("198.19.255.255");
374+
}
375+
376+
@Test
377+
void ipv4AllHostsMulticastGroup() {
378+
InetAddressFilter filter = InetAddressFilter.externalAddresses();
379+
assertThat(filter).doesNotMatch("224.0.0.1");
380+
assertThat(filter).doesNotMatch("239.255.255.250");
381+
}
382+
383+
@Test
384+
void ipv6NodeLinkMulticastAddress() {
385+
InetAddressFilter filter = InetAddressFilter.externalAddresses();
386+
assertThat(filter).doesNotMatch("ff02::1");
387+
}
388+
330389
}
331390

332391
@Nested
@@ -521,6 +580,163 @@ void routable() {
521580

522581
}
523582

583+
@Nested
584+
class Multicast {
585+
586+
@Test
587+
void multicast() {
588+
InetAddressFilter filter = InetAddressFilter.multicast();
589+
assertThat(filter).matches("239.255.255.255");
590+
assertThat(filter).matches("FF00:0000:0000:0000:0000:0000:0000:0001");
591+
}
592+
593+
}
594+
595+
@Nested
596+
class SpecialPurpose {
597+
598+
@Test
599+
void publicAddress() {
600+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
601+
assertThat(filter).doesNotMatch("8.8.8.8");
602+
}
603+
604+
@Test
605+
void thisHostNetwork() {
606+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
607+
assertThat(filter).matches("0.0.0.1");
608+
}
609+
610+
@Test
611+
void privateUseNetwork() {
612+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
613+
assertThat(filter).matches("10.0.0.1");
614+
assertThat(filter).matches("172.16.0.1");
615+
assertThat(filter).matches("192.168.0.1");
616+
}
617+
618+
@Test
619+
void sharedAddressSpace() {
620+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
621+
assertThat(filter).matches("100.64.0.1");
622+
}
623+
624+
@Test
625+
void loopback() {
626+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
627+
assertThat(filter).matches("127.0.0.0");
628+
assertThat(filter).matches("::1");
629+
}
630+
631+
@Test
632+
void linkLocal() {
633+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
634+
assertThat(filter).matches("169.254.0.1");
635+
}
636+
637+
@Test
638+
void protocolAssignments() {
639+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
640+
assertThat(filter).matches("192.0.0.1");
641+
assertThat(filter).matches("2001:0000:0000:0000:0000:0000:0000:0001");
642+
}
643+
644+
@Test
645+
void dsLite() {
646+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
647+
assertThat(filter).matches("192.0.0.1");
648+
}
649+
650+
@Test
651+
void documentation() {
652+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
653+
assertThat(filter).matches("192.0.2.1");
654+
assertThat(filter).matches("198.51.100.1");
655+
assertThat(filter).matches("203.0.113.1");
656+
assertThat(filter).matches("2001:0db8:0000:0000:0000:0000:0000:0001");
657+
}
658+
659+
@Test
660+
void SixToFourRelay() {
661+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
662+
assertThat(filter).matches("192.88.99.1");
663+
}
664+
665+
@Test
666+
void deviceBenchmarking() {
667+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
668+
assertThat(filter).matches("198.18.0.1");
669+
assertThat(filter).matches("2001:0002:0000:0000:0000:0000:0000:0001");
670+
}
671+
672+
@Test
673+
void futureUse() {
674+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
675+
assertThat(filter).matches("240.0.0.1");
676+
}
677+
678+
@Test
679+
void limitedBroadcast() {
680+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
681+
assertThat(filter).matches("255.255.255.255");
682+
}
683+
684+
@Test
685+
void unspecifiedAddress() {
686+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
687+
assertThat(filter).matches("0000:0000:0000:0000:0000:0000:0000:0001");
688+
}
689+
690+
@Test
691+
void ipv4ToIpv6AddressTranslation() {
692+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
693+
assertThat(filter).matches("0064:ff9b:0000:0000:0000:0000:0000:0001");
694+
}
695+
696+
@Test
697+
void ipv4MappedAddress() {
698+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
699+
assertThat(filter).matches("0000:0000:0000:0000:0000:ffff:0000:0001");
700+
}
701+
702+
@Test
703+
void discardOnly() {
704+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
705+
assertThat(filter).matches("0100:0000:0000:0000:0000:0000:0000:0001");
706+
}
707+
708+
@Test
709+
void teredo() {
710+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
711+
assertThat(filter).matches("2001:0000:0000:0000:0000:0000:0000:0001");
712+
}
713+
714+
@Test
715+
void orchid() {
716+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
717+
assertThat(filter).matches("2001:10:0000:0000:0000:0000:0000:0001");
718+
}
719+
720+
@Test
721+
void sixToFour() {
722+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
723+
assertThat(filter).matches("2002:0000:0000:0000:0000:0000:0000:0001");
724+
}
725+
726+
@Test
727+
void uniqueLocal() {
728+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
729+
assertThat(filter).matches("fc00:0000:0000:0000:0000:0000:0000:0001");
730+
}
731+
732+
@Test
733+
void linkedScopedUnicast() {
734+
InetAddressFilter filter = InetAddressFilter.specialPurpose();
735+
assertThat(filter).matches("fe80:0000:0000:0000:0000:0000:0000:0001");
736+
}
737+
738+
}
739+
524740
@Nested
525741
class NotTests {
526742

0 commit comments

Comments
 (0)