วิธีทำให้ Java ใช้ DNS Caching Timeout ได้อย่างไร


102

เราใช้ GSLB สำหรับการกระจายทางภูมิศาสตร์และการจัดสรรภาระงาน แต่ละบริการได้รับการกำหนดชื่อโดเมนคงที่ ด้วยความมหัศจรรย์ของ DNS ชื่อโดเมนจะถูกแก้ไขเป็น IP ที่ใกล้เคียงกับเซิร์ฟเวอร์ที่โหลดน้อยที่สุด เพื่อให้การทำโหลดบาลานซ์ทำงานได้แอ็พพลิเคชันเซิร์ฟเวอร์จำเป็นต้องใช้ TTL จากการตอบสนอง DNS และเพื่อแก้ไขชื่อโดเมนอีกครั้งเมื่อแคชหมดเวลา อย่างไรก็ตามฉันไม่สามารถหาวิธีทำได้ใน Java

แอปพลิเคชันอยู่ใน Java 5 ซึ่งทำงานบน Linux (Centos 5)

คำตอบ:


77

ตามคำตอบของ Byron คุณไม่สามารถตั้งค่าnetworkaddress.cache.ttlหรือnetworkaddress.cache.negative.ttlเป็นคุณสมบัติของระบบโดยใช้-Dแฟล็กหรือการโทรSystem.setPropertyเนื่องจากสิ่งเหล่านี้ไม่ใช่คุณสมบัติของระบบ - เป็นคุณสมบัติด้านความปลอดภัย

หากคุณต้องการใช้คุณสมบัติของระบบเพื่อทริกเกอร์ลักษณะการทำงานนี้ (เพื่อให้คุณสามารถใช้-Dแฟล็กหรือการโทรSystem.setProperty) คุณจะต้องตั้งค่าคุณสมบัติของระบบต่อไปนี้:

-Dsun.net.inetaddr.ttl=0

คุณสมบัติของระบบนี้จะเปิดใช้งานเอฟเฟกต์ที่ต้องการ

แต่โปรดทราบ: หากคุณไม่ใช้-Dแฟล็กเมื่อเริ่มกระบวนการ JVM และเลือกที่จะเรียกสิ่งนี้จากโค้ดแทน:

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

รหัสนี้ต้องดำเนินการก่อนรหัสอื่น ๆ ใน JVM จะพยายามดำเนินการเครือข่าย

สิ่งนี้มีความสำคัญเนื่องจากตัวอย่างเช่นหากคุณเรียกSecurity.setPropertyไฟล์. war และนำ. war นั้นไปใช้กับ Tomcat สิ่งนี้จะไม่ได้ผล: Tomcat ใช้สแต็กเครือข่าย Java เพื่อเริ่มต้นตัวเองเร็วกว่าที่เรียกใช้โค้ด. war ของคุณ เนื่องจาก 'เงื่อนไขการแข่งขัน' นี้มักจะสะดวกกว่าในการใช้-Dแฟล็กเมื่อเริ่มกระบวนการ JVM

หากคุณไม่ได้ใช้-Dsun.net.inetaddr.ttl=0หรือเรียกใช้Security.setPropertyคุณจะต้องแก้ไข$JRE_HOME/lib/security/java.securityและตั้งค่าคุณสมบัติความปลอดภัยเหล่านั้นในไฟล์นั้นเช่น

networkaddress.cache.ttl = 0
networkaddress.cache.negative.ttl = 0

แต่ให้ใส่ใจกับคำเตือนด้านความปลอดภัยในความคิดเห็นเกี่ยวกับคุณสมบัติเหล่านั้น ทำสิ่งนี้ก็ต่อเมื่อคุณมั่นใจพอสมควรว่าคุณไม่หวั่นไหวต่อการโจมตีด้วยการปลอมแปลง DNS


2
FQN คือjava.security.Security(อย่างน้อยใน jdk7)
Pablo Fernandez

1
เพียงแค่แสดงความคิดเห็นคำเตือนด้านความปลอดภัยเหล่านั้นส่วนใหญ่เกี่ยวข้องกับผู้จัดการความปลอดภัยและการโหลดระยะไกล สำหรับแอปพลิเคชันเซิร์ฟเวอร์ปกติใด ๆ ที่เชื่อถือ DNS เป็นส่วนขยายการลด TTL ก็ใช้ได้ (อย่างไรก็ตามฉันไม่คิดว่า 0 เป็นค่าต่ำสุดที่ดีและค่าเริ่มต้นของ 30 สำหรับผู้จัดการที่ไม่ใช่ความปลอดภัยนั้นใช้ได้ในกรณีส่วนใหญ่)
เช่น

