def run(self): CgfwUtil.mkDirAndClear(self.param.tmpDir) try: sys.stdout = StdoutRedirector(os.path.join(self.param.tmpDir, "fpemud-cgfw.out")) sys.stderr = sys.stdout logging.getLogger().addHandler(logging.StreamHandler(sys.stderr)) logging.getLogger().setLevel(logging.INFO) # check configuration if len(CgfwCommon.getCgfwCfgList(self.param.etcDir)) == 0: raise Exception("no cgfw config file") # create main loop DBusGMainLoop(set_as_default=True) self.param.mainloop = GLib.MainLoop() self.param.dbusMainObject = DbusMainObject(self.param, self) # write pid file with open(os.path.join(self.param.tmpDir, "fpemud-cgfw.pid"), "w") as f: f.write(str(os.getpid())) # modify dns server configuration with open("/etc/resolv.conf", "r") as f: self.resloveFileContent = f.read() self.dnsmasqProc = self._runDnsmasq() with open("/etc/resolv.conf", "w") as f: f.write("# Generated by fpemud-cgfw\n") f.write("nameserver 127.0.0.1\n") logging.info("DNS resolution path modified.") # run vpn client GObject.timeout_add_seconds(0, self._timeoutCallback) # start main loop logging.info("Mainloop begins.") GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGINT, self._sigHandlerINT, None) GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM, self._sigHandlerTERM, None) GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGHUP, self._sigHandlerHUP, None) GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGUSR1, self._sigHandlerUSR1, None) self.param.mainloop.run() logging.info("Mainloop exits.") finally: if self.vpnClientPidWatch is not None: GLib.source_remove(self.vpnClientPidWatch) if self.vpnClientProc is not None: self.vpnClientProc.terminate() self.vpnClientProc.wait() # revert dns resolution path if self.resloveFileContent is not None: with open("/etc/resolv.conf", "w") as f: f.write(self.resloveFileContent) if self.dnsmasqProc is not None: self.dnsmasqProc.terminate() self.dnsmasqProc.wait() logging.shutdown() shutil.rmtree(self.param.tmpDir)
def _runVpnClient(self): assert self.vpnClientProc is None and self.vpnClientPidWatch is None # randomly select a config cgfwCfg = random.choice(CgfwCommon.getCgfwCfgList(self.param.etcDir)) # start vpn client process logging.info("CGFW VPN %s establishing." % (cgfwCfg.name)) if cgfwCfg.vtype == "pptp": cmd = "/usr/sbin/pppd call %s nodetach" % (cgfwCfg.name) self.vpnClientProc = subprocess.Popen(cmd, shell=True, universal_newlines=True) else: assert False # wait for the vpn interface time.sleep(0.1) while not CgfwUtil.interfaceExists(cgfwCfg.interface): if self.vpnClientProc.poll() is not None: self.vpnClientProc = None logging.info("CGFW VPN %s failed to establish, retry in %d seconds." % (cgfwCfg.name, self.param.retryTimeout)) GObject.timeout_add_seconds(self.param.retryTimeout, self._timeoutCallback) return time.sleep(1.0) # add routes for ip in self.param.nameServerList: CgfwUtil.shell("/bin/route add -host %s dev %s" % (ip, cgfwCfg.interface), "stdout") for net in CgfwCommon.getPrefixList(self.param.gfwDir): r = net.with_netmask.split("/") ip = r[0] mask = r[1] CgfwUtil.shell("/bin/route add -net %s netmask %s dev %s" % (ip, mask, cgfwCfg.interface), "stdout") # add dns server # dbusObj = dbus.SystemBus().get_object('org.freedesktop.resolve1', '/org/freedesktop/resolve1') # ifid = CgfwUtil.getInterfaceIfIndex(cgfwCfg.interface) # dbusObj.SetLinkDNS(ifid, [CgfwUtil.ip2ipar("8.8.8.8"), CgfwUtil.ip2ipar("8.8.4.4")], dbus_interface="org.freedesktop.resolve1.Manager") # logging.info("CGFW DNS server installed.") # watch vpn client process # bad things happen if the vpn process terminates before this operation self.vpnClientPidWatch = GLib.child_watch_add(self.vpnClientProc.pid, self._childWatchCallback) self.curCgfwCfg = cgfwCfg logging.info("CGFW VPN %s established." % (cgfwCfg.name)) self.param.dbusMainObject.VpnConnected(self.bDataChanged)
def cmdUpdate(self): CgfwUtil.printInfo("Checking IP ranges:") if True: prefixList = CgfwCommon.getPrefixList(self.param.gfwDir) CgfwUtil.printInfoNoNewLine(" Checking private network...") priList = CgfwUtil.getReservedIpv4NetworkList() for net in prefixList: for net2 in priList: if net.overlaps(net2): raise CgfwCmdException("GFWed prefix %s overlaps private network %s" % (net.with_prefixlen, net2.with_prefixlen)) print("Done.") CgfwUtil.printInfoNoNewLine(" Checking non-GFWed network...") try: lcmList = CgfwCommon.getLatestChinaMainLandIpv4NetworkList() for net in prefixList: for net2 in lcmList: if net.overlaps(net2): raise CgfwCmdException("GFWed prefix %s overlaps non-GFWed network %s" % (net.with_prefixlen, net2.with_prefixlen)) print("Done.") except Exception as e: if isinstance(e, CgfwCmdException): raise else: print("Failed, but however it's better to continue.") CgfwUtil.printInfo("Modifying configuration files:") for cgfwCfg in CgfwCommon.getCgfwCfgList(self.param.etcDir): if cgfwCfg.vtype == "pptp": self._syncPptpVpnScript(cgfwCfg) else: assert False # send signal to daemon process if exists try: with open(os.path.join(self.param.tmpDir, "fpemud-cgfw.pid")) as f: os.kill(int(f.read()), signal.SIGHUP) except: pass
def cmdCheck(self): for cgfwCfg in CgfwCommon.getCgfwCfgList(self.param.etcDir): if cgfwCfg.vtype == "pptp": self._checkPptpVpn(cgfwCfg) else: assert False