Пример #1
0
 def _createNewPrefix(self, excludeList):
     item = None
     while True:
         item = ("192.168.%d.0" % (random.randint(0, 255)), "255.255.255.0")
         if WrtUtil.prefixConflictWithPrefixList(
                 item, self.defaultExcludePrefixList):
             continue
         if WrtUtil.prefixConflictWithPrefixList(item, excludeList):
             continue
         break
     assert item is not None
     return item
Пример #2
0
    def refresh_host(self, source_id, ip_data_dict):
        fn = os.path.join(self.hostsDir, source_id)
        itemDict = WrtUtil.dnsmasqHostFileToDict(fn)

        itemDict2 = dict()
        for ip, data in ip_data_dict.items():
            if "hostname" in data:
                itemDict2[ip] = data["hostname"]

        if itemDict != itemDict2:
            WrtUtil.dictToDnsmasqHostFile(itemDict2, fn)
            self.dnsmasqProc.send_signal(signal.SIGHUP)
Пример #3
0
    def remove_host(self, source_id, ip_list):
        fn = os.path.join(self.hostsDir, source_id)
        itemDict = WrtUtil.dnsmasqHostFileToOrderedDict(fn)
        bChanged = False

        for ip in ip_list:
            if ip in itemDict:
                del itemDict[ip]
                bChanged = True

        if bChanged:
            WrtUtil.dictToDnsmasqHostFile(itemDict, fn)
            self.dnsmasqProc.send_signal(signal.SIGHUP)
Пример #4
0
    def setExcludePrefixList(self, key, prefixList):
        """Returns True means conflict is found and solved, reboot needed"""

        ret = False

        # get conflict items
        idxList = []
        for i in range(0, len(self.prefixList)):
            if WrtUtil.prefixConflictWithPrefixList(self.prefixList[i],
                                                    prefixList):
                idxList.append(i)
                if self.prefixList[i][2]:
                    ret = True  # program restart needed
                break

        # get a reference list for create new prefix
        refList = []
        for i in range(0, len(self.prefixList)):
            if i not in idxList:
                refList.append(self.prefixList[i])

        # create new prefix for conflict items
        for i in idxList:
            pip, pmask = self._createNewPrefix(refList + prefixList)
            self.prefixList[i] = (pip, pmask, False)

        self.excludePrefixDict[key] = prefixList
        self._save()
        return ret
Пример #5
0
    def __init__(self, param):
        self.param = param
        self.logger = logging.getLogger(self.__module__ + "." + self.__class__.__name__)

        self.wanConnPluginApi = None
        self.wanConnPlugin = None

        self.ifconfigDict = dict()      # dict<ifname,ifconfig>

        try:
            cfgfile = os.path.join(self.param.etcDir, "wan-connection.json")
            if os.path.exists(cfgfile):
                cfgObj = WrtUtil.loadJsonEtcCfg(cfgfile)
                self.wanConnPluginApi = WanConnectionPluginApi(self, cfgObj["plugin"])
                self.wanConnPlugin = self.param.pluginHub.getPlugin("wconn", cfgObj["plugin"])
                self.wanConnPlugin.start(cfgObj, self.wanConnPluginApi)
                self.logger.info("Internet connection activated, plugin: %s." % (cfgObj["plugin"]))
            else:
                self.logger.info("No internet connection configured.")
        except BaseException:
            if self.wanConnPlugin is not None:
                self.wanConnPlugin.stop()
                self.wanConnPlugin = None
                self.logger.info("Internet connection deactivated.")
            if self.wanConnPluginApi is not None:
                self.wanConnPluginApi.dispose()
                self.wanConnPluginApi = None
            raise
