Пример #1
0
 def update_dns_record(self, dns_record, public_ip):
     """
     Update a dns record at dns provider side with a given dns record
     """
     DDNSUtils.info(
         'Updating value [{rec.value}] for [{rec.rr}.{rec.domainname}]'.
         format(rec=dns_record))
     acsClient = AcsClient(ak=self.access_key_id,
                           secret=self.access_Key_secret,
                           region_id='cn-hangzhou')
     request = UpdateDomainRecordRequest.UpdateDomainRecordRequest()
     request.set_RR(dns_record.rr)
     request.set_Type(dns_record.type)
     request.set_Value(dns_record.value)
     request.set_RecordId(dns_record.recordid)
     request.set_TTL(dns_record.ttl)
     request.set_accept_format('json')
     try:
         result = acsClient.do_action_with_exception(request)
         return result
     except Exception as exception:
         DDNSUtils.err(
             'Failed to update value [{rec.value}] for [{rec.rr}.{rec.domainname}]'
             .format(rec=dns_record))
         raise exception
Пример #2
0
    def sync(self, localRecord, currentPublicIP):
        remoteRecord = self.matchRemoteDomainRecord(localRecord.domain, localRecord.subDomain, localRecord.type)
        if not remoteRecord:
            return self.addDomainRecord(localRecord, currentPublicIP)

        remoteRecordId = self.extractDomainRecordId(remoteRecord)
        if not remoteRecordId:
            DDNSUtils.err("Failed to extract domain id from remote domain record desc")
            return False

        # save domain record id for future reference
        if not self.config.save(localRecord.alias, "id", remoteRecordId):
            DDNSUtils.err("Failed to save domain record id to config file")
            return False

        remoteRecordValue = self.extractDomainRecordValue(remoteRecord)
        if not remoteRecordValue:
            DDNSUtils.err("Failed to extract domain value from remote domain record desc")
            return False

        # check whether to update the remote record or just update current profile;
        if currentPublicIP == remoteRecordValue and currentPublicIP != localRecord.value:
            # sync local record
            if not self.config.save(localRecord.alias, "value", currentPublicIP):
                DDNSUtils.err("Failed to save domain record value to config file")
                return False
            return True;

        # Now, check if domain record value is different with current public ip or not
        if currentPublicIP != remoteRecordValue:
            return self.updateDomainRecord(localRecord, currentPublicIP)

        if self.config.debug:
            DDNSUtils.info("No change with domain record value on remote server, skip it...")
        return True
Пример #3
0
    def syncFirstTime(self, localRecord, currentPublicIP):
        remoteRecord = self.matchRemoteDomainRecord(localRecord.domain, localRecord.subDomain, localRecord.type)
        if not remoteRecord:
            DDNSUtils.err("Failed to match remote domain record for {0}.{1}"
                          "".format(localRecord.subDomain, localRecord.domain))
            return False

        remoteRecordId = self.extractDomainRecordId(remoteRecord)
        if not remoteRecordId:
            DDNSUtils.err("Failed to extract domain id from remote domain record desc")
            return False

        # save domain record id for future reference
        if not self.config.save(localRecord.alias, "id", remoteRecordId):
            DDNSUtils.err("Failed to save domain record id to config file")
            return False

        remoteRecordValue = self.extractDomainRecordValue(remoteRecord)
        if not remoteRecordValue:
            DDNSUtils.err("Failed to extract domain value from remote domain record desc")
            return False

        # Now, check if domain record value is different with current public ip or not
        if currentPublicIP != remoteRecordValue or currentPublicIP != localRecord.value:
            return self.sync(localRecord, currentPublicIP)

        if self.config.debug:
            DDNSUtils.info("No change with domain record value on remote server, skip it...")
        return True
