Skip to content

Commit 3f61870

Browse files
java-team-github-botGoogle Java Core Libraries
authored and
Google Java Core Libraries
committed
Change InetAddress-String conversion methods to preserve the scope ID.
This matches the behavior in https://bugs.openjdk.org/browse/JDK-8272215 (except still not supporting brackets []) RELNOTES=`net`: Changed `InetAddress`-`String` conversion methods to preserve the scope ID. This may lead to two kinds of problems: First, callers of those methods may be relying on the returned values _not_ to include the scope ID. For example, they might compensate for the old behavior of the methods by appending the scope ID to a returned string themselves. (If so, you can update your code to stop doing so at the same time as you upgrade Guava. Of, if your code might run against multiple versions of Guava, you can check whether Guava included a scope ID before adding one yourself.) Or they may pass the returned string to another system that does not understand scope IDs. (If so, you can strip the scope ID off, whether by truncating the string form at a `%` character (leaving behind any trailing `]` character in the case of `forUriString`) or by replacing the returned `InetAddress` with a new instance constructed by calling `InetAddress.getByAddress(addr)`. The other possible cause for problems is that `java.net.InetAddress` validates any provided scope ID against the interfaces available on the machine. As a result, methods in `InetAddresses` may now fail if the scope ID fails validation, including if the code runs in an Android app without networking permission. If this is not the behavior that you want, then you can strip off the scope ID from the input string before passing it to Guava, as discussed above. PiperOrigin-RevId: 636947430
1 parent f238ae4 commit 3f61870

File tree

4 files changed

+420
-88
lines changed

4 files changed

+420
-88
lines changed

android/guava-tests/test/com/google/common/net/InetAddressesTest.java

+110-20
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
import java.net.Inet4Address;
2626
import java.net.Inet6Address;
2727
import java.net.InetAddress;
28+
import java.net.NetworkInterface;
29+
import java.net.SocketException;
2830
import java.net.UnknownHostException;
31+
import java.util.Enumeration;
2932
import junit.framework.TestCase;
3033

