Java resolve dns via proxy when using custom ProxySelector - java

I'm in need to develop a java library which allows a traffic to be directed via proxy only for specified hosts.
The library is almost ready and working, but there is problem with resolving dns addresses via proxy.
In short words I extended CustomProxySelector class which has following logic:
public class CustomProxySelector extends ProxySelector {
public List<Proxy> select(URI uri) {
if (customProxyDefinedFor(uri)) {
return getCustomProxyFor(uri);
} else {
// use direct connection
}
}
}
All works fine if local dns can resolve host given as "uri" parameter (for example if I want stackoverflow.com to go via proxy it will work because my local dns can resolve stackoverflow.com).
The problem comes when there is a host which is not known to my local dns. For example the dns behind proxy knows how to resolve address like "host1.private.dmz" because this is special host only known behind proxy (the proxy acts really as reverse proxy here). JVM seems to first try to resolve "host1.private.dmz" to ip, and when it fails it ends with folowing stacktrace:
Caused by: java.net.UnknownHostException: host1.private.dmz
at java.net.InetAddress.getAllByName0(InetAddress.java:1259)
at java.net.InetAddress.getAllByName(InetAddress.java:1171)
at java.net.InetAddress.getAllByName(InetAddress.java:1105)
at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:247)
(...)
Because it fails to resolve the ip, my Custom ProxySelector is never used. Is there any option to force java not to resolve ip via localdns but via proxy?
If I give the ip address of host1.private.dmz (for example 10.100.12.13) all works ok. The communication is directed to my Custom Proxy Selector and the traffic goes via custom proxy without problem.

