Problem in calling a server behind a NAT router
Hi All,
I've been struggling with this problem for the past few days but I can't find any solution.
I'm trying to establish a connection from a remote client to a server behind a NAT router. I put-Djava.rmi.server.hostname=XXX.18.5.236 in the server side, I'm calling the server with the correct port, but the connection is not established. I receive the following exception in the client:
com.company.ems.client.login.LoginFrame.OKButton_actionPerformed \ java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
java.lang.ClassNotFoundException: com.company.ems.server.framework.LoginImpl_Stub
I can see in a networking monitoring tool, that that returned packet contains the wrong IP (XXX.17.5.236)
What did I miss here?
[800 byte] By [
Lior_Levya] at [2007-11-27 4:59:17]

# 1
Well you missed that the client has a missing class for a start.
You have to set that system property before exporting any RMI objects and that includes creating the Registry if you do that in your JVM. You also have to control the ports your server(s) are exported on explicitly, and ensure those ports are mapped at the NAT device.
ejpa at 2007-7-12 10:15:30 >

# 2
Thanks for your reply.
The missing class which is LoginImpl_stub is the stub which should be sent from the server to the client after the lookup, isn't it? Why should I keep the stubs in the client?
Regarding what you wrote You have to set that system property before exporting any RMI objects and that includes creating the Registry - I set the system property at the script that runs the application. Should I put it somewhere else?
One last thing - what do you mean by ports are mapped at the NAT device? Do I have to explicitly configure the ports in the NAT router?
Thanks!!
# 3
> The missing class which is LoginImpl_stub is the stub
> which should be sent from the server to the client
> after the lookup, isn't it? Why should I keep the
> stubs in the client?
The stub object is sent from the server to the client. The missing class is a class. The client needs the remote interface class, the remote stub class, and any class they depend on, and so oin recursively until closure.
> Should I put it somewhere else?
No
> Do I have to explicitly configure the ports in the NAT router?
Yes.
ejpa at 2007-7-12 10:15:30 >

# 4
This is exactly the architecture! I have the Login interface which extends from Remote interface, but the lookup still fails with the ClassNotFoundException:
Login login = (Login)Naming.lookup(url + "LookupString");
Why is that?
When I put the stubs in the client jar, I receive a different exception:
com.company.ems.client.login.LoginFrame.OKButton_actionPerformed \ java.rmi.ConnectIOException: Exception creating connection to: XXX.17.5.236; nested exception is:
java.io.IOException: Connection timed out: connect
Please note that the IP in the exception is XXX.17.5.236 which is the IP behind the NAT router which indicates that setting the system property didn't help.
BTW, the router is configured well...
# 5
> Why is that?
Because the client needs the stub class like I said.
> When I put the stubs in the client jar, I receive a
> different exception:
Exactly. You get further when the client has the stub class.
> which indicates that setting the system property
> didn't help.
Are you sure you spelt it correctly? It has to be set on every JVM that exports a remote object, and on the Registry too.
ejpa at 2007-7-12 10:15:30 >

# 6
Here is the server launch command which is done in a solaris server:
/usr/bin/java -Xms32m -Xmx200m -server -cp "server.jar:externals:AdventNetSnmp4.jar:AdventNetLogging4.jar:AdventNetUtils.jar:jdbc2_0-stdext.jar:concurrent.jar:${oraHome}/jdbc/lib/classes12.jar" -Djava.rmi.server.codebase=http://${serverIP}:22001/ -Djava.security.auth.login.config=./externals/ldapSecurityConfig/audcJaas.config -Djava.library.path=./lib com.company.ems.server.framework.ServerStartup -Djava.rmi.server.hostname=10.18.5.236
Maybe there is a collision between 2 system parameters? Could it be?
# 7
The name of the class or JAR to execute must come after all the -D arguments.
ejpa at 2007-7-12 10:15:30 >

