def update_pac(self): if settings.get("proxy_mode", "off") != "pac": return host = "http://%(local_address)s:%(local_port)d" % settings url = host + ProxyAutoConfig.URI logging.info("pac url: %s" % url) ethname = settings.get("eth", "eth0") cmd = "networksetup -setautoproxyurl %s %s" % (ethname, url) os.system(cmd)
def load(cls): path = settings["pac"] with open(path, "r") as f: data = f.read() host = settings["local_address"] socks5_port = settings.get("local_port", 1080) http_port = settings.get("local_http_port", 1081) proxy = ' proxy = "PROXY %s:%d; SOCKS %s:%d; ";\n' %\ (host, http_port, host, socks5_port) data = re.sub("proxy *= *[\s\S]+?\n", proxy, data, 1) cls.content = data cls.URI = "/pac?t=%d" % int(time.time()) logging.info("reload pac file : %s" % path)
def on_reload(self, old): change = lambda key: old.get(key) != settings.get(key) if change("pac"): Pac.load() if change("proxy_mode"): from ss.config import set_proxy_mode set_proxy_mode()
def update_pac(self): if settings.get("proxy_mode", "off") != "pac": return try: host = "http://%(local_address)s:%(local_port)d" % settings url = host + ProxyAutoConfig.URI logging.info("pac url: %s" % url) List = INTERNET_PER_CONN_OPTION_LIST() nSize = c_ulong(sizeof(INTERNET_PER_CONN_OPTION_LIST)) option_count = 3 Option = (INTERNET_PER_CONN_OPTION * option_count)() Option[0].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL Option[0].Value.pszValue = create_unicode_buffer(url) Option[1].dwOption = INTERNET_PER_CONN_FLAGS Option[1].Value.dwValue = PROXY_TYPE_AUTO_PROXY_URL Option[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS Option[2].Value.pszValue = create_unicode_buffer( self.PROXY_OVERRIDE) List.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LIST) List.pszConnection = None List.dwOptionCount = option_count List.dwOptionError = 0 List.pOptions = Option self.inte_set_opt(None, INTERNET_OPTION_PER_CONNECTION_OPTION, byref(List), nSize) self.inte_set_opt(None, INTERNET_OPTION_SETTINGS_CHANGED, None, 0) self.inte_set_opt(None, INTERNET_OPTION_REFRESH, None, 0) except Exception as e: logging.warn("fail to update pac url: %s" % e)
def clear_log(textarea): logfile = settings.get("log_file") or os.path.join(basedir, "ss.log") log = textarea.get("1.0", tk.END) log = utils.to_bytes(log) with open(logfile, "ab") as f: f.write(log) textarea.delete("1.0", tk.END)
def shift(self, mode): if mode not in self.MODE: logging.warn("invalid proxy mode %s" % mode) return eth = settings.get("eth", "eth0") if mode == self.MODE_OFF: cmd = "\n".join([ "networksetup -setwebproxystate %s off" % eth, "networksetup -setautoproxystate %s off" % eth, "networksetup -setsocksfirewallproxystate %s off" % eth, "networksetup -setsecurewebproxystate %s off" % eth, ]) logging.warn("set proxy mode to `off`") elif mode == self.MODE_PAC: host = "http://%(local_address)s:%(local_port)d" % settings url = host + ProxyAutoConfig.URI logging.info("set proxy mode to `pac`, pac url: %s" % url) cmd = "\n".join([ "networksetup -setautoproxyurl %s %s" % (eth, url), "networksetup -setwebproxystate %s off" % eth, "networksetup -setsocksfirewallproxystate %s off" % eth, "networksetup -setsecurewebproxystate %s off" % eth, ]) else: logging.warn("set proxy mode to `global`") socks5 = "networksetup -setsocksfirewallproxy %s %s %d" % ( eth, settings["local_address"], settings["local_port"]) cmd = "\n".join([ socks5, "networksetup -setwebproxystate %s off" % eth, "networksetup -setautoproxystate %s off" % eth, "networksetup -setsecurewebproxystate %s off" % eth, ]) os.system(cmd)
def run_local(io_loop): if not io_loop: io_loop = IOLoop.current() try: sa = settings['local_address'], settings['local_port'] logging.info("starting local at %s:%d" % sa) dns_resolver = DNSResolver(io_loop) tcp_server = tcphandler.ListenHandler(io_loop, sa, tcphandler.LocalConnHandler, dns_resolver) udp_server = udphandler.ListenHandler(io_loop, sa, udphandler.ConnHandler, 1, dns_resolver) # 1 means local servers = [dns_resolver, tcp_server, udp_server] if settings.get("local_http_port"): http_sa = settings['local_address'], settings['local_http_port'] logging.info("starting local http tunnel at %s:%d" % http_sa) http_tunnel = tcphandler.ListenHandler( io_loop, http_sa, tcphandler.HttpLocalConnHandler, dns_resolver) servers.append(http_tunnel) for server in servers: server.register() wrapper.onexit(server.destroy) wrapper.register(['SIGQUIT', 'SIGINT', 'SIGTERM'], wrapper.exec_exitfuncs) wrapper.exec_startfuncs(None, None) io_loop.run() except Exception as e: logging.error(e, exc_info=True) sys.exit(1)
def run(io_loop=None): cli.parse_cli() # if not io_loop: # io_loop = IOLoop.current() subcmd = settings.get("subcmd") handlers = {"local": run_local, "server": run_server} return handlers[subcmd](io_loop)
def run_server(io_loop): sa = settings['server'], settings['server_port'] logging.info("starting server at %s:%d" % sa) dns_resolver = DNSResolver(io_loop) tcp_server = tcphandler.ListenHandler(io_loop, sa, tcphandler.RemoteConnHandler, dns_resolver) udp_server = udphandler.ListenHandler(io_loop, sa, udphandler.ConnHandler, 0, dns_resolver) servers = [tcp_server, udp_server, dns_resolver] def start(): try: for server in servers: server.register() wrapper.onexit(server.destroy) io_loop = IOLoop.current() io_loop.run() except Exception as e: logging.error(e, exc_info=True) sys.exit(1) print(settings) workers = settings.get("workers", 1) is_daemon = settings["fork"] children = [] if not is_daemon: for _ in range(workers - 1): rpid = os.fork() if rpid: print("sub process %d forked" % rpid) children.append(rpid) else: logging.info("proxy start in sub process %d " % os.getpid()) return start() if children: wrapper.register(['SIGQUIT', 'SIGINT', 'SIGTERM'], partial(on_master_exit, children=children)) logging.info("proxy start in master process %d" % os.getpid()) return start() else: for _ in range(workers): rpid = os.fork() if rpid: print("sub process %d forked" % rpid) children.append(rpid) else: logging.info("proxy start in sub process %d " % os.getpid()) return start() if settings["pid_file"]: with open(settings["pid_file"], "w") as f: sc = [str(pid) for pid in children] f.write(" ".join(sc)) print("all pids are written in pid file %s" % settings["pid_file"]) print("%d workers spwaned, now master process exit" % workers) sys.exit(0)
def parse_cli(args=None): cmd = Command() cfg = cmd.parse(args) if "rhost" in cfg: cfg["server"], cfg["server_port"] = cfg["rhost"] del cfg["rhost"] settings.update(cfg) settings["fork"] = check_fork(settings.get("fork", False)) if settings["fork"] and not settings["log_file"]: settings["log_file"] = DEFAULT_LOGFILE config_logging(cfg) return cfg
def bind(self, sa): addrs = socket.getaddrinfo(sa[0], sa[1], 0, socket.SOCK_STREAM, socket.SOL_TCP) if not addrs: raise RuntimeError("can't get addrinfo for %s:%d" % tuple(sa)) af, socktype, proto, canonname, sa_ = addrs[0] server_socket = socket.socket(af, socktype, proto) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind(sa_) server_socket.setblocking(False) if settings.get("fast_open", False): try: server_socket.setsockopt(socket.SOL_TCP, 23, 5) except socket.error: logging.warning("fast open is not available!!") server_socket.listen(self.BACKLOG) return server_socket
def on_exit(self): path = settings.get("dns_cache") if not path: # local return path = os.path.expanduser(path) keys = self._cache._cache.keys() dns_dict = dict() for k in keys: dns_dict[k] = self._cache[k] f = open(path, "w") try: import fcntl fcntl.lockf(f.fileno(), fcntl.LOCK_EX) except ImportError: pass finally: json.dump(dns_dict, f) f.close()
def last_cache(self): dns_cache_file = settings.get("dns_cache") if not dns_cache_file: # local return path = os.path.expanduser(dns_cache_file) folder = os.path.dirname(path) if not os.path.exists(folder): os.makedirs(folder) if not os.path.exists(path): with open(path, "w") as f: f.write('{}') return try: with open(path, "r") as f: cache = json.load(f) for k in cache: self._cache[k] = cache[k] except Exception: logging.warn("fail to load dns cache") return
def fmt(self): if not settings.get("config_file"): return None return self.inteval, self.priority, self.run, tuple()
def get_pacfile(): default = os.path.join(basedir, DEFAULT_PAC) default = os.path.abspath(default) path = settings.get("pac", default) return os.path.abspath(path)
def _exclusive_host(self, host): if self.ISLOCAL: return True iplist = settings.get("forbidden_ip", []) return (host in iplist)