On Wed, Nov 12, 2025 at 4:03 PM Christopher Schultz < [email protected]> wrote:
> Dimitris, > > On 11/11/25 5:46 PM, Dimitris Soumis wrote: > > On Tue, Nov 11, 2025 at 9:47 PM Christopher Schultz < > > [email protected]> wrote: > > > >> Mark, > >> > >> On 11/11/25 1:17 PM, Christopher Schultz wrote: > >>> Mark, > >>> > >>> On 11/11/25 10:53 AM, Christopher Schultz wrote: > >>>> Mark, > >>>> > >>>> On 11/10/25 10:08 AM, Mark Thomas wrote: > >>>>> On 10/11/2025 15:01, Christopher Schultz wrote: > >>>>>> Mark, > >>>>>> > >>>>>> On 11/10/25 9:48 AM, Mark Thomas wrote: > >>>>>>> On 10/11/2025 14:15, Christopher Schultz wrote: > >>>>>>>> All, > >>>>>>>> > >>>>>>>> I've been looking into this, and I think the problem is that all > >>>>>>>> of the link-local interfaces detected during this test are not > >>>>>>>> actually routable: > >>>>>>>> > >>>>>>>> fe80:0:0:0:2609:93a5:c4ac:15ea%utun7 > >>>>>>>> fe80:0:0:0:926b:f264:7ec7:283e%utun6 > >>>>>>>> fe80:0:0:0:4ab0:1734:75f8:c236%utun5 > >>>>>>>> fe80:0:0:0:edc2:bbe0:ab0e:db71%utun4 > >>>>>>>> fe80:0:0:0:898:f4ff:feb6:6b87%llw0 > >>>>>>>> fe80:0:0:0:898:f4ff:feb6:6b87%awdl0 > >>>>>>>> fe80:0:0:0:ce81:b1c:bd2c:69e%utun3 > >>>>>>>> fe80:0:0:0:96b7:f229:b97f:3887%utun2 > >>>>>>>> fe80:0:0:0:c055:a248:e218:ba6b%utun1 > >>>>>>>> fe80:0:0:0:310c:b555:9669:572a%utun0 > >>>>>>>> > >>>>>>>> So even though Tomcat can bind to them, and you can create a URL > >>>>>>>> to try to connect, the OS will never route the packets as > expected. > >>>>>>>> > >>>>>>>> When checking all available interfaces on my machine, they all > >>>>>>>> seem to be IPv6 and all seem to be .. unusable to Tomcat? > >>>>>>>> > >>>>>>>> If I hard-code the interface "fe80::1%lo0" into the unit test, it > >>>>>>>> passes immediately and successfully. But when left to its own > >>>>>>>> devices, the test will randomly pick one of the other interfaces > >>>>>>>> and hang. > >>>>>>>> > >>>>>>>> I think the testing environment is being sandboxed by the OS and > >>>>>>>> so it doesn't even see those other interfaces that I know exist. > >>>>>>>> Instead, I only see these useless tunneling interfaces. For > >>>>>>>> example, "lo0" doesn't show up, and "en0" doesn't show up -- the > >>>>>>>> primary useful interfaces on this machine. > >>>>>>>> > >>>>>>>> So I wonder if we need some kind of workaround for MacOS. > >>>>>>> > >>>>>>> I think we need a more general work-around. Seeing a number of > >>>>>>> those were tunnels reminded me of the change we made to the unlock > >>>>>>> accept code to skip point to point interfaces. > >>>>>>> > >>>>>>> Something like: > >>>>>>> > >>>>>>> diff --git a/test/org/apache/catalina/startup/ > >>>>>>> TestStartupIPv6Connectors.java b/test/org/apache/catalina/startup/ > >>>>>>> TestStartupIPv6Connectors.java > >>>>>>> index c3c4b9a..2212e39 100644 > >>>>>>> --- > a/test/org/apache/catalina/startup/TestStartupIPv6Connectors.java > >>>>>>> +++ > b/test/org/apache/catalina/startup/TestStartupIPv6Connectors.java > >>>>>>> @@ -68,6 +68,9 @@ > >>>>>>> while (interfaces.hasMoreElements()) { > >>>>>>> NetworkInterface interf = interfaces.nextElement(); > >>>>>>> Enumeration<InetAddress> addresses = > >>>>>>> interf.getInetAddresses(); > >>>>>>> + if (interf.isPointToPoint()) { > >>>>>>> + continue; > >>>>>>> + } > >>>>>>> while (addresses.hasMoreElements()) { > >>>>>>> InetAddress address = addresses.nextElement(); > >>>>>>> if (address instanceof Inet6Address > inet6Address) { > >>>>>> > >>>>>> +1 > >>>>>> > >>>>>> This is one of the patches I had considered, but when I started > >>>>>> adding debug code to print stuff out, I had a in it and it wasn't > >>>>>> printing the %en interface (which would work) so I thought it would > >>>>>> always fail. > >>>>>> > >>>>>> I've fixed it and I think we basically have the same patch at this > >>>>>> point. > >>>>>> > >>>>>> But it still doesn't work for me, since %lo0 doesn't appear in the > >>>>>> list. %en0 not does appear > >>>> > >>>> This should have been "%en0 DOES appear..." > >>>> > >>>>> , but it's not link-local and so it doesn't > >>>>>> get chosen for this. Instead, the test chooses the %awdl0 interface > >>>>>> which is equally as useless for this test. > >>>>> > >>>>> What is that interface? Is there some characteristic we can use to > >>>>> filter it out as well? If the test can't find any interfaces, it will > >>>>> skip the test. > >>>> > >>>> I think awdl0 has something to do with AirPlay. > >>>> > >>>>>> ChatGPT says that I need to allow Java more privileges -- like "Full > >>>>>> Disk Access" in order to get access to the various real network > >>>>>> interfaces. I was hoping for a solution that didn't require that > >>>>>> because while it will work for me, it won't likely work for anyone > >>>>>> else who just happens to want to run the unit tests. > >>>>>> > >>>>>> We might have to implement an allow-list, block-list, etc. > >>>>> > >>>>> Yuck. I'd much prefer a general solution if we can find one. > >>>> > >>>> I spent some time chatting with AI and it didn't have any better ideas > >>>> other than a combination allow-list + deny-list to skip known-bad > >>>> interfaces (like %utun*) and include known-good interfaces (like %lo* > >>>> and %en*). > >>>> > >>>> I would also very much like to find a better solution. > >>>> > >>>> If I run the test with your patch, the test is skipped. Which is good, > >>>> I suppose. But it means the test isn't being run. I will give more > >>>> permissions to the JVM and see if it can see all interfaces and, > >>>> therefore, allow this test to run. > >>> > >>> Something is still weird. > >>> > >>> I wrote a short program to just dump out all the details of the network > >>> interfaces so I could compare before/after giving privileges and the > >>> before-state shows *everything*. > >>> > >>> So I'll need to dig more into why the test isn't seeing these > interfaces > >>> in my environment. > >> > >> This is a face-palm; I had completely forgotten that the test runs > >> through interfaces until it finds what it's looking for: both link-local > >> and "global" addresses. But it doesn't have any preference for which > >> one(s) of those it chooses. > >> > >> So it can detect-and-choose more than one link-local address, for > >> example, and the last one wins. Since we don't really care about which > >> link-local interface is chosen, it doesn't matter to us, either. But it > >> also doesn't have a fixed order in which it traverses the interface > >> list: it just looks in the order in which the JVM handed-out the > >> interfaces. > >> > >> So in my environment, the llw0 and awdl0 interfaces are listed first, > >> and are both acceptable as link-local addresses. Then later it sees the > >> %en0 interface -- which is "global" and stops. If it had continued > >> through the list, it would have seen the %lo0 interface which would work > >> much better. > >> > >> Here are all the interfaces and their flags on this system, in the order > >> in which Java ends up seeing them: > >> > >> Name Addr U L V P M n s l m > >> utun7 fe80:0:0:0:2609:93a5:c4ac:15ea%utun7 Y N N Y Y Y N N N > >> utun6 fe80:0:0:0:926b:f264:7ec7:283e%utun6 Y N N Y Y Y N N N > >> utun5 fe80:0:0:0:4ab0:1734:75f8:c236%utun5 Y N N Y Y Y N N N > >> utun4 fe80:0:0:0:edc2:bbe0:ab0e:db71%utun4 Y N N Y Y Y N N N > >> llw0 fe80:0:0:0:6473:baff:fe97:b9d%llw0 Y N N N Y Y N N N > >> awdl0 fe80:0:0:0:6473:baff:fe97:b9d%awdl0 Y N N N Y Y N N N > >> utun3 fe80:0:0:0:ce81:b1c:bd2c:69e%utun3 Y N N Y Y Y N N N > >> utun2 fe80:0:0:0:96b7:f229:b97f:3887%utun2 Y N N Y Y Y N N N > >> utun1 fe80:0:0:0:c055:a248:e218:ba6b%utun1 Y N N Y Y Y N N N > >> utun0 fe80:0:0:0:310c:b555:9669:572a%utun0 Y N N Y Y Y N N N > >> en0 fd00:0:0:0:10ce:a902:a735:c03a%en0 Y N N N Y N N N N > >> en0 2600:4040:452e:500:18cb:a7f7:f0ac:e9f0%en0 Y N N N Y N N N N > >> en0 2600:4040:452e:500:142c:94b5:4311:f3f1%en0 Y N N N Y N N N N > >> en0 fe80:0:0:0:1033:a61d:8b9c:3289%en0 Y N N N Y Y N N N > >> en0 192.168.50.225 Y N N N Y N Y N N > >> lo0 fe80:0:0:0:0:0:0:1%lo0 Y Y N N Y Y N N N > >> lo0 0:0:0:0:0:0:0:1%lo0 Y Y N N Y N N Y N > >> lo0 127.0.0.1 Y Y N N Y N N Y N > >> > >> The key for the flags is: > >> U - Up > >> L - Loop-back (interface) > >> V - Virtual > >> P - P-to-P > >> M - Multi-cast (interface) > >> n - Link-local > >> s - Site-Local > >> l - Loop-back (address) > >> m - Multi-cast (address) > >> > >> I think the only usable link-local interface in my environment will be > >> these: > >> > >> Name Addr U L V P M n s l m > >> en0 fe80:0:0:0:1033:a61d:8b9c:3289%en0 Y N N N Y Y N N N > >> lo0 fe80:0:0:0:0:0:0:1%lo0 Y Y N N Y Y N N N > >> > >> Both of those have the link-local flag set to TRUE, but these do as > well: > >> > >> Name Addr U L V P M n s l m > >> utun7 fe80:0:0:0:2609:93a5:c4ac:15ea%utun7 Y N N Y Y Y N N N > >> utun6 fe80:0:0:0:926b:f264:7ec7:283e%utun6 Y N N Y Y Y N N N > >> utun5 fe80:0:0:0:4ab0:1734:75f8:c236%utun5 Y N N Y Y Y N N N > >> utun4 fe80:0:0:0:edc2:bbe0:ab0e:db71%utun4 Y N N Y Y Y N N N > >> llw0 fe80:0:0:0:6473:baff:fe97:b9d%llw0 Y N N N Y Y N N N > >> awdl0 fe80:0:0:0:6473:baff:fe97:b9d%awdl0 Y N N N Y Y N N N > >> utun3 fe80:0:0:0:ce81:b1c:bd2c:69e%utun3 Y N N Y Y Y N N N > >> utun2 fe80:0:0:0:96b7:f229:b97f:3887%utun2 Y N N Y Y Y N N N > >> utun1 fe80:0:0:0:c055:a248:e218:ba6b%utun1 Y N N Y Y Y N N N > >> utun0 fe80:0:0:0:310c:b555:9669:572a%utun0 Y N N Y Y Y N N N > >> > >> Further removing the point-to-point ones leaves these: > >> > >> Name Addr U L V P M n s l m > >> llw0 fe80:0:0:0:6473:baff:fe97:b9d%llw0 Y N N N Y Y N N N > >> awdl0 fe80:0:0:0:6473:baff:fe97:b9d%awdl0 Y N N N Y Y N N N > >> > >> Maybe we want link-local PLUS interface-loopback? > >> > >> I think that gets us only these: > >> Name Addr U L V P M n s l m > >> lo0 fe80:0:0:0:0:0:0:1%lo0 Y Y N N Y Y N N N > >> > >> This patch (relative to the previous release) chooses %lo0 for the > >> link-local IPv6 address and %en0 for the global IPv6 address. And then > >> both unit tests pass. > >> > >> @@ -67,16 +67,22 @@ public class TestStartupIPv6Connectors extends > >> TomcatBaseTest { > >> Enumeration<NetworkInterface> interfaces = > >> NetworkInterface.getNetworkInterfaces(); > >> while (interfaces.hasMoreElements()) { > >> NetworkInterface interf = interfaces.nextElement(); > >> + if(interf.isPointToPoint()) { > >> + continue; > >> + } > >> Enumeration<InetAddress> addresses = > >> interf.getInetAddresses(); > >> while (addresses.hasMoreElements()) { > >> InetAddress address = addresses.nextElement(); > >> + System.out.println("Detected interface " + address); > >> if (address instanceof Inet6Address) { > >> Inet6Address inet6Address = (Inet6Address) > address; > >> - if (inet6Address.isLinkLocalAddress()) { > >> + if (inet6Address.isLinkLocalAddress() && > >> interf.isLoopback()) { > >> linklocalAddress = > inet6Address.getHostAddress(); > >> + System.out.println("Chose " + address + " as > >> link-local address"); > >> } > >> if (!inet6Address.isAnyLocalAddress() && > >> !inet6Address.isLoopbackAddress() && !inet6Address.isLinkLocalAddress() > >> && !inet6Address.isMulticastAddress()) { > >> globalAddress = > inet6Address.getHostAddress(); > >> + System.out.println("Chose global address: " + > >> address); > >> } > >> if (linklocalAddress != null && globalAddress != > >> null) { > >> return; > >> > >> Obviously the System.outs will be removed. > >> > >> WDYT? > >> > >> -chris > >> > >> > >> --------------------------------------------------------------------- > >> To unsubscribe, e-mail: [email protected] > >> For additional commands, e-mail: [email protected] > >> > >> > > Kind of late to the discussion, but the link-local IPv6 to be on the > > loopback interface is not the default on Linux and the test gets > skipped. I > > propose the following patch: > > > > --- a/test/org/apache/catalina/startup/TestStartupIPv6Connectors.java > > +++ b/test/org/apache/catalina/startup/TestStartupIPv6Connectors.java > > @@ -64,28 +64,62 @@ public class TestStartupIPv6Connectors extends > > TomcatBaseTest { > > > > @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(); > > Enumeration<InetAddress> addresses = > interf.getInetAddresses(); > > - if (interf.isPointToPoint()) { > > + if (!interf.isUp() || interf.isVirtual() || > > interf.isPointToPoint()) { > > continue; > > } > > + boolean globalOnInterface = false; > > while (addresses.hasMoreElements()) { > > InetAddress address = addresses.nextElement(); > > if (address instanceof Inet6Address inet6Address) { > > - if (inet6Address.isLinkLocalAddress()) { > > - linklocalAddress = > inet6Address.getHostAddress(); > > - } > > if (!inet6Address.isAnyLocalAddress() && > > !inet6Address.isLoopbackAddress() && !inet6Address.isLinkLocalAddress() > && > > !inet6Address.isMulticastAddress()) { > > - globalAddress = inet6Address.getHostAddress(); > > + globalOnInterface = true; > > + if (!interf.isLoopback()) { > > + globalAddress = > inet6Address.getHostAddress(); > > + break; > > + } > > } > > - if (linklocalAddress != null && globalAddress != > null) > > { > > - return; > > + } > > + } > > + > > + // 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(); > > + } > > } > > Looks good to me. Mark, does this look like Windows will have any > issues? I suspect you wouldn't have +1'd if it did. > We can harden it more by also skipping interfaces that don't support multicast as it can be disabled by firewall rules. - if (!interf.isUp() || interf.isVirtual() || interf.isPointToPoint()) { + if (!interf.isUp() || interf.isVirtual() || interf.isPointToPoint() || !interf.supportsMulticast()) { > > I can also post my interface info class source if anyone is interested > in what their system interfaces loo like to Windows. > This could help identify possible edge cases. > > -chris > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [email protected] > For additional commands, e-mail: [email protected] > >
