Clean DNS server in JVM - java

After my first post dealing with DNS,which is still not resolved: JVM and OS DNS Caching
,i am facing a new problem.
First here is my use case: i want to check if my private DNS is alive. If not i want to use a general DNS (e.g 8.8.8.8).
My private DNS (a bind9 on ubuntu with 192.168.1.188) as a specific record: test.testdnd.fr -> 192.168.1.100
So i thought i could do this:
if(InetAddress.getByAddress(my_dns_ip_in_byte).isReachable()){
System.setProperty("sun.net.spi.nameservice.provider.1", "dns,sun");
System.setProperty("sun.net.spi.nameservice.nameservers", 192.168.1.188);
}else{
System.setProperty("sun.net.spi.nameservice.provider.1", "dns,sun");
System.setProperty("sun.net.spi.nameservice.nameservers", "8.8.8.8");
}
InetAddress.getHostByAddress(test.testdnd.fr) -> unknow host exception
But if i only Do:
System.setProperty("sun.net.spi.nameservice.provider.1", "dns,sun");
System.setProperty("sun.net.spi.nameservice.nameservers", 192.168.1.188);
InetAddress.getHostByAddress(test.testdnd.fr) -> 192.168.1.100
So as soon as i called an InetAddress method before setting system.property, it seems that the system.property has no effect. Maybe because the JVM load the system DNS values when a InetAddress method is called even if it dont use DNS resolution.
Is that a standard behavior in the JVM or am i loosing something?
Any help is welcome,

The problem is that the nameservice providers are loaded only once in InetAddress and cached for further use. The loading happens in the static initializer of the class InetAddress. So once InetAddress is initialized, setting or changing the sun.net.spi.nameservice.provider properties will have no more effect.

The JVM only uses the DNS provider you set on lookups that fail using the system's default. You can see this in the documentation (http://docs.oracle.com/javase/7/docs/technotes/guides/net/properties.html), relevant excerpts:
By default, Java will use the system configured name lookup
mechanism
You can specify a comma separated list of IP addresses that point to the DNS servers you want to use
In JDK 7, providers are chained, which means that if a
lookup on a provider fails, the next provider in the list is consulted
to resolve the name.

Related

In Java 8, how do I get my hostname without hard-coding it in my environment?