Пример #6
0
    def __init__(self, param):
        self.param = param
        self.cfgFile = os.path.join(self.param.tmpDir, "l2-dnsmasq.conf")
        self.pidFile = os.path.join(self.param.tmpDir, "l2-dnsmasq.pid")
        self.hostsDir = os.path.join(self.param.tmpDir, "l2-dnsmasq.hosts.d")
        self.logger = logging.getLogger(self.__module__ + "." +
                                        self.__class__.__name__)

        self.wanServDict = dict()  # dict<name,json-object>

        self.tfacGroupDict = dict()  # dict<name, priority>

        self.routeFullDict = _NamePriorityKeyValueDict()
        self.routeDict = dict()  # dict<prefix, data>
        self.gatewayDict = dict()  # dict<name, set<interface>>

        self.domainNameserverFullDict = _NamePriorityKeyValueDict()
        self.domainNameserverDict = dict()

        self.domainIpFullDict = _NamePriorityKeyValueDict()

        self.routeRefreshInterval = 10  # 10 seconds
        self.routeRefreshTimer = GObject.timeout_add_seconds(
            self.routeRefreshInterval, self._routeRefreshTimerCallback)

        self.dnsPort = WrtUtil.getFreeSocketPort("tcp")
        self.dnsmasqProc = None
        try:
            self._runDnsmasq()
            self.logger.info("Level 2 nameserver started.")
        except BaseException:
            self._dispose()
            raise
Пример #7
0
 def on_wan_conn_up(self):
     # set exclude prefix and restart if neccessary
     wanPrefixList = []
     for ifc in self.ifconfigDict.values():
         wanPrefixList.append(WrtUtil.ipMaskToPrefix(ifc["prefix"].split("/")[0], ifc["prefix"].split("/")[1]))
     if self.param.prefixPool.setExcludePrefixList("wan", wanPrefixList):
         os.kill(os.getpid(), signal.SIGHUP)
         raise Exception("bridge prefix duplicates with internet connection, autofix it and restart")
Пример #8
0
 def _stopDnsmasq(self):
     self.lastScanRecord = None
     if self.leaseMonitor is not None:
         self.leaseMonitor.cancel()
         self.leaseMonitor = None
     if self.dnsmasqProc is not None:
         self.dnsmasqProc.terminate()
         self.dnsmasqProc.wait()
         self.dnsmasqProc = None
     WrtUtil.forceDelete(self.pidFile)
     WrtUtil.forceDelete(self.leasesFile)
     WrtUtil.forceDelete(self.hostsDir)
     WrtUtil.forceDelete(self.myhostnameFile)
Пример #9
0
    def add_host(self, source_id, ip_data_dict):
        fn = os.path.join(self.hostsDir, source_id)
        itemDict = WrtUtil.dnsmasqHostFileToOrderedDict(fn)
        bChanged = False

        for ip, data in ip_data_dict.items():
            if ip in itemDict:
                if "hostname" in data:
                    if itemDict[ip] != data["hostname"]:
                        itemDict[ip] = data["hostname"]
                        bChanged = True
                else:
                    del itemDict[ip]
                    bChanged = True
            else:
                if "hostname" in data:
                    itemDict[ip] = data["hostname"]
                    bChanged = True

        if bChanged:
            WrtUtil.dictToDnsmasqHostFile(itemDict, fn)
            self.dnsmasqProc.send_signal(signal.SIGHUP)
Пример #10
0
 def _stopDnsmasq(self):
     if self.dnsmasqProc is not None:
         self.dnsmasqProc.terminate()
         self.dnsmasqProc.wait()
         self.dnsmasqProc = None
     WrtUtil.forceDelete(self.hostsDir)
     WrtUtil.forceDelete(self.pidFile)
     WrtUtil.forceDelete(self.cfgFile)
