1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package libcore.java.net;
18
19import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertFalse;
21import static org.junit.Assert.assertNotNull;
22import static org.junit.Assert.assertNotSame;
23import static org.junit.Assert.assertTrue;
24import static org.junit.Assert.fail;
25
26import java.net.Inet4Address;
27import java.net.Inet6Address;
28import java.net.InetAddress;
29import java.net.InetSocketAddress;
30import java.net.NetworkInterface;
31import java.net.UnknownHostException;
32import java.util.Arrays;
33import java.util.Collections;
34import java.util.HashSet;
35import java.util.Set;
36import junitparams.JUnitParamsRunner;
37import junitparams.Parameters;
38import libcore.util.SerializationTester;
39import org.junit.Test;
40import org.junit.runner.RunWith;
41
42@RunWith(JUnitParamsRunner.class)
43public class InetAddressTest {
44    private static final byte[] LOOPBACK4_BYTES = new byte[] { 127, 0, 0, 1 };
45    private static final byte[] LOOPBACK6_BYTES = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
46
47    private static final String[] INVALID_IPv4_AND_6_NUMERIC_ADDRESSES = new String[] {
48        // IPv4 addresses may not be surrounded by square brackets.
49        "[127.0.0.1]",
50
51        // Trailing dots are not allowed.
52        "1.2.3.4.",
53        // Nor is any kind of trailing junk.
54        "1.2.3.4hello",
55
56        // Out of range.
57        "256.2.3.4",
58        "1.256.3.4",
59        "1.2.256.4",
60        "1.2.3.256",
61
62        // Deprecated.
63        "1.2.3",
64        "1.2",
65        "1",
66        "1234",
67        "0", // Single out the deprecated form of the ANY address.
68
69        // Older Harmony tests expected this to be resolved to 255.255.255.255.
70        "4294967295", // 0xffffffffL,
71
72        // Hex. Not supported by Android but supported by the RI.
73        "0x1.0x2.0x3.0x4",
74        "0x7f.0x00.0x00.0x01",
75        "7f.0.0.1",
76
77        // Octal. Not supported by Android but supported by the RI. In the RI, if any of the numbers
78        // cannot be treated as a decimal the entire IP is interpreted differently, leading to
79        // "0177.00.00.01" -> 177.0.0.1, but "0177.0x0.00.01" -> 127.0.0.1.
80        // Android does not do this.
81        "0256.00.00.01", // Historically, this could have been interpreted as 174.0.0.1.
82
83        // Negative numbers.
84        "-1.0.0.1",
85        "1.-1.0.1",
86        "1.0.-1.1",
87        "1.0.0.-1",
88
89        // Invalid IPv6 addresses
90        "FFFF:FFFF",
91    };
92
93    private static final String VALID_IPv6_ADDRESSES[] = {
94        "::1.2.3.4",
95        "::",
96        "::",
97        "1::0",
98        "1::",
99        "::1",
100        "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF",
101        "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255",
102        "0:0:0:0:0:0:0:0",
103        "0:0:0:0:0:0:0.0.0.0",
104        "::255.255.255.255",
105        "::FFFF:0.0.0.0",
106        "F:F:F:F:F:F:F:F",
107    };
108
109    private static Inet6Address loopback6() throws Exception {
110        return (Inet6Address) InetAddress.getByAddress(LOOPBACK6_BYTES);
111    }
112
113    private static Inet6Address localhost6() throws Exception {
114        return (Inet6Address) InetAddress.getByAddress("ip6-localhost", LOOPBACK6_BYTES);
115    }
116
117    public static String[][] validNumericAddressesAndStringRepresentation() {
118        return new String[][]{
119            // Regular IPv4.
120            { "1.2.3.4", "/1.2.3.4" },
121
122            // Regular IPv6.
123            { "2001:4860:800d::68", "/2001:4860:800d::68" },
124
125            // Mapped IPv4
126            { "::ffff:127.0.0.1", "/127.0.0.1" },
127
128            // Optional square brackets around IPv6 addresses, including mapped IPv4.
129            { "[2001:4860:800d::68]", "/2001:4860:800d::68" },
130            { "[::ffff:127.0.0.1]", "/127.0.0.1" },
131
132            // Android does not recognize Octal (leading 0) cases: they are treated as decimal.
133            { "0177.00.00.01", "/177.0.0.1" },
134        };
135    }
136
137    @Parameters(method = "validNumericAddressesAndStringRepresentation")
138    @Test
139    public void test_parseNumericAddress(String address, String expectedString) throws Exception {
140        assertEquals(expectedString, InetAddress.parseNumericAddress(address).toString());
141    }
142
143    @Test
144    public void test_parseNumericAddress_notNumeric() throws Exception {
145        try {
146            InetAddress.parseNumericAddress("example.com"); // Not numeric.
147            fail();
148        } catch (IllegalArgumentException expected) {
149        }
150
151        // Strange special cases, for compatibility with InetAddress.getByName.
152        assertTrue(InetAddress.parseNumericAddress(null).isLoopbackAddress());
153        assertTrue(InetAddress.parseNumericAddress("").isLoopbackAddress());
154    }
155
156    @Parameters(method = "invalidNumericAddresses")
157    @Test
158    public void test_parseNumericAddress_invalid(String invalid) throws Exception {
159        try {
160            InetAddress.parseNumericAddress(invalid);
161            fail(invalid);
162        } catch (IllegalArgumentException expected) {
163        }
164    }
165
166    public static String[] validNumericAddresses() {
167        return new String[] {
168            // IPv4
169            "1.2.3.4",
170            "127.0.0.1",
171
172            // IPv6
173            "::1",
174            "2001:4860:800d::68",
175
176            // Mapped IPv4
177            "::ffff:127.0.0.1",
178
179            // Optional square brackets around IPv6 addresses, including mapped IPv4.
180            "[2001:4860:800d::68]",
181            "[::ffff:127.0.0.1]",
182
183            // Android does not handle Octal (leading 0) cases: they are treated as decimal.
184            "0177.00.00.01",
185        };
186    }
187
188    @Parameters(method = "validNumericAddresses")
189    @Test
190    public void test_isNumeric(String valid) throws Exception {
191        assertTrue(InetAddress.isNumeric(valid));
192    }
193
194    @Test
195    public void test_isNumeric_notNumeric() throws Exception {
196        // Negative test
197        assertFalse(InetAddress.isNumeric("example.com"));
198    }
199
200    @Parameters(method = "invalidNumericAddresses")
201    @Test
202    public void test_isNumeric_invalid(String invalid) {
203        assertFalse(invalid, InetAddress.isNumeric(invalid));
204    }
205
206    @Test
207    public void test_isLinkLocalAddress() throws Exception {
208        assertFalse(InetAddress.getByName("127.0.0.1").isLinkLocalAddress());
209        assertFalse(InetAddress.getByName("::ffff:127.0.0.1").isLinkLocalAddress());
210        assertTrue(InetAddress.getByName("169.254.1.2").isLinkLocalAddress());
211
212        assertFalse(InetAddress.getByName("fec0::").isLinkLocalAddress());
213        assertTrue(InetAddress.getByName("fe80::").isLinkLocalAddress());
214    }
215
216    @Test
217    public void test_isMCSiteLocalAddress() throws Exception {
218        assertFalse(InetAddress.getByName("239.254.255.255").isMCSiteLocal());
219        assertTrue(InetAddress.getByName("239.255.0.0").isMCSiteLocal());
220        assertTrue(InetAddress.getByName("239.255.255.255").isMCSiteLocal());
221        assertFalse(InetAddress.getByName("240.0.0.0").isMCSiteLocal());
222
223        assertFalse(InetAddress.getByName("ff06::").isMCSiteLocal());
224        assertTrue(InetAddress.getByName("ff05::").isMCSiteLocal());
225        assertTrue(InetAddress.getByName("ff15::").isMCSiteLocal());
226    }
227
228    @Test
229    public void test_isReachable() throws Exception {
230        // http://code.google.com/p/android/issues/detail?id=20203
231        String s = "aced0005737200146a6176612e6e65742e496e6574416464726573732d9b57af"
232                + "9fe3ebdb0200034900076164647265737349000666616d696c794c0008686f737"
233                + "44e616d657400124c6a6176612f6c616e672f537472696e673b78704a7d9d6300"
234                + "00000274000e7777772e676f6f676c652e636f6d";
235        InetAddress inetAddress = InetAddress.getByName("www.google.com");
236        new SerializationTester<InetAddress>(inetAddress, s) {
237            @Override protected void verify(InetAddress deserialized) throws Exception {
238                deserialized.isReachable(500);
239                for (NetworkInterface nif
240                        : Collections.list(NetworkInterface.getNetworkInterfaces())) {
241                    deserialized.isReachable(nif, 20, 500);
242                }
243            }
244            @Override protected boolean equals(InetAddress a, InetAddress b) {
245                return a.getHostName().equals(b.getHostName());
246            }
247        }.test();
248    }
249
250    @Test
251    public void test_isReachable_neverThrows() throws Exception {
252        InetAddress inetAddress = InetAddress.getByName("www.google.com");
253
254        final NetworkInterface netIf = NetworkInterface.getByName("dummy0");
255        if (netIf == null) {
256            System.logI("Skipping test_isReachable_neverThrows because dummy0 isn't available");
257            return;
258        }
259
260        assertFalse(inetAddress.isReachable(netIf, 256, 500));
261    }
262
263    // IPPROTO_ICMP socket kind requires setting ping_group_range. This is set on boot on Android.
264    // When running on host, make sure you run the command:
265    //   sudo sysctl -w net.ipv4.ping_group_range="0 65535"
266    @Test
267    public void test_isReachable_by_ICMP() throws Exception {
268        InetAddress[] inetAddresses = InetAddress.getAllByName("www.google.com");
269        for (InetAddress ia : inetAddresses) {
270            // ICMP is not reliable, allow 5 attempts before failing.
271            assertTrue(ia.isReachableByICMP(5 * 1000 /* ICMP timeout */));
272        }
273
274        // IPv6 discard prefix. RFC 6666.
275        final InetAddress blackholeAddress = InetAddress.getByName("100::1");
276        assertFalse(blackholeAddress.isReachable(1000));
277    }
278
279    @Test
280    public void test_isSiteLocalAddress() throws Exception {
281        assertFalse(InetAddress.getByName("144.32.32.1").isSiteLocalAddress());
282        assertTrue(InetAddress.getByName("10.0.0.1").isSiteLocalAddress());
283        assertTrue(InetAddress.getByName("172.16.0.1").isSiteLocalAddress());
284        assertFalse(InetAddress.getByName("172.32.0.1").isSiteLocalAddress());
285        assertTrue(InetAddress.getByName("192.168.0.1").isSiteLocalAddress());
286
287        assertFalse(InetAddress.getByName("fc00::").isSiteLocalAddress());
288        assertTrue(InetAddress.getByName("fec0::").isSiteLocalAddress());
289    }
290
291    public static String[] invalidNumericAddresses() {
292        return INVALID_IPv4_AND_6_NUMERIC_ADDRESSES;
293    }
294
295    @SuppressWarnings("ResultOfMethodCallIgnored")
296    @Parameters(method = "invalidNumericAddresses")
297    @Test
298    public void test_getByName_invalid(String invalid) throws Exception {
299        try {
300            InetAddress.getByName(invalid);
301            fail("Invalid IP address incorrectly recognized as valid: "
302                + invalid);
303        } catch (UnknownHostException expected) {
304        }
305
306        // exercise negative cache
307        try {
308            InetAddress.getByName(invalid);
309            fail("Invalid IP address incorrectly recognized as valid: "
310                + invalid);
311        } catch (Exception expected) {
312        }
313    }
314
315    public static String[] validIPv6Addresses() {
316        return VALID_IPv6_ADDRESSES;
317    }
318
319    @Parameters(method = "validIPv6Addresses")
320    @Test
321    public void test_getByName_valid(String valid) throws Exception {
322        InetAddress.getByName(valid);
323
324        // exercise positive cache
325        InetAddress.getByName(valid);
326
327        // when wrapped in [..]
328        String tempIPAddress = "[" + valid + "]";
329        InetAddress.getByName(tempIPAddress);
330    }
331
332    @Test
333    public void test_getLoopbackAddress() throws Exception {
334        assertTrue(InetAddress.getLoopbackAddress().isLoopbackAddress());
335    }
336
337    @Test
338    public void test_equals() throws Exception {
339        InetAddress addr = InetAddress.getByName("239.191.255.255");
340        assertTrue(addr.equals(addr));
341        assertTrue(loopback6().equals(localhost6()));
342        assertFalse(addr.equals(loopback6()));
343
344        assertTrue(Inet4Address.LOOPBACK.equals(Inet4Address.LOOPBACK));
345
346        // http://b/4328294 - the scope id isn't included when comparing Inet6Address instances.
347        byte[] bs = new byte[16];
348        assertEquals(Inet6Address.getByAddress("1", bs, 1), Inet6Address.getByAddress("2", bs, 2));
349    }
350
351    @Test
352    public void test_getHostAddress() throws Exception {
353        assertEquals("::1", localhost6().getHostAddress());
354        assertEquals("::1", InetAddress.getByName("::1").getHostAddress());
355
356        assertEquals("127.0.0.1", Inet4Address.LOOPBACK.getHostAddress());
357
358        // IPv4 mapped address
359        assertEquals("127.0.0.1", InetAddress.getByName("::ffff:127.0.0.1").getHostAddress());
360
361        InetAddress aAddr = InetAddress.getByName("224.0.0.0");
362        assertEquals("224.0.0.0", aAddr.getHostAddress());
363
364
365        try {
366            InetAddress.getByName("1");
367            fail();
368        } catch (UnknownHostException expected) {
369        }
370
371        byte[] bAddr = {
372            (byte) 0xFE, (byte) 0x80, (byte) 0x00, (byte) 0x00,
373            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
374            (byte) 0x02, (byte) 0x11, (byte) 0x25, (byte) 0xFF,
375            (byte) 0xFE, (byte) 0xF8, (byte) 0x7C, (byte) 0xB2
376        };
377        aAddr = Inet6Address.getByAddress(bAddr);
378        String aString = aAddr.getHostAddress();
379        assertTrue(aString.equals("fe80:0:0:0:211:25ff:fef8:7cb2") || aString.equals("fe80::211:25ff:fef8:7cb2"));
380
381        byte[] cAddr = {
382            (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
383            (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
384            (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
385            (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF
386        };
387        aAddr = Inet6Address.getByAddress(cAddr);
388        assertEquals("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", aAddr.getHostAddress());
389
390        byte[] dAddr = {
391            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
392            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
393            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
394            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
395        };
396        aAddr = Inet6Address.getByAddress(dAddr);
397        aString = aAddr.getHostAddress();
398        assertTrue(aString.equals("0:0:0:0:0:0:0:0") || aString.equals("::"));
399
400        byte[] eAddr = {
401            (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03,
402            (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07,
403            (byte) 0x08, (byte) 0x09, (byte) 0x0a, (byte) 0x0b,
404            (byte) 0x0c, (byte) 0x0d, (byte) 0x0e, (byte) 0x0f
405        };
406        aAddr = Inet6Address.getByAddress(eAddr);
407        assertEquals("1:203:405:607:809:a0b:c0d:e0f", aAddr.getHostAddress());
408
409        byte[] fAddr = {
410            (byte) 0x00, (byte) 0x10, (byte) 0x20, (byte) 0x30,
411            (byte) 0x40, (byte) 0x50, (byte) 0x60, (byte) 0x70,
412            (byte) 0x80, (byte) 0x90, (byte) 0xa0, (byte) 0xb0,
413            (byte) 0xc0, (byte) 0xd0, (byte) 0xe0, (byte) 0xf0
414        };
415        aAddr = Inet6Address.getByAddress(fAddr);
416        assertEquals("10:2030:4050:6070:8090:a0b0:c0d0:e0f0", aAddr.getHostAddress());
417    }
418
419    @Test
420    public void test_hashCode() throws Exception {
421        InetAddress addr1 = InetAddress.getByName("1.0.0.1");
422        InetAddress addr2 = InetAddress.getByName("1.0.0.1");
423        assertTrue(addr1.hashCode() == addr2.hashCode());
424
425        assertTrue(loopback6().hashCode() == localhost6().hashCode());
426    }
427
428    public static String[][] validAddressesAndStringRepresentation() {
429        return new String[][] {
430            { "::1.2.3.4", "/::1.2.3.4" },
431            { "::", "/::" },
432            { "1::0", "/1::" },
433            { "1::", "/1::" },
434            { "::1", "/::1" },
435            { "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", "/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" },
436            { "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255", "/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" },
437            { "0:0:0:0:0:0:0:0", "/::" },
438            { "0:0:0:0:0:0:0.0.0.0", "/::" },
439        };
440    }
441
442    @Parameters(method = "validAddressesAndStringRepresentation")
443    @Test
444    public void test_toString(String address, String expectedString) throws Exception {
445        InetAddress ia = InetAddress.getByName(address);
446        String result = ia.toString();
447        assertNotNull(result);
448        assertEquals(expectedString, result);
449    }
450
451    @Test
452    public void test_getHostNameCaches() throws Exception {
453        InetAddress inetAddress = InetAddress.getByAddress(LOOPBACK6_BYTES);
454
455        // There should be no cached name.
456        assertEquals("::1", getHostStringWithoutReverseDns(inetAddress));
457
458        // Force the reverse-DNS lookup.
459        assertEquals("ip6-localhost", inetAddress.getHostName());
460
461        // The cached name should now be different.
462        assertEquals("ip6-localhost", getHostStringWithoutReverseDns(inetAddress));
463    }
464
465    @Test
466    public void test_getByAddress_loopbackIpv4() throws Exception {
467        InetAddress inetAddress = InetAddress.getByAddress(LOOPBACK4_BYTES);
468        checkInetAddress(LOOPBACK4_BYTES, "localhost", inetAddress);
469        assertTrue(inetAddress.isLoopbackAddress());
470    }
471
472    @Test
473    public void test_getByAddress_loopbackIpv6() throws Exception {
474        InetAddress inetAddress = InetAddress.getByAddress(LOOPBACK6_BYTES);
475        checkInetAddress(LOOPBACK6_BYTES, "ip6-localhost", inetAddress);
476        assertTrue(inetAddress.isLoopbackAddress());
477    }
478
479    @Test
480    public void test_getByName_loopbackIpv4() throws Exception {
481        InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
482        checkInetAddress(LOOPBACK4_BYTES, "localhost", inetAddress);
483        assertTrue(inetAddress.isLoopbackAddress());
484    }
485
486    @Test
487    public void test_getByName_loopbackIpv6() throws Exception {
488        InetAddress inetAddress = InetAddress.getByName("::1");
489        checkInetAddress(LOOPBACK6_BYTES, "ip6-localhost", inetAddress);
490        assertTrue(inetAddress.isLoopbackAddress());
491    }
492
493    @Test
494    public void test_getByName_empty() throws Exception {
495        InetAddress inetAddress = InetAddress.getByName("");
496        checkInetAddress(LOOPBACK6_BYTES, "ip6-localhost", inetAddress);
497        assertTrue(inetAddress.isLoopbackAddress());
498    }
499
500    @Test
501    public void test_getAllByName_localhost() throws Exception {
502        InetAddress[] inetAddresses = InetAddress.getAllByName("localhost");
503        assertEquals(1, inetAddresses.length);
504        InetAddress inetAddress = inetAddresses[0];
505        checkInetAddress(LOOPBACK4_BYTES, "localhost", inetAddress);
506        assertTrue(inetAddress.isLoopbackAddress());
507    }
508
509    @Test
510    public void test_getAllByName_ip6_localhost() throws Exception {
511        InetAddress[] inetAddresses = InetAddress.getAllByName("ip6-localhost");
512        assertEquals(1, inetAddresses.length);
513        InetAddress inetAddress = inetAddresses[0];
514        checkInetAddress(LOOPBACK6_BYTES, "ip6-localhost", inetAddress);
515        assertTrue(inetAddress.isLoopbackAddress());
516    }
517
518    @Test
519    public void test_getByName_v6loopback() throws Exception {
520        InetAddress inetAddress = InetAddress.getByName("::1");
521
522        Set<InetAddress> expectedLoopbackAddresses =
523                createSet(Inet4Address.LOOPBACK, Inet6Address.LOOPBACK);
524        assertTrue(expectedLoopbackAddresses.contains(inetAddress));
525    }
526
527    @Test
528    public void test_getByName_cloning() throws Exception {
529        InetAddress[] addresses = InetAddress.getAllByName(null);
530        InetAddress[] addresses2 = InetAddress.getAllByName(null);
531        assertNotNull(addresses[0]);
532        assertNotNull(addresses[1]);
533        assertNotSame(addresses, addresses2);
534
535        // Also assert that changes to the return value do not affect the cache
536        // etc. i.e, that we return a copy.
537        addresses[0] = null;
538        addresses2 = InetAddress.getAllByName(null);
539        assertNotNull(addresses2[0]);
540        assertNotNull(addresses2[1]);
541    }
542
543    @Test
544    public void test_getAllByName_null() throws Exception {
545        InetAddress[] inetAddresses = InetAddress.getAllByName(null);
546        assertEquals(2, inetAddresses.length);
547        Set<InetAddress> expectedLoopbackAddresses =
548                createSet(Inet4Address.LOOPBACK, Inet6Address.LOOPBACK);
549        assertEquals(expectedLoopbackAddresses, createSet(inetAddresses));
550    }
551
552    // http://b/29311351
553    @Test
554    public void test_loopbackConstantsPreInitializedNames() {
555        // Note: Inet6Address / Inet4Address equals() does not check host name.
556        assertEquals("ip6-localhost", getHostStringWithoutReverseDns(Inet6Address.LOOPBACK));
557        assertEquals("localhost", getHostStringWithoutReverseDns(Inet4Address.LOOPBACK));
558    }
559
560    private static void checkInetAddress(
561        byte[] expectedAddressBytes, String expectedHostname, InetAddress actual) {
562        assertArrayEquals(expectedAddressBytes, actual.getAddress());
563        assertEquals(expectedHostname, actual.getHostName());
564
565    }
566
567    private static void assertArrayEquals(byte[] expected, byte[] actual) {
568        assertTrue("Expected=" + Arrays.toString(expected) + ", actual=" + Arrays.toString(actual),
569                Arrays.equals(expected, actual));
570    }
571
572    private static Set<InetAddress> createSet(InetAddress... members) {
573        return new HashSet<InetAddress>(Arrays.asList(members));
574    }
575
576    private static String getHostStringWithoutReverseDns(InetAddress inetAddress) {
577        // The InetAddress API provides no way of avoiding a DNS lookup, but InetSocketAddress
578        // does via InetSocketAddress.getHostString().
579        InetSocketAddress inetSocketAddress = new InetSocketAddress(inetAddress, 9999);
580        return inetSocketAddress.getHostString();
581    }
582}
583