Java內部DNS查詢實現和參數設置


一、Java內部DNS查詢

Java使用域名查詢時,用的自己內部的域名實現機制,最后都是交給InetAddress去做DNS解析。

源碼分析參考:http://blog.arganzheng.me/posts/java-dns-lookup-internal.html

//域名查詢
String dottedQuadIpAddress = InetAddress.getByName( "blog.arganzheng.me" ).getHostAddress();

//IP對應域名
InetAddress[] addresses = InetAddress.getAllByName("8.8.8.8"); // ip or DNS name
for (int i = 0; i < addresses.length; i++) {
    String hostname = addresses[i].getHostName();
    System.out.println(hostname);
}

 

 

二、JNDI DNS服務提供者設置(JNDI DNS service provider settings)

http://docs.oracle.com/javase/7/docs/technotes/guides/net/properties.html

sun.net.spi.nameservice.provider.<n>=<default|dns,sun|...>Specifies the name service provider that you can use. By default, Java will use the system configured name lookup mechanism, such as file, nis, etc. You can specify your own by setting this option. <n> takes the value of a positive number, it indicates the precedence order with a small number takes higher precendence over a bigger number. Aside from the default provider, the JDK includes a DNS provider named "dns,sun".

Prior to JDK 7, the first provider that was successfully loaded was used. 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.

重點是這個參數,區分jdk版本,jdk7之前,只有第一個設置的provier生效;jdk7及其之后,provider鏈都生效,從第一個開始,指導解析成功。

Java有兩個實現:

  Default:相當於設置System.setProperty("sun.net.spi.nameservice.provider.1", "default"); 具體解析過程是系統調用(getaddrinfo),依賴系統的DNS解析方式。

      getaddrinfo:https://linux.die.net/man/3/getaddrinfo

        Linux 系統如何處理名稱解析: https://blog.arstercz.com/linux-%E7%B3%BB%E7%BB%9F%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86%E5%90%8D%E7%A7%B0%E8%A7%A3%E6%9E%90/

        getaddrinfo工作原理分析: https://www.cnblogs.com/battzion/p/4235562.html 

        resolv.conf文件更新了,getaddrinfo系統調用感知不到,它只會加載一次: https://stackoverflow.com/questions/19930037/an-issue-of-getaddrinfo-function-call-on-linux-platform  

    linux 默認的DNS方式是讀取/etc/resolv.conf進行DNS解析。

      resolv.conf文件變更了,java進程感知不到,必須得程序重啟才能生效

      Linux 系統如何處理名稱解析: https://blog.arstercz.com/linux-%E7%B3%BB%E7%BB%9F%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86%E5%90%8D%E7%A7%B0%E8%A7%A3%E6%9E%90/

        修改 resolv.conf 里的 dns server, 多數運行的程序不會立即生效. Centos 7 系統中, glibc-2.17-202 版本合並了官方 glibc-2.25.90-18 的功能, 增加了自動檢測 resolv.conf 修改功能, 如下:

