Merhaba Arkadaşlar, Cloudflare hesabınızdaki tüm domainleri aynı anda yönetmenizi sağlayan kendi yazmış olduğum Türkçe arayüzlü Python aracımı sizlerle paylaşmak istiyorum.
Bu araç sayesinde onlarca domaininizi tek seferde yönetebilir, DNS kayıtlarınızı toplu olarak ekleyebilir veya güncelleyebilirsiniz.

### Aracın Özellikleri:

1. 🌐 **Domain Yönetimi**:
- Tüm domainlerinizi (zone) listeleme
- Domain nameserver bilgilerini görüntüleme
- Nameserver bilgilerini CSV veya TXT dosyasına aktarma

2. 📝 **DNS Kayıt Yönetimi**:
- Domain için tüm DNS kayıtlarını listeleme
- Tüm domainlere aynı anda root (@) ve www A kaydı ekleme
- Tüm domainlere aynı anda subdomain A kaydı ekleme
- MX kayıtları (mail sunucusu) ekleme
- Özel DNS kayıtları ekleme (A, CNAME, TXT, MX, vb.)
- Tüm A kayıtlarını toplu olarak güncelleme
- DNS kayıtlarını CSV dosyasına aktarma
- CSV dosyasından DNS kayıtlarını içe aktarma

3. 🔒 **Güvenlik Duvarı Kuralları**:
- Toplu IP kısıtlaması ekleme

4. ⚡ **Paralel İşlem Desteği**:
- Çok sayıda domain üzerinde eş zamanlı işlem yapabilme
### Kurulum ve Kullanım:
1. Python 3.x kurulu olmalıdır
2. Gerekli kütüphaneleri yükleyin: `pip install requests`
3. Kodun başındaki Cloudflare API bilgilerinizi güncelleyin
4. Scripti çalıştırın: `python cloudflare_manager.py`

### Güvenlik Notu: Paylaştığım koddaki API anahtarını kendi API anahtarınızla değiştirmeyi unutmayın! Kod açık kaynaklıdır, dilediğiniz gibi geliştirip kullanabilirsiniz. Sorularınız veya önerileriniz için yorum bırakabilirsiniz. İyi kullanımlar!


#!/usr/bin/env python3
import os
import requests
import json
import csv
import sys
import threading
import concurrent.futures
CLOUDFLARE_EMAIL = 'mail_adresiniz'
CLOUDFLARE_API_KEY = 'cloudfare_apikey'
ORIGIN_CA_KEY = 'v1.32443424...' #gereksiz
CF_API_URL = 'https://api.cloudflare.com/client/v4'
headers = {
    'X-Auth-Email': CLOUDFLARE_EMAIL,
    'X-Auth-Key': CLOUDFLARE_API_KEY,
    'Content-Type': 'application/json'
}
def list_zones():
    try:
        response = requests.get(f'{CF_API_URL}/zones?status=active&per_page=50', headers=headers)
        data = response.json()
        
        if not data['success']:
            print(f"Hata: {data['errors']}")
            return None
        
        print(f"Toplam domain sayısı: {len(data['result'])}")
        zones = []
        for zone in data['result']:
            print(f"Domain: {zone['name']}, ID: {zone['id']}")
            zones.append(zone)
        
        return zones
    except Exception as e:
        print(f"Alan adları listelenirken hata: {e}")
        return None
def get_nameservers(zone_id):
    try:
        response = requests.get(f'{CF_API_URL}/zones/{zone_id}', headers=headers)
        data = response.json()
        
        if not data['success']:
            print(f"Hata: {data['errors']}")
            return None
        
        return data['result']['name_servers']
    except Exception as e:
        print(f"Nameserver bilgileri alınırken hata: {e}")
        return None
