def dns_system_resolve(host, qtypes=qtypes): now = time() try: if local_dnsservers: iplist = _dns_remote_resolve(host, local_dnsservers, timeout=2, qtypes=qtypes) else: if AAAA in qtypes: # getaddrinfo 在Windows 下无法并发,其它系统未知 if A in qtypes: iplist = list( set(ipaddr[4][0] for ipaddr in socket.getaddrinfo(host, None)) - GC.DNS_BLACKLIST) else: iplist = list( set(ipaddr[4][0] for ipaddr in socket.getaddrinfo( host, None, socket.AF_INET6)) - GC.DNS_BLACKLIST) else: iplist = list( set(socket.gethostbyname_ex(host)[-1]) - GC.DNS_BLACKLIST) except: iplist = None cost = int((time() - now) * 1000) logging.test('dns_system_resolve 已缓存:%s/%s,耗时:%s 毫秒,%s = %s', len(dns), dns.max_items, cost, host, iplist or '查询失败') return iplist
def dns_system_resolve(host, qtypes=qtypes): start = mtime() try: if dns_system_servers: iplist = _dns_udp_resolve(host, dns_system_servers, timeout=2, qtypes=qtypes) # getaddrinfo 在 Windows 下无法并发,其它系统未知 else: if AAAA not in qtypes: iplist = socket.gethostbyname_ex(host)[-1] elif A in qtypes: iplist = [ ipaddr[4][0] for ipaddr in socket.getaddrinfo(host, None) ] else: iplist = [ ipaddr[4][0] for ipaddr in socket.getaddrinfo( host, None, socket.AF_INET6) ] except: iplist = None cost = int((mtime() - start) * 1000) logging.test('%sdns_system_resolve 已缓存:%s/%s,耗时:%s 毫秒,%s = %s', address_string(iplist), len(dns), dns.max_items, cost, host, iplist or '查询失败') return iplist
def refreship(needgws=None, needcom=None): threading.current_thread().setName('Find GAE') #检测当前 IP 并搜索新的 IP network_test() if needgws is None: needgws = countneedgws() if needcom is None: needcom = countneedcom() gaeip = getgaeip(GC.IPLIST_MAP['google_gws'], needgws, needcom) #更新 IP if gaeip and gaeip['google_gws']: _refreship(gaeip) #更新 ip.use with open(GC.CONFIG_IPDB, 'wb') as f: write = writebytes(f.write) f.write(ipuse_h) for name in gaeip: write(name) f.write(b' = ') write('|'.join(GC.IPLIST_MAP[name])) f.write(b'\n') logging.test('GAE IP 更新完毕') if len(GC.IPLIST_MAP['google_gws']) < GC.FINDER_MINIPCNT: logging.warning('没有检测到足够数量符合要求的 GAE IP,请重新设定参数!') #更新完毕 updateip.running = False
def check_response(response, host): if response: if response.headers.get('Server') == 'cloudflare': if response.headers.get('X-Fetch-Status'): # ok / fail return 'ok' elif response.status == 429: # a burst rate limit of 1000 requests per minute. if lock.acquire(timeout=1): try: logging.warning('CFW %r 超限,暂停使用 30 秒', cfw_params.host) sleep(30) finally: lock.release() elif response.status == 302 or 400 <= response.status < 500 or \ response.status == 530 and dns_resolve(host): with lock: try: cfw_iplist.remove(response.xip[0]) logging.test('CFW 移除 %s', response.xip[0]) except: pass elif response.status in (500, 530): return 'ok' else: #打印收集未知异常状态 logging.warning('CFW %r 工作异常:%d %s', cfw_params.host, response.status, response.reason) return 'ok' else: logging.error('CFW %r 工作异常:%r 可能不是可用的 CloudFlare 节点', cfw_params.host, response.xip[0]) return 'retry' else: logging.test('CFW %r 连接失败', cfw_params.host) return 'fail'
def clear_node(node, pname): for k, v in node.items(): lname = '%s.%s' % (k, pname) if v is self.leaf: logging.test('移除直连域名:%s', lname) self.count_dm -= 1 else: clear_node(v, lname)
def dns_over_https_resolve(host, qtypes=qtypes): start = mtime() iplist = _dns_over_https_resolve(host, qtypes=qtypes) cost = int((mtime() - start) * 1000) logging.test('%sdns_over_https 已缓存:%s/%s,耗时:%s 毫秒,%s = %s', address_string(iplist), len(dns), dns.max_items, cost, host, iplist or '查询失败') return iplist
def dns_over_https_resolve(host, qtypes=qtypes): if not GC.DNS_OVER_HTTPS: return now = time() iplist = _dns_over_https_resolve(host, qtypes=qtypes) cost = int((time() - now) * 1000) logging.test('%sdns_over_https 已缓存:%s/%s,耗时:%s 毫秒,%s = %s', address_string(iplist), len(dns), dns.max_items, cost, host, iplist or '查询失败') return iplist
def dns_local_resolve(host, qtypes=qtypes): start = time() iplist = _dns_remote_resolve(host, GC.DNS_LOCAL_SERVERS, timeout=2, qtypes=qtypes) cost = int((time() - start) * 1000) logging.test('%sdns_local_resolve 已缓存:%s/%s,耗时:%s 毫秒,%s = %s', address_string(iplist), len(dns), dns.max_items, cost, host, iplist or '查询失败') return iplist
def dns_local_resolve(host, qtypes=qtypes): start = mtime() iplist = _dns_udp_resolve(host, dns_local_servers, timeout=2, qtypes=qtypes) cost = int((mtime() - start) * 1000) logging.test('%sdns_local_resolve 已缓存:%s/%s,耗时:%s 毫秒,%s = %s', address_string(iplist), len(dns), dns.max_items, cost, host, iplist or '查询失败') return iplist
def dns_remote_resolve(host, qtypes=qtypes): now = time() iplist = _dns_remote_resolve(host, GC.DNS_SERVERS, GC.DNS_BLACKLIST, timeout=2, qtypes=qtypes) cost = int((time() - now) * 1000) logging.test('%sdns_remote_resolve 已缓存:%s/%s,耗时:%s 毫秒,%s = %s', address_string(iplist), len(dns), dns.max_items, cost, host, iplist or '查询失败') return iplist
def _verify_callback(self, sock, cert, error_number, depth, ok): if ok and depth == 0 and not self.gws: self.match_hostname(sock, cert) elif error_number: if error_number in CertificateErrorTab: raise CertificateError(-1, (CertificateErrorTab[error_number](cert), depth)) else: logging.test('%s:%d-%d,%s', sock.get_servername(), depth, error_number, cert.get_subject()) elif depth and ok: #添加可信的中间证书,一定程度上有助于验证配置缺失的服务器 #下一步计划使用直接下载 OpenSSL._util.lib.X509_STORE_add_cert(self._cert_store, cert._x509) return ok
def get_wan_ipv4(): for url in GC.DNS_IP_API: response = None try: response = direct_opener.open(url, timeout=10) content = response.read().decode().strip() if isip(content): logging.test('当前 IPv4 公网出口 IP 是:%s', content) return content except: pass finally: if response: response.close() logging.warning('获取 IPv4 公网出口 IP 失败,请增加更多的 IP-API')
def add(self, domain): if not domain or not isinstance(domain, str) or \ len(domain) > 253 or \ self.add_ip(domain) or \ self.check_domain(domain) is None: return def clear_node(node, pname): for k, v in node.items(): lname = '%s.%s' % (k, pname) if v is self.leaf: logging.debug('移除直连域名:%s', lname) self.count_dm -= 1 else: clear_node(v, lname) if domain[0] == '.': domain = domain[1:] domain = domain.lower() names = domain.split('.') node = self.root while names: name = names.pop() try: child = node[name] except KeyError: if names: node[name] = child = {} else: node[name] = self.leaf break else: if child is self.leaf: lname = domain[domain.find(name):] logging.test('发现重复直连域名:%s < %s', domain, lname) return elif not names: node[name] = self.leaf lname = domain[domain.find(name):] logging.test('发现重复直连域名:%s > *.%s', domain, lname) clear_node(child, lname) node = child self.count_dm += 1
def load_domains(): global direct_domains_tree, DDTVer domains_tree = DomainsTree('直连/白名单') if os.path.exists(direct_domains): domains_tree.add_file(direct_domains) DDTVer = '%s, domains count: %d, IPs count: %d' % ( domains_tree.update, domains_tree.count_dm, domains_tree.count_ip) else: DDTVer = '列表文件未安装' buildscript = os.path.join(launcher_dir, 'builddomains.py') logging.warning('无法找到直连域名列表文件,Win 用户可用托盘工具下载更新,' '其它系统请运行脚本 %r 下载更新。', buildscript) logging.test('开始添加内置直连域名列表') for domain in direct_tlds: domains_tree.add(domain) logging.test('开始添加用户本地域名列表') for domain in GC.DNS_LOCAL_WHITELIST: domains_tree.add(domain) direct_domains_tree = domains_tree
def get_wan_ipv4(): if direct_opener is None: init_direct_opener() if dns_ip_api: apis = list(dns_ip_api) random.shuffle(apis) for url in apis: response = None try: response = direct_opener.open(url, timeout=10) content = response.read().decode().strip() if isipv4(content): logging.test('当前 IPv4 公网出口 IP 是:%s', content) return content except: pass finally: if response: response.close() logging.warning('获取 IPv4 公网出口 IP 失败,请增加更多的 IP-API')
def check_response(response, host): if response: if response.headers.get('Server') == 'cloudflare': # https://support.cloudflare.com/hc/zh-cn/articles/115003014512-4xx-客户端错误 # https://support.cloudflare.com/hc/zh-cn/articles/115003011431-Cloudflare-5XX-错误故障排除 # https://support.cloudflare.com/hc/zh-cn/articles/360029779472-Cloudflare-1XXX-错误故障排除 if response.headers.get('X-Fetch-Status'): # ok / fail return 'ok' content = None if response.status == 530: ce = response.headers.get('Content-Encoding') if ce and ce in decompress_readers: del response.headers['Content-Encoding'] response = decompress_readers[ce](response) content = response.read() response.fp = BytesIO(content) response.chunked = False response.length = len(content) if content and (cfw_530_ignore not in content or not dns_resolve(GC.CFW_WORKER)): return 'ok' if response.status == 429: # https://developers.cloudflare.com/workers/platform/limits#request # a burst rate limit of 1000 requests per minute. if lock.acquire(timeout=1): try: logging.warning('CFW %r 超限,暂停使用 30 秒', cfw_params.host) sleep(30) finally: lock.release() elif response.status in (502, 503, 504): sleep(5) elif remove_badip(response.xip[0]): logging.test('CFW %d 移除 %s', response.status, response.xip[0]) elif remove_badip(response.xip[0]): logging.error('CFW %r 工作异常:%r 可能不是可用的 CloudFlare 节点', cfw_params.host, response.xip[0]) return 'retry' else: logging.test('CFW %r 连接失败', cfw_params.host) return 'fail'
def check_response(response, host): if response: if response.headers.get('Server') == 'cloudflare': if response.headers.get('X-Fetch-Status'): # ok / fail return 'ok' elif response.status == 429: # https://developers.cloudflare.com/workers/about/limits/ # a burst rate limit of 1000 requests per minute. if lock.acquire(timeout=1): try: logging.warning('CFW %r 超限,暂停使用 30 秒', cfw_params.host) sleep(30) finally: lock.release() elif response.status == 302 or 400 <= response.status < 500 or \ response.status == 530 and dns_resolve(host): # https://support.cloudflare.com/hc/zh-cn/articles/360029779472-Cloudflare-1XXX-错误故障排除 # https://support.cloudflare.com/hc/zh-cn/articles/115003011431-Cloudflare-5XX-错误故障排除 with lock: try: cfw_iplist.remove(response.xip[0]) logging.test('CFW 移除 %s', response.xip[0]) except: pass elif response.status in (500, 530): return 'ok' else: #打印收集未知异常状态 logging.warning('CFW %r 工作异常:%d %s', cfw_params.host, response.status, response.reason) return 'ok' else: logging.error('CFW %r 工作异常:%r 可能不是可用的 CloudFlare 节点', cfw_params.host, response.xip[0]) return 'retry' else: logging.test('CFW %r 连接失败', cfw_params.host) return 'fail'
def _testallgaeip(): iplist = GC.IPLIST_MAP['google_gws'] if not iplist: testip.running = False return updateip() badip = set() timeout = gettimeout() timeoutl = timeout + 1000 logging.test('连接测试开始,超时:%d 毫秒', timeout) network_test() testip.queobj.queue.clear() for ip in iplist: if ip in GC.IPLIST_MAP['google_com']: _timeout = timeoutl else: _timeout = timeout thread.start_new_thread( http_gws._create_ssl_connection, ((ip, 443), getcachekey(), None, testip.queobj, _timeout / 1000)) for _ in iplist: result = testip.queobj.get() if isinstance(result, Exception): ip = result.xip[0] logging.warning('测试失败 %s:%s' % ('.'.join(x.rjust(3) for x in ip.split('.')), result.args[0])) badip.add(ip) else: logging.test('测试连接 %s: %d' % ('.'.join( x.rjust(3) for x in result[0].split('.')), int(result[1] * 1000))) #删除 bad IP nbadip = len(badip) if nbadip > 0: for ip in badip: removeip(ip) logging.test('连接测试完毕%s', ',Bad IP 已删除' if nbadip > 0 else '') testip.lastactive = testip.lasttest = time() testip.running = False #刷新开始 needgws = countneedgws() needcom = countneedcom() if needgws > 0 or needcom > 0: updateip(needgws, needcom)
with open('/etc/resolv.conf', 'r') as fp: return re.findall(r'(?m)^nameserver\s+(\S+)', fp.read()) else: import sys logging.warning('get_dnsserver_list 失败:不支持 "%s-%s" 平台', sys.platform, os.name) return [] local_dnsservers = set(ip for ip in get_dnsserver_list() if isip(ip)) if '127.0.0.1' in local_dnsservers and '::1' in local_dnsservers: #视为同一个本地服务器,大多数情况下这是正确地 local_dnsservers.remove('::1') local_dnsservers = tuple((server, 53) for server in local_dnsservers) if local_dnsservers: logging.test('已读取系统当前 DNS 设置:%r', local_dnsservers) else: logging.warning('读取系统当前 DNS 设置失败') def dns_system_resolve(host, qtypes=qtypes): start = time() try: if local_dnsservers: iplist = _dns_remote_resolve(host, local_dnsservers, timeout=2, qtypes=qtypes) # getaddrinfo 在 Windows 下无法并发,其它系统未知 else: if AAAA not in qtypes:
def PRINT(fmt, *args, **kwargs): #logging.info(strlog) logging.test('[%s] %s' % (threading.current_thread().name, fmt), *args, **kwargs)
with open('/etc/resolv.conf', 'r') as fp: return re.findall(r'(?m)^nameserver\s+(\S+)', fp.read()) else: import sys logging.warning('get_dnsserver_list 失败:不支持 "%s-%s" 平台', sys.platform, os.name) return [] dns_system_servers = set(ip for ip in get_dnsserver_list() if isip(ip)) if '127.0.0.1' in dns_system_servers and '::1' in dns_system_servers: #视为同一个本地服务器,大多数情况下这是正确地 dns_system_servers.remove('::1') dns_system_servers = tuple((server, 53) for server in dns_system_servers) if dns_system_servers: logging.test('已读取系统当前 DNS 设置:%r', dns_system_servers) else: logging.warning('读取系统当前 DNS 设置失败') def dns_system_resolve(host, qtypes=qtypes): start = mtime() try: if dns_system_servers: iplist = _dns_udp_resolve(host, dns_system_servers, timeout=2, qtypes=qtypes) # getaddrinfo 在 Windows 下无法并发,其它系统未知 else: if AAAA not in qtypes:
def __fetchlet(self, range_queue, data_queue, threadorder): headers = {k.title(): v for k, v in self.headers.items()} #headers['Connection'] = 'close' while True: try: with self.tLock: if self.lastupdate != ip_manager_gae.last_update: self.lastupdate = ip_manager_gae.last_update self.iplist = GC.IPLIST_MAP['google_gae'].copy() noerror = True response = None starttime = None appid = None if self._stopped: return try: if self.response: response = self.response self.response = None start, end = self.firstrange else: appid = get_appid() if self._last_app_status.get(appid, 200) >= 500: sleep(2) start, end = range_queue.get(timeout=1) headers['Range'] = 'bytes=%d-%d' % (start, end) while start - self.expect_begin > self.threads * self.delaysize and \ data_queue.qsize() * self.bufsize > 3 * self.threads * self.delaysize: if self._stopped: return sleep(0.1) if appid: response = gae_urlfetch(self.command, self.url, headers, self.payload, appid, getfast=self.timeout) if response: if appid: self._last_app_status[appid] = response.app_status xip = response.xip[0] if xip in self.iplist: realstart = start starttime = time() else: range_queue.put((start, end)) noerror = False continue except queue.Empty: appid = None return except LimiterFull: range_queue.put((start, end)) sleep(2) continue except Exception as e: logging.warning('%s Response %r in __fetchlet', self.address_string(response), e) range_queue.put((start, end)) continue if self._stopped: return if not response: logging.warning('%s RangeFetch %s 没有响应,重试', self.address_string(response), headers['Range']) range_queue.put((start, end)) elif response.app_status == 503: if appid: mark_badappid(appid) range_queue.put((start, end)) noerror = False elif response.app_status != 200: logging.warning('%s Range Fetch "%s %s" %s 返回 %s', self.address_string(response), self.command, self.url, headers['Range'], response.app_status) range_queue.put((start, end)) noerror = False elif response.getheader('Location'): self.url = urljoin(self.url, response.getheader('Location')) logging.info('%s RangeFetch Redirect(%r)', self.address_string(response), self.url) range_queue.put((start, end)) elif 200 <= response.status < 300: content_range = response.getheader('Content-Range') if not content_range: logging.warning( '%s RangeFetch "%s %s" 返回 Content-Range=%r: response headers=%r', self.address_string(response), self.command, self.url, content_range, response.getheaders()) range_queue.put((start, end)) continue content_length = int( response.getheader('Content-Length', 0)) logging.test('%s >>>> %s: 线程 %s %s %s', self.address_string(response), self.host, threadorder, content_length, content_range) try: data = response.read(self.bufsize) while data: data_queue.put((start, data)) start += len(data) if self._stopped: return if (start - realstart) / ( time() - starttime) < self.lowspeed: #移除慢速 ip if self.delable: with self.tLock: if xip in self.iplist and len( self.iplist) > self.minip: self.iplist.remove(xip) logging.warning( '%s RangeFetch 移除慢速 ip %s', self.address_string(), xip) noerror = False break else: data = response.read(self.bufsize) except Exception as e: noerror = False logging.warning('%s RangeFetch "%s %s" %s 失败:%r', self.address_string(response), self.command, self.url, headers['Range'], e) if self._stopped: return if start < end + 1: logging.warning('%s RangeFetch "%s %s" 重试 %s-%s', self.address_string(response), self.command, self.url, start, end) range_queue.put((start, end)) continue logging.test('%s >>>> %s: 线程 %s 成功接收到 %d 字节', self.address_string(response), self.host, threadorder, start) else: logging.error('%s RangeFetch %r 返回 %s', self.address_string(response), self.url, response.status) range_queue.put((start, end)) noerror = False except Exception as e: logging.exception('%s RangeFetch._fetchlet 错误:%r', self.address_string(), e) noerror = False raise finally: if appid: qGAE.put(True) if response: response.close() if noerror: #放入套接字缓存 ssl_connection_cache['google_gae|:443'].append( (time(), response.sock)) elif self.delable: with self.tLock: if xip in self.iplist and len( self.iplist) > self.minip: self.iplist.remove(xip) logging.warning('%s RangeFetch 移除故障 ip %s', self.address_string(response), xip) if noerror: sleep(0.1)
def import_ca(certfile=None): if certfile is None: certfile = ca_certfile with open(certfile, 'rb') as fp: certdata = fp.read().strip() try: begin = b'-----BEGIN CERTIFICATE-----' end = b'-----END CERTIFICATE-----' if certdata.startswith(begin) and certdata.endswith(end): certdata = binascii.a2b_base64(certdata[len(begin):-len(end)]) commonname = crypto.load_certificate(crypto.FILETYPE_ASN1, certdata).get_subject().CN except Exception as e: logging.error('load_certificate(certfile=%r) 失败:%s', certfile, e) return -1 if sys.platform.startswith('win'): import ctypes import ctypes.wintypes class CERT_CONTEXT(ctypes.Structure): _fields_ = [ ('dwCertEncodingType', ctypes.wintypes.DWORD), ('pbCertEncoded', ctypes.POINTER(ctypes.wintypes.BYTE)), ('cbCertEncoded', ctypes.wintypes.DWORD), ('pCertInfo', ctypes.c_void_p), ('hCertStore', ctypes.c_void_p), ] X509_ASN_ENCODING = 0x1 CERT_STORE_ADD_ALWAYS = 4 CERT_STORE_PROV_SYSTEM = 10 CERT_STORE_OPEN_EXISTING_FLAG = 0x4000 CERT_SYSTEM_STORE_CURRENT_USER = 1 << 16 CERT_SYSTEM_STORE_LOCAL_MACHINE = 2 << 16 CERT_FIND_SUBJECT_STR = 8 << 16 | 7 crypt32 = ctypes.windll.crypt32 ca_exists = False store_handle = None pCertCtx = None for store in (CERT_SYSTEM_STORE_LOCAL_MACHINE, CERT_SYSTEM_STORE_CURRENT_USER): try: store_handle = crypt32.CertOpenStore( CERT_STORE_PROV_SYSTEM, 0, None, CERT_STORE_OPEN_EXISTING_FLAG | store, 'root') if not store_handle: if store == CERT_SYSTEM_STORE_CURRENT_USER and not ca_exists: logging.warning('导入证书时发生错误:无法打开 Windows 系统证书仓库') return -1 else: continue pCertCtx = crypt32.CertFindCertificateInStore( store_handle, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR, commonname, None) while pCertCtx: certCtx = CERT_CONTEXT.from_address(pCertCtx) _certdata = ctypes.string_at(certCtx.pbCertEncoded, certCtx.cbCertEncoded) if _certdata == certdata: ca_exists = True logging.test("证书 %r 已经存在于 Windows 系统证书仓库", commonname) else: cert = crypto.load_certificate(crypto.FILETYPE_ASN1, _certdata) if cert.get_subject().CN == commonname: ret = crypt32.CertDeleteCertificateFromStore( crypt32.CertDuplicateCertificateContext( pCertCtx)) if ret == 1: logging.test("已经移除无效的 Windows 证书 %r", commonname) elif ret == 0 and store == CERT_SYSTEM_STORE_LOCAL_MACHINE: logging.warning( '无法从 Windows 计算机账户删除无效证书 %r,请用管理员权限重新运行 GotoX,或者手动删除', commonname) pCertCtx = crypt32.CertFindCertificateInStore( store_handle, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR, commonname, pCertCtx) #只导入到当前用户账户,无需管理员权限 if store == CERT_SYSTEM_STORE_CURRENT_USER and \ not ca_exists and \ crypt32.CertAddEncodedCertificateToStore(store_handle, X509_ASN_ENCODING, certdata, len(certdata), CERT_STORE_ADD_ALWAYS, None) == 1: ca_exists = True msg = ('已经将 GotoX CA 证书导入到系统证书仓库,请重启浏览器。\n\n' '如果你使用的是 Firefox,且导入过老旧证书,请在高级设置中手动删除,' '再重启浏览器,设置好代理后访问以下网址即可导入新证书:\n\n' '\thttp://gotox.go') title = 'GotoX 提示' ctypes.windll.user32.MessageBoxW(None, msg, title, 48) except Exception as e: logging.warning('导入证书时发生错误:%r', e) if isinstance(e, OSError): store_handle = None finally: if pCertCtx: crypt32.CertFreeCertificateContext(pCertCtx) pCertCtx = None if store_handle: crypt32.CertCloseStore(store_handle, 0) store_handle = None return 0 if ca_exists else -1 #放弃其它系统 return 0 if sys.platform == 'darwin': return os.system(( 'security find-certificate -a -c "%s" | grep "%s" >/dev/null || security add-trusted-cert -d -r trustRoot -k "/Library/Keychains/System.keychain" "%s"' % (commonname, commonname, certfile.decode('utf-8'))).encode('utf-8')) if sys.platform.startswith('linux'): import platform platform_distname = platform.dist()[0] if platform_distname == 'Ubuntu': pemfile = "/etc/ssl/certs/%s.pem" % commonname new_certfile = "/usr/local/share/ca-certificates/%s.crt" % commonname if not os.path.exists(pemfile): return os.system('cp "%s" "%s" && update-ca-certificates' % (certfile, new_certfile)) elif any( os.path.isfile('%s/certutil' % x) for x in os.environ['PATH'].split(os.pathsep)): return os.system( 'certutil -L -d sql:$HOME/.pki/nssdb | grep "%s" || certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n "%s" -i "%s"' % (commonname, commonname, certfile)) else: logging.warning( 'please install *libnss3-tools* package to import GotoX root ca' ) return 0
def testonegaeip(): with tLock: if updateip.running or testip.running: return testip.running = 1 iplist = GC.IPLIST_MAP['google_gws'] if not iplist: testip.running = False return updateip() ip = iplist[-1] timeout = gettimeout() if ip in GC.IPLIST_MAP['google_com'] and len( GC.IPLIST_MAP['google_com']) < len(iplist): iplist.insert(0, iplist.pop()) testip.running = False return badip = False statistics = finder.statistics network_test() testip.queobj.queue.clear() http_gws._create_ssl_connection((ip, 443), getcachekey(), None, testip.queobj, timeout / 1000) result = testip.queobj.get() if isinstance(result, Exception): logging.warning( '测试失败(超时:%d 毫秒)%s:%s,Bad IP 已删除' % (timeout, '.'.join(x.rjust(3) for x in ip.split('.')), result.args[0])) removeip(ip) badip = True ipdict, ipdicttoday = statistics if ip in ipdict: good, bad = ipdict[ip] #失败次数超出预期,设置 -1 表示删除 s = bad / max(good, 1) if s > 2 or (s > 0.4 and bad > 10): ipdict[ip] = ipdicttoday[ip] = -1, 0 else: ipdict[ip] = good, bad + 1 if ip in ipdicttoday: good, bad = ipdicttoday[ip] else: good = bad = 0 ipdicttoday[ip] = good, bad + 1 #加入统计 else: ipdict[ip] = ipdicttoday[ip] = 0, 1 else: logging.test('测试连接(超时:%d 毫秒)%s: %d' % (timeout, '.'.join( x.rjust(3) for x in result[0].split('.')), int(result[1] * 1000))) iplist.insert(0, iplist.pop()) #调高 com 权重 addn = 2 if ip in GC.IPLIST_MAP['google_com'] else 1 baddict = finder.baddict for ipdict in statistics: if ip in ipdict: good, bad = ipdict[ip] good += addn ipdict[ip] = good, bad #当天通过测试次数达到条件后重置容忍次数 if ipdict is statistics[1] and ip in baddict: s = bad / max(good, 1) if s < 0.1: del baddict[ip] #加入统计 else: ipdict[ip] = addn, 0 savestatistics() testip.lasttest = time() testip.running = False #刷新开始 needgws = countneedgws() needcom = countneedcom() if needgws > 0 or needcom > 0: updateip(needgws, needcom) elif badip: testonegaeip()