Client computer name in java - java

I want to find client computer name in java. My applciation runs in intranet. so i am using below code
public String findClientComputerName(HttpServletRequest request) {
String computerName = null;
String remoteAddress = request.getRemoteAddr();
System.out.println("remoteAddress: " + remoteAddress);
try {
InetAddress inetAddress = InetAddress.getByName(remoteAddress);
System.out.println("inetAddress: " + inetAddress);
computerName = inetAddress.getHostName();
System.out.println("computerName: " + computerName);
if (computerName.equalsIgnoreCase("localhost")) {
computerName = java.net.InetAddress.getLocalHost().getCanonicalHostName();
}
} catch (UnknownHostException e) {
log.error("UnknownHostException detected in StartAction. ", e);
}
if(StringUtils.trim(computerName).length()>0) computerName = computerName.toUpperCase();
System.out.println("computerName: " + computerName);
return computerName;
}
but sometimes i am getting host name properly but some time not. I am getting Correct IP. What may be the reason for this? Why inetAddress.getHostName(); is failing to give host name some time? Your help is very appriciated.

private String getHostName (InetAddress inaHost) throws UnknownHostException
{
try
{
Class clazz = Class.forName("java.net.InetAddress");
Constructor[] constructors = clazz.getDeclaredConstructors();
constructors[0].setAccessible(true);
InetAddress ina = (InetAddress) constructors[0].newInstance();
Field[] fields = ina.getClass().getDeclaredFields();
for (Field field: fields)
{
if (field.getName().equals("nameService"))
{
field.setAccessible(true);
Method[] methods = field.get(null).getClass().getDeclaredMethods();
for (Method method: methods)
{
if (method.getName().equals("getHostByAddr"))
{
method.setAccessible(true);
return (String) method.invoke(field.get (null), inaHost.getAddress());
}
}
}
}
} catch (ClassNotFoundException cnfe) {
} catch (IllegalAccessException iae) {
} catch (InstantiationException ie) {
} catch (InvocationTargetException ite) {
throw (UnknownHostException) ite.getCause();
}
return null;
}
above function returning host name correctly in Intranet. for local it will return localhost.
To get the name for local host we use computerName = java.net.InetAddress.getLocalHost().getCanonicalHostName();

HttpServletRequest will return the IP address (either v4 or v6) of whoever is hitting your servlet. That address may or may not resolve to a valid hostname. InetAddress.getHostName() does a reverse DNS resolution of the IP address. It is not required that each IP address allocated maps back to a valid DNS entry. There are, in fact, a large percent of IP addresses in the world that will not resolve to a hostname.
You can see the same thing using the 'host' command on a linux box to look up the reverse DNS entry (if any) for a given IP address.

The InetAddress.getHostName() function will return the host name if the InetAddress object was initialized with a host name. Otherwise, it'll do a reverse DNS lookup to get the host name.
To get this reverse DNS lookup to work, you'll need to make sure all of the clients on your intranet are configured with host names and that your DNS provider (e.g. your router) properly matches up the host names with its records. (Some routers can do this automatically.)

In order to get the hostname of windows machines, you will need to perform a reverse NetBIOS lookup on the IP address. Windows uses a system called WINS to provide hostnames to its computers. This system is based off NetBIOS.
If you don't want to try to find a specification of the protocol and implement it yourself, then you will want to execute the command nbtstat -A [ip address] if you are on Windows, or nmblookup -A [ip address] if you are on a Linux machine. If you are on a Linux machine, the Samba package will have to be installed as the nmblookup executable is installed on all Linux machines. You will then have to parse the output of that command to get the host name.
The alternative is, as stated before, try to find a specification of the protocol, and implement the part that you need to implement.

Related

Why does HttpServletRequest.getRemoteAddr() with IPv6 address return extra characters

In my Tomcat-hosted web app, the first two lines in a doGet(...) method are:
String ip = request.getRemoteAddr();
System.out.println("ip = " + ip);
With an IPv6 address on our local network, it outputs:
ip = fe80:0:0:0:ac40:98cb:ca2e:c03c%4
The %4 at the end seems extraneous. It is causing requests to our geolocation service to fail. Is this %4 supposed to be there? If so, what does it signify? Is there a reliable way to get a IPv6 address from an HttpServletRequest instance that does NOT have the %4?
It's the scope ID. Using native APIs, your best bet to get rid of it would be as below with help of java.net.InetAddress and Inet6Address#getScopeId():
String ip = request.getRemoteAddr();
InetAddress inetAddress = InetAddress.getByName(ip);
if (inetAddress instanceof Inet6Address) {
Inet6Address inet6Address = (Inet6Address) inetAddress;
int scopeId = inet6Address.getScopeId();
if (scopeId > 0) {
ip = inet6Address.getHostName().replaceAll("%" + scopeId + "$", "");
}
}
This clumsiness is because the standard java.net.Inet6Address API doesn't have any method which returns the bare hostname without scope ID.
On the other hand, I'd wonder if the geolocation service in question should in turn not already be taking that into account. If the support for IPv6 scopes is even not explicitly excluded in their API documentation, then I'd file an issue at their issue tracker.