def export_nameservers_to_csv(zones, filename="domain_nameservers.csv"):
    if not zones:
        print("Domain bulunamadı!")
        return
    
    nameserver_info = []
    
    def process_zone(zone):
        nameservers = get_nameservers(zone['id'])
        if nameservers:
            return {
                'domain': zone['name'],
                'nameservers': ', '.join(nameservers)
            }
        return None
    
    with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
        results = executor.map(process_zone, zones)
        for result in results:
            if result:
                nameserver_info.append(result)
    
    try:
        with open(filename, 'w', newline='', encoding='utf-8') as csvfile:
            fieldnames = ['domain', 'nameservers']
            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
            
            writer.writeheader()
            for info in nameserver_info:
                writer.writerow(info)
        
        print(f"\nTüm nameserver bilgileri {filename} dosyasına aktarıldı.")
        return filename
    except Exception as e:
        print(f"CSV dosyası oluşturulurken hata: {e}")
        return None
def export_nameservers_to_txt(zones, filename="domain_nameservers.txt"):
    if not zones:
        print("Domain bulunamadı!")
        return
    
    try:
        with open(filename, 'w', encoding='utf-8') as txtfile:
            txtfile.write("Domain Nameserver Bilgileri\n")
            txtfile.write("=========================\n\n")
            
            def process_zone(zone):
                nameservers = get_nameservers(zone['id'])
                result = f"Domain: {zone['name']}\n"
                if nameservers:
                    result += f"Nameservers: {', '.join(nameservers)}\n\n"
                else:
                    result += "Nameserver bilgisi alınamadı!\n\n"
                return result
            
            with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
                results = executor.map(process_zone, zones)
                for result in results:
                    txtfile.write(result)
        
        print(f"\nTüm nameserver bilgileri {filename} dosyasına aktarıldı.")
        return filename
    except Exception as e:
        print(f"TXT dosyası oluşturulurken hata: {e}")
        return None
def get_dns_records(zone_id):
    try:
        response = requests.get(f'{CF_API_URL}/zones/{zone_id}/dns_records?per_page=100', headers=headers)
        data = response.json()
        
        if not data['success']:
            print(f"Hata: {data['errors']}")
            return None
        
        print(f"Toplam DNS kaydı sayısı: {len(data['result'])}")
        for record in data['result']:
            print(f"Tür: {record['type']}, Ad: {record['name']}, İçerik: {record['content']}, Proxy: {record['proxied']}")
        
        return data['result']
    except Exception as e:
        print(f"DNS kayıtları listelenirken hata: {e}")
        return None
def create_dns_record(zone_id, record_type, name, content, ttl=1, proxied=True, priority=None):
    data = {
        'type': record_type,
        'name': name,
        'content': content,
        'ttl': ttl,
        'proxied': proxied
    }
    
    if record_type == "MX" and priority is not None:
        data['priority'] = priority
    
    try:
        response = requests.post(
            f'{CF_API_URL}/zones/{zone_id}/dns_records',
            headers=headers,
            json=data
        )
        result = response.json()
        
        if not result['success']:
            print(f"Hata: {result['errors']}")
            return None
        
        print(f"DNS kaydı eklendi: {result['result']['name']}")
        return result['result']
    except Exception as e:
        print(f"DNS kaydı oluşturulurken hata: {e}")
        return None
def add_root_and_www_a_records(zones, ip_address, proxied=True):
    if not zones:
        print("Domain bulunamadı!")
        return
    
    results = []
    
    def process_zone(zone):
        zone_results = []
        root_result = create_dns_record(
            zone_id=zone['id'],
            record_type="A",
            name="@",
            content=ip_address,
            proxied=proxied
        )
        zone_results.append({
            'domain': zone['name'],
            'record': '@',
            'result': 'Başarılı' if root_result else 'Başarısız'
        })
        
        www_result = create_dns_record(
            zone_id=zone['id'],
            record_type="A",
            name="www",
            content=ip_address,
            proxied=proxied
        )
        zone_results.append({
            'domain': zone['name'],
            'record': 'www',
            'result': 'Başarılı' if www_result else 'Başarısız'
        })
        return zone_results
    
    with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
        futures = [executor.submit(process_zone, zone) for zone in zones]
        for future in concurrent.futures.as_completed(futures):
            results.extend(future.result())
    
    print("\nİşlem sonuçları:")
    for r in results:
        print(f"{r['domain']} ({r['record']}): {r['result']}")
    
    return results