Пример #11
0
    def _loadManagerPlugins(self):
        # load manager plugin
        for name in self.param.pluginHub.getPluginList("manager"):
            assert name not in self.managerPluginDict
            self.managerPluginDict[name] = self.param.pluginHub.getPlugin("manager", name)

        # create manager data
        class _Stub:
            pass
        data = _Stub()
        data.etcDir = self.param.etcDir
        data.tmpDir = self.param.tmpDir
        data.varDir = self.param.varDir
        data.uuid = self.param.uuid
        data.plugin_hub = self.param.pluginHub
        data.prefix_pool = self.param.prefixPool
        data.manager_caller = self.param.managerCaller
        data.managers = {
            "traffic": self.param.trafficManager,
            "wan": self.param.wanManager,
            "lan": self.param.lanManager,
        }
        data.managers.update(self.managerPluginDict)

        # get init order
        tdict = dict()
        for name in self.managerPluginDict:
            tdict[name] = set(self.managerPluginDict[name].init_after)
        tlist = toposort.toposort_flatten(tdict)

        # init manager plugin
        for name in tlist:
            fn = os.path.join(self.param.etcDir, "manager-%s.json" % (name))
            if os.path.exists(fn) and os.path.getsize(fn) > 0:
                cfgObj = WrtUtil.loadJsonEtcCfg(fn)
            else:
                cfgObj = dict()

            p = self.managerPluginDict[name]
            p.init2(cfgObj, self.param.tmpDir, self.param.varDir, data)
            logging.info("Manager plugin \"%s\" activated." % (p.full_name))

            self.param.managerCaller.call("on_manager_init", p)
            self.param.managerCaller.add_manager(name, p)
Пример #12
0
    def _getInstanceAndInfoFromEtcDir(self, pluginPrefix, cfgfilePrefix, name):
        # Returns (instanceName, cfgobj, tmpdir, vardir)

        ret = []
        for fn in glob.glob(
                os.path.join(self.param.etcDir,
                             "%s-%s*.json" % (cfgfilePrefix, name))):
            bn = os.path.basename(fn)

            instanceName = bn[len("%s-%s" %
                                  (cfgfilePrefix, name)):len(".json") * -1]
            if instanceName != "":
                instanceName = instanceName.lstrip("-")

            if instanceName != "":
                fullName = "%s-%s" % (name, instanceName)
            else:
                fullName = name

            if os.path.getsize(fn) > 0:
                cfgObj = WrtUtil.loadJsonEtcCfg(fn)
            else:
                cfgObj = dict()

            tmpdir = os.path.join(self.param.tmpDir,
                                  "%s-%s" % (pluginPrefix, fullName))
            vardir = os.path.join(self.param.varDir,
                                  "%s-%s" % (pluginPrefix, fullName))

            ret.append((instanceName, cfgObj, tmpdir, vardir))

        if len(ret) == 0:
            instanceName = ""
            fullName = name
            cfgObj = dict()
            tmpdir = os.path.join(self.param.tmpDir,
                                  "%s-%s" % (pluginPrefix, fullName))
            vardir = os.path.join(self.param.varDir,
                                  "%s-%s" % (pluginPrefix, fullName))
            ret.append((instanceName, cfgObj, tmpdir, vardir))

        return ret
