2014-07-15 87 views
2

我需要開發一個Java庫,它允許通過代理僅爲指定主機定向流量。Java在使用自定義ProxySelector時通過代理解析DNS

該庫幾乎準備就緒並正在運行,但是通過代理解析dns地址存在問題。

總而言之一句話我伸出CustomProxySelector類有以下邏輯:

public class CustomProxySelector extends ProxySelector { 

    public List<Proxy> select(URI uri) { 
    if (customProxyDefinedFor(uri)) { 
     return getCustomProxyFor(uri); 
    } else { 
     // use direct connection 
    } 
    } 
} 

所有工作正常,如果本地DNS能夠解決給定爲「URI」參數(如主機,如果我想stackoverflow.com通過去代理它將工作,因爲我的本地DNS可以解決stackoverflow.com)。

問題出現時,有一個主機,這是我的本地DNS不知道。例如,代理之後的dns知道如何解析像「host1.private.dmz」這樣的地址,因爲這是僅在代理之後已知的特殊主機(代理在這裏充當反向代理)。 JVM似乎第一次嘗試解決「host1.private.dmz」到IP,而當它失敗與如下因素堆棧跟蹤結束:

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) 
    (...) 

因爲它無法解析IP,是從來沒有使用過我的自定義的ProxySelector。有沒有任何選項強制java不通過localdns解析IP,而是通過代理?

如果我給host1.private.dmz的IP地址(例如10.100.12.13),所有工作正常。通信被定向到我的自定義代理選擇器,流量通過自定義代理而沒有問題。

回答

1

我解決了這個問題。解決這個問題的重要事情是正確的理解問題不在於jvm而是在應用程序中。在調用自定義代理選擇器之前,Jvm不會嘗試解析host1.private.dmz,而是應用程序本身。

如果我們看一下堆棧跟蹤的最後一行,可以看到這個異常來自mysql jdbc驅動程序,所以它是在嘗試將host1.private.dmz解析爲IP地址的mysql驅動程序之前,實際打開連接之前主辦。因此,因爲應用程序不打開連接(因爲應用程序嘗試解析dns時發生異常),所以不會調用代理選擇器(「no connection」==「no proxy selector」)。

在這種情況下我們能做些什麼?

如果是您編寫應用程序,則不要通過調用InetAddress.getAllByName()來解析IP,並直接打開與主機域名(host1.private.dmz)的連接。如果由於某種原因,您需要一個IP而不是處理異常(如果發生異常,請嘗試在不解析地址的情況下打開連接)。如果仍然不能接受,還有一個選擇。您可以指示jvm使用能夠解析此域的IP的額外DNS服務器。您可以通過設置以下屬性來執行此操作:

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); 

這應該爲您的應用程序設置額外的dns服務器。

然而,可以有一個更有問題的情況。嘗試將域名解析爲IP可能會在您有機會設置額外的dns服務器之前發生。例如,您可能正在Tomcat上運行Web應用程序,並在Tomcat的上下文中配置數據庫連接池。在這種情況下,在設置額外的dnses之前,可能會發生異常「UnknownHostException」。在這種情況下,您可以通過「代理它」運行此應用程序。嚴格在Java中,你可以通過運行帶有以下參數的應用做到這一點通過jProxyLoader庫(http://jproxyloader.sourceforge.net),例如:

-Djava.system.class.loader=net.sf.jproxyloader.JProxyLoader -DjplDnsServers=10.0.1.18 

上面的例子將設立10.0.1.18作爲額外的DNS服務器(這是能夠解決應用程序啓動時不知道的域名)。感謝這個額外的dns在應用程序啓動時已經可用。

通過查看jProxyLoader故障排除頁面,您可以更好地瞭解此問題:http://jproxyloader.sourceforge.net/troubleshooting.html