Get the name and IP of devices on a Wifi network

I know this question has been asked here but it didn't get answered.
I'm writing a simple Java Swing application in which I want to show the name and IP address of each and every device that is connected to my wireless network.
I want to show this list in a JFrame. I searched a lot on the web but couldn't find a way to achieve this. Please help me out Java masters!
Thanks in advance!
I found this code after looking a little bit. It works, but it is slow, and probably not the best way to do it, but it works.
import java.io.IOException;
import java.net.InetAddress;
public class NetworkPing {
/**
* JavaProgrammingForums.com
*/
public static void main(String[] args) throws IOException {
InetAddress localhost = InetAddress.getLocalHost();
// this code assumes IPv4 is used
byte[] ip = localhost.getAddress();
for (int i = 1; i <= 254; i++)
{
ip[3] = (byte)i;
InetAddress address = InetAddress.getByAddress(ip);
if (address.isReachable(1000))
{
System.out.println(address + " machine is turned on and can be pinged");
}
else if (!address.getHostAddress().equals(address.getHostName()))
{
System.out.println(address + " machine is known in a DNS lookup");
}
else
{
System.out.println(address + " the host address and host name are equal, meaning the host name could not be resolved");
}
}
}
}
Couple things to note, address.getHostAddress() returns the 192.168.0.xxx
and address.getHostName() returns the name of the device like "Kevins-PC"
It's a pretty simple piece of code, but I'll walk through it real fast.
It starts off by getting your localhost IP address (which on a normal household network would be 192.168.0.xxx) and it stores that in a byte[] so it looks something like {192, 168, 0, xxx}.
Then it creates a for loop starting at 1 and going to 254 (because this code assumes a /24 subnet mask (255.255.255.0) but if its running a different subnet mask then it might not be 1-254).
Then in the for loop it sets the third index of the ip to i.
It then creates an InetAddress from that address.
Then it tries to reach it in 1000 milliseconds (1 second), and if it succeeds then it prints the address and says its reachable.
Else if the machine host address (the 192.168.0.xxx) does not equal the host name (like the name of your computer like Kevins-PC), then it says that the machine is known in a DNS lookup meaning it is found in a DNS lookup but it wasnt reachable (so its probably off or not connected, but it has been before), DNS is Domain Name Service. The DNS basically stores the information (your router probably does this).
Finally, else it just says it couldn't be resolved which means it wasnt reachable nor was it found looking in the DNS.
I found this code here and here
UPDATE
So if you run this and you just keep getting something like "192.168.0.5/192.168.0.5 the host address and host name are equal, meaning the host name could not be resolved"
That means that your router (your local DNS) just isn't storing the information OR those devices just choose not to submit their host name to the router, and that is why you will continually get that message. As far as I am aware, there isn't a way around this because those device names literally aren't stored
Try this :)
import java.io.IOException;
import java.net.*;
import java.util.Vector;
public class search {
public static void main(String args[]) throws UnknownHostException{
Vector<String> Available_Devices=new Vector<>();
String myip=InetAddress.getLocalHost().getHostAddress();
String mynetworkips=new String();
for(int i=myip.length();i>0;--i) {
if(myip.charAt(i-1)=='.'){ mynetworkips=myip.substring(0,i); break; }
}
System.out.println("My Device IP: " + myip+"\n");
System.out.println("Search log:");
for(int i=1;i<=254;++i){
try {
InetAddress addr=InetAddress.getByName(mynetworkips + new Integer(i).toString());
if (addr.isReachable(1000)){
System.out.println("Available: " + addr.getHostAddress());
Available_Devices.add(addr.getHostAddress());
}
else System.out.println("Not available: "+ addr.getHostAddress());
}catch (IOException ioex){}
}
System.out.println("\nAll Connected devices(" + Available_Devices.size() +"):");
for(int i=0;i<Available_Devices.size();++i) System.out.println(Available_Devices.get(i));
}
}