def add_mx_records(zones, mail_server_prefix="mail", priority=10, proxied=False, mail_ip=None):
    if not zones:
        print("Domain bulunamadı!")
        return
    
    if not mail_ip:
        mail_ip = input(f"Tüm {mail_server_prefix} subdomainleri için IP adresi: ")
    
    results = []
    
    def process_zone(zone):
        zone_results = []
        mail_server = f"{mail_server_prefix}.{zone['name']}"
        
        data = {
            'type': "MX",
            'name': "@",
            'content': mail_server,
            'ttl': 1,
            'proxied': proxied,
            'priority': priority
        }
        
        try:
            response = requests.post(
                f'{CF_API_URL}/zones/{zone["id"]}/dns_records',
                headers=headers,
                json=data
            )
            result = response.json()
            
            if not result['success']:
                print(f"Hata: {result['errors']}")
                result = None
            else:
                print(f"MX kaydı eklendi: {result['result']['name']}")
                result = result['result']
        except Exception as e:
            print(f"MX kaydı oluşturulurken hata: {e}")
            result = None
        
        mail_a_result = create_dns_record(
            zone_id=zone['id'],
            record_type="A",
            name=mail_server_prefix,
            content=mail_ip,
            ttl=1,
            proxied=proxied
        )
        
        zone_results.append({
            'domain': zone['name'],
            'record': 'MX',
            'result': 'Başarılı' if result else 'Başarısız'
        })
        return zone_results
    
    with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
        futures = [executor.submit(process_zone, zone) for zone in zones]
        for future in concurrent.futures.as_completed(futures):
            results.extend(future.result())
    
    print("\nİşlem sonuçları:")
    for r in results:
        print(f"{r['domain']} ({r['record']}): {r['result']}")
    
    return results
def add_subdomain_to_domains(zones, subdomain, ip_address, proxied=True):
    if not zones:
        print("Domain bulunamadı!")
        return
    
    results = []
    
    def process_zone(zone):
        result = create_dns_record(
            zone_id=zone['id'],
            record_type="A",
            name=subdomain,
            content=ip_address,
            proxied=proxied
        )
        return {
            'domain': zone['name'],
            'record': subdomain,
            'result': 'Başarılı' if result else 'Başarısız'
        }
    
    with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(process_zone, zones))
    
    print("\nİşlem sonuçları:")
    for r in results:
        print(f"{r['domain']} ({r['record']}): {r['result']}")
    
    return results
def add_record_to_domains(zones, record_type, name, content, proxied=True):
    if not zones:
        print("Domain bulunamadı!")
        return
    
    results = []
    
    def process_zone(zone):
        result = create_dns_record(
            zone_id=zone['id'],
            record_type=record_type,
            name=name,
            content=content,
            proxied=proxied
        )
        return {
            'domain': zone['name'],
            'result': 'Başarılı' if result else 'Başarısız'
        }
    
    with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(process_zone, zones))
    
    print("\nİşlem sonuçları:")
    for r in results:
        print(f"{r['domain']}: {r['result']}")
    
    return results
def update_dns_record(zone_id, record_id, record_type, name, content, ttl=1, proxied=True):
    data = {
        'type': record_type,
        'name': name,
        'content': content,
        'ttl': ttl,
        'proxied': proxied
    }
    
    try:
        response = requests.put(
            f'{CF_API_URL}/zones/{zone_id}/dns_records/{record_id}',
            headers=headers,
            json=data
        )
        result = response.json()
        
        if not result['success']:
            print(f"Hata: {result['errors']}")
            return None
        
        print(f"DNS kaydı güncellendi: {result['result']['name']}")
        return result['result']
    except Exception as e:
        print(f"DNS kaydı güncellenirken hata: {e}")
        return None
