I have the following code:
import java.net.InetAddress;
public class lookup {
public static void main(String[] args) throws Exception {
for(String host : args){
for(InetAddress addr : InetAddress.getAllByName(host)){
System.out.println(addr.getHostAddress());
}
}
}
}
We recently changed the CNAME for a host we'll call foo.example.com from pointing at bar.example.com to point at baz.example.com. If I run:
java -Djava.net.preferIPv4Stack=true lookup foo.example.com
I get baz.example.com's ip address, as expected. However if I run:
java lookup foo.example.com
I still get bar.example.com's ip address.
I've confirmed that neither bar.example.com nor baz.example.com have AAAA records. dig and ping both resolve baz.example.com as expected. How do I get java's ipv6 stack to properly resolve this?
The problem was nscd was running and had cached the records. Why it didn't respect the TTLs and why ping doesn't use the cache are still a mystery.
Hmm, there's something a bit odd going on here. I suspect it might have something to do with DNS caching the domain name lookups performed. Modify the following properties in:
java.home/lib/security/java.security
and see whether this resolves the issue:
networkaddress.cache.ttl: 10
networkaddress.cache.negative.ttl: 10
A value of -1 (the default for networkaddress.cache) indicates "cache forever" which might be causing what you see above.
Could it be that your operating system is aware of two different DNS servers, one reachable by IPv4, the other reachable by and preferred for IPv6 and that the IPv6 preferred DNS server is still caching the old configuration?
Related
I'm trying to remote-debug a yajsw-wrapped application with JDK>=9.
Timeout issues aside, tt works fine with below config:
wrapper.java.additional.2.1=-Xdebug
wrapper.java.additional.2.2=-Xrunjdwp:transport=dt_socket\,server=y\,suspend=y\,address=*:8888
However I'm having issues (can't attach remote-debugger) with the assumedly equivalent below config:
wrapper.java.debug.port=*:8888
Note1: For JDK>=9, the IP address or hostname needs to be provided in front of the port # otherwise only local connections are accepted (hence the "*:" prefix)
Note2: "wrapper.java.debug.port" option will also set friendly timeout values to allow the end-user to remote-debug without having to worry about timeout issues which is why I'm eager to use it.
Is there any way to do remote-debugging by using "wrapper.java.debug.port" option with JDK>=9 ?
Thank you very much in advance for your feedback.
Best Regards
as of yajsw 12.14, after looking at the source-code, it doesn't seem possible to use wrapper.java.debug.port option to refer to a different hostname:
WrappedJavaProcess.java extract:
int port = _config.getInt("wrapper.java.debug.port", -1);
if (port != -1)
{
result.add("-Xdebug");
result.add("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address="
+ port);
}
As for timeout values, to obtain the same effect as "wrapper.java.debug.port", set following 3 values to a large number: "wrapper.startup.timeout", "wrapper.shutdown.timeout" & "wrapper.ping.timeout"
If I am not wrong, one can connect to a Cassandra cluster knowing at least one of the nodes that is in the cluster, and then the others can be discovered.
Lets say I have three nodes (1, 2 and 3) and I connect to those nodes like this:
Cluster.builder().addContactPoints("1,2,3".split(",")).build();
Then, if node 3 for example goes down, and the IP cannot be resolved, this line of code will throw an IllegalArgumentException as stated in the docs:
#throws IllegalArgumentException if no IP address for at least one of {#code addresses} could be found
Why would anyone want this behavior? I mean, if one of the nodes is down, I want the app to be able to run, as the Cassandra is still working fine.
I have checked this Cassandra Java driver: how many contact points is reasonable?
but that does not answer my question as it doesn't say anything about hosts than can't be reachable.
How should I handle this? Maybe this is changed in another version of the java driver? I am currently using cassandra-driver-core-3.0.3
This validation is only to make sure that all the provided hosts can be resolved, it doesn't even check if a Cassandra server is running on each host. So it is basically to ensure that you did not do any typos while providing the hosts as indeed it doesn't assume that it could be a normal use case to have a provided host that cannot be resolved.
As workaround in your case (host been removed from the DNS entries), you could simply call the method addContactPoint(String address) explicitly instead of using addContactPoints(String... addresses) (which behind the scene simply call addContactPoint(String address) for each provided address) and manage the exception by yourself.
The code could be something like this:
Cluster.Builder builder = Cluster.builder();
// Boolean used to check if at least one host could be resolved
boolean found = false;
for (String address : "1,2,3".split(",")) {
try {
builder.addContactPoint(address);
// One host could be resolved
found = true;
} catch (IllegalArgumentException e) {
// This host could not be resolved so we log a message and keep going
Log.log(
Level.WARNING,
String.format("The host '%s' is unknown so it will be ignored", address)
);
}
}
if (!found) {
// No host could be resolved so we throw an exception
throw new IllegalStateException("All provided hosts are unknown");
}
Cluster cluster = builder.build();
FYI: I've just created a ticket to propose an improvement in the Java driver https://datastax-oss.atlassian.net/browse/JAVA-1334.
As Nick mentioned, it's based on DNS resolution, not Cassandra server health.
If you remove hosts from your environment more often than you recompile your application, then you should consider not baking your contact points into the code, and instead, feed them in through some other means (environment variable, REST service, a single DNS name that always resolves to one live seed, etc).
The documentation there is just in regards to "resolving" the contact points that are passed in. So converting hostnames to ip addresses. If you are specifying ip addresses to begin with, they will not be resolved, simply checked for validity. If you are using hostnames then each contact point will need to be resolvable. This doesn't mean that the cassandra machine needs to be running, just that a DNS lookup on the hostname returns any ip address. So the case where things would break would be if you removed a DNS entry for one of your contact points and restarted your application.
I have the following little code snippet:
InetAddress address = InetAddress.getByName(host);
if(address.isReachable(TIMEOUT_IN_MILLISECONDS)) {
System.out.println(host + " is reachable.");
String hostName = address.getHostName();
System.out.println(hostName);
}
The getHostName() method is taking quite some time to execute if a machine has been found. Could someone please explain why?
From the InetAddress#getHostName() javadocs, that method will perform a reverse hostname lookup. So the performance of that method call depends on the performance of the network/technology stack between the JVM and the domain name server for the target host.
In brief, that method will make a system call to perform the reverse lookup (e.g. getaddrinfo(3)) and that call will be implemented by the operating system to perform the network actions required to gather the host information via the Name Server configured for your machine.
Some of the addresses need longer time to be resolved. InetAddress has a cache to store successful and unsuccessful resolutions. Also, make a threadpool. You can improve the performance
toString() seems to be faster:
given an InetAddress ia or InterfaceAddress ia,
System.out.println ( ia.toString() ) will show a string containing your ipAddress faster than ia.getHostName()
You can then use ia.toString().substring to extract it.
I don't know why.
Here is some code to determine the local host name that is supposed to work on a multi-homed box:
/**
* Work out the first local host name by iterating the network interfaces
*
* #return
* #throws SocketException
*/
private String findFirstLocalHostName() throws SocketException {
Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
while (ifaces.hasMoreElements()) {
NetworkInterface iface = ifaces.nextElement();
Enumeration<InetAddress> addresses = iface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress add = addresses.nextElement();
if (!add.isLoopbackAddress() && add.isSiteLocalAddress()) {
return add.getHostName();
}
}
}
throw new RuntimeException("Failed to determine local hostname");
}
Does the call to isSiteLocalAddress introduce a bug? I can't find any useful information about this method, but I have a feeling that it relates to IP v 6 only and is deprecated.
The method is definitely not deprecated and it's definitely not just used in IPv6.
In IPv4 there are 3 network address ranges that are defined for site-local addresses: 10/8, 172.16/12 and 192.168/16.
Reading Inet4Address.isSiteLocalAddress() shows that addresses from exactly those 3 networks will return true on those methods.
IPv6 has a similar concept, here these addresses are called unique local addresses.
Effectively this tells you if the address you have is definitely not a public one (note that even if this method returns false, the address might still not be public).
Looking at the implementation...
For an Inet4Address, it checks to see if it's one of the RFC1918 "unrouteable" addresses: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16.
For an Inet6Address, it checks the first two octets to see if it's a real "site local" address.
'Site local' is a deprecated name for private IP space. (Some nuances, but basically right.) See RFC 1918.
I just came across what I believe is a similar problem: trying to determine what IPv6 I should use for LAN comuncation:
IMHO, Inet6Address.isSiteLocalAddress() is useless. Given that the 0xFEC0 prefix has been depricated by RFC 3879 as #tigz mentioned. I have yet to see any device (android, win, osx) actually have a 0xFEC0 (with limited testing)
//from java.net.Inet6Address (1.8.0_45)
boolean isSiteLocalAddress() {
return ((ipaddress[0] & 0xff) == 0xfe
&& (ipaddress[1] & 0xc0) == 0xc0);
}
0xFE80 address although not supposed be used for traffic (from my understanding and reading (www.cisco.com)) did work for LAN communication with my single router (ping6, curl, http).
My Global Unicast (which is just another name for public IP) 2601::/20 from Comcast worked for my LAN communication. So I would say that this is the correct address to use.
Prefix table: www.iana.org
As far as I know the isSiteLocalAddress method is not deprecated.
isSiteLocalAddress - Explanation
indicating if the InetAddress is a site local address; or false if address is not a site local unicast address.
The InetAddress even have two direct subclasses;
Inet4Address and
Inet6Address
The best bet is to read the JavaDocs.
Which version of the JDK are you using?
I would like the fastest and most accurate function boolean isReachable(String host, int port) that passes the following JUnit tests under the conditions below. Timeout values are specified by the JUnit test itself, and may be considered "unreachable."
Please note: All answers must be platform-independent. This means that InetAddress.isReachable(int timeout) is not going to work, since it relies on port 7 to do a ping on Windows (ICMP ping being an undocumented function on Windows), and this port is blocked in this setup.
LAN Setup:
thisMachine (192.168.0.100)
otherMachine (192.168.0.200)
no machine is called noMachine or has the IP 192.168.0.222 (always unreachable)
both machines are running Apache Tomcat on port 8080; all other ports are unreachable (including port 7)
example.com (208.77.188.166) is running a webserver on port 80 and is only reachable when the LAN is connected to the Internet
Occasionally, the LAN is disconnected from the Internet in which case only local machines called by IP address are reachable (all others are unreachable; there's no DNS).
All tests are run on thisMachine.
#Test(timeout=1600) // ~320ms per call (should be possible to do better)
public void testLocalhost() {
// We can always reach ourselves.
assertTrue(isReachable("localhost", 8080));
assertTrue(isReachable("127.0.0.1", 8080));
assertTrue(isReachable("thisMachine", 8080)); // Even if there's no DNS!
assertTrue(isReachable("192.168.0.100", 8080));
assertFalse(isReachable("localhost", 80)); // Nothing on that port.
}
#Test(timeout=5500) // ~1867ms per call (should be able to do better)
public void testLAN() {
assertTrue(isReachable("192.168.0.200", 8080)); // Always connected to the LAN.
assertFalse(isReachable("192.168.0.222", 8080)); // No such a machine.
assertFalse(isReachable("noMachine", 8080)); // No such machine.
}
The following test is only run when the LAN is disconnected from the Internet.
#Test(timeout=5600) // ~1867ms per call (reasonable?)
public void testNoDNS() {
assertFalse(isReachable("otherMachine", 8080)); // No DNS.
assertFalse(isReachable("example.com", 80)); // No DNS & no Internet.
assertFalse(isReachable("208.77.188.166", 80)); // No Internet.
}
The following test is only run when the LAN is connected to the Internet.
#Test(timeout=5600) // ~1867ms per call (reasonable?)
public void testHaveDNS() {
assertTrue(isReachable("otherMachine", 8080)); // DNS resolves local names.
assertTrue(isReachable("example.com", 80)); // DNS available.
assertTrue(isReachable("208.77.188.166", 80)); // Internet available.
}
Firstly you need to recognise that you have potentially conflicting requirements; IP sockets are not time deterministic. The quickest you can ever detect unreachability is after your elapsed timeout. You can only detect reachability quicker.
Assuming reachability/isReachable is your real objective, you should just use a straightforward non-blocking socket IO as shown in the Java Ping simulator, the example connects to the time service but would work equally well on 8080.
If you want to test whether you can connect to a web server you could also create a URL based on the host name and the port number and use that to create a URLConnection checking the result (including exceptions) of the connect method should tell you whether the webserver is reachable.
Not sure how practical this is.
How about doing the equivalent of traceroute(tracert on windows) and once you get a success, you can proceed.
In corporate networks, I've seen ICMP(ping) blocked by admins BUT usually, tracert still works. If you can figure out a quick way to do what tracert does, that should do the trick ?
Good luck!
My most recent solution depends using a TimedSocket (source code) with 3000ms timeout while performing a connect.
Timings:
1406ms : testLocalHost()
5280ms : testLAN()
Can't even get these to work properly:
testNoDNS()
testHaveDNS()
If you need to do this with a seriously large number of hosts in a very brief period of time, I'd consider using a tool like fping instead- shell out to exec it and parse the output when it comes back. fping runs a large number of parallel queries at once, so you could theoretically check a few thousand hosts in a minute (I think the limit is 4096?)
The rate determining step for host availability is not within your own code, but in the netlag. You must wait for the host to respond, and this can take time. If your program blocks while waiting for a response it could be a problem. I got around this by creating each host as an object, each with its own threaded method for checking availability. In my own situation I have 40 hosts I keep track of. My main program loops through an array of 40 machine objects once every 20 seconds, calling the appropriate method on each to check availability. Since each machine object spawns its own thread to do this, all 40 machines are interrogated concurrently and the (up to 500ms) response time for each isn't a problem.