| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.catalina.startup; |
| |
| import java.io.File; |
| import java.net.HttpURLConnection; |
| import java.net.Inet6Address; |
| import java.net.InetAddress; |
| import java.net.NetworkInterface; |
| import java.net.URI; |
| import java.net.URL; |
| import java.util.Enumeration; |
| |
| import jakarta.servlet.http.HttpServletResponse; |
| |
| import org.junit.Assert; |
| import org.junit.Assume; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| |
| import org.apache.catalina.Context; |
| |
| public class TestStartupIPv6Connectors extends TomcatBaseTest { |
| |
| private static String linklocalAddress; |
| private static String globalAddress; |
| |
| @Test |
| public void testIPv6Localhost() throws Exception { |
| assertHttpOkOnAddress("::1"); |
| } |
| |
| @Test |
| public void testIPv6LinkLocal() throws Exception { |
| Assume.assumeTrue("No IPv6 link-local present", linklocalAddress != null); |
| assertHttpOkOnAddress(linklocalAddress); |
| } |
| |
| @Test |
| public void testIPv6Global() throws Exception { |
| Assume.assumeTrue("No IPv6 global-unicast present", globalAddress != null); |
| assertHttpOkOnAddress(globalAddress); |
| } |
| |
| @Test |
| public void testIPv6MappedIPv4() throws Exception { |
| assertHttpOkOnAddress("::ffff:127.0.0.1"); |
| } |
| |
| @BeforeClass |
| public static void initializeTestIpv6Addresses() throws Exception { |
| Inet6Address possibleLinkLocalLoopback = null; |
| Inet6Address possibleLinkLocalOnGlobal = null; |
| Inet6Address possibleLinkLocalAny = null; |
| |
| Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); |
| while (interfaces.hasMoreElements()) { |
| NetworkInterface interf = interfaces.nextElement(); |
| if (!interf.isUp() || interf.isVirtual() || interf.isPointToPoint() || !interf.supportsMulticast()) { |
| continue; |
| } |
| Enumeration<InetAddress> addresses = interf.getInetAddresses(); |
| boolean globalOnInterface = false; |
| while (addresses.hasMoreElements()) { |
| InetAddress address = addresses.nextElement(); |
| if (address instanceof Inet6Address inet6Address) { |
| if (!inet6Address.isAnyLocalAddress() && !inet6Address.isLoopbackAddress() && !inet6Address.isLinkLocalAddress() && !inet6Address.isMulticastAddress()) { |
| globalOnInterface = true; |
| if (!interf.isLoopback()) { |
| globalAddress = inet6Address.getHostAddress(); |
| break; |
| } |
| } |
| } |
| } |
| |
| // Second pass to get link-local results with specific order |
| addresses = interf.getInetAddresses(); |
| while (addresses.hasMoreElements()) { |
| InetAddress address = addresses.nextElement(); |
| if (address instanceof Inet6Address inet6Address) { |
| if (inet6Address.isLinkLocalAddress()) { |
| if (interf.isLoopback()) { |
| // Best option for mac |
| possibleLinkLocalLoopback = inet6Address; |
| } else if (globalOnInterface && possibleLinkLocalOnGlobal == null) { |
| // link-local on an interface that also has a global IPv6 (e.g. en0) |
| possibleLinkLocalOnGlobal = inet6Address; |
| } else if (possibleLinkLocalAny == null) { |
| possibleLinkLocalAny = inet6Address; |
| } |
| } |
| } |
| } |
| } |
| |
| if (possibleLinkLocalLoopback != null) { |
| linklocalAddress = possibleLinkLocalLoopback.getHostAddress(); |
| } else if (possibleLinkLocalOnGlobal != null) { |
| linklocalAddress = possibleLinkLocalOnGlobal.getHostAddress(); |
| } else if (possibleLinkLocalAny != null) { |
| linklocalAddress = possibleLinkLocalAny.getHostAddress(); |
| } |
| |
| } |
| |
| private void assertHttpOkOnAddress(String address) throws Exception { |
| Tomcat tomcat = getTomcatInstance(); |
| tomcat.getConnector().setProperty("address", address); |
| File baseDir = new File(getTemporaryDirectory(), "ipv6"); |
| addDeleteOnTearDown(baseDir); |
| Assert.assertTrue(baseDir.mkdirs() && baseDir.isDirectory()); |
| tomcat.setBaseDir(baseDir.getAbsolutePath()); |
| Context context = tomcat.addContext("", null); |
| Tomcat.addServlet(context, "simple", new HelloWorldServlet()); |
| context.addServletMappingDecoded("/", "simple"); |
| |
| try { |
| tomcat.start(); |
| } catch (Exception e) { |
| Assume.assumeNoException("Can't bind to " + address, e); |
| } |
| if (address.contains(":")) { |
| address = "[" + address + "]"; |
| } |
| URL url = new URI("http://" + address + ":" + getPort() + "/").toURL(); |
| HttpURLConnection connection = (HttpURLConnection) url.openConnection(); |
| connection.connect(); |
| Assert.assertEquals(HttpServletResponse.SC_OK, connection.getResponseCode()); |
| tomcat.stop(); |
| } |
| } |