We just upgraded to Java 8 on Amazon Linux. We are using Spring 4.3.8.RELEASE. It used to be that we could get our machine hostname by setting up beans in our application context file like so ...
<bean id="localhostInetAddress" class="java.net.InetAddress" factory-method="getLocalHost" />
<bean id="hostname" factory-bean="localhostInetAddress" factory-method="getHostName" />
But with Java 8, the bean "hostname" now contains the string
localhost
Before Java 8, it used to contain the "hostname" value as run on the command line, which is
[myuser#machine1 ~]$ hostname
machine1.mydomain.org
How can I reconfigure our bean so that it gets the hostname that the command line lists out? I don't want to hard-code anything anywhere.
From InetAddress java 8 is not getting the hostname :
There was similar bug fired in JDK.
What I understand is that they changed default resolution process.
They honor configuration in /etc/nsswitch.conf where hosts are configured for /etc/hosts that gives it main priority for name resolution.
Usually /etc/hosts has record for 127.0.0.1 localhost that provide name for host localhost
There are a similar question in the OpenJDK bugs
The newer calls respect the localhosts /etc/nsswitch.conf configuration files. In the case of this machine that file tells these
calls to look in files before referencing other naming services.
Since the /etc/hosts file contains an explicit mapping for this
hostname / IP combination, that is what is returned.
In the older JDK's the gethostbyname actually ignored the local
machines settings and immediately delegated to the naming service.
You can always use the Runtime class for that :
Process hostname = Runtime.getRuntime().exec("hostname");
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(hostname.getInputStream()));
String s;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
But it's not so recommended as you can see
I believe Java still calls the native gethostname(), but couldn't say why this fails.
For Linux, you could try this alternative:
String hostname = new String(Files.readAllBytes(Paths.get("/proc/sys/kernel/hostname")), StandardCharsets.US_ASCII);
You could try InetAddress.getCanonicalHostName()
The JavaDocs for getCanonicalHostName() says
Gets the fully qualified domain name for this IP address. Best effort method, meaning we may not be able to return the FQDN depending on the underlying system configuration.
You really have three options of differing complexity and information value:
Actually run the hostname command using Runtime. It's fairly portable and should work pretty much everywhere. (Maybe not on IBM's Mainframes)
Grab all available network interfaces and get their hostnames. https://docs.oracle.com/javase/tutorial/networking/nifs/listing.html
Set an environment or system property as the value of hostname.
Like java -Dmy.hostname=hostname ...
Sad part is that it's not that straightforward in Spring XML.
All other options are known to give varying degrees of accuracy.
Like 127.0.0.1 will likely resolve to localhost or localhost.localdomain.
Alternatively, you can run the hostname linux command using Java Runtime, code should be something like below:
String cmdResult="";
Runtime r = Runtime.getRuntime();
Process p = r.exec("hostname");
BufferedReader in = new BufferedReader(new
InputStreamReader(p.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
cmdResult += inputLine;
}
in.close();
Since my comment got lost in the stream, please try
<bean id="hostname" class="com.amazonaws.util.EC2MetadataUtils" factory-method="getLocalHostName()">
Have a look at Amazon's documemtation if the result does not suits your needs.
InetAddress in Java 8 had a bug regarding the resolution of hostname. The bug was reported in version 8u20 and has been fixed since then. Please check that you are not on this version. If not, then using InetAddress.getLocalHost().getHostName() will give you the hostname.
Also I suggest, setting up a static hostname on the AWS instance.
Update /etc/hosts
Update /etc/hostname
Run hostname to check the hostname
Reboot and check the persisted hostname
This should allow you to read the hostname from the file if required.
Also, if hostname command is giving the correct result, then use exec method in Runtime class to execute the command and the read the InputStream to get the response.
PS: You can use InetAddress.getLocalHost().isLoopbackAddress() to check whether the address is a LoopbackAddress and then use a fallback method.
I can be better to define a property in your .properties file for hostname like.
hostname=myserver.mydomain.com
And use it in your application. This way is not harcoded. It also avoid dependency to operating system config which can be changed without attention.

Does JVM cache url because of networkaddress.cache.ttl setting?

Oracle's documentation says following about cache ttl -
networkaddress.cache.ttl
Specified in java.security to indicate the caching policy for successful name lookups from the name service.. The value is specified as integer to indicate the number of seconds to cache the successful lookup.
How does this setting impact the way DNS gets resolved? I have two nodes behind geo load balancer to which I connect for a service. Now, if they switch to point to other two nodes and if the above setting is set to -1, would it still attempt to the earlier resolved DNS and attempt to go to the node that probably no longer exist? If I do not use security manager in that case does this setting have any value?
Thanks in advance.
Default behaviour of JVM is to cache forever(setting -1) if security manager is installed. So you have to explicitly set the ttl timeout so that reattempt for DNS resolution happens. You may set this property via security manager in your application startup (app level) or system level.
java.security.Security.setProperty("networkaddress.cache.ttl" , "10");
For system wide edit below file to include ttl to zero.
<JAVA_HOME>/jre/lib/security/java.security
networkaddress.cache.ttl=0
Without security manager:
Usually default value depends os & jvm type. AWS uses 60sec, Refer this
PS: System level settings always override app level settings.

Error connecting to Oracle database using JDBC [duplicate]

I am new to Oracle, and am trying to run a simple example code with Java, but am getting this error when executing the code.. I am able to start up the listener via CMD and am also able to run SQL Plus. Can anyone give me a hand and tell me what I might be doing wrong?
Update:
I am using JDBC.
Database is local, and I actually had it working but it stopped working just today. I'm not really sure why though. Would you mind giving me some procedures to follow by since I don't know much.
Either:
The database isn't running
You got the URL wrong
There is a firewall in the way.
(This strange error message is produced by Oracle's JDBC driver when it can't connect to the database server. 'Network adapter' appears to refer to some component of their code, which isn't very useful. Real network adapters (NICs) don't establish connections at all: TCP protocol stacks do that. It would have been a lot more useful if they had just let the original ConnectException be thrown, or at least used its error message and let it appear in the stack trace.)
I had the same problem, and this is how I fixed it.
I was using the wrong port for my connection.
private final String DB_URL = "jdbc:oracle:thin:#localhost:1521:orcll"; // 1521 my wrong port
go to your localhost
(my localhost address) : https://localhost:1158/em
login
user name
password
connect as --> normal
Below 'General' click on LISTENER_localhost
look at you port number
Net Address (ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1522))
Connect to port 1522
Edit you connection
change port 1521 to 1522.
done
Another thing you might want to check that the listener.ora file matches the way you are trying to connect to the DB. If you were connecting via a localhost reference and your listener.ora file got changed from:
HOST = localhost
to
HOST = 192.168.XX.XX
then this can cause the error that you had unless you update your hosts file to accommodate for this. Someone might have made this change to allow for remote connections to the DB from other machines.
I figured out that in my case, my database was in different subnet than the subnet from where i was trying to access the db.
I had this error when i renamed the pc in the windows-properties. The pc-name must be updated in the listener.ora-file
Most probably you have listener configured wrongly, the hostname you specify in connection string must be the same as in the listener.
First check the Firewall and network related issues.
Check if Oracle Listener service is available and running. If not you may use Oracle Net Configuration Assistant tool to add and register new listener.
If the above steps are ok then you need to configure Oracle Listener appropriately. You may use Oracle Net Manager tool or edit “%ORACLE_HOME%\network\admin\listener.ora” file manually.
There are 2 options that need to be considered carefully:
Listening Locations associated with the Listener – Hostname(IP) and Port in Listening Location must exactly match the ones used in the connection string.
For example, if you use 192.168.74.139 as target hostname, then there must be Listening Location registered with the same IP address.
Also make sure the you use the same SID as indicated in Database Service associated with the Listener.
https://adhoctuts.com/fix-oracle-io-error-the-network-adapter-could-not-establish-the-connection-error/
IO Error: The Network Adapter could not establish the connection (CONNECTION_ID=iKQM6lBbSLiArrYuDqud8A==)
if you are facing this issue
1- make sure you have downloaded oracle databases like oracle 11g,19c, 21c, or any latest databases.
2- search for services in your computer or type win+r then services.mis then search for oracleservice you will find orcl or xe or any other sid like oracleserviceorcl;
after that you can test your connection using sql developer, sql plus or cmd
To resolve the Network Adapter Error I had to remove the - in the name of the computer name.
In my case, I needed to specify a viahost and viauser. Worth trying if you're in a complex system. :)
For me the basic oracle only was not installed. Please ensure you have oracle installed and then try checking host and port.
I was having issues with this as well. I was using the jdbc connection string to connect to the database. The hostname was incorrectly configured in the string. I am using Mac, and the same string was being used on Windows machines without an issue. On my connection string, I had to make sure that I had the full url with the appending "organizationname.com" to the end of the hostname.
Hope this helps.
Just try to re-create connection. In my situation one of jdbc connection stopped working for no reason. From console sqlplus was working ok.
It took me 2 hours to realize that If i create the same connection - it works.