I solved this issue. The important thing to fix this problem is correct understanding that the problem does not lay in jvm but in application. Jvm does not try to resolve host1.private.dmz before calling custom proxy selector, it is the application itself.
If we have a look at last line of the stacktrace you can see that exception comes from mysql jdbc driver, so it is mysql driver who trys to resolve host1.private.dmz to IP address, before actually opening connection to that host. Therefore because application does not open a connection (because exception occurs when application trys to resolve dns), no proxy selector is called ("no connection" == "no proxy selector").
What can we do in such case?
If it is you who writes the application, simply don't resolve the IP by calling InetAddress.getAllByName() and directly open connection to host domain name (host1.private.dmz). If for some reason you need an IP than handle the exception (in case of exception try to open connection without resolving the address). If still this is not acceptable for you there is one more option. You can instruct jvm to use extra DNS server which is able to resolve IP of this domain. You can do this by setting following properties:
System.setProperty("sun.net.spi.nameservice.provider.1", "dns,sun");
System.setProperty("sun.net.spi.nameservice.nameservers", "10.200.2.3,100.40.70.5);
This should set extra dns server for your application.
There can however be one more problematic situation. An attempt to resolve domain name to ip might take place before you have the chance to set up extra dns servers. For example you might be running web application on Tomcat with database connection pool configured in Tomcat's context. In such case the exception "UnknownHostException" can happen before you set up extra dnses. In such case you can run this application by "proxifying it". Strictly in java you can do this by using jProxyLoader library (http://jproxyloader.sourceforge.net) , for example by running the application with following parameters:
-Djava.system.class.loader=net.sf.jproxyloader.JProxyLoader -DjplDnsServers=10.0.1.18
Above example will set up 10.0.1.18 as extra dns server (which is able to resolve the uknown domain name) at application startup. Thanks to this extra dns will already be available when application boots up.
You understand more about this problem, by having a look at jProxyLoader troubleshooting page: http://jproxyloader.sourceforge.net/troubleshooting.html

Related

How to specify gRPC server address target on client side when the service is on format <my-service:port>

We are using grpc spring boot starter on our Java application service in order to establish a connection to another 'server' service, so I define in the application.properties the following address:
grpc.client.name.address=static://service-name:port
When tried to connect it I got the following error message:
StatusRuntimeException: UNAVAILABLE: io exception
So I know for sure I have a connectivity issue. On the documentation it says regarding the static scheme:
A simple static list of IPs (both v4 and v6), that can be use connect to the server
So I guess this is not what I need to use. It seems the best option in my case is using the discovery scheme, but it doesn't contains any port...
What is the right scheme configuration I need to use to set the server address?
Wanted to share the resolution for this very annoying issue for those who will encounter the same problem in the future like I did.
So first, the scheme needs to be set indeed of dns type, like the following: grpc.client._name_.address=dns:///<service-name>:26502
but this alone is not enough. (at least in my case) The server was configured to run in PLAINTEXT, while my client, by default, was configured to run with TLS mode, so it must be set with grpc.client.__name__.negotiationType=PLAINTEXT property.
See the following documentation for further information
It caused by gRPC can't resolve addresss service-name:port;
If you use static, the value must be ip:port; The service-name need to be resolved as ip address;
If you are using register center like consul or eureka etc., you should use discovery:///service-name without specify port.
If you didn't use register center, only end to end with server, replace service-name as a ip like 127.0.0.1 which belong to server;
Or modify host config for parse service-name like below, the file on Linux is /etc/hosts
127.0.0.1 service-name

Spring boot RabbitMQ Host string format

I am using spring boot to listen for messages on my rabbitmq instance. I have it working locally using an application.properties file.
However, when I want to connect to the remote rabbit instance I am getting number format exceptions and unknown host exceptions because of my url.
I've tried setting spring.rabbitmq.host to:
amqp://myurl/dev and myurl/dev and amqp%3A%2F%2Fmyurl%2Fdev
Nothing is working. Any ideas what could be up. I have set my user name and pass for the remote instance as well.
Try removing the amqp:// part. The host property should just be that, the hostname:
spring.rabbitmq.host=myurl
Not sure what the /dev part is. Are you saying that is your virtual-host? If so then just set this property too:
spring.rabbitmq.virtual-host=dev
For username/password, set these properties:
spring.rabbitmq.username=
spring.rabbitmq.password=
A better way to do this is to set
spring.rabbitmq.addresses=amqps://user:password#10.0.0.123/virtualhost
This will get auto-resolved, and correctly set your hostname, password etc
Github issue that fixes this:
https://github.com/spring-projects/spring-boot/issues/6401

dnsjava can't resolve "localhost" on Linux machine

After I registered dnsjava as default Java DNS provider I get a problem. It can't resolve local addresses which described in /etc/hosts file on my Linux machine. This file look something like this:
127.0.0.1 localhost
127.0.1.1 servername
So if I try to resolve one of such names UnknownHostException happens:
org.xbill.DNS.Address.getByName("localhost");
org.xbill.DNS.Address.getByName("servername");
It's not a problem when you're using dnsjava along with default dns provider. Being a sole provider, dnsjava causes lots of errors in default libraries, which turn out to be highly dependent on localhost resolution capability. So, the question is: how to change behavior of dnsjava to resolve local hostnames?
Edit. Next code works fine:
java.net.InetAddress.getByName("localhost");
But java.net.InetAddress.getLocalHost() method throws:
java.net.UnknownHostException: servername
dnsjava is a DNS client library; it talks to DNS servers. /etc/hosts is not part of the DNS protocol nor does dnsjava know anything about it.
See this old post on a the dnsjava users mailing list from the guy who wrote it: http://old.nabble.com/DNS-Resolve-from-hosts-file-first-then-DNS-Server-td15431381.html
Nothing has changed in that regard.
If java.net.InetAddress.getByName() is working, then your DNS server is configured to respond to queries for localhost.

JMX Spring connect to localhost without specifying the server address and port

I am referring here
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/jmx.html#jmx-proxy
I am trying to connect to localhost MBeanServer and perform some operation using Spring Proxy.
The problem is just specifying the ObjectName and ProxyInterface, I am unable to connect to localhost. I am able to solve this problem by specifying the server property of the MBeanProxyFactoryBean.
Here is my spring context.xml
bean id="proxyWithoutServer" class="org.springframework.jmx.access.MBeanProxyFactoryBean"
p:objectName="com.xxx.yyy"
p:proxyInterface="com.MyInterface"
bean id="proxyWithServer" class="org.springframework.jmx.access.MBeanProxyFactoryBean"
p:objectName="com.xxx.yyy"
p:proxyInterface="com.MyInterface"
p:server-ref="clientConnector"
<bean id="clientConnector" class="org.springframework.jmx.support.MBeanServerConnectionFactoryBean"
p:serviceUrl="service:jmx:rmi://localhost/jndi/rmi://localhost:8001/jmxrmi" />
In Java code, I simply do
MyInterface myInterface = context.getBean("proxyWithoutServer");
myInterface.myMethod();
But this doesnt work. - Says Unable to connect to localhost
But If I use
MyInterface myInterface = context.getBean("proxyWithServer");
myInterface.myMethod();
This works.
The problem here is that this code would be run on multiple servers and the jmx port in each would be different. SO I would not want to specify the port number. Hence I would like
the proxyWithoutServer version of this to work.
Looking at the spring jmx documentation it seems we do not need to specify the server port if we are trying to connect to local MBean Server.
Would need some advice on what I am doing wrong here.
Thanks in advance
Create a local reference to the MBeanServer.
<context:mbean-server id="localMBeanServer"/>
Then use localMBeanServer in the p:server-ref.

Issue while connecting to remote weblogic server over proxy

I have configured a proxy in my java source code as:
systemSettings.put("http.proxyHost", "www.proxyserver.com");
systemSettings.put("http.proxyPort", "8080");
systemSettings.put("http.nonProxyHosts", "10.x.y.z");
Here 10.x.y.z is the actual IP of my weblogic server.
But whenever code tried to connect to weblogic server, I receive error as:
Caused by: java.net.ConnectException: t3://10.x.y.z:7001: Destination
unreachable; nested exception is: java.net.ProtocolException:
unrecognized response from proxy: 'HTTP/1.0 403 Forbidden'; No
available router to destination at
weblogic.rjvm.RJVMFinder.findOrCreateInternal(RJVMFinder.java:216) at
weblogic.rjvm.RJVMFinder.findOrCreate(RJVMFinder.java:170) at
weblogic.rjvm.ServerURL.findOrCreateRJVM(ServerURL.java:153) at
weblogic.jndi.WLInitialContextFactoryDelegate$1.run(WLInitialContextFactoryDelegate.java:345)
at
weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:363)
at
weblogic.security.service.SecurityManager.runAs(SecurityManager.java:146)
at
weblogic.jndi.WLInitialContextFactoryDelegate.getInitialContext(WLInitialContextFactoryDelegate.java:340)
It seems that setting http.nonProxyHosts is not working as expected. I tried to find solution over the Internet, but most of them says remove proxy settings. I can not remove proxy, as my code tries to connect to some of the Internet URLs. Also note that, weblogic server is on remote machine.
Can you please give me a hint, what must be the issue here?
Have a look at this OTN thread.
From 3rd comment :
You are setting nonProxyHosts, which doesn't exist as a system property, via System.setProperties().
I haven't read all so far, but it seems the system.properties is not the convenient way to set
nonProxyHosts.
Did you tried to set it from command line ?
-Dhttp.nonProxyHosts="*.foo.com|localhost".
I resolved the issue. I had setup the proxy initially when connection with weblogic was setup. So due to some network restrictions I believe it didnt work. In modified code, I used the same 3 lines to setup proxy:
System.setProperty("java.net.useSystemProxies", "false");
System.setProperty("http.proxyHost", "www.proxyserver.com");
System.setProperty("http.proxyPort", "8080");
The only difference is, I did it at exact place where I needed. So for initial connection setup with weblogic proxy wont be used. I also did not have to bypass, weblogic server URL to not to use proxy.
#Arcadien: I appreciate your efforts to help me. Thanks.

Categories