3134
/**
@@ -191,14 +194,10 @@ public void testConvertDottedQuadToHex() throws UnknownHostException {
191194
}
192195
}
193196

194-
// see https://github.com/google/guava/issues/2587
195-
private static final ImmutableSet<String> SCOPE_IDS =
196-
ImmutableSet.of("eno1", "en1", "eth0", "X", "1", "2", "14", "20");
197-
198-
public void testIPv4AddressWithScopeId() {
197+
public void testIPv4AddressWithScopeId() throws SocketException {
199198
ImmutableSet<String> ipStrings = ImmutableSet.of("1.2.3.4", "192.168.0.1");
200199
for (String ipString : ipStrings) {
201-
for (String scopeId : SCOPE_IDS) {
200+
for (String scopeId : getMachineScopesAndInterfaces()) {
202201
String withScopeId = ipString + "%" + scopeId;
203202
assertFalse(
204203
"InetAddresses.isInetAddress(" + withScopeId + ") should be false but was true",
@@ -207,11 +206,11 @@ public void testIPv4AddressWithScopeId() {
207206
}
208207
}
209208

210-
public void testDottedQuadAddressWithScopeId() {
209+
public void testDottedQuadAddressWithScopeId() throws SocketException {
211210
ImmutableSet<String> ipStrings =
212211
ImmutableSet.of("7::0.128.0.127", "7::0.128.0.128", "7::128.128.0.127", "7::0.128.128.127");
213212
for (String ipString : ipStrings) {
214-
for (String scopeId : SCOPE_IDS) {
213+
for (String scopeId : getMachineScopesAndInterfaces()) {
215214
String withScopeId = ipString + "%" + scopeId;
216215
assertFalse(
217216
"InetAddresses.isInetAddress(" + withScopeId + ") should be false but was true",
@@ -220,29 +219,108 @@ public void testDottedQuadAddressWithScopeId() {
220219
}
221220
}
222221

223-
public void testIPv6AddressWithScopeId() {
222+
public void testIPv6AddressWithScopeId() throws SocketException, UnknownHostException {
223+
ImmutableSet<String> ipStrings =
224+
ImmutableSet.of(
225+
"::1",
226+
"1180::a",
227+
"1180::1",
228+
"1180::2",
229+
"1180::42",
230+
"1180::3dd0:7f8e:57b7:34d5",
231+
"1180::71a3:2b00:ddd3:753f",
232+
"1180::8b2:d61e:e5c:b333",
233+
"1180::b059:65f4:e877:c40",
234+
"fe80::34",
235+
"fec0::34");
236+
boolean processedNamedInterface = false;
237+
for (String ipString : ipStrings) {
238+
for (String scopeId : getMachineScopesAndInterfaces()) {
239+
String withScopeId = ipString + "%" + scopeId;
240+
assertTrue(
241+
"InetAddresses.isInetAddress(" + withScopeId + ") should be true but was false",
242+
InetAddresses.isInetAddress(withScopeId));
243+
Inet6Address parsed;
244+
boolean isNumeric = scopeId.matches("\\d+");
245+
try {
246+
parsed = (Inet6Address) InetAddresses.forString(withScopeId);
247+
} catch (IllegalArgumentException e) {
248+
if (!isNumeric) {
249+
// Android doesn't recognize %interface as valid
250+
continue;
251+
}
252+
throw e;
253+
}
254+
processedNamedInterface |= !isNumeric;
255+
assertThat(InetAddresses.toAddrString(parsed)).contains("%");
256+
if (isNumeric) {
257+
assertEquals(Integer.parseInt(scopeId), parsed.getScopeId());
258+
} else {
259+
assertEquals(scopeId, parsed.getScopedInterface().getName());
260+
}
261+
Inet6Address reparsed =
262+
(Inet6Address) InetAddresses.forString(InetAddresses.toAddrString(parsed));
263+
assertEquals(reparsed, parsed);
264+
assertEquals(reparsed.getScopeId(), parsed.getScopeId());
265+
}
266+
}
267+
assertTrue(processedNamedInterface);
268+
}
269+
270+
public void testIPv6AddressWithScopeId_platformEquivalence()
271+
throws SocketException, UnknownHostException {
224272
ImmutableSet<String> ipStrings =
225273
ImmutableSet.of(
226-
"0:0:0:0:0:0:0:1",
227-
"fe80::a",
228-
"fe80::1",
229-
"fe80::2",
230-
"fe80::42",
231-
"fe80::3dd0:7f8e:57b7:34d5",
232-
"fe80::71a3:2b00:ddd3:753f",
233-
"fe80::8b2:d61e:e5c:b333",
234-
"fe80::b059:65f4:e877:c40");
274+
"::1",
275+
"1180::a",
276+
"1180::1",
277+
"1180::2",
278+
"1180::42",
279+
"1180::3dd0:7f8e:57b7:34d5",
280+
"1180::71a3:2b00:ddd3:753f",
281+
"1180::8b2:d61e:e5c:b333",
282+
"1180::b059:65f4:e877:c40",
283+
"fe80::34",
284+
"fec0::34");
235285
for (String ipString : ipStrings) {
236-
for (String scopeId : SCOPE_IDS) {
286+
for (String scopeId : getMachineScopesAndInterfaces()) {
237287
String withScopeId = ipString + "%" + scopeId;
238288
assertTrue(
239289
"InetAddresses.isInetAddress(" + withScopeId + ") should be true but was false",
240290
InetAddresses.isInetAddress(withScopeId));
241-
assertEquals(InetAddresses.forString(withScopeId), InetAddresses.forString(ipString));
291+
Inet6Address parsed;
292+
boolean isNumeric = scopeId.matches("\\d+");
293+
try {
294+
parsed = (Inet6Address) InetAddresses.forString(withScopeId);
295+
} catch (IllegalArgumentException e) {
296+
if (!isNumeric) {
297+
// Android doesn't recognize %interface as valid
298+
continue;
299+
}
300+
throw e;
301+
}
302+
Inet6Address platformValue;
303+
try {
304+
platformValue = (Inet6Address) InetAddress.getByName(withScopeId);
305+
} catch (UnknownHostException e) {
306+
// Android doesn't recognize %interface as valid
307+
if (!isNumeric) {
308+
continue;
309+
}
310+
throw e;
311+
}
312+
assertEquals(platformValue, parsed);
313+
assertEquals(platformValue.getScopeId(), parsed.getScopeId());
242314
}
243315
}
244316
}
245317

318+
public void testIPv6AddressWithBadScopeId() throws SocketException, UnknownHostException {
319+
assertThrows(
320+
IllegalArgumentException.class,
321+
() -> InetAddresses.forString("1180::b059:65f4:e877:c40%eth9"));
322+
}
323+
246324
public void testToAddrStringIPv4() {
247325
// Don't need to test IPv4 much; it just calls getHostAddress().
248326
assertEquals("1.2.3.4", InetAddresses.toAddrString(InetAddresses.forString("1.2.3.4")));
@@ -792,6 +870,18 @@ public void testFromIpv6BigIntegerInputTooLarge() {
792870
expected.getMessage());
793871
}
794872

873+
// see https://github.com/google/guava/issues/2587
874+
private static ImmutableSet<String> getMachineScopesAndInterfaces() throws SocketException {
875+
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
876+
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
877+
assertTrue(interfaces.hasMoreElements());
878+
while (interfaces.hasMoreElements()) {
879+
NetworkInterface i = interfaces.nextElement();
880+
builder.add(i.getName()).add(String.valueOf(i.getIndex()));
881+
}
882+
return builder.build();
883+
}
884+
795885
/** Checks that the IP converts to the big integer and the big integer converts to the IP. */
796886
private static void checkBigIntegerConversion(String ip, BigInteger bigIntegerIp) {
797887
InetAddress address = InetAddresses.forString(ip);

0 commit comments

Comments
 (0)