Choose DNS server for resolving hostnames in Java

resolving a hostname to an IP address is rather easy in Java by using the InetAddress class like this:
InetAddress address = InetAddress.getByName("www.example.com");
But this method uses the DNS server which is used by the running system.
Is there any way to specify the DNS server that should be used for resolving?
If you use Sun Java, you can use this code:
//Override system DNS setting with Google free DNS server
System.setProperty("sun.net.spi.nameservice.nameservers", "8.8.8.8");
System.setProperty("sun.net.spi.nameservice.provider.1", "dns,sun");
See this blog post: How to set a custom DNS server with Java System properties for more details.

What parameters for an NTLM authentication can be automatized , and how to do it with java?

I want to know what parameters can be automatized out of the 6 used during an NTLM authentication, which are:
"Username" - The one used to login on the Operating System's profile currently in use. -Already automatized, using System.getProperty("user.name")
"Password" - Same as the above. -Probably can't be automated, but i'm never sure till i try and ask...
"ProxyAddress" - Address of the proxy, to which the authentication is "handshaked to" in order to pass. -I already pseudo-automatized, but its fixed code, thus bad.
"ProxyPort" - The listening port on the proxy previously explained. -I already pseudo-automatized, but its fixed code, thus bad.
"Workstation" - My PC's ID in the local network or something...I'm currently using my machine's property ID, and its working, but i have no idea if its the correct value, or if there is a need for a value in the first place. -No idea how to automatize, but i know it's possible. NEED HELP
"Domain" - No idea which domain it refers to, thus no idea what value it should have...leaving it blank seems to be working... -No idea how to automatize, but i know it's possible. NEED HELP
EXTRA INFO: I'm using the HtmlClient library for the process, including authentication.
DefaultCredentialsProvider credentialProvider = (DefaultCredentialsProvider) webClient.getCredentialsProvider();
credentialProvider.addNTLMCredentials(username, password, proxyAddress, proxyPort, workstation, domain);
webClient.setUseInsecureSSL(true);
I'm sort of assuming that you're talking about Apache HTTPClient and HTLMUnit, but I'm basing that assumption off the method signatures in the code you provided, so I apologize if I'm mistaken.
For NTLM, this is the remote username, not necessarily the currently logged in user on the local host. I suspect that these are the same user in your scenario, but I did want to point that out. In that case, yes, using the user.name system property will provide the name of the currently logged in user:
System.getProperty("user.name");
on Windows, you can also use the USERNAME environment variable:
System.getEnv("USERNAME");
or you could use the com.sun.security.auth.module.NTSystem class:
new NTSystem.getName();
You cannot get the user's password. However, you may still be able to perform single signon where the user does not need to provide a password (more on that below.)
The Java mechanism for specifying HTTP proxies is using the http.proxyHost system property:
String proxyHost = System.getProperty("http.proxyHost");
Note that you should also check the http.nonProxyHosts system property.
Some JREs (Mac OS comes to mind immediately) will set these system properties based on the system proxy settings. If this is not set by your JRE, you will probably want to try to determine the proxy from another source. On Unix systems, you may wish to use the HTTP_PROXY environment variable. On Windows systems, you're likely best off using the ProxySelector class, as explained in this stackoverflow post.
Similar to the http.proxyHost system property, the Java mechanism is with the http.proxyPort system property:
int proxyPort = Integer.parseInt(System.getProperty("http.proxyPort"));
To reliably get your hostname on Unix, you should really call gethostname(2) via JNI or exec /usr/bin/hostname, unfortunately. On Windows, you may use the COMPUTERNAME environment variable:
System.getEnv("COMPUTERNAME");
You can get the domain name that the local machine is joined to, however (short of prompting the user), there's no way to automatically get the domain name of the machine you're authenticating to. Of course this is moot if your local workstation and the authentication target are on the same domain. Thus, on Windows, you can either use the USERDOMAIN environment variable:
System.getEnv("USERDOMAIN");
or you can use the NTSystem class:
new NTSystem().getDomain();
Whew.
As for implementing "single signon" (such that the user need not provide a password):
You may be able to perform single signon (without needing a password) by using the Java Kerberos functionality, however I was unsuccessful in this because Java requires explicit Kerberos configuration (and does not use the host's configuration) and it does not implement some ciphers required by Active Directory. (Or that's my understanding.)
You could also perform single signon with NTLM or SPNEGO (Kerberos) by using JNI to call InitializeSecurityContext and pass the resulting tokens in the WWW-Authenticate header.

Categories

Resources