def bulk_update_a_records(zones, new_ip):
    if not zones:
        print("Domain bulunamadı!")
        return
    
    results = []
    
    def process_zone(zone):
        zone_results = []
        records = get_dns_records(zone['id'])
        if not records:
            return []
        
        a_records = [r for r in records if r['type'] == 'A']
        for record in a_records:
            result = update_dns_record(
                zone_id=zone['id'],
                record_id=record['id'],
                record_type='A',
                name=record['name'],
                content=new_ip,
                proxied=record['proxied']
            )
            zone_results.append({
                'domain': zone['name'],
                'record': record['name'],
                'result': 'Başarılı' if result else 'Başarısız'
            })
        return zone_results
    
    with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
        futures = [executor.submit(process_zone, zone) for zone in zones]
        for future in concurrent.futures.as_completed(futures):
            results.extend(future.result())
    
    print("\nGüncelleme sonuçları:")
    for r in results:
        print(f"{r['domain']} ({r['record']}): {r['result']}")
    
    return results
def export_dns_records_to_csv(zones, filename="dns_records.csv"):
    if not zones:
        print("Domain bulunamadı!")
        return
    
    all_records = []
    
    def process_zone(zone):
        zone_records = []
        records = get_dns_records(zone['id'])
        if not records:
            return []
        
        for record in records:
            zone_records.append({
                'domain': zone['name'],
                'type': record['type'],
                'name': record['name'],
                'content': record['content'],
                'proxied': record['proxied'],
                'ttl': record['ttl'],
                'id': record['id'],
                'zone_id': zone['id']
            })
        return zone_records
    
    with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
        futures = [executor.submit(process_zone, zone) for zone in zones]
        for future in concurrent.futures.as_completed(futures):
            all_records.extend(future.result())
    
    try:
        with open(filename, 'w', newline='', encoding='utf-8') as csvfile:
            fieldnames = ['domain', 'type', 'name', 'content', 'proxied', 'ttl', 'id', 'zone_id']
            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
            
            writer.writeheader()
            for record in all_records:
                writer.writerow(record)
        
        print(f"\nTüm DNS kayıtları {filename} dosyasına aktarıldı.")
        return filename
    except Exception as e:
        print(f"CSV dosyası oluşturulurken hata: {e}")
        return None
def import_dns_records_from_csv(filename="dns_records.csv"):
    try:
        with open(filename, 'r', newline='', encoding='utf-8') as csvfile:
            reader = csv.DictReader(csvfile)
            records = list(reader)
        
        results = []
        
        def process_record(record):
            try:
                proxied = record['proxied'].lower() == 'true'
                result = create_dns_record(
                    zone_id=record['zone_id'],
                    record_type=record['type'],
                    name=record['name'],
                    content=record['content'],
                    ttl=int(record['ttl']),
                    proxied=proxied
                )
                return {
                    'domain': record['domain'],
                    'record': record['name'],
                    'result': 'Başarılı' if result else 'Başarısız'
                }
            except Exception as e:
                return {
                    'domain': record['domain'],
                    'record': record['name'],
                    'result': f'Hata: {str(e)}'
                }
        
        with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
            results = list(executor.map(process_record, records))
        
        print("\nİçe aktarma sonuçları:")
        for r in results:
            print(f"{r['domain']} ({r['record']}): {r['result']}")
        
        return results
    except Exception as e:
        print(f"CSV dosyası okunurken hata: {e}")
        return None
def create_firewall_rule(zone_id, name, action="block", expression="", paused=False):
    data = {
        'filter': {
            'expression': expression
        },
        'action': action,
        'description': name,
        'paused': paused
    }
    
    try:
        response = requests.post(
            f'{CF_API_URL}/zones/{zone_id}/firewall/rules',
            headers=headers,
            json=data
        )
        result = response.json()
        
        if not result['success']:
            print(f"Hata: {result['errors']}")
            return None
        
        print(f"Güvenlik duvarı kuralı oluşturuldu: {name}")
        return result['result']
    except Exception as e:
        print(f"Güvenlik duvarı kuralı oluşturulurken hata: {e}")
        return None
