1 Reply Latest reply on Feb 21, 2018 4:46 AM by poppjens

    Wildfly 10.1 - ActiveMQ on IPv6

    poppjens

      Hi all,

       

      I have a Wildfly 10.1 server providing ActiveMQ Topics and Queues as well as Session Bean access via http-remoting to a Java Client. The server and client work for IPv4 without a problem.

       

      Right now I need to switch to IPv6. I got everything working but JMS. I use the following code:

       

        String JMS_CONNECTION_FACTORY_JNDI = "jms/RemoteConnectionFactory";
        Context context = getApplicationManager().getConnectionHandler().getContext();
        TopicConnectionFactory cf = (TopicConnectionFactory) context.lookup(JMS_CONNECTION_FACTORY_JNDI);
        topicConnection = cf.createTopicConnection();

       

      The same context is used to lookup session beans and this works! If I try to create the TopicConnection I get:

          java.nio.channels.UnresolvedAddressException

          at sun.nio.ch.Net.checkAddress(Net.java:101)

          at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:622)

          at io.netty.channel.socket.nio.NioSocketChannel.doConnect(NioSocketChannel.java:209)

          at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.connect(AbstractNioChannel.java:207)

          at io.netty.channel.DefaultChannelPipeline$HeadContext.connect(DefaultChannelPipeline.java:1097)

       

      After debugging I found, that the lookup returns a ServerLocator Object that has the IPv6 address with scope (%enp0s3 - which is the server network interface). I assume since the client doesn't know the scope (since it is on the server) it is not able to resolve the address. When I remove the scope in debugging in the URL in ActiveMQConnectionFactory.readExternal(..) during lookup the client starts without a problem.

       

      The strange thing is, that the EJB lookup on the same context works and I can access the server logic. So I assume that it is either a wrong setting or bug in Wildfly ActiveMQ.

       

      The binding on the Wildfly server is to the IPv6 Address without scope (so the scope is nowhere set but in the operating system!).

       

      2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000

      ....

          inet6 fd00::d7dc:b4cc:2e2a:ea1/64 scope global noprefixroute dynamic

             valid_lft 6893sec preferred_lft 3293sec

      ...

       

      This is only a test setup on a VM, so the IPv6  Address is just auto assigned.

       

      Any help on the topic is appreciated ;-)

        • 1. Re: Wildfly 10.1 - ActiveMQ on IPv6
          poppjens

          UPDATE Workaround

          Since this seems to be a problem with NettyConnector, I found a workaround. This is not nice, but it seems to work:

          String JMS_CONNECTION_FACTORY_JNDI = "jms/RemoteConnectionFactory"; 
          Context context = getApplicationManager().getConnectionHandler().getContext();
          TopicConnectionFactory cf = (TopicConnectionFactory) context.lookup(JMS_CONNECTION_FACTORY_JNDI);
          // TODO: Remove if fixed in Netty
          // THIS IS A PATCH SINCE NETTYCONNECTOR DOES NOT STRIP IPv6 SCOPE
          if (cf instanceof ActiveMQJMSConnectionFactory) {
          TransportConfiguration[] o = ((ActiveMQJMSConnectionFactory) cf).getStaticConnectors();
          for (TransportConfiguration tc : o) {
            String host = tc.getParams().get("host").toString();
            tc.getParams().put("host", stripScope(host));
          }
          }

          The stripScope is defined as:

          private static String stripScope(String ipV6host) {

          // only if it contains a %

          if (ipV6host != null && ipV6host.contains("%")) {

          // Strip [ and ] if any

          if (ipV6host.charAt(0) == '[') {

          if (ipV6host.length() > 2 && ipV6host.charAt(ipV6host.length() - 1) == ']') {

          ipV6host = ipV6host.substring(1, ipV6host.length() - 1);

          } else {

          // no closing ] return input value

          return ipV6host;

          }

          }

          if (Character.digit(ipV6host.charAt(0), 16) != -1 || (ipV6host.charAt(0) == ':')) {

          // see if it is IPv6 address

          byte[] addr;

          if (IPAddressUtil.textToNumericFormatV4(ipV6host) == null

          && (addr = IPAddressUtil.textToNumericFormatV6(ipV6host)) != null) {

          try {

          return InetAddress.getByAddress(addr).getHostAddress();

          } catch (UnknownHostException e) {

          }

          }

          }

          }

          return ipV6host;

          }

          This needs to be tested... is just a first working hack... any comments / better solutions are welcome.

          Please note: The default code from InetAddress.getByName cannot be used. This code tries to find the network interface, if it is defined in the host string. Since the network interface is not available on the client, this will fail, if the client does not have a interface with the same name / number!

          The underlying problem is, that the lookup distributes the IPv6 address with scope. This should only be done for Link-Local Addresses and not for Global or ULA.