Пример #13
0
    def __init__(self, param):
        self.param = param
        self.logger = logging.getLogger(self.__module__ + "." +
                                        self.__class__.__name__)

        self.defaultBridge = None

        self.lifPluginList = []
        self.vpnsPluginList = []

        self.propDict = dict()  # dict<property-source,property-dict>

        self.clientDict = dict()  # dict<ip,data>
        self.clientSourceDict = dict()  # dict<ip,source_id>
        self.clientPropDict = dict(
        )  # dict<ip,dict<property-source,property-dict>>

        try:
            # create default bridge
            tmpdir = os.path.join(self.param.tmpDir, "bridge-default")
            os.mkdir(tmpdir)
            vardir = os.path.join(self.param.varDir, "bridge-default")
            WrtUtil.ensureDir(vardir)
            self.defaultBridge = _DefaultBridge(self, tmpdir, vardir)
            self.defaultBridge.init2(
                "wrtd-br", self.param.prefixPool.usePrefix(),
                self.param.trafficManager.get_l2_nameserver_port(),
                lambda source_id, ip_data_dict: self._clientAdd(
                    source_id, ip_data_dict),
                lambda source_id, ip_data_dict: self._clientChange(
                    source_id, ip_data_dict),
                lambda source_id, ip_list: self._clientRemove(
                    source_id, ip_list))
            self.logger.info("Default bridge started.")

            # start all lan interface plugins
            for name in self.param.pluginHub.getPluginList("lif"):
                for instanceName, cfgObj, tmpdir, vardir in self._getInstanceAndInfoFromEtcDir(
                        "lif", "lan-interface", name):
                    os.mkdir(tmpdir)
                    WrtUtil.ensureDir(vardir)

                    p = self.param.pluginHub.getPlugin("lif", name,
                                                       instanceName)
                    p.init2(instanceName, cfgObj, tmpdir, vardir)
                    p.start()
                    self.lifPluginList.append(p)
                    self.logger.info("LAN interface plugin \"%s\" activated." %
                                     (p.full_name))

            # start all vpn server plugins
            for name in self.param.pluginHub.getPluginList("vpns"):
                for instanceName, cfgObj, tmpdir, vardir in self._getInstanceAndInfoFromEtcDir(
                        "vpns", "vpn-server", name):
                    os.mkdir(tmpdir)
                    WrtUtil.ensureDir(vardir)

                    p = self.param.pluginHub.getPlugin("vpns", name,
                                                       instanceName)
                    p.init2(
                        instanceName, cfgObj, tmpdir, vardir,
                        self.param.prefixPool.usePrefix(),
                        self.param.trafficManager.get_l2_nameserver_port(),
                        lambda source_id, ip_data_dict: self._clientAdd(
                            source_id, ip_data_dict),
                        lambda source_id, ip_data_dict: self._clientChange(
                            source_id, ip_data_dict),
                        lambda source_id, ip_list: self._clientRemove(
                            source_id, ip_list))
                    p.start()
                    self.vpnsPluginList.append(p)
                    self.logger.info("VPN server plugin \"%s\" activated." %
                                     (p.full_name))

                    if p.get_wan_service() is not None:
                        self.param.trafficManager.add_wan_service(
                            p.full_name, p.get_wan_service())

            # send other-bridge-create event
            all_bridges = [self.defaultBridge
                           ] + [x.get_bridge() for x in self.vpnsPluginList]
            for bridge in all_bridges:
                for other_bridge in all_bridges:
                    if bridge == other_bridge:
                        continue
                    bridge.add_source(other_bridge.get_bridge_id())
        except BaseException:
            self._dispose()
            raise
Пример #14
0
    def run(self):
        WrtUtil.ensureDir(self.param.varDir)
        WrtUtil.mkDirAndClear(self.param.tmpDir)
        WrtUtil.mkDirAndClear(self.param.runDir)
        try:
            logging.getLogger().addHandler(logging.StreamHandler(sys.stderr))
            logging.getLogger().setLevel(WrtUtil.getLoggingLevel(self.param.logLevel))
            logging.info("Program begins.")

            # manipulate iptables
            if not self.param.abortOnError:
                WrtUtil.iptablesSetEmpty()
            else:
                if not WrtUtil.iptablesIsEmpty():
                    raise Exception("iptables is not empty, wrtd use iptables exclusively")

            # load configuration
            self._loadCfg()

            # load UUID
            if WrtCommon.loadUuid(self.param):
                logging.info("UUID generated: \"%s\"." % (self.param.uuid))
            else:
                logging.info("UUID loaded: \"%s\"." % (self.param.uuid))

            # write pid file
            with open(self.param.pidFile, "w") as f:
                f.write(str(os.getpid()))

            # load plugin hub
            self.param.pluginHub = PluginHub(self.param)
            logging.info("Plugin HUB loaded.")

            # load prefix pool
            self.param.prefixPool = PrefixPool(os.path.join(self.param.varDir, "prefix-pool.json"))
            logging.info("Prefix pool loaded.")

            # create our own resolv.conf
            with open(self.param.ownResolvConf, "w") as f:
                f.write("")

            # load manager caller
            self.param.managerCaller = ManagerCaller(self.param)
            logging.info("Manager caller initialized.")

            # create main loop
            DBusGMainLoop(set_as_default=True)
            self.param.mainloop = GLib.MainLoop()

            # business initialize
            self.param.trafficManager = WrtTrafficManager(self.param)
            self.param.wanManager = WrtWanManager(self.param)
            self.param.lanManager = WrtLanManager(self.param)
            self._loadManagerPlugins()
            self.interfaceTimer = GObject.timeout_add_seconds(0, self._interfaceTimerCallback)

            # enable ip forward
            if WrtUtil.readFile(self.param.procIpForwareFile) == "0":
                with open(self.param.procIpForwareFile, "w") as f:
                    f.write("1")
                logging.info("IP forwarding enabled.")
            else:
                logging.warn("IP forwarding already enabled.")

            # start DBUS API server
            self.param.dbusMainObject = DbusMainObject(self.param)
            self.param.dbusIpForwardObject = DbusIpForwardObject(self.param)
            logging.info("DBUS-API server started.")

            # 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)
            self.param.mainloop.run()
            logging.info("Mainloop exits.")
        finally:
            if self.interfaceTimer is not None:
                GLib.source_remove(self.interfaceTimer)
                self.interfaceTimer = None
            if True:
                for p in self.managerPluginDict.values():
                    p.dispose()
                    logging.info("Manager plugin \"%s\" deactivated." % (p.full_name))
                self.managerPluginDict = dict()
            if self.param.lanManager is not None:
                self.param.lanManager.dispose()
                self.param.lanManager = None
            if self.param.wanManager is not None:
                self.param.wanManager.dispose()
                self.param.wanManager = None
            if self.param.trafficManager is not None:
                self.param.trafficManager.dispose()
                self.param.trafficManager = None
            logging.shutdown()
            shutil.rmtree(self.param.tmpDir)
            if self.bRestart:
                WrtUtil.restartProgram()