def add_ip_restriction(zones, rule_name, allowed_ips):
    if not zones:
        print("Domain bulunamadı!")
        return
    
    ip_list = " or ".join([f"ip.src eq {ip}" for ip in allowed_ips])
    expression = f"not ({ip_list})"
    
    results = []
    
    def process_zone(zone):
        result = create_firewall_rule(
            zone_id=zone['id'],
            name=rule_name,
            action="block",
            expression=expression
        )
        return {
            'domain': zone['name'],
            'result': 'Başarılı' if result else 'Başarısız'
        }
    
    with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
        results = list(executor.map(process_zone, zones))
    
    print("\nIP kısıtlaması sonuçları:")
    for r in results:
        print(f"{r['domain']}: {r['result']}")
    
    return results
def select_domains(all_zones):
    print("\nDomain seçim modu:")
    print("1. Tüm domainler")
    print("2. Tek domain")
    print("3. Çoklu domain seçimi")
    
    choice = input("\nSeçiminiz (1-3): ")
    
    if choice == "1":
        return all_zones
    
    elif choice == "2":
        if all_zones and len(all_zones) > 0:
            print("\nİşlem yapmak istediğiniz domainin numarasını seçin:")
            for i, zone in enumerate(all_zones):
                print(f"{i+1}. {zone['name']}")
            
            try:
                zone_index = int(input("\nSeçiminiz: ")) - 1
                if 0 <= zone_index < len(all_zones):
                    return [all_zones[zone_index]]
                else:
                    print("Geçersiz numara!")
                    return None
            except ValueError:
                print("Lütfen bir numara girin!")
                return None
    
    elif choice == "3":
        if all_zones and len(all_zones) > 0:
            print("\nİşlem yapmak istediğiniz domainlerin numaralarını virgülle ayırarak girin:")
            for i, zone in enumerate(all_zones):
                print(f"{i+1}. {zone['name']}")
            
            try:
                indices = input("\nSeçimleriniz (örn: 1,3,5): ").split(',')
                selected_zones = []
                
                for idx in indices:
                    zone_index = int(idx.strip()) - 1
                    if 0 <= zone_index < len(all_zones):
                        selected_zones.append(all_zones[zone_index])
                    else:
                        print(f"Geçersiz numara: {idx}")
                
                if selected_zones:
                    return selected_zones
                else:
                    print("Geçerli domain seçilmedi!")
                    return None
            except ValueError:
                print("Lütfen geçerli numaralar girin!")
                return None
    
    print("Geçersiz seçim!")
    return None
def display_menu():
    print("\nCloudflare API Yönetim Aracı")
    print("---------------------------")
    print("1. Domainleri listele")
    print("2. Domain için DNS kayıtları listele")
    print("3. Root (@) ve www A kaydı ekle")
    print("4. Belirli bir subdomain A kaydı ekle")
    print("5. MX kaydı ekle (mail.domain.com)")
    print("6. Aynı DNS kaydı ekle")
    print("7. A kayıtlarını güncelle")
    print("8. DNS kayıtlarını CSV'ye aktar")
    print("9. CSV'den DNS kayıtlarını içe aktar")
    print("10. IP kısıtlaması ekle")
    print("11. Nameserver bilgilerini CSV'ye aktar")
    print("12. Nameserver bilgilerini TXT'ye aktar")
    print("0. Çıkış")
    
    choice = input("\nSeçiminiz (0-12): ")
    return choice
def main():
    all_zones = list_zones()
    
    while True:
        choice = display_menu()
        
        if choice == "1":
            list_zones()
        
        elif choice == "2":
            if all_zones and len(all_zones) > 0:
                print("\nDNS kayıtlarını görmek istediğiniz domainin numarasını seçin:")
                for i, zone in enumerate(all_zones):
                    print(f"{i+1}. {zone['name']}")
                
                try:
                    zone_index = int(input("\nSeçiminiz: ")) - 1
                    if 0 <= zone_index < len(all_zones):
                        get_dns_records(all_zones[zone_index]['id'])
                    else:
                        print("Geçersiz numara!")
                except ValueError:
                    print("Lütfen bir numara girin!")
        
        elif choice == "3":
            selected_zones = select_domains(all_zones)
            if selected_zones:
                ip_address = input("Eklenecek IP adresi: ")
                proxied = input("Proxy kullanılsın mı? (e/h): ").lower() == 'e'
                add_root_and_www_a_records(selected_zones, ip_address, proxied)
        
        elif choice == "4":
            selected_zones = select_domains(all_zones)
            if selected_zones:
                subdomain = input("Eklenecek subdomain adı: ")
                ip_address = input(f"{subdomain} için IP adresi: ")
                proxied = input("Proxy kullanılsın mı? (e/h): ").lower() == 'e'
                add_subdomain_to_domains(selected_zones, subdomain, ip_address, proxied)
        
        elif choice == "5":
            selected_zones = select_domains(all_zones)
            if selected_zones:
                mail_prefix = input("Mail sunucusu öneki (varsayılan: mail): ") or "mail"
                priority = int(input("MX önceliği (varsayılan: 10): ") or "10")
                proxied = input("Proxy kullanılsın mı? (e/h): ").lower() == 'e'
                add_mx_records(selected_zones, mail_prefix, priority, proxied)
        
        elif choice == "6":
            selected_zones = select_domains(all_zones)
            if selected_zones:
                record_type = input("Kayıt türü (A, CNAME, TXT, MX, vb.): ").upper()
                name = input("Kayıt adı (@ root için): ")
                content = input("İçerik (IP adresi veya hedef): ")
                proxied = input("Proxy kullanılsın mı? (e/h): ").lower() == 'e'
                add_record_to_domains(selected_zones, record_type, name, content, proxied)
        
        elif choice == "7":
            selected_zones = select_domains(all_zones)
            if selected_zones:
                new_ip = input("A kayıtları için yeni IP adresi: ")
                bulk_update_a_records(selected_zones, new_ip)
        
        elif choice == "8":
            selected_zones = select_domains(all_zones)
            if selected_zones:
                filename = input("CSV dosya adı (varsayılan: dns_records.csv): ") or "dns_records.csv"
                export_dns_records_to_csv(selected_zones, filename)
        
        elif choice == "9":
            filename = input("İçe aktarılacak CSV dosya adı: ")
            if os.path.exists(filename):
                import_dns_records_from_csv(filename)
            else:
                print(f"Hata: {filename} dosyası bulunamadı!")
        
        elif choice == "10":
            selected_zones = select_domains(all_zones)
            if selected_zones:
                rule_name = input("Kural adı: ")
                allowed_ips = input("İzin verilen IP'ler (virgülle ayırın): ").split(',')
                allowed_ips = [ip.strip() for ip in allowed_ips]
                add_ip_restriction(selected_zones, rule_name, allowed_ips)
            
        elif choice == "11":
            selected_zones = select_domains(all_zones)
            if selected_zones:
                filename = input("CSV dosya adı (varsayılan: domain_nameservers.csv): ") or "domain_nameservers.csv"
                export_nameservers_to_csv(selected_zones, filename)
            
        elif choice == "12":
            selected_zones = select_domains(all_zones)
            if selected_zones:
                filename = input("TXT dosya adı (varsayılan: domain_nameservers.txt): ") or "domain_nameservers.txt"
                export_nameservers_to_txt(selected_zones, filename)
        
        elif choice == "0":
            print("Programdan çıkılıyor...")
            sys.exit(0)
        
        else:
            print("Geçersiz seçim!")
        
        input("\nDevam etmek için Enter tuşuna basın...")
if __name__ == "__main__":
    main()