www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

dns_worker.js (8995B)


      1 /*
      2     ***** BEGIN LICENSE BLOCK *****
      3     
      4     Copyright © 2015 Center for History and New Media
      5                      George Mason University, Fairfax, Virginia, USA
      6                      http://zotero.org
      7     
      8     This file is part of Zotero.
      9     
     10     Zotero is free software: you can redistribute it and/or modify
     11     it under the terms of the GNU Affero General Public License as published by
     12     the Free Software Foundation, either version 3 of the License, or
     13     (at your option) any later version.
     14     
     15     Zotero is distributed in the hope that it will be useful,
     16     but WITHOUT ANY WARRANTY; without even the implied warranty of
     17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18     GNU Affero General Public License for more details.
     19     
     20     You should have received a copy of the GNU Affero General Public License
     21     along with Zotero.  If not, see <http://www.gnu.org/licenses/>.
     22     
     23     ***** END LICENSE BLOCK *****
     24 */
     25 
     26 function getIPForLookup(ip) {
     27 	if (ip.indexOf(".") != -1) {
     28 		// IPv4
     29 		x = ip.split(".").reverse().join(".")+".in-addr.arpa";
     30 	} else {
     31 		if (ip.indexOf("%") != -1) ip = ip.substr(0, ip.indexOf("%"));
     32 		// IPv6
     33 		var parts = ip.split(":");
     34 		x = "ip6.arpa"
     35 		for (var i = 0; i < parts.length; i++) {
     36 			var part = parts[i];
     37 			for (var j = 0; j < (part.length == 0 ? 4*(9-parts.length) : 4-part.length); j++) x = "0." + x;
     38 			for (var j = 0; j < part.length; j++) x = part[j] + "." + x;
     39 		}
     40 	}
     41 	return x;
     42 }
     43 
     44 function isLocalIP(ip) {
     45 	return ip.startsWith("169.254.") || ip.startsWith("192.168.") || ip.startsWith("10.") ||
     46 	       /^172\.(?:1[6-9]|2[0-9]|3[01])\./.test(ip) ||
     47 	       ip.startsWith("fe80:") || ip.startsWith("fd00:") || ip == "";
     48 }
     49 
     50 onmessage = function (e) {
     51 	var libc, reverseLookup, getIPs, getnameinfo;
     52 	var sockaddr = new ctypes.StructType("sockaddr");
     53 	platform = e.data;
     54 
     55 	if (platform == "win") {
     56 		libc = ctypes.open("Ws2_32.dll");
     57 		var addrinfo = new ctypes.StructType("arrinfo");
     58 		addrinfo.define([{"ai_flags":ctypes.int}, {"ai_family":ctypes.int}, {"ai_socktype":ctypes.int},
     59 		                 {"ai_protocol":ctypes.int}, {"ai_addrlen":ctypes.int}, {"ai_canonname":ctypes.char.ptr},
     60 		                 {"ai_addr":sockaddr.ptr}, {"ai_next":addrinfo.ptr}]);
     61 		var gethostname = libc.declare("gethostname", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.size_t);
     62 		var getaddrinfo = libc.declare("getaddrinfo", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.char.ptr,
     63 		                               addrinfo.ptr, addrinfo.ptr.ptr);
     64 		var freeaddrinfo = libc.declare("freeaddrinfo", ctypes.default_abi, ctypes.void_t, addrinfo.ptr);
     65 		getnameinfo = libc.declare("getnameinfo", ctypes.default_abi, ctypes.int, sockaddr.ptr, ctypes.int,
     66 		                           ctypes.char.ptr, ctypes.int, ctypes.char.ptr, ctypes.int, ctypes.int);
     67 		getIPs = function () {
     68 			var buf = new new ctypes.ArrayType(ctypes.char, 1025);
     69 			var status = gethostname(buf, 1025);
     70 			if (status != 0) throw new Error("could not get hostname: "+status);
     71 
     72 			var ips = [];
     73 			var out = new addrinfo.ptr();
     74 			status = getaddrinfo(buf, null, null, out.address());
     75 			if (status != 0) throw new Error("could not get addrinfo: "+status);
     76 			var rec = out;
     77 			try {
     78 				while (!rec.isNull()) {
     79 					status = getnameinfo(rec.contents.ai_addr, rec.contents.ai_addrlen, buf, 1025, null, 0, 2);
     80 					if (status != 0) throw new Error("could not get IP address: "+status);
     81 					var ip = buf.readString();
     82 					if (!isLocalIP(ip)) ips.push(ip);
     83 					rec = rec.contents.ai_next;
     84 				}
     85 			} finally {
     86 				freeaddrinfo(out);
     87 			}
     88 			return ips;
     89 		};
     90 
     91 		var dnsapi = ctypes.open("Dnsapi.dll");
     92 		var DNS_RECORD = new ctypes.StructType("DNS_RECORD");
     93 		DNS_RECORD.define([{"pNext":DNS_RECORD.ptr}, {"pName":ctypes.char.ptr}, {"wType":ctypes.unsigned_short},
     94 		                   {"wDataLength":ctypes.unsigned_short}, {"DW":ctypes.unsigned_long}, {"dwTtl":ctypes.unsigned_long},
     95 		                   {"dwReserved":ctypes.unsigned_long}, {"pNameHost":ctypes.char.ptr}]);
     96 		var DnsQuery = dnsapi.declare("DnsQuery_A", ctypes.winapi_abi, ctypes.int, ctypes.char.ptr, ctypes.unsigned_short,
     97 		                              ctypes.unsigned_long, ctypes.voidptr_t, DNS_RECORD.ptr, ctypes.voidptr_t);
     98 		var DnsRecordListFree = dnsapi.declare("DnsRecordListFree", ctypes.winapi_abi, ctypes.void_t, DNS_RECORD.ptr,
     99 		                                       ctypes.int);
    100 		reverseLookup = function (ip) {
    101 			var record = new DNS_RECORD();
    102 			var status = DnsQuery(getIPForLookup(ip), 12 /*DNS_TYPE_PTR*/, 32 /*DNS_QUERY_NO_LOCAL_NAME*/, null, record.address(), null);
    103 			if (status != 0 || record.pNext.isNull()) return null;
    104 			var retval = record.pNext.contents.pNameHost.readString();
    105 			DnsRecordListFree(record.pNext, 1);
    106 			return retval;
    107 		};
    108 	} else {
    109 		if (platform == "mac") {
    110 			libc = ctypes.open("libc.dylib");
    111 		} else {
    112 			var possibleLibcs = [
    113 				"libc.so.6",
    114 				"libc.so.6.1",
    115 				"libc.so"
    116 			];
    117 			for(var i = 0; i < possibleLibcs.length; i++) {
    118 				try {
    119 					libc = ctypes.open(possibleLibcs[i]);
    120 					break;
    121 				} catch(e) {}
    122 			}
    123 		}
    124 
    125 		var AF_INET = 2, AF_INET6, NI_NUMERICHOST, sockaddr_size, libresolv;
    126 		if (platform == "linux") {
    127 			libresolv = ctypes.open("libresolv.so");
    128 			sockaddr.define([{"sa_family":ctypes.unsigned_short}]);
    129 			sockaddrSize = function (x) { return x.sa_family == 10 ? 28 : 16; };
    130 			AF_INET6 = 10;
    131 			NI_NUMERICHOST = 1;
    132 		} else {
    133 			libresolv = libc;
    134 			sockaddr.define([{"sa_len":ctypes.uint8_t}, {"sa_family":ctypes.uint8_t}]);
    135 			sockaddrSize = function (x) { return x.sa_len; };
    136 			AF_INET6 = 30;
    137 			NI_NUMERICHOST = 2;
    138 		}
    139 
    140 		var ifaddrs = new ctypes.StructType("ifaddrs");
    141 		ifaddrs.define([{"ifa_next":ifaddrs.ptr}, {"ifa_name":ctypes.char.ptr}, {"ifa_flags":ctypes.unsigned_int},
    142 		                {"ifa_addr":sockaddr.ptr}]);
    143 		var getifaddrs = libc.declare("getifaddrs", ctypes.default_abi, ctypes.int, ifaddrs.ptr.ptr);
    144 		var freeifaddrs = libc.declare("freeifaddrs", ctypes.default_abi, ctypes.void_t, ifaddrs.ptr);
    145 		getnameinfo = libc.declare("getnameinfo", ctypes.default_abi, ctypes.int, sockaddr.ptr, ctypes.int,
    146 		                           ctypes.char.ptr, ctypes.int, ctypes.char.ptr, ctypes.int, ctypes.int);
    147 		getIPs = function () {
    148 			var buf = new new ctypes.ArrayType(ctypes.char, 1025);
    149 			var out = new ifaddrs.ptr();
    150 			var status = getifaddrs(out.address());
    151 			if (status != 0) throw new Error("could not get ifaddrs: "+status);
    152 			var ips = [];
    153 			var rec = out;
    154 			try {
    155 				while (!rec.isNull()) {
    156 					if (!rec.contents.ifa_name.readString().startsWith("lo")) {
    157 						var family = rec.contents.ifa_addr.contents.sa_family;
    158 						if (family == AF_INET || family == AF_INET6) {
    159 							status = getnameinfo(rec.contents.ifa_addr, sockaddrSize(rec.contents.ifa_addr.contents),
    160 								                 buf, 1025, null, 0, NI_NUMERICHOST);
    161 							if (status != 0) throw new Error("could not get IP address: "+status);
    162 							var ip = buf.readString();
    163 							if (!isLocalIP(ip)) ips.push(ip);
    164 						}
    165 					}
    166 					rec = rec.contents.ifa_next;
    167 				}
    168 			} finally {
    169 				freeifaddrs(out);
    170 			}
    171 			return ips;
    172 		};
    173 
    174 		var res_query;
    175 		try {
    176 			res_query = libresolv.declare("res_query", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.int,
    177 		                                  ctypes.int, ctypes.uint8_t.ptr, ctypes.int);
    178 		} catch(e) {
    179 			res_query = libresolv.declare("__res_query", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.int,
    180 		                                  ctypes.int, ctypes.uint8_t.ptr, ctypes.int);
    181 		}
    182 		let response = new new ctypes.ArrayType(ctypes.uint8_t, 1025);
    183 		var skipName = function(response, offset) {
    184 			var len = response[offset++];
    185 			if ((len & 192) == 192) return offset+1; // compressed
    186 			while (len != 0) {
    187 				offset += len;
    188 				len = response[offset++];
    189 			};
    190 			return offset;
    191 		};
    192 		var reverseLookup = function(ip) {
    193 			var len = res_query(getIPForLookup(ip), 1, 12, response, 1025);
    194 			if (len <= 0) return null;
    195 
    196 			var offset = 4;
    197 			var qdCount = (response[offset++] << 8) + response[offset++];
    198 			var anCount = (response[offset++] << 8) + response[offset++];
    199 			offset += 4;
    200 			for (var i=0; i<qdCount; i++) {
    201 				offset = skipName(response, offset)+4;
    202 			}
    203 			var domain = [];
    204 			if (anCount >= 1) {
    205 				offset = skipName(response, offset);
    206 				offset += 8;
    207 				var rdLength = (response[offset++] << 8) + response[offset++];       // RDLENGTH
    208 				var endOfData = offset+rdLength;
    209 				while(offset < endOfData) {
    210 					if(offset > endOfData) break;
    211 					var len = response[offset++];
    212 					if(offset+len > endOfData) break;
    213 					var str = "";
    214 					for(var i = 0; i < len; i++) {
    215 						str += String.fromCharCode(response[offset++]);
    216 					}
    217 					domain.push(str);
    218 				}
    219 				domain.pop();
    220 			}
    221 			return domain.join(".")
    222 		};
    223 	}
    224 
    225 	var ips = getIPs();
    226 	var hosts = [];
    227 	for (var i = 0; i < ips.length; i++) {
    228 		var host = reverseLookup(ips[i]);
    229 		if(host) hosts.push(host);
    230 	}
    231 
    232 	postMessage(hosts);
    233 };