def pick_proxy_and_forward(client): if lan_ip.is_lan_traffic(client.src_ip, client.dst_ip): try: DIRECT_PROXY.forward(client) except ProxyFallBack: pass return if client.dst_ip in fqdns.BUILTIN_WRONG_ANSWERS(): LOGGER.error('[%s] destination is GFW wrong answer' % repr(client)) NONE_PROXY.forward(client) return if CHINA_PROXY and china_ip.is_china_ip(client.dst_ip): try: CHINA_PROXY.forward(client) except ProxyFallBack: pass return for i in range(3): proxy = pick_proxy(client) while proxy: if not client.host: break elif 'PUBLIC' in proxy.flags and any(fnmatch.fnmatch(client.host, host) for host in NO_PUBLIC_PROXY_HOSTS): client.tried_proxies[proxy] = 'skip PUBLIC' else: break proxy = pick_proxy(client) proxy = proxy or DIRECT_PROXY if is_direct_access_disabled() and isinstance(proxy, DirectProxy): # try disabled LOGGER.info('[%s] no proxy available, and DIRECT has been disabled' % repr(client)) return if 'DIRECT' in proxy.flags: LOGGER.debug('[%s] picked proxy: %s' % (repr(client), repr(proxy))) else: LOGGER.info('[%s] picked proxy: %s' % (repr(client), repr(proxy))) try: proxy.forward(client) return except ProxyFallBack, e: LOGGER.error('[%s] fall back to other proxy due to %s: %s' % (repr(client), e.reason, repr(proxy))) client.tried_proxies[proxy] = e.reason except NotHttp: client.tried_proxies[proxy] = 'not http' continue
if 'DIRECT' in proxy.flags: LOGGER.debug('[%s] picked proxy: %s' % (repr(client), repr(proxy))) else: LOGGER.info('[%s] picked proxy: %s' % (repr(client), repr(proxy))) try: proxy.forward(client) return except ProxyFallBack, e: LOGGER.error('[%s] fall back to other proxy due to %s: %s' % (repr(client), e.reason, repr(proxy))) client.tried_proxies[proxy] = e.reason except NotHttp: client.tried_proxies[proxy] = 'not http' continue LOGGER.error('[%s] fall back to direct after too many retries: %s' % (repr(client), client.tried_proxies)) try: DIRECT_PROXY.forward(client) except ProxyFallBack: pass def pick_proxy(client): if mandatory_proxies: available_mandatory_proxies = [p for p in mandatory_proxies if not p.died and p not in client.tried_proxies] if available_mandatory_proxies: return random.choice(available_mandatory_proxies) raise Exception('[%s] no proxy to handle' % repr(client)) if not client.peeked_data: ins, _, errors = select.select([client.downstream_sock], [], [client.downstream_sock], 0.1) if errors: LOGGER.error('[%s] peek data failed' % repr(client)) return DIRECT_PROXY, ''