Salah satu hal menarik dari DNS Resolver Cloudflare yang diluncurkan 1 April 2018 kemarin adalah ia bisa dipanggil melalui HTTPS. Ini adalah apa yang disebut sebagai DNS over HTTPS (DoH). Selain Cloudflare, DNS Resolver dari Google juga mendukung DoH. Bukan hanya itu, juga sudah tersedia website untuk pencarian hasil query DNS di https://dns.google.com.

Berbeda dengan DNSCrypt, DoH lebih mudah dipakai diberbagai platform karena hampir semua platform menyediakan API untuk melakukan request HTTPS. Sebagai latihan, kali ini saya melakukan query DNS melalui DoH dengan JavaScript. Kode program dan hasil akhirnya dapat dilihat pada halaman ini.

Informasi IP Address Kamu

IP address
Organisasi

Pencarian DNS Lewat HTTPS

IP Address
-
Organisasi
-
IP DNS Resolver
-
Negara DNS Resolver
-
ISP DNS Resolver
-
function setValue(id, value, extraClass) {
	var element = document.getElementById(id);
	$(element).find(".spinner").hide();
	$(element).find(".value").text(value).show();
	if (extraClass) {
		$(element).addClass(extraClass);
	}
}

function refreshUserIP() {		
	$("#userInformation .value").hide();
	$("#userInformation .spinner").show();
	jQuery.getJSON("https://api.ipify.org?format=jsonp&callback=?").then(function(json) {
		setValue("ip-address", json.ip);
		return Promise.resolve(json.ip);
	}).then(function(ip) {			
		return jQuery.get("https://whois.arin.net/rest/ip/" + ip, {}, null,"json");
	}).then(result => {				
		setValue("organization", result.net.orgRef['@name']);						
	});		
}

function searchDomain(domainName) {
	$("#responseInformation .value").hide();
	$("#responseInformation .spinner").show();
	jQuery.get("https://cloudflare-dns.com/dns-query?ct=application/dns-json&name=maxmind.test-ipv6.com&type=TXT").then(result => {			
		var ip = 'Not Found', isp = 'Not Found', country = 'Not Found';
		if (result.Status === 0) {
			var answer = result.Answer[0].data.slice(1, -1);
			var data = answer.split(/ +(?=[\w]+=)/g);
			for (var i = 0; i < data.length; i++) {					
				var field = data[i].split("=");
				var value = field[1].slice(1, -1);
				if (field[0] === 'ip') {
					ip = value;
				} else if (field[0] === 'isp') {
					isp = value;
				} else if (field[0] === 'country') {
					country = value;
				}
			}				
		} 
		setValue('resolver-ip', ip);
		setValue('resolver-isp', isp);
		setValue('resolver-country', country);			
	});
	jQuery.get("https://cloudflare-dns.com/dns-query?ct=application/dns-json&name=" + domainName + "&type=A").then(result => {			
		var ip = 'Not Found', organization = 'Not Found';
		if (result.Status === 0) {
			for (var i=0; i<result.Answer.length; i++) {
				var answer = result.Answer[i];
				if (answer.type === 1) {
					ip = answer.data;		
					break;
				}
			}				
		}
		setValue('dns-ip', ip);
		return Promise.resolve(ip);
	}).then(ip => {
		if (ip !== 'Not Found') {
			return jQuery.get("https://whois.arin.net/rest/ip/" + ip, {}, null, "json");
		} else {
			return Promise.resolve(null);			
		}
	}).then(result => {
		if (result == null)	{
			setValue("dns-organization", "Not Found");
		} else {
			setValue("dns-organization", result.net.orgRef['@name']);
		}			
	});		
}

window.onload = function() {	
	$("#search").click(function() {
		var domainName = $("#domainName").val();
		if (domainName) {
			searchDomain(domainName);
		}
	});
	$(".spinner").hide();
	refreshUserIP();
};

Tidak ada yang spesial pada kode program ini karena pada dasarnya saya hanya memanggil layanan yang sudah ada dengan jQuery.get() dan jQuery.getJson(). Cukup lama rasanya sejak terakhir kali memakai jQuery :) Selain itu, saya juga tidak berani memakai fitur ES2016 seperti keyword const dan string interpolation (dengan memakai tanda backtick sebagai pengganti kutip di string) karena tanpa batuan Babel atau TypeScript, tidak semua browser bisa menjalankan kode program yang sama. Untuk animasi spinner, saya menggunakan CSS3 yang kode-nya saya ambil dari https://tobiasahlin.com/spinkit/.

Untuk mendapatkan IP publik pengguna, saya memanggil https://api.ipify.org yang akan mengembalikan JSONP. Setelah itu, setelah mendapatkan IP publik, saya memanggil https://whois.arin.net guna mendapatkan informasi lebih lanjut mengenai IP tersebut. Karena sudah terbiasa memakai Promise dan kebetulan hasil kembalian jQuery.get() dan jQuery.getJson() kompatibel dengan Promise, maka saya melakukan chaining then pada kode program.

Untuk mendapatkan IPv4 address dari domain yang dimasukkan oleh pengguna, saya memanggil https://cloudflare-dns.com/dns-query?ct=application/dns-json. Sama seperti sebelumnya, saya juga memanggil https://whois.arin.net untuk mendaftarkan informasi lebih lanjut mengenai IP yang ditemukan. Selain itu, saya juga menggunakan Cloudflare DNS untuk mendapatkan record TXT dari maxmind.test-ipv6.com untuk memastikan bahwa DNS resolver yang bekerja adalah Cloudflare. Sayang sekali browser tidak memungkinkan membuat socket UDP untuk alasan keamanan. Seandainya saya pemograman socket di browser diperbolehkan, saya bisa menambahkan fasilitas lebih jauh seperti pemeriksaan DNS spoofing langsung dari browser. Untuk mengakali keterbatasan ini, website pemeriksa DNS spoofing seperti https://dnsleaktest.com/ membutuhkan sebuah name server khusus yang di-hit pada saat pengguna membuka situs tersebut.