Can I filter and select only IPV4 adresses on the InetAddress object? How to exlude the IPV6?

I have the following problem: I create an ArrayList and I put in this arraylist all the IP addresses of my client (one if the client have a single network card, n if the client run on a PC having n network card) excluding the loopback adress, the point to point adress and the virtual adress.
I have do this in this way:
private static List<String> allIps = new ArrayList<String>();
static {
Enumeration<NetworkInterface> nets;
try {
nets = NetworkInterface.getNetworkInterfaces();
while(nets.hasMoreElements()) {
NetworkInterface current = nets.nextElement();
if ((current.isUp()) && (!current.isPointToPoint()) && (!current.isVirtual()) && (!current.isLoopback())) {
System.out.println(current.getName());
Enumeration<InetAddress> ee = current.getInetAddresses();
while (ee.hasMoreElements()) {
InetAddress i = ee.nextElement();
System.out.println(i.getHostAddress());
allIps.add(i.getHostAddress());
}
}
}
} catch (SocketException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("List of all IP on this client: "
+ allIps.toString());
System.out.println("Number of ip: " + allIps.size());
}
It seems work well, the only problem is that my output (in the Eclipse console) is:
eth0
fe80:0:0:0:20c:29ff:fe15:3dfe%2
192.168.15.135
List of all IP on this client: [fe80:0:0:0:20c:29ff:fe15:3dfe%2, 192.168.15.135]
Number of ip: 2
Using the debugger and the console output appear clear to me that, in this case, the only network interface present is eth0 (and this is ok) but, for this network interface, id found 2 IP adresses (the fits one is IPV6 address, the second one is the classic IPV4 address)
So it put in my adresses list allIps both.
I want select and put in my allIps list only the IPV4 adresses and not also the IPV6. What can I do to do it? Can I filter and select only IPV4 on my InetAddress object?
Tnx
Andrea
Use instanceof and the Inet4Address type:
for (NetworkInterface ni :
Collections.list(NetworkInterface.getNetworkInterfaces())) {
for (InetAddress address : Collections.list(ni.getInetAddresses())) {
if (address instanceof Inet4Address) {
System.out.println(address);
}
}
}

Java regex for accepting a valid hostname, IPv4, or IPv6 address

Does anyone have a good (preferably tested) regex for accepting only a valid DNS hostname, IPv4, or IPv6 address?
I understand that you may be forced to use a regex. However, if possible it is better to avoid using regexes for this task and use a Java library class to do the validation instead.
If you want to do validation and DNS lookup together, then InetAddress.getByName(String) is a good choice. This will cope with DNS, IPv4 and IPv6 in one go, and it returns you a neatly wrapped InetAddress instance that contains both the DNS name (if provided) and the IPv4 or IPv6 address.
If you just want to do a syntactic validation, then Apache commons has a couple of classes that should do the job: DomainValidator and InetAddressValidator.
Guava has a new class HostSpecifier. It will even validate that the host name (if it is a host name) ends in a valid "public suffix" (e.g., ".com", ".co.uk", etc.), based on the latest mozilla public suffix list. That's something you would NOT want to attempt with a hand-crafted regex!
As others have said, doing this with a regex is quite a challenge and not advisable. But it is easy to do with the IPAddress Java library which can parse host names, IPv4 and IPv6 addresses, without triggering DNS lookup. Disclaimer: I am the project manager of that library.
Sample code:
check("1.2.3.4");
check("::1");
check("a.b.com");
static void check(String hostStr) {
HostName host = new HostName(hostStr);
try {
host.validate(); // triggers exception for invalid
if(host.isAddress()) {
IPAddress address = host.asAddress();
System.out.println(address.getIPVersion() + " address: " + address);
} else {
System.out.println("host name: " + host);
}
} catch(HostNameException e) {
System.out.println(e.getMessage());
}
}
Output:
IPv4 address: 1.2.3.4
IPv6 address: ::1
host name: a.b.com
Inspired by the code I found in this post, I created the following validator method that seems to suit simple validation needs quite nicely. By reading the JavaDoc of URI I removed some false positives such as "host:80" and "hostname/page", but I cannot guarantee there are some false positives left.
public static boolean isValidHostNameSyntax(String candidateHost) {
if (candidateHost.contains("/")) {
return false;
}
try {
// WORKAROUND: add any scheme and port to make the resulting URI valid
return new URI("my://userinfo#" + candidateHost + ":80").getHost() != null;
} catch (URISyntaxException e) {
return false;
}
}
You can also do this. Let's say:
public boolean isHostnameValid(String hostname) {
try {
InetAddress.getAllByName(hostname); // throws an error when the hostnme could not be found, if so, then return false
return true;
} catch(Exception exc) {
return false;
}
}

How do you tell whether a string is an IP or a hostname

So you have a String that is retrieved from an admin web UI (so it is definitely a String). How can you find out whether this string is an IP address or a hostname in Java?
Update: I think I didn't make myself clear, I was more asking if there is anything in the Java SDK that I can use to distinguish between IPs and hostnames? Sorry for the confusion and thanks for everybody who took/will take the time to answer this.
You can use a regular expression with this pattern:
\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b
That will tell you if it's an IPv4 address.
Do we get to make the assumption that it is one or the other, and not something completely different? If so, I'd probably use a regex to see if it matched the "dotted quad" format.
You can see if the string matches the number.number.number.number format, for example:
\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b
will match anything from 0 - 999.
Anything else you can have it default to hostname.
URI validator = new URI(yourString);
That code will validate the IP address or Hostname. (It throws a malformed URI Exception if the string is invalid)
If you are trying to distinguish the two..then I miss read your question.
You can use a security manager with the InetAddress.getByName(addr) call.
If the addr is not a dotted quad, getByName will attempt to perform a connect to do the name lookup, which the security manager can capture as a checkConnect(addr, -1) call, resulting in a thrown SecurityException that you can catch.
You can use System.setSecurityManager() if you're running fully privileged to insert your custom security manager before the getByName call is made.
It is not as simple as it may appear, there are some ambiguities around characters like hyphens, underscore, and square brackets '-', '_', '[]'.
The Java SDK is has some limitations in this area. When using InetAddress.getByName it will go out onto the network to do a DNS name resolution and resolve the address, which is expensive and unnecessary if all you want is to detect host vs address. Also, if an address is written in a slightly different but valid format (common in IPv6) doing a string comparison on the results of InetAddress.getByName will not work.
The IPAddress Java library will do it. The javadoc is available at the link. Disclaimer: I am the project manager.
static void check(HostName host) {
try {
host.validate();
if(host.isAddress()) {
System.out.println("address: " + host.asAddress());
} else {
System.out.println("host name: " + host);
}
} catch(HostNameException e) {
System.out.println(e.getMessage());
}
}
public static void main(String[] args) {
HostName host = new HostName("1.2.3.4");
check(host);
host = new HostName("1.2.a.4");
check(host);
host = new HostName("::1");
check(host);
host = new HostName("[::1]");
check(host);
host = new HostName("1.2.?.4");
check(host);
}
Output:
address: 1.2.3.4
host name: 1.2.a.4
address: ::1
address: ::1
1.2.?.4 Host error: invalid character at index 4
Couldn't you just to a regexp match on it?
Use InetAddress#getAllByName(String hostOrIp) - if hostOrIp is an IP-address the result is an array with single InetAddress and it's .getHostAddress() returns the same string as hostOrIp.
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
public class IPvsHostTest {
private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(IPvsHostTest.class);
#org.junit.Test
public void checkHostValidity() {
Arrays.asList("10.10.10.10", "google.com").forEach( hostname -> isHost(hostname));
}
private void isHost(String ip){
try {
InetAddress[] ips = InetAddress.getAllByName(ip);
LOG.info("IP-addresses for {}", ip);
Arrays.asList(ips).forEach( ia -> {
LOG.info(ia.getHostAddress());
});
} catch (UnknownHostException e) {
LOG.error("Invalid hostname", e);
}
}
}
The output:
IP-addresses for 10.10.10.10
10.10.10.10
IP-addresses for google.com
64.233.164.100
64.233.164.138
64.233.164.139
64.233.164.113
64.233.164.102
64.233.164.101
This code still performs the DNS lookup if a host name is specified, but at least it skips the reverse lookup that may be performed with other approaches:
...
isDottedQuad("1.2.3.4");
isDottedQuad("google.com");
...
boolean isDottedQuad(String hostOrIP) throws UnknownHostException {
InetAddress inet = InetAddress.getByName(hostOrIP);
boolean b = inet.toString().startsWith("/");
System.out.println("Is " + hostOrIP + " dotted quad? " + b + " (" + inet.toString() + ")");
return b;
}
It generates this output:
Is 1.2.3.4 dotted quad? true (/1.2.3.4)
Is google.com dotted quad? false (google.com/172.217.12.238)
Do you think we can expect the toString() behavior to change anytime soon?

Categories