def resolve(self, hostname, callback): if type(hostname) != bytes: hostname = hostname.encode('utf8') if not hostname: callback(None, Exception('empty hostname')) elif utils.is_ip(hostname): callback((hostname, hostname), None) elif hostname in self._hosts: logging.debug('hit hosts: %s', hostname) ip = self._hosts[hostname] callback((hostname, ip), None) elif hostname in self._cache: logging.debug('hit cache: %s', hostname) ip = self._cache[hostname] callback((hostname, ip), None) else: if not is_valid_hostname(hostname): callback(None, Exception('invalid hostname: %s' % hostname)) return if hostname in self._cbs: # if hostname is under-resolving, just adds cb to self.add_callback( hostname, # callback list, doesn't send new request any more. callback) return try: self._send_req( hostname, DNSParser.QTYPE_A) # ipv4 first. if failed, send ipv6 req self._hostname_status[hostname] = DNSParser.QTYPE_A self.add_callback(hostname, callback) except InvalidDomainName as e: logging.warn("invalid hostname when build dns request: %s" % hostname)
def http2shadosocks(data): """ genearte http response and shadowsocks premble """ words = data.split() if len(words) < 3: raise HttpRequestError(400, "Bad request version") method, path, version = words[:3] https = True if method.upper() == "CONNECT" else False if version[:5] != 'HTTP/': raise HttpRequestError(400, "Bad request version (%r)" % version) # socks5 request format cmd = 0x01 # connect try: if https: host, port = path.split(":") else: result = urlparse.urlsplit(path) host = result.hostname if not host: logging.debug(data) raise HttpRequestError(400, "Bad request") port = result.port or 80 uri = result.path or "/" if result.query: data += (result.query + "\r\n") except IndexError: raise HttpRequestError(400, "Bad request") atyp = utils.is_ip(host) if not atyp: atyp = struct.pack("!B", 0x03) addr = struct.pack("!B", len(host)) + \ utils.to_bytes(host) elif atyp == socket.AF_INET: addr = utils.inet_pton(atyp, host) atyp = struct.pack("!B", 0x01) else: addr = utils.inet_pton(atyp, host) atyp = struct.pack("!B", 0x04) premble = atyp + addr + struct.pack("!H", int(port)) if not https: premble += data.replace(path, uri, 1) addr = (utils.to_str(host), port) http_response = "%s 200 Connection Established\r\n"\ "Proxy-Agent: myss\r\n"\ "\r\n" % version if https else "" return http_response, premble, addr
def _parse_hosts(self): etc_path = '/etc/hosts' if 'WINDIR' in os.environ: etc_path = os.environ['WINDIR'] + '/system32/drivers/etc/hosts' try: with open(etc_path, 'rb') as f: for line in f.readlines(): line = line.strip() parts = line.split() if len(parts) >= 2: ip = parts[0] if utils.is_ip(ip): for i in range(1, len(parts)): hostname = parts[i] if hostname: self._hosts[hostname] = ip except IOError: self._hosts['localhost'] = '127.0.0.1'
def _parse_resolv(self): self._servers = [] try: with open('/etc/resolv.conf', 'rb') as f: content = f.readlines() for line in content: line = line.strip() if line: if line.startswith(b'nameserver'): parts = line.split() if len(parts) >= 2: server = parts[1] if utils.is_ip(server) == socket.AF_INET: if type(server) != str: server = server.decode('utf8') self._servers.append(server) except IOError: pass if not self._servers: self._servers = ['8.8.4.4', '8.8.8.8']