3
คุณสมบัติของระบบทำงานร่วมกับ OpenJDK ได้ด้วยหรือเป็น Oracle เฉพาะหรือไม่
mhlz

อย่าตรวจสอบ DNS อีกครั้งหลังจากการค้นหาครั้งแรกไม่ได้ป้องกันคุณจากการโจมตีที่หลอกลวงทำให้การโจมตีปลอมแปลงเป็นแบบถาวรแทนที่จะเป็นการโจมตีชั่วคราว
kbolino

67

Java มีพฤติกรรมการแคช DNS แปลก ๆ ทางออกที่ดีที่สุดของคุณคือปิดการแคช DNS หรือตั้งค่าเป็นตัวเลขต่ำ ๆ เช่น 5 วินาที

networkaddress.cache.ttl (ค่าเริ่มต้น: -1)
ระบุนโยบายการแคชสำหรับการค้นหาชื่อที่ประสบความสำเร็จจากบริการชื่อ ค่านี้ระบุเป็นจำนวนเต็มเพื่อระบุจำนวนวินาทีในการแคชการค้นหาที่สำเร็จ ค่า -1 หมายถึง "แคชตลอดไป"

networkaddress.cache.negative.ttl (ค่าเริ่มต้น: 10)
ระบุนโยบายการแคชสำหรับการค้นหาชื่อที่ไม่สำเร็จจากบริการชื่อ ค่านี้ระบุเป็นจำนวนเต็มเพื่อระบุจำนวนวินาทีในการแคชความล้มเหลวสำหรับการค้นหาที่ไม่สำเร็จ ค่า 0 แสดงว่า "ไม่เคยแคช" ค่า -1 หมายถึง "แคชตลอดไป"


7
หมายเหตุ: สิ่งนี้ไม่ได้ปิดใช้งานการแคช DNS ทั้งหมดในระบบปฏิบัติการของคุณ เพียงปิดการใช้งานแคชในหน่วยความจำที่เสียของ Java ในไลบรารี คุณสามารถตั้งค่าคุณสมบัติเหล่านี้ในบรรทัดคำสั่งเมื่อคุณเรียกใช้ JVM
Nelson

2
ไม่รู้ว่า "หัก" ใช้ได้ Java (ด้วยเหตุผลด้านความปลอดภัย) จะแคชรายการ DNS ตลอดไปหรือจนกว่า JVM จะเริ่มต้นใหม่แล้วแต่ว่ากรณีใดจะเกิดขึ้นก่อน สิ่งนี้ (จากสิ่งที่ฉันบอกได้) มาจากการออกแบบ การตั้งค่าสามารถทำได้ในไฟล์นโยบาย java.security หรือที่บรรทัดคำสั่ง การตั้งค่าจะแตกต่างกันสำหรับแต่ละรายการ อ้างอิง: rgagnon.com/javadetails/java-0445.html
Milner

4
โปรดทราบว่าคุณไม่สามารถตั้งค่าสิ่งเหล่านี้เป็นคุณสมบัติของระบบ (เช่นใช้แฟล็ก -D หรือ System.setProperty) เนื่องจากไม่ใช่คุณสมบัติของระบบ - เป็นคุณสมบัติด้านความปลอดภัย
Les Hazlewood

6
เอกสารนี้แตกต่างกันเล็กน้อยใน 1.7 โดยเฉพาะอย่างยิ่งแคชตลอดไปจะเกิดขึ้นเมื่อมีตัวจัดการความปลอดภัยเท่านั้น: "ลักษณะการทำงานเริ่มต้นคือการแคชตลอดไปเมื่อมีการติดตั้งตัวจัดการความปลอดภัยและเพื่อแคชสำหรับช่วงเวลาที่ใช้งานเฉพาะเมื่อไม่มีการติดตั้งตัวจัดการความปลอดภัย" docs.oracle.com/javase/7/docs/technotes/guides/net/…
Brett Okken

1
@ ไมเคิลดูSystem.getSecurityManager(). เอกสารสำหรับ Java 8: docs.oracle.com/javase/8/docs/api/java/lang/…
gesellix

22

เห็นได้ชัดว่าสิ่งนี้ได้รับการแก้ไขแล้วในรุ่นใหม่ (SE 6 และ 7) ฉันพบเวลาในการแคชสูงสุด 30 วินาทีเมื่อเรียกใช้ข้อมูลโค้ดต่อไปนี้ขณะดูกิจกรรมพอร์ต 53 โดยใช้ tcpdump

