Uploaded image for project: 'WildFly'
  1. WildFly
  2. WFLY-9876

ActiveMQ Artemis with IPv6 and Scope fails

    XMLWordPrintable

Details

    • Bug
    • Status: Closed (View Workflow)
    • Major
    • Resolution: Done
    • 10.1.0.Final, 11.0.0.Final
    • 14.0.0.Final
    • JMS
    • None
    • Hide

      1.) Configure Centos 7 system (other might also work) with IPv6 ULA address
      2.) Install Wildfly 10.1 and configure JMS Topic via http remoting
      3.) Configury wildfly to bind to IPv6 Address (without scope!)
      4.) Use java client on Windows Machine to Lookup the Topic.

      Show
      1.) Configure Centos 7 system (other might also work) with IPv6 ULA address 2.) Install Wildfly 10.1 and configure JMS Topic via http remoting 3.) Configury wildfly to bind to IPv6 Address (without scope!) 4.) Use java client on Windows Machine to Lookup the Topic.
    • Hide

      The TransportConfiguration must be patched to strip the scope...

              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));
                  }
              }
      

      ....
      And don't use InetAddress.getByName (see error description). A independent solution is needed, e.g.:

      private 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;
      }
      
      Show
      The TransportConfiguration must be patched to strip the scope... 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)); } } .... And don't use InetAddress.getByName (see error description). A independent solution is needed, e.g.: private 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; }

    Description

      Somehow Java behaves differently on Linux and Windows regarding the IPv6 Network Interfaces. With a small programm you can test this:

          Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
          while (interfaces.hasMoreElements()) {
              NetworkInterface netInterface = interfaces.nextElement();
              Enumeration<InetAddress> address = netInterface.getInetAddresses();
              while (address.hasMoreElements()) {
                  InetAddress addr = address.nextElement();
                  if (addr instanceof Inet6Address) {
                      Inet6Address inet6addr = (Inet6Address) addr;
                      if (!inet6addr.isLinkLocalAddress() && !inet6addr.isLoopbackAddress())
                          System.out.println(netInterface.getName() +":"+ inet6addr.isLinkLocalAddress() +":"+ inet6addr +" - "+ inet6addr.getScopedInterface());
      
                  }
              }
          }
      

      In windows the scope will only be set for Link Local, in CentOS also for ULA addresses.

      If I lookup the JMS from a ULA address (without scope) e.g. with:

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

      The TopicConnectionFactory is ActiveMQJMSConnectionFactory. This factory receives a TransportConfiguration from the server that includes the server scope (IPv6 Address with NetworkInterface after % e.g. [fd00::d7dc:b4cc:2e2a:ea1%enp0s3]). Trying to create a topic connection with the TopicConnectionFactory will fail, since the client does not know the scope (enp0s3).

      There is a bug fix in NettyConnector (HORNETQ-907) to strip this "%enp0s3" scope, but this BugFix does not work. The fix uses the standard InetAddress methods to parse the host String, which fails, if the host String contains a server scope (network interface) not available on the client. This will only cause an exception, if server and client have different names for the NetworkInterfaces! Testing e.g. on two identical Linux machines will not uncover the problem!

      I think the underlying problem is, that the lookup distributes the server scope in the IPv6 Address. The scope should only be distributed for Link-local Addresses, for all other addresses the scope should be stripped already on the server and not be distributed during lookup.

      Attachments

        Activity

          People

            jmesnil1@redhat.com Jeff Mesnil
            jens.popp@camline.com Jens Popp (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: