def get_zone(cf:CloudFlare.CloudFlare, zone_name:str): zone_name = zone_name.lower() all_zones = cf.zones() for zone in all_zones: if zone["name"].lower() == zone_name: return zone raise ValueError("could not find zone with name '"+zone_name+"'")
def suggest_set_up(): print("Cloudflare authentication is not set or invalid. " "See https://fds.getpagespeed.com/cloudflare/") print('Type n to keep Cloudflare integration disabled, or enter token: ') cf_token = six.moves.input("Cloudflare token: ") if cf_token and 'n' != cf_token.lower(): cf = CloudFlare(token=cf_token) try: token_verification = cf.user.tokens.verify.get() if token_verification['status'] == 'active': config = ConfigParser() config.read(cf_config_filename) section = "CloudFlare" if not config.has_section(section): # prefer "fds" section in cloudflare.cfg for new setup section = "fds" config.add_section("CloudFlare") config.set('CloudFlare', 'token', cf_token) # ensure dir .cloudflare exists: if not exists(dirname(cf_config_filename)): os.makedirs(dirname(cf_config_filename)) with open(cf_config_filename, 'w') as configfile: # save config.write(configfile) # TODO evaluate security while creation os.chmod(cf_config_filename, 0o600) print('Token is valid. Saved to {}'.format(cf_config_filename)) return True else: print('Token is inactive') except CloudFlareAPIError as e: print('Token verification failed: {}'.format(e)) else: print('No token') return False
def main() -> None: cloudflare = CloudFlare() zones = cloudflare.zones.get(params={"name": root, "per_page": 1}) if not zones: sys.stdout.write("Cannot find domain") sys.exit(1) zone_id: str = zones[0]["id"] existing_domains = cloudflare.zones.dns_records.get(zone_id) remove: List[str] = [] add: List[AddDomain] = [] update: List[UpdateDomain] = [] known: Set[str] = set() for record in existing_domains: if record["type"] != "CNAME": continue domain_id: str = record["id"] name: str = record["name"][:-len(root) - 1] known.add(name) if name not in domains: logging.warning(f"Removing record for {name}") remove.append(domain_id) else: domain = domains[name] old, new = record["content"], domain["cname"] if old != new or record["proxied"] != domain.get( "cloudflare", False): logging.info(f"Updating record for {name} ({old} → {new})") update.append( UpdateDomain(name=name, id=domain_id, info=domain)) else: logging.info(f"Nothing to do for {name}") for name, domain in domains.items(): if name not in known: logging.info(f"Adding record for {name} ({domain['cname']})") add.append(AddDomain(name=name, info=domain)) logging.warning("Applying DNS changes.") for record in add: cloudflare.zones.dns_records.post(zone_id, data=make_zone( record.name, record.info)) for record in update: cloudflare.zones.dns_records.put(zone_id, record.id, data=make_zone( record.name, record.info)) for record in remove: cloudflare.zones.dns_records.delete(zone_id, record) logging.warning("Done.")
def setup_cloudflare(self): cf_email = self.param('cloudflare_email') cf_token = self.param('cloudflare_token') cf_debug = self.verbose >= 4 cf = CloudFlare(email=cf_email, token=cf_token, debug=cf_debug) zones = cf.zones.get(params=dict(name=self.domain, per_page=1)) if not zones: self.fatal('invalid zone: %s', self.domain) self.zone_id = zones[0]['id'] self.cf_dns = cf.zones.dns_records
def __init__(self, config_file: Optional[str] = None, dry_run: bool = False, debug: bool = False, verbosity: int = 0) -> None: self.config = Config(config_file) self.debug = debug self.dry_run = dry_run or debug or self.config.settings.dry_run self.verbosity = verbosity self.cf = CloudFlare( raw=True, email=self.config.settings.cloudflare_email, token=self.config.settings.cloudflare_token, )
def main(): global verbose parser = ArgumentParser( description= "Update CloudFlare DNS records according to local IP addresses") parser.add_argument('configfile', type=str) parser.add_argument('--verbose', action='store_true') args = parser.parse_args() verbose = args.verbose cp = configparser.ConfigParser() cp.read(args.configfile) cf = CloudFlare(email=cp.get("api", "email"), token=cp.get("api", "token")) zone_name = cp.get("record", "zone") zone_id = CFDNSUpdater.get_zone_id(cf, zone_name) print_debug("Using zone:\n%s %s" % (zone_id, zone_name)) dns_records = CFDNSUpdater.get_dns_records(cf, zone_id) print_debug("Found existings DNS records:") # then all the DNS records for that zone for dns_record in dns_records: print_debug(" %s %20s %6d %-5s %s ; proxied=%s proxiable=%s" % (dns_record["id"], dns_record["name"], dns_record["ttl"], dns_record["type"], dns_record["content"], dns_record["proxied"], dns_record["proxiable"])) rname = cp.get("record", "name") rtype = cp.get("record", "type") dns_record = CFDNSUpdater.filter_dns_record(dns_records, rtype, rname) rcontent = CFDNSUpdater.retrieve_record_content(rtype) if dns_record["content"] == rcontent: print( "Record with name %s and type %s is already up to date with content %s" % (rname, rtype, rcontent)) else: print("Updating record with name %s and type %s with content %s" % (rname, rtype, rcontent)) dns_record["content"] = rcontent response = CFDNSUpdater.update_dns_record(cf, zone_id, dns_record) print_debug( "Response:\n %s %20s %6d %-5s %s ; proxied=%s proxiable=%s" % (response["id"], response["name"], response["ttl"], response["type"], response["content"], response["proxied"], response["proxiable"]))
def main(token, zone_id, files): with CloudFlare(token=token) as cloudflare: dns_records = cloudflare.zones.dns_records.get(zone_id) cname_records = { dns_record["name"]: dns_record for dns_record in dns_records if dns_record["type"] == "CNAME" } click.echo(f"{len(cname_records)} CNAME in Cloudflare") cname_files = {} for pathname in files: for filename in glob(pathname): if isfile(filename): cname_files[basename(filename)] = filename click.echo(f"{len(cname_records)} CNAME in File System") for name in cname_files.keys() - cname_records.keys(): with open(cname_files[name]) as file: content = file.read().strip() data = {"type": "CNAME", "name": name, "content": content, "ttl": 1} cloudflare.zones.dns_records.post(zone_id, data=data) click.echo(f"+ {name}") for name in cname_records.keys() - cname_files.keys(): dns_record_id = cname_records[name]["id"] cloudflare.zones.dns_records.delete(zone_id, dns_record_id) click.echo(f"- {name}") for name in cname_records.keys() & cname_files.keys(): with open(cname_files[name]) as file: cname_file_content = file.read().strip() dns_record_content = cname_records[name]["content"] if cname_file_content == dns_record_content: click.echo(f"S {name}") continue dns_record_id = cname_records[name]["id"] data = {"content": cname_file_content} cloudflare.zones.dns_records.patch(zone_id, dns_record_id, data=data) click.echo(f"U {name}")
def updateRecords(recType, extip): utils.printToLog("Starting {} record updates with IP address: {}".format(recType, extip)) from CloudFlare import CloudFlare, exceptions as cf_exceptions try: cf = CloudFlare(email=CF_EMAIL, token=CF_TOKEN) cf_zones = cf.zones.get() updateZones = [] for cf_zone in cf_zones: if cf_zone['name'] in ZONES_TO_UPDATE: updateZones.append(cf_zone) if len(updateZones) == 0: utils.printToLog("Zones to update not found in Cloudflare") return updatedZones = [] for zone in updateZones: dns_records = cf.zones.dns_records.get(zone['id'], params={'per_page': 100}) for dns_record in dns_records: if dns_record['type'] == recType: #print("{}\n\n".format(dns_record)) if dns_record['name'] in HOSTS_TO_UPDATE: dns_record['content'] = extip cf.zones.dns_records.put(zone['id'], dns_record['id'], data=dns_record) #print("Updated " + dns_record['name']) updatedZones.append(dns_record['name']) utils.printToLog("{} record updates successfull".format(recType)) except cf_exceptions.CloudFlareAPIError as e: utils.printToLog("CloudFlareAPIError in updateARecords(): {}".format(e))
def main(argv): args = parse_args(argv) global config config = configparser.ConfigParser() config.read_file(open(args.config)) global cf cf = CloudFlare(email=config['cloudflare']['CF_API_EMAIL'], token=config['cloudflare']['CF_API_KEY']) zone_id = get_zone_id() sections = [s for s in config.sections() if s not in CONFIG_SECTIONS] dns_records = build_records(sections) for dns_record in dns_records: old_records = get_existing_records(dns_record, zone_id) r = update_record(dns_record, old_records=old_records, zone_id=zone_id, noop=args.noop) if r: logging.info("Update result: %s", r)
def updateRecord(dnsRecord, ipAddress, proxied, cfToken): isUpdate = False isPresent = False try: hostName, zoneName = '.'.join(dnsRecord.split('.')[:2]), '.'.join( dnsRecord.split('.')[-2:]) ipInfo = IPAddress(ipAddress) cf = CloudFlare(token=cfToken) recordType = "A" recordContent = ipInfo.compressed if ipInfo.version == 6: recordType = "AAAA" LogDebug("Zone Name: {}, DNS Record: {}, IP Address: {}({})".format( zoneName, dnsRecord, recordContent, recordType)) zones = cf.zones.get(params={'name': zoneName}) for zone in zones: LogDebug("Searching zone {}".format(zone['name'])) dnsRecords = cf.zones.dns_records.get(zone['id'], params={ 'name': dnsRecord, 'match': 'all', 'type': recordType }) for dnsRecord in dnsRecords: LogDebug("Examining record {}".format(dnsRecord['name'])) if dnsRecord['type'] == recordType: LogDebug("Record type match") isPresent = True if dnsRecord['content'] != recordContent: LogDebug("Record need updating") if proxied != None: dnsRecord['proxied'] = proxied newRecord = { 'name': dnsRecord['name'], 'type': dnsRecord['type'], 'content': recordContent, 'proxied': dnsRecord['proxied'] } cf.zones.dns_records.put(zone['id'], dnsRecord['id'], data=newRecord) LogInfo( "Zone Name: {}, DNS Record {}: {}({}) - Updated". format(zone['name'], newRecord['name'], newRecord['content'], newRecord['type'])) isUpdate = True else: LogInfo( "Zone Name: {}, DNS Record {}: {}({}) - Up to date" .format(zone['name'], dnsRecord['name'], dnsRecord['content'], dnsRecord['type'])) else: LogInfo( "Zone Name: {}, DNS Record {}: {}({}) - Type does not match ({})" .format(zone['name'], dnsRecord['name'], dnsRecord['content'], dnsRecord['type'], recordType)) if not isPresent: LogDebug("Record not found, adding record") for zone in zones: LogDebug("Searching zone {}".format(zone['name'])) if zone['name'] == zoneName: if proxied == None: proxied = False cf.zones.dns_records.post(zone['id'], data={ 'name': dnsRecord, 'type': recordType, 'content': recordContent, 'proxied': proxied }) LogInfo( "Zone Name: {}, DNS Record {}: {}({}) - Added".format( zone['name'], dnsRecord, recordContent, recordType)) isUpdate = True except CFExceptions as e: LogError("Cloudflare exception: {}".format(e)) except Exception as e: LogError("Error while updating record: {}".format(e)) finally: return isUpdate
import binascii import datetime import hashlib import os from typing import List, Set, Iterable, Union from ipaddress import IPv6Address, IPv4Address from CloudFlare import CloudFlare _zone_id = os.getenv("CLOUDFLARE_ZONE_ID") token = os.getenv('CLOUDFLARE_TOKEN') _client = CloudFlare(token=token) _zone_name = os.getenv("CLOUDFLARE_ZONE_NAME") infix = os.getenv("CLOUDFLARE_INFIX") def _get_domain_space(instance_id: str) -> str: return f'{instance_id}.{infix}' def get_wildcard_domain(instance_id: str) -> str: return f'*.{_get_domain_space(instance_id)}.{_zone_name}' def _encode_ips(ips: Iterable[Union[IPv4Address, IPv6Address]]) -> str: sha = hashlib.sha1() for ip in ips: sha.update(ip.packed) digest = sha.digest()
def __init__(self, *args, **kwargs): super(CloudflareDNSUpdater, self).__init__(*args, **kwargs) self.cf = CloudFlare(token=self.config["token"]) self._cf_zone = None self._cf_zone_last_update = datetime.min
from CloudFlare import CloudFlare from decouple import Csv, config LOG_LEVEL = config('LOG_LEVEL', default='INFO', cast=lambda x: getattr(logging, x)) FETCH_INTERVAL = config('FETCH_INTERVAL', default=1, cast=int) DEAD_MANS_SNITCH_URL = config('DEAD_MANS_SNITCH_URL', None) # Cloudflare configuration CF_API_EMAIL = config('CF_API_EMAIL') CF_API_KEY = config('CF_API_KEY') ZONE = config('ZONE', default=None) DOMAIN = config('DOMAIN', default=None) SINCE = config('SINCE', default='-360') if (not (ZONE or DOMAIN)) or (ZONE and DOMAIN): print('One of ZONE or DOMAIN must be provided') if DOMAIN: cf = CloudFlare(email=CF_API_EMAIL, token=CF_API_KEY) ZONE = cf.zones.get(params={'name': DOMAIN})[0]['id'] # Datadog configuration DATADOG_API_KEY = config('DATADOG_API_KEY') DATADOG_APP_KEY = config('DATADOG_APP_KEY') STATS_KEY_PREFIX = config('STATS_KEY_PREFIX', default='cloudflare') if not STATS_KEY_PREFIX.endswith('.'): STATS_KEY_PREFIX += '.' TAGS = config('TAGS', default='source:cloudflare', cast=Csv())
def get_zone(prog, api): """Get the zone ID for the domain. This function will get a zone ID for the domain. It will also initialize the CloudFlare.CloudFlare object if the Cloudflare python package is present, which future read/publish/delete functions will use. Otherwise, we'll just use raw HTTP calls directly. Args: prog (State): not changed. api (ApiCloudflare): contains Cloudflare login details. Raises: DNSProcessingError: raised for all errors encountered. """ # if zone is not empty, then we have already initialized if api.zone: return prog.log.info2(" + need a zone ID for {}".format(api.domain)) params = {'name': api.domain} # try native method try: from CloudFlare import CloudFlare from CloudFlare.exceptions import CloudFlareAPIError prog.log.info2(" + using native call(s)...") api.cloudflare = CloudFlare(email=api.email, token=api.key) zones = api.cloudflare.zones.get(params=params) for z in zones: if z['name'] == api.domain: api.zone = z['id'] break if not api.zone: raise Except.DNSProcessingError( "Cloudflare: no zone with domain '{}' found".format( api.domain)) # all done; return explicitly to avoid running the fallback code return # use fallback method except ModuleNotFoundError: pass except CloudFlareAPIError as exc: if len(exc) > 0: errs = [] for e in exc: errs += ["Cloudflare error {}: {}".format(int(e), str(e))] raise Except.DNSProcessingError(errs) else: raise Except.DNSProcessingError("Cloudflare error {}: {}".format( int(exc), str(exc))) except KeyError: raise Except.DNSProcessingError("Cloudflare: zone ID not found") # the fallback method: prog.log.info2(" + using fallback call(s)...") import requests headers = { "X-Auth-Email": api.email, "X-Auth-Key": api.key, "Content-Type": "application/json" } try: r = requests.get("https://api.cloudflare.com/client/v4/zones", params=params, headers=headers) except ConnectionError: raise Except.DNSProcessingError("connection error encountered") except requests.exceptions.Timeout: raise Except.DNSProcessingError("request timed out") except requests.exceptions.TooManyRedirects: raise Except.DNSProcessingError("too many redirects") except requests.exceptions.RequestException as ex: raise Except.DNSProcessingError("{}".format(ex)) prog.log.info3(" + HTTP response: {}".format(r.status_code)) response = r.json() prog.log.info3(" + JSON response: {}".format(response)) errors = get_errors(response) if errors: raise Except.DNSProcessingError(errors) if r.status_code >= 400 and r.status_code < 600: raise Except.DNSProcessingError( "Cloudflare4 HTTP response was {}".format(r.status_code)) if not response['success']: raise Except.DNSProcessingError("Cloudflare4 JSON response failure") try: for z in response['result']: if z['name'] == api.domain: api.zone = z['id'] break if not api.zone: raise Except.DNSProcessingError( "Cloudflare: no zone with domain '{}' found".format( api.domain)) except KeyError: raise Except.DNSProcessingError("Cloudflare: zone ID not found") prog.log.info2(" + zone ID retrieved: '...({})'".format(len(api.zone)))
def TraefikFlare( log_level, slack_webhook, slack_username, slack_format, sleep_time, traefik_url, ipify_url, cloudflare_email, cloudflare_api_key, ): logger.remove() logger.add(stderr, level=log_level) if slack_webhook: params = {"username": slack_username, "webhook_url": slack_webhook} slack = NotificationHandler("slack", defaults=params) logger.add(slack, format=slack_format, level="SUCCESS") logger.success(f"{basename(argv[0])} Started") logger.info(f' --log-level "{log_level}"') logger.info(f' --slack-webhook "{slack_webhook}"') logger.info(f' --slack-username "{slack_username}"') logger.info(f' --slack-format "{slack_format}"') logger.info(f" --sleep-time {sleep_time}") logger.info(f' --traefik-url "{traefik_url}"') logger.info(f' --ipify-url "{ipify_url}"') logger.info(f' --cloudflare-email "{cloudflare_email}"') logger.info(f' --cloudflare-api-key "{cloudflare_api_key}"') traefik = Traefik(url=traefik_url) ipify = IPIFY(url=ipify_url) cloudflare = CloudFlare(email=cloudflare_email, token=cloudflare_api_key) zones = None while True: try: zones = { zone["name"]: zone["id"] for zone in cloudflare.zones.get(params={"per_page": 100}) } logger.info(f"Cloudflare connection OK, {len(zones)} zones found:") for zone in zones: logger.info(f" {zones[zone]}: {zone}") except CloudFlareAPIError as e: logger.error( f"CloudFlareAPIError getting zones for {cloudflare_email}: {e}" ) continue except Exception as e: logger.error( f"Exception getting zones for {cloudflare_email}: {e}") continue if zones is not None: break logger.info(f"Sleeping {sleep_time} seconds") sleep(sleep_time) previous = None current = None while True: try: hosts = traefik.routes.hosts logger.info(f"Traefik connection OK, {len(hosts)} hosts found:") for host in hosts: logger.info(f" {host}") except Exception as e: logger.error(f"Exception getting hosts from {traefik_url}: {e}") previous = None logger.info(f"Sleeping {sleep_time} seconds") sleep(sleep_time) continue try: ip_address = ipify.ip_address except Exception as e: logger.error(f"Exception getting IP address from {ipify_url}: {e}") previous = None logger.info(f"Sleeping {sleep_time} seconds") sleep(sleep_time) continue current = { host: str(ip_address) for host in hosts if host.endswith(tuple(zones)) } if current != previous: logger.info( f"Hosts changed, {len(current)} hosts found ({len(hosts) - len(current)} filtered):" ) previous = current for host in current: zone_name = [zone for zone in zones if host.endswith(zone)][0] zone_id = zones[zone_name] logger.debug( f"Starting {host} {current[host]} in zone {zone_id} {zone_name}" ) try: dns_records = cloudflare.zones.dns_records.get(zone_id, params={ "name": host, "match": "all", "type": "A" }) except CloudFlareAPIError as e: logger.error( f"CloudFlareAPIError getting dns records for {zone_id}: {host}: {e}" ) previous = None continue except Exception as e: logger.error( f"Exception getting dns records for {zone_id}: {host}: {e}" ) previous = None continue if len(dns_records) > 1: logger.error( f"Received {len(dns_records)} dns records for {zone_id}: {host}, expected 1" ) previous = None continue if len(dns_records) == 0: # Create a new record try: cloudflare.zones.dns_records.post( zone_id, data={ "name": host, "type": "A", "content": current[host], "proxied": False, }, ) except CloudFlareAPIError as e: logger.error( f"CloudFlareAPIError creating dns record for {zone_id}: {host}: {e}" ) previous = None continue except Exception as e: logger.error( f"Exception creating dns record for {zone_id}: {host}: {e}" ) previous = None continue logger.success( f"{host} created and set to {current[host]}.") if len(dns_records) == 1: # update the record - unless it's already correct dns_record = dns_records[0] old_ip_address = dns_record["content"] if current[host] == old_ip_address: logger.info( f"{host} already set to {current[host]}, no change required." ) continue dns_record_id = dns_record["id"] try: cloudflare.zones.dns_records.put( zone_id, dns_record_id, data={ "name": host, "type": "A", "content": current[host], "proxied": False, }, ) except CloudFlareAPIError as e: logger.error( f"CloudFlareAPIError updating dns record for {zone_id}: {host}: {e}" ) previous = None continue except Exception as e: logger.error( f"Exception updating dns record for {zone_id}: {host}: {e}" ) previous = None continue logger.success( f"{host} updated from {old_ip_address} to {current[host]}." ) if sleep_time == 0: break logger.info(f"Sleeping {sleep_time} seconds") sleep(sleep_time)
from CloudFlare import CloudFlare if __name__ == '__main__': cloudFlare = CloudFlare() for zone_id in cloudFlare.get_zone_ids(): for dns_record_id, dns_record_name in cloudFlare.get_dns_record_ids(zone_id): cloudFlare.update_new_ip_for_dns_record(zone_id, dns_record_id, dns_record_name)
def _work(self, domains: List[str], dkim_keys: Dict[str, Dict[str, str]], cf_api: Tuple[str, str], vm_ips: Tuple[str, str], dmarc_mail: str) -> None: cf: CloudFlare = CloudFlare(email=cf_api[0], token=cf_api[1]) zones: List[Dict[str, str]] = cf.zones.get(params={'per_page': 100}) ip4, ip6 = vm_ips for zone in zones: zone_name: str = zone['name'] if zone_name not in domains: continue zone_id: str = zone['id'] dns_records: List[Dict[str, str]] = cf.zones.dns_records.get(zone_id) # print(zone_name) # for dns_record in dns_records: # print(dns_record) # DKIM records dkim_key_dict: Dict[str, str] = dkim_keys[zone_name] needs_adding_key = [True, True] dkim_key: str = "v={0}; k={1}; p={2}".format( dkim_key_dict['v'], dkim_key_dict['k'], dkim_key_dict['p']) for wild in range(2): for dns_record in dns_records: if dns_record['type'] != 'TXT' or not dns_record[ 'name'].endswith('._domainkey.' + ('*.' * wild) + zone_name): continue existing_key: str = dns_record['content'] if dkim_key == existing_key: needs_adding_key[wild] = False else: dns_record_id: str = dns_record['id'] cf.zones.dns_records.delete(zone_id, dns_record_id) if needs_adding_key[wild]: new_record: Dict[str, str] = { 'name': 'mail._domainkey.' + ('*.' * wild) + zone_name, 'type': 'TXT', 'content': dkim_key, } cf.zones.dns_records.post(zone_id, data=new_record) # No CAAs or CNAMEs for dns_record in dns_records: if dns_record['type'] in ['CAA', 'CNAME']: cf.zones.dns_records.delete(zone_id, dns_record['id']) # A and AAAA records a_records_matrix = [[False, False], [False, False]] for dns_record in dns_records: if dns_record['type'] not in ['A', 'AAAA']: continue expectedContent = ip4 if dns_record['type'] == 'A' else ip6 if dns_record['content'] == expectedContent: a_records_matrix[int(dns_record['type'] == 'A')][int( dns_record['name'].startswith('*.'))] = True elif dns_record['name'] in [zone_name, '*.' + zone_name]: a_records_matrix[int(dns_record['type'] == 'A')][int( dns_record['name'].startswith('*.'))] = True new_record = { 'id': dns_record['id'], 'name': dns_record['name'], 'type': dns_record['type'], 'content': expectedContent, } cf.zones.dns_records.put(zone_id, dns_record['id'], data=new_record) else: cf.zones.dns_records.delete(zone_id, dns_record['id']) for v4t_v6f, k in enumerate(a_records_matrix): v4t_v6f = bool(v4t_v6f) for wild, created in enumerate(k): wild = bool(wild) if not created: cf.zones.dns_records.post( zone_id, data={ 'name': (int(wild) * '*.') + zone_name, 'type': 'A' if v4t_v6f else 'AAAA', 'content': ip4 if v4t_v6f else ip6, }) # DMARC records dmarc_okays = [False, False] dmarc_value = 'v=DMARC1; p=reject; rua=mailto:' + dmarc_mail for wild, dmarc_okay in enumerate(dmarc_okays): for dns_record in dns_records: if dns_record['type'] != 'TXT' or dns_record[ 'name'] != '_dmarc.' + ('*.' * wild) + zone_name: continue if dns_record['content'] == dmarc_value: dmarc_okay = True else: dmarc_okay = True new_record = { 'id': dns_record['id'], 'name': dns_record['name'], 'type': dns_record['type'], 'content': dmarc_value, } cf.zones.dns_records.put(zone_id, dns_record['id'], data=new_record) if not dmarc_okay: new_record: Dict[str, str] = { 'name': '_dmarc.' + ('*.' * wild) + zone_name, 'type': 'TXT', 'content': dmarc_value, } cf.zones.dns_records.post(zone_id, data=new_record) # print(dmarc_value) # SPF records spf_okays = [False, False] spf_value = 'v=spf1 ip4:' + ip4 + ' ip6:' + ip6 + ' a aaaa mx -all' for wild, spf_okay in enumerate(spf_okays): for dns_record in dns_records: if dns_record['type'] != 'TXT' or dns_record['name'] != ( '*.' * wild) + zone_name: continue if dns_record['content'] == spf_value: spf_okay = True else: spf_okay = True new_record = { 'id': dns_record['id'], 'name': dns_record['name'], 'type': dns_record['type'], 'content': spf_value, } cf.zones.dns_records.put(zone_id, dns_record['id'], data=new_record) if not spf_okay: new_record: Dict[str, str] = { 'name': ('*.' * wild) + zone_name, 'type': 'TXT', 'content': spf_value, } cf.zones.dns_records.post(zone_id, data=new_record) # MX records mx_okays = [False, False] for dns_record in dns_records: if dns_record['type'] != 'MX': continue if dns_record['name'] not in [zone_name, '*.' + zone_name]: cf.zones.dns_records.delete(zone_id, dns_record['id']) continue mx_okays[int(dns_record['name'].startswith('*.'))] = True if dns_record['content'] == zone_name: continue new_record = { 'id': dns_record['id'], 'name': dns_record['name'], 'type': dns_record['type'], 'content': zone_name, } cf.zones.dns_records.put(zone_id, dns_record['id'], data=new_record) for wild, is_okay in enumerate(mx_okays): wild = bool(wild) if not is_okay: new_record: Dict[str, str] = { 'name': (int(wild) * '*.') + zone_name, 'type': 'MX', 'priority': 1, 'content': zone_name, } cf.zones.dns_records.post(zone_id, data=new_record)
#!/usr/bin/env python from CloudFlare import CloudFlare import config cf = CloudFlare(email=config.CF_API_EMAIL, token=config.CF_API_KEY) for zone in cf.zones.get(): print '{}: {}'.format(zone['name'], zone['id'])
from CloudFlare import CloudFlare import ipdb with open('cloudflare_key.txt') as fh: cloudflare = CloudFlare(email='*****@*****.**', token=fh.read().strip()) zone = cloudflare.zones.get(params={'name': 'mause.me'})[0]['id'] prefix = 'novell.mause.me' IP = '192.168.1.8' def main(): dns_records = cloudflare.zones.dns_records records = dns_records.get(zone) for record in records: print(record['name']) ipdb.set_trace() dns_records.post( zone, data={ 'name': 'transmission.novell', 'type': 'A', "content":IP, "ttl":120, 'proxied': False } )
def main(email: str, api_key: str, dns_name: str, ip_address: str): """main function""" logger = get_logger("main") _, zone_name = dns_name.split(".", 1) if "." not in zone_name: zone_name = dns_name ip_address_type = "AAAA" if ":" in ip_address else "A" cloudflare = CloudFlare(email=email, token=api_key) zones = get_zones(cloudflare, zone_name) if not zones: logger.info("no zone specified", zones=zones, zone_name=zone_name) return 0 if len(zones) != 1: logger.error( "api call returned multiple items", zone_name=zone_name, num_zones=len(zones), method="zones.get", ) return 2 dns_records = get_dns_records(cloudflare, zones[0]["id"], dns_name, ip_address_type) if not dns_records: return 2 zone_id: str = zones[0]["id"] dns_name: str = zones[0]["name"] updated = False unchanged = True # update the record - unless it's already correct for dns_record in dns_records: old_ip_address = dns_record["content"] old_ip_address_type = dns_record["type"] if ip_address_type != old_ip_address_type: continue if ip_address == old_ip_address: updated = True continue update_record(cloudflare, zone_id, dns_record["id"], dns_name, ip_address_type, ip_address) unchanged = False updated = True if updated: if unchanged: logger.info( "No Change required", name=dns_name, type=ip_address_type, address=ip_address, ) return 0 add_record(cloudflare, zone_id, dns_name, ip_address_type, ip_address) return 0
# TODO cds set txt example.com "value" (unique by name, suitable for dkim set script import argparse import six from CloudFlare import CloudFlare import logging as log from CloudFlare.exceptions import CloudFlareAPIError cf = CloudFlare() def commandline_arg(bytestring): """ Workaround fix for Python 2 input argument to be Unicode. See: https://stackoverflow.com/questions/22947181/dont-argparse-read-unicode-from-commandline """ unicode_string = bytestring.decode(sys.getfilesystemencoding()) return unicode_string def action_config(): pass def action_list(): pass def action_reset(): pass