/**
 * http://stackoverflow.com/questions/1256556/any-way-to-make-java-honor-the-dns-caching-timeout-ttl
 *
 * Result: Java 6 distributed with Ubuntu 12.04 and Java 7 u15 downloaded from Oracle have
 * an expiry time for dns lookups of approx. 30 seconds.
 */

import java.util.*;
import java.text.*;
import java.security.*;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class Test {
    final static String hostname = "www.google.com";
    public static void main(String[] args) {
        // only required for Java SE 5 and lower:
        //Security.setProperty("networkaddress.cache.ttl", "30");

        System.out.println(Security.getProperty("networkaddress.cache.ttl"));
        System.out.println(System.getProperty("networkaddress.cache.ttl"));
        System.out.println(Security.getProperty("networkaddress.cache.negative.ttl"));
        System.out.println(System.getProperty("networkaddress.cache.negative.ttl"));

        while(true) {
            int i = 0;
            try {
                makeRequest();
                InetAddress inetAddress = InetAddress.getLocalHost();
                System.out.println(new Date());
                inetAddress = InetAddress.getByName(hostname);
                displayStuff(hostname, inetAddress);
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
            try {
                Thread.sleep(5L*1000L);
            } catch(Exception ex) {}
            i++;
        }
    }

    public static void displayStuff(String whichHost, InetAddress inetAddress) {
        System.out.println("Which Host:" + whichHost);
        System.out.println("Canonical Host Name:" + inetAddress.getCanonicalHostName());
        System.out.println("Host Name:" + inetAddress.getHostName());
        System.out.println("Host Address:" + inetAddress.getHostAddress());
    }

    public static void makeRequest() {
        try {
            URL url = new URL("http://"+hostname+"/");
            URLConnection conn = url.openConnection();
            conn.connect();
            InputStream is = conn.getInputStream();
            InputStreamReader ird = new InputStreamReader(is);
            BufferedReader rd = new BufferedReader(ird);
            String res;
            while((res = rd.readLine()) != null) {
                System.out.println(res);
                break;
            }
            rd.close();
        } catch(Exception ex) {
            ex.printStackTrace();
        }
    }
}

16
ใช่ Java 1.5 มีค่าเริ่มต้นของการแคชแบบไม่สิ้นสุด Java 1.6 และ 1.7 มีค่าเริ่มต้น 30 วินาที
Michael

7
เอกสารประกอบสำหรับ 1.7 ระบุว่าสิ่งนี้อาจเป็นจริงเฉพาะในกรณีที่ไม่มีตัวจัดการความปลอดภัย: "ลักษณะการทำงานเริ่มต้นคือการแคชตลอดไปเมื่อมีการติดตั้งตัวจัดการความปลอดภัยและเพื่อแคชสำหรับช่วงเวลาที่ใช้งานเฉพาะเมื่อการรักษาความปลอดภัย ไม่ได้ติดตั้งผู้จัดการ " docs.oracle.com/javase/7/docs/technotes/guides/net/…
Brett Okken

1
@ ไมเคิลสนใจที่จะแบ่งปันแหล่งที่มาของข้อมูลที่?
rustyx

4
@rustyx Oracle's 1.6 และ 1.7 JDK มีสิ่งนี้ใน jre / lib / security / java.security สำหรับ networkaddress.cache.ttl: "# ค่าเริ่มต้นคือตลอดไป (ตลอดไป) ด้วยเหตุผลด้านความปลอดภัยการแคช # นี้จะถูกสร้างขึ้นตลอดไปเมื่อผู้จัดการความปลอดภัย ถูกตั้งค่าเมื่อไม่ได้ตั้งค่าตัวจัดการความปลอดภัยพฤติกรรมเริ่มต้นคือแคชเป็นเวลา 30 วินาที " ดังนั้นแอพเพล็ตและแอปที่ใช้งานผ่าน Java Web Start จะยังคงแคชตลอดไปมิฉะนั้นจะใช้เวลา 30 วินาที
Michael

1
นี่เป็นตัวชี้รหัส java.security OpenJDK 8 ซึ่งกล่าวว่าไม่มีผู้จัดการการรักษาความปลอดภัย TTL เป็นยุค 30: hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/f940e7a48b72/src/share/... ฉันทดสอบสิ่งนี้บน Mac OS X และ Ubuntu 14.04
tro

18

เพื่อขยายคำตอบของ Byron ฉันเชื่อว่าคุณต้องแก้ไขไฟล์java.securityใน%JRE_HOME%\lib\securityไดเร็กทอรีเพื่อให้มีผลต่อการเปลี่ยนแปลงนี้

นี่คือส่วนที่เกี่ยวข้อง:

#
# The Java-level namelookup cache policy for successful lookups:
#
# any negative value: caching forever
# any positive value: the number of seconds to cache an address for
# zero: do not cache
#
# default value is forever (FOREVER). For security reasons, this
# caching is made forever when a security manager is set. When a security
# manager is not set, the default behavior is to cache for 30 seconds.
#
# NOTE: setting this to anything other than the default value can have
#       serious security implications. Do not set it unless 
#       you are sure you are not exposed to DNS spoofing attack.
#
#networkaddress.cache.ttl=-1 

เอกสารเกี่ยวกับjava.securityไฟล์ที่นี่


5
ในการเพิ่มสิ่งนี้เมื่อใช้ tomcat6 ฉันต้องแก้ไขไฟล์ lib / security ของฉันเนื่องจากการตั้งค่า networkaddress.cache.ttl หรือ sun.net.inetaddr.ttl โดยทางโปรแกรมหรือผ่านตัวแปร JAVA_OPTS ไม่ทำงาน
bramp

1
@bramp ขอบคุณครับฉันกำลังประสบปัญหาเดียวกันและได้รับการแก้ไขโดยใช้ความคิดเห็นและคำตอบของคุณ +1 เพื่อแสดงความคิดเห็นและคำตอบ
Bhavik Ambani

7

เพื่อสรุปคำตอบอื่น ๆ<jre-path>/lib/security/java.securityคุณสามารถตั้งค่าของคุณสมบัติnetworkaddress.cache.ttlเพื่อปรับวิธีการแคชการค้นหา DNS โปรดทราบว่านี่ไม่ใช่คุณสมบัติของระบบ แต่เป็นคุณสมบัติความปลอดภัย ฉันสามารถตั้งค่าได้โดยใช้:

java.security.Security.setProperty("networkaddress.cache.ttl", "<value>");

นอกจากนี้ยังสามารถตั้งค่าโดยคุณสมบัติระบบ-Dsun.net.inetaddr.ttlแม้ว่าจะไม่แทนที่คุณสมบัติความปลอดภัยหากตั้งค่าไว้ที่อื่น

ฉันต้องการเพิ่มเติมว่าหากคุณพบปัญหานี้กับบริการเว็บใน WebSphere เหมือนเดิมการตั้งค่าnetworkaddress.cache.ttlจะไม่เพียงพอ คุณจำเป็นต้องตั้งค่าคุณสมบัติของระบบการdisableWSAddressCaching trueซึ่งแตกต่างจากคุณสมบัติ time-to-live ซึ่งสามารถตั้งค่าเป็นอาร์กิวเมนต์ JVM หรือผ่านSystem.setProperty)

