5 Replies Latest reply on Nov 22, 2005 6:24 PM by twalsh2

    HttpNamingContextFactory and NAT

      I am having a problem using HttpNamingContextFactory to access JNDI running within a JBoss server which is sitting behind a NAT.

      This is happening with JBoss 3.2.6. I have customized my server config to use HTTPS for remote JNDI and EJB method invocations.

      Basically, when I try to look up the Home interface of an EJB I get a Connection refused error. The flow basically runs like this:

      1) I create an Initial context, specifying HttpNamingContextFactory as the "java.naming.factory.initial" and specifying an url of the form "https://<nat.ip.address>:8443/invoker/JNDIFactory" for the "java.naming.provider.url". I also specify the "java.naming.factory.url.pkgs" as "org.jboss.naming:org.jnp.interfaces".

      2) HttpNamingContextFactory makes the HTTPS request to ttps://<nat.ip.address>:8443/invoker/JNDIFactory and downloads the Naming Proxy. Within the Naming proxy is a URL referring to the JMXInvokerServlet of the form: "https://<actual.ip.address>:8443/invoker/JMXInvokerServlet"

      3) When I try to do a lookup(String) for the EJB home interface, HttpInvokerProxy tries to access the Naming service using the "https://<actual.ip.address>:8443/invoker/JMXInvokerServlet" URL, which is inaccessible since it has the actual address of the server rather than the address of the NAT gateway.

      I can see in the mbean definition of the "jboss:service=invoker,type=http,target=Naming" mbean how the JMXInvokerServlet URL is built. The code within HttpProxyFactory clearly uses the local hostname or a jboss.bind.address if specified.

      In non-NAT cases, the lookup works fine. We seem to get a failure because the NamingFactoryServlet returns a URL which contains an IP which is inaccessible to the client.

      The client knows the NAT address of the server. Is there anyway for the client to "override" the URL passed back by the NamingFactoryServlet?

      I have a very similar problem if the hostname of the machine running the JBoss server is not in DNS, which I worked around by setting the jboss.bind.address system property. Not an ideal solution but it works.

      In this case, the jboss.bind.address system property does not help as the server does not know it accessible via NAT.

      Any ideas? Does Jboss have support for using JNDI though a NAT?

        • 1. Re: HttpNamingContextFactory and NAT

          This seems to be related to a similar problem I posted here:
          http://www.jboss.com/index.html?module=bb&op=viewtopic&t=61514

          In general, the whole JNDI infrastructure seems to rely on the JBoss Application Server being in DNS and being directly accessible to clients (and not behind a NAT). When you bootstrap JNDI either via port 1099 or the JNDIFactory servlet, the stub returned is harcoded to use the hostname (or bind address) of the server.

          Is this accurate, or am I missing something?

          Does anyone run their app server on a machine not in DNS or on a machine sitting behind a NAT?

          I guess this problem only occurs with thick (rich) clients running on remote machines as a servlet probably would have no such problems looking up things (being that it is running on the same machine.

          Any help appreciated.

          • 2. Re: HttpNamingContextFactory and NAT
            bg000


            After the lookup, the server sends the addresses specified in deploy/http-invoker.sar/META-INF/jboss-service.xml to the client (when using http).

            Try this option :
            a) delet the attribute "UseHostName" and
            b) add an InvokerURL attribute and
            c) change the ports used in the file to your 8443 port.
            E.g :

            <!--
            true
            -->
            http://<nat.ip.address>:8443/invoker/JMXInvokerServlet


            • 3. Re: HttpNamingContextFactory and NAT
              bg000

              oh oh... none of the xml tags can be seen ! sorry about that... under the Naming bean and the HttpInvoker bean :

               <attribute name="InvokerURLSuffix">:8443/invoker/readonly/JMXInvokerServlet</attribute>
               <!-- <attribute name="UseHostName">true</attribute> -->
               <attribute name="InvokerURL">http://<nat.ip.address>:8443/invoker/readonly/JMXInvokerServlet</attribute>
              
              



              • 4. Re: HttpNamingContextFactory and NAT

                Thanks for pointing that out. I wasn't aware that you could do something like:

                <attribute name="InvokerURL">http://virtualhost.domain.com:8443/invoker/readonly/JMXInvokerServlet</attribute>


                And bypass the whole InvokerURLPrefix/InvokerURLSuffix mechanism.

                I still have a couple of problems though:

                1) I want the machine to be accessible both to other machines behind that NAT on its actual IP at the same time it is accessible to external machines through the NAT.

                2) How to handle multi-homed machines? Looking at the code for HttpInvoker.checkInvokerURL it looks like if you set useHostName to false and do not directly set a invokerURL, then it calls addr.getHostAddress() to build the URL . A quick test on a multi-homed Linux machine seems to indicate that this returns the IP of eth0.

                Can the InvokerURL be a relative URL (for example /invoker/JMXInvokerServlet) where the rest of the URL comes from the java.naming.provider.url specified when building the InitialContext?

                • 5. Re: HttpNamingContextFactory and NAT

                  Well a first pass at using a relative URL didn't work..

                  However Util.resolveURL has something interesting in it:

                  public static URL resolveURL(String urlValue) throws MalformedURLException
                   {
                   if (urlValue == null)
                   return null;
                  
                   URL externalURL = null;
                   try
                   {
                   externalURL = new URL(urlValue);
                   }
                   catch (MalformedURLException e)
                   {
                   // See if externalURL refers to a property
                   String urlProperty = System.getProperty(urlValue);
                   if (urlProperty == null)
                   throw e;
                   externalURL = new URL(urlProperty);
                   }
                   return externalURL;
                   }


                  Util.resolveURL is called by HttpInvokerProxy.readExternal when we are deserializing the proxy returned in the HTTP response to https://hostname:8443/invoker/JNDIFactory. It looks like in place of a URL, you can specify the name of a system property that contains the URL.

                  Maybe something like:

                  <attribute name="InvokerURL">jboss.httpinvoker.url</attribute>
                  

                  Note to mods: I know I am replying to my own posts. Just documenting things here in case another person has a similar requirement.