Пример #4
0
    def from_config_file(cls, configFilePath):
        """
        Construct a Config object from a given config file

        Args:
            configFilePath: path to the given config file
        Returns: 
            Instance of Config
        """
        parser = ConfigParser()
        if not parser.read(configFilePath):
            DDNSUtils.err_and_exit("Failed to read config file.")

        try:
            access_key_id = parser.get("ApiProvider", "access_key_id")
            access_key_secret = parser.get("ApiProvider", "access_key_secret")
            
            if not access_key_id or not access_key_secret:
                DDNSUtils.err_and_exit("Invalid access_id or access_key in config file.")
            apiProviderInfo = ApiProviderInfo(access_key_id, access_key_secret)

            DDNSUtils.info("Read Access Key Id: [{0}]".format(access_key_id))
            DDNSUtils.info("Read Access Key Secret: [{0}]".format(access_key_secret))

            recordsSections = [s for s in parser.sections() if s.startswith("DomainNameToUpdate") ]

            records = []
            for record in recordsSections:
                domain = parser.get(record,'domain')
                type = parser.get(record,'type')
                subDomains = parser.get(record,'sub_domain').split(',')
                if not domain or not type or not subDomains:
                    DDNSUtils.err_and_exit("Invalid domian record.")
                
                DDNSUtils.info("Read Domain: [{0}]".format(domain))
                DDNSUtils.info("Read Sub Domains: [{0}]".format(subDomains))
                DDNSUtils.info("Read Type: [{0}]".format(type))

                for subDomain in subDomains:
                    record = DomainSection(domain, subDomain.strip(), type)
                    records.append(record)
            config = cls(apiProviderInfo, records)
            return config

        except ValueError as ex:
            DDNSUtils.err_and_exit("Invalid debug in config: {0}".format(ex))
        except NoSectionError as ex:
            DDNSUtils.err_and_exit("Invalid config: {0}".format(ex))
        except NoOptionError as ex:
            DDNSUtils.err_and_exit("Invalid config: {0}".format(ex))