ไอบีเอ็มมีการโพสต์รายละเอียดเกี่ยวกับวิธีสวย WebSphere จับ DNS แคชที่นี่ ส่วนที่เกี่ยวข้องกับด้านบนคือ:

ในการปิดใช้งานการแคชที่อยู่สำหรับบริการบนเว็บคุณต้องตั้งค่าคุณสมบัติที่กำหนดเองของ JVM เพิ่มเติมปิดการใช้งาน WSAddressCaching เป็น true ใช้คุณสมบัตินี้เพื่อปิดใช้งานการแคชที่อยู่สำหรับบริการบนเว็บ หากโดยทั่วไประบบของคุณทำงานโดยมีเธรดไคลเอ็นต์จำนวนมากและคุณพบปัญหาการล็อกบนแคช wsAddrCache คุณสามารถตั้งค่าคุณสมบัติที่กำหนดเองนี้เป็นจริงเพื่อป้องกันการแคชข้อมูลบริการบนเว็บ


2

ตามที่คุณสมบัติ oracle จาวาอย่างเป็นทางการ , sun.net.inetaddr.ttlเป็นดวงอาทิตย์คุณสมบัติการใช้งานที่เฉพาะเจาะจงซึ่ง "อาจจะไม่ได้รับการสนับสนุนในอนาคต" networkaddress.cache.ttl"วิธีที่ต้องการคือการใช้คุณสมบัติการรักษาความปลอดภัย"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.