Пример #15
0
 def prefixConvert(prefix):
     tl = prefix.split("/")
     return tl[0] + "/" + str(WrtUtil.ipMaskToLen(tl[1]))
Пример #16
0
    def _dnsmasqLeaseChanged(self, monitor, file, other_file, event_type):
        if event_type != Gio.FileMonitorEvent.CHANGED:
            return

        try:
            newLeaseList = WrtUtil.readDnsmasqLeaseFile(self.leasesFile)

            addList = []
            changeList = []
            removeList = []
            for item in newLeaseList:
                item2 = self.___dnsmasqLeaseChangedFind(
                    item, self.lastScanRecord)
                if item2 is not None:
                    if item[1] != item2[1] or item[3] != item2[
                            3]:  # mac or hostname change
                        changeList.append(item)
                else:
                    addList.append(item)
            for item in self.lastScanRecord:
                if self.___dnsmasqLeaseChangedFind(item, newLeaseList) is None:
                    removeList.append(item)

            if len(addList) > 0:
                ipDataDict = dict()
                for expiryTime, mac, ip, hostname, clientId in addList:
                    self.__dnsmasqLeaseChangedAddToIpDataDict(
                        ipDataDict, ip, mac, hostname)
                    if hostname != "":
                        self.pObj.logger.info(
                            "Client %s(IP:%s, MAC:%s) appeared." %
                            (hostname, ip, mac))
                    else:
                        self.pObj.logger.info("Client %s(%s) appeared." %
                                              (ip, mac))
                for expiryTime, mac, ip, hostname, clientId in changeList:
                    self.__dnsmasqLeaseChangedAddToIpDataDict(
                        ipDataDict, ip, mac, hostname)
                    # log is not needed for client change
                self.clientAddFunc(self.get_bridge_id(), ipDataDict)

            if len(changeList) > 0:
                ipDataDict = dict()
                for expiryTime, mac, ip, hostname, clientId in changeList:
                    self.__dnsmasqLeaseChangedAddToIpDataDict(
                        ipDataDict, ip, mac, hostname)
                    # log is not needed for client change
                self.clientChangeFunc(self.get_bridge_id(), ipDataDict)

            if len(removeList) > 0:
                ipList = [x[2] for x in removeList]
                self.clientRemoveFunc(self.get_bridge_id(), ipList)
                for expiryTime, mac, ip, hostname, clientId in removeList:
                    if hostname != "":
                        self.pObj.logger.info(
                            "Client %s(IP:%s, MAC:%s) disappeared." %
                            (hostname, ip, mac))
                    else:
                        self.pObj.logger.info("Client %s(%s) disappeared." %
                                              (ip, mac))

            self.lastScanRecord = newLeaseList
        except Exception:
            self.pObj.logger.error("Lease scan failed", exc_info=True)  # fixme
