java 1.5 InetAddr doesn't consult system hosts file unless run from [pseudo]tty?

T

trawick

A simple test program can look up hostnames defined in system host file
as long as it is run with a tty. When run without a tty, it can't find
the hostnames. This issue leads to the failure of an application when
run remotely.

Various properties tweaked; seen on AIX and Linux/PPC too with
IBM-supplied java 1.5; recreated below with current Sun java 1.5 for
Solaris; an application which has the same issue with java 1.5 ran for
ages with java 1.4.2 on many platforms with no such issue

Has anybody seen anything similar?
From a Solaris 9 run with freshly downloaded/untweaked jre 1.5:

$ cat /etc/inet/ipnodes
#
# Internet host table
#
#::1 localhost
::1 ipv6host
127.0.0.1 ipv4host

$ cat useinetaddr.sh
#!/bin/sh

PATH=$HOME/jre1.5.0_09/bin:$PATH
export PATH

java -version

java UseInetAddr ipv4host
java UseInetAddr ipv6host

$ cat UseInetAddr.java
import java.net.InetAddress;

public class UseInetAddr {

public static void main(String[] args) throws Exception {
InetAddress inetAddr;

System.out.println("looking up " + args[0] + "...");
inetAddr = InetAddress.getByName(args[0]);
System.out.println("okay");
}
}

Run it directly from remote terminal... no problems

$ ./useinetaddr.sh
java version "1.5.0_09"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_09-b03)
Java HotSpot(TM) Client VM (build 1.5.0_09-b03, mixed mode, sharing)
looking up ipv4host...
okay
looking up ipv6host...
okay

Run it via ssh to self... fails to find the definition

$ ssh 127.0.0.1 ./useinetaddr.sh
java version "1.5.0_09"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_09-b03)
Java HotSpot(TM) Client VM (build 1.5.0_09-b03, mixed mode, sharing)
looking up ipv4host...
Exception in thread "main" java.net.UnknownHostException: ipv4host:
ipv4host
at java.net.InetAddress.getAllByName0(Unknown Source)
at java.net.InetAddress.getAllByName0(Unknown Source)
at java.net.InetAddress.getAllByName(Unknown Source)
at java.net.InetAddress.getByName(Unknown Source)
at UseInetAddr.main(UseInetAddr.java:9)
looking up ipv6host...
Exception in thread "main" java.net.UnknownHostException: ipv6host:
ipv6host
at java.net.InetAddress.getAllByName0(Unknown Source)
at java.net.InetAddress.getAllByName0(Unknown Source)
at java.net.InetAddress.getAllByName(Unknown Source)
at java.net.InetAddress.getByName(Unknown Source)
at UseInetAddr.main(UseInetAddr.java:9)

Run it via ssh to self, but tell ssh to allocate a pseudoterminal using
ssh -t option... works...

$ ssh -t 127.0.0.1 ./useinetaddr.sh
java version "1.5.0_09"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_09-b03)
Java HotSpot(TM) Client VM (build 1.5.0_09-b03, mixed mode, sharing)
looking up ipv4host...
okay
looking up ipv6host...
okay
Connection to 127.0.0.1 closed.
 
G

Gordon Beaton

A simple test program can look up hostnames defined in system host file
as long as it is run with a tty. When run without a tty, it can't find
the hostnames. This issue leads to the failure of an application when
run remotely.

I'm unable to reproduce this error using 1.5.0_09 on Linux or 1.5.0_08
on Solaris 10, however I suspect that the different behaviour can be
explained by differences in the environment set up by your shell in
the two cases.

E.g. what happens when you run these commands:

$ ssh localhost /usr/ucb/printenv
$ ssh -t localhost /usr/ucb/printenv

/gordon
 
T

trawick

Gordon said:
I'm unable to reproduce this error using 1.5.0_09 on Linux or 1.5.0_08
on Solaris 10, however I suspect that the different behaviour can be
explained by differences in the environment set up by your shell in
the two cases.

First, thanks for taking an interest! I had considered envvars before
and didn't come up with any key difference (see below). Also, I saved
envvars from a working environment and changed the env table to match
exactly when run via ssh, all with no happiness.
E.g. what happens when you run these commands:

$ ssh localhost /usr/ucb/printenv
$ ssh -t localhost /usr/ucb/printenv