Пример #5
0
def main():
    """
    Main routine
    """
    config = DDNSConfig()
    record_manager = DDNSDomainRecordManager(config)

    for local_record in record_manager.local_record_list:
        family = AF_INET if local_record.type == 'A' else AF_INET6
        interface = local_record.interface
        if interface is None:
            current_public_ip = {
                AF_INET: DDNSUtils.get_current_public_ip(),
                AF_INET6: DDNSUtils.get_current_public_ipv6()
            }
        else:
            current_public_ip = {
                AF_INET: DDNSUtils.get_interface_address(interface),
                AF_INET6: DDNSUtils.get_interface_address(interface, AF_INET6)
            }

        if not current_public_ip:
            DDNSUtils.info(
                "Unable to get current IP for [{rec.subdomain}.{rec.domainname}.{rec.type}]"
                .format(rec=local_record))
            continue

        dns_resolved_ip = DDNSUtils.get_dns_resolved_ip(
            local_record.subdomain, local_record.domainname, family)
        if current_public_ip[family] == dns_resolved_ip:
            DDNSUtils.info("Skipped as no changes for DomainRecord" \
                           "[{rec.subdomain}.{rec.domainname}.{rec.type}]".format(rec=local_record))
            continue

        # If current public IP doesn't equal to current DNS resolved ip, only in three cases:
        # 1. The new synced IP for remote record in Aliyun doesn't take effect yet
        # 2. remote record's IP in Aliyun server has changed
        # 3. current public IP is changed
        remote_record = record_manager.fetch_remote_record(local_record)
        if not remote_record:
            DDNSUtils.err("Failed finding remote DomainRecord" \
                          "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
            continue

        if current_public_ip[family] == remote_record.value:
            DDNSUtils.info("Skipped as we already updated DomainRecord" \
                           "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
            continue

        # if we can fetch remote record and record's value doesn't equal to public IP
        record_type = 'A' if family == AF_INET else 'AAAA'
        sync_result = record_manager.update(remote_record,
                                            current_public_ip[family],
                                            record_type)
        if not sync_result:
            DDNSUtils.err("Failed updating DomainRecord" \
                          "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
        else:
            DDNSUtils.info("Successfully updated DomainRecord" \
                           "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
Пример #6
0
    def get_dns_resolved_ip(self):
        if self.subDomainName == "@":
            hostname = self.domainName
        else:
            hostname = "{0}.{1}".format(self.subDomainName, self.domainName)

        try:
            ip_addr = socket.gethostbyname(hostname)
            DDNSUtils.info("RR value read: [{0}] for [{1}]".format(
                ip_addr, hostname))
            return ip_addr
        except Exception as exception:
            DDNSUtils.err(
                "Failed to read ip address for [{0}]".format(hostname))
            raise exception
Пример #7
0
    def get_dns_record(self, dns_section):
        """
        Get the dns record from dns provider by a given dns section
        """
        DDNSUtils.info(
            "Reading dns records for [{section.subDomainName}.{section.domainName}], type=[{section.type}]"
            .format(section=dns_section))

        acsClient = AcsClient(ak=self.access_key_id,
                              secret=self.access_Key_secret,
                              region_id='cn-hangzhou')
        request = DescribeDomainRecordsRequest.DescribeDomainRecordsRequest()
        request.set_DomainName(dns_section.domainName)
        request.set_accept_format('json')
        result = acsClient.do_action_with_exception(request)
        result = json.loads(result.decode('utf8'))

        dns_record_list = result['DomainRecords']['Record']

        if not dns_record_list:
            DDNSUtils.err(
                "Failed to fetch dns resolution records for [{rec.domainName}] by rr={rec.subDomainName} and type={rec.type}"
                .format(rec=dns_section))
            return None

        matched_records = []

        for record in dns_record_list:
            if record['DomainName'] == dns_section.domainName and record[
                    'RR'] == dns_section.subDomainName and record[
                        'Type'] == dns_section.type:
                matched_records.append(record)

        if not matched_records:
            return None

        if len(matched_records) > 1:
            DDNSUtils.err(
                'Duplicate dns resolution records: [{rec.subDomainName}.{rec.domaiNname}]'
                .format(rec=dns_section))

        try:
            dns_record = DnsRecord(matched_records[0])
        except Exception as exception:
            raise exception

        return dns_record
Пример #8
0
def main():
    """
    Main routine
    """
    config = DDNSConfig()
    record_manager = DDNSDomainRecordManager(config)

    # get current public ip for this server
    if config.pifn_enable:
        current_public_ip = DDNSUtils.get_interface_address(
            config.pifn_interface)
    else:
        current_public_ip = DDNSUtils.get_current_public_ip()
    if not current_public_ip:
        DDNSUtils.err_and_exit("Failed to get current public IP")

    for local_record in record_manager.local_record_list:
        if local_record.subdomain == '*':
            dns_resolved_ip = DDNSUtils.get_dns_resolved_ip(
                'xxx', local_record.domainname)
        else:
            dns_resolved_ip = DDNSUtils.get_dns_resolved_ip(
                local_record.subdomain, local_record.domainname)

        if local_record.type == "AAAA":
            current_ip = DDNSUtils.get_interface_ipv6_address(
                local_record.interface)
        else:
            current_ip = current_public_ip

        if current_ip == dns_resolved_ip:
            DDNSUtils.info("Skipped as no changes for DomainRecord" \
                           "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
            continue

        # If current public IP doesn't equal to current DNS resolved ip, only in three cases:
        # 1. The new synced IP for remote record in Aliyun doesn't take effect yet
        # 2. remote record's IP in Aliyun server has changed
        # 3. current public IP is changed
        remote_record = record_manager.fetch_remote_record(local_record)
        if not remote_record:
            DDNSUtils.err("Failed finding remote DomainRecord" \
                          "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
            continue

        if current_ip == remote_record.value:
            DDNSUtils.info("Skipped as we already updated DomainRecord" \
                           "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
            continue

        # if we can fetch remote record and record's value doesn't equal to public IP
        sync_result = record_manager.update(remote_record, current_ip,
                                            local_record.type)

        if not sync_result:
            DDNSUtils.err("Failed updating DomainRecord" \
                          "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
        else:
            DDNSUtils.info("Successfully updated DomainRecord" \
                           "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
Пример #9
0
    def perform_ddns(self):
        """
        Perform the ddns process when everything is ready
        """
        current_public_ip = DDNSUtils.get_current_public_ip()

        if not current_public_ip:
            DDNSUtils.err_and_exit("Failed to get local public IP")

        DDNSUtils.info(
            "Local public ip address read: [{0}]".format(current_public_ip))

        for record_to_update in self.configuration.recordsToUpdate:
            dns_resolved_ip = record_to_update.get_dns_resolved_ip()

            if current_public_ip == dns_resolved_ip:
                DDNSUtils.info(
                    "Skipped as no changes for DomainRecord: [{rec.subDomainName}.{rec.domainName}]"
                    .format(rec=record_to_update))
                continue

            # If current public IP doesn't equal to current DNS resolved ip, only in three cases:
            # 1. The new synchronized IP for remote record in api provider doesn't take effect yet
            # 2. remote record's IP in Aliyun server has changed
            # 3. current public IP is changed
            dns_record = self.get_dns_record(record_to_update)
            if not dns_record:
                DDNSUtils.err(
                    "Failed to get dns resolution record for [{rec.subDomainName}.{rec.domainName}]"
                    .format(rec=record_to_update))
                continue

            if current_public_ip == dns_record.value:
                DDNSUtils.info(
                    "Skipped: dns record already updated: [{rec.subDomainName}.{rec.domainName}]"
                    .format(rec=record_to_update))
                continue

            dns_record.value = current_public_ip
            result = self.update_dns_record(dns_record, current_public_ip)
            if not result:
                DDNSUtils.err(
                    "Failed to update dns record: [{rec.subDomainName}.{rec.domainName}]"
                    .format(rec=record_to_update))
            else:
                DDNSUtils.info(
                    "Successfully update dns record: [{rec.subDomainName}.{rec.domainName}]"
                    .format(rec=record_to_update))
Пример #10
0
    def syncFirstTime(self, localRecord, currentPublicIP):
        remoteRecord = self.matchRemoteDomainRecord(localRecord.domain,
                                                    localRecord.subDomain,
                                                    localRecord.type)
        if not remoteRecord:
            DDNSUtils.err("Failed to match remote domain record for {0}.{1}"
                          "".format(localRecord.subDomain, localRecord.domain))
            return False

        remoteRecordId = self.extractDomainRecordId(remoteRecord)
        if not remoteRecordId:
            DDNSUtils.err(
                "Failed to extract domain id from remote domain record desc")
            return False

        # save domain record id for future reference
        localRecord.id = remoteRecordId
        if not self.config.save(localRecord.alias, "id", remoteRecordId):
            DDNSUtils.err("Failed to save domain record id to config file")
            return False

        remoteRecordValue = self.extractDomainRecordValue(remoteRecord)
        if not remoteRecordValue:
            DDNSUtils.err(
                "Failed to extract domain value from remote domain record desc"
            )
            return False

        # Now, check if domain record value is different with current public ip or not
        if currentPublicIP != remoteRecordValue or currentPublicIP != localRecord.value:
            return self.sync(localRecord, currentPublicIP)

        if self.config.debug:
            DDNSUtils.info(
                "No change with domain record value on remote server, skip it..."
            )
        return True
Пример #11
0
def main(method, *args):
    """
    Main routine
    """
    config = DDNSConfig()
    record_manager = DDNSDomainRecordManager(config)

    # get current public ip for this server
    def switch(m):
        switcher = {
            "net": lambda: DDNSUtils.get_current_public_ip(),
            "static": lambda: args[0],
        }
        return switcher.get(m, lambda: "net|static 10.0.0.1")

    func = switch(method)
    current_public_ip = func()

    if not current_public_ip:
        DDNSUtils.err_and_exit("Failed to get current public IP")

    for local_record in record_manager.local_record_list:
        dns_resolved_ip = DDNSUtils.get_dns_resolved_ip(local_record.subdomain,
                                                        local_record.domainname)

        if current_public_ip == dns_resolved_ip:
            DDNSUtils.info("Skipped as no changes for DomainRecord" \
                           "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
            continue

        # If current public IP doesn't equal to current DNS resolved ip, only in three cases:
        # 1. The new synced IP for remote record in Aliyun doesn't take effect yet
        # 2. remote record's IP in Aliyun server has changed
        # 3. current public IP is changed
        remote_record = record_manager.fetch_remote_record(local_record)
        if not remote_record:
            DDNSUtils.err("Failed finding remote DomainRecord" \
                          "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
            continue

        if current_public_ip == remote_record.value:
            DDNSUtils.info("Skipped as we already updated DomainRecord" \
                           "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
            continue

        # if we can fetch remote record and record's value doesn't equal to public IP
        sync_result = record_manager.update(remote_record, current_public_ip)
        if not sync_result:
            DDNSUtils.err("Failed updating DomainRecord" \
                          "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
        else:
            DDNSUtils.info("Successfully updated DomainRecord" \
                           "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
Пример #12
0
def main():
    """
    Main routine
    """
    config = DDNSConfig()
    record_manager = DDNSDomainRecordManager(config)

    # get current public ip for this server
    current_public_ip = DDNSUtils.get_current_public_ip()
    if not current_public_ip:
        DDNSUtils.err_and_exit("Failed to get current public IP")

    for local_record in record_manager.local_record_list:
        dns_resolved_ip = DDNSUtils.get_dns_resolved_ip(local_record.subdomain,
                                                        local_record.domainname)

        if current_public_ip == dns_resolved_ip:
            DDNSUtils.info("Skipped as no changes for DomainRecord" \
                           "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
            continue

        # If current public IP doesn't equal to current DNS resolved ip, only in three cases:
        # 1. The new synced IP for remote record in Aliyun doesn't take effect yet
        # 2. remote record's IP in Aliyun server has changed
        # 3. current public IP is changed
        remote_record = record_manager.fetch_remote_record(local_record)
        if not remote_record:
            DDNSUtils.err("Failed finding remote DomainRecord" \
                          "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
            continue

        if current_public_ip == remote_record.value:
            DDNSUtils.info("Skipped as we already updated DomainRecord" \
                           "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
            continue

        # if we can fetch remote record and record's value doesn't equal to public IP
        sync_result = record_manager.update(remote_record, current_public_ip)
        if not sync_result:
            DDNSUtils.err("Failed updating DomainRecord" \
                          "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
        else:
            DDNSUtils.info("Successfully updated DomainRecord" \
                           "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
Пример #13
0
    # get current public ip
    currentPublicIP = utils.getCurrentPublicIP()
    if not currentPublicIP:
        DDNSUtils.err_and_exit("Failed to get current public ip")

    for localRecord in config.localDomainRecordList:
        # if we don't have domain record's id in config file, then we never sync to server before
        if not localRecord.id or not localRecord.value:
            result = helper.syncFirstTime(localRecord, currentPublicIP)
            if result is False:
                DDNSUtils.err_and_exit(
                    "Failed doing the first time sync for record:{0}".format(
                        localRecord.alias))
                continue

            DDNSUtils.info("Successfully sync done for record:{0}".format(
                localRecord.alias))
            continue

        # if current public ip is not the same as the one in server
        if currentPublicIP != localRecord.value:
            if config.debug:
                DDNSUtils.info(
                    "current public ip is:{0}, server ip is:{1}".format(
                        currentPublicIP, localRecord.value))

            result = helper.sync(localRecord, currentPublicIP)
            if result is False:
                DDNSUtils.err_and_exit(
                    "Failed to sync the current public IP for record:{0}".
                    format(localRecord.alias))
Пример #14
0
    helper = DDNSHelper(config)

    # get current public ip
    currentPublicIP = utils.getCurrentPublicIP()
    if not currentPublicIP:
        DDNSUtils.err_and_exit("Failed to get current public ip")

    for localRecord in config.localDomainRecordList:
        # if we don't have domain record's id in config file, then we never sync to server before
        if not localRecord.id or not localRecord.value:
            result = helper.syncFirstTime(localRecord,currentPublicIP)
            if result is False:
                DDNSUtils.err_and_exit("Failed doing the first time sync for record:{0}".format(localRecord.alias))
                continue

            DDNSUtils.info("Successfully sync done for record:{0}".format(localRecord.alias))
            continue

        # if current public ip is not the same as the one in server
        if currentPublicIP != localRecord.value:
            if config.debug:
                DDNSUtils.info("current public ip is:{0}, server ip is:%s".format(currentPublicIP, localRecord.value))

            result = helper.sync(localRecord, currentPublicIP)
            if result is False:
                DDNSUtils.err_and_exit("Failed to sync the current public IP for record:{0}".format(localRecord.alias))

            DDNSUtils.info("Successfully sync done on:{0}".format(utils.getCurrentTime()))
            sys.exit(0)

        # all done for one record
Пример #15
0
    help='The access key secret assigned by ddns api provider.')
argParser.add_argument(
    "--config",
    '-c',
    help=
    'The configuration file to refer to for ddns process. If this option is set, all other options will be ignored.'
)

args = argParser.parse_args()

if args.config:
    CONFIG_FILE_PATH = args.config
    if not os.path.exists(CONFIG_FILE_PATH):
        DDNSUtils.err_and_exit('File not found: {0}'.format(CONFIG_FILE_PATH))

    DDNSUtils.info(
        "Loading configuration from file: {0}".format(CONFIG_FILE_PATH))
    config = Config.from_config_file(CONFIG_FILE_PATH)
    coordinator = DDNSCoordinator(config)
    coordinator.perform_ddns()
    pass
elif not args.domains or not args.access_key_id or not args.access_key_secret:
    argParser.print_help()
else:
    DDNSUtils.info("Loading configuration from arguments.")
    config = Config.from_cli_options(args.domains, args.access_key_id,
                                     args.access_key_secret, args.type)
    coordinator = DDNSCoordinator(config)
    coordinator.perform_ddns()

pass
Пример #16
0
if __name__ == "__main__":
    config = DDNSConfig(CONF_FILE)
    config.validate()

    utils = DDNSUtils(config.debug)
    helper = DDNSHelper(config)

    # get current public ip
    currentPublicIP = utils.getCurrentPublicIP()
    if not currentPublicIP:
        DDNSUtils.err_and_exit("Failed to get current public ip")

    for localRecord in config.localDomainRecordList:
        # try to sync all record,
        if config.debug:
            DDNSUtils.info("current public ip is:{0}, cached ip is:{1}".format(currentPublicIP, localRecord.value))

        result = helper.sync(localRecord, currentPublicIP);

        if result is False:
            DDNSUtils.err_and_exit("Failed doing the first time sync for record:{0}".format(localRecord.alias))
            continue

        DDNSUtils.info("Successfully sync done for record:{0}".format(localRecord.alias))
        continue

        # all done for one record
        if config.debug:
            DDNSUtils.info("No changes,skipped...")
            continue