All pastes #177836 Raw Edit

Someone

public javascript v1 · immutable
#177836 ·published 2006-09-20 19:16 UTC
rendered paste body
/* * DNS LIBRARY IN JAVASCRIPT * * Copyright 2005 Joshua Tauberer <tauberer@for.net> * * Feel free to use this file however you want, but * credit would be nice. * * A major limitation of this library is that Mozilla * only provides TCP sockets, and DNS servers sometimes * only respond on UDP.  To get around this, you can set * the profile option "dns.nameserver" to the hostname or * IP of your own ISP's nameserver that your computer * normally uses, which should respond on TCP. * If no dns.nameserver option is given, the Windows registry and * the file /etc/resolv.conf (on Linux) will be scanned * for a DNS server to use. */var DNS_ROOT_NAME_SERVER = "J.ROOT-SERVERS.NET";var DNS_ALLOW_RECURSION = 1;var DNS_FOUND_NAME_SERVER_AUTOMATICALLY = 0;var DNS_CACHE_SIZE = 1000;var dnsCache = Array(DNS_CACHE_SIZE);var dnsCachePos = 0;DNS_LoadPrefs();function DNS_LoadPrefs() {	var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);	if (prefs.getPrefType("dns.nameserver") == prefs.PREF_STRING		&& prefs.getCharPref("dns.nameserver") != null && prefs.getCharPref("dns.nameserver") != "") {		DNS_ROOT_NAME_SERVER = prefs.getCharPref("dns.nameserver");		DNS_ALLOW_RECURSION = 0; // When our own name server has no answer								  // for us, but gives us an authority server,								  // we don't want to follow it to see if it								  // has an answer.	} else {		// Try getting a nameserver from /etc/resolv.conf.		try {			var resolvconf = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);			resolvconf.initWithPath("/etc/resolv.conf");						var stream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance();			var stream_filestream = stream.QueryInterface(Components.interfaces.nsIFileInputStream);			stream_filestream.init(resolvconf, 0, 0, 0); // don't know what the flags are...						var stream_reader = stream.QueryInterface(Components.interfaces.nsILineInputStream);						var out_line = Object();			while (stream_reader.readLine(out_line)) {				if (DNS_StartsWith(out_line.value, "nameserver ")) {					DNS_ROOT_NAME_SERVER = out_line.value.substring("nameserver ".length);					DNS_ALLOW_RECURSION = 0;					DNS_FOUND_NAME_SERVER_AUTOMATICALLY = 1;					break;				}			}						stream_filestream.close();		} catch (e) {		}				// Try getting a nameserver from the windows registry		try {			var registry_object = Components.classes["@mozilla.org/windows-registry-key;1"].createInstance();			var registry = registry_object.QueryInterface(Components.interfaces.nsIWindowsRegKey);						registry.open(registry.ROOT_KEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", registry.ACCESS_QUERY_VALUE);			var ns = "";			if (registry.hasValue("DhcpNameServer")) ns = registry.readStringValue("DhcpNameServer");			if (ns == "" && registry.hasValue("NameServer")) ns = registry.readStringValue("NameServer");			registry.close();						if (ns != "") {				var servers = ns.split(' ');				if (servers.length > 0 && servers[0] != "") {					DNS_ROOT_NAME_SERVER = servers[0];					DNS_ALLOW_RECURSION = 0;					DNS_FOUND_NAME_SERVER_AUTOMATICALLY = 1;				}			}		} catch (e) {		}	}}var dns_test_domains = Array("for.net", "www.for.net", "yy.for.net", "www.gmail.net");var dns_test_domidx = 0;//DNS_Test();function DNS_Test() {	queryDNS(dns_test_domains[dns_test_domidx], "MX",		function(data) {			var str;			var i;			if (data == null) { str = "no data"; }			else {				for (i = 0; i < data.length; i++) {					if (data[i].host != null)						data[i] = "host=" + data[i].host + ";address=" + data[i].address;										if (str != null) str += ", "; else str = "";					str += data[i];				}			}						alert(dns_test_domains[dns_test_domidx] + " => " + str);			dns_test_domidx++;			DNS_Test();		} );}//queryDNS("www.example.com", "A", function(data) { alert(data); } );//reverseDNS("123.456.789.123", function(addrs) { for (var i = 0; i < addrs.length; i++) { alert(addrs[i]); } } );// queryDNS: This is the main entry point for external callers.function queryDNS(host, recordtype, callback, callbackdata) {	var server = DNS_ROOT_NAME_SERVER;	var authlen = 0;		// Check if an authority exists pertaining to this host.	for (var c = 0; c < dnsCache.length; c++) {		if (dnsCache[c] == null) break;		if (dnsCache[c].domain == host) { server = dnsCache[c].authority; break; }		if (endsWith(host, "." + dnsCache[c].domain) && dnsCache[c].domain.length > authlen) {			server = dnsCache[c].authority;			authlen = dnsCache[c].domain.length;		}	}		queryDNSRecursive(server, host, recordtype, callback, callbackdata, 0);}function reverseDNS(ip, callback, callbackdata) {	// Get a list of reverse-DNS hostnames,	// and then make sure that each hostname	// resolves to the original IP.		queryDNS(DNS_ReverseIPHostname(ip), "PTR",		function(hostnames) {			// No reverse DNS info available.			if (hostnames == null) { callback(null, callbackdata); return; }						var obj = new Object();			obj.ret = Array(0);			obj.retctr = 0;			obj.resolvectr = 0;						var i;						// Check that each one resolves forward.			for (i = 0; i < hostnames.length; i++) {				var o2 = new Object();				o2.retobj = obj;				o2.curhostname = hostnames[i];								queryDNS(hostnames[i], "A",				function(arecs, cb) {					if (arecs != null) {						var j;						var matched = false;						for (j = 0; j < arecs.length; j++) {							if (arecs[j] == ip) { matched = true; break; }						}					}										if (matched)						cb.retobj.ret[cb.retobj.retctr++] = cb.curhostname;										if (++cb.retobj.resolvectr == hostnames.length) {						if (cb.retobj.retctr == 0)							callback(null, callbackdata);						else							callback(cb.retobj.ret, callbackdata);					}				}, o2);			}		});}function DNS_ReverseIPHostname(ip) {	var q = ip.split(".");	return q[3] + "." + q[2] + "." + q[1] + "." + q[0] + ".in-addr.arpa";}function dnsCacheItem(domain, authority) {	this.domain = domain;	this.authority = authority;}function queryDNSRecursive(server, host, recordtype, callback, callbackdata, hops) {	if (hops == 10) {		DNS_Debug("DNS: Maximum number of recursive steps taken in resolving " + host);		callback(null, callbackdata);		return;	}		// Figure out who's responsible for this domain.	queryDNSDirect(server, host, recordtype,		// Got the answer		function(data, innercallbackdata) {			DNS_Debug("DNS: Resolved " + host + " " + recordtype + ": " + data);			callback(data, innercallbackdata);		},				// Authority Server		function(domain, authority, innercallbackdata) {			//DNS_Debug("DNS: Got authority " + authority + " for domain " + domain + " while querying " + server + " for " + host + " " + recordtype);						// Cache this authority record.			dnsCache[dnsCachePos] = new dnsCacheItem(domain, authority);			dnsCachePos = (++dnsCachePos) % dnsCache.length;						// Recurse on the authority.			queryDNSRecursive(authority, host, recordtype, callback, innercallbackdata, hops+1);		},				callbackdata		);}function queryDNSDirect(server, host, recordtype, callback, authorityCallback, callbackdata) {	DNS_Debug("DNS: Resolving " + host + " " + recordtype + " by querying " + server);			var query =		// HEADER		  "00" // ID		+ String.fromCharCode(1) // QR=0, OPCODE=0, AA=0, TC=0, RD=1 (Recursion desired)		+ String.fromCharCode(0) // all zeroes		+ DNS_wordToStr(1) // 1 query		+ DNS_wordToStr(0) // ASCOUNT=0		+ DNS_wordToStr(0) // NSCOUNT=0		+ DNS_wordToStr(0) // ARCOUNT=0		;			var hostparts = host.split(".");	for (var hostpartidx = 0; hostpartidx < hostparts.length; hostpartidx++)		query += DNS_octetToStr(hostparts[hostpartidx].length) + hostparts[hostpartidx];	query += DNS_octetToStr(0);	if (recordtype == "A")		query += DNS_wordToStr(1);	else if (recordtype == "NS")		query += DNS_wordToStr(2); 	else if (recordtype == "CNAME")		query += DNS_wordToStr(5); 	else if (recordtype == "PTR")		query += DNS_wordToStr(12); 	else if (recordtype == "MX")		query += DNS_wordToStr(15); 	else if (recordtype == "TXT")		query += DNS_wordToStr(16); 	else		throw "Invalid record type.";	query += DNS_wordToStr(1); // IN			// Prepend query message length	query = DNS_wordToStr(query.length) + query;		var listener = {		msgsize : null,		readcount : 0,		responseHeader : "",		responseBody : "",		done : false,		finished : function(data) {			if (!this.done)				callback(null, callbackdata);		},		process : function(data){			if (this.done) return false;						this.readcount += data.length;						while (this.responseHeader.length < 14 && data.length > 0) {				this.responseHeader += data.charAt(0);				data = data.substr(1);			}			if (this.responseHeader.length == 14) {				this.msgsize = DNS_strToWord(this.responseHeader.substr(0, 2));				this.responseBody += data;				//DNS_Debug("DNS: Received Reply: " + (this.readcount-2) + " of " + this.msgsize + " bytes");				if (this.readcount >= this.msgsize+2) {					this.responseHeader = this.responseHeader.substr(2); // chop the length field					this.done = true;					DNS_getRDData(this.responseHeader + this.responseBody, callback, authorityCallback, callbackdata, server);					return false;				}			}			return true;		}	}	var ex = DNS_readAllFromSocket(server, 53, query, listener);	if (ex != null) {	  alert(ex);	}}function DNS_readDomain(ctx) {	var domainname = "";	var ctr = 20;	while (ctr-- > 0) {		var l = ctx.str.charCodeAt(ctx.idx++);		if (l == 0) break;				if (domainname != "") domainname += ".";				if ((l >> 6) == 3) {			// Pointer			var ptr = ((l & 63) << 8) + ctx.str.charCodeAt(ctx.idx++);			var ctx2 = { str : ctx.str, idx : ptr };			domainname += DNS_readDomain(ctx2);			break;		} else {			domainname += ctx.str.substr(ctx.idx, l);			ctx.idx += l;		}	}	return domainname;}function DNS_readRec(ctx) {	var rec = new Object();	var ctr;	var txtlen;		rec.dom = DNS_readDomain(ctx);	rec.type = DNS_strToWord(ctx.str.substr(ctx.idx, 2)); ctx.idx += 2;	rec.cls = DNS_strToWord(ctx.str.substr(ctx.idx, 2)); ctx.idx += 2;	rec.ttl = DNS_strToWord(ctx.str.substr(ctx.idx, 2)); ctx.idx += 4; // 32bit	rec.rdlen = DNS_strToWord(ctx.str.substr(ctx.idx, 2)); ctx.idx += 2;		var ctxnextidx = ctx.idx + rec.rdlen;		if (rec.type == 16) {		// TXT		rec.rddata = "";		ctr = 10;		while (rec.rdlen > 0 && ctr-- > 0) {			txtlen = DNS_strToOctet(ctx.str.substr(ctx.idx,1)); ctx.idx++; rec.rdlen--;			rec.rddata += ctx.str.substr(ctx.idx, txtlen); ctx.idx += txtlen; rec.rdlen -= txtlen;		}	} else if (rec.type == 1) {		// A: Return as a dotted-quad		rec.rddata = ctx.str.substr(ctx.idx, rec.rdlen);		rec.rddata = rec.rddata.charCodeAt(0) + "." + rec.rddata.charCodeAt(1) + "." + rec.rddata.charCodeAt(2) + "." + rec.rddata.charCodeAt(3);	} else if (rec.type == 15) {		// MX		rec.rddata = new Object();		rec.rddata.preference = DNS_strToWord(ctx.str.substr(ctx.idx,2)); ctx.idx += 2;		rec.rddata.host = DNS_readDomain(ctx);	} else {		// NS, PTR		rec.rddata = DNS_readDomain(ctx);	}		ctx.idx = ctxnextidx;		return rec;}function DNS_getRDData(str, callback, authorityCallback, callbackdata, server) {	var qcount = DNS_strToWord(str.substr(4, 2));	var ancount = DNS_strToWord(str.substr(6, 2));	var aucount = DNS_strToWord(str.substr(8, 2));	var adcount = DNS_strToWord(str.substr(10, 2));		var ctx = { str : str, idx : 12 };		var i;	var j;	var dom;	var cls;	var ttl;	var rec;		// sanity checks	if (qcount > 1) qcount = 1;	if (ancount > 64) ancount = 64;	if (aucount > 64) aucount = 64;		for (i = 0; i < qcount; i++) {		dom = DNS_readDomain(ctx);		type = DNS_strToWord(str.substr(ctx.idx, 2)); ctx.idx += 2;		cls = DNS_strToWord(str.substr(ctx.idx, 2)); ctx.idx += 2;	}		var results = Array(ancount);	for (i = 0; i < ancount; i++) {		rec = DNS_readRec(ctx);		results[i] = rec.rddata;				DNS_Debug("DNS: Received Result: Result Item: " + rec.rddata);	}	for (i = 0; i < aucount; i++) {		rec = DNS_readRec(ctx);		if (results.length == 0 && DNS_ALLOW_RECURSION && rec.rddata != server) {			DNS_Debug("DNS: Received Result: Authority: " + rec.rddata);			authorityCallback(rec.dom, rec.rddata, callbackdata);			return;		}	}		for (i = 0; i < adcount; i++) {		rec = DNS_readRec(ctx);		DNS_Debug("DNS: Received Result: Additional: " + " (type=" + rec.type + ")" + rec.rddata);		if (rec.type == 1) {			for (j = 0; j < results.length; j++) {				if (results[j].host == rec.dom) {					if (results[j].address == null) results[j].address = Array(0);					results[j].address[results[j].address.length] = rec.rddata;				}			}		}	}	if (results.length > 0) {		callback(results, callbackdata);	} else {		callback(null, callbackdata);	}}function DNS_strToWord(str) {	return str.charCodeAt(1) + (str.charCodeAt(0) << 8);}function DNS_strToOctet(str) {	return str.charCodeAt(0);}function DNS_wordToStr(word) {	return DNS_octetToStr((word >> 8) % 256) + DNS_octetToStr(word % 256);}function DNS_octetToStr(octet) {	return String.fromCharCode(octet);}// This comes from http://xulplanet.com/tutorials/mozsdk/sockets.phpfunction DNS_readAllFromSocket(host,port,outputData,listener){  try {    var transportService =      Components.classes["@mozilla.org/network/socket-transport-service;1"]        .getService(Components.interfaces.nsISocketTransportService);		    var transport = transportService.createTransport(null,0,host,port,null);    var outstream = transport.openOutputStream(0,0,0);    outstream.write(outputData,outputData.length);    var stream = transport.openInputStream(0,0,0);    var instream = Components.classes["@mozilla.org/binaryinputstream;1"]      .createInstance(Components.interfaces.nsIBinaryInputStream);    instream.setInputStream(stream);    var dataListener = {		data : "",		onStartRequest: function(request, context){},		onStopRequest: function(request, context, status){			outstream.close();			stream.close();			if (listener.finished != null) {				listener.finished(this.data);			}			//DNS_Debug("DNS: Connection closed (" + host + ")");		},		onDataAvailable: function(request, context, inputStream, offset, count){			//DNS_Debug("DNS: Got data (" + host + ")");			for (var i = 0; i < count; i++) {			  this.data += String.fromCharCode(instream.read8());			}			if (listener.process != null) {				if (!listener.process(this.data)) {					outstream.close();					stream.close();				}				this.data = "";			}      }    };	    var pump = Components.      classes["@mozilla.org/network/input-stream-pump;1"].        createInstance(Components.interfaces.nsIInputStreamPump);    pump.init(stream, -1, -1, 0, 0, false);    pump.asyncRead(dataListener,null);  } catch (ex) {    return ex;  }  return null;}function DNS_Debug(message) {	if (false) {		var consoleService = Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);		consoleService.logStringMessage(message);	}}function DNS_StartsWith(a, b) {	if (b.length > a.length) return false;	return a.substring(0, b.length) == b;}