$ ssh 127.0.0.1 /usr/ucb/printenv >envvars.notty
$ ssh -t 127.0.0.1 /usr/ucb/printenv >envvars.tty
Connection to 127.0.0.1 closed.
$ diff -ub envvars.notty envvars.tty
--- envvars.notty Wed Nov 15 10:48:13 2006
+++ envvars.tty Wed Nov 15 10:48:18 2006
@@ -9,6 +9,7 @@
HOSTTYPE=sparc
OSTYPE=solaris2.9
HOME=/home/trawick
-TERM=dumb
+TERM=xterm
PATH=/usr/bin:/bin:/usr/sbin:/sbin
+SSH_TTY=/dev/pts/3
_=/usr/ucb/printenv

FWIW, I just checked if changing my login shell from /usr/bin/bash to
/bin/sh would help. But it didn't.
 
T

trawick

Gordon said:
I'm unable to reproduce this error using 1.5.0_09 on Linux or 1.5.0_08
on Solaris 10...

Even though I've encountered the problem on several platforms with
different levels of Java 1.5, your failure to recreate promped the
thought that the failure is related to some common setting I apply to
my user id. I created a new user id on the Solaris 9 system, but it
still failed.
 
T

trawick

A simple test program can look up hostnames defined in system host file
as long as it is run with a tty. When run without a tty, it can't find
the hostnames. This issue leads to the failure of an application when
run remotely.

I compared truss of both runs. Here's what happens between loading
java libnet.so and making the door call to the resolver:

Good run (stdin is a terminal):

531/1: so_socket(PF_INET6, SOCK_STREAM, IPPROTO_IP, "", 1) = 5
Is this next line nonsense because it is calling getsockname() on
the wrong descriptor or nonsense because this resolver interface code
shouldn't care whether or not FILE_STDIN is a socket? Either way, this
error path from getsockname() is apparently related to the testcase
working.
531/1: getsockname(0, 0xFFBFDCEC, 0xFFBFDD0C, 1) Err#95
ENOTSOCK
531/1: ioctl(5, 0xC00C6982, 0xFFBFDCE0) = 0
531/1: close(5) = 0
531/1:
stat64("/home/trawick/jre1.5.0_09/lib/security/java.security",
0xFFBFC688) = 0
531/1:
open64("/home/trawick/jre1.5.0_09/lib/security/java.security",
O_RDONLY) = 5
531/1: fstat64(5, 0xFFBFC5F8) = 0
531/1: read(5, " #\n # T h i s i s ".., 8192) = 8192
531/1: lwp_cond_signal(0x000365D0) = 0
531/6: lwp_cond_wait(0x000365D0, 0x000365B8, 0x00000000) = 0
531/6: lwp_mutex_lock(0x000365B8) = 0
531/6: lwp_schedctl(SC_PREEMPT, 0, 0xFB77EA04) = 0
531/6: lwp_self() = 6
531/6: lwp_schedctl(SC_PREEMPT, 0, 0xFB77EA04) = 0
531/6: lwp_self() = 6
531/6: brk(0x0011FEA0) = 0
531/6: brk(0x00127EA0) = 0
531/6: brk(0x00127EA0) = 0
531/6: brk(0x0012FEA0) = 0
531/1: lwp_mutex_wakeup(0x000365B8) = 0
531/1: read(5, " f t h e c e r t i f".., 8192) = 2057
531/1: fstat64(5, 0xFFBFC450) = 0
531/1: llseek(5, 0, SEEK_CUR) = 10249
531/1: llseek(5, 0, SEEK_END) = 10249
531/1: llseek(5, 10249, SEEK_SET) = 10249
531/1: read(5, 0xFFBFA440, 8192) = 0
531/1: close(5) = 0
531/8: poll(0x00000000, 0, 50) = 0
531/1: open("/etc/netconfig", O_RDONLY|O_LARGEFILE) = 5
531/1: fcntl(5, F_DUPFD, 0x00000100) = 256
531/1: close(5) = 0
531/1: read(256, " # p r a g m a i d e n".., 1024) = 1024
531/1: read(256, " t s t p i _ c".., 1024) = 215
531/1: read(256, 0x0012E258, 1024) = 0
531/1: lseek(256, 0, SEEK_SET) = 0
531/1: read(256, " # p r a g m a i d e n".., 1024) = 1024
531/1: read(256, " t s t p i _ c".., 1024) = 215
531/1: read(256, 0x0012E258, 1024) = 0
531/1: close(256) = 0
531/1: open("/dev/udp", O_RDONLY) = 5
531/1: ioctl(5, 0xC00C6982, 0xFFBFE8FC) = 0
531/1: close(5) = 0
531/1: door_info(4, 0xFFBFC880) = 0
531/1: door_call(4, 0xFFBFC868) = 0
531/1: write(1, " o k a y", 4) = 4
531/1: write(1, "\n", 1) = 1

