16

This sounds like something that should have been asked before, and it has sort of, but I'm looking to get the local hostname and IP addresses of a machine even when it is not resolvable through DNS (in Java).

I can get the local IP addresses without resolution by iterating through NetworkInterfaces.getNetworkInterfaces().

Any answers to this question I've found indicate to use getLocalHost()

InetAddress localhost = java.net.InetAddress.getLocalHost();
hostName = localhost.getHostName();

but this throws an UnknownHostException if the hostname isn't resolvable through DNS.

Is there no way to get the local hostname without a DNS lookup happening behind the scenes?

edit: the IP address retrieved is 10.4.168.23 The exception is java.net.UnknownHostException: cms1.companyname.com: cms1.companyname.com (hostname changed for pseudo-anonymity), and the hosts file does not contain the hostname. But it does know its hostname, so I'm not sure why I can't get it without an exception being thrown.

Shawn D.
  • 7,895
  • 8
  • 35
  • 47

8 Answers8

16

Yes, there should be a way in Java to get the hostname without resorting to name service lookups but unfortunately there isn't.

However, you can do something like this:

if (System.getProperty("os.name").startsWith("Windows")) {
    // Windows will always set the 'COMPUTERNAME' variable
    return System.getenv("COMPUTERNAME");
} else {
    // If it is not Windows then it is most likely a Unix-like operating system
    // such as Solaris, AIX, HP-UX, Linux or MacOS.

    // Most modern shells (such as Bash or derivatives) sets the 
    // HOSTNAME variable so lets try that first.
    String hostname = System.getenv("HOSTNAME");
    if (hostname != null) {
       return hostname;
    } else {

       // If the above returns null *and* the OS is Unix-like
       // then you can try an exec() and read the output from the 
       // 'hostname' command which exist on all types of Unix/Linux.

       // If you are an OS other than Unix/Linux then you would have 
       // to do something else. For example on OpenVMS you would find 
       // it like this from the shell:  F$GETSYI("NODENAME") 
       // which you would probably also have to find from within Java 
       // via an exec() call.

       // If you are on zOS then who knows ??

       // etc, etc
    }
}

and that will get you 100% what you want on the traditional Sun JDK platforms (Windows, Solaris, Linux) but becomes less easy if your OS is more excotic (from a Java perspective). See the comments in the code example.

I wish there was a better way.

peterh
  • 18,404
  • 12
  • 87
  • 115
  • I don't get no `HOSTNAME` when Tomcat is an rc.d service under FreeBSD, unfortunately. – lapo May 06 '14 at 11:23
  • @lapo. Not a Java issue. You'll need to understand your shell: when is the `HOSTNAME` environment variable set? You'll probably get a good answer if you ask in a Unix/Linux forum something like: *"Environment variable HOSTNAME not defined. Why?"*. – peterh May 07 '14 at 11:19
  • not a Java issue, but being available by default is one thing; if I must change the system defaults, I might as well properly define in `127.0.0.1` in `/etc/host` (which is a good rule anyways). In the end I used `HOSTNAME` else `COMUTERNAME` else `getLocalHost()`. – lapo May 07 '14 at 12:16
7

This question is old, but unfortunately still relevant since it's still not trivial to get a machine's host name in Java. Here's my solution with some test runs on different systems:

public static void main(String[] args) throws IOException {
        String OS = System.getProperty("os.name").toLowerCase();

        if (OS.indexOf("win") >= 0) {
            System.out.println("Windows computer name throguh env:\"" + System.getenv("COMPUTERNAME") + "\"");
            System.out.println("Windows computer name through exec:\"" + execReadToString("hostname") + "\"");
        } else {
            if (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0) {
                System.out.println("Linux computer name throguh env:\"" + System.getenv("HOSTNAME") + "\"");
                System.out.println("Linux computer name through exec:\"" + execReadToString("hostname") + "\"");
                System.out.println("Linux computer name through /etc/hostname:\"" + execReadToString("cat /etc/hostname") + "\"");
            }
        }
    }

    public static String execReadToString(String execCommand) throws IOException {
        Process proc = Runtime.getRuntime().exec(execCommand);
        try (InputStream stream = proc.getInputStream()) {
            try (Scanner s = new Scanner(stream).useDelimiter("\\A")) {
                return s.hasNext() ? s.next() : "";
            }
        }
    }