# rpm -q --changelog glibc-2.17-260
...
* Fri Sep 29 2017 Florian Weimer <fweimer@redhat.com> - 2.17-202
....
- Detect and apply /etc/resolv.conf changes in libresolv (#1432085)

    mac 默認的方式是向網關請求獲取DNS服務器,然后直接請求DNS服務器進行解析,沒有讀取/etc/resolv.conf。

  <dns,sun>:System.setProperty("sun.net.spi.nameservice.provider.1", "dns,sun"); 讀取/etc/resolv.conf進行DNS解析,不同於默認的用getaddrinfo系統調用

    不同於“default”, 使用"dns,sun",每5分鍾會讀取一次/etc/resolv.conf,更新內存中的dns nameserver


sun.net.spi.nameservice.nameservers=<server1_ipaddr,server2_ipaddr ...>You can specify a comma separated list of IP addresses that point to the DNS servers you want to use. If the sun.net.spi.nameservice.nameservers property is not defined, then the provider will use any name servers already configured in the platform DNS configuration.


sun.net.spi.nameservice.domain=<domainname>This property specifies the default DNS domain name, for instance, eng.example.com. If the sun.net.spi.nameservice.domain property is not defined then the provider will use any domain or domain search list configured in the platform DNS configuration.

 

使用dnsjava的provider:

1. 工程添加dnsjava包。

2. 設置provider:System.setProperty("sun.net.spi.nameservice.provider.1","dns,dnsjava");

dnsjava的provider功能強大:

There's no standard way to determine what the local nameserver or DNS search
path is at runtime from within the JVM.  dnsjava attempts several methods
until one succeeds.

 - The properties 'dns.server' and 'dns.search' (comma delimited lists) are
   checked.  The servers can either be IP addresses or hostnames (which are
   resolved using Java's built in DNS support).
 - The sun.net.dns.ResolverConfiguration class is queried.
 - On Unix, /etc/resolv.conf is parsed.
 - On Windows, ipconfig/winipcfg is called and its output parsed.  This may
   fail for non-English versions on Windows.
 - As a last resort, "localhost" is used as the nameserver, and the search
   path is empty.

參考:

http://www.xbill.org/dnsjava/dnsjava-current/README

http://stackoverflow.com/questions/5668058/how-to-change-the-java-dns-service-provider

 

三、JVM DNS緩存

如果啟動了security manager,則永久緩存,但一般情況下大家是不會去啟動security manager的。

可以再程序里面設置不緩存,或者在啟動參數里面設置

java.security.Security.setProperty("networkaddress.cache.ttl" , "0")

如果沒有啟動security manager,則要區分JDK版本:

1.5及其一下,java對DNS解析IP進行緩存,默認緩存超時時間為-1(在重啟JVM前永久緩存)

1.6及其以上,緩存時間根據ttl。

參考:

http://docs.oracle.com/javase/1.5.0/docs/guide/net/properties.html

http://docs.oracle.com/javase/7/docs/technotes/guides/net/properties.html

設置ttl:在命令啟動JVM的時候設置參數"-Dnetworkaddress.cache.ttl=60 -Dsun.net.inetaddr.ttl=60"

 

四、Linux服務器是否會對dns緩存,ttl是否有用?

linux本身是沒有dns緩存的,想使用dns緩存的話需要自己安裝一個服務程序NSCD.

$ ps aux | grep nscd 可以查看

相關問題:http://blogread.cn/it/article/7043?f=wb

 

五、nginx 自己實現了dns resolver,並且會對dns緩存

六、ping 未知域名的全過程(依賴於操作系統)

主機A,B(可不再同一網段),主機B有域名假設為www.baidu.com
首先:1. 本地主機A在命令行下執行"ipconfig/flushdns"命令來清空本地DNS高速緩存;
      2. 本地主機A在命令行下執行"arp -d"命令來清空arp緩存

然后,主機A執行ping www.baidu.com(即主機B的域名)

在此過程中都發生了那些報文交互?

思路:

  1.要執行ping命令主機A必須將域名轉化為IP地址,故而一定會有DNS解析過程;
      2.在DNS解析之前,主機A一定要知道自己默認網關的MAC地址,這就要涉及到ARP解析的問題;
      3.ping命令本身是ICMP回顯請求,故而肯定要有ICMP協議的回顯請求交互。

以下是全過程:

(此處可參照“跨網段的ping過程”來看,此處假設DNS服務器和主機A不在同一網段,若二者在同一網段那么我想只需進行簡單arp就可得到DNS服務器的mac不需經過網關)
1.主機A發送ARP請求報文目的mac為FFFFFF-FFFFFF,目的IP為網關的IP,要求獲得網關的MAC地址;
2.路由器(主機A的默認網關)發送目的mac為A的mac,目的IP為A的IP的ARP回答報文,以告知A網關的mac地址;
3.A獲得網關的mac地址后,就向網關發送一個DNS查詢報文,其目的mac地址為網關的mac地址,目的IP為DNS服務器的IP地址;
4.網關收到DNS查詢報文后,拆包檢查發現是DNS查詢於是將相應(查詢)信息封裝,向DNS服務器發送該報文,其目的IP地址為DNS服務器的IP,目的mac為下一跳的mac,解析域名IP地址此時就交給了DNS服務器;
5.經過DNS解析,主機A知道了所要ping的域名的ip地址;
6.剩下的ping過程就和ping一個特定的ip地址相同了,首先判斷ping命令的目的B的IP地址是否和A在同一網段,若在同一網段則相當於同網段內ping,若不在同一網段,就是不同網段的ping只不過此時主機不需要再解析網關的mac地址了。

參考:

http://blog.sina.com.cn/s/blog_7c35df9b0100vomk.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM