diff --git a/module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/InetAddressFilter.java b/module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/InetAddressFilter.java index 2dfd54be693..94ebc86ebe0 100644 --- a/module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/InetAddressFilter.java +++ b/module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/InetAddressFilter.java @@ -185,12 +185,16 @@ public interface InetAddressFilter { /** * Return a filter that will match external (non-private) IP addresses. External - * addresses are all non-{@link #internalAddresses() internal addresses} + * addresses are all {@link #routable() routable} addresses that are not: + * * @return a filter for external IP addresses * @see #internalAddresses() */ static InetAddressFilter externalAddresses() { - return routable().andNot(InternalInetAddressFilter.instance); + return routable().andNot(multicast(), specialPurpose()); } /** @@ -224,6 +228,27 @@ public interface InetAddressFilter { }; } + /** + * Returns a filter that will match all multicast addresses. + * @return a filter for multicast IP addresses + */ + static InetAddressFilter multicast() { + return InetAddress::isMulticastAddress; + } + + /** + * Returns a filter that will match special purpose IP addresses as defined by + * RFC 6890. + * @return a filter for this network + */ + static InetAddressFilter specialPurpose() { + 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", + "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", + "255.255.255.255/32", "::1/128", "::/128", "64:ff9b::/96", "100::/64", "2001::/23", "2001::/32", + "2001:2::/48", "2001:db8::/32", "2001:10::/28", "2002::/16", "fc00::/7", "fe80::/10") + .or(InternalInetAddressFilter.instance); + } + /** * Return a filter that is the negation of all the given addresses. * @param addresses the addresses to negate in any form supported by diff --git a/module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/InetAddressFilterTests.java b/module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/InetAddressFilterTests.java index 3eb8d408913..31106bacb94 100644 --- a/module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/InetAddressFilterTests.java +++ b/module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/InetAddressFilterTests.java @@ -327,6 +327,65 @@ class InetAddressFilterTests { assertThat(filter).doesNotMatch("::"); } + @Test + void ipv4CurrentLocalThisNetwork() { + InetAddressFilter filter = InetAddressFilter.externalAddresses(); + assertThat(filter).doesNotMatch("0.0.0.4"); + } + + @Test + void ipv4Subnet() { + InetAddressFilter filter = InetAddressFilter.externalAddresses(); + assertThat(filter).doesNotMatch("169.254.0.1"); + assertThat(filter).doesNotMatch("255.255.255.255"); + } + + @Test + void ipv4Documentation() { + InetAddressFilter filter = InetAddressFilter.externalAddresses(); + assertThat(filter).doesNotMatch("192.0.2.1"); + assertThat(filter).doesNotMatch("203.0.113.1"); + } + + @Test + void ipv4Multicast() { + InetAddressFilter filter = InetAddressFilter.externalAddresses(); + assertThat(filter).doesNotMatch("224.0.0.1"); + } + + @Test + void ipv4ReservedForFutureUse() { + InetAddressFilter filter = InetAddressFilter.externalAddresses(); + assertThat(filter).doesNotMatch("240.0.0.1"); + } + + @Test + void ipv4SharedAddressSpace() { + InetAddressFilter filter = InetAddressFilter.externalAddresses(); + assertThat(filter).doesNotMatch("100.64.0.1"); + assertThat(filter).doesNotMatch("100.127.255.254"); + } + + @Test + void ipv4PerformanceBenchmarking() { + InetAddressFilter filter = InetAddressFilter.externalAddresses(); + assertThat(filter).doesNotMatch("198.18.0.1"); + assertThat(filter).doesNotMatch("198.19.255.255"); + } + + @Test + void ipv4AllHostsMulticastGroup() { + InetAddressFilter filter = InetAddressFilter.externalAddresses(); + assertThat(filter).doesNotMatch("224.0.0.1"); + assertThat(filter).doesNotMatch("239.255.255.250"); + } + + @Test + void ipv6NodeLinkMulticastAddress() { + InetAddressFilter filter = InetAddressFilter.externalAddresses(); + assertThat(filter).doesNotMatch("ff02::1"); + } + } @Nested @@ -521,6 +580,163 @@ class InetAddressFilterTests { } + @Nested + class Multicast { + + @Test + void multicast() { + InetAddressFilter filter = InetAddressFilter.multicast(); + assertThat(filter).matches("239.255.255.255"); + assertThat(filter).matches("FF00:0000:0000:0000:0000:0000:0000:0001"); + } + + } + + @Nested + class SpecialPurpose { + + @Test + void publicAddress() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).doesNotMatch("8.8.8.8"); + } + + @Test + void thisHostNetwork() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("0.0.0.1"); + } + + @Test + void privateUseNetwork() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("10.0.0.1"); + assertThat(filter).matches("172.16.0.1"); + assertThat(filter).matches("192.168.0.1"); + } + + @Test + void sharedAddressSpace() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("100.64.0.1"); + } + + @Test + void loopback() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("127.0.0.0"); + assertThat(filter).matches("::1"); + } + + @Test + void linkLocal() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("169.254.0.1"); + } + + @Test + void protocolAssignments() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("192.0.0.1"); + assertThat(filter).matches("2001:0000:0000:0000:0000:0000:0000:0001"); + } + + @Test + void dsLite() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("192.0.0.1"); + } + + @Test + void documentation() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("192.0.2.1"); + assertThat(filter).matches("198.51.100.1"); + assertThat(filter).matches("203.0.113.1"); + assertThat(filter).matches("2001:0db8:0000:0000:0000:0000:0000:0001"); + } + + @Test + void SixToFourRelay() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("192.88.99.1"); + } + + @Test + void deviceBenchmarking() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("198.18.0.1"); + assertThat(filter).matches("2001:0002:0000:0000:0000:0000:0000:0001"); + } + + @Test + void futureUse() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("240.0.0.1"); + } + + @Test + void limitedBroadcast() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("255.255.255.255"); + } + + @Test + void unspecifiedAddress() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("0000:0000:0000:0000:0000:0000:0000:0001"); + } + + @Test + void ipv4ToIpv6AddressTranslation() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("0064:ff9b:0000:0000:0000:0000:0000:0001"); + } + + @Test + void ipv4MappedAddress() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("0000:0000:0000:0000:0000:ffff:0000:0001"); + } + + @Test + void discardOnly() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("0100:0000:0000:0000:0000:0000:0000:0001"); + } + + @Test + void teredo() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("2001:0000:0000:0000:0000:0000:0000:0001"); + } + + @Test + void orchid() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("2001:10:0000:0000:0000:0000:0000:0001"); + } + + @Test + void sixToFour() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("2002:0000:0000:0000:0000:0000:0000:0001"); + } + + @Test + void uniqueLocal() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("fc00:0000:0000:0000:0000:0000:0000:0001"); + } + + @Test + void linkedScopedUnicast() { + InetAddressFilter filter = InetAddressFilter.specialPurpose(); + assertThat(filter).matches("fe80:0000:0000:0000:0000:0000:0000:0001"); + } + + } + @Nested class NotTests {