Пример #17
0
def checkTrafficFacilityGroup(tfac_group):
    i = 0
    for tfac in tfac_group:
        i += 1

        if "facility-name" not in tfac:
            raise TfacException(
                "Lacking \"facility-name\" for facility No.%d." % (i))

        if "facility-type" not in tfac:
            raise TfacException(
                "Lacking \"facility-type\" for facility \"%s\"." %
                (tfac["facility-name"]))

        if tfac["facility-type"] == "nameserver":
            if "target" not in tfac:
                raise TfacException("Lacking \"target\" for facility \"%s\"." %
                                    (tfac["facility-name"]))
            if not isinstance(tfac["target"], list):
                raise TfacException(
                    "Type of \"target\" is invalid for facility \"%s\"." %
                    (tfac["facility-name"]))
            for item in tfac["target"]:
                msg = "Some element in \"target\" is invalid for facility \"%s\"." % (
                    tfac["facility-name"])
                if ":" in item:
                    tlist = item.split(":")
                    if len(tlist) != 2:
                        raise TfacException(msg)
                    if not WrtUtil.is_int(tlist[1]):
                        raise TfacException(msg)

            if "domain-list" not in tfac:
                raise TfacException(
                    "Lacking \"domain-list\" for facility \"%s\"." %
                    (tfac["facility-name"]))
            if not isinstance(tfac["domain-list"], list):
                raise TfacException(
                    "Type of \"domain-list\" is invalid for facility \"%s\"." %
                    (tfac["facility-name"]))
            for item in tfac["domain-list"]:
                if not isinstance(item, str):
                    raise TfacException(
                        "Some element in \"domain-list\" is invalid for facility \"%s\"."
                        % (tfac["facility-name"]))

            continue

        if tfac["facility-type"] == "gateway":
            if "target" not in tfac:
                raise TfacException("Lacking \"target\" for facility \"%s\"." %
                                    (tfac["facility-name"]))
            msg = "Invalid \"target\" for facility \"%s\"." % (
                tfac["facility-name"])
            if not isinstance(tfac["target"], list):
                raise TfacException(msg)
            if len(tfac["target"]) != 2:
                raise TfacException(msg)
            if tfac["target"][0] is not None and not isinstance(
                    tfac["target"][0], str):
                raise TfacException(msg)
            if tfac["target"][1] is not None and not isinstance(
                    tfac["target"][1], str):
                raise TfacException(msg)

            if "network-list" not in tfac:
                raise TfacException(
                    "Lacking \"network-list\" for facility \"%s\"." %
                    (tfac["facility-name"]))
            if not isinstance(tfac["network-list"], list):
                raise TfacException(
                    "Type of \"network-list\" is invalid for facility \"%s\"."
                    % (tfac["facility-name"]))
            for item in tfac["network-list"]:
                msg = "Some element in \"domain-list\" is invalid for facility \"%s\"." % (
                    tfac["facility-name"])
                if not isinstance(item, str):
                    raise TfacException(msg)
                try:
                    tnet = ipaddress.IPv4Network(item)
                    if tnet.is_private:
                        raise TfacException(msg)
                    if re.match("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+",
                                item.split("/")[0]) is None:
                        raise TfacException(msg)
                except ipaddress.AddressValueError:
                    raise TfacException(msg)
                except ipaddress.NetmaskValueError:
                    raise TfacException(msg)
                except ValueError:
                    raise TfacException(msg)

            continue

        raise TfacException("Invalid \"facility-type\" for facility \"%s\"." %
                            (tfac["facility-name"]))