Results for different operating systems:

OpenSuse 13.1

Linux computer name throguh env:"machinename"
Linux computer name through exec:"machinename
"
Linux computer name through /etc/hostname:""

Ubuntu 14.04 LTS This one is kinda strange since echo $HOSTNAME returns the correct hostname, but System.getenv("HOSTNAME") does not (this however might be an issue with my environment only):

Linux computer name throguh env:"null"
Linux computer name through exec:"machinename
"
Linux computer name through /etc/hostname:"machinename
"

Windows 7

Windows computer name throguh env:"MACHINENAME"
Windows computer name through exec:"machinename
"

The machine names have been replaced for (some) anonymization, but I've kept the capitalization and structure. Note the extra newline when executing hostname, you might have to take it into account in some cases.

Malt
  • 28,965
  • 9
  • 65
  • 105
  • I see the same issue on Ubuntu 14.04 with the `HOSTNAME` environment variable. It is not being exported to tasks launched by the shell (bash). Executing `export HOSTNAME` solves the issue. – neuhaus Oct 11 '16 at 15:51
3

Alternatively, use JNA to call the gethostname function on unixes, avoiding the reverse DNS lookup.

Some notes: on Linux, I believe gethostname simply calls uname and parses the output. On OS X the situation is more complex, as your hostname can be affected by DNS, but those side-effects aside, it's definitely what I get from hostname.

import com.sun.jna.LastErrorException
import com.sun.jna.Library
import com.sun.jna.Native

...

private static final C c = (C) Native.loadLibrary("c", C.class);

private static interface C extends Library {
    public int gethostname(byte[] name, int size_t) throws LastErrorException;
}

public String getHostName() {
    byte[] hostname = new byte[256];
    c.gethostname(hostname, hostname.length)
    return Native.toString(hostname)
}

jna-platform.jar includes Win32 functions, so there it's as simple as a call to Kernel32Util.getComputerName().

Danny Thomas
  • 1,879
  • 1
  • 18
  • 32
1

Java will read the /etc/hosts file if there is no DNS configured, or rather the corresponding C functions will.

user207421
  • 305,947
  • 44
  • 307
  • 483
1

If you are getting 127.0.0.1 as the IP address then you may need to locate your Operating System specific hosts file and add a mapping to your hostname in it.

sinha
  • 588
  • 2
  • 5
  • The OS knows the hostname, as when I call getLocalHost(), it throws an exception containing the hostname. I just want to be able to get that hostname without a lookup. – Shawn D. May 18 '11 at 20:31
  • Make sure your hostname does not contains any underscore characters. If you are on Windows then it would not prevent you from using underscores in hostname, but it does not work with Java because of strict check on permitted characters. – sinha May 19 '11 at 05:39
1

This is a bit of a hack. But you could launch a new Process from Java and run the hostname command. Reading the outputstream of the child process would give you the name of the localhost.

Vineet Reynolds
  • 76,006
  • 17
  • 150
  • 174
0

on Linux read

/proc/sys/kernel/hostname
weberjn
  • 1,840
  • 20
  • 24
0

If you're not against using an external dependency from maven central, I wrote gethostname4j to solve this problem for myself. It just uses JNA to call libc's gethostname function (or gets the ComputerName on Windows) and returns it to you as a string.

https://github.com/mattsheppard/gethostname4j

(I think it's almost exactly what @danny-thomas proposed, but maybe more convenient if you're already using Maven ;)

Matt Sheppard
  • 116,545
  • 46
  • 111
  • 131