Exemple #1
0
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+"'")
Exemple #2
0
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
Exemple #3
0
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.")
Exemple #4
0
    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
Exemple #5
0
 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"]))
Exemple #7
0
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}")
Exemple #8
0
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))
Exemple #9
0
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)
Exemple #10
0
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
Exemple #11
0
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()
Exemple #12
0
 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
Exemple #13
0
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())
Exemple #14
0
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)
Exemple #16
0
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'])
Exemple #19
0
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
        }
    )
Exemple #20
0
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
Exemple #21
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