Failing run (stdin is not a terminal):

512/1: so_socket(PF_INET6, SOCK_STREAM, IPPROTO_IP, "", 1) = 5
Note that this getsockname(FILENO_STDIN) succeeds. But why does it
matter?
512/1: getsockname(0, 0xFFBFDD04, 0xFFBFDD24, 1) = 0
512/1:
stat64("/home/trawick/jre1.5.0_09/lib/security/java.security",
0xFFBFC6A0) = 0
512/1:
open64("/home/trawick/jre1.5.0_09/lib/security/java.security",
O_RDONLY) = 6
512/1: fstat64(6, 0xFFBFC610) = 0
512/1: read(6, " #\n # T h i s i s ".., 8192) = 8192
512/1: lwp_cond_signal(0x000365D0) = 0
512/6: lwp_cond_wait(0x000365D0, 0x000365B8, 0x00000000) = 0
512/6: lwp_mutex_lock(0x000365B8) = 0
512/6: lwp_schedctl(SC_PREEMPT, 0, 0xFB77EB84) = 0
512/6: lwp_self() = 6
512/6: lwp_schedctl(SC_PREEMPT, 0, 0xFB77EB84) = 0
512/6: lwp_self() = 6
512/6: brk(0x0011FEA0) = 0
512/6: brk(0x00127EA0) = 0
512/6: brk(0x00127EA0) = 0
512/6: brk(0x0012FEA0) = 0
512/1: lwp_mutex_wakeup(0x000365B8) = 0
512/1: read(6, " f t h e c e r t i f".., 8192) = 2057
512/1: fstat64(6, 0xFFBFC468) = 0
512/1: llseek(6, 0, SEEK_CUR) = 10249
512/1: llseek(6, 0, SEEK_END) = 10249
512/1: llseek(6, 10249, SEEK_SET) = 10249
512/1: read(6, 0xFFBFA458, 8192) = 0
512/1: close(6) = 0
512/1: open("/etc/netconfig", O_RDONLY|O_LARGEFILE) = 6
512/1: fcntl(6, F_DUPFD, 0x00000100) = 256
512/1: close(6) = 0
512/1: read(256, " # p r a g m a i d e n".., 1024) = 1024
512/1: read(256, " t s t p i _ c".., 1024) = 215
512/1: read(256, 0x0012E250, 1024) = 0
512/1: lseek(256, 0, SEEK_SET) = 0
512/1: read(256, " # p r a g m a i d e n".., 1024) = 1024
512/1: read(256, " t s t p i _ c".., 1024) = 215
512/1: read(256, 0x0012E250, 1024) = 0
512/1: close(256) = 0
512/1: open("/dev/udp", O_RDONLY) = 6
512/1: ioctl(6, 0xC00C6982, 0xFFBFE72C) = 0
512/1: close(6) = 0
512/1: door_info(4, 0xFFBFC6B0) = 0
512/8: poll(0x00000000, 0, 50) = 0
512/1: door_call(4, 0xFFBFC698) = 0
512/1: write(2, " E x c e p t i o n i n".., 27) = 27

Now tweak the shell script so that stdin isn't a socket even when ssh
doesn't allocate a tty:

$ cat useinetaddr2.sh
#!/bin/sh

PATH=$HOME/jre1.5.0_09/bin:$PATH
export PATH

java -version

java UseInetAddr ipv4host </dev/null
java UseInetAddr ipv6host </dev/null

$ ssh 127.0.0.1 ./useinetaddr2.sh
java version "1.5.0_09"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_09-b03)
Java HotSpot(TM) Client VM (build 1.5.0_09-b03, mixed mode, sharing)
looking up ipv4host...
okay
looking up ipv6host...
okay

Groan!
 
G

Gordon Beaton

I compared truss of both runs. Here's what happens between loading
java libnet.so and making the door call to the resolver:

I really don't have any concrete suggestions here, but maybe this will
give you some ideas...

I don't use Solaris much these days, but my understanding is that
/etc/inet/ipnodes was added to provide support for ipv6 addresses, and
that the resolver falls back to /etc/hosts when an entry isn't found
(but don't quote me on this). Is ipnodes still used if you haven't
enabled ipv6 support on your system?

Do you see similar behaviour if you write a short C program that uses
gethostbyname() or getipnode()? What if you put the hostname in
/etc/hosts instead of /etc/inet/ipnodes?

/gordon
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,533
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top