# 8
I did everything by the book (including your last comment), but still I receive "connection refused".
When I use a network monitoring tool I see that the IP the client is trying to connect to is the IP behind the NAT router and not the one in the -Djava.rmi.server.hostname parameter.
What could be the reason for this?
# 9
show the command line you're using now
ejpa at 2007-7-12 10:15:30 >

# 10
Here it is:
/usr/bin/java -Xms32m -Xmx200m -server -cp "server.jar:externals:AdventNetSnmp4.jar:AdventNetLogging4.jar:AdventNetUtils.jar:jdbc2_0-stdext.jar:concurrent.jar:${oraHome}/jdbc/lib/classes12.jar" -Djava.rmi.server.hostname=10.18.5.236 -Djava.rmi.server.codebase=http://${serverIP}:22001/ -Djava.security.auth.login.config=./externals/ldapSecurityConfig/audcJaas.config -Djava.library.path=./lib com.company.ems.server.framework.ServerStartup
# 11
> -Djava.rmi.server.hostname=10.18.5.236That looks like an IP address behind a NAT router to me, not a public IP address.
ejpa at 2007-7-12 10:15:30 >

# 12
No. This is not the IP behind a NAT router. This is the IP that the client refers to. The IP behind the NAT router is 10.17.5.236 and this is the IP I see in the networking monitoring tool which the client tries to call after the server sends the stub.
# 13
OK, does that JMV start other JMVs by any chance? or are you using RMI Activation by any chance?
ejpa at 2007-7-12 10:15:30 >

# 14
I managed to solve this problem by setting both java.rmi.server.hostname and java.rmi.server.codebase to 10.18.5.236.
I don't know why it solved the problem, but it did.
The only problem now is, that if someone wants to connect the application from within the network behind the NAT router (10.17.xxx.xxx) - he can't. This solution is working only for someone who connects the application from outside the NAT router (10.18.xxx.xxx).
Any idea why?
# 15
That would be because your external clients need access to the codebase, which you've evidently only just given them by providing an external IP address for it.
Your internal clients are now probably failing because your netadmins have prevented access to the outside address from the inside. Try pinging it from inside to check this.
ejpa at 2007-7-21 21:17:22 >

# 16
I can successfully ping the outside address (10.18.xxx.xxx) from the inside address (10.17.xxx.xxx), so the problem is probably not a prevention of access.
I have a feeling that the problem is in the hostname parameter. When a client from the inside address calls the server, the host name parameter should be set differently than in the case of a calling client from the outside address. Does it make any sense?
# 17
No, they have to be the same, and they both have to be the 'public' hostname or IP address. This is a constraint laid down by Sun for RMI. That's what java.rmi.server.hostname is for - to control which hostname/IP address is embedded in stubs exported from this JVM.
See my last post in http://forum.java.sun.com/thread.jspa?threadID=5167942&tstart=0
ejpa at 2007-7-21 21:17:22 >

# 18
You wrote "Internal clients will be expected to connect to the RMI server(s) via the public IP address"
How is it possible?
If those two parameters (codebase and hostname) need to have the same IP addresses, how can you enable the following situation:
You work in a company and you connect the company server using the inside IP address. When you go home, you can also connect this server from your private pc where your client is of course in an outside IP address and in order to connect the server you need to pass through a NAT router.
This situation is of course possible. The BIG question is how can I make it work.
# 19
Sun have made the assumption in RMI that there is always a 'most public' IP address for any device, that anybody can use. In this case they are expecting that internal clients use the outside IP address.
Their assumption is frequently incorrect, of course, and it is also unnecessary, as there is a better and simpler solution, involving no system properties, which they haven't implemented even though I pointed out all this on the mailing list some years ago. The reaction from inside Sun was basically negative.
So, if you can't get your network adjusted to suit Sun's preconceptions, you only have the choices outlined in this thread and the other one I referred you to above.
Or see http://www.telekinesis.com.au, my RMI Proxy product, for another possible solution.
ejpa at